From 6b01a9836331e981fc88e64b7f3851bb44a79128 Mon Sep 17 00:00:00 2001 From: David Anson Date: Mon, 19 Dec 2022 21:36:24 -0800 Subject: [PATCH] Add ESLint plugin eslint-plugin-regexp, enable recommended rules, apply all automated fixes (refs #657). --- .eslintrc.json | 6 ++++++ demo/markdownlint-browser.js | 32 ++++++++++++++++---------------- helpers/helpers.js | 10 +++++----- lib/md011.js | 2 +- lib/md019.js | 2 +- lib/md023.js | 2 +- lib/md026.js | 2 +- lib/md033.js | 4 ++-- lib/md034.js | 2 +- lib/md035.js | 2 +- lib/md037.js | 4 ++-- lib/md039.js | 2 +- package.json | 1 + test/markdownlint-test.js | 2 +- test/rules/lint-javascript.js | 2 +- 15 files changed, 41 insertions(+), 34 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 46e07bb95..705789e7b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -7,6 +7,7 @@ "eslint:all", "plugin:jsdoc/recommended", "plugin:n/recommended", + "plugin:regexp/recommended", "plugin:unicorn/all" ], "ignorePatterns": [ @@ -200,6 +201,11 @@ "n/prefer-promises/dns": "error", "n/prefer-promises/fs": "error", + "regexp/no-empty-alternative": "off", + "regexp/no-super-linear-backtracking": "off", + "regexp/no-unused-capturing-group": "off", + "regexp/no-useless-assertions": "off", + "unicorn/better-regex": "off", "unicorn/consistent-function-scoping": "off", "unicorn/filename-case": "off", diff --git a/demo/markdownlint-browser.js b/demo/markdownlint-browser.js index 10ffb46b5..b32aa7eab 100644 --- a/demo/markdownlint-browser.js +++ b/demo/markdownlint-browser.js @@ -37,14 +37,14 @@ module.exports.newLineRe = newLineRe; // Regular expression for matching common front matter (YAML and TOML) module.exports.frontMatterRe = // eslint-disable-next-line max-len - /((^---\s*$[^]*?^---\s*$)|(^\+\+\+\s*$[^]*?^(\+\+\+|\.\.\.)\s*$)|(^\{\s*$[^]*?^\}\s*$))(\r\n|\r|\n|$)/m; + /((^---\s*$[\s\S]*?^---\s*$)|(^\+\+\+\s*$[\s\S]*?^(\+\+\+|\.\.\.)\s*$)|(^\{\s*$[\s\S]*?^\}\s*$))(\r\n|\r|\n|$)/m; // Regular expression for matching the start of inline disable/enable comments const inlineCommentStartRe = // eslint-disable-next-line max-len -/()/ig; +/()/gi; module.exports.inlineCommentStartRe = inlineCommentStartRe; // Regular expression for matching HTML elements -const htmlElementRe = /<(([A-Za-z][A-Za-z0-9-]*)(?:\s[^`>]*)?)\/?>/g; +const htmlElementRe = /<(([A-Za-z][A-Za-z\d-]*)(?:\s[^`>]*)?)\/?>/g; module.exports.htmlElementRe = htmlElementRe; // Regular expressions for range matching module.exports.listItemMarkerRe = /^([\s>]*)(?:[*+-]|\d+[.)])\s+/; @@ -55,9 +55,9 @@ const emphasisMarkersRe = /[_*]/g; const blockquotePrefixRe = /^[>\s]*/; module.exports.blockquotePrefixRe = blockquotePrefixRe; // Regular expression for reference links (full, collapsed, and shortcut) -const referenceLinkRe = /!?\\?\[((?:\[[^\]\0]*]|[^[\]\0])*)](?:(?:\[([^\]\0]*)\])|([^(])|$)/g; +const referenceLinkRe = /!?\\?\[((?:\[[^\]\0]*\]|[^[\]\0])*)\](?:\[([^\]\0]*)\]|([^(])|$)/g; // Regular expression for link reference definitions -const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])]:/; +const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])\]:/; module.exports.linkReferenceDefinitionRe = linkReferenceDefinitionRe; // All punctuation characters (normal and full-width) const allPunctuation = ".,;:!?。,;:!?"; @@ -2902,7 +2902,7 @@ module.exports = { const { addError, forEachLine, withinAnyRange } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"); const { codeBlockAndSpanRanges, lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js"); -const reversedLinkRe = /(^|[^\\])\(([^()]+)\)\[([^\]^][^\]]*)](?!\()/g; +const reversedLinkRe = /(^|[^\\])\(([^()]+)\)\[([^\]^][^\]]*)\](?!\()/g; module.exports = { "names": ["MD011", "no-reversed-links"], "description": "Reversed link syntax", @@ -3163,7 +3163,7 @@ module.exports = { filterTokens(params, "heading_open", (token) => { if (headingStyleFor(token) === "atx") { const { line, lineNumber } = token; - const match = /^(#+)([ \t]{2,})(?:\S)/.exec(line); + const match = /^(#+)([ \t]{2,})\S/.exec(line); if (match) { const [, { "length": hashLength }, { "length": spacesLength }] = match; addErrorContext(onError, lineNumber, line.trim(), null, null, [1, hashLength + spacesLength + 1], { @@ -3346,7 +3346,7 @@ module.exports = { // @ts-check const { addErrorContext, filterTokens } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"); -const spaceBeforeHeadingRe = /^((?:\s+)|(?:[>\s]+\s\s))[^>\s]/; +const spaceBeforeHeadingRe = /^(\s+|[>\s]+\s\s)[^>\s]/; module.exports = { "names": ["MD023", "heading-start-left", "header-start-left"], "description": "Headings must start at the beginning of the line", @@ -3465,7 +3465,7 @@ module.exports = { // @ts-check const { addError, allPunctuationNoQuestion, escapeForRegExp, forEachHeading } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"); -const endOfLineHtmlEntityRe = /&#?[0-9a-zA-Z]+;$/; +const endOfLineHtmlEntityRe = /&#?[\da-zA-Z]+;$/; module.exports = { "names": ["MD026", "no-trailing-punctuation"], "description": "Trailing punctuation in heading", @@ -3798,11 +3798,11 @@ module.exports = { const { addError, forEachLine, htmlElementRe, withinAnyRange, unescapeMarkdown } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"); const { codeBlockAndSpanRanges, lineMetadata, referenceLinkImageData } = __webpack_require__(/*! ./cache */ "../lib/cache.js"); -const linkDestinationRe = /]\(\s*$/; +const linkDestinationRe = /\]\(\s*$/; // See https://spec.commonmark.org/0.29/#autolinks const emailAddressRe = // eslint-disable-next-line max-len -/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; +/^[\w.!#$%&'*+/=?^`{|}~-]+@[a-zA-Z\d](?:[a-zA-Z\d-]{0,61}[a-zA-Z\d])?(?:\.[a-zA-Z\d](?:[a-zA-Z\d-]{0,61}[a-zA-Z\d])?)*$/; module.exports = { "names": ["MD033", "no-inline-html"], "description": "Inline HTML", @@ -3858,7 +3858,7 @@ module.exports = { const { addErrorContext, filterTokens, funcExpExec, urlFe, withinAnyRange } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"); const { codeBlockAndSpanRanges, htmlElementRanges, referenceLinkImageData } = __webpack_require__(/*! ./cache */ "../lib/cache.js"); -const htmlLinkRe = /]+)>[^<>]*<\/a\s*>/ig; +const htmlLinkRe = /]+)>[^<>]*<\/a\s*>/gi; module.exports = { "names": ["MD034", "no-bare-urls"], "description": "Bare URL used", @@ -3945,7 +3945,7 @@ module.exports = { filterTokens(params, "hr", (token) => { const { line, lineNumber } = token; let { markup } = token; - const match = line.match(/[_*\-\s\t]+$/); + const match = line.match(/[_*\-\s]+$/); if (match) { markup = match[0].trim(); } @@ -4036,8 +4036,8 @@ module.exports = { const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine, withinAnyRange } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"); const { htmlElementRanges, lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js"); -const emphasisRe = /(^|[^\\]|\\\\)(?:(\*\*?\*?)|(__?_?))/g; -const embeddedUnderscoreRe = /([A-Za-z0-9])_([A-Za-z0-9])/g; +const emphasisRe = /(^|[^\\]|\\\\)(?:(\*{1,3})|(_{1,3}))/g; +const embeddedUnderscoreRe = /([A-Za-z\d])_([A-Za-z\d])/g; const asteriskListItemMarkerRe = /^([\s>]*)\*(\s+)/; const leftSpaceRe = /^\s+/; const rightSpaceRe = /\s+$/; @@ -4271,7 +4271,7 @@ module.exports = { // @ts-check const { addErrorContext, filterTokens } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"); -const spaceInLinkRe = /\[(?:\s+(?:[^\]]*?)\s*|(?:[^\]]*?)\s+)](?=((?:\([^)]*\))|(?:\[[^\]]*\])))/; +const spaceInLinkRe = /\[(?:\s[^\]]*|[^\]]*?\s)\](?=(\([^)]*\)|\[[^\]]*\]))/; module.exports = { "names": ["MD039", "no-space-in-links"], "description": "Spaces inside link text", diff --git a/helpers/helpers.js b/helpers/helpers.js index 3db2a98ff..5f1560fcd 100644 --- a/helpers/helpers.js +++ b/helpers/helpers.js @@ -10,16 +10,16 @@ module.exports.newLineRe = newLineRe; // Regular expression for matching common front matter (YAML and TOML) module.exports.frontMatterRe = // eslint-disable-next-line max-len - /((^---\s*$[^]*?^---\s*$)|(^\+\+\+\s*$[^]*?^(\+\+\+|\.\.\.)\s*$)|(^\{\s*$[^]*?^\}\s*$))(\r\n|\r|\n|$)/m; + /((^---\s*$[\s\S]*?^---\s*$)|(^\+\+\+\s*$[\s\S]*?^(\+\+\+|\.\.\.)\s*$)|(^\{\s*$[\s\S]*?^\}\s*$))(\r\n|\r|\n|$)/m; // Regular expression for matching the start of inline disable/enable comments const inlineCommentStartRe = // eslint-disable-next-line max-len - /()/ig; + /()/gi; module.exports.inlineCommentStartRe = inlineCommentStartRe; // Regular expression for matching HTML elements -const htmlElementRe = /<(([A-Za-z][A-Za-z0-9-]*)(?:\s[^`>]*)?)\/?>/g; +const htmlElementRe = /<(([A-Za-z][A-Za-z\d-]*)(?:\s[^`>]*)?)\/?>/g; module.exports.htmlElementRe = htmlElementRe; // Regular expressions for range matching @@ -35,10 +35,10 @@ module.exports.blockquotePrefixRe = blockquotePrefixRe; // Regular expression for reference links (full, collapsed, and shortcut) const referenceLinkRe = - /!?\\?\[((?:\[[^\]\0]*]|[^[\]\0])*)](?:(?:\[([^\]\0]*)\])|([^(])|$)/g; + /!?\\?\[((?:\[[^\]\0]*\]|[^[\]\0])*)\](?:\[([^\]\0]*)\]|([^(])|$)/g; // Regular expression for link reference definitions -const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])]:/; +const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])\]:/; module.exports.linkReferenceDefinitionRe = linkReferenceDefinitionRe; // All punctuation characters (normal and full-width) diff --git a/lib/md011.js b/lib/md011.js index 401c7d097..090db726c 100644 --- a/lib/md011.js +++ b/lib/md011.js @@ -6,7 +6,7 @@ const { addError, forEachLine, withinAnyRange } = require("../helpers"); const { codeBlockAndSpanRanges, lineMetadata } = require("./cache"); const reversedLinkRe = - /(^|[^\\])\(([^()]+)\)\[([^\]^][^\]]*)](?!\()/g; + /(^|[^\\])\(([^()]+)\)\[([^\]^][^\]]*)\](?!\()/g; module.exports = { "names": [ "MD011", "no-reversed-links" ], diff --git a/lib/md019.js b/lib/md019.js index bb5b2b265..b7d343551 100644 --- a/lib/md019.js +++ b/lib/md019.js @@ -13,7 +13,7 @@ module.exports = { filterTokens(params, "heading_open", (token) => { if (headingStyleFor(token) === "atx") { const { line, lineNumber } = token; - const match = /^(#+)([ \t]{2,})(?:\S)/.exec(line); + const match = /^(#+)([ \t]{2,})\S/.exec(line); if (match) { const [ , diff --git a/lib/md023.js b/lib/md023.js index c7173c172..ee7ace277 100644 --- a/lib/md023.js +++ b/lib/md023.js @@ -4,7 +4,7 @@ const { addErrorContext, filterTokens } = require("../helpers"); -const spaceBeforeHeadingRe = /^((?:\s+)|(?:[>\s]+\s\s))[^>\s]/; +const spaceBeforeHeadingRe = /^(\s+|[>\s]+\s\s)[^>\s]/; module.exports = { "names": [ "MD023", "heading-start-left", "header-start-left" ], diff --git a/lib/md026.js b/lib/md026.js index 0a517d790..6ab1f6457 100644 --- a/lib/md026.js +++ b/lib/md026.js @@ -5,7 +5,7 @@ const { addError, allPunctuationNoQuestion, escapeForRegExp, forEachHeading } = require("../helpers"); -const endOfLineHtmlEntityRe = /&#?[0-9a-zA-Z]+;$/; +const endOfLineHtmlEntityRe = /&#?[\da-zA-Z]+;$/; module.exports = { "names": [ "MD026", "no-trailing-punctuation" ], diff --git a/lib/md033.js b/lib/md033.js index 1e427edd7..c3ffd3680 100644 --- a/lib/md033.js +++ b/lib/md033.js @@ -8,11 +8,11 @@ const { const { codeBlockAndSpanRanges, lineMetadata, referenceLinkImageData } = require("./cache"); -const linkDestinationRe = /]\(\s*$/; +const linkDestinationRe = /\]\(\s*$/; // See https://spec.commonmark.org/0.29/#autolinks const emailAddressRe = // eslint-disable-next-line max-len - /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; + /^[\w.!#$%&'*+/=?^`{|}~-]+@[a-zA-Z\d](?:[a-zA-Z\d-]{0,61}[a-zA-Z\d])?(?:\.[a-zA-Z\d](?:[a-zA-Z\d-]{0,61}[a-zA-Z\d])?)*$/; module.exports = { "names": [ "MD033", "no-inline-html" ], diff --git a/lib/md034.js b/lib/md034.js index b479642ab..51e9bc247 100644 --- a/lib/md034.js +++ b/lib/md034.js @@ -7,7 +7,7 @@ const { addErrorContext, filterTokens, funcExpExec, urlFe, withinAnyRange } = const { codeBlockAndSpanRanges, htmlElementRanges, referenceLinkImageData } = require("./cache"); -const htmlLinkRe = /]+)>[^<>]*<\/a\s*>/ig; +const htmlLinkRe = /]+)>[^<>]*<\/a\s*>/gi; module.exports = { "names": [ "MD034", "no-bare-urls" ], diff --git a/lib/md035.js b/lib/md035.js index e6afb5442..b8dbb5d30 100644 --- a/lib/md035.js +++ b/lib/md035.js @@ -13,7 +13,7 @@ module.exports = { filterTokens(params, "hr", (token) => { const { line, lineNumber } = token; let { markup } = token; - const match = line.match(/[_*\-\s\t]+$/); + const match = line.match(/[_*\-\s]+$/); if (match) { markup = match[0].trim(); } diff --git a/lib/md037.js b/lib/md037.js index cc1f401e4..ec6bb6461 100644 --- a/lib/md037.js +++ b/lib/md037.js @@ -6,8 +6,8 @@ const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine, withinAnyRange } = require("../helpers"); const { htmlElementRanges, lineMetadata } = require("./cache"); -const emphasisRe = /(^|[^\\]|\\\\)(?:(\*\*?\*?)|(__?_?))/g; -const embeddedUnderscoreRe = /([A-Za-z0-9])_([A-Za-z0-9])/g; +const emphasisRe = /(^|[^\\]|\\\\)(?:(\*{1,3})|(_{1,3}))/g; +const embeddedUnderscoreRe = /([A-Za-z\d])_([A-Za-z\d])/g; const asteriskListItemMarkerRe = /^([\s>]*)\*(\s+)/; const leftSpaceRe = /^\s+/; const rightSpaceRe = /\s+$/; diff --git a/lib/md039.js b/lib/md039.js index 8362eb26d..1cfe71acd 100644 --- a/lib/md039.js +++ b/lib/md039.js @@ -5,7 +5,7 @@ const { addErrorContext, filterTokens } = require("../helpers"); const spaceInLinkRe = - /\[(?:\s+(?:[^\]]*?)\s*|(?:[^\]]*?)\s+)](?=((?:\([^)]*\))|(?:\[[^\]]*\])))/; + /\[(?:\s[^\]]*|[^\]]*?\s)\](?=(\([^)]*\)|\[[^\]]*\]))/; module.exports = { "names": [ "MD039", "no-space-in-links" ], diff --git a/package.json b/package.json index b769a1cb9..486467c12 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,7 @@ "eslint-plugin-es": "4.1.0", "eslint-plugin-jsdoc": "39.6.4", "eslint-plugin-n": "15.6.0", + "eslint-plugin-regexp": "1.11.0", "eslint-plugin-unicorn": "45.0.2", "globby": "13.1.3", "js-yaml": "4.1.0", diff --git a/test/markdownlint-test.js b/test/markdownlint-test.js index 24a3e4391..93b863b91 100644 --- a/test/markdownlint-test.js +++ b/test/markdownlint-test.js @@ -568,7 +568,7 @@ test("customFrontMatter", (t) => new Promise((resolve) => { "strings": { "content": "\n\t\n\n# Heading\n" }, - "frontMatter": /[^]*<\/head>/, + "frontMatter": /[\s\S]*<\/head>/, "config": { "default": false, "MD010": true diff --git a/test/rules/lint-javascript.js b/test/rules/lint-javascript.js index c80f15580..10612e761 100644 --- a/test/rules/lint-javascript.js +++ b/test/rules/lint-javascript.js @@ -17,7 +17,7 @@ const languageJavaScript = /js|javascript/i; function cleanJsdocRulesFromEslintConfig(config) { const cleanedConfig = { ...config }; for (const rule in config.rules) { - if (/^(es|jsdoc|n|unicorn)\//.test(rule)) { + if (/^(es|jsdoc|n|regexp|unicorn)\//.test(rule)) { delete cleanedConfig.rules[rule]; } }