Add lint rules from eslint-plugin-unicorn.

This commit is contained in:
David Anson 2020-09-06 20:34:10 -07:00
parent 0f4745efe3
commit 5ab938a6ab
11 changed files with 96 additions and 31 deletions

View file

@ -8,7 +8,8 @@
}, },
"plugins": [ "plugins": [
"jsdoc", "jsdoc",
"node" "node",
"unicorn"
], ],
"extends": [ "extends": [
"eslint:all", "eslint:all",
@ -113,6 +114,62 @@
"node/prefer-global/url-search-params": "error", "node/prefer-global/url-search-params": "error",
"node/prefer-global/url": "error", "node/prefer-global/url": "error",
"node/prefer-promises/dns": "error", "node/prefer-promises/dns": "error",
"node/prefer-promises/fs": "off" "node/prefer-promises/fs": "off",
"unicorn/better-regex": "off",
"unicorn/catch-error-name": "error",
"unicorn/consistent-function-scoping": "off",
"unicorn/custom-error-definition": "error",
"unicorn/error-message": "error",
"unicorn/escape-case": "error",
"unicorn/expiring-todo-comments": "error",
"unicorn/explicit-length-check": "error",
"unicorn/filename-case": "off",
"unicorn/import-index": "error",
"unicorn/new-for-builtins": "error",
"unicorn/no-abusive-eslint-disable": "error",
"unicorn/no-array-instanceof": "error",
"unicorn/no-console-spaces": "error",
"unicorn/no-fn-reference-in-iterator": "off",
"unicorn/no-for-loop": "error",
"unicorn/no-hex-escape": "error",
"unicorn/no-keyword-prefix": "off",
"unicorn/no-nested-ternary": "error",
"unicorn/no-new-buffer": "error",
"unicorn/no-null": "off",
"unicorn/no-object-as-default-parameter": "error",
"unicorn/no-process-exit": "error",
"unicorn/no-reduce": "error",
"unicorn/no-unreadable-array-destructuring": "error",
"unicorn/no-unsafe-regex": "off",
"unicorn/no-unused-properties": "error",
"unicorn/no-useless-undefined": "error",
"unicorn/no-zero-fractions": "error",
"unicorn/number-literal-case": "error",
"unicorn/prefer-add-event-listener": "error",
"unicorn/prefer-array-find": "error",
"unicorn/prefer-dataset": "error",
"unicorn/prefer-event-key": "error",
"unicorn/prefer-flat-map": "error",
"unicorn/prefer-includes": "error",
"unicorn/prefer-modern-dom-apis": "error",
"unicorn/prefer-negative-index": "error",
"unicorn/prefer-node-append": "error",
"unicorn/prefer-node-remove": "error",
"unicorn/prefer-number-properties": "error",
"unicorn/prefer-optional-catch-binding": "error",
"unicorn/prefer-query-selector": "error",
"unicorn/prefer-reflect-apply": "error",
"unicorn/prefer-replace-all": "off",
"unicorn/prefer-set-has": "error",
"unicorn/prefer-spread": "error",
"unicorn/prefer-starts-ends-with": "error",
"unicorn/prefer-string-slice": "off",
"unicorn/prefer-text-content": "error",
"unicorn/prefer-trim-start-end": "off",
"unicorn/prefer-type-error": "error",
"unicorn/prevent-abbreviations": "off",
"unicorn/string-content": "error",
"unicorn/throw-new-error": "error"
} }
} }

View file

