From d4e633d2693b3f47602a5047833ee57ce7a99cd6 Mon Sep 17 00:00:00 2001 From: Johan Kaving Date: Thu, 26 Oct 2017 00:15:47 +0200 Subject: [PATCH 1/2] Handle table of contents not on top level Table of contents are now correctly generated even if the top level headings are not included with the "!heading" marker. Fixes #18 --- markdown-include.js | 47 +++++++++++++++++++++++----------- tests/all.js | 1 + tests/unit/buildContentItem.js | 6 +++-- tests/unit/parseHeadingTag.js | 4 +++ 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/markdown-include.js b/markdown-include.js index 304cc63..9254653 100644 --- a/markdown-include.js +++ b/markdown-include.js @@ -25,32 +25,30 @@ this.customTags = []; * @return {String} String for markdown navigation item */ exports.buildContentItem = function (obj) { - var headingTag = obj.headingTag; var count = obj.count; - var item = headingTag.substring(count + 1); - var index = headingTag.indexOf(item); - var headingTrimmed = this.buildLinkString(headingTag.substring(index)); + var item = obj.item; + var itemLink = this.buildLinkString(item); var lead = this.options.tableOfContents.lead && this.options.tableOfContents.lead === 'number' ? '1.' : '*'; var navItem; - switch (obj.count) { + switch (count) { case 1: - navItem = lead + ' ' + this.buildLink(item, headingTrimmed); + navItem = lead + ' ' + this.buildLink(item, itemLink); break; case 2: - navItem = ' ' + lead + ' ' + this.buildLink(item, headingTrimmed); + navItem = ' ' + lead + ' ' + this.buildLink(item, itemLink); break; case 3: - navItem = ' ' + lead + ' ' + this.buildLink(item, headingTrimmed); + navItem = ' ' + lead + ' ' + this.buildLink(item, itemLink); break; case 4: - navItem = ' ' + lead + ' ' + this.buildLink(item, headingTrimmed); + navItem = ' ' + lead + ' ' + this.buildLink(item, itemLink); break; case 5: - navItem = ' ' + lead + ' ' + this.buildLink(item, headingTrimmed); + navItem = ' ' + lead + ' ' + this.buildLink(item, itemLink); break; case 6: - navItem = ' ' + lead + ' ' + this.buildLink(item, headingTrimmed); + navItem = ' ' + lead + ' ' + this.buildLink(item, itemLink); break; } @@ -167,13 +165,18 @@ exports.compileFiles = function (path) { exports.compileHeadingTags = function (file) { var headingTags = this.findHeadingTags(this.build[file].parsedData); var replacedHeadingTag; - var parsedHeading; + var parsedHeadings = []; var i; for (i = 0; i < headingTags.length; i += 1) { replacedHeadingTag = headingTags[i].replace(this.headingTag, ''); - parsedHeading = this.parseHeadingTag(replacedHeadingTag); - this.tableOfContents += this.buildContentItem(parsedHeading); + parsedHeadings.push(this.parseHeadingTag(replacedHeadingTag)); + } + var minCount = this.getMinCount(parsedHeadings); + + for (i = 0; i < parsedHeadings.length; i += 1) { + parsedHeadings[i].count = parsedHeadings[i].count - minCount + 1; + this.tableOfContents += this.buildContentItem(parsedHeadings[i]); } this.build[file].parsedData = this.stripTagsInFile({ @@ -183,6 +186,17 @@ exports.compileHeadingTags = function (file) { }); }; +exports.getMinCount = function getMinCount(parsedHeadings) { + var minCount = 0; + for (var i = 0; i < parsedHeadings.length; i += 1) { + var count = parsedHeadings[i].count; + if (minCount === 0 || count < minCount) { + minCount = count; + } + } + return minCount; +} + /** * Finding heading tags that have !heading * @param {String} parsedData Parsed data from includes @@ -228,6 +242,7 @@ exports.findIncludeTags = function (rawData) { */ exports.parseHeadingTag = function (headingTag) { var count = 0; + var item; var i; for (i = 0; i < headingTag.length; i += 1) { @@ -235,6 +250,7 @@ exports.parseHeadingTag = function (headingTag) { count += 1; } else { + item = headingTag.slice(count + 1); break; } } @@ -242,7 +258,8 @@ exports.parseHeadingTag = function (headingTag) { // Do we need to return the heading tag?? return { count: count, - headingTag: headingTag + headingTag: headingTag, + item: item }; }; diff --git a/tests/all.js b/tests/all.js index b5f4643..379a263 100644 --- a/tests/all.js +++ b/tests/all.js @@ -1,6 +1,7 @@ /* eslint-env amd */ define([ './unit/buildContentItem', + './unit/buildTableOfContents', './unit/buildLinkString', './unit/compileFiles', './unit/compileHeadingTags', diff --git a/tests/unit/buildContentItem.js b/tests/unit/buildContentItem.js index 1bea3d6..df7bd40 100644 --- a/tests/unit/buildContentItem.js +++ b/tests/unit/buildContentItem.js @@ -17,7 +17,8 @@ define([ var contentItem = markdownInclude.buildContentItem({ count: 1, - headingTag: '# My Heading To Link' + headingTag: '# My Heading To Link', + item: 'My Heading To Link' }); assert.equal(contentItem, '1. [My Heading To Link](#my-heading-to-link)\n', 'Content items match'); @@ -32,7 +33,8 @@ define([ var contentItem = markdownInclude.buildContentItem({ count: 1, - headingTag: '# My Heading To Link' + headingTag: '# My Heading To Link', + item: 'My Heading To Link' }); assert.equal(contentItem, '* [My Heading To Link](#my-heading-to-link)\n', 'Content items match'); diff --git a/tests/unit/parseHeadingTag.js b/tests/unit/parseHeadingTag.js index ccdbd99..4116088 100644 --- a/tests/unit/parseHeadingTag.js +++ b/tests/unit/parseHeadingTag.js @@ -8,5 +8,9 @@ define([ var count = markdownInclude.parseHeadingTag('### heading').count; assert.equal(count, 3, 'Counts match'); }); + bdd.it('should return the item string from a heading tag', function () { + var item = markdownInclude.parseHeadingTag('### heading').item; + assert.equal(item, 'heading', 'Item match'); + }); }); }); \ No newline at end of file From 793c24c27579a23f0033b2f177e918139417bd7d Mon Sep 17 00:00:00 2001 From: Johan Kaving Date: Thu, 26 Oct 2017 09:54:54 +0200 Subject: [PATCH 2/2] Add missing files --- .../docs/has_heading_tags_on_lower_levels.md | 6 ++++ tests/unit/buildTableOfContents.js | 34 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 tests/data/docs/has_heading_tags_on_lower_levels.md create mode 100644 tests/unit/buildTableOfContents.js diff --git a/tests/data/docs/has_heading_tags_on_lower_levels.md b/tests/data/docs/has_heading_tags_on_lower_levels.md new file mode 100644 index 0000000..146ba81 --- /dev/null +++ b/tests/data/docs/has_heading_tags_on_lower_levels.md @@ -0,0 +1,6 @@ +# First Test Heading +## Second Test Heading +### Third Test Heading !heading +#### Fourth Test Heading !heading +##### Fifth Test Heading !heading +###### Sixth Test Heading !heading \ No newline at end of file diff --git a/tests/unit/buildTableOfContents.js b/tests/unit/buildTableOfContents.js new file mode 100644 index 0000000..7fb45e7 --- /dev/null +++ b/tests/unit/buildTableOfContents.js @@ -0,0 +1,34 @@ +define([ + 'intern!bdd', + 'intern/chai!assert', + 'intern/dojo/node!../../markdown-include' +], function (bdd, assert, markdownInclude) { + bdd.describe('markdownInclude.buildTableOfContents', function () { + bdd.after(function () { + markdownInclude.options = markdownInclude.build = {}; + markdownInclude.tableOfContents = ''; + }); + + bdd.beforeEach(function () { + markdownInclude.options = { + tableOfContents: { + lead: 'number' + } + }; + markdownInclude.tableOfContents = ''; + + markdownInclude.processFile('tests/data/docs/has_heading_tags_on_lower_levels.md'); + }); + + bdd.it('should create a table of contents with correct level', function () { + markdownInclude.compileHeadingTags('tests/data/docs/has_heading_tags_on_lower_levels.md'); + + assert.equal(markdownInclude.tableOfContents, + '1. [Third Test Heading](#third-test-heading)\n' + + ' 1. [Fourth Test Heading](#fourth-test-heading)\n' + + ' 1. [Fifth Test Heading](#fifth-test-heading)\n' + + ' 1. [Sixth Test Heading](#sixth-test-heading)\n', + 'Data matches'); + }); + }); +}); \ No newline at end of file