diff --git a/lib/main/build-site.js b/lib/main/build-site.js index 69a45e6e7..705c138c7 100644 --- a/lib/main/build-site.js +++ b/lib/main/build-site.js @@ -22,19 +22,139 @@ const highlights = [ 'type' ]; -const hlTypes = [ - 'html', - 'js', - 'shell' -]; - const hlSources = [ 'highlight', 'source', 'text' ]; -function build(type) { +const hlTypes = [ + 'html', + 'js', + 'shell' +]; + +/** + * Converts Lodash method references into documentation links. + * + * @private + * @param {Object} $ The Cheerio object. + */ +function autoLink($) { + $('code').each(function() { + const $code = $(this); + const html = $code.html(); + if (/^_\.\w+$/.test(html)) { + const id = html.split('.')[1]; + $code.html(`_.${ id }`); + } + }); +} + +/** + * Removes horizontal rules from the document. + * + * @private + * @param {Object} $ The Cheerio object. + */ +function removeHorizontalRules($) { + $('hr').remove(); +} + +/** + * Removes marky-markdown specific ids and class names. + * + * @private + * @param {Object} $ The Cheerio object. + */ +function removeMarkyAttributes($) { + $('[id^="user-content-"]') + .attr('class', null) + .attr('id', null); + + $(':header:not(h3) > a').each(function() { + const $a = $(this); + $a.replaceWith($a.html()); + }); +} + +/** + * Renames "_" id and anchor references to "lodash". + * + * @private + * @param {Object} $ The Cheerio object. + */ +function renameLodashId($) { + $('#_').attr('id', 'lodash'); + $('[href="#_"]').attr('href', '#lodash'); +} + +/** + * Repairs broken marky-markdown headers. + * See https://github.com/npm/marky-markdown/issues/217 for more details. + * + * @private + * @param {Object} $ The Cheerio object. + */ +function repairMarkyHeaders($) { + $('p:empty + h3').prev().remove(); + + $('h3 ~ p:empty').each(function() { + const $p = $(this); + let node = this.prev; + while ((node = node.prev) && node.name != 'h3' && node.name != 'p') { + $p.prepend(node.next); + } + }); + + $('h3 code em').parent().each(function() { + const $code = $(this); + $code.html($code.html().replace(/<\/?em>/g, '_')); + }); +} + +/** + * Cleans up highlights blocks by removing extraneous class names and elements. + * + * @private + * @param {Object} $ The Cheerio object. + */ +function tidyHighlights($) { + // Remove extraneous class names. + $('.highlight [class]').each(function() { + const $element = $(this); + const classes = $element.attr('class').split(' '); + if (!_.isEmpty(_.intersection(classes, hlSources)) && + !_.isEmpty(_.intersection(classes, hlTypes))) { + return; + } + const attr = _.intersection(classes, highlights).join(' '); + $element.attr('class', attr || null); + }); + // Unwrap elements containing only text. + $('.highlight :not([class])').each(function() { + let element = $(this); + while (element && !element.children.length) { + const $element = $(element); + $element.replaceWith($element.text()); + element = element.parent; + } + }); + // Collapse comments. + $('.highlight [class~="comment"] > [class~="comment"]').each(function() { + const $parent = $(this).parent(); + $parent.text($parent.text()); + }); +} + +/*----------------------------------------------------------------------------*/ + +/** + * Creates the documentation HTML. + * + * @private + */ +function build() { const markdown = fs // Load markdown. .readFileSync(readmePath, 'utf8') @@ -47,67 +167,18 @@ function build(type) { const $header = $('h1').first().remove(); const version = _.trim($header.find('span').first().text()).slice(1); + // Auto-link Lodash method references. + autoLink($); // Rename "_" id references to "lodash". - $('#_').attr('id', 'lodash'); - $('[href="#_"]').attr('href', '#lodash'); - + renameLodashId($); // Remove docdown horizontal rules. - $('hr').remove(); - - // Remove marky-markdown additions. - $('[id^="user-content-"]') - .attr('class', null) - .attr('id', null); - - $(':header:not(h3) > a').each(function() { - const $a = $(this); - $a.replaceWith($a.html()); - }); - - // Fix marky-markdown wrapping around headers. - $('p:empty + h3').prev().remove(); - - $('h3 ~ p:empty').each(function() { - const $p = $(this); - let node = this.previousSibling; - - while ((node = node.previousSibling) && node.name != 'h3' && node.name != 'p') { - $p.prepend(node.nextSibling); - } - }); - - $('h3 code em').parent().each(function() { - const $code = $(this); - $code.html($code.html().replace(/<\/?em>/g, '_')); - }); - - // Cleanup highlights class names. - $('.highlight [class]').each(function() { - const $el = $(this); - const names = $el.attr('class').split(/\s+/); - const attr = _.intersection(names, highlights).join(' '); - - if (!_.isEmpty(_.intersection(names, hlSources)) && - !_.isEmpty(_.intersection(names, hlTypes))) { - return; - } - $el.attr('class', attr || null); - }); - - // Unwrap elements containing only text. - $('.highlight :not([class])').each(function() { - let $el = $(this); - while ($el[0] && _.every($el.children(), ['type', 'text'])) { - $el.replaceWith($el.text()); - $el = $el.parent(); - } - }); - - // Collapse hightlights comments. - $('.highlight [class~="comment"] > [class~="comment"]').each(function() { - const $parent = $(this).parent(); - $parent.text($parent.text()); - }); + removeHorizontalRules($); + // Remove marky-markdown attribute additions. + removeMarkyAttributes($); + // Repair marky-markdown wrapping around headers. + repairMarkyHeaders($); + // Cleanup highlights. + tidyHighlights($); const html = [ // Append YAML front matter.