Enable ESLint rule unicorn/no-array-for-each, auto-fix all violations, manually address new issues for ~4% time reduction measured via profile-fixture.mjs on Apple Silicon M1.

This commit is contained in:
David Anson 2022-06-08 22:10:27 -07:00
parent 15efcb4282
commit b6471fba31
34 changed files with 414 additions and 389 deletions

View file

@ -29,32 +29,32 @@ function validateRuleList(ruleList, synchronous) {
return result;
}
const allIds = {};
ruleList.forEach(function forRule(rule, index) {
for (const [ index, rule ] of ruleList.entries()) {
const customIndex = index - rules.length;
// eslint-disable-next-line jsdoc/require-jsdoc
// eslint-disable-next-line no-inner-declarations, jsdoc/require-jsdoc
function newError(property) {
return new Error(
"Property '" + property + "' of custom rule at index " +
customIndex + " is incorrect.");
}
[ "names", "tags" ].forEach(function forProperty(property) {
for (const property of [ "names", "tags" ]) {
const value = rule[property];
if (!result &&
(!value || !Array.isArray(value) || (value.length === 0) ||
!value.every(helpers.isString) || value.some(helpers.isEmptyString))) {
result = newError(property);
}
});
[
}
for (const propertyInfo of [
[ "description", "string" ],
[ "function", "function" ]
].forEach(function forProperty(propertyInfo) {
]) {
const property = propertyInfo[0];
const value = rule[property];
if (!result && (!value || (typeof value !== propertyInfo[1]))) {
result = newError(property);
}
});
}
if (
!result &&
rule.information &&
@ -76,24 +76,25 @@ function validateRuleList(ruleList, synchronous) {
);
}
if (!result) {
rule.names.forEach(function forName(name) {
for (const name of rule.names) {
const nameUpper = name.toUpperCase();
if (!result && (allIds[nameUpper] !== undefined)) {
result = new Error("Name '" + name + "' of custom rule at index " +
customIndex + " is already used as a name or tag.");
}
allIds[nameUpper] = true;
});
rule.tags.forEach(function forTag(tag) {
}
for (const tag of rule.tags) {
const tagUpper = tag.toUpperCase();
if (!result && allIds[tagUpper]) {
result = new Error("Tag '" + tag + "' of custom rule at index " +
customIndex + " is already used as a name.");
}
allIds[tagUpper] = false;
});
}
}
});
}
// @ts-ignore
return result;
}
@ -111,10 +112,10 @@ function newResults(ruleList) {
const results = [];
const keys = Object.keys(lintResults);
keys.sort();
keys.forEach(function forFile(file) {
for (const file of keys) {
const fileResults = lintResults[file];
if (Array.isArray(fileResults)) {
fileResults.forEach(function forResult(result) {
for (const result of fileResults) {
const ruleMoniker = result.ruleNames ?
result.ruleNames.join("/") :
(result.ruleName + "/" + result.ruleAlias);
@ -129,30 +130,32 @@ function newResults(ruleList) {
(result.errorContext ?
" [Context: \"" + result.errorContext + "\"]" :
""));
});
}
} else {
if (!ruleNameToRule) {
ruleNameToRule = {};
ruleList.forEach(function forRule(rule) {
for (const rule of ruleList) {
const ruleName = rule.names[0].toUpperCase();
ruleNameToRule[ruleName] = rule;
});
}
}
Object.keys(fileResults).forEach(function forRule(ruleName) {
for (const [ ruleName, ruleResults ] of Object.entries(fileResults)) {
const rule = ruleNameToRule[ruleName.toUpperCase()];
const ruleResults = fileResults[ruleName];
ruleResults.forEach(function forLine(lineNumber) {
for (const lineNumber of ruleResults) {
// @ts-ignore
const nameIndex = Math.min(useAlias ? 1 : 0, rule.names.length - 1);
const result =
file + ": " +
lineNumber + ": " +
// @ts-ignore
rule.names[nameIndex] + " " +
// @ts-ignore
rule.description;
results.push(result);
});
});
}
}
}
});
}
return results.join("\n");
}
Object.defineProperty(lintResults, "toString", { "value": toString });
@ -196,7 +199,7 @@ function removeFrontMatter(content, frontMatter) {
*/
function annotateTokens(tokens, lines) {
let trMap = null;
tokens.forEach(function forToken(token) {
for (const token of tokens) {
// Provide missing maps for table content
if (token.type === "tr_open") {
trMap = token.map;
@ -228,7 +231,7 @@ function annotateTokens(tokens, lines) {
codeSpanExtraLines.push(code.split(helpers.newLineRe).length - 1);
}
);
(token.children || []).forEach(function forChild(child) {
for (const child of (token.children || [])) {
child.lineNumber = lineNumber;
child.line = lines[lineNumber - 1];
if ((child.type === "softbreak") || (child.type === "hardbreak")) {
@ -236,9 +239,9 @@ function annotateTokens(tokens, lines) {
} else if (child.type === "code_inline") {
lineNumber += codeSpanExtraLines.shift();
}
});
}
}
});
}
}
/**
@ -250,24 +253,24 @@ function annotateTokens(tokens, lines) {
function mapAliasToRuleNames(ruleList) {
const aliasToRuleNames = {};
// const tagToRuleNames = {};
ruleList.forEach(function forRule(rule) {
for (const rule of ruleList) {
const ruleName = rule.names[0].toUpperCase();
// The following is useful for updating README.md:
// console.log(
// "* **[" + ruleName + "](doc/Rules.md#" + ruleName.toLowerCase() +
// ")** *" + rule.names.slice(1).join("/") + "* - " + rule.description);
rule.names.forEach(function forName(name) {
for (const name of rule.names) {
const nameUpper = name.toUpperCase();
aliasToRuleNames[nameUpper] = [ ruleName ];
});
rule.tags.forEach(function forTag(tag) {
}
for (const tag of rule.tags) {
const tagUpper = tag.toUpperCase();
const ruleNames = aliasToRuleNames[tagUpper] || [];
ruleNames.push(ruleName);
aliasToRuleNames[tagUpper] = ruleNames;
// tagToRuleNames[tag] = ruleName;
});
});
}
}
// The following is useful for updating README.md:
// Object.keys(tagToRuleNames).sort().forEach(function forTag(tag) {
// console.log("* **" + tag + "** - " +
@ -292,14 +295,14 @@ function getEffectiveConfig(ruleList, config, aliasToRuleNames) {
);
const ruleDefault = (defaultKey.length === 0) || !!config[defaultKey[0]];
const effectiveConfig = {};
ruleList.forEach((rule) => {
for (const rule of ruleList) {
const ruleName = rule.names[0].toUpperCase();
effectiveConfig[ruleName] = ruleDefault;
});
deprecatedRuleNames.forEach((ruleName) => {
}
for (const ruleName of deprecatedRuleNames) {
effectiveConfig[ruleName] = false;
});
Object.keys(config).forEach((key) => {
}
for (const key of Object.keys(config)) {
let value = config[key];
if (value) {
if (!(value instanceof Object)) {
@ -309,10 +312,10 @@ function getEffectiveConfig(ruleList, config, aliasToRuleNames) {
value = false;
}
const keyUpper = key.toUpperCase();
(aliasToRuleNames[keyUpper] || []).forEach((ruleName) => {
for (const ruleName of (aliasToRuleNames[keyUpper] || [])) {
effectiveConfig[ruleName] = value;
});
});
}
}
return effectiveConfig;
}
@ -378,7 +381,7 @@ function getEnabledRulesPerLineNumber(
// Helper functions
// eslint-disable-next-line jsdoc/require-jsdoc
function handleInlineConfig(input, forEachMatch, forEachLine) {
input.forEach((line, lineIndex) => {
for (const [ lineIndex, line ] of input.entries()) {
if (!noInlineConfig) {
let match = null;
while ((match = helpers.inlineCommentStartRe.exec(line))) {
@ -395,7 +398,7 @@ function getEnabledRulesPerLineNumber(
if (forEachLine) {
forEachLine();
}
});
}
}
// eslint-disable-next-line jsdoc/require-jsdoc
function configureFile(action, parameter) {
@ -417,11 +420,11 @@ function getEnabledRulesPerLineNumber(
const enabled = (action.startsWith("ENABLE"));
const trimmed = parameter && parameter.trim();
const items = trimmed ? trimmed.toUpperCase().split(/\s+/) : allRuleNames;
items.forEach((nameUpper) => {
(aliasToRuleNames[nameUpper] || []).forEach((ruleName) => {
for (const nameUpper of items) {
for (const ruleName of (aliasToRuleNames[nameUpper] || [])) {
state[ruleName] = enabled;
});
});
}
}
return state;
}
// eslint-disable-next-line jsdoc/require-jsdoc
@ -463,11 +466,11 @@ function getEnabledRulesPerLineNumber(
handleInlineConfig([ lines.join("\n") ], configureFile);
const effectiveConfig = getEffectiveConfig(
ruleList, config, aliasToRuleNames);
ruleList.forEach((rule) => {
for (const rule of ruleList) {
const ruleName = rule.names[0].toUpperCase();
allRuleNames.push(ruleName);
enabledRules[ruleName] = !!effectiveConfig[ruleName];
});
}
capturedRules = enabledRules;
handleInlineConfig(lines, enableDisableFile);
handleInlineConfig(lines, captureRestoreEnableDisable, updateLineState);
@ -844,10 +847,10 @@ function lintInput(options, synchronous, callback) {
3 : options.resultVersion;
const md = markdownIt({ "html": true });
const markdownItPlugins = options.markdownItPlugins || [];
markdownItPlugins.forEach(function forPlugin(plugin) {
for (const plugin of markdownItPlugins) {
// @ts-ignore
md.use(...plugin);
});
}
const fs = options.fs || require("fs");
const results = newResults(ruleList);
let done = false;

View file

@ -26,12 +26,12 @@ module.exports = {
const style = String(params.config.style || "consistent");
let expectedStyle = style;
const nestingStyles = [];
flattenedLists().forEach((list) => {
for (const list of flattenedLists()) {
if (list.unordered) {
if (expectedStyle === "consistent") {
expectedStyle = unorderedListStyleFor(list.items[0]);
}
list.items.forEach((item) => {
for (const item of list.items) {
const itemStyle = unorderedListStyleFor(item);
if (style === "sublist") {
const nesting = list.nesting;
@ -69,8 +69,8 @@ module.exports = {
range,
fixInfo
);
});
}
}
});
}
}
};

View file

@ -11,12 +11,12 @@ module.exports = {
"description": "Inconsistent indentation for list items at the same level",
"tags": [ "bullet", "ul", "indentation" ],
"function": function MD005(params, onError) {
flattenedLists().forEach((list) => {
for (const list of flattenedLists()) {
const expectedIndent = list.indent;
let expectedEnd = 0;
let actualEnd = -1;
let endMatching = false;
list.items.forEach((item) => {
for (const item of list.items) {
const { line, lineNumber } = item;
const actualIndent = indentFor(item);
let match = null;
@ -63,7 +63,7 @@ module.exports = {
}
}
}
});
});
}
}
}
};

View file

@ -12,9 +12,9 @@ module.exports = {
"Consider starting bulleted lists at the beginning of the line",
"tags": [ "bullet", "ul", "indentation" ],
"function": function MD006(params, onError) {
flattenedLists().forEach((list) => {
for (const list of flattenedLists()) {
if (list.unordered && !list.nesting && (list.indent !== 0)) {
list.items.forEach((item) => {
for (const item of list.items) {
const { lineNumber, line } = item;
addErrorDetailIf(
onError,
@ -27,8 +27,8 @@ module.exports = {
{
"deleteCount": line.length - line.trimStart().length
});
});
}
}
});
}
}
};

View file

@ -14,9 +14,9 @@ module.exports = {
const indent = Number(params.config.indent || 2);
const startIndented = !!params.config.start_indented;
const startIndent = Number(params.config.start_indent || indent);
flattenedLists().forEach((list) => {
for (const list of flattenedLists()) {
if (list.unordered && list.parentsUnordered) {
list.items.forEach((item) => {
for (const item of list.items) {
const { lineNumber, line } = item;
const expectedIndent =
(startIndented ? startIndent : 0) +
@ -42,8 +42,8 @@ module.exports = {
"deleteCount": actualIndent,
"insertText": "".padEnd(expectedIndent)
});
});
}
}
});
}
}
};

View file

@ -58,11 +58,11 @@ module.exports = {
const linkOnlyLineNumbers = [];
filterTokens(params, "inline", (token) => {
let childTokenTypes = "";
token.children.forEach((child) => {
for (const child of token.children) {
if (child.type !== "text" || child.content !== "") {
childTokenTypes += tokenTypeMap[child.type] || "x";
}
});
}
if (linkOrImageOnlyLineRe.test(childTokenTypes)) {
linkOnlyLineNumbers.push(token.lineNumber);
}

View file

@ -11,7 +11,7 @@ module.exports = {
"description": "Dollar signs used before commands without showing output",
"tags": [ "code" ],
"function": function MD014(params, onError) {
[ "code_block", "fence" ].forEach((type) => {
for (const type of [ "code_block", "fence" ]) {
filterTokens(params, type, (token) => {
const margin = (token.type === "fence") ? 1 : 0;
const dollarInstances = [];
@ -31,7 +31,7 @@ module.exports = {
}
}
if (allDollars) {
dollarInstances.forEach((instance) => {
for (const instance of dollarInstances) {
const [ i, lineTrim, column, length ] = instance;
addErrorContext(
onError,
@ -45,9 +45,9 @@ module.exports = {
"deleteCount": length
}
);
});
}
}
});
});
}
}
};

View file

@ -13,7 +13,7 @@ module.exports = {
"function": function MD027(params, onError) {
let blockquoteNesting = 0;
let listItemNesting = 0;
params.tokens.forEach((token) => {
for (const token of params.tokens) {
const { content, lineNumber, type } = token;
if (type === "blockquote_open") {
blockquoteNesting++;
@ -51,6 +51,6 @@ module.exports = {
}
}
}
});
}
}
};

View file

@ -11,7 +11,7 @@ module.exports = {
"function": function MD028(params, onError) {
let prevToken = {};
let prevLineNumber = null;
params.tokens.forEach(function forToken(token) {
for (const token of params.tokens) {
if ((token.type === "blockquote_open") &&
(prevToken.type === "blockquote_close")) {
for (
@ -25,6 +25,6 @@ module.exports = {
if (token.type === "blockquote_open") {
prevLineNumber = token.map[1] + 1;
}
});
}
}
};

View file

@ -18,7 +18,8 @@ module.exports = {
"tags": [ "ol" ],
"function": function MD029(params, onError) {
const style = String(params.config.style || "one_or_ordered");
flattenedLists().filter((list) => !list.unordered).forEach((list) => {
const filteredLists = flattenedLists().filter((list) => !list.unordered);
for (const list of filteredLists) {
const { items } = list;
let current = 1;
let incrementing = false;
@ -49,7 +50,7 @@ module.exports = {
current = 1;
}
// Validate each list item marker
items.forEach((item) => {
for (const item of items) {
const match = orderedListItemMarkerRe.exec(item.line);
if (match) {
addErrorDetailIf(onError, item.lineNumber,
@ -60,7 +61,7 @@ module.exports = {
current++;
}
}
});
});
}
}
}
};

View file

@ -14,13 +14,13 @@ module.exports = {
const olSingle = Number(params.config.ol_single || 1);
const ulMulti = Number(params.config.ul_multi || 1);
const olMulti = Number(params.config.ol_multi || 1);
flattenedLists().forEach((list) => {
for (const list of flattenedLists()) {
const lineCount = list.lastLineIndex - list.open.map[0];
const allSingle = lineCount === list.items.length;
const expectedSpaces = list.unordered ?
(allSingle ? ulSingle : ulMulti) :
(allSingle ? olSingle : olMulti);
list.items.forEach((item) => {
for (const item of list.items) {
const { line, lineNumber } = item;
const match = /^[\s>]*\S+(\s*)/.exec(line);
const [ { "length": matchLength }, { "length": actualSpaces } ] = match;
@ -44,7 +44,7 @@ module.exports = {
fixInfo
);
}
});
});
}
}
}
};

View file

@ -13,7 +13,8 @@ module.exports = {
"tags": [ "bullet", "ul", "ol", "blank_lines" ],
"function": function MD032(params, onError) {
const { lines } = params;
flattenedLists().filter((list) => !list.nesting).forEach((list) => {
const filteredLists = flattenedLists().filter((list) => !list.nesting);
for (const list of filteredLists) {
const firstIndex = list.open.map[0];
if (!isBlankLine(lines[firstIndex - 1])) {
const line = lines[firstIndex];
@ -45,6 +46,6 @@ module.exports = {
"insertText": `${quotePrefix}\n`
});
}
});
}
}
};

View file

@ -11,7 +11,7 @@ module.exports = {
"function": function MD034(params, onError) {
filterTokens(params, "inline", (token) => {
let inLink = false;
token.children.forEach((child) => {
for (const child of token.children) {
const { content, line, lineNumber, type } = child;
let match = null;
if (type === "link_open") {
@ -55,7 +55,7 @@ module.exports = {
}
}
}
});
}
});
}
};

View file

@ -49,8 +49,8 @@ module.exports = {
return base;
}
let state = base;
params.tokens.forEach(function forToken(token) {
for (const token of params.tokens) {
state = state(token);
});
}
}
};

View file

@ -18,7 +18,7 @@ module.exports = {
let inLink = false;
let linkText = "";
let lineIndex = 0;
children.forEach((child) => {
for (const child of children) {
const { content, markup, type } = child;
if (type === "link_open") {
inLink = true;
@ -61,7 +61,7 @@ module.exports = {
`${markup}${content}${markup}` :
(content || markup);
}
});
}
});
}
};

View file

@ -14,15 +14,15 @@ module.exports = {
let inLink = false;
let linkText = "";
let emptyLink = false;
token.children.forEach(function forChild(child) {
for (const child of token.children) {
if (child.type === "link_open") {
inLink = true;
linkText = "";
child.attrs.forEach(function forAttr(attr) {
for (const attr of child.attrs) {
if (attr[0] === "href" && (!attr[1] || (attr[1] === "#"))) {
emptyLink = true;
}
});
}
} else if (child.type === "link_close") {
inLink = false;
if (emptyLink) {
@ -43,7 +43,7 @@ module.exports = {
} else if (inLink) {
linkText += child.content;
}
});
}
});
}
};

View file

@ -13,9 +13,9 @@ module.exports = {
const requiredHeadings = params.config.headings || params.config.headers;
if (Array.isArray(requiredHeadings)) {
const levels = {};
[ 1, 2, 3, 4, 5, 6 ].forEach((level) => {
for (const level of [ 1, 2, 3, 4, 5, 6 ]) {
levels["h" + level] = "######".substr(-level);
});
}
let i = 0;
let matchAny = false;
let hasError = false;

View file

@ -15,18 +15,19 @@ module.exports = {
"tags": [ "code" ],
"function": function MD046(params, onError) {
let expectedStyle = String(params.config.style || "consistent");
params.tokens
.filter((token) => token.type === "code_block" || token.type === "fence")
.forEach((token) => {
const { lineNumber, type } = token;
if (expectedStyle === "consistent") {
expectedStyle = tokenTypeToStyle[type];
}
addErrorDetailIf(
onError,
lineNumber,
expectedStyle,
tokenTypeToStyle[type]);
});
const codeBlocksAndFences = params.tokens.filter(
(token) => (token.type === "code_block") || (token.type === "fence")
);
for (const token of codeBlocksAndFences) {
const { lineNumber, type } = token;
if (expectedStyle === "consistent") {
expectedStyle = tokenTypeToStyle[type];
}
addErrorDetailIf(
onError,
lineNumber,
expectedStyle,
tokenTypeToStyle[type]);
}
}
};

View file

@ -11,19 +11,18 @@ module.exports = {
"function": function MD048(params, onError) {
const style = String(params.config.style || "consistent");
let expectedStyle = style;
params.tokens
.filter((token) => token.type === "fence")
.forEach((fenceToken) => {
const { lineNumber, markup } = fenceToken;
if (expectedStyle === "consistent") {
expectedStyle = fencedCodeBlockStyleFor(markup);
}
addErrorDetailIf(
onError,
lineNumber,
expectedStyle,
fencedCodeBlockStyleFor(markup)
);
});
const fenceTokens = params.tokens.filter((token) => token.type === "fence");
for (const fenceToken of fenceTokens) {
const { lineNumber, markup } = fenceToken;
if (expectedStyle === "consistent") {
expectedStyle = fencedCodeBlockStyleFor(markup);
}
addErrorDetailIf(
onError,
lineNumber,
expectedStyle,
fencedCodeBlockStyleFor(markup)
);
}
}
};

View file

@ -54,10 +54,10 @@ const rules = [
require("./md052"),
require("./md053")
];
rules.forEach((rule) => {
for (const rule of rules) {
const name = rule.names[0].toLowerCase();
// eslint-disable-next-line dot-notation
rule["information"] =
new URL(`${homepage}/blob/v${version}/doc/Rules.md#${name}`);
});
}
module.exports = rules;