diff options
Diffstat (limited to 'node_modules/markdown-it-anchor/index.js')
| -rw-r--r-- | node_modules/markdown-it-anchor/index.js | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/node_modules/markdown-it-anchor/index.js b/node_modules/markdown-it-anchor/index.js new file mode 100644 index 00000000..1a087b58 --- /dev/null +++ b/node_modules/markdown-it-anchor/index.js @@ -0,0 +1,93 @@ +const slugify = (s) => encodeURIComponent(String(s).trim().toLowerCase().replace(/\s+/g, '-')) + +const position = { + false: 'push', + true: 'unshift' +} + +const hasProp = Object.prototype.hasOwnProperty + +const permalinkHref = slug => `#${slug}` + +const renderPermalink = (slug, opts, state, idx) => { + const space = () => Object.assign(new state.Token('text', '', 0), { content: ' ' }) + + const linkTokens = [ + Object.assign(new state.Token('link_open', 'a', 1), { + attrs: [ + ['class', opts.permalinkClass], + ['href', opts.permalinkHref(slug, state)], + ['aria-hidden', 'true'] + ] + }), + Object.assign(new state.Token('html_block', '', 0), { content: opts.permalinkSymbol }), + new state.Token('link_close', 'a', -1) + ] + + // `push` or `unshift` according to position option. + // Space is at the opposite side. + linkTokens[position[!opts.permalinkBefore]](space()) + state.tokens[idx + 1].children[position[opts.permalinkBefore]](...linkTokens) +} + +const uniqueSlug = (slug, slugs) => { + let uniq = slug + let i = 2 + while (hasProp.call(slugs, uniq)) uniq = `${slug}-${i++}` + slugs[uniq] = true + return uniq +} + +const isLevelSelectedNumber = selection => level => level >= selection +const isLevelSelectedArray = selection => level => selection.includes(level) + +const anchor = (md, opts) => { + opts = Object.assign({}, anchor.defaults, opts) + + md.core.ruler.push('anchor', state => { + const slugs = {} + const tokens = state.tokens + + const isLevelSelected = Array.isArray(opts.level) + ? isLevelSelectedArray(opts.level) + : isLevelSelectedNumber(opts.level) + + tokens + .filter(token => token.type === 'heading_open') + .filter(token => isLevelSelected(Number(token.tag.substr(1)))) + .forEach(token => { + // Aggregate the next token children text. + const title = tokens[tokens.indexOf(token) + 1].children + .filter(token => token.type === 'text' || token.type === 'code_inline') + .reduce((acc, t) => acc + t.content, '') + + let slug = token.attrGet('id') + + if (slug == null) { + slug = uniqueSlug(opts.slugify(title), slugs) + token.attrPush(['id', slug]) + } + + if (opts.permalink) { + opts.renderPermalink(slug, opts, state, tokens.indexOf(token)) + } + + if (opts.callback) { + opts.callback(token, { slug, title }) + } + }) + }) +} + +anchor.defaults = { + level: 1, + slugify, + permalink: false, + renderPermalink, + permalinkClass: 'header-anchor', + permalinkSymbol: 'ΒΆ', + permalinkBefore: false, + permalinkHref +} + +module.exports = anchor |
