diff --git a/lib/contents.js b/lib/contents.js index 8856d1e..25c16d8 100644 --- a/lib/contents.js +++ b/lib/contents.js @@ -1,12 +1,14 @@ 'use strict' +var extend = require('extend') + module.exports = contents var LIST = 'list' var LIST_ITEM = 'listItem' var PARAGRAPH = 'paragraph' var LINK = 'link' -var TEXT = 'text' +var LINK_REFERENCE = 'linkReference' // Transform a list of heading objects to a markdown list. function contents(map, tight) { @@ -42,8 +44,8 @@ function contents(map, tight) { return table } -// Insert a `node` into a `parent`. -function insert(node, parent, tight) { +// Insert an entry into `parent`. +function insert(entry, parent, tight) { var children = parent.children var length = children.length var last = children[length - 1] @@ -51,7 +53,7 @@ function insert(node, parent, tight) { var index var item - if (node.depth === 1) { + if (entry.depth === 1) { item = listItem() item.children.push({ @@ -60,30 +62,30 @@ function insert(node, parent, tight) { { type: LINK, title: null, - url: '#' + node.id, - children: [{type: TEXT, value: node.value}] + url: '#' + entry.id, + children: all(entry.children) } ] }) children.push(item) } else if (last && last.type === LIST_ITEM) { - insert(node, last, tight) + insert(entry, last, tight) } else if (last && last.type === LIST) { - node.depth-- + entry.depth-- - insert(node, last, tight) + insert(entry, last, tight) } else if (parent.type === LIST) { item = listItem() - insert(node, item, tight) + insert(entry, item, tight) children.push(item) } else { item = list() - node.depth-- + entry.depth-- - insert(node, item, tight) + insert(entry, item, tight) children.push(item) } @@ -129,6 +131,39 @@ function insert(node, parent, tight) { } } +function all(children) { + var result = [] + var length = children.length + var index = -1 + + while (++index < length) { + result = result.concat(one(children[index])) + } + + return result +} + +function one(node) { + var copy + + if (node.type === LINK || node.type === LINK_REFERENCE) { + return all(node.children) + } + + copy = extend({}, node) + + delete copy.children + delete copy.position + + copy = extend(true, {}, copy) + + if (node.children) { + copy.children = all(node.children) + } + + return copy +} + // Create a list. function list() { return {type: LIST, ordered: false, spread: false, children: []} diff --git a/lib/search.js b/lib/search.js index 17c1b7b..3e8f30c 100644 --- a/lib/search.js +++ b/lib/search.js @@ -63,7 +63,11 @@ function search(root, expression, settings) { } if (!lookingForToc && value && child.depth <= maxDepth) { - map.push({depth: child.depth, value: value, id: slugs.slug(id || value)}) + map.push({ + depth: child.depth, + children: child.children, + id: slugs.slug(id || value) + }) } } } diff --git a/package.json b/package.json index 592523b..b0ce5ae 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "index.js" ], "dependencies": { + "extend": "^3.0.2", "github-slugger": "^1.2.1", "mdast-util-to-string": "^1.0.5", "unist-util-is": "^2.1.2", @@ -32,10 +33,12 @@ "remark": "^10.0.0", "remark-attr": "^0.8.0", "remark-cli": "^6.0.0", + "remark-parse": "^6.0.3", "remark-preset-wooorm": "^4.0.0", "remark-usage": "^6.1.3", "tape": "^4.10.1", "tinyify": "^2.5.0", + "unified": "^7.1.0", "unist-builder": "^1.0.3", "xo": "^0.24.0" }, diff --git a/test/fixtures/normal-attr/config.json b/test/fixtures/normal-attr/config.json new file mode 100644 index 0000000..14e568f --- /dev/null +++ b/test/fixtures/normal-attr/config.json @@ -0,0 +1,3 @@ +{ + "useRemarkAttr": true +} diff --git a/test/fixtures/phrasing-content/config.json b/test/fixtures/phrasing-content/config.json new file mode 100644 index 0000000..be0fe09 --- /dev/null +++ b/test/fixtures/phrasing-content/config.json @@ -0,0 +1,5 @@ +{ + "remarkParseOptions": { + "footnotes": true + } +} diff --git a/test/fixtures/phrasing-content/input.md b/test/fixtures/phrasing-content/input.md new file mode 100644 index 0000000..a90fd8f --- /dev/null +++ b/test/fixtures/phrasing-content/input.md @@ -0,0 +1,29 @@ +# Text + +# *Emphasis* + +# **Importance** + +# ~~Strikethrough~~ + +# HTML + +# `inline.code()` + +# [^a footnote] + +# footnote reference [^1] + +# ![image](image.png) + +# ![image reference][image] + +# [link](example.com) + +# ![link reference][link] + +[^1]: footnote reference + +[image]: image.png + +[link]: example.com diff --git a/test/fixtures/phrasing-content/output.json b/test/fixtures/phrasing-content/output.json new file mode 100644 index 0000000..c1f6c9e --- /dev/null +++ b/test/fixtures/phrasing-content/output.json @@ -0,0 +1,328 @@ +{ + "index": null, + "endIndex": null, + "map": { + "type": "list", + "ordered": false, + "spread": false, + "children": [ + { + "type": "listItem", + "loose": false, + "spread": false, + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "link", + "title": null, + "url": "#text", + "children": [ + { + "type": "text", + "value": "Text" + } + ] + } + ] + } + ] + }, + { + "type": "listItem", + "loose": false, + "spread": false, + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "link", + "title": null, + "url": "#emphasis", + "children": [ + { + "type": "emphasis", + "children": [ + { + "type": "text", + "value": "Emphasis" + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "listItem", + "loose": false, + "spread": false, + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "link", + "title": null, + "url": "#importance", + "children": [ + { + "type": "strong", + "children": [ + { + "type": "text", + "value": "Importance" + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "listItem", + "loose": false, + "spread": false, + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "link", + "title": null, + "url": "#strikethrough", + "children": [ + { + "type": "delete", + "children": [ + { + "type": "text", + "value": "Strikethrough" + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "listItem", + "loose": false, + "spread": false, + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "link", + "title": null, + "url": "#ihtmli", + "children": [ + { + "type": "html", + "value": "" + }, + { + "type": "text", + "value": "HTML" + }, + { + "type": "html", + "value": "" + } + ] + } + ] + } + ] + }, + { + "type": "listItem", + "loose": false, + "spread": false, + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "link", + "title": null, + "url": "#inlinecode", + "children": [ + { + "type": "inlineCode", + "value": "inline.code()" + } + ] + } + ] + } + ] + }, + { + "type": "listItem", + "loose": false, + "spread": false, + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "link", + "title": null, + "url": "#a-footnote", + "children": [ + { + "type": "footnote", + "children": [ + { + "type": "text", + "value": "a footnote" + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "listItem", + "loose": false, + "spread": false, + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "link", + "title": null, + "url": "#footnote-reference", + "children": [ + { + "type": "text", + "value": "footnote reference " + }, + { + "type": "footnoteReference", + "identifier": "1", + "label": "1" + } + ] + } + ] + } + ] + }, + { + "type": "listItem", + "loose": false, + "spread": false, + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "link", + "title": null, + "url": "#image", + "children": [ + { + "type": "image", + "title": null, + "url": "image.png", + "alt": "image" + } + ] + } + ] + } + ] + }, + { + "type": "listItem", + "loose": false, + "spread": false, + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "link", + "title": null, + "url": "#image-reference", + "children": [ + { + "type": "imageReference", + "identifier": "image", + "label": "image", + "referenceType": "full", + "alt": "image reference" + } + ] + } + ] + } + ] + }, + { + "type": "listItem", + "loose": false, + "spread": false, + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "link", + "title": null, + "url": "#link", + "children": [ + { + "type": "text", + "value": "link" + } + ] + } + ] + } + ] + }, + { + "type": "listItem", + "loose": false, + "spread": false, + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "link", + "title": null, + "url": "#link-reference", + "children": [ + { + "type": "imageReference", + "identifier": "link", + "label": "link", + "referenceType": "full", + "alt": "link reference" + } + ] + } + ] + } + ] + } + ] + } +} diff --git a/test/fixtures/slug-for-images-and-links/output.json b/test/fixtures/slug-for-images-and-links/output.json index c6a96f0..c5f1b7c 100644 --- a/test/fixtures/slug-for-images-and-links/output.json +++ b/test/fixtures/slug-for-images-and-links/output.json @@ -46,8 +46,10 @@ "url": "#something-else", "children": [ { - "type": "text", - "value": "Something else" + "type": "image", + "title": null, + "url": "an-image.svg", + "alt": "Something else" } ] } @@ -69,8 +71,10 @@ "url": "#something-elsefi", "children": [ { - "type": "text", - "value": "Something elsefi" + "type": "image", + "title": "Something elsefi", + "url": "an-alt.jpeg", + "alt": null } ] } @@ -96,8 +100,10 @@ "url": "#another-title", "children": [ { - "type": "text", - "value": "another title" + "type": "image", + "title": "a title", + "url": "a-link.png", + "alt": "Something iffi" } ] } diff --git a/test/index.js b/test/index.js index 56c794b..ce0615b 100644 --- a/test/index.js +++ b/test/index.js @@ -2,7 +2,8 @@ var test = require('tape') var fs = require('fs') var path = require('path') -var remark = require('remark') +var unified = require('unified') +var remarkParse = require('remark-parse') var remarkAttr = require('remark-attr') var u = require('unist-builder') var toc = require('..') @@ -36,17 +37,19 @@ test('Fixtures', function(t) { var config = {} var expected = JSON.parse(output) var actual + var processor = unified() try { config = JSON.parse(fs.readFileSync(join(root, name, 'config.json'))) } catch (error) {} - actual = toc( - remark() - .use(remarkAttr) - .parse(input), - config - ) + processor.use(remarkParse, config.remarkParseOptions) + + if (config.useRemarkAttr) { + processor.use(remarkAttr) + } + + actual = toc(processor.parse(input), config) t.deepEqual(actual, expected, name) })