diff --git a/tools/lint-md/lint-md.mjs b/tools/lint-md/lint-md.mjs index bd893097132255..9d3903a1d4b478 100644 --- a/tools/lint-md/lint-md.mjs +++ b/tools/lint-md/lint-md.mjs @@ -1738,50 +1738,6 @@ function constructs(existing, list) { splice(existing, 0, 0, before); } -/** - * Combine several HTML extensions into one. - * - * @param {HtmlExtension[]} htmlExtensions List of HTML extensions. - * @returns {HtmlExtension} A single combined extension. - */ -function combineHtmlExtensions(htmlExtensions) { - /** @type {HtmlExtension} */ - const handlers = {}; - let index = -1; - - while (++index < htmlExtensions.length) { - htmlExtension(handlers, htmlExtensions[index]); - } - - return handlers -} - -/** - * Merge `extension` into `all`. - * - * @param {HtmlExtension} all Extension to merge into. - * @param {HtmlExtension} extension Extension to merge. - * @returns {void} - */ -function htmlExtension(all, extension) { - /** @type {string} */ - let hook; - - for (hook in extension) { - const maybe = hasOwnProperty.call(all, hook) ? all[hook] : undefined; - const left = maybe || (all[hook] = {}); - const right = extension[hook]; - /** @type {string} */ - let type; - - if (right) { - for (type in right) { - left[type] = right[type]; - } - } - } -} - // This module is generated by `script/`. // // CommonMark handles attention (emphasis, strong) markers based on what comes @@ -8640,7 +8596,7 @@ const listItemPrefixWhitespaceConstruct = { /** @type {Construct} */ const indentConstruct = { - tokenize: tokenizeIndent, + tokenize: tokenizeIndent$1, partial: true }; /** @@ -8820,7 +8776,7 @@ function tokenizeListContinuation(effects, ok, nok) { * @this {TokenizeContextWithState} */ -function tokenizeIndent(effects, ok, nok) { +function tokenizeIndent$1(effects, ok, nok) { const self = this; return factorySpace( effects, @@ -13827,7 +13783,8 @@ function joinDefinition(left, right) { /** * @typedef {import('mdast').Root|import('mdast').Content} Node - * @typedef {import('mdast-util-to-markdown').Options} Options + * @typedef {import('mdast-util-to-markdown').Options} ToMarkdownOptions + * @typedef {Omit} Options */ /** @type {import('unified').Plugin<[Options]|void[], Node, string>} */ @@ -13843,7 +13800,10 @@ function remarkStringify(options) { // Note: this option is not in the readme. // The goal is for it to be set by plugins on `data` instead of being // passed by users. - extensions: this.data('toMarkdownExtensions') || [] + extensions: + /** @type {ToMarkdownOptions['extensions']} */ ( + this.data('toMarkdownExtensions') + ) || [] }) ) }; @@ -14479,201 +14439,419 @@ function previousUnbalanced(events) { return result } -const characterReferences = {'"': 'quot', '&': 'amp', '<': 'lt', '>': 'gt'}; - /** - * Encode only the dangerous HTML characters. - * - * This ensures that certain characters which have special meaning in HTML are - * dealt with. - * Technically, we can skip `>` and `"` in many cases, but CM includes them. - * - * @param {string} value - * @returns {string} + * @typedef {import('micromark-util-types').Extension} Extension + * @typedef {import('micromark-util-types').Resolver} Resolver + * @typedef {import('micromark-util-types').Token} Token + * @typedef {import('micromark-util-types').Tokenizer} Tokenizer + * @typedef {import('micromark-util-types').Exiter} Exiter + * @typedef {import('micromark-util-types').State} State + * @typedef {import('micromark-util-types').Event} Event + */ +const indent = { + tokenize: tokenizeIndent, + partial: true +}; +/** + * @returns {Extension} */ -function encode(value) { - return value.replace(/["&<>]/g, replace) - /** - * @param {string} value - * @returns {string} - */ - function replace(value) { - // @ts-expect-error Hush, it’s fine. - return '&' + characterReferences[value] + ';' +function gfmFootnote() { + /** @type {Extension} */ + return { + document: { + [91]: { + tokenize: tokenizeDefinitionStart, + continuation: { + tokenize: tokenizeDefinitionContinuation + }, + exit: gfmFootnoteDefinitionEnd + } + }, + text: { + [91]: { + tokenize: tokenizeGfmFootnoteCall + }, + [93]: { + add: 'after', + tokenize: tokenizePotentialGfmFootnoteCall, + resolveTo: resolveToPotentialGfmFootnoteCall + } + } } } +/** @type {Tokenizer} */ -/** - * Make a value safe for injection as a URL. - * - * This encodes unsafe characters with percent-encoding and skips already - * encoded sequences (see `normalizeUri` below). - * Further unsafe characters are encoded as character references (see - * `micromark-util-encode`). - * - * Then, a regex of allowed protocols can be given, in which case the URL is - * sanitized. - * For example, `/^(https?|ircs?|mailto|xmpp)$/i` can be used for `a[href]`, - * or `/^https?$/i` for `img[src]`. - * If the URL includes an unknown protocol (one not matched by `protocol`, such - * as a dangerous example, `javascript:`), the value is ignored. - * - * @param {string|undefined} url - * @param {RegExp} [protocol] - * @returns {string} - */ -function sanitizeUri(url, protocol) { - const value = encode(normalizeUri(url || '')); +function tokenizePotentialGfmFootnoteCall(effects, ok, nok) { + const self = this; + let index = self.events.length; + /** @type {string[]} */ + // @ts-expect-error It’s fine! - if (!protocol) { - return value + const defined = self.parser.gfmFootnotes || (self.parser.gfmFootnotes = []); + /** @type {Token} */ + + let labelStart; // Find an opening. + + while (index--) { + 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 + } } - const colon = value.indexOf(':'); - const questionMark = value.indexOf('?'); - const numberSign = value.indexOf('#'); - const slash = value.indexOf('/'); + return start + /** @type {State} */ - if ( - // If there is no protocol, it’s relative. - colon < 0 || // If the first colon is after a `?`, `#`, or `/`, it’s not a protocol. - (slash > -1 && colon > slash) || - (questionMark > -1 && colon > questionMark) || - (numberSign > -1 && colon > numberSign) || // It is a protocol, it should be allowed. - protocol.test(value.slice(0, colon)) - ) { - return value + function start(code) { + if (!labelStart || !labelStart._balanced) { + return nok(code) + } + + const id = normalizeIdentifier( + self.sliceSerialize({ + start: labelStart.end, + end: self.now() + }) + ); + + if (id.charCodeAt(0) !== 94 || !defined.includes(id.slice(1))) { + return nok(code) + } + + effects.enter('gfmFootnoteCallLabelMarker'); + effects.consume(code); + effects.exit('gfmFootnoteCallLabelMarker'); + return ok(code) } +} +/** @type {Resolver} */ - return '' +function resolveToPotentialGfmFootnoteCall(events, context) { + let index = events.length; + + while (index--) { + if ( + events[index][1].type === 'labelImage' && + events[index][0] === 'enter' + ) { + events[index][1]; + break + } + } + + // Change the `labelImageMarker` to a `data`. + events[index + 1][1].type = 'data'; + events[index + 3][1].type = 'gfmFootnoteCallLabelMarker'; // The whole (without `!`): + + const call = { + type: 'gfmFootnoteCall', + start: Object.assign({}, events[index + 3][1].start), + end: Object.assign({}, events[events.length - 1][1].end) + }; // The `^` marker + + const marker = { + type: 'gfmFootnoteCallMarker', + start: Object.assign({}, events[index + 3][1].end), + end: Object.assign({}, events[index + 3][1].end) + }; // Increment the end 1 character. + + marker.end.column++; + marker.end.offset++; + marker.end._bufferIndex++; + const string = { + type: 'gfmFootnoteCallString', + start: Object.assign({}, marker.end), + end: Object.assign({}, events[events.length - 1][1].start) + }; + const chunk = { + type: 'chunkString', + contentType: 'string', + start: Object.assign({}, string.start), + end: Object.assign({}, string.end) + }; + /** @type {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 } -/** - * Normalize a URL (such as used in definitions). - * - * Encode unsafe characters with percent-encoding, skipping already encoded - * sequences. - * - * @param {string} value - * @returns {string} - */ +/** @type {Tokenizer} */ -function normalizeUri(value) { +function tokenizeGfmFootnoteCall(effects, ok, nok) { + const self = this; /** @type {string[]} */ - const result = []; - let index = -1; - let start = 0; - let skip = 0; + // @ts-expect-error It’s fine! - while (++index < value.length) { - const code = value.charCodeAt(index); - /** @type {string} */ + const defined = self.parser.gfmFootnotes || (self.parser.gfmFootnotes = []); + let size = 0; + /** @type {boolean} */ + + let data; + return start + /** @type {State} */ + + function start(code) { + effects.enter('gfmFootnoteCall'); + effects.enter('gfmFootnoteCallLabelMarker'); + effects.consume(code); + effects.exit('gfmFootnoteCallLabelMarker'); + return callStart + } + /** @type {State} */ + + 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 + } + /** @type {State} */ + + function callData(code) { + /** @type {Token} */ + let token; + + if (code === null || code === 91 || size++ > 999) { + return nok(code) + } + + if (code === 93) { + if (!data) { + return nok(code) + } + + effects.exit('chunkString'); + token = effects.exit('gfmFootnoteCallString'); + return defined.includes(normalizeIdentifier(self.sliceSerialize(token))) + ? end(code) + : nok(code) + } + + effects.consume(code); + + if (!markdownLineEndingOrSpace(code)) { + data = true; + } + + return code === 92 ? callEscape : callData + } + /** @type {State} */ + + function callEscape(code) { + if (code === 91 || code === 92 || code === 93) { + effects.consume(code); + size++; + return callData + } + + return callData(code) + } + /** @type {State} */ + + function end(code) { + effects.enter('gfmFootnoteCallLabelMarker'); + effects.consume(code); + effects.exit('gfmFootnoteCallLabelMarker'); + effects.exit('gfmFootnoteCall'); + return ok + } +} +/** @type {Tokenizer} */ + +function tokenizeDefinitionStart(effects, ok, nok) { + const self = this; + /** @type {string[]} */ + // @ts-expect-error It’s fine! + + const defined = self.parser.gfmFootnotes || (self.parser.gfmFootnotes = []); + /** @type {string} */ + + let identifier; + let size = 0; + /** @type {boolean|undefined} */ + + let data; + return start + /** @type {State} */ + + function start(code) { + effects.enter('gfmFootnoteDefinition')._container = true; + effects.enter('gfmFootnoteDefinitionLabel'); + effects.enter('gfmFootnoteDefinitionLabelMarker'); + effects.consume(code); + effects.exit('gfmFootnoteDefinitionLabelMarker'); + return labelStart + } + /** @type {State} */ + + function labelStart(code) { + if (code === 94) { + effects.enter('gfmFootnoteDefinitionMarker'); + effects.consume(code); + effects.exit('gfmFootnoteDefinitionMarker'); + effects.enter('gfmFootnoteDefinitionLabelString'); + return atBreak + } + + return nok(code) + } + /** @type {State} */ + + function atBreak(code) { + /** @type {Token} */ + let token; + + if (code === null || code === 91 || size > 999) { + return nok(code) + } + + if (code === 93) { + if (!data) { + return nok(code) + } - let replace = ''; // A correct percent encoded value. + token = effects.exit('gfmFootnoteDefinitionLabelString'); + identifier = normalizeIdentifier(self.sliceSerialize(token)); + effects.enter('gfmFootnoteDefinitionLabelMarker'); + effects.consume(code); + effects.exit('gfmFootnoteDefinitionLabelMarker'); + effects.exit('gfmFootnoteDefinitionLabel'); + return labelAfter + } + if (markdownLineEnding(code)) { + effects.enter('lineEnding'); + effects.consume(code); + effects.exit('lineEnding'); + size++; + return atBreak + } + + effects.enter('chunkString').contentType = 'string'; + return label(code) + } + /** @type {State} */ + + function label(code) { if ( - code === 37 && - asciiAlphanumeric(value.charCodeAt(index + 1)) && - asciiAlphanumeric(value.charCodeAt(index + 2)) + code === null || + markdownLineEnding(code) || + code === 91 || + code === 93 || + size > 999 ) { - skip = 2; - } // ASCII. - else if (code < 128) { - if (!/[!#$&-;=?-Z_a-z~]/.test(String.fromCharCode(code))) { - replace = String.fromCharCode(code); - } - } // Astral. - else if (code > 55295 && code < 57344) { - const next = value.charCodeAt(index + 1); // A correct surrogate pair. - - if (code < 56320 && next > 56319 && next < 57344) { - replace = String.fromCharCode(code, next); - skip = 1; - } // Lone surrogate. - else { - replace = '\uFFFD'; - } - } // Unicode. - else { - replace = String.fromCharCode(code); + effects.exit('chunkString'); + return atBreak(code) } - if (replace) { - result.push(value.slice(start, index), encodeURIComponent(replace)); - start = index + skip + 1; - replace = ''; + if (!markdownLineEndingOrSpace(code)) { + data = true; } - if (skip) { - index += skip; - skip = 0; + size++; + effects.consume(code); + return code === 92 ? labelEscape : label + } + /** @type {State} */ + + function labelEscape(code) { + if (code === 91 || code === 92 || code === 93) { + effects.consume(code); + size++; + return label } + + return label(code) } + /** @type {State} */ - return result.join('') + value.slice(start) -} + function labelAfter(code) { + if (code === 58) { + effects.enter('definitionMarker'); + effects.consume(code); + effects.exit('definitionMarker'); // Any whitespace after the marker is eaten, forming indented code + // is not possible. + // No space is also fine, just like a block quote marker. -/** - * @typedef {import('micromark-util-types').HtmlExtension} HtmlExtension - * @typedef {import('micromark-util-types').Handle} Handle - * @typedef {import('micromark-util-types').CompileContext} CompileContext - * @typedef {import('micromark-util-types').Token} Token - */ -/** @type {HtmlExtension} */ + return factorySpace(effects, done, 'gfmFootnoteDefinitionWhitespace') + } -const gfmAutolinkLiteralHtml = { - exit: { - literalAutolinkEmail, - literalAutolinkHttp, - literalAutolinkWww + return nok(code) } -}; -/** @type {Handle} */ + /** @type {State} */ -function literalAutolinkWww(token) { - anchorFromToken.call(this, token, 'http://'); -} -/** @type {Handle} */ + function done(code) { + if (!defined.includes(identifier)) { + defined.push(identifier); + } -function literalAutolinkEmail(token) { - anchorFromToken.call(this, token, 'mailto:'); + return ok(code) + } } -/** @type {Handle} */ +/** @type {Tokenizer} */ -function literalAutolinkHttp(token) { - anchorFromToken.call(this, token); +function tokenizeDefinitionContinuation(effects, ok, nok) { + // Either a blank line, which is okay, or an indented thing. + return effects.check(blankLine, ok, effects.attempt(indent, ok, nok)) } -/** - * @this CompileContext - * @param {Token} token - * @param {string} [protocol] - * @returns {void} - */ +/** @type {Exiter} */ -function anchorFromToken(token, protocol) { - const url = this.sliceSerialize(token); - this.tag(''); - this.raw(this.encode(url)); - this.tag(''); +function gfmFootnoteDefinitionEnd(effects) { + effects.exit('gfmFootnoteDefinition'); } +/** @type {Tokenizer} */ -/** - * @typedef {import('micromark-util-types').HtmlExtension} HtmlExtension - */ +function tokenizeIndent(effects, ok, nok) { + const self = this; + return factorySpace( + effects, + afterPrefix, + 'gfmFootnoteDefinitionIndent', + 4 + 1 + ) + /** @type {State} */ -/** @type {HtmlExtension} */ -const gfmStrikethroughHtml = { - enter: { - strikethrough() { - this.tag(''); - } - }, - exit: { - strikethrough() { - this.tag(''); - } + 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) } -}; +} /** * @typedef {import('micromark-util-types').Extension} Extension @@ -14835,156 +15013,6 @@ function gfmStrikethrough(options = {}) { } } -/** - * @typedef {import('micromark-util-types').HtmlExtension} HtmlExtension - */ - -/** - * @typedef {import('./syntax.js').Align} Align - */ -const alignment = { - null: '', - left: ' align="left"', - right: ' align="right"', - center: ' align="center"' -}; -/** @type {HtmlExtension} */ - -const gfmTableHtml = { - enter: { - table(token) { - this.lineEndingIfNeeded(); - this.tag(''); // @ts-expect-error Custom. - - this.setData('tableAlign', token._align); - }, - - tableBody() { - // Clear slurping line ending from the delimiter row. - this.setData('slurpOneLineEnding'); - this.tag(''); - }, - - tableData() { - /** @type {string|undefined} */ - const align = // @ts-expect-error Custom. - alignment[this.getData('tableAlign')[this.getData('tableColumn')]]; - - if (align === undefined) { - // Capture results to ignore them. - this.buffer(); - } else { - this.lineEndingIfNeeded(); - this.tag(''); - } - }, - - tableHead() { - this.lineEndingIfNeeded(); - this.tag(''); - }, - - tableHeader() { - this.lineEndingIfNeeded(); - this.tag( - '' - ); - }, - - tableRow() { - this.setData('tableColumn', 0); - this.lineEndingIfNeeded(); - this.tag(''); - } - }, - exit: { - // Overwrite the default code text data handler to unescape escaped pipes when - // they are in tables. - codeTextData(token) { - let value = this.sliceSerialize(token); - - if (this.getData('tableAlign')) { - value = value.replace(/\\([\\|])/g, replace$1); - } - - this.raw(this.encode(value)); - }, - - table() { - this.setData('tableAlign'); // If there was no table body, make sure the slurping from the delimiter row - // is cleared. - - this.setData('slurpAllLineEndings'); - this.lineEndingIfNeeded(); - this.tag('
'); - }, - - tableBody() { - this.lineEndingIfNeeded(); - this.tag(''); - }, - - tableData() { - /** @type {number} */ - // @ts-expect-error Custom. - const column = this.getData('tableColumn'); // @ts-expect-error Custom. - - if (column in this.getData('tableAlign')) { - this.tag(''); - this.setData('tableColumn', column + 1); - } else { - // Stop capturing. - this.resume(); - } - }, - - tableHead() { - this.lineEndingIfNeeded(); - this.tag(''); - this.setData('slurpOneLineEnding', true); // Slurp the line ending from the delimiter row. - }, - - tableHeader() { - this.tag(''); // @ts-expect-error Custom. - - this.setData('tableColumn', this.getData('tableColumn') + 1); - }, - - tableRow() { - /** @type {Align[]} */ - // @ts-expect-error Custom. - const align = this.getData('tableAlign'); - /** @type {number} */ - // @ts-expect-error Custom. - - let column = this.getData('tableColumn'); - - while (column < align.length) { - this.lineEndingIfNeeded(); // @ts-expect-error `null` is fine as an index. - - this.tag(''); - column++; - } - - this.setData('tableColumn', column); - this.lineEndingIfNeeded(); - this.tag(''); - } - } -}; -/** - * @param {string} $0 - * @param {string} $1 - * @returns {string} - */ - -function replace$1($0, $1) { - // Pipes work, backslashes don’t (but can’t escape pipes). - return $1 === '|' ? $1 : $0 -} - /** * @typedef {import('micromark-util-types').Extension} Extension * @typedef {import('micromark-util-types').Resolver} Resolver @@ -15601,74 +15629,6 @@ function tokenizeNextPrefixedOrBlank(effects, ok, nok) { } } -/** - * @typedef {import('micromark-util-types').HtmlExtension} HtmlExtension - * @typedef {import('micromark-util-types').Token} Token - * @typedef {import('micromark-util-types').CompileContext} CompileContext - */ - -/** - * An opening or closing tag, followed by a case-insensitive specific tag name, - * followed by HTML whitespace, a greater than, or a slash. - */ -const reFlow = - /<(\/?)(iframe|noembed|noframes|plaintext|script|style|title|textarea|xmp)(?=[\t\n\f\r />])/gi; - -/** - * As HTML (text) parses tags separately (and v. strictly), we don’t need to be - * global. - */ -const reText = new RegExp('^' + reFlow.source, 'i'); - -/** @type {HtmlExtension} */ -const gfmTagfilterHtml = { - exit: { - htmlFlowData(token) { - exitHtmlData.call(this, token, reFlow); - }, - htmlTextData(token) { - exitHtmlData.call(this, token, reText); - } - } -}; - -/** - * @this {CompileContext} - * @param {Token} token - * @param {RegExp} filter - */ -function exitHtmlData(token, filter) { - let value = this.sliceSerialize(token); - - if (this.options.allowDangerousHtml) { - value = value.replace(filter, '<$1$2'); - } - - this.raw(this.encode(value)); -} - -/** - * @typedef {import('micromark-util-types').HtmlExtension} HtmlExtension - */ - -/** @type {HtmlExtension} */ -const gfmTaskListItemHtml = { - enter: { - taskListCheck() { - this.tag(''); - }, - - taskListCheckValueChecked() { - this.tag('checked="" '); - } - } -}; - /** * @typedef {import('micromark-util-types').Extension} Extension * @typedef {import('micromark-util-types').ConstructRecord} ConstructRecord @@ -15770,6 +15730,7 @@ function spaceThenNonSpace(effects, ok, nok) { * @typedef {import('micromark-util-types').Extension} Extension * @typedef {import('micromark-util-types').HtmlExtension} HtmlExtension * @typedef {import('micromark-extension-gfm-strikethrough').Options} Options + * @typedef {import('micromark-extension-gfm-footnote').HtmlOptions} HtmlOptions */ /** @@ -15781,21 +15742,13 @@ function spaceThenNonSpace(effects, ok, nok) { function gfm(options) { return combineExtensions([ gfmAutolinkLiteral, + gfmFootnote(), gfmStrikethrough(options), gfmTable, gfmTaskListItem ]) } -/** @type {HtmlExtension} */ -combineHtmlExtensions([ - gfmAutolinkLiteralHtml, - gfmStrikethroughHtml, - gfmTableHtml, - gfmTagfilterHtml, - gfmTaskListItemHtml -]); - /** * Get the total count of `character` in `value`. * @@ -16454,6 +16407,174 @@ function previous(match, email) { ) } +/** + * @typedef {import('mdast').FootnoteReference} FootnoteReference + * @typedef {import('mdast').FootnoteDefinition} FootnoteDefinition + * @typedef {import('mdast-util-from-markdown').Extension} FromMarkdownExtension + * @typedef {import('mdast-util-from-markdown').Handle} FromMarkdownHandle + * @typedef {import('mdast-util-to-markdown').Options} ToMarkdownExtension + * @typedef {import('mdast-util-to-markdown').Handle} ToMarkdownHandle + * @typedef {import('mdast-util-to-markdown').Map} Map + */ + +let warningColonInFootnote = false; +let warningListInFootnote = false; + +/** + * @returns {FromMarkdownExtension} + */ +function gfmFootnoteFromMarkdown() { + return { + enter: { + gfmFootnoteDefinition: enterFootnoteDefinition, + gfmFootnoteDefinitionLabelString: enterFootnoteDefinitionLabelString, + gfmFootnoteCall: enterFootnoteCall, + gfmFootnoteCallString: enterFootnoteCallString + }, + exit: { + gfmFootnoteDefinition: exitFootnoteDefinition, + gfmFootnoteDefinitionLabelString: exitFootnoteDefinitionLabelString, + gfmFootnoteCall: exitFootnoteCall, + gfmFootnoteCallString: exitFootnoteCallString + } + } + + /** @type {FromMarkdownHandle} */ + function enterFootnoteDefinition(token) { + this.enter( + {type: 'footnoteDefinition', identifier: '', label: '', children: []}, + token + ); + } + + /** @type {FromMarkdownHandle} */ + function enterFootnoteDefinitionLabelString() { + this.buffer(); + } + + /** @type {FromMarkdownHandle} */ + function exitFootnoteDefinitionLabelString(token) { + const label = this.resume(); + const node = /** @type {FootnoteDefinition} */ ( + this.stack[this.stack.length - 1] + ); + node.label = label; + node.identifier = normalizeIdentifier( + this.sliceSerialize(token) + ).toLowerCase(); + } + + /** @type {FromMarkdownHandle} */ + function exitFootnoteDefinition(token) { + this.exit(token); + } + + /** @type {FromMarkdownHandle} */ + function enterFootnoteCall(token) { + this.enter({type: 'footnoteReference', identifier: '', label: ''}, token); + } + + /** @type {FromMarkdownHandle} */ + function enterFootnoteCallString() { + this.buffer(); + } + + /** @type {FromMarkdownHandle} */ + function exitFootnoteCallString(token) { + const label = this.resume(); + const node = /** @type {FootnoteDefinition} */ ( + this.stack[this.stack.length - 1] + ); + node.label = label; + node.identifier = normalizeIdentifier( + this.sliceSerialize(token) + ).toLowerCase(); + } + + /** @type {FromMarkdownHandle} */ + function exitFootnoteCall(token) { + this.exit(token); + } +} + +/** + * @returns {ToMarkdownExtension} + */ +function gfmFootnoteToMarkdown() { + footnoteReference.peek = footnoteReferencePeek; + + return { + // This is on by default already. + unsafe: [{character: '[', inConstruct: ['phrasing', 'label', 'reference']}], + handlers: {footnoteDefinition, footnoteReference} + } + + /** + * @type {ToMarkdownHandle} + * @param {FootnoteReference} node + */ + function footnoteReference(node, _, context) { + const exit = context.enter('footnoteReference'); + const subexit = context.enter('reference'); + const reference = safe(context, association(node), { + before: '^', + after: ']' + }); + subexit(); + exit(); + return '[^' + reference + ']' + } + + /** @type {ToMarkdownHandle} */ + function footnoteReferencePeek() { + return '[' + } + + /** + * @type {ToMarkdownHandle} + * @param {FootnoteDefinition} node + */ + function footnoteDefinition(node, _, context) { + const exit = context.enter('footnoteDefinition'); + const subexit = context.enter('label'); + const id = safe(context, association(node), {before: '^', after: ']'}); + const label = '[^' + id + ']:'; + subexit(); + const value = indentLines(containerFlow(node, context), map); + exit(); + + if (!warningColonInFootnote && id.includes(':')) { + console.warn( + '[mdast-util-gfm-footnote] Warning: Found a colon in footnote identifier `' + + id + + '`. GitHub currently crahes on colons in footnotes (see for more info)' + ); + warningColonInFootnote = true; + } + + if (!warningListInFootnote) { + visit$1(node, 'list', () => { + console.warn( + '[mdast-util-gfm-footnote] Warning: Found a list in a footnote definition. GitHub currently crahes on lists in footnotes (see for more info)' + ); + warningListInFootnote = true; + return EXIT$1 + }); + } + + return value + + /** @type {Map} */ + function map(line, index, blank) { + if (index) { + return (blank ? '' : ' ') + line + } + + return (blank ? label : label + ' ') + line + } + } +} + /** * @typedef {import('mdast').Delete} Delete * @typedef {import('mdast-util-from-markdown').Extension} FromMarkdownExtension @@ -17110,14 +17231,17 @@ function listItemWithTaskListItem(node, parent, context) { */ /** - * @type {Array.} + * @returns {Array.} */ -const gfmFromMarkdown = [ - gfmAutolinkLiteralFromMarkdown, - gfmStrikethroughFromMarkdown, - gfmTableFromMarkdown, - gfmTaskListItemFromMarkdown -]; +function gfmFromMarkdown() { + return [ + gfmAutolinkLiteralFromMarkdown, + gfmFootnoteFromMarkdown(), + gfmStrikethroughFromMarkdown, + gfmTableFromMarkdown, + gfmTaskListItemFromMarkdown + ] +} /** * @param {Options} [options] @@ -17127,6 +17251,7 @@ function gfmToMarkdown(options) { return { extensions: [ gfmAutolinkLiteralToMarkdown, + gfmFootnoteToMarkdown(), gfmStrikethroughToMarkdown, gfmTableToMarkdown(options), gfmTaskListItemToMarkdown @@ -17148,7 +17273,7 @@ function remarkGfm(options = {}) { const data = this.data(); add('micromarkExtensions', gfm(options)); - add('fromMarkdownExtensions', gfmFromMarkdown); + add('fromMarkdownExtensions', gfmFromMarkdown()); add('toMarkdownExtensions', gfmToMarkdown(options)); /** @@ -27397,8 +27522,17 @@ function testProhibited (val, content) { } let regexpString = '(? escapeStringRegexp(a)).join('|'); + ignoreNextTo = `(?:${parts})`; + } else { + ignoreNextTo = escapeStringRegexp(val.ignoreNextTo); + } + } else { + ignoreNextTo = ''; + } const replaceCaptureGroups = !!val.replaceCaptureGroups; // If it starts with a letter, make sure it is a word break. @@ -28211,12 +28345,6 @@ var remarkLintUnorderedListMarkerStyle$1 = remarkLintUnorderedListMarkerStyle; // @see https://github.com/nodejs/node/blob/HEAD/doc/guides/doc-style-guide.md -// Remove remark-lint-no-auto-link-without-protocol -remarkPresetLintRecommended$1.plugins = - remarkPresetLintRecommended$1.plugins.filter( - (fn) => fn.name !== "remark-lint:no-auto-link-without-protocol" - ); - // Add in rules alphabetically after Gfm and PresetLintRecommended. const plugins = [ remarkGfm, diff --git a/tools/lint-md/package-lock.json b/tools/lint-md/package-lock.json index 4525157c8bf8af..75e4ea906e72b5 100644 --- a/tools/lint-md/package-lock.json +++ b/tools/lint-md/package-lock.json @@ -9,8 +9,8 @@ "version": "1.0.0", "dependencies": { "remark-parse": "^10.0.0", - "remark-preset-lint-node": "^3.0.1", - "remark-stringify": "^10.0.0", + "remark-preset-lint-node": "^3.3.0", + "remark-stringify": "^10.0.1", "to-vfile": "^7.2.2", "unified": "^10.1.0", "vfile-reporter": "^7.0.2" @@ -621,11 +621,12 @@ } }, "node_modules/mdast-util-gfm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-1.0.0.tgz", - "integrity": "sha512-JY4qImsTqivQ0Gl3qvdaizCpomFaNrHnjEhNjNNKeNEA5jZHAJDYu1+yO4V9jn4/ti8GrKdAScaT4F71knoxsA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-2.0.0.tgz", + "integrity": "sha512-wMwejlTN3EQADPFuvxe8lmGsay3+f6gSJKdAHR6KBJzpcxvsjJSILB9K6u6G7eQLC7iOTyVIHYGui9uBc9r1Tg==", "dependencies": { "mdast-util-gfm-autolink-literal": "^1.0.0", + "mdast-util-gfm-footnote": "^1.0.0", "mdast-util-gfm-strikethrough": "^1.0.0", "mdast-util-gfm-table": "^1.0.0", "mdast-util-gfm-task-list-item": "^1.0.0" @@ -650,6 +651,21 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdast-util-gfm-footnote": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.0.tgz", + "integrity": "sha512-qeg9YoS2YYP6OBmMyUFxKXb6BLwAsbGidIxgwDAXHIMYZQhIwe52L9BSJs+zP29Jp5nSERPkmG3tSwAN23/ZbQ==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "unist-util-visit": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/mdast-util-gfm-strikethrough": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.0.tgz", @@ -808,11 +824,12 @@ } }, "node_modules/micromark-extension-gfm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-1.0.0.tgz", - "integrity": "sha512-OjqbQPL1Vec/4l5hnC8WnMNmWwgrT9JvzR2udqIGrGKecZsdwY9GAWZ5482CuD12SXuHNj8aS8epni6ip0Pwog==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-2.0.0.tgz", + "integrity": "sha512-yYPlZ48Ss8fRFSmlQP/QXt3/M6tEvawEVFO+jDPnFA3mGeVgzIyaeHgrIV/9AMFAjQhctKA47Bk8xBhcuaL74Q==", "dependencies": { "micromark-extension-gfm-autolink-literal": "^1.0.0", + "micromark-extension-gfm-footnote": "^1.0.0", "micromark-extension-gfm-strikethrough": "^1.0.0", "micromark-extension-gfm-table": "^1.0.0", "micromark-extension-gfm-tagfilter": "^1.0.0", @@ -841,6 +858,24 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.0.2.tgz", + "integrity": "sha512-C6o+B7w1wDM4JjDJeHCTszFYF1q46imElNY6mfXsBfw4E91M9TvEEEt3sy0FbJmGVzdt1pqFVRYWT9ZZ0FjFuA==", + "dependencies": { + "micromark-core-commonmark": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/micromark-extension-gfm-strikethrough": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.3.tgz", @@ -1344,13 +1379,13 @@ } }, "node_modules/remark-gfm": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-2.0.0.tgz", - "integrity": "sha512-waIv4Tjcd2CTUDxKRYzuPyIHw1FoX4H2GjXAzXV9PxQWb+dU4fJivd/FZ+nxyzPARrqTjMIkwIwPoWNbpBhjcQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.0.tgz", + "integrity": "sha512-CXJw5h1iwUW6czFwi4tveoOSlsEZU44hcdNzUxC5uiNi7r/OQySf46AoEihM8/NwBbW1LcsnyGIsHBnbURFw2g==", "dependencies": { "@types/mdast": "^3.0.0", - "mdast-util-gfm": "^1.0.0", - "micromark-extension-gfm": "^1.0.0", + "mdast-util-gfm": "^2.0.0", + "micromark-extension-gfm": "^2.0.0", "unified": "^10.0.0" }, "funding": { @@ -1975,9 +2010,9 @@ } }, "node_modules/remark-lint-prohibited-strings": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/remark-lint-prohibited-strings/-/remark-lint-prohibited-strings-3.0.0.tgz", - "integrity": "sha512-Aw21KVeoOiDte6dNfeTfTgjKV19yWXpPjLxfJ3ShC22/r97gkGdOo4dnuwyEEAfKhr3uimtSf3rRQyGSudY5tQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/remark-lint-prohibited-strings/-/remark-lint-prohibited-strings-3.1.0.tgz", + "integrity": "sha512-zwfDDdYl7ye0gEHcwhdkv1ZGXj1ibw4gnLLZkkvySnDdTz2tshY3fOJLY5NikbVseaIRVGOr5qa+8J9WNQT/fA==", "dependencies": { "escape-string-regexp": "^5.0.0", "unified-lint-rule": "^2.0.0", @@ -2099,12 +2134,12 @@ } }, "node_modules/remark-preset-lint-node": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/remark-preset-lint-node/-/remark-preset-lint-node-3.2.0.tgz", - "integrity": "sha512-FWKZOVYiiAd9eRMvcjlJihatuXnzfgD/PEO1Oc8+USZe/3MFH3HcUCsUvoymalJ0YM++ekKTQEYrhsFYtk4PIQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/remark-preset-lint-node/-/remark-preset-lint-node-3.3.0.tgz", + "integrity": "sha512-JPjXould+7VTpwj+YJHSoPiGwKLpmLAZJRveU/dT7mCDOdSSORe/SGo9fJDm6owUReg50b5AG2AY8nlReytHcA==", "dependencies": { "js-yaml": "^4.0.0", - "remark-gfm": "^2.0.0", + "remark-gfm": "^3.0.0", "remark-lint-blockquote-indentation": "^3.0.0", "remark-lint-checkbox-character-style": "^4.0.0", "remark-lint-checkbox-content-indent": "^4.0.0", @@ -2134,7 +2169,7 @@ "remark-lint-table-cell-padding": "^4.0.0", "remark-lint-table-pipes": "^4.0.0", "remark-lint-unordered-list-marker-style": "^3.0.0", - "remark-preset-lint-recommended": "^6.0.0", + "remark-preset-lint-recommended": "^6.1.1", "semver": "^7.3.2", "unified-lint-rule": "^2.0.0", "unist-util-visit": "^4.1.0" @@ -2172,9 +2207,9 @@ } }, "node_modules/remark-stringify": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-10.0.0.tgz", - "integrity": "sha512-3LAQqJ/qiUxkWc7fUcVuB7RtIT38rvmxfmJG8z1TiE/D8zi3JGQ2tTcTJu9Tptdpb7gFwU0whRi5q1FbFOb9yA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-10.0.1.tgz", + "integrity": "sha512-380vOu9EHqRTDhI9RlPU2EKY1abUDEmxw9fW7pJ/8Jr1izk0UcdnZB30qiDDRYi6pGn5FnVf9Wd2iUeCWTqM7Q==", "dependencies": { "@types/mdast": "^3.0.0", "mdast-util-to-markdown": "^1.0.0", @@ -3027,11 +3062,12 @@ } }, "mdast-util-gfm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-1.0.0.tgz", - "integrity": "sha512-JY4qImsTqivQ0Gl3qvdaizCpomFaNrHnjEhNjNNKeNEA5jZHAJDYu1+yO4V9jn4/ti8GrKdAScaT4F71knoxsA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-2.0.0.tgz", + "integrity": "sha512-wMwejlTN3EQADPFuvxe8lmGsay3+f6gSJKdAHR6KBJzpcxvsjJSILB9K6u6G7eQLC7iOTyVIHYGui9uBc9r1Tg==", "requires": { "mdast-util-gfm-autolink-literal": "^1.0.0", + "mdast-util-gfm-footnote": "^1.0.0", "mdast-util-gfm-strikethrough": "^1.0.0", "mdast-util-gfm-table": "^1.0.0", "mdast-util-gfm-task-list-item": "^1.0.0" @@ -3048,6 +3084,17 @@ "micromark-util-character": "^1.0.0" } }, + "mdast-util-gfm-footnote": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.0.tgz", + "integrity": "sha512-qeg9YoS2YYP6OBmMyUFxKXb6BLwAsbGidIxgwDAXHIMYZQhIwe52L9BSJs+zP29Jp5nSERPkmG3tSwAN23/ZbQ==", + "requires": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "unist-util-visit": "^4.0.0" + } + }, "mdast-util-gfm-strikethrough": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.0.tgz", @@ -3158,11 +3205,12 @@ } }, "micromark-extension-gfm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-1.0.0.tgz", - "integrity": "sha512-OjqbQPL1Vec/4l5hnC8WnMNmWwgrT9JvzR2udqIGrGKecZsdwY9GAWZ5482CuD12SXuHNj8aS8epni6ip0Pwog==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-2.0.0.tgz", + "integrity": "sha512-yYPlZ48Ss8fRFSmlQP/QXt3/M6tEvawEVFO+jDPnFA3mGeVgzIyaeHgrIV/9AMFAjQhctKA47Bk8xBhcuaL74Q==", "requires": { "micromark-extension-gfm-autolink-literal": "^1.0.0", + "micromark-extension-gfm-footnote": "^1.0.0", "micromark-extension-gfm-strikethrough": "^1.0.0", "micromark-extension-gfm-table": "^1.0.0", "micromark-extension-gfm-tagfilter": "^1.0.0", @@ -3183,6 +3231,20 @@ "uvu": "^0.5.0" } }, + "micromark-extension-gfm-footnote": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.0.2.tgz", + "integrity": "sha512-C6o+B7w1wDM4JjDJeHCTszFYF1q46imElNY6mfXsBfw4E91M9TvEEEt3sy0FbJmGVzdt1pqFVRYWT9ZZ0FjFuA==", + "requires": { + "micromark-core-commonmark": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "uvu": "^0.5.0" + } + }, "micromark-extension-gfm-strikethrough": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.3.tgz", @@ -3458,13 +3520,13 @@ "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==" }, "remark-gfm": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-2.0.0.tgz", - "integrity": "sha512-waIv4Tjcd2CTUDxKRYzuPyIHw1FoX4H2GjXAzXV9PxQWb+dU4fJivd/FZ+nxyzPARrqTjMIkwIwPoWNbpBhjcQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.0.tgz", + "integrity": "sha512-CXJw5h1iwUW6czFwi4tveoOSlsEZU44hcdNzUxC5uiNi7r/OQySf46AoEihM8/NwBbW1LcsnyGIsHBnbURFw2g==", "requires": { "@types/mdast": "^3.0.0", - "mdast-util-gfm": "^1.0.0", - "micromark-extension-gfm": "^1.0.0", + "mdast-util-gfm": "^2.0.0", + "micromark-extension-gfm": "^2.0.0", "unified": "^10.0.0" } }, @@ -3939,9 +4001,9 @@ } }, "remark-lint-prohibited-strings": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/remark-lint-prohibited-strings/-/remark-lint-prohibited-strings-3.0.0.tgz", - "integrity": "sha512-Aw21KVeoOiDte6dNfeTfTgjKV19yWXpPjLxfJ3ShC22/r97gkGdOo4dnuwyEEAfKhr3uimtSf3rRQyGSudY5tQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/remark-lint-prohibited-strings/-/remark-lint-prohibited-strings-3.1.0.tgz", + "integrity": "sha512-zwfDDdYl7ye0gEHcwhdkv1ZGXj1ibw4gnLLZkkvySnDdTz2tshY3fOJLY5NikbVseaIRVGOr5qa+8J9WNQT/fA==", "requires": { "escape-string-regexp": "^5.0.0", "unified-lint-rule": "^2.0.0", @@ -4035,12 +4097,12 @@ } }, "remark-preset-lint-node": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/remark-preset-lint-node/-/remark-preset-lint-node-3.2.0.tgz", - "integrity": "sha512-FWKZOVYiiAd9eRMvcjlJihatuXnzfgD/PEO1Oc8+USZe/3MFH3HcUCsUvoymalJ0YM++ekKTQEYrhsFYtk4PIQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/remark-preset-lint-node/-/remark-preset-lint-node-3.3.0.tgz", + "integrity": "sha512-JPjXould+7VTpwj+YJHSoPiGwKLpmLAZJRveU/dT7mCDOdSSORe/SGo9fJDm6owUReg50b5AG2AY8nlReytHcA==", "requires": { "js-yaml": "^4.0.0", - "remark-gfm": "^2.0.0", + "remark-gfm": "^3.0.0", "remark-lint-blockquote-indentation": "^3.0.0", "remark-lint-checkbox-character-style": "^4.0.0", "remark-lint-checkbox-content-indent": "^4.0.0", @@ -4070,7 +4132,7 @@ "remark-lint-table-cell-padding": "^4.0.0", "remark-lint-table-pipes": "^4.0.0", "remark-lint-unordered-list-marker-style": "^3.0.0", - "remark-preset-lint-recommended": "^6.0.0", + "remark-preset-lint-recommended": "^6.1.1", "semver": "^7.3.2", "unified-lint-rule": "^2.0.0", "unist-util-visit": "^4.1.0" @@ -4101,9 +4163,9 @@ } }, "remark-stringify": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-10.0.0.tgz", - "integrity": "sha512-3LAQqJ/qiUxkWc7fUcVuB7RtIT38rvmxfmJG8z1TiE/D8zi3JGQ2tTcTJu9Tptdpb7gFwU0whRi5q1FbFOb9yA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-10.0.1.tgz", + "integrity": "sha512-380vOu9EHqRTDhI9RlPU2EKY1abUDEmxw9fW7pJ/8Jr1izk0UcdnZB30qiDDRYi6pGn5FnVf9Wd2iUeCWTqM7Q==", "requires": { "@types/mdast": "^3.0.0", "mdast-util-to-markdown": "^1.0.0", diff --git a/tools/lint-md/package.json b/tools/lint-md/package.json index a6c883f9882c85..6b3e48c4671817 100644 --- a/tools/lint-md/package.json +++ b/tools/lint-md/package.json @@ -7,8 +7,8 @@ }, "dependencies": { "remark-parse": "^10.0.0", - "remark-preset-lint-node": "^3.0.1", - "remark-stringify": "^10.0.0", + "remark-preset-lint-node": "^3.3.0", + "remark-stringify": "^10.0.1", "to-vfile": "^7.2.2", "unified": "^10.1.0", "vfile-reporter": "^7.0.2"