micromark-extension-gfm-footnote
Advanced tools
Comparing version 2.0.0 to 2.1.0
@@ -0,10 +1,151 @@ | ||
export {gfmFootnoteHtml, defaultBackLabel} from './lib/html.js' | ||
export {gfmFootnote} from './lib/syntax.js' | ||
export { | ||
gfmFootnoteHtml, | ||
defaultBackLabel, | ||
type BackLabelTemplate, | ||
type Options as HtmlOptions | ||
} from './lib/html.js' | ||
/** | ||
* Generate a back label dynamically. | ||
* | ||
* For the following markdown: | ||
* | ||
* ```markdown | ||
* Alpha[^micromark], bravo[^micromark], and charlie[^remark]. | ||
* | ||
* [^remark]: things about remark | ||
* [^micromark]: things about micromark | ||
* ``` | ||
* | ||
* This function will be called with: | ||
* | ||
* * `0` and `0` for the backreference from `things about micromark` to | ||
* `alpha`, as it is the first used definition, and the first call to it | ||
* * `0` and `1` for the backreference from `things about micromark` to | ||
* `bravo`, as it is the first used definition, and the second call to it | ||
* * `1` and `0` for the backreference from `things about remark` to | ||
* `charlie`, as it is the second used definition | ||
* | ||
* @param referenceIndex | ||
* Index of the definition in the order that they are first referenced, | ||
* 0-indexed. | ||
* @param rereferenceIndex | ||
* Index of calls to the same definition, 0-indexed. | ||
* @returns | ||
* Back label to use when linking back from definitions to their reference. | ||
*/ | ||
export type BackLabelTemplate = ( | ||
referenceIndex: number, | ||
rereferenceIndex: number | ||
) => string | ||
/** | ||
* Configuration. | ||
*/ | ||
export interface HtmlOptions { | ||
/** | ||
* Prefix to use before the `id` attribute on footnotes to prevent them from | ||
* *clobbering* (default: `'user-content-'`). | ||
* | ||
* Pass `''` for trusted markdown and when you are careful with | ||
* polyfilling. | ||
* You could pass a different prefix. | ||
* | ||
* DOM clobbering is this: | ||
* | ||
* ```html | ||
* <p id="x"></p> | ||
* <script>alert(x) // `x` now refers to the `p#x` DOM element</script> | ||
* ``` | ||
* | ||
* The above example shows that elements are made available by browsers, by | ||
* their ID, on the `window` object. | ||
* This is a security risk because you might be expecting some other variable | ||
* at that place. | ||
* It can also break polyfills. | ||
* Using a prefix solves these problems. | ||
*/ | ||
clobberPrefix?: string | null | undefined | ||
/** | ||
* Textual label to use for the footnotes section (default: `'Footnotes'`). | ||
* | ||
* Change it when the markdown is not in English. | ||
* | ||
* This label is typically hidden visually (assuming a `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass different attributes with the `labelAttributes` option. | ||
*/ | ||
label?: string | null | undefined | ||
/** | ||
* Attributes to use on the footnote label (default: `'class="sr-only"'`). | ||
* | ||
* Change it to show the label and add other attributes. | ||
* | ||
* This label is typically hidden visually (assuming an `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass an empty string. | ||
* You can also add different attributes. | ||
* | ||
* > 👉 **Note**: `id="footnote-label"` is always added, because footnote | ||
* > calls use it with `aria-describedby` to provide an accessible label. | ||
*/ | ||
labelAttributes?: string | null | undefined | ||
/** | ||
* HTML tag name to use for the footnote label element (default: `'h2'`). | ||
* | ||
* Change it to match your document structure. | ||
* | ||
* This label is typically hidden visually (assuming a `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass different attributes with the `labelAttributes` option. | ||
*/ | ||
labelTagName?: string | null | undefined | ||
/** | ||
* Textual label to describe the backreference back to references (default: | ||
* `defaultBackLabel`). | ||
* | ||
* The default value is: | ||
* | ||
* ```js | ||
* function defaultBackLabel(referenceIndex, rereferenceIndex) { | ||
* return ( | ||
* 'Back to reference ' + | ||
* (referenceIndex + 1) + | ||
* (rereferenceIndex > 1 ? '-' + rereferenceIndex : '') | ||
* ) | ||
* } | ||
* ``` | ||
* | ||
* Change it when the markdown is not in English. | ||
* | ||
* This label is used in the `aria-label` attribute on each backreference | ||
* (the `↩` links). | ||
* It affects users of assistive technology. | ||
*/ | ||
backLabel?: BackLabelTemplate | string | null | undefined | ||
} | ||
/** | ||
* Augment types. | ||
*/ | ||
declare module 'micromark-util-types' { | ||
/** | ||
* Compile data. | ||
*/ | ||
interface CompileData { | ||
gfmFootnoteDefinitions?: Record<string, string> | ||
gfmFootnoteDefinitionStack?: Array<string> | ||
gfmFootnoteCallCounts?: Record<string, number> | ||
gfmFootnoteCallOrder?: Array<string> | ||
} | ||
/** | ||
* Parse context. | ||
*/ | ||
interface ParseContext { | ||
gfmFootnotes?: Array<string> | ||
} | ||
/** | ||
* Token types. | ||
*/ | ||
interface TokenTypeMap { | ||
@@ -23,13 +164,2 @@ gfmFootnoteCall: 'gfmFootnoteCall' | ||
} | ||
interface ParseContext { | ||
gfmFootnotes?: string[] | ||
} | ||
interface CompileData { | ||
gfmFootnoteDefinitions?: Record<string, string> | ||
gfmFootnoteDefinitionStack?: string[] | ||
gfmFootnoteCallCounts?: Record<string, number> | ||
gfmFootnoteCallOrder?: string[] | ||
} | ||
} |
@@ -12,6 +12,3 @@ /** | ||
*/ | ||
export function defaultBackLabel( | ||
referenceIndex: number, | ||
rereferenceIndex: number | ||
): string | ||
export function defaultBackLabel(referenceIndex: number, rereferenceIndex: number): string; | ||
/** | ||
@@ -27,118 +24,4 @@ * Create an extension for `micromark` to support GFM footnotes when | ||
*/ | ||
export function gfmFootnoteHtml( | ||
options?: Options | null | undefined | ||
): HtmlExtension | ||
export type HtmlExtension = import('micromark-util-types').HtmlExtension | ||
/** | ||
* Generate a back label dynamically. | ||
* | ||
* For the following markdown: | ||
* | ||
* ```markdown | ||
* Alpha[^micromark], bravo[^micromark], and charlie[^remark]. | ||
* | ||
* [^remark]: things about remark | ||
* [^micromark]: things about micromark | ||
* ``` | ||
* | ||
* This function will be called with: | ||
* | ||
* * `0` and `0` for the backreference from `things about micromark` to | ||
* `alpha`, as it is the first used definition, and the first call to it | ||
* * `0` and `1` for the backreference from `things about micromark` to | ||
* `bravo`, as it is the first used definition, and the second call to it | ||
* * `1` and `0` for the backreference from `things about remark` to | ||
* `charlie`, as it is the second used definition | ||
*/ | ||
export type BackLabelTemplate = ( | ||
referenceIndex: number, | ||
rereferenceIndex: number | ||
) => string | ||
/** | ||
* Configuration. | ||
*/ | ||
export type Options = { | ||
/** | ||
* Prefix to use before the `id` attribute on footnotes to prevent them from | ||
* *clobbering* (default: `'user-content-'`). | ||
* | ||
* Pass `''` for trusted markdown and when you are careful with | ||
* polyfilling. | ||
* You could pass a different prefix. | ||
* | ||
* DOM clobbering is this: | ||
* | ||
* ```html | ||
* <p id="x"></p> | ||
* <script>alert(x) // `x` now refers to the `p#x` DOM element</script> | ||
* ``` | ||
* | ||
* The above example shows that elements are made available by browsers, by | ||
* their ID, on the `window` object. | ||
* This is a security risk because you might be expecting some other variable | ||
* at that place. | ||
* It can also break polyfills. | ||
* Using a prefix solves these problems. | ||
*/ | ||
clobberPrefix?: string | null | undefined | ||
/** | ||
* Textual label to use for the footnotes section (default: `'Footnotes'`). | ||
* | ||
* Change it when the markdown is not in English. | ||
* | ||
* This label is typically hidden visually (assuming a `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass different attributes with the `labelAttributes` option. | ||
*/ | ||
label?: string | null | undefined | ||
/** | ||
* Attributes to use on the footnote label (default: `'class="sr-only"'`). | ||
* | ||
* Change it to show the label and add other attributes. | ||
* | ||
* This label is typically hidden visually (assuming an `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass an empty string. | ||
* You can also add different attributes. | ||
* | ||
* > 👉 **Note**: `id="footnote-label"` is always added, because footnote | ||
* > calls use it with `aria-describedby` to provide an accessible label. | ||
*/ | ||
labelAttributes?: string | null | undefined | ||
/** | ||
* HTML tag name to use for the footnote label element (default: `'h2'`). | ||
* | ||
* Change it to match your document structure. | ||
* | ||
* This label is typically hidden visually (assuming a `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass different attributes with the `labelAttributes` option. | ||
*/ | ||
labelTagName?: string | null | undefined | ||
/** | ||
* Textual label to describe the backreference back to references (default: | ||
* `defaultBackLabel`). | ||
* | ||
* The default value is: | ||
* | ||
* ```js | ||
* function defaultBackLabel(referenceIndex, rereferenceIndex) { | ||
* return ( | ||
* 'Back to reference ' + | ||
* (referenceIndex + 1) + | ||
* (rereferenceIndex > 1 ? '-' + rereferenceIndex : '') | ||
* ) | ||
* } | ||
* ``` | ||
* | ||
* Change it when the markdown is not in English. | ||
* | ||
* This label is used in the `aria-label` attribute on each backreference | ||
* (the `↩` links). | ||
* It affects users of assistive technology. | ||
*/ | ||
backLabel?: BackLabelTemplate | string | null | undefined | ||
} | ||
export function gfmFootnoteHtml(options?: Options | null | undefined): HtmlExtension; | ||
import type { HtmlOptions as Options } from 'micromark-extension-gfm-footnote'; | ||
import type { HtmlExtension } from 'micromark-util-types'; |
/** | ||
* @typedef {import('micromark-util-types').HtmlExtension} HtmlExtension | ||
* @import {HtmlOptions as Options} from 'micromark-extension-gfm-footnote' | ||
* @import {HtmlExtension} from 'micromark-util-types' | ||
*/ | ||
/** | ||
* @callback BackLabelTemplate | ||
* Generate a back label dynamically. | ||
* | ||
* For the following markdown: | ||
* | ||
* ```markdown | ||
* Alpha[^micromark], bravo[^micromark], and charlie[^remark]. | ||
* | ||
* [^remark]: things about remark | ||
* [^micromark]: things about micromark | ||
* ``` | ||
* | ||
* This function will be called with: | ||
* | ||
* * `0` and `0` for the backreference from `things about micromark` to | ||
* `alpha`, as it is the first used definition, and the first call to it | ||
* * `0` and `1` for the backreference from `things about micromark` to | ||
* `bravo`, as it is the first used definition, and the second call to it | ||
* * `1` and `0` for the backreference from `things about remark` to | ||
* `charlie`, as it is the second used definition | ||
* @param {number} referenceIndex | ||
* Index of the definition in the order that they are first referenced, | ||
* 0-indexed. | ||
* @param {number} rereferenceIndex | ||
* Index of calls to the same definition, 0-indexed. | ||
* @returns {string} | ||
* Back label to use when linking back from definitions to their reference. | ||
*/ | ||
/** | ||
* @typedef Options | ||
* Configuration. | ||
* @property {string | null | undefined} [clobberPrefix='user-content-'] | ||
* Prefix to use before the `id` attribute on footnotes to prevent them from | ||
* *clobbering* (default: `'user-content-'`). | ||
* | ||
* Pass `''` for trusted markdown and when you are careful with | ||
* polyfilling. | ||
* You could pass a different prefix. | ||
* | ||
* DOM clobbering is this: | ||
* | ||
* ```html | ||
* <p id="x"></p> | ||
* <script>alert(x) // `x` now refers to the `p#x` DOM element</script> | ||
* ``` | ||
* | ||
* The above example shows that elements are made available by browsers, by | ||
* their ID, on the `window` object. | ||
* This is a security risk because you might be expecting some other variable | ||
* at that place. | ||
* It can also break polyfills. | ||
* Using a prefix solves these problems. | ||
* @property {string | null | undefined} [label='Footnotes'] | ||
* Textual label to use for the footnotes section (default: `'Footnotes'`). | ||
* | ||
* Change it when the markdown is not in English. | ||
* | ||
* This label is typically hidden visually (assuming a `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass different attributes with the `labelAttributes` option. | ||
* @property {string | null | undefined} [labelAttributes='class="sr-only"'] | ||
* Attributes to use on the footnote label (default: `'class="sr-only"'`). | ||
* | ||
* Change it to show the label and add other attributes. | ||
* | ||
* This label is typically hidden visually (assuming an `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass an empty string. | ||
* You can also add different attributes. | ||
* | ||
* > 👉 **Note**: `id="footnote-label"` is always added, because footnote | ||
* > calls use it with `aria-describedby` to provide an accessible label. | ||
* @property {string | null | undefined} [labelTagName='h2'] | ||
* HTML tag name to use for the footnote label element (default: `'h2'`). | ||
* | ||
* Change it to match your document structure. | ||
* | ||
* This label is typically hidden visually (assuming a `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass different attributes with the `labelAttributes` option. | ||
* @property {BackLabelTemplate | string | null | undefined} [backLabel] | ||
* Textual label to describe the backreference back to references (default: | ||
* `defaultBackLabel`). | ||
* | ||
* The default value is: | ||
* | ||
* ```js | ||
* function defaultBackLabel(referenceIndex, rereferenceIndex) { | ||
* return ( | ||
* 'Back to reference ' + | ||
* (referenceIndex + 1) + | ||
* (rereferenceIndex > 1 ? '-' + rereferenceIndex : '') | ||
* ) | ||
* } | ||
* ``` | ||
* | ||
* Change it when the markdown is not in English. | ||
* | ||
* This label is used in the `aria-label` attribute on each backreference | ||
* (the `↩` links). | ||
* It affects users of assistive technology. | ||
*/ | ||
import {ok as assert} from 'devlop' | ||
@@ -114,0 +7,0 @@ import {normalizeIdentifier} from 'micromark-util-normalize-identifier' |
@@ -8,10 +8,3 @@ /** | ||
*/ | ||
export function gfmFootnote(): Extension | ||
export type Event = import('micromark-util-types').Event | ||
export type Exiter = import('micromark-util-types').Exiter | ||
export type Extension = import('micromark-util-types').Extension | ||
export type Resolver = import('micromark-util-types').Resolver | ||
export type State = import('micromark-util-types').State | ||
export type Token = import('micromark-util-types').Token | ||
export type TokenizeContext = import('micromark-util-types').TokenizeContext | ||
export type Tokenizer = import('micromark-util-types').Tokenizer | ||
export function gfmFootnote(): Extension; | ||
import type { Extension } from 'micromark-util-types'; |
/** | ||
* @typedef {import('micromark-util-types').Event} Event | ||
* @typedef {import('micromark-util-types').Exiter} Exiter | ||
* @typedef {import('micromark-util-types').Extension} Extension | ||
* @typedef {import('micromark-util-types').Resolver} Resolver | ||
* @typedef {import('micromark-util-types').State} State | ||
* @typedef {import('micromark-util-types').Token} Token | ||
* @typedef {import('micromark-util-types').TokenizeContext} TokenizeContext | ||
* @typedef {import('micromark-util-types').Tokenizer} Tokenizer | ||
* @import {Event, Exiter, Extension, Resolver, State, Token, TokenizeContext, Tokenizer} from 'micromark-util-types' | ||
*/ | ||
@@ -39,2 +32,3 @@ | ||
[codes.leftSquareBracket]: { | ||
name: 'gfmFootnoteDefinition', | ||
tokenize: tokenizeDefinitionStart, | ||
@@ -46,4 +40,8 @@ continuation: {tokenize: tokenizeDefinitionContinuation}, | ||
text: { | ||
[codes.leftSquareBracket]: {tokenize: tokenizeGfmFootnoteCall}, | ||
[codes.leftSquareBracket]: { | ||
name: 'gfmFootnoteCall', | ||
tokenize: tokenizeGfmFootnoteCall | ||
}, | ||
[codes.rightSquareBracket]: { | ||
name: 'gfmPotentialFootnoteCall', | ||
add: 'after', | ||
@@ -50,0 +48,0 @@ tokenize: tokenizePotentialGfmFootnoteCall, |
164
index.d.ts
@@ -0,10 +1,151 @@ | ||
export {gfmFootnoteHtml, defaultBackLabel} from './lib/html.js' | ||
export {gfmFootnote} from './lib/syntax.js' | ||
export { | ||
gfmFootnoteHtml, | ||
defaultBackLabel, | ||
type BackLabelTemplate, | ||
type Options as HtmlOptions | ||
} from './lib/html.js' | ||
/** | ||
* Generate a back label dynamically. | ||
* | ||
* For the following markdown: | ||
* | ||
* ```markdown | ||
* Alpha[^micromark], bravo[^micromark], and charlie[^remark]. | ||
* | ||
* [^remark]: things about remark | ||
* [^micromark]: things about micromark | ||
* ``` | ||
* | ||
* This function will be called with: | ||
* | ||
* * `0` and `0` for the backreference from `things about micromark` to | ||
* `alpha`, as it is the first used definition, and the first call to it | ||
* * `0` and `1` for the backreference from `things about micromark` to | ||
* `bravo`, as it is the first used definition, and the second call to it | ||
* * `1` and `0` for the backreference from `things about remark` to | ||
* `charlie`, as it is the second used definition | ||
* | ||
* @param referenceIndex | ||
* Index of the definition in the order that they are first referenced, | ||
* 0-indexed. | ||
* @param rereferenceIndex | ||
* Index of calls to the same definition, 0-indexed. | ||
* @returns | ||
* Back label to use when linking back from definitions to their reference. | ||
*/ | ||
export type BackLabelTemplate = ( | ||
referenceIndex: number, | ||
rereferenceIndex: number | ||
) => string | ||
/** | ||
* Configuration. | ||
*/ | ||
export interface HtmlOptions { | ||
/** | ||
* Prefix to use before the `id` attribute on footnotes to prevent them from | ||
* *clobbering* (default: `'user-content-'`). | ||
* | ||
* Pass `''` for trusted markdown and when you are careful with | ||
* polyfilling. | ||
* You could pass a different prefix. | ||
* | ||
* DOM clobbering is this: | ||
* | ||
* ```html | ||
* <p id="x"></p> | ||
* <script>alert(x) // `x` now refers to the `p#x` DOM element</script> | ||
* ``` | ||
* | ||
* The above example shows that elements are made available by browsers, by | ||
* their ID, on the `window` object. | ||
* This is a security risk because you might be expecting some other variable | ||
* at that place. | ||
* It can also break polyfills. | ||
* Using a prefix solves these problems. | ||
*/ | ||
clobberPrefix?: string | null | undefined | ||
/** | ||
* Textual label to use for the footnotes section (default: `'Footnotes'`). | ||
* | ||
* Change it when the markdown is not in English. | ||
* | ||
* This label is typically hidden visually (assuming a `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass different attributes with the `labelAttributes` option. | ||
*/ | ||
label?: string | null | undefined | ||
/** | ||
* Attributes to use on the footnote label (default: `'class="sr-only"'`). | ||
* | ||
* Change it to show the label and add other attributes. | ||
* | ||
* This label is typically hidden visually (assuming an `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass an empty string. | ||
* You can also add different attributes. | ||
* | ||
* > 👉 **Note**: `id="footnote-label"` is always added, because footnote | ||
* > calls use it with `aria-describedby` to provide an accessible label. | ||
*/ | ||
labelAttributes?: string | null | undefined | ||
/** | ||
* HTML tag name to use for the footnote label element (default: `'h2'`). | ||
* | ||
* Change it to match your document structure. | ||
* | ||
* This label is typically hidden visually (assuming a `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass different attributes with the `labelAttributes` option. | ||
*/ | ||
labelTagName?: string | null | undefined | ||
/** | ||
* Textual label to describe the backreference back to references (default: | ||
* `defaultBackLabel`). | ||
* | ||
* The default value is: | ||
* | ||
* ```js | ||
* function defaultBackLabel(referenceIndex, rereferenceIndex) { | ||
* return ( | ||
* 'Back to reference ' + | ||
* (referenceIndex + 1) + | ||
* (rereferenceIndex > 1 ? '-' + rereferenceIndex : '') | ||
* ) | ||
* } | ||
* ``` | ||
* | ||
* Change it when the markdown is not in English. | ||
* | ||
* This label is used in the `aria-label` attribute on each backreference | ||
* (the `↩` links). | ||
* It affects users of assistive technology. | ||
*/ | ||
backLabel?: BackLabelTemplate | string | null | undefined | ||
} | ||
/** | ||
* Augment types. | ||
*/ | ||
declare module 'micromark-util-types' { | ||
/** | ||
* Compile data. | ||
*/ | ||
interface CompileData { | ||
gfmFootnoteDefinitions?: Record<string, string> | ||
gfmFootnoteDefinitionStack?: Array<string> | ||
gfmFootnoteCallCounts?: Record<string, number> | ||
gfmFootnoteCallOrder?: Array<string> | ||
} | ||
/** | ||
* Parse context. | ||
*/ | ||
interface ParseContext { | ||
gfmFootnotes?: Array<string> | ||
} | ||
/** | ||
* Token types. | ||
*/ | ||
interface TokenTypeMap { | ||
@@ -23,13 +164,2 @@ gfmFootnoteCall: 'gfmFootnoteCall' | ||
} | ||
interface ParseContext { | ||
gfmFootnotes?: string[] | ||
} | ||
interface CompileData { | ||
gfmFootnoteDefinitions?: Record<string, string> | ||
gfmFootnoteDefinitionStack?: string[] | ||
gfmFootnoteCallCounts?: Record<string, number> | ||
gfmFootnoteCallOrder?: string[] | ||
} | ||
} |
// Note: types are exported from `dev/index.d.ts`. | ||
export {gfmFootnote} from './lib/syntax.js' | ||
export {gfmFootnoteHtml, defaultBackLabel} from './lib/html.js' | ||
export { gfmFootnote } from './lib/syntax.js'; | ||
export { gfmFootnoteHtml, defaultBackLabel } from './lib/html.js'; |
@@ -12,6 +12,3 @@ /** | ||
*/ | ||
export function defaultBackLabel( | ||
referenceIndex: number, | ||
rereferenceIndex: number | ||
): string | ||
export function defaultBackLabel(referenceIndex: number, rereferenceIndex: number): string; | ||
/** | ||
@@ -27,118 +24,4 @@ * Create an extension for `micromark` to support GFM footnotes when | ||
*/ | ||
export function gfmFootnoteHtml( | ||
options?: Options | null | undefined | ||
): HtmlExtension | ||
export type HtmlExtension = import('micromark-util-types').HtmlExtension | ||
/** | ||
* Generate a back label dynamically. | ||
* | ||
* For the following markdown: | ||
* | ||
* ```markdown | ||
* Alpha[^micromark], bravo[^micromark], and charlie[^remark]. | ||
* | ||
* [^remark]: things about remark | ||
* [^micromark]: things about micromark | ||
* ``` | ||
* | ||
* This function will be called with: | ||
* | ||
* * `0` and `0` for the backreference from `things about micromark` to | ||
* `alpha`, as it is the first used definition, and the first call to it | ||
* * `0` and `1` for the backreference from `things about micromark` to | ||
* `bravo`, as it is the first used definition, and the second call to it | ||
* * `1` and `0` for the backreference from `things about remark` to | ||
* `charlie`, as it is the second used definition | ||
*/ | ||
export type BackLabelTemplate = ( | ||
referenceIndex: number, | ||
rereferenceIndex: number | ||
) => string | ||
/** | ||
* Configuration. | ||
*/ | ||
export type Options = { | ||
/** | ||
* Prefix to use before the `id` attribute on footnotes to prevent them from | ||
* *clobbering* (default: `'user-content-'`). | ||
* | ||
* Pass `''` for trusted markdown and when you are careful with | ||
* polyfilling. | ||
* You could pass a different prefix. | ||
* | ||
* DOM clobbering is this: | ||
* | ||
* ```html | ||
* <p id="x"></p> | ||
* <script>alert(x) // `x` now refers to the `p#x` DOM element</script> | ||
* ``` | ||
* | ||
* The above example shows that elements are made available by browsers, by | ||
* their ID, on the `window` object. | ||
* This is a security risk because you might be expecting some other variable | ||
* at that place. | ||
* It can also break polyfills. | ||
* Using a prefix solves these problems. | ||
*/ | ||
clobberPrefix?: string | null | undefined | ||
/** | ||
* Textual label to use for the footnotes section (default: `'Footnotes'`). | ||
* | ||
* Change it when the markdown is not in English. | ||
* | ||
* This label is typically hidden visually (assuming a `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass different attributes with the `labelAttributes` option. | ||
*/ | ||
label?: string | null | undefined | ||
/** | ||
* Attributes to use on the footnote label (default: `'class="sr-only"'`). | ||
* | ||
* Change it to show the label and add other attributes. | ||
* | ||
* This label is typically hidden visually (assuming an `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass an empty string. | ||
* You can also add different attributes. | ||
* | ||
* > 👉 **Note**: `id="footnote-label"` is always added, because footnote | ||
* > calls use it with `aria-describedby` to provide an accessible label. | ||
*/ | ||
labelAttributes?: string | null | undefined | ||
/** | ||
* HTML tag name to use for the footnote label element (default: `'h2'`). | ||
* | ||
* Change it to match your document structure. | ||
* | ||
* This label is typically hidden visually (assuming a `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass different attributes with the `labelAttributes` option. | ||
*/ | ||
labelTagName?: string | null | undefined | ||
/** | ||
* Textual label to describe the backreference back to references (default: | ||
* `defaultBackLabel`). | ||
* | ||
* The default value is: | ||
* | ||
* ```js | ||
* function defaultBackLabel(referenceIndex, rereferenceIndex) { | ||
* return ( | ||
* 'Back to reference ' + | ||
* (referenceIndex + 1) + | ||
* (rereferenceIndex > 1 ? '-' + rereferenceIndex : '') | ||
* ) | ||
* } | ||
* ``` | ||
* | ||
* Change it when the markdown is not in English. | ||
* | ||
* This label is used in the `aria-label` attribute on each backreference | ||
* (the `↩` links). | ||
* It affects users of assistive technology. | ||
*/ | ||
backLabel?: BackLabelTemplate | string | null | undefined | ||
} | ||
export function gfmFootnoteHtml(options?: Options | null | undefined): HtmlExtension; | ||
import type { HtmlOptions as Options } from 'micromark-extension-gfm-footnote'; | ||
import type { HtmlExtension } from 'micromark-util-types'; |
320
lib/html.js
/** | ||
* @typedef {import('micromark-util-types').HtmlExtension} HtmlExtension | ||
* @import {HtmlOptions as Options} from 'micromark-extension-gfm-footnote' | ||
* @import {HtmlExtension} from 'micromark-util-types' | ||
*/ | ||
/** | ||
* @callback BackLabelTemplate | ||
* Generate a back label dynamically. | ||
* | ||
* For the following markdown: | ||
* | ||
* ```markdown | ||
* Alpha[^micromark], bravo[^micromark], and charlie[^remark]. | ||
* | ||
* [^remark]: things about remark | ||
* [^micromark]: things about micromark | ||
* ``` | ||
* | ||
* This function will be called with: | ||
* | ||
* * `0` and `0` for the backreference from `things about micromark` to | ||
* `alpha`, as it is the first used definition, and the first call to it | ||
* * `0` and `1` for the backreference from `things about micromark` to | ||
* `bravo`, as it is the first used definition, and the second call to it | ||
* * `1` and `0` for the backreference from `things about remark` to | ||
* `charlie`, as it is the second used definition | ||
* @param {number} referenceIndex | ||
* Index of the definition in the order that they are first referenced, | ||
* 0-indexed. | ||
* @param {number} rereferenceIndex | ||
* Index of calls to the same definition, 0-indexed. | ||
* @returns {string} | ||
* Back label to use when linking back from definitions to their reference. | ||
*/ | ||
import { normalizeIdentifier } from 'micromark-util-normalize-identifier'; | ||
import { sanitizeUri } from 'micromark-util-sanitize-uri'; | ||
const own = {}.hasOwnProperty; | ||
/** | ||
* @typedef Options | ||
* Configuration. | ||
* @property {string | null | undefined} [clobberPrefix='user-content-'] | ||
* Prefix to use before the `id` attribute on footnotes to prevent them from | ||
* *clobbering* (default: `'user-content-'`). | ||
* | ||
* Pass `''` for trusted markdown and when you are careful with | ||
* polyfilling. | ||
* You could pass a different prefix. | ||
* | ||
* DOM clobbering is this: | ||
* | ||
* ```html | ||
* <p id="x"></p> | ||
* <script>alert(x) // `x` now refers to the `p#x` DOM element</script> | ||
* ``` | ||
* | ||
* The above example shows that elements are made available by browsers, by | ||
* their ID, on the `window` object. | ||
* This is a security risk because you might be expecting some other variable | ||
* at that place. | ||
* It can also break polyfills. | ||
* Using a prefix solves these problems. | ||
* @property {string | null | undefined} [label='Footnotes'] | ||
* Textual label to use for the footnotes section (default: `'Footnotes'`). | ||
* | ||
* Change it when the markdown is not in English. | ||
* | ||
* This label is typically hidden visually (assuming a `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass different attributes with the `labelAttributes` option. | ||
* @property {string | null | undefined} [labelAttributes='class="sr-only"'] | ||
* Attributes to use on the footnote label (default: `'class="sr-only"'`). | ||
* | ||
* Change it to show the label and add other attributes. | ||
* | ||
* This label is typically hidden visually (assuming an `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass an empty string. | ||
* You can also add different attributes. | ||
* | ||
* > 👉 **Note**: `id="footnote-label"` is always added, because footnote | ||
* > calls use it with `aria-describedby` to provide an accessible label. | ||
* @property {string | null | undefined} [labelTagName='h2'] | ||
* HTML tag name to use for the footnote label element (default: `'h2'`). | ||
* | ||
* Change it to match your document structure. | ||
* | ||
* This label is typically hidden visually (assuming a `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass different attributes with the `labelAttributes` option. | ||
* @property {BackLabelTemplate | string | null | undefined} [backLabel] | ||
* Textual label to describe the backreference back to references (default: | ||
* `defaultBackLabel`). | ||
* | ||
* The default value is: | ||
* | ||
* ```js | ||
* function defaultBackLabel(referenceIndex, rereferenceIndex) { | ||
* return ( | ||
* 'Back to reference ' + | ||
* (referenceIndex + 1) + | ||
* (rereferenceIndex > 1 ? '-' + rereferenceIndex : '') | ||
* ) | ||
* } | ||
* ``` | ||
* | ||
* Change it when the markdown is not in English. | ||
* | ||
* This label is used in the `aria-label` attribute on each backreference | ||
* (the `↩` links). | ||
* It affects users of assistive technology. | ||
*/ | ||
import {normalizeIdentifier} from 'micromark-util-normalize-identifier' | ||
import {sanitizeUri} from 'micromark-util-sanitize-uri' | ||
const own = {}.hasOwnProperty | ||
/** @type {Options} */ | ||
const emptyOptions = {} | ||
const emptyOptions = {}; | ||
@@ -132,7 +25,3 @@ /** | ||
export function defaultBackLabel(referenceIndex, rereferenceIndex) { | ||
return ( | ||
'Back to reference ' + | ||
(referenceIndex + 1) + | ||
(rereferenceIndex > 1 ? '-' + rereferenceIndex : '') | ||
) | ||
return 'Back to reference ' + (referenceIndex + 1) + (rereferenceIndex > 1 ? '-' + rereferenceIndex : ''); | ||
} | ||
@@ -151,25 +40,19 @@ | ||
export function gfmFootnoteHtml(options) { | ||
const config = options || emptyOptions | ||
const label = config.label || 'Footnotes' | ||
const labelTagName = config.labelTagName || 'h2' | ||
const labelAttributes = | ||
config.labelAttributes === null || config.labelAttributes === undefined | ||
? 'class="sr-only"' | ||
: config.labelAttributes | ||
const backLabel = config.backLabel || defaultBackLabel | ||
const clobberPrefix = | ||
config.clobberPrefix === null || config.clobberPrefix === undefined | ||
? 'user-content-' | ||
: config.clobberPrefix | ||
const config = options || emptyOptions; | ||
const label = config.label || 'Footnotes'; | ||
const labelTagName = config.labelTagName || 'h2'; | ||
const labelAttributes = config.labelAttributes === null || config.labelAttributes === undefined ? 'class="sr-only"' : config.labelAttributes; | ||
const backLabel = config.backLabel || defaultBackLabel; | ||
const clobberPrefix = config.clobberPrefix === null || config.clobberPrefix === undefined ? 'user-content-' : config.clobberPrefix; | ||
return { | ||
enter: { | ||
gfmFootnoteDefinition() { | ||
const stack = this.getData('tightStack') | ||
stack.push(false) | ||
const stack = this.getData('tightStack'); | ||
stack.push(false); | ||
}, | ||
gfmFootnoteDefinitionLabelString() { | ||
this.buffer() | ||
this.buffer(); | ||
}, | ||
gfmFootnoteCallString() { | ||
this.buffer() | ||
this.buffer(); | ||
} | ||
@@ -179,135 +62,96 @@ }, | ||
gfmFootnoteDefinition() { | ||
let definitions = this.getData('gfmFootnoteDefinitions') | ||
const footnoteStack = this.getData('gfmFootnoteDefinitionStack') | ||
const tightStack = this.getData('tightStack') | ||
const current = footnoteStack.pop() | ||
const value = this.resume() | ||
let definitions = this.getData('gfmFootnoteDefinitions'); | ||
const footnoteStack = this.getData('gfmFootnoteDefinitionStack'); | ||
const tightStack = this.getData('tightStack'); | ||
const current = footnoteStack.pop(); | ||
const value = this.resume(); | ||
if (!definitions) { | ||
this.setData('gfmFootnoteDefinitions', (definitions = {})) | ||
this.setData('gfmFootnoteDefinitions', definitions = {}); | ||
} | ||
if (!own.call(definitions, current)) definitions[current] = value | ||
tightStack.pop() | ||
this.setData('slurpOneLineEnding', true) | ||
if (!own.call(definitions, current)) definitions[current] = value; | ||
tightStack.pop(); | ||
this.setData('slurpOneLineEnding', true); | ||
// “Hack” to prevent a line ending from showing up if we’re in a definition in | ||
// an empty list item. | ||
this.setData('lastWasTag') | ||
this.setData('lastWasTag'); | ||
}, | ||
gfmFootnoteDefinitionLabelString(token) { | ||
let footnoteStack = this.getData('gfmFootnoteDefinitionStack') | ||
let footnoteStack = this.getData('gfmFootnoteDefinitionStack'); | ||
if (!footnoteStack) { | ||
this.setData('gfmFootnoteDefinitionStack', (footnoteStack = [])) | ||
this.setData('gfmFootnoteDefinitionStack', footnoteStack = []); | ||
} | ||
footnoteStack.push(normalizeIdentifier(this.sliceSerialize(token))) | ||
this.resume() // Drop the label. | ||
this.buffer() // Get ready for a value. | ||
footnoteStack.push(normalizeIdentifier(this.sliceSerialize(token))); | ||
this.resume(); // Drop the label. | ||
this.buffer(); // Get ready for a value. | ||
}, | ||
gfmFootnoteCallString(token) { | ||
let calls = this.getData('gfmFootnoteCallOrder') | ||
let counts = this.getData('gfmFootnoteCallCounts') | ||
const id = normalizeIdentifier(this.sliceSerialize(token)) | ||
let calls = this.getData('gfmFootnoteCallOrder'); | ||
let counts = this.getData('gfmFootnoteCallCounts'); | ||
const id = normalizeIdentifier(this.sliceSerialize(token)); | ||
/** @type {number} */ | ||
let counter | ||
this.resume() | ||
if (!calls) this.setData('gfmFootnoteCallOrder', (calls = [])) | ||
if (!counts) this.setData('gfmFootnoteCallCounts', (counts = {})) | ||
const index = calls.indexOf(id) | ||
const safeId = sanitizeUri(id.toLowerCase()) | ||
let counter; | ||
this.resume(); | ||
if (!calls) this.setData('gfmFootnoteCallOrder', calls = []); | ||
if (!counts) this.setData('gfmFootnoteCallCounts', counts = {}); | ||
const index = calls.indexOf(id); | ||
const safeId = sanitizeUri(id.toLowerCase()); | ||
if (index === -1) { | ||
calls.push(id) | ||
counts[id] = 1 | ||
counter = calls.length | ||
calls.push(id); | ||
counts[id] = 1; | ||
counter = calls.length; | ||
} else { | ||
counts[id]++ | ||
counter = index + 1 | ||
counts[id]++; | ||
counter = index + 1; | ||
} | ||
const reuseCounter = counts[id] | ||
this.tag( | ||
'<sup><a href="#' + | ||
clobberPrefix + | ||
'fn-' + | ||
safeId + | ||
'" id="' + | ||
clobberPrefix + | ||
'fnref-' + | ||
safeId + | ||
(reuseCounter > 1 ? '-' + reuseCounter : '') + | ||
'" data-footnote-ref="" aria-describedby="footnote-label">' + | ||
String(counter) + | ||
'</a></sup>' | ||
) | ||
const reuseCounter = counts[id]; | ||
this.tag('<sup><a href="#' + clobberPrefix + 'fn-' + safeId + '" id="' + clobberPrefix + 'fnref-' + safeId + (reuseCounter > 1 ? '-' + reuseCounter : '') + '" data-footnote-ref="" aria-describedby="footnote-label">' + String(counter) + '</a></sup>'); | ||
}, | ||
null() { | ||
const calls = this.getData('gfmFootnoteCallOrder') || [] | ||
const counts = this.getData('gfmFootnoteCallCounts') || {} | ||
const definitions = this.getData('gfmFootnoteDefinitions') || {} | ||
let index = -1 | ||
const calls = this.getData('gfmFootnoteCallOrder') || []; | ||
const counts = this.getData('gfmFootnoteCallCounts') || {}; | ||
const definitions = this.getData('gfmFootnoteDefinitions') || {}; | ||
let index = -1; | ||
if (calls.length > 0) { | ||
this.lineEndingIfNeeded() | ||
this.tag( | ||
'<section data-footnotes="" class="footnotes"><' + | ||
labelTagName + | ||
' id="footnote-label"' + | ||
(labelAttributes ? ' ' + labelAttributes : '') + | ||
'>' | ||
) | ||
this.raw(this.encode(label)) | ||
this.tag('</' + labelTagName + '>') | ||
this.lineEndingIfNeeded() | ||
this.tag('<ol>') | ||
this.lineEndingIfNeeded(); | ||
this.tag('<section data-footnotes="" class="footnotes"><' + labelTagName + ' id="footnote-label"' + (labelAttributes ? ' ' + labelAttributes : '') + '>'); | ||
this.raw(this.encode(label)); | ||
this.tag('</' + labelTagName + '>'); | ||
this.lineEndingIfNeeded(); | ||
this.tag('<ol>'); | ||
} | ||
while (++index < calls.length) { | ||
// Called definitions are always defined. | ||
const id = calls[index] | ||
const safeId = sanitizeUri(id.toLowerCase()) | ||
let referenceIndex = 0 | ||
const id = calls[index]; | ||
const safeId = sanitizeUri(id.toLowerCase()); | ||
let referenceIndex = 0; | ||
/** @type {Array<string>} */ | ||
const references = [] | ||
const references = []; | ||
while (++referenceIndex <= counts[id]) { | ||
references.push( | ||
'<a href="#' + | ||
clobberPrefix + | ||
'fnref-' + | ||
safeId + | ||
(referenceIndex > 1 ? '-' + referenceIndex : '') + | ||
'" data-footnote-backref="" aria-label="' + | ||
this.encode( | ||
typeof backLabel === 'string' | ||
? backLabel | ||
: backLabel(index, referenceIndex) | ||
) + | ||
'" class="data-footnote-backref">↩' + | ||
(referenceIndex > 1 | ||
? '<sup>' + referenceIndex + '</sup>' | ||
: '') + | ||
'</a>' | ||
) | ||
references.push('<a href="#' + clobberPrefix + 'fnref-' + safeId + (referenceIndex > 1 ? '-' + referenceIndex : '') + '" data-footnote-backref="" aria-label="' + this.encode(typeof backLabel === 'string' ? backLabel : backLabel(index, referenceIndex)) + '" class="data-footnote-backref">↩' + (referenceIndex > 1 ? '<sup>' + referenceIndex + '</sup>' : '') + '</a>'); | ||
} | ||
const reference = references.join(' ') | ||
let injected = false | ||
this.lineEndingIfNeeded() | ||
this.tag('<li id="' + clobberPrefix + 'fn-' + safeId + '">') | ||
this.lineEndingIfNeeded() | ||
this.tag( | ||
definitions[id].replace(/<\/p>(?:\r?\n|\r)?$/, function ($0) { | ||
injected = true | ||
return ' ' + reference + $0 | ||
}) | ||
) | ||
const reference = references.join(' '); | ||
let injected = false; | ||
this.lineEndingIfNeeded(); | ||
this.tag('<li id="' + clobberPrefix + 'fn-' + safeId + '">'); | ||
this.lineEndingIfNeeded(); | ||
this.tag(definitions[id].replace(/<\/p>(?:\r?\n|\r)?$/, function ($0) { | ||
injected = true; | ||
return ' ' + reference + $0; | ||
})); | ||
if (!injected) { | ||
this.lineEndingIfNeeded() | ||
this.tag(reference) | ||
this.lineEndingIfNeeded(); | ||
this.tag(reference); | ||
} | ||
this.lineEndingIfNeeded() | ||
this.tag('</li>') | ||
this.lineEndingIfNeeded(); | ||
this.tag('</li>'); | ||
} | ||
if (calls.length > 0) { | ||
this.lineEndingIfNeeded() | ||
this.tag('</ol>') | ||
this.lineEndingIfNeeded() | ||
this.tag('</section>') | ||
this.lineEndingIfNeeded(); | ||
this.tag('</ol>'); | ||
this.lineEndingIfNeeded(); | ||
this.tag('</section>'); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
} |
@@ -8,10 +8,3 @@ /** | ||
*/ | ||
export function gfmFootnote(): Extension | ||
export type Event = import('micromark-util-types').Event | ||
export type Exiter = import('micromark-util-types').Exiter | ||
export type Extension = import('micromark-util-types').Extension | ||
export type Resolver = import('micromark-util-types').Resolver | ||
export type State = import('micromark-util-types').State | ||
export type Token = import('micromark-util-types').Token | ||
export type TokenizeContext = import('micromark-util-types').TokenizeContext | ||
export type Tokenizer = import('micromark-util-types').Tokenizer | ||
export function gfmFootnote(): Extension; | ||
import type { Extension } from 'micromark-util-types'; |
/** | ||
* @typedef {import('micromark-util-types').Event} Event | ||
* @typedef {import('micromark-util-types').Exiter} Exiter | ||
* @typedef {import('micromark-util-types').Extension} Extension | ||
* @typedef {import('micromark-util-types').Resolver} Resolver | ||
* @typedef {import('micromark-util-types').State} State | ||
* @typedef {import('micromark-util-types').Token} Token | ||
* @typedef {import('micromark-util-types').TokenizeContext} TokenizeContext | ||
* @typedef {import('micromark-util-types').Tokenizer} Tokenizer | ||
* @import {Event, Exiter, Extension, Resolver, State, Token, TokenizeContext, Tokenizer} from 'micromark-util-types' | ||
*/ | ||
import {blankLine} from 'micromark-core-commonmark' | ||
import {factorySpace} from 'micromark-factory-space' | ||
import {markdownLineEndingOrSpace} from 'micromark-util-character' | ||
import {normalizeIdentifier} from 'micromark-util-normalize-identifier' | ||
import { blankLine } from 'micromark-core-commonmark'; | ||
import { factorySpace } from 'micromark-factory-space'; | ||
import { markdownLineEndingOrSpace } from 'micromark-util-character'; | ||
import { normalizeIdentifier } from 'micromark-util-normalize-identifier'; | ||
const indent = { | ||
tokenize: tokenizeIndent, | ||
partial: true | ||
} | ||
}; | ||
@@ -39,2 +32,3 @@ // To do: micromark should support a `_hiddenGfmFootnoteSupport`, which only | ||
[91]: { | ||
name: 'gfmFootnoteDefinition', | ||
tokenize: tokenizeDefinitionStart, | ||
@@ -49,5 +43,7 @@ continuation: { | ||
[91]: { | ||
name: 'gfmFootnoteCall', | ||
tokenize: tokenizeGfmFootnoteCall | ||
}, | ||
[93]: { | ||
name: 'gfmPotentialFootnoteCall', | ||
add: 'after', | ||
@@ -58,3 +54,3 @@ tokenize: tokenizePotentialGfmFootnoteCall, | ||
} | ||
} | ||
}; | ||
} | ||
@@ -68,28 +64,22 @@ | ||
function tokenizePotentialGfmFootnoteCall(effects, ok, nok) { | ||
const self = this | ||
let index = self.events.length | ||
const defined = self.parser.gfmFootnotes || (self.parser.gfmFootnotes = []) | ||
const self = this; | ||
let index = self.events.length; | ||
const defined = self.parser.gfmFootnotes || (self.parser.gfmFootnotes = []); | ||
/** @type {Token} */ | ||
let labelStart | ||
let labelStart; | ||
// Find an opening. | ||
while (index--) { | ||
const token = self.events[index][1] | ||
if (token.type === 'labelImage') { | ||
labelStart = token | ||
break | ||
const token = self.events[index][1]; | ||
if (token.type === "labelImage") { | ||
labelStart = token; | ||
break; | ||
} | ||
// Exit if we’ve walked far enough. | ||
if ( | ||
token.type === 'gfmFootnoteCall' || | ||
token.type === 'labelLink' || | ||
token.type === 'label' || | ||
token.type === 'image' || | ||
token.type === 'link' | ||
) { | ||
break | ||
if (token.type === 'gfmFootnoteCall' || token.type === "labelLink" || token.type === "label" || token.type === "image" || token.type === "link") { | ||
break; | ||
} | ||
} | ||
return start | ||
return start; | ||
@@ -101,17 +91,15 @@ /** | ||
if (!labelStart || !labelStart._balanced) { | ||
return nok(code) | ||
return nok(code); | ||
} | ||
const id = normalizeIdentifier( | ||
self.sliceSerialize({ | ||
start: labelStart.end, | ||
end: self.now() | ||
}) | ||
) | ||
const id = normalizeIdentifier(self.sliceSerialize({ | ||
start: labelStart.end, | ||
end: self.now() | ||
})); | ||
if (id.codePointAt(0) !== 94 || !defined.includes(id.slice(1))) { | ||
return nok(code) | ||
return nok(code); | ||
} | ||
effects.enter('gfmFootnoteCallLabelMarker') | ||
effects.consume(code) | ||
effects.exit('gfmFootnoteCallLabelMarker') | ||
return ok(code) | ||
effects.enter('gfmFootnoteCallLabelMarker'); | ||
effects.consume(code); | ||
effects.exit('gfmFootnoteCallLabelMarker'); | ||
return ok(code); | ||
} | ||
@@ -123,19 +111,16 @@ } | ||
function resolveToPotentialGfmFootnoteCall(events, context) { | ||
let index = events.length | ||
let index = events.length; | ||
/** @type {Token | undefined} */ | ||
let labelStart | ||
let labelStart; | ||
// Find an opening. | ||
while (index--) { | ||
if ( | ||
events[index][1].type === 'labelImage' && | ||
events[index][0] === 'enter' | ||
) { | ||
labelStart = events[index][1] | ||
break | ||
if (events[index][1].type === "labelImage" && events[index][0] === 'enter') { | ||
labelStart = events[index][1]; | ||
break; | ||
} | ||
} | ||
// Change the `labelImageMarker` to a `data`. | ||
events[index + 1][1].type = 'data' | ||
events[index + 3][1].type = 'gfmFootnoteCallLabelMarker' | ||
events[index + 1][1].type = "data"; | ||
events[index + 3][1].type = 'gfmFootnoteCallLabelMarker'; | ||
@@ -148,3 +133,3 @@ // The whole (without `!`): | ||
end: Object.assign({}, events[events.length - 1][1].end) | ||
} | ||
}; | ||
// The `^` marker | ||
@@ -156,7 +141,7 @@ /** @type {Token} */ | ||
end: Object.assign({}, events[index + 3][1].end) | ||
} | ||
}; | ||
// Increment the end 1 character. | ||
marker.end.column++ | ||
marker.end.offset++ | ||
marker.end._bufferIndex++ | ||
marker.end.column++; | ||
marker.end.offset++; | ||
marker.end._bufferIndex++; | ||
/** @type {Token} */ | ||
@@ -167,35 +152,25 @@ const string = { | ||
end: Object.assign({}, events[events.length - 1][1].start) | ||
} | ||
}; | ||
/** @type {Token} */ | ||
const chunk = { | ||
type: 'chunkString', | ||
type: "chunkString", | ||
contentType: 'string', | ||
start: Object.assign({}, string.start), | ||
end: Object.assign({}, string.end) | ||
} | ||
}; | ||
/** @type {Array<Event>} */ | ||
const replacement = [ | ||
// Take the `labelImageMarker` (now `data`, the `!`) | ||
events[index + 1], | ||
events[index + 2], | ||
['enter', call, context], | ||
// The `[` | ||
events[index + 3], | ||
events[index + 4], | ||
// The `^`. | ||
['enter', marker, context], | ||
['exit', marker, context], | ||
// Everything in between. | ||
['enter', string, context], | ||
['enter', chunk, context], | ||
['exit', chunk, context], | ||
['exit', string, context], | ||
// The ending (`]`, properly parsed and labelled). | ||
events[events.length - 2], | ||
events[events.length - 1], | ||
['exit', call, context] | ||
] | ||
events.splice(index, events.length - index + 1, ...replacement) | ||
return events | ||
// Take the `labelImageMarker` (now `data`, the `!`) | ||
events[index + 1], events[index + 2], ['enter', call, context], | ||
// The `[` | ||
events[index + 3], events[index + 4], | ||
// The `^`. | ||
['enter', marker, context], ['exit', marker, context], | ||
// Everything in between. | ||
['enter', string, context], ['enter', chunk, context], ['exit', chunk, context], ['exit', string, context], | ||
// The ending (`]`, properly parsed and labelled). | ||
events[events.length - 2], events[events.length - 1], ['exit', call, context]]; | ||
events.splice(index, events.length - index + 1, ...replacement); | ||
return events; | ||
} | ||
@@ -208,7 +183,7 @@ | ||
function tokenizeGfmFootnoteCall(effects, ok, nok) { | ||
const self = this | ||
const defined = self.parser.gfmFootnotes || (self.parser.gfmFootnotes = []) | ||
let size = 0 | ||
const self = this; | ||
const defined = self.parser.gfmFootnotes || (self.parser.gfmFootnotes = []); | ||
let size = 0; | ||
/** @type {boolean} */ | ||
let data | ||
let data; | ||
@@ -220,3 +195,3 @@ // Note: the implementation of `markdown-rs` is different, because it houses | ||
// needed for labels. | ||
return start | ||
return start; | ||
@@ -234,7 +209,7 @@ /** | ||
function start(code) { | ||
effects.enter('gfmFootnoteCall') | ||
effects.enter('gfmFootnoteCallLabelMarker') | ||
effects.consume(code) | ||
effects.exit('gfmFootnoteCallLabelMarker') | ||
return callStart | ||
effects.enter('gfmFootnoteCall'); | ||
effects.enter('gfmFootnoteCallLabelMarker'); | ||
effects.consume(code); | ||
effects.exit('gfmFootnoteCallLabelMarker'); | ||
return callStart; | ||
} | ||
@@ -253,9 +228,9 @@ | ||
function callStart(code) { | ||
if (code !== 94) return nok(code) | ||
effects.enter('gfmFootnoteCallMarker') | ||
effects.consume(code) | ||
effects.exit('gfmFootnoteCallMarker') | ||
effects.enter('gfmFootnoteCallString') | ||
effects.enter('chunkString').contentType = 'string' | ||
return callData | ||
if (code !== 94) return nok(code); | ||
effects.enter('gfmFootnoteCallMarker'); | ||
effects.consume(code); | ||
effects.exit('gfmFootnoteCallMarker'); | ||
effects.enter('gfmFootnoteCallString'); | ||
effects.enter('chunkString').contentType = 'string'; | ||
return callData; | ||
} | ||
@@ -275,32 +250,29 @@ | ||
if ( | ||
// Too long. | ||
size > 999 || | ||
// Closing brace with nothing. | ||
(code === 93 && !data) || | ||
// Space or tab is not supported by GFM for some reason. | ||
// `\n` and `[` not being supported makes sense. | ||
code === null || | ||
code === 91 || | ||
markdownLineEndingOrSpace(code) | ||
) { | ||
return nok(code) | ||
// Too long. | ||
size > 999 || | ||
// Closing brace with nothing. | ||
code === 93 && !data || | ||
// Space or tab is not supported by GFM for some reason. | ||
// `\n` and `[` not being supported makes sense. | ||
code === null || code === 91 || markdownLineEndingOrSpace(code)) { | ||
return nok(code); | ||
} | ||
if (code === 93) { | ||
effects.exit('chunkString') | ||
const token = effects.exit('gfmFootnoteCallString') | ||
effects.exit('chunkString'); | ||
const token = effects.exit('gfmFootnoteCallString'); | ||
if (!defined.includes(normalizeIdentifier(self.sliceSerialize(token)))) { | ||
return nok(code) | ||
return nok(code); | ||
} | ||
effects.enter('gfmFootnoteCallLabelMarker') | ||
effects.consume(code) | ||
effects.exit('gfmFootnoteCallLabelMarker') | ||
effects.exit('gfmFootnoteCall') | ||
return ok | ||
effects.enter('gfmFootnoteCallLabelMarker'); | ||
effects.consume(code); | ||
effects.exit('gfmFootnoteCallLabelMarker'); | ||
effects.exit('gfmFootnoteCall'); | ||
return ok; | ||
} | ||
if (!markdownLineEndingOrSpace(code)) { | ||
data = true | ||
data = true; | ||
} | ||
size++ | ||
effects.consume(code) | ||
return code === 92 ? callEscape : callData | ||
size++; | ||
effects.consume(code); | ||
return code === 92 ? callEscape : callData; | ||
} | ||
@@ -320,7 +292,7 @@ | ||
if (code === 91 || code === 92 || code === 93) { | ||
effects.consume(code) | ||
size++ | ||
return callData | ||
effects.consume(code); | ||
size++; | ||
return callData; | ||
} | ||
return callData(code) | ||
return callData(code); | ||
} | ||
@@ -334,10 +306,10 @@ } | ||
function tokenizeDefinitionStart(effects, ok, nok) { | ||
const self = this | ||
const defined = self.parser.gfmFootnotes || (self.parser.gfmFootnotes = []) | ||
const self = this; | ||
const defined = self.parser.gfmFootnotes || (self.parser.gfmFootnotes = []); | ||
/** @type {string} */ | ||
let identifier | ||
let size = 0 | ||
let identifier; | ||
let size = 0; | ||
/** @type {boolean | undefined} */ | ||
let data | ||
return start | ||
let data; | ||
return start; | ||
@@ -355,8 +327,8 @@ /** | ||
function start(code) { | ||
effects.enter('gfmFootnoteDefinition')._container = true | ||
effects.enter('gfmFootnoteDefinitionLabel') | ||
effects.enter('gfmFootnoteDefinitionLabelMarker') | ||
effects.consume(code) | ||
effects.exit('gfmFootnoteDefinitionLabelMarker') | ||
return labelAtMarker | ||
effects.enter('gfmFootnoteDefinition')._container = true; | ||
effects.enter('gfmFootnoteDefinitionLabel'); | ||
effects.enter('gfmFootnoteDefinitionLabelMarker'); | ||
effects.consume(code); | ||
effects.exit('gfmFootnoteDefinitionLabelMarker'); | ||
return labelAtMarker; | ||
} | ||
@@ -376,10 +348,10 @@ | ||
if (code === 94) { | ||
effects.enter('gfmFootnoteDefinitionMarker') | ||
effects.consume(code) | ||
effects.exit('gfmFootnoteDefinitionMarker') | ||
effects.enter('gfmFootnoteDefinitionLabelString') | ||
effects.enter('chunkString').contentType = 'string' | ||
return labelInside | ||
effects.enter('gfmFootnoteDefinitionMarker'); | ||
effects.consume(code); | ||
effects.exit('gfmFootnoteDefinitionMarker'); | ||
effects.enter('gfmFootnoteDefinitionLabelString'); | ||
effects.enter('chunkString').contentType = 'string'; | ||
return labelInside; | ||
} | ||
return nok(code) | ||
return nok(code); | ||
} | ||
@@ -402,30 +374,27 @@ | ||
if ( | ||
// Too long. | ||
size > 999 || | ||
// Closing brace with nothing. | ||
(code === 93 && !data) || | ||
// Space or tab is not supported by GFM for some reason. | ||
// `\n` and `[` not being supported makes sense. | ||
code === null || | ||
code === 91 || | ||
markdownLineEndingOrSpace(code) | ||
) { | ||
return nok(code) | ||
// Too long. | ||
size > 999 || | ||
// Closing brace with nothing. | ||
code === 93 && !data || | ||
// Space or tab is not supported by GFM for some reason. | ||
// `\n` and `[` not being supported makes sense. | ||
code === null || code === 91 || markdownLineEndingOrSpace(code)) { | ||
return nok(code); | ||
} | ||
if (code === 93) { | ||
effects.exit('chunkString') | ||
const token = effects.exit('gfmFootnoteDefinitionLabelString') | ||
identifier = normalizeIdentifier(self.sliceSerialize(token)) | ||
effects.enter('gfmFootnoteDefinitionLabelMarker') | ||
effects.consume(code) | ||
effects.exit('gfmFootnoteDefinitionLabelMarker') | ||
effects.exit('gfmFootnoteDefinitionLabel') | ||
return labelAfter | ||
effects.exit('chunkString'); | ||
const token = effects.exit('gfmFootnoteDefinitionLabelString'); | ||
identifier = normalizeIdentifier(self.sliceSerialize(token)); | ||
effects.enter('gfmFootnoteDefinitionLabelMarker'); | ||
effects.consume(code); | ||
effects.exit('gfmFootnoteDefinitionLabelMarker'); | ||
effects.exit('gfmFootnoteDefinitionLabel'); | ||
return labelAfter; | ||
} | ||
if (!markdownLineEndingOrSpace(code)) { | ||
data = true | ||
data = true; | ||
} | ||
size++ | ||
effects.consume(code) | ||
return code === 92 ? labelEscape : labelInside | ||
size++; | ||
effects.consume(code); | ||
return code === 92 ? labelEscape : labelInside; | ||
} | ||
@@ -448,7 +417,7 @@ | ||
if (code === 91 || code === 92 || code === 93) { | ||
effects.consume(code) | ||
size++ | ||
return labelInside | ||
effects.consume(code); | ||
size++; | ||
return labelInside; | ||
} | ||
return labelInside(code) | ||
return labelInside(code); | ||
} | ||
@@ -468,7 +437,7 @@ | ||
if (code === 58) { | ||
effects.enter('definitionMarker') | ||
effects.consume(code) | ||
effects.exit('definitionMarker') | ||
effects.enter('definitionMarker'); | ||
effects.consume(code); | ||
effects.exit('definitionMarker'); | ||
if (!defined.includes(identifier)) { | ||
defined.push(identifier) | ||
defined.push(identifier); | ||
} | ||
@@ -479,9 +448,5 @@ | ||
// No space is also fine, just like a block quote marker. | ||
return factorySpace( | ||
effects, | ||
whitespaceAfter, | ||
'gfmFootnoteDefinitionWhitespace' | ||
) | ||
return factorySpace(effects, whitespaceAfter, 'gfmFootnoteDefinitionWhitespace'); | ||
} | ||
return nok(code) | ||
return nok(code); | ||
} | ||
@@ -501,3 +466,3 @@ | ||
// `markdown-rs` has a wrapping token for the prefix that is closed here. | ||
return ok(code) | ||
return ok(code); | ||
} | ||
@@ -520,3 +485,3 @@ } | ||
// Either a blank line, which is okay, or an indented thing. | ||
return effects.check(blankLine, ok, effects.attempt(indent, ok, nok)) | ||
return effects.check(blankLine, ok, effects.attempt(indent, ok, nok)); | ||
} | ||
@@ -526,3 +491,3 @@ | ||
function gfmFootnoteDefinitionEnd(effects) { | ||
effects.exit('gfmFootnoteDefinition') | ||
effects.exit('gfmFootnoteDefinition'); | ||
} | ||
@@ -535,9 +500,4 @@ | ||
function tokenizeIndent(effects, ok, nok) { | ||
const self = this | ||
return factorySpace( | ||
effects, | ||
afterPrefix, | ||
'gfmFootnoteDefinitionIndent', | ||
4 + 1 | ||
) | ||
const self = this; | ||
return factorySpace(effects, afterPrefix, 'gfmFootnoteDefinitionIndent', 4 + 1); | ||
@@ -548,9 +508,5 @@ /** | ||
function afterPrefix(code) { | ||
const tail = self.events[self.events.length - 1] | ||
return tail && | ||
tail[1].type === 'gfmFootnoteDefinitionIndent' && | ||
tail[2].sliceSerialize(tail[1], true).length === 4 | ||
? ok(code) | ||
: nok(code) | ||
const tail = self.events[self.events.length - 1]; | ||
return tail && tail[1].type === 'gfmFootnoteDefinitionIndent' && tail[2].sliceSerialize(tail[1], true).length === 4 ? ok(code) : nok(code); | ||
} | ||
} | ||
} |
{ | ||
"name": "micromark-extension-gfm-footnote", | ||
"version": "2.0.0", | ||
"version": "2.1.0", | ||
"description": "micromark extension to support GFM footnotes", | ||
@@ -50,12 +50,12 @@ "license": "MIT", | ||
"@types/node": "^20.0.0", | ||
"c8": "^8.0.0", | ||
"c8": "^10.0.0", | ||
"create-gfm-fixtures": "^1.0.0", | ||
"micromark": "^4.0.0", | ||
"micromark-build": "^2.0.0", | ||
"prettier": "^2.0.0", | ||
"remark-cli": "^11.0.0", | ||
"remark-preset-wooorm": "^9.0.0", | ||
"prettier": "^3.0.0", | ||
"remark-cli": "^12.0.0", | ||
"remark-preset-wooorm": "^10.0.0", | ||
"type-coverage": "^2.0.0", | ||
"typescript": "^5.0.0", | ||
"xo": "^0.54.0" | ||
"xo": "^0.58.0" | ||
}, | ||
@@ -65,3 +65,3 @@ "scripts": { | ||
"build": "tsc --build --clean && tsc --build && type-coverage && micromark-build", | ||
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", | ||
"format": "remark . -qfo && prettier . -w --log-level warn && xo --fix", | ||
"test-api-prod": "node --conditions production test/index.js", | ||
@@ -95,3 +95,6 @@ "test-api-dev": "node --conditions development test/index.js", | ||
"rules": { | ||
"unicorn/no-this-assignment": "off" | ||
"logical-assignment-operators": "off", | ||
"unicorn/no-this-assignment": "off", | ||
"unicorn/prefer-at": "off", | ||
"unicorn/prefer-string-replace-all": "off" | ||
}, | ||
@@ -101,6 +104,21 @@ "overrides": [ | ||
"files": [ | ||
"**/*.ts" | ||
"**/*.d.ts" | ||
], | ||
"rules": { | ||
"@typescript-eslint/consistent-type-definitions": 0 | ||
"@typescript-eslint/array-type": [ | ||
"error", | ||
{ | ||
"default": "generic" | ||
} | ||
], | ||
"@typescript-eslint/ban-types": [ | ||
"error", | ||
{ | ||
"extendDefaults": true | ||
} | ||
], | ||
"@typescript-eslint/consistent-type-definitions": [ | ||
"error", | ||
"interface" | ||
] | ||
} | ||
@@ -107,0 +125,0 @@ }, |
130
readme.md
@@ -15,23 +15,23 @@ # micromark-extension-gfm-footnote | ||
* [What is this?](#what-is-this) | ||
* [When to use this](#when-to-use-this) | ||
* [Install](#install) | ||
* [Use](#use) | ||
* [API](#api) | ||
* [`defaultBackLabel(referenceIndex, rereferenceIndex)`](#defaultbacklabelreferenceindex-rereferenceindex) | ||
* [`gfmFootnote()`](#gfmfootnote) | ||
* [`gfmFootnoteHtml(options?)`](#gfmfootnotehtmloptions) | ||
* [`BackLabelTemplate`](#backlabeltemplate) | ||
* [`HtmlOptions`](#htmloptions) | ||
* [Bugs](#bugs) | ||
* [Authoring](#authoring) | ||
* [HTML](#html) | ||
* [CSS](#css) | ||
* [Syntax](#syntax) | ||
* [Types](#types) | ||
* [Compatibility](#compatibility) | ||
* [Security](#security) | ||
* [Related](#related) | ||
* [Contribute](#contribute) | ||
* [License](#license) | ||
* [What is this?](#what-is-this) | ||
* [When to use this](#when-to-use-this) | ||
* [Install](#install) | ||
* [Use](#use) | ||
* [API](#api) | ||
* [`defaultBackLabel(referenceIndex, rereferenceIndex)`](#defaultbacklabelreferenceindex-rereferenceindex) | ||
* [`gfmFootnote()`](#gfmfootnote) | ||
* [`gfmFootnoteHtml(options?)`](#gfmfootnotehtmloptions) | ||
* [`BackLabelTemplate`](#backlabeltemplate) | ||
* [`HtmlOptions`](#htmloptions) | ||
* [Bugs](#bugs) | ||
* [Authoring](#authoring) | ||
* [HTML](#html) | ||
* [CSS](#css) | ||
* [Syntax](#syntax) | ||
* [Types](#types) | ||
* [Compatibility](#compatibility) | ||
* [Security](#security) | ||
* [Related](#related) | ||
* [Contribute](#contribute) | ||
* [License](#license) | ||
@@ -184,4 +184,4 @@ ## What is this? | ||
* `options` ([`HtmlOptions`][api-html-options], optional) | ||
— configuration | ||
* `options` ([`HtmlOptions`][api-html-options], optional) | ||
— configuration | ||
@@ -209,16 +209,16 @@ ###### Returns | ||
* `0` and `0` for the backreference from `things about micromark` to | ||
`alpha`, as it is the first used definition, and the first call to it | ||
* `0` and `1` for the backreference from `things about micromark` to | ||
`bravo`, as it is the first used definition, and the second call to it | ||
* `1` and `0` for the backreference from `things about remark` to | ||
`charlie`, as it is the second used definition | ||
* `0` and `0` for the backreference from `things about micromark` to | ||
`alpha`, as it is the first used definition, and the first call to it | ||
* `0` and `1` for the backreference from `things about micromark` to | ||
`bravo`, as it is the first used definition, and the second call to it | ||
* `1` and `0` for the backreference from `things about remark` to | ||
`charlie`, as it is the second used definition | ||
###### Parameters | ||
* `referenceIndex` (`number`) | ||
— index of the definition in the order that they are first referenced, | ||
0-indexed | ||
* `rereferenceIndex` (`number`) | ||
— index of calls to the same definition, 0-indexed | ||
* `referenceIndex` (`number`) | ||
— index of the definition in the order that they are first referenced, | ||
0-indexed | ||
* `rereferenceIndex` (`number`) | ||
— index of calls to the same definition, 0-indexed | ||
@@ -312,25 +312,25 @@ ###### Returns | ||
* [Footnote reference call identifiers are trimmed, but definition | ||
identifiers aren’t](https://github.com/github/cmark-gfm/issues/237)\ | ||
— initial and final whitespace in labels causes them not to match | ||
* [Footnotes are matched case-insensitive, but links keep their casing, | ||
breaking them](https://github.com/github/cmark-gfm/issues/239)\ | ||
— using uppercase (or any character that will be percent encoded) in | ||
identifiers breaks links | ||
* [Colons in footnotes generate links w/o | ||
`href`](https://github.com/github/cmark-gfm/issues/250)\ | ||
— colons in identifiers generate broken links | ||
* [Character escape of `]` does not work in footnote | ||
identifiers](https://github.com/github/cmark-gfm/issues/240)\ | ||
— some character escapes don’t work | ||
* [Footnotes in links are | ||
broken](https://github.com/github/cmark-gfm/issues/249)\ | ||
— while `CommonMark` prevents links in links, GitHub does not prevent | ||
footnotes (which turn into links) in links | ||
* [Footnote-like brackets around image, break that | ||
image](https://github.com/github/cmark-gfm/issues/275)\ | ||
— images can’t be used in what looks like a footnote call | ||
* [GFM footnotes: line ending in footnote definition label causes text to | ||
disappear](https://github.com/github/cmark-gfm/issues/282)\ | ||
— line endings in footnote definitions cause text to disappear | ||
* [Footnote reference call identifiers are trimmed, but definition | ||
identifiers aren’t](https://github.com/github/cmark-gfm/issues/237)\ | ||
— initial and final whitespace in labels causes them not to match | ||
* [Footnotes are matched case-insensitive, but links keep their casing, | ||
breaking them](https://github.com/github/cmark-gfm/issues/239)\ | ||
— using uppercase (or any character that will be percent encoded) in | ||
identifiers breaks links | ||
* [Colons in footnotes generate links w/o | ||
`href`](https://github.com/github/cmark-gfm/issues/250)\ | ||
— colons in identifiers generate broken links | ||
* [Character escape of `]` does not work in footnote | ||
identifiers](https://github.com/github/cmark-gfm/issues/240)\ | ||
— some character escapes don’t work | ||
* [Footnotes in links are | ||
broken](https://github.com/github/cmark-gfm/issues/249)\ | ||
— while `CommonMark` prevents links in links, GitHub does not prevent | ||
footnotes (which turn into links) in links | ||
* [Footnote-like brackets around image, break that | ||
image](https://github.com/github/cmark-gfm/issues/275)\ | ||
— images can’t be used in what looks like a footnote call | ||
* [GFM footnotes: line ending in footnote definition label causes text to | ||
disappear](https://github.com/github/cmark-gfm/issues/282)\ | ||
— line endings in footnote definitions cause text to disappear | ||
@@ -537,10 +537,10 @@ ## Authoring | ||
* [`micromark-extension-gfm`][micromark-extension-gfm] | ||
— support all of GFM | ||
* [`mdast-util-gfm-footnote`][mdast-util-gfm-footnote] | ||
— support all of GFM in mdast | ||
* [`mdast-util-gfm`][mdast-util-gfm] | ||
— support all of GFM in mdast | ||
* [`remark-gfm`][remark-gfm] | ||
— support all of GFM in remark | ||
* [`micromark-extension-gfm`][micromark-extension-gfm] | ||
— support all of GFM | ||
* [`mdast-util-gfm-footnote`][mdast-util-gfm-footnote] | ||
— support all of GFM in mdast | ||
* [`mdast-util-gfm`][mdast-util-gfm] | ||
— support all of GFM in mdast | ||
* [`remark-gfm`][remark-gfm] | ||
— support all of GFM in remark | ||
@@ -547,0 +547,0 @@ ## Contribute |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
79466
1699