mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-09-22 05:40:48 +02:00
Remove helpers.deepFreeze and call Object.freeze only on things that need it for ~11% time reduction measured via profile-fixture.mjs on Apple Silicon M1.
This commit is contained in:
parent
b6471fba31
commit
936c876810
5 changed files with 110 additions and 97 deletions
|
@ -1113,27 +1113,6 @@ function getNextChildToken(parentToken, childToken, nextType, nextNextType) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
module.exports.getNextChildToken = getNextChildToken;
|
module.exports.getNextChildToken = getNextChildToken;
|
||||||
/**
|
|
||||||
* Calls Object.freeze() on an object and its children.
|
|
||||||
*
|
|
||||||
* @param {Object} obj Object to deep freeze.
|
|
||||||
* @returns {Object} Object passed to the function.
|
|
||||||
*/
|
|
||||||
function deepFreeze(obj) {
|
|
||||||
const pending = [obj];
|
|
||||||
let current = null;
|
|
||||||
while ((current = pending.shift())) {
|
|
||||||
Object.freeze(current);
|
|
||||||
for (const name of Object.getOwnPropertyNames(current)) {
|
|
||||||
const value = current[name];
|
|
||||||
if (value && (typeof value === "object")) {
|
|
||||||
pending.push(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
module.exports.deepFreeze = deepFreeze;
|
|
||||||
/**
|
/**
|
||||||
* Expands a path with a tilde to an absolute path.
|
* Expands a path with a tilde to an absolute path.
|
||||||
*
|
*
|
||||||
|
@ -1442,13 +1421,37 @@ function removeFrontMatter(content, frontMatter) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Annotate tokens with line/lineNumber.
|
* Freeze all freeze-able members of a token and its children.
|
||||||
|
*
|
||||||
|
* @param {MarkdownItToken} token A markdown-it token.
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function freezeToken(token) {
|
||||||
|
if (token.attrs) {
|
||||||
|
for (const attr of token.attrs) {
|
||||||
|
Object.freeze(attr);
|
||||||
|
}
|
||||||
|
Object.freeze(token.attrs);
|
||||||
|
}
|
||||||
|
if (token.children) {
|
||||||
|
for (const child of token.children) {
|
||||||
|
freezeToken(child);
|
||||||
|
}
|
||||||
|
Object.freeze(token.children);
|
||||||
|
}
|
||||||
|
if (token.map) {
|
||||||
|
Object.freeze(token.map);
|
||||||
|
}
|
||||||
|
Object.freeze(token);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Annotate tokens with line/lineNumber and freeze them.
|
||||||
*
|
*
|
||||||
* @param {MarkdownItToken[]} tokens Array of markdown-it tokens.
|
* @param {MarkdownItToken[]} tokens Array of markdown-it tokens.
|
||||||
* @param {string[]} lines Lines of Markdown content.
|
* @param {string[]} lines Lines of Markdown content.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function annotateTokens(tokens, lines) {
|
function annotateAndFreezeTokens(tokens, lines) {
|
||||||
let trMap = null;
|
let trMap = null;
|
||||||
for (const token of tokens) {
|
for (const token of tokens) {
|
||||||
// Provide missing maps for table content
|
// Provide missing maps for table content
|
||||||
|
@ -1474,13 +1477,15 @@ function annotateTokens(tokens, lines) {
|
||||||
while (token.map[1] && !((lines[token.map[1] - 1] || "").trim())) {
|
while (token.map[1] && !((lines[token.map[1] - 1] || "").trim())) {
|
||||||
token.map[1]--;
|
token.map[1]--;
|
||||||
}
|
}
|
||||||
// Annotate children with lineNumber
|
}
|
||||||
|
// Annotate children with lineNumber
|
||||||
|
if (token.children) {
|
||||||
let lineNumber = token.lineNumber;
|
let lineNumber = token.lineNumber;
|
||||||
const codeSpanExtraLines = [];
|
const codeSpanExtraLines = [];
|
||||||
helpers.forEachInlineCodeSpan(token.content, function handleInlineCodeSpan(code) {
|
helpers.forEachInlineCodeSpan(token.content, function handleInlineCodeSpan(code) {
|
||||||
codeSpanExtraLines.push(code.split(helpers.newLineRe).length - 1);
|
codeSpanExtraLines.push(code.split(helpers.newLineRe).length - 1);
|
||||||
});
|
});
|
||||||
for (const child of (token.children || [])) {
|
for (const child of token.children) {
|
||||||
child.lineNumber = lineNumber;
|
child.lineNumber = lineNumber;
|
||||||
child.line = lines[lineNumber - 1];
|
child.line = lines[lineNumber - 1];
|
||||||
if ((child.type === "softbreak") || (child.type === "hardbreak")) {
|
if ((child.type === "softbreak") || (child.type === "hardbreak")) {
|
||||||
|
@ -1491,7 +1496,9 @@ function annotateTokens(tokens, lines) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
freezeToken(token);
|
||||||
}
|
}
|
||||||
|
Object.freeze(tokens);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Map rule names/tags to canonical rule name.
|
* Map rule names/tags to canonical rule name.
|
||||||
|
@ -1741,14 +1748,14 @@ function lintContent(ruleList, name, content, md, config, configParsers, frontMa
|
||||||
// Parse content into tokens and lines
|
// Parse content into tokens and lines
|
||||||
const tokens = md.parse(content, {});
|
const tokens = md.parse(content, {});
|
||||||
const lines = content.split(helpers.newLineRe);
|
const lines = content.split(helpers.newLineRe);
|
||||||
annotateTokens(tokens, lines);
|
annotateAndFreezeTokens(tokens, lines);
|
||||||
// Create parameters for rules
|
// Create (frozen) parameters for rules
|
||||||
const paramsBase = helpers.deepFreeze({
|
const paramsBase = {
|
||||||
name,
|
name,
|
||||||
tokens,
|
tokens,
|
||||||
lines,
|
"lines": Object.freeze(lines),
|
||||||
frontMatterLines
|
"frontMatterLines": Object.freeze(frontMatterLines)
|
||||||
});
|
};
|
||||||
const lineMetadata = helpers.getLineMetadata(paramsBase);
|
const lineMetadata = helpers.getLineMetadata(paramsBase);
|
||||||
const codeBlockAndSpanRanges = helpers.codeBlockAndSpanRanges(paramsBase, lineMetadata);
|
const codeBlockAndSpanRanges = helpers.codeBlockAndSpanRanges(paramsBase, lineMetadata);
|
||||||
const flattenedLists = helpers.flattenLists(paramsBase.tokens);
|
const flattenedLists = helpers.flattenLists(paramsBase.tokens);
|
||||||
|
|
|
@ -1153,28 +1153,6 @@ function getNextChildToken(parentToken, childToken, nextType, nextNextType) {
|
||||||
}
|
}
|
||||||
module.exports.getNextChildToken = getNextChildToken;
|
module.exports.getNextChildToken = getNextChildToken;
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls Object.freeze() on an object and its children.
|
|
||||||
*
|
|
||||||
* @param {Object} obj Object to deep freeze.
|
|
||||||
* @returns {Object} Object passed to the function.
|
|
||||||
*/
|
|
||||||
function deepFreeze(obj) {
|
|
||||||
const pending = [ obj ];
|
|
||||||
let current = null;
|
|
||||||
while ((current = pending.shift())) {
|
|
||||||
Object.freeze(current);
|
|
||||||
for (const name of Object.getOwnPropertyNames(current)) {
|
|
||||||
const value = current[name];
|
|
||||||
if (value && (typeof value === "object")) {
|
|
||||||
pending.push(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
module.exports.deepFreeze = deepFreeze;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expands a path with a tilde to an absolute path.
|
* Expands a path with a tilde to an absolute path.
|
||||||
*
|
*
|
||||||
|
|
|
@ -191,13 +191,38 @@ function removeFrontMatter(content, frontMatter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Annotate tokens with line/lineNumber.
|
* Freeze all freeze-able members of a token and its children.
|
||||||
|
*
|
||||||
|
* @param {MarkdownItToken} token A markdown-it token.
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function freezeToken(token) {
|
||||||
|
if (token.attrs) {
|
||||||
|
for (const attr of token.attrs) {
|
||||||
|
Object.freeze(attr);
|
||||||
|
}
|
||||||
|
Object.freeze(token.attrs);
|
||||||
|
}
|
||||||
|
if (token.children) {
|
||||||
|
for (const child of token.children) {
|
||||||
|
freezeToken(child);
|
||||||
|
}
|
||||||
|
Object.freeze(token.children);
|
||||||
|
}
|
||||||
|
if (token.map) {
|
||||||
|
Object.freeze(token.map);
|
||||||
|
}
|
||||||
|
Object.freeze(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotate tokens with line/lineNumber and freeze them.
|
||||||
*
|
*
|
||||||
* @param {MarkdownItToken[]} tokens Array of markdown-it tokens.
|
* @param {MarkdownItToken[]} tokens Array of markdown-it tokens.
|
||||||
* @param {string[]} lines Lines of Markdown content.
|
* @param {string[]} lines Lines of Markdown content.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function annotateTokens(tokens, lines) {
|
function annotateAndFreezeTokens(tokens, lines) {
|
||||||
let trMap = null;
|
let trMap = null;
|
||||||
for (const token of tokens) {
|
for (const token of tokens) {
|
||||||
// Provide missing maps for table content
|
// Provide missing maps for table content
|
||||||
|
@ -222,7 +247,9 @@ function annotateTokens(tokens, lines) {
|
||||||
while (token.map[1] && !((lines[token.map[1] - 1] || "").trim())) {
|
while (token.map[1] && !((lines[token.map[1] - 1] || "").trim())) {
|
||||||
token.map[1]--;
|
token.map[1]--;
|
||||||
}
|
}
|
||||||
// Annotate children with lineNumber
|
}
|
||||||
|
// Annotate children with lineNumber
|
||||||
|
if (token.children) {
|
||||||
let lineNumber = token.lineNumber;
|
let lineNumber = token.lineNumber;
|
||||||
const codeSpanExtraLines = [];
|
const codeSpanExtraLines = [];
|
||||||
helpers.forEachInlineCodeSpan(
|
helpers.forEachInlineCodeSpan(
|
||||||
|
@ -231,7 +258,7 @@ function annotateTokens(tokens, lines) {
|
||||||
codeSpanExtraLines.push(code.split(helpers.newLineRe).length - 1);
|
codeSpanExtraLines.push(code.split(helpers.newLineRe).length - 1);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
for (const child of (token.children || [])) {
|
for (const child of token.children) {
|
||||||
child.lineNumber = lineNumber;
|
child.lineNumber = lineNumber;
|
||||||
child.line = lines[lineNumber - 1];
|
child.line = lines[lineNumber - 1];
|
||||||
if ((child.type === "softbreak") || (child.type === "hardbreak")) {
|
if ((child.type === "softbreak") || (child.type === "hardbreak")) {
|
||||||
|
@ -241,7 +268,9 @@ function annotateTokens(tokens, lines) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
freezeToken(token);
|
||||||
}
|
}
|
||||||
|
Object.freeze(tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -532,14 +561,14 @@ function lintContent(
|
||||||
// Parse content into tokens and lines
|
// Parse content into tokens and lines
|
||||||
const tokens = md.parse(content, {});
|
const tokens = md.parse(content, {});
|
||||||
const lines = content.split(helpers.newLineRe);
|
const lines = content.split(helpers.newLineRe);
|
||||||
annotateTokens(tokens, lines);
|
annotateAndFreezeTokens(tokens, lines);
|
||||||
// Create parameters for rules
|
// Create (frozen) parameters for rules
|
||||||
const paramsBase = helpers.deepFreeze({
|
const paramsBase = {
|
||||||
name,
|
name,
|
||||||
tokens,
|
tokens,
|
||||||
lines,
|
"lines": Object.freeze(lines),
|
||||||
frontMatterLines
|
"frontMatterLines": Object.freeze(frontMatterLines)
|
||||||
});
|
};
|
||||||
const lineMetadata =
|
const lineMetadata =
|
||||||
helpers.getLineMetadata(paramsBase);
|
helpers.getLineMetadata(paramsBase);
|
||||||
const codeBlockAndSpanRanges =
|
const codeBlockAndSpanRanges =
|
||||||
|
|
|
@ -1200,6 +1200,39 @@ test("customRulesAsyncThrowsInSyncContext", (t) => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("customRulesParamsAreFrozen", (t) => {
|
||||||
|
const options = {
|
||||||
|
"customRules": [
|
||||||
|
{
|
||||||
|
"names": [ "name" ],
|
||||||
|
"description": "description",
|
||||||
|
"tags": [ "tag" ],
|
||||||
|
"function":
|
||||||
|
(params) => {
|
||||||
|
const pending = [ params ];
|
||||||
|
let current = null;
|
||||||
|
while ((current = pending.shift())) {
|
||||||
|
t.true(Object.isFrozen(current) || (current === params));
|
||||||
|
for (const name of Object.getOwnPropertyNames(current)) {
|
||||||
|
const value = current[name];
|
||||||
|
if (value && (typeof value === "object")) {
|
||||||
|
pending.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"CONTRIBUTING.md",
|
||||||
|
"README.md",
|
||||||
|
"doc/CustomRules.md",
|
||||||
|
"doc/Rules.md"
|
||||||
|
]
|
||||||
|
};
|
||||||
|
return markdownlint.promises.markdownlint(options).then(() => null);
|
||||||
|
});
|
||||||
|
|
||||||
test("customRulesParamsAreStable", (t) => {
|
test("customRulesParamsAreStable", (t) => {
|
||||||
t.plan(4);
|
t.plan(4);
|
||||||
const config1 = { "value1": 10 };
|
const config1 = { "value1": 10 };
|
||||||
|
|
|
@ -953,40 +953,6 @@ test("applyFixes", (t) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("deepFreeze", (t) => {
|
|
||||||
t.plan(6);
|
|
||||||
const obj = {
|
|
||||||
"prop": true,
|
|
||||||
"func": () => true,
|
|
||||||
"sub": {
|
|
||||||
"prop": [ 1 ],
|
|
||||||
"sub": {
|
|
||||||
"prop": "one"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
t.is(helpers.deepFreeze(obj), obj, "Did not return object.");
|
|
||||||
for (const scenario of [
|
|
||||||
() => {
|
|
||||||
obj.prop = false;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
obj.func = () => false;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
obj.sub.prop = [];
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
obj.sub.prop[0] = 0;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
obj.sub.sub.prop = "zero";
|
|
||||||
}
|
|
||||||
]) {
|
|
||||||
t.throws(scenario, null, "Assigned to frozen object.");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test("forEachLink", (t) => {
|
test("forEachLink", (t) => {
|
||||||
t.plan(291);
|
t.plan(291);
|
||||||
const testCases = [
|
const testCases = [
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue