diff --git a/packages/gitbook/package.json b/packages/gitbook/package.json index 0ecbf212e..9e236f259 100644 --- a/packages/gitbook/package.json +++ b/packages/gitbook/package.json @@ -43,7 +43,7 @@ "json-schema-defaults": "0.1.1", "jsonschema": "1.1.0", "juice": "2.0.0", - "markup-it": "^3.2.2", + "markup-it": "^3.4.0", "mkdirp": "0.5.1", "moment": "2.13.0", "npm": "3.10.9", diff --git a/packages/gitbook/src/parse/__tests__/fixtures/summary/empty-items.yaml b/packages/gitbook/src/parse/__tests__/fixtures/summary/empty-items.yaml index 5c7ead287..787a5cc3c 100644 --- a/packages/gitbook/src/parse/__tests__/fixtures/summary/empty-items.yaml +++ b/packages/gitbook/src/parse/__tests__/fixtures/summary/empty-items.yaml @@ -21,5 +21,11 @@ nodes: - kind: block type: unstyled nodes: - - kind: text - text: '' + - kind: inline + type: link + data: + href: 'art1.md' + nodes: + - kind: text + text: '' # No title so ignored + diff --git a/packages/gitbook/src/parse/__tests__/fixtures/summary/flexible.yaml b/packages/gitbook/src/parse/__tests__/fixtures/summary/flexible.yaml new file mode 100644 index 000000000..d62d7f283 --- /dev/null +++ b/packages/gitbook/src/parse/__tests__/fixtures/summary/flexible.yaml @@ -0,0 +1,115 @@ +nodes: + - kind: block + type: header_one + nodes: + - kind: text + text: Summary + - kind: block + type: unordered_list + nodes: + - kind: block + type: list_item + nodes: + - kind: block + type: unstyled + nodes: + - kind: text + text: 'ignored text' + - kind: inline + type: link + data: + href: 'art1.md' + nodes: + - kind: text + text: 'Article 1' + - kind: text + text: '' + + - kind: block + type: list_item + nodes: + - kind: block + type: paragraph + nodes: + - kind: text + text: 'Article 2' + - kind: block + type: paragraph + nodes: + - kind: text + text: 'Ignored' + + - kind: block + type: list_item + nodes: + - kind: block + type: paragraph + nodes: + - kind: text + text: 'First paragraph. There is a link further, so should be ignored' + + # Sublist, that is not after a link. Should be ignored + - kind: block + type: unordered_list + nodes: + - kind: block + type: list_item + nodes: + - kind: block + type: unstyled + nodes: + - kind: inline + type: link + data: + href: 'ignored.md' + nodes: + - kind: text + text: 'Ignored' + + - kind: block + type: paragraph + nodes: + - kind: inline + type: link + data: + href: 'art3.md' + nodes: + - kind: text + text: 'Article 3' + + # First sublist that is after the link. Parsed as subarticles + - kind: block + type: unordered_list + nodes: + - kind: block + type: list_item + nodes: + - kind: block + type: unstyled + nodes: + - kind: inline + type: link + data: + href: 'art2.1.md' + nodes: + - kind: text + text: 'Article 2.1' + + # Ignored because we already parsed the previous list + - kind: block + type: unordered_list + nodes: + - kind: block + type: list_item + nodes: + - kind: block + type: unstyled + nodes: + - kind: inline + type: link + data: + href: 'ignored' + nodes: + - kind: text + text: 'ignored' + diff --git a/packages/gitbook/src/parse/__tests__/summaryFromDocument.js b/packages/gitbook/src/parse/__tests__/summaryFromDocument.js index 1714f269f..d19e5cdc8 100644 --- a/packages/gitbook/src/parse/__tests__/summaryFromDocument.js +++ b/packages/gitbook/src/parse/__tests__/summaryFromDocument.js @@ -92,22 +92,13 @@ describe('summaryFromDocument', () => { ]); }); - it('should parse empty items', () => { + it('should ignore empty items', () => { const summary = readSummary('summary/empty-items.yaml'); expectParts(summary, [ { title: '', - articles: [ - { - title: '', - ref: '' - }, - { - title: '', - ref: '' - } - ] + articles: [] } ]); }); @@ -210,4 +201,36 @@ describe('summaryFromDocument', () => { expectParts(summary, [ ]); }); + + it('should be flexible', () => { + const summary = readSummary('summary/flexible.yaml'); + + expectParts(summary, [ + { + title: '', + articles: [ + { + title: 'Article 1', + ref: 'art1.md' + }, + { + title: 'Article 2', + articles: [] + }, + { + title: 'Article 3', + ref: 'art3.md', + articles: [ + { + title: 'Article 2.1', + ref: 'art2.1.md', + articles: [] + } + ] + } + ] + } + ]); + }); + }); diff --git a/packages/gitbook/src/parse/summaryFromDocument.js b/packages/gitbook/src/parse/summaryFromDocument.js index 1ce14b8d1..42b9c10c7 100644 --- a/packages/gitbook/src/parse/summaryFromDocument.js +++ b/packages/gitbook/src/parse/summaryFromDocument.js @@ -9,17 +9,48 @@ const isLink = node => node.type === INLINES.LINK; /** * Create a summary article from a list item. * @param {Block} item - * @return {SummaryArticleLike} article + * @return {SummaryArticleLike | Null} article */ function createArticleFromItem(item) { const { nodes } = item; - const titleParent = nodes.first(); - const list = nodes.skip(1).find(isList); + // Find the link that represents the article's title + const linkParent = nodes + .filterNot(isList) + .find(node => node.findDescendant(isLink)); + + // Or find text that could act as title + const textParent = nodes.filterNot(node => isList(node) || node.isEmpty).first(); + + let title, ref, parent; + if (linkParent) { + const link = linkParent.findDescendant(isLink); + + if (!link.isEmpty) { + parent = linkParent; + title = link.text; + ref = link.data.get('href'); + } + } + + if (!parent) { + // Could not find a proper link + + if (textParent) { + parent = textParent; + title = textParent.text; + ref = null; + } else { + // This item has no proper title or link + return null; + } + } + + const list = nodes + // Skip until after the article's title or link + .skipUntil(node => node === parent).skip(1) + .find(isList); const articles = list ? listArticles(list) : []; - const title = titleParent.text; - const link = titleParent.findDescendant(isLink); - const ref = link ? link.data.get('href') : null; return { title, @@ -35,7 +66,9 @@ function createArticleFromItem(item) { */ function listArticles(list) { const { nodes } = list; - return nodes.map(item => createArticleFromItem(item)); + return nodes + .map(item => createArticleFromItem(item)) + .filter(article => Boolean(article)); } /**