{"version":3,"file":"index.cjs","sources":["../src/footnote.ts","../src/references.ts","../src/footnotes.ts","../src/index.ts"],"sourcesContent":["import type { TokenizerAndRendererExtension, TokenizerThis } from 'marked'\nimport type { Footnote, Footnotes, LexerTokens } from './types.js'\n\n/**\n * Returns an extension object for parsing footnote definitions.\n */\nexport function createFootnote(lexer: LexerTokens, description: string) {\n  const footnotes: Footnotes = {\n    type: 'footnotes',\n    raw: description,\n    rawItems: [],\n    items: []\n  }\n\n  return {\n    name: 'footnote',\n    level: 'block',\n    childTokens: ['content'],\n    tokenizer(this: TokenizerThis, src: string) {\n      if (!lexer.hasFootnotes) {\n        this.lexer.tokens.push(footnotes)\n\n        lexer.tokens = this.lexer.tokens\n        lexer.hasFootnotes = true\n\n        // always begin with empty items\n        footnotes.rawItems = []\n        footnotes.items = []\n      }\n\n      const match =\n        /^\\[\\^([^\\]\\n]+)\\]:(?:[ \\t]+|[\\n]*?|$)([^\\n]*?(?:\\n|$)(?:\\n*?[ ]{4,}[^\\n]*)*)/.exec(\n          src\n        )\n\n      if (match) {\n        const [raw, label, text = ''] = match\n        let content = text.split('\\n').reduce((acc, curr) => {\n          return acc + '\\n' + curr.replace(/^(?:[ ]{4}|[\\t])/, '')\n        }, '')\n\n        const contentLastLine = content.trimEnd().split('\\n').pop()\n\n        content +=\n          // add lines after list, blockquote, codefence, and table\n          contentLastLine &&\n          /^[ \\t]*?[>\\-*][ ]|[`]{3,}$|^[ \\t]*?[|].+[|]$/.test(contentLastLine)\n            ? '\\n\\n'\n            : ''\n\n        const token: Footnote = {\n          type: 'footnote',\n          raw,\n          label,\n          refs: [],\n          content: this.lexer.blockTokens(content)\n        }\n\n        footnotes.rawItems.push(token)\n\n        return token\n      }\n    },\n    renderer() {\n      // skip it for now!\n      // we will render all `Footnote` through the footnotes renderer\n      return ''\n    }\n  } as TokenizerAndRendererExtension\n}\n","import type { TokenizerAndRendererExtension, TokenizerThis } from 'marked'\nimport type { FootnoteRef, Footnotes } from './types.js'\n\n/**\n * Returns an extension object for parsing inline footnote references.\n */\nexport function createFootnoteRef(prefixId: string, refMarkers = false) {\n  let order = 0\n\n  return {\n    name: 'footnoteRef',\n    level: 'inline',\n    tokenizer(this: TokenizerThis, src: string) {\n      const match = /^\\[\\^([^\\]\\n]+)\\]/.exec(src)\n\n      if (match) {\n        const [raw, label] = match\n        const footnotes = this.lexer.tokens[0] as Footnotes\n        const filteredRawItems = footnotes.rawItems.filter(\n          item => item.label === label\n        )\n\n        if (!filteredRawItems.length) return\n\n        const rawFootnote = filteredRawItems[0]\n        const footnote = footnotes.items.filter(item => item.label === label)[0]\n\n        const ref: FootnoteRef = {\n          type: 'footnoteRef',\n          raw,\n          id: '',\n          label\n        }\n\n        if (footnote) {\n          ref.id = footnote.refs[0].id\n          footnote.refs.push(ref)\n        } else {\n          order++\n          ref.id = String(order)\n          rawFootnote.refs.push(ref)\n          footnotes.items.push(rawFootnote)\n        }\n\n        return ref\n      }\n    },\n    renderer({ id, label }: FootnoteRef) {\n      order = 0 // reset order\n      const encodedLabel = encodeURIComponent(label)\n\n      return `<sup><a id=\"${prefixId}ref-${encodedLabel}\" href=\"#${\n        prefixId + encodedLabel\n      }\" data-${prefixId}ref aria-describedby=\"${prefixId}label\">${\n        refMarkers ? `[${id}]` : id\n      }</a></sup>`\n    }\n  } as TokenizerAndRendererExtension\n}\n","import type { RendererExtension, RendererThis } from 'marked'\nimport type { Footnotes } from './types.js'\n\n/**\n * Returns an extension object for rendering the list of footnotes.\n */\nexport function createFootnotes(\n  prefixId: string,\n  prefixData: string,\n  footnoteDivider: boolean,\n  sectionClass: string,\n  headingClass: string,\n  backRefLabel: string\n) {\n  return {\n    name: 'footnotes',\n    renderer(this: RendererThis, { raw, items = [] }: Footnotes) {\n      if (items.length === 0) return ''\n\n      const footnotesItemsHTML = items.reduce(\n        (acc, { label, content, refs }) => {\n          const encodedLabel = encodeURIComponent(label)\n          const parsedContent = this.parser.parse(content).trimEnd()\n          const isEndsWithP = parsedContent.endsWith('</p>')\n\n          let footnoteItem = `<li id=\"${prefixId + encodedLabel}\">\\n`\n          footnoteItem += isEndsWithP\n            ? parsedContent.replace(/<\\/p>$/, '')\n            : parsedContent\n\n          refs.forEach((_, i) => {\n            const ariaLabel = backRefLabel.replace('{0}', label)\n            footnoteItem += ` <a href=\"#${prefixId}ref-${encodedLabel}\" data-${prefixId}backref aria-label=\"${ariaLabel}\">${\n              i > 0 ? `↩<sup>${i + 1}</sup>` : '↩'\n            }</a>`\n          })\n\n          footnoteItem += isEndsWithP ? '</p>\\n' : '\\n'\n          footnoteItem += '</li>\\n'\n\n          return acc + footnoteItem\n        },\n        ''\n      )\n\n      let footnotesHTML = ''\n      if (footnoteDivider) {\n        footnotesHTML += `<hr data-${prefixData}footnotes>\\n`\n      }\n      let sectionAttrs = ''\n      if (sectionClass) {\n        sectionAttrs = ` class=\"${sectionClass}\"`\n      }\n      let headingAttrs = ''\n      if (headingClass) {\n        headingAttrs = ` class=\"${headingClass}\"`\n      }\n      footnotesHTML += `<section${sectionAttrs} data-${prefixData}footnotes>\\n`\n      footnotesHTML += `<h2 id=\"${prefixId}label\"${headingAttrs}>${raw.trimEnd()}</h2>\\n`\n      footnotesHTML += `<ol>\\n${footnotesItemsHTML}</ol>\\n`\n      footnotesHTML += '</section>\\n'\n\n      return footnotesHTML\n    }\n  } as RendererExtension\n}\n","import type { MarkedExtension } from 'marked'\nimport { createFootnote } from './footnote.js'\nimport { createFootnoteRef } from './references.js'\nimport { createFootnotes } from './footnotes.js'\nimport type { LexerTokens, Options } from './types.js'\n\n/**\n * A [marked](https://marked.js.org/) extension to support [GFM footnotes](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#footnotes).\n */\nexport default function markedFootnote(options: Options = {}): MarkedExtension {\n  const {\n    prefixId = 'footnote-',\n    prefixData = '',\n    description = 'Footnotes',\n    refMarkers = false,\n    footnoteDivider = false,\n    sectionClass = 'footnotes',\n    headingClass = 'sr-only',\n    backRefLabel = 'Back to reference {0}'\n  } = options\n  const lexer: LexerTokens = { hasFootnotes: false, tokens: [] }\n\n  return {\n    extensions: [\n      createFootnote(lexer, description),\n      createFootnoteRef(prefixId, refMarkers),\n      createFootnotes(\n        prefixId,\n        prefixData,\n        footnoteDivider,\n        sectionClass,\n        headingClass,\n        backRefLabel\n      )\n    ],\n    walkTokens(token) {\n      if (\n        token.type === 'footnotes' &&\n        lexer.tokens.indexOf(token) === 0 &&\n        token.items.length\n      ) {\n        lexer.tokens[0] = { type: 'space', raw: '' }\n        lexer.tokens.push(token)\n      }\n\n      if (lexer.hasFootnotes) lexer.hasFootnotes = false\n    }\n  }\n}\n\nexport type { Footnote, FootnoteRef, Footnotes, Options } from './types.js'\n"],"names":["createFootnote","lexer","description","footnotes","src","match","raw","label","text","content","acc","curr","contentLastLine","token","createFootnoteRef","prefixId","refMarkers","order","filteredRawItems","item","rawFootnote","footnote","ref","id","encodedLabel","createFootnotes","prefixData","footnoteDivider","sectionClass","headingClass","backRefLabel","items","footnotesItemsHTML","refs","parsedContent","isEndsWithP","footnoteItem","_","i","ariaLabel","footnotesHTML","sectionAttrs","headingAttrs","markedFootnote","options"],"mappings":"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"}