@ -196,7 +196,8 @@
if (hashPrefix === decodedHash.substring(0, hashPrefix.length)) { if (hashPrefix === decodedHash.substring(0, hashPrefix.length)) {
markdown.value = decodedHash.substring(hashPrefix.length); markdown.value = decodedHash.substring(hashPrefix.length);
} }
} catch (ex) { /* eslint-disable-next-line unicorn/prefer-optional-catch-binding */
} catch (error) {
// Invalid // Invalid
} }
} }
@ -205,7 +206,8 @@
try { try {
/* eslint-disable-next-line no-new */ /* eslint-disable-next-line no-new */
new URL(rulesMd); new URL(rulesMd);
} catch (ex) { /* eslint-disable-next-line unicorn/prefer-optional-catch-binding */
} catch (error) {
markdown.value = [ markdown.value = [
"# Sorry", "# Sorry",
"", "",

View file

@ -2782,10 +2782,10 @@ module.exports = {
// Close current run // Close current run
var content = line.substring(emphasisIndex, matchIndex); var content = line.substring(emphasisIndex, matchIndex);
if (!emphasisLength) { if (!emphasisLength) {
content = content.trimStart(); content = content.trimLeft();
} }
if (!match) { if (!match) {
content = content.trimEnd(); content = content.trimRight();
} }
var leftSpace = leftSpaceRe.test(content); var leftSpace = leftSpaceRe.test(content);
var rightSpace = rightSpaceRe.test(content); var rightSpace = rightSpaceRe.test(content);

View file

@ -154,7 +154,7 @@ function removeFrontMatter(content, frontMatter) {
const contentMatched = frontMatterMatch[0]; const contentMatched = frontMatterMatch[0];
content = content.slice(contentMatched.length); content = content.slice(contentMatched.length);
frontMatterLines = contentMatched.split(helpers.newLineRe); frontMatterLines = contentMatched.split(helpers.newLineRe);
if (frontMatterLines.length && if ((frontMatterLines.length > 0) &&
(frontMatterLines[frontMatterLines.length - 1] === "")) { (frontMatterLines[frontMatterLines.length - 1] === "")) {
frontMatterLines.length--; frontMatterLines.length--;
} }
@ -343,7 +343,8 @@ function getEnabledRulesPerLineNumber(
...config, ...config,
...json ...json
}; };
} catch (ex) { // eslint-disable-next-line unicorn/prefer-optional-catch-binding
} catch (error) {
// Ignore parse errors for inline configuration // Ignore parse errors for inline configuration
} }
} }
@ -459,7 +460,7 @@ function lintContent(
resultVersion, resultVersion,
callback) { callback) {
// Remove UTF-8 byte order marker (if present) // Remove UTF-8 byte order marker (if present)
content = content.replace(/^\ufeff/, ""); content = content.replace(/^\uFEFF/, "");
// Remove front matter // Remove front matter
const removeFrontMatterResult = removeFrontMatter(content, frontMatter); const removeFrontMatterResult = removeFrontMatter(content, frontMatter);
const frontMatterLines = removeFrontMatterResult.frontMatterLines; const frontMatterLines = removeFrontMatterResult.frontMatterLines;
@ -582,17 +583,17 @@ function lintContent(
if (handleRuleFailures) { if (handleRuleFailures) {
try { try {
rule.function(params, onError); rule.function(params, onError);
} catch (ex) { } catch (error) {
onError({ onError({
"lineNumber": 1, "lineNumber": 1,
"detail": `This rule threw an exception: ${ex.message}` "detail": `This rule threw an exception: ${error.message}`
}); });
} }
} else { } else {
rule.function(params, onError); rule.function(params, onError);
} }
// Record any errors (significant performance benefit from length check) // Record any errors (significant performance benefit from length check)
if (errors.length) { if (errors.length > 0) {
errors.sort(lineNumberComparison); errors.sort(lineNumberComparison);
const filteredErrors = errors const filteredErrors = errors
.filter((resultVersion === 3) ? .filter((resultVersion === 3) ?
@ -624,7 +625,7 @@ function lintContent(
} }
return errorObject; return errorObject;
}); });
if (filteredErrors.length) { if (filteredErrors.length > 0) {
if (resultVersion === 0) { if (resultVersion === 0) {
result[ruleNameFriendly] = filteredErrors; result[ruleNameFriendly] = filteredErrors;
} else { } else {
@ -636,9 +637,9 @@ function lintContent(
// Run all rules // Run all rules
try { try {
ruleList.forEach(forRule); ruleList.forEach(forRule);
} catch (ex) { } catch (error) {
cache.clear(); cache.clear();
return callback(ex); return callback(error);
} }
cache.clear(); cache.clear();
return callback(null, result); return callback(null, result);
@ -819,8 +820,8 @@ function parseConfiguration(name, content, parsers) {
(parsers || [ JSON.parse ]).every((parser) => { (parsers || [ JSON.parse ]).every((parser) => {
try { try {
config = parser(content); config = parser(content);
} catch (ex) { } catch (error) {
errors.push(ex.message); errors.push(error.message);
} }
return !config; return !config;
}); });

View file

@ -11,7 +11,7 @@ module.exports = {
"function": function MD001(params, onError) { "function": function MD001(params, onError) {
let prevLevel = 0; let prevLevel = 0;
filterTokens(params, "heading_open", function forToken(token) { filterTokens(params, "heading_open", function forToken(token) {
const level = parseInt(token.tag.slice(1), 10); const level = Number.parseInt(token.tag.slice(1), 10);
if (prevLevel && (level > prevLevel)) { if (prevLevel && (level > prevLevel)) {
addErrorDetailIf(onError, token.lineNumber, addErrorDetailIf(onError, token.lineNumber,
"h" + (prevLevel + 1), "h" + level); "h" + (prevLevel + 1), "h" + level);

View file

@ -13,7 +13,7 @@ module.exports = {
const maximum = Number(params.config.maximum || 1); const maximum = Number(params.config.maximum || 1);
let count = 0; let count = 0;
forEachLine(lineMetadata(), (line, lineIndex, inCode) => { forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
count = (inCode || line.trim().length) ? 0 : count + 1; count = (inCode || (line.trim().length > 0)) ? 0 : count + 1;
if (maximum < count) { if (maximum < count) {
addErrorDetailIf( addErrorDetailIf(
onError, onError,

View file

@ -32,10 +32,10 @@ module.exports = {
// Close current run // Close current run
let content = line.substring(emphasisIndex, matchIndex); let content = line.substring(emphasisIndex, matchIndex);
if (!emphasisLength) { if (!emphasisLength) {
content = content.trimStart(); content = content.trimLeft();
} }
if (!match) { if (!match) {
content = content.trimEnd(); content = content.trimRight();
} }
const leftSpace = leftSpaceRe.test(content); const leftSpace = leftSpaceRe.test(content);
const rightSpace = rightSpaceRe.test(content); const rightSpace = rightSpaceRe.test(content);

View file

@ -17,7 +17,7 @@
"test-cover": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 node test/markdownlint-test.js", "test-cover": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 node test/markdownlint-test.js",
"test-declaration": "cd example/typescript && tsc && node type-check.js", "test-declaration": "cd example/typescript && tsc && node type-check.js",
"test-extra": "node test/markdownlint-test-extra.js", "test-extra": "node test/markdownlint-test-extra.js",
"lint": "eslint --max-warnings 0 lib helpers test schema && eslint --env browser --global markdownit --global markdownlint --rule \"no-unused-vars: 0, no-extend-native: 0, max-statements: 0, no-console: 0, no-var: 0\" demo && eslint --rule \"no-console: 0, no-invalid-this: 0, no-shadow: 0, object-property-newline: 0, node/no-missing-require: 0, node/no-extraneous-require: 0\" example", "lint": "eslint --max-warnings 0 lib helpers test schema && eslint --env browser --global markdownit --global markdownlint --rule \"no-unused-vars: 0, no-extend-native: 0, max-statements: 0, no-console: 0, no-var: 0, unicorn/prefer-add-event-listener: 0, unicorn/prefer-query-selector: 0, unicorn/prefer-replace-all: 0\" demo && eslint --rule \"no-console: 0, no-invalid-this: 0, no-shadow: 0, object-property-newline: 0, node/no-missing-require: 0, node/no-extraneous-require: 0\" example",
"ci": "npm run test-cover && npm run lint && npm run test-declaration", "ci": "npm run test-cover && npm run lint && npm run test-declaration",
"build-config-schema": "node schema/build-config-schema.js", "build-config-schema": "node schema/build-config-schema.js",
"build-declaration": "tsc --allowJs --declaration --outDir declaration --resolveJsonModule lib/markdownlint.js && cpy declaration/lib/markdownlint.d.ts lib && rimraf declaration", "build-declaration": "tsc --allowJs --declaration --outDir declaration --resolveJsonModule lib/markdownlint.js && cpy declaration/lib/markdownlint.d.ts lib && rimraf declaration",
@ -43,6 +43,7 @@
"eslint": "~7.8.1", "eslint": "~7.8.1",
"eslint-plugin-jsdoc": "~30.3.1", "eslint-plugin-jsdoc": "~30.3.1",
"eslint-plugin-node": "~11.1.0", "eslint-plugin-node": "~11.1.0",
"eslint-plugin-unicorn": "~21.0.0",
"globby": "~11.0.1", "globby": "~11.0.1",
"js-yaml": "~3.14.0", "js-yaml": "~3.14.0",
"make-dir-cli": "~2.0.0", "make-dir-cli": "~2.0.0",

View file

@ -55,7 +55,7 @@ function lintTestRepo(test, globPatterns, configPath) {
}; };
return markdownlintPromise(options).then((results) => { return markdownlintPromise(options).then((results) => {
const resultsString = results.toString(); const resultsString = results.toString();
if (resultsString.length) { if (resultsString.length > 0) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(resultsString); console.log(resultsString);
} }

View file

@ -24,7 +24,7 @@ const configSchema = require("../schema/markdownlint-config-schema.json");
const homepage = packageJson.homepage; const homepage = packageJson.homepage;
const version = packageJson.version; const version = packageJson.version;
const deprecatedRuleNames = [ "MD002", "MD006" ]; const deprecatedRuleNames = new Set([ "MD002", "MD006" ]);
/** /**
* Create a test function for the specified test file. * Create a test function for the specified test file.
@ -128,7 +128,11 @@ function createTestForFile(file) {
while ((match = regex.exec(line))) { while ((match = regex.exec(line))) {
const rule = match[1]; const rule = match[1];
const errors = results[rule] || []; const errors = results[rule] || [];
errors.push(match[2] ? parseInt(match[2], 10) : lineNum + 1); errors.push(
match[2] ?
Number.parseInt(match[2], 10) :
lineNum + 1
);
results[rule] = errors; results[rule] = errors;
} }
}); });
@ -1504,7 +1508,7 @@ tape("readme", (test) => {
let expected = "**[" + ruleName + "](doc/Rules.md#" + let expected = "**[" + ruleName + "](doc/Rules.md#" +
ruleName.toLowerCase() + ")** *" + ruleName.toLowerCase() + ")** *" +
ruleAliases.join("/") + "* - " + rule.description; ruleAliases.join("/") + "* - " + rule.description;
if (deprecatedRuleNames.includes(ruleName)) { if (deprecatedRuleNames.has(ruleName)) {
expected = "~~" + expected + "~~"; expected = "~~" + expected + "~~";
} }
test.equal(token.content, expected, "Rule mismatch."); test.equal(token.content, expected, "Rule mismatch.");
@ -1566,7 +1570,7 @@ tape("rules", (test) => {
"Missing rule implementation for " + token.content + "."); "Missing rule implementation for " + token.content + ".");
const ruleName = rule.names[0]; const ruleName = rule.names[0];
let headingContent = ruleName + " - " + rule.description; let headingContent = ruleName + " - " + rule.description;
if (deprecatedRuleNames.includes(ruleName)) { if (deprecatedRuleNames.has(ruleName)) {
headingContent = "~~" + headingContent + "~~"; headingContent = "~~" + headingContent + "~~";
} }
test.equal(token.content, test.equal(token.content,
@ -1580,16 +1584,16 @@ tape("rules", (test) => {
}); });
ruleUsesParams.sort(); ruleUsesParams.sort();
} }
} else if (/^Tags: /.test(token.content) && rule) { } else if (token.content.startsWith("Tags: ") && rule) {
test.deepEqual(token.content.split(tagAliasParameterRe).slice(1), test.deepEqual(token.content.split(tagAliasParameterRe).slice(1),
rule.tags, "Tag mismatch for rule " + rule.names + "."); rule.tags, "Tag mismatch for rule " + rule.names + ".");
ruleHasTags = true; ruleHasTags = true;
} else if (/^Aliases: /.test(token.content) && rule) { } else if (token.content.startsWith("Aliases: ") && rule) {
test.deepEqual(token.content.split(tagAliasParameterRe).slice(1), test.deepEqual(token.content.split(tagAliasParameterRe).slice(1),
rule.names.slice(1), rule.names.slice(1),
"Alias mismatch for rule " + rule.names + "."); "Alias mismatch for rule " + rule.names + ".");
ruleHasAliases = true; ruleHasAliases = true;
} else if (/^Parameters: /.test(token.content) && rule) { } else if (token.content.startsWith("Parameters: ") && rule) {
let inDetails = false; let inDetails = false;
const parameters = token.content.split(tagAliasParameterRe) const parameters = token.content.split(tagAliasParameterRe)
.slice(1) .slice(1)

View file

@ -17,7 +17,7 @@ const languageJavaScript = /js|javascript/i;
function cleanJsdocRulesFromEslintConfig(config) { function cleanJsdocRulesFromEslintConfig(config) {
const cleanedConfig = { ...config }; const cleanedConfig = { ...config };
for (const rule in config.rules) { for (const rule in config.rules) {
if (/^(jsdoc|node)\//.test(rule)) { if (/^(jsdoc|node|unicorn)\//.test(rule)) {
delete cleanedConfig.rules[rule]; delete cleanedConfig.rules[rule];
} }
} }