mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-12-16 22:10:13 +01:00
Refactor to freeze parser tokens only when custom rules are present (negligable performance improvement).
This commit is contained in:
parent
a63972a666
commit
5e1b269fa5
4 changed files with 110 additions and 92 deletions
|
|
@ -986,26 +986,36 @@ const { isHtmlFlowComment } = __webpack_require__(/*! ./micromark-helpers.cjs */
|
||||||
const { flatTokensSymbol, htmlFlowSymbol, newLineRe } = __webpack_require__(/*! ./shared.js */ "../helpers/shared.js");
|
const { flatTokensSymbol, htmlFlowSymbol, newLineRe } = __webpack_require__(/*! ./shared.js */ "../helpers/shared.js");
|
||||||
|
|
||||||
/** @typedef {import("markdownlint-micromark").Event} Event */
|
/** @typedef {import("markdownlint-micromark").Event} Event */
|
||||||
/** @typedef {import("markdownlint-micromark").ParseOptions} ParseOptions */
|
/** @typedef {import("markdownlint-micromark").ParseOptions} MicromarkParseOptions */
|
||||||
/** @typedef {import("../lib/markdownlint.js").MicromarkToken} Token */
|
/** @typedef {import("../lib/markdownlint.js").MicromarkToken} Token */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse options.
|
||||||
|
*
|
||||||
|
* @typedef {Object} ParseOptions
|
||||||
|
* @property {boolean} [freezeTokens] Whether to freeze output Tokens.
|
||||||
|
* @property {boolean} [shimReferences] Whether to shim missing references.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a Markdown document and returns Micromark events.
|
* Parses a Markdown document and returns Micromark events.
|
||||||
*
|
*
|
||||||
* @param {string} markdown Markdown document.
|
* @param {string} markdown Markdown document.
|
||||||
* @param {ParseOptions} [micromarkOptions] Options for micromark.
|
* @param {ParseOptions} [parseOptions] Options.
|
||||||
* @param {boolean} [referencesDefined] Treat references as defined.
|
* @param {MicromarkParseOptions} [micromarkParseOptions] Options for micromark.
|
||||||
* @returns {Event[]} Micromark events.
|
* @returns {Event[]} Micromark events.
|
||||||
*/
|
*/
|
||||||
function getEvents(
|
function getEvents(
|
||||||
markdown,
|
markdown,
|
||||||
micromarkOptions = {},
|
parseOptions = {},
|
||||||
referencesDefined = true
|
micromarkParseOptions = {}
|
||||||
) {
|
) {
|
||||||
|
// Get options
|
||||||
|
const shimReferences = Boolean(parseOptions.shimReferences);
|
||||||
|
|
||||||
// Customize options object to add useful extensions
|
// Customize options object to add useful extensions
|
||||||
micromarkOptions.extensions = micromarkOptions.extensions || [];
|
micromarkParseOptions.extensions = micromarkParseOptions.extensions || [];
|
||||||
micromarkOptions.extensions.push(
|
micromarkParseOptions.extensions.push(
|
||||||
micromark.directive(),
|
micromark.directive(),
|
||||||
micromark.gfmAutolinkLiteral(),
|
micromark.gfmAutolinkLiteral(),
|
||||||
micromark.gfmFootnote(),
|
micromark.gfmFootnote(),
|
||||||
|
|
@ -1016,8 +1026,8 @@ function getEvents(
|
||||||
// Use micromark to parse document into Events
|
// Use micromark to parse document into Events
|
||||||
const encoding = undefined;
|
const encoding = undefined;
|
||||||
const eol = true;
|
const eol = true;
|
||||||
const parseContext = micromark.parse(micromarkOptions);
|
const parseContext = micromark.parse(micromarkParseOptions);
|
||||||
if (referencesDefined) {
|
if (shimReferences) {
|
||||||
// Customize ParseContext to treat all references as defined
|
// Customize ParseContext to treat all references as defined
|
||||||
parseContext.defined.includes = (searchElement) => searchElement.length > 0;
|
parseContext.defined.includes = (searchElement) => searchElement.length > 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1027,26 +1037,27 @@ function getEvents(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a Markdown document and returns (frozen) tokens.
|
* Parses a Markdown document and returns micromark tokens (internal).
|
||||||
*
|
*
|
||||||
* @param {string} markdown Markdown document.
|
* @param {string} markdown Markdown document.
|
||||||
* @param {ParseOptions} micromarkOptions Options for micromark.
|
* @param {ParseOptions} [parseOptions] Options.
|
||||||
* @param {boolean} referencesDefined Treat references as defined.
|
* @param {MicromarkParseOptions} [micromarkParseOptions] Options for micromark.
|
||||||
* @param {number} lineDelta Offset to apply to start/end line.
|
* @param {number} [lineDelta] Offset for start/end line.
|
||||||
* @param {Token} [ancestor] Parent of top-most tokens.
|
* @param {Token} [ancestor] Parent of top-most tokens.
|
||||||
* @returns {Token[]} Micromark tokens (frozen).
|
* @returns {Token[]} Micromark tokens.
|
||||||
*/
|
*/
|
||||||
function parseWithOffset(
|
function parseInternal(
|
||||||
markdown,
|
markdown,
|
||||||
micromarkOptions,
|
parseOptions = {},
|
||||||
referencesDefined,
|
micromarkParseOptions = {},
|
||||||
lineDelta,
|
lineDelta = 0,
|
||||||
ancestor
|
ancestor = undefined
|
||||||
) {
|
) {
|
||||||
|
// Get options
|
||||||
|
const freezeTokens = Boolean(parseOptions.freezeTokens);
|
||||||
|
|
||||||
// Use micromark to parse document into Events
|
// Use micromark to parse document into Events
|
||||||
const events = getEvents(
|
const events = getEvents(markdown, parseOptions, micromarkParseOptions);
|
||||||
markdown, micromarkOptions, referencesDefined
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create Token objects
|
// Create Token objects
|
||||||
const document = [];
|
const document = [];
|
||||||
|
|
@ -1065,7 +1076,7 @@ function parseWithOffset(
|
||||||
const history = [ root ];
|
const history = [ root ];
|
||||||
let current = root;
|
let current = root;
|
||||||
// eslint-disable-next-line jsdoc/valid-types
|
// eslint-disable-next-line jsdoc/valid-types
|
||||||
/** @type ParseOptions | null */
|
/** @type MicromarkParseOptions | null */
|
||||||
let reparseOptions = null;
|
let reparseOptions = null;
|
||||||
let lines = null;
|
let lines = null;
|
||||||
let skipHtmlFlowChildren = false;
|
let skipHtmlFlowChildren = false;
|
||||||
|
|
@ -1097,7 +1108,7 @@ function parseWithOffset(
|
||||||
skipHtmlFlowChildren = true;
|
skipHtmlFlowChildren = true;
|
||||||
if (!reparseOptions || !lines) {
|
if (!reparseOptions || !lines) {
|
||||||
reparseOptions = {
|
reparseOptions = {
|
||||||
...micromarkOptions,
|
...micromarkParseOptions,
|
||||||
"extensions": [
|
"extensions": [
|
||||||
{
|
{
|
||||||
"disable": {
|
"disable": {
|
||||||
|
|
@ -1111,10 +1122,10 @@ function parseWithOffset(
|
||||||
const reparseMarkdown = lines
|
const reparseMarkdown = lines
|
||||||
.slice(current.startLine - 1, current.endLine)
|
.slice(current.startLine - 1, current.endLine)
|
||||||
.join("\n");
|
.join("\n");
|
||||||
const tokens = parseWithOffset(
|
const tokens = parseInternal(
|
||||||
reparseMarkdown,
|
reparseMarkdown,
|
||||||
|
parseOptions,
|
||||||
reparseOptions,
|
reparseOptions,
|
||||||
referencesDefined,
|
|
||||||
current.startLine - 1,
|
current.startLine - 1,
|
||||||
current
|
current
|
||||||
);
|
);
|
||||||
|
|
@ -1128,8 +1139,10 @@ function parseWithOffset(
|
||||||
skipHtmlFlowChildren = false;
|
skipHtmlFlowChildren = false;
|
||||||
}
|
}
|
||||||
if (!skipHtmlFlowChildren) {
|
if (!skipHtmlFlowChildren) {
|
||||||
Object.freeze(current.children);
|
if (freezeTokens) {
|
||||||
Object.freeze(current);
|
Object.freeze(current.children);
|
||||||
|
Object.freeze(current);
|
||||||
|
}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
current = history.pop();
|
current = history.pop();
|
||||||
}
|
}
|
||||||
|
|
@ -1138,29 +1151,21 @@ function parseWithOffset(
|
||||||
|
|
||||||
// Return document
|
// Return document
|
||||||
Object.defineProperty(document, flatTokensSymbol, { "value": flatTokens });
|
Object.defineProperty(document, flatTokensSymbol, { "value": flatTokens });
|
||||||
Object.freeze(document);
|
if (freezeTokens) {
|
||||||
|
Object.freeze(document);
|
||||||
|
}
|
||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a Markdown document and returns (frozen) tokens.
|
* Parses a Markdown document and returns micromark tokens.
|
||||||
*
|
*
|
||||||
* @param {string} markdown Markdown document.
|
* @param {string} markdown Markdown document.
|
||||||
* @param {ParseOptions} [micromarkOptions] Options for micromark.
|
* @param {ParseOptions} [parseOptions] Options.
|
||||||
* @param {boolean} [referencesDefined] Treat references as defined.
|
* @returns {Token[]} Micromark tokens.
|
||||||
* @returns {Token[]} Micromark tokens (frozen).
|
|
||||||
*/
|
*/
|
||||||
function parse(
|
function parse(markdown, parseOptions) {
|
||||||
markdown,
|
return parseInternal(markdown, parseOptions);
|
||||||
micromarkOptions = {},
|
|
||||||
referencesDefined = true
|
|
||||||
) {
|
|
||||||
return parseWithOffset(
|
|
||||||
markdown,
|
|
||||||
micromarkOptions,
|
|
||||||
referencesDefined,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
@ -1965,8 +1970,12 @@ function lintContent(
|
||||||
const needMarkdownItTokens = enabledRuleList.some(
|
const needMarkdownItTokens = enabledRuleList.some(
|
||||||
(rule) => (rule.parser === "markdownit") || (rule.parser === undefined)
|
(rule) => (rule.parser === "markdownit") || (rule.parser === undefined)
|
||||||
);
|
);
|
||||||
|
const customRulesPresent = (ruleList.length !== rules.length);
|
||||||
// Parse content into parser tokens
|
// Parse content into parser tokens
|
||||||
const micromarkTokens = micromark.parse(content);
|
const micromarkTokens = micromark.parse(
|
||||||
|
content,
|
||||||
|
{ "freezeTokens": customRulesPresent, "shimReferences": true }
|
||||||
|
);
|
||||||
// Hide the content of HTML comments from rules
|
// Hide the content of HTML comments from rules
|
||||||
const preClearedContent = content;
|
const preClearedContent = content;
|
||||||
content = helpers.clearHtmlCommentText(content);
|
content = helpers.clearHtmlCommentText(content);
|
||||||
|
|
@ -5079,7 +5088,7 @@ module.exports = {
|
||||||
if (autoLinks.length > 0) {
|
if (autoLinks.length > 0) {
|
||||||
// Re-parse with correct link/image reference definition handling
|
// Re-parse with correct link/image reference definition handling
|
||||||
const document = params.lines.join("\n");
|
const document = params.lines.join("\n");
|
||||||
const tokens = parse(document, undefined, false);
|
const tokens = parse(document);
|
||||||
for (const token of literalAutolinks(tokens)) {
|
for (const token of literalAutolinks(tokens)) {
|
||||||
const range = [
|
const range = [
|
||||||
token.startColumn,
|
token.startColumn,
|
||||||
|
|
|
||||||
|
|
@ -7,26 +7,36 @@ const { isHtmlFlowComment } = require("./micromark-helpers.cjs");
|
||||||
const { flatTokensSymbol, htmlFlowSymbol, newLineRe } = require("./shared.js");
|
const { flatTokensSymbol, htmlFlowSymbol, newLineRe } = require("./shared.js");
|
||||||
|
|
||||||
/** @typedef {import("markdownlint-micromark").Event} Event */
|
/** @typedef {import("markdownlint-micromark").Event} Event */
|
||||||
/** @typedef {import("markdownlint-micromark").ParseOptions} ParseOptions */
|
/** @typedef {import("markdownlint-micromark").ParseOptions} MicromarkParseOptions */
|
||||||
/** @typedef {import("../lib/markdownlint.js").MicromarkToken} Token */
|
/** @typedef {import("../lib/markdownlint.js").MicromarkToken} Token */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse options.
|
||||||
|
*
|
||||||
|
* @typedef {Object} ParseOptions
|
||||||
|
* @property {boolean} [freezeTokens] Whether to freeze output Tokens.
|
||||||
|
* @property {boolean} [shimReferences] Whether to shim missing references.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a Markdown document and returns Micromark events.
|
* Parses a Markdown document and returns Micromark events.
|
||||||
*
|
*
|
||||||
* @param {string} markdown Markdown document.
|
* @param {string} markdown Markdown document.
|
||||||
* @param {ParseOptions} [micromarkOptions] Options for micromark.
|
* @param {ParseOptions} [parseOptions] Options.
|
||||||
* @param {boolean} [referencesDefined] Treat references as defined.
|
* @param {MicromarkParseOptions} [micromarkParseOptions] Options for micromark.
|
||||||
* @returns {Event[]} Micromark events.
|
* @returns {Event[]} Micromark events.
|
||||||
*/
|
*/
|
||||||
function getEvents(
|
function getEvents(
|
||||||
markdown,
|
markdown,
|
||||||
micromarkOptions = {},
|
parseOptions = {},
|
||||||
referencesDefined = true
|
micromarkParseOptions = {}
|
||||||
) {
|
) {
|
||||||
|
// Get options
|
||||||
|
const shimReferences = Boolean(parseOptions.shimReferences);
|
||||||
|
|
||||||
// Customize options object to add useful extensions
|
// Customize options object to add useful extensions
|
||||||
micromarkOptions.extensions = micromarkOptions.extensions || [];
|
micromarkParseOptions.extensions = micromarkParseOptions.extensions || [];
|
||||||
micromarkOptions.extensions.push(
|
micromarkParseOptions.extensions.push(
|
||||||
micromark.directive(),
|
micromark.directive(),
|
||||||
micromark.gfmAutolinkLiteral(),
|
micromark.gfmAutolinkLiteral(),
|
||||||
micromark.gfmFootnote(),
|
micromark.gfmFootnote(),
|
||||||
|
|
@ -37,8 +47,8 @@ function getEvents(
|
||||||
// Use micromark to parse document into Events
|
// Use micromark to parse document into Events
|
||||||
const encoding = undefined;
|
const encoding = undefined;
|
||||||
const eol = true;
|
const eol = true;
|
||||||
const parseContext = micromark.parse(micromarkOptions);
|
const parseContext = micromark.parse(micromarkParseOptions);
|
||||||
if (referencesDefined) {
|
if (shimReferences) {
|
||||||
// Customize ParseContext to treat all references as defined
|
// Customize ParseContext to treat all references as defined
|
||||||
parseContext.defined.includes = (searchElement) => searchElement.length > 0;
|
parseContext.defined.includes = (searchElement) => searchElement.length > 0;
|
||||||
}
|
}
|
||||||
|
|
@ -48,26 +58,27 @@ function getEvents(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a Markdown document and returns (frozen) tokens.
|
* Parses a Markdown document and returns micromark tokens (internal).
|
||||||
*
|
*
|
||||||
* @param {string} markdown Markdown document.
|
* @param {string} markdown Markdown document.
|
||||||
* @param {ParseOptions} micromarkOptions Options for micromark.
|
* @param {ParseOptions} [parseOptions] Options.
|
||||||
* @param {boolean} referencesDefined Treat references as defined.
|
* @param {MicromarkParseOptions} [micromarkParseOptions] Options for micromark.
|
||||||
* @param {number} lineDelta Offset to apply to start/end line.
|
* @param {number} [lineDelta] Offset for start/end line.
|
||||||
* @param {Token} [ancestor] Parent of top-most tokens.
|
* @param {Token} [ancestor] Parent of top-most tokens.
|
||||||
* @returns {Token[]} Micromark tokens (frozen).
|
* @returns {Token[]} Micromark tokens.
|
||||||
*/
|
*/
|
||||||
function parseWithOffset(
|
function parseInternal(
|
||||||
markdown,
|
markdown,
|
||||||
micromarkOptions,
|
parseOptions = {},
|
||||||
referencesDefined,
|
micromarkParseOptions = {},
|
||||||
lineDelta,
|
lineDelta = 0,
|
||||||
ancestor
|
ancestor = undefined
|
||||||
) {
|
) {
|
||||||
|
// Get options
|
||||||
|
const freezeTokens = Boolean(parseOptions.freezeTokens);
|
||||||
|
|
||||||
// Use micromark to parse document into Events
|
// Use micromark to parse document into Events
|
||||||
const events = getEvents(
|
const events = getEvents(markdown, parseOptions, micromarkParseOptions);
|
||||||
markdown, micromarkOptions, referencesDefined
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create Token objects
|
// Create Token objects
|
||||||
const document = [];
|
const document = [];
|
||||||
|
|
@ -86,7 +97,7 @@ function parseWithOffset(
|
||||||
const history = [ root ];
|
const history = [ root ];
|
||||||
let current = root;
|
let current = root;
|
||||||
// eslint-disable-next-line jsdoc/valid-types
|
// eslint-disable-next-line jsdoc/valid-types
|
||||||
/** @type ParseOptions | null */
|
/** @type MicromarkParseOptions | null */
|
||||||
let reparseOptions = null;
|
let reparseOptions = null;
|
||||||
let lines = null;
|
let lines = null;
|
||||||
let skipHtmlFlowChildren = false;
|
let skipHtmlFlowChildren = false;
|
||||||
|
|
@ -118,7 +129,7 @@ function parseWithOffset(
|
||||||
skipHtmlFlowChildren = true;
|
skipHtmlFlowChildren = true;
|
||||||
if (!reparseOptions || !lines) {
|
if (!reparseOptions || !lines) {
|
||||||
reparseOptions = {
|
reparseOptions = {
|
||||||
...micromarkOptions,
|
...micromarkParseOptions,
|
||||||
"extensions": [
|
"extensions": [
|
||||||
{
|
{
|
||||||
"disable": {
|
"disable": {
|
||||||
|
|
@ -132,10 +143,10 @@ function parseWithOffset(
|
||||||
const reparseMarkdown = lines
|
const reparseMarkdown = lines
|
||||||
.slice(current.startLine - 1, current.endLine)
|
.slice(current.startLine - 1, current.endLine)
|
||||||
.join("\n");
|
.join("\n");
|
||||||
const tokens = parseWithOffset(
|
const tokens = parseInternal(
|
||||||
reparseMarkdown,
|
reparseMarkdown,
|
||||||
|
parseOptions,
|
||||||
reparseOptions,
|
reparseOptions,
|
||||||
referencesDefined,
|
|
||||||
current.startLine - 1,
|
current.startLine - 1,
|
||||||
current
|
current
|
||||||
);
|
);
|
||||||
|
|
@ -149,8 +160,10 @@ function parseWithOffset(
|
||||||
skipHtmlFlowChildren = false;
|
skipHtmlFlowChildren = false;
|
||||||
}
|
}
|
||||||
if (!skipHtmlFlowChildren) {
|
if (!skipHtmlFlowChildren) {
|
||||||
Object.freeze(current.children);
|
if (freezeTokens) {
|
||||||
Object.freeze(current);
|
Object.freeze(current.children);
|
||||||
|
Object.freeze(current);
|
||||||
|
}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
current = history.pop();
|
current = history.pop();
|
||||||
}
|
}
|
||||||
|
|
@ -159,29 +172,21 @@ function parseWithOffset(
|
||||||
|
|
||||||
// Return document
|
// Return document
|
||||||
Object.defineProperty(document, flatTokensSymbol, { "value": flatTokens });
|
Object.defineProperty(document, flatTokensSymbol, { "value": flatTokens });
|
||||||
Object.freeze(document);
|
if (freezeTokens) {
|
||||||
|
Object.freeze(document);
|
||||||
|
}
|
||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a Markdown document and returns (frozen) tokens.
|
* Parses a Markdown document and returns micromark tokens.
|
||||||
*
|
*
|
||||||
* @param {string} markdown Markdown document.
|
* @param {string} markdown Markdown document.
|
||||||
* @param {ParseOptions} [micromarkOptions] Options for micromark.
|
* @param {ParseOptions} [parseOptions] Options.
|
||||||
* @param {boolean} [referencesDefined] Treat references as defined.
|
* @returns {Token[]} Micromark tokens.
|
||||||
* @returns {Token[]} Micromark tokens (frozen).
|
|
||||||
*/
|
*/
|
||||||
function parse(
|
function parse(markdown, parseOptions) {
|
||||||
markdown,
|
return parseInternal(markdown, parseOptions);
|
||||||
micromarkOptions = {},
|
|
||||||
referencesDefined = true
|
|
||||||
) {
|
|
||||||
return parseWithOffset(
|
|
||||||
markdown,
|
|
||||||
micromarkOptions,
|
|
||||||
referencesDefined,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
||||||
|
|
@ -495,8 +495,12 @@ function lintContent(
|
||||||
const needMarkdownItTokens = enabledRuleList.some(
|
const needMarkdownItTokens = enabledRuleList.some(
|
||||||
(rule) => (rule.parser === "markdownit") || (rule.parser === undefined)
|
(rule) => (rule.parser === "markdownit") || (rule.parser === undefined)
|
||||||
);
|
);
|
||||||
|
const customRulesPresent = (ruleList.length !== rules.length);
|
||||||
// Parse content into parser tokens
|
// Parse content into parser tokens
|
||||||
const micromarkTokens = micromark.parse(content);
|
const micromarkTokens = micromark.parse(
|
||||||
|
content,
|
||||||
|
{ "freezeTokens": customRulesPresent, "shimReferences": true }
|
||||||
|
);
|
||||||
// Hide the content of HTML comments from rules
|
// Hide the content of HTML comments from rules
|
||||||
const preClearedContent = content;
|
const preClearedContent = content;
|
||||||
content = helpers.clearHtmlCommentText(content);
|
content = helpers.clearHtmlCommentText(content);
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ module.exports = {
|
||||||
if (autoLinks.length > 0) {
|
if (autoLinks.length > 0) {
|
||||||
// Re-parse with correct link/image reference definition handling
|
// Re-parse with correct link/image reference definition handling
|
||||||
const document = params.lines.join("\n");
|
const document = params.lines.join("\n");
|
||||||
const tokens = parse(document, undefined, false);
|
const tokens = parse(document);
|
||||||
for (const token of literalAutolinks(tokens)) {
|
for (const token of literalAutolinks(tokens)) {
|
||||||
const range = [
|
const range = [
|
||||||
token.startColumn,
|
token.startColumn,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue