Bump the npm group with 2 updates (#1819)
* Bump the npm group with 2 updates Bumps the npm group with 2 updates: [eslint](https://github.com/eslint/eslint) and [eslint-plugin-import](https://github.com/import-js/eslint-plugin-import). Updates `eslint` from 8.45.0 to 8.46.0 - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v8.45.0...v8.46.0) Updates `eslint-plugin-import` from 2.27.5 to 2.28.0 - [Release notes](https://github.com/import-js/eslint-plugin-import/releases) - [Changelog](https://github.com/import-js/eslint-plugin-import/blob/main/CHANGELOG.md) - [Commits](https://github.com/import-js/eslint-plugin-import/compare/v2.27.5...v2.28.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm - dependency-name: eslint-plugin-import dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm ... Signed-off-by: dependabot[bot] <support@github.com> * Update checked-in dependencies --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
a6b0ced86b
commit
e7e35baaf0
1408 changed files with 27215 additions and 9910 deletions
70
node_modules/eslint/lib/config/flat-config-schema.js
generated
vendored
70
node_modules/eslint/lib/config/flat-config-schema.js
generated
vendored
|
|
@ -212,6 +212,38 @@ function assertIsObject(value) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The error type when there's an eslintrc-style options in a flat config.
|
||||
*/
|
||||
class IncompatibleKeyError extends Error {
|
||||
|
||||
/**
|
||||
* @param {string} key The invalid key.
|
||||
*/
|
||||
constructor(key) {
|
||||
super("This appears to be in eslintrc format rather than flat config format.");
|
||||
this.messageTemplate = "eslintrc-incompat";
|
||||
this.messageData = { key };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The error type when there's an eslintrc-style plugins array found.
|
||||
*/
|
||||
class IncompatiblePluginsError extends Error {
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {Array<string>} plugins The plugins array.
|
||||
*/
|
||||
constructor(plugins) {
|
||||
super("This appears to be in eslintrc format (array of strings) rather than flat config format (object).");
|
||||
this.messageTemplate = "eslintrc-plugins";
|
||||
this.messageData = { plugins };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Low-Level Schemas
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -303,6 +335,11 @@ const pluginsSchema = {
|
|||
throw new TypeError("Expected an object.");
|
||||
}
|
||||
|
||||
// make sure it's not an array, which would mean eslintrc-style is used
|
||||
if (Array.isArray(value)) {
|
||||
throw new IncompatiblePluginsError(value);
|
||||
}
|
||||
|
||||
// second check the keys to make sure they are objects
|
||||
for (const key of Object.keys(value)) {
|
||||
|
||||
|
|
@ -438,11 +475,44 @@ const sourceTypeSchema = {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a schema that always throws an error. Useful for warning
|
||||
* about eslintrc-style keys.
|
||||
* @param {string} key The eslintrc key to create a schema for.
|
||||
* @returns {ObjectPropertySchema} The schema.
|
||||
*/
|
||||
function createEslintrcErrorSchema(key) {
|
||||
return {
|
||||
merge: "replace",
|
||||
validate() {
|
||||
throw new IncompatibleKeyError(key);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const eslintrcKeys = [
|
||||
"env",
|
||||
"extends",
|
||||
"globals",
|
||||
"ignorePatterns",
|
||||
"noInlineConfig",
|
||||
"overrides",
|
||||
"parser",
|
||||
"parserOptions",
|
||||
"reportUnusedDisableDirectives",
|
||||
"root"
|
||||
];
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Full schema
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
exports.flatConfigSchema = {
|
||||
|
||||
// eslintrc-style keys that should always error
|
||||
...Object.fromEntries(eslintrcKeys.map(key => [key, createEslintrcErrorSchema(key)])),
|
||||
|
||||
// flat config keys
|
||||
settings: deepObjectAssignSchema,
|
||||
linterOptions: {
|
||||
schema: {
|
||||
|
|
|
|||
8
node_modules/eslint/lib/eslint/flat-eslint.js
generated
vendored
8
node_modules/eslint/lib/eslint/flat-eslint.js
generated
vendored
|
|
@ -714,12 +714,10 @@ class FlatESLint {
|
|||
}
|
||||
const rule = getRuleFromConfig(ruleId, config);
|
||||
|
||||
// ensure the rule exists
|
||||
if (!rule) {
|
||||
throw new TypeError(`Could not find the rule "${ruleId}".`);
|
||||
// ignore unknown rules
|
||||
if (rule) {
|
||||
resultRules.set(ruleId, rule);
|
||||
}
|
||||
|
||||
resultRules.set(ruleId, rule);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
17
node_modules/eslint/lib/rules/no-control-regex.js
generated
vendored
17
node_modules/eslint/lib/rules/no-control-regex.js
generated
vendored
|
|
@ -14,6 +14,16 @@ const collector = new (class {
|
|||
}
|
||||
|
||||
onPatternEnter() {
|
||||
|
||||
/*
|
||||
* `RegExpValidator` may parse the pattern twice in one `validatePattern`.
|
||||
* So `this._controlChars` should be cleared here as well.
|
||||
*
|
||||
* For example, the `/(?<a>\x1f)/` regex will parse the pattern twice.
|
||||
* This is based on the content described in Annex B.
|
||||
* If the regex contains a `GroupName` and the `u` flag is not used, `ParseText` will be called twice.
|
||||
* See https://tc39.es/ecma262/2023/multipage/additional-ecmascript-features-for-web-browsers.html#sec-parsepattern-annexb
|
||||
*/
|
||||
this._controlChars = [];
|
||||
}
|
||||
|
||||
|
|
@ -32,10 +42,13 @@ const collector = new (class {
|
|||
|
||||
collectControlChars(regexpStr, flags) {
|
||||
const uFlag = typeof flags === "string" && flags.includes("u");
|
||||
const vFlag = typeof flags === "string" && flags.includes("v");
|
||||
|
||||
this._controlChars = [];
|
||||
this._source = regexpStr;
|
||||
|
||||
try {
|
||||
this._source = regexpStr;
|
||||
this._validator.validatePattern(regexpStr, void 0, void 0, uFlag); // Call onCharacter hook
|
||||
this._validator.validatePattern(regexpStr, void 0, void 0, { unicode: uFlag, unicodeSets: vFlag }); // Call onCharacter hook
|
||||
} catch {
|
||||
|
||||
// Ignore syntax errors in RegExp.
|
||||
|
|
|
|||
45
node_modules/eslint/lib/rules/no-empty-character-class.js
generated
vendored
45
node_modules/eslint/lib/rules/no-empty-character-class.js
generated
vendored
|
|
@ -5,20 +5,18 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const { RegExpParser, visitRegExpAST } = require("@eslint-community/regexpp");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* plain-English description of the following regexp:
|
||||
* 0. `^` fix the match at the beginning of the string
|
||||
* 1. `([^\\[]|\\.|\[([^\\\]]|\\.)+\])*`: regexp contents; 0 or more of the following
|
||||
* 1.0. `[^\\[]`: any character that's not a `\` or a `[` (anything but escape sequences and character classes)
|
||||
* 1.1. `\\.`: an escape sequence
|
||||
* 1.2. `\[([^\\\]]|\\.)+\]`: a character class that isn't empty
|
||||
* 2. `$`: fix the match at the end of the string
|
||||
*/
|
||||
const regex = /^([^\\[]|\\.|\[([^\\\]]|\\.)+\])*$/u;
|
||||
const parser = new RegExpParser();
|
||||
const QUICK_TEST_REGEX = /\[\]/u;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
|
|
@ -45,9 +43,32 @@ module.exports = {
|
|||
create(context) {
|
||||
return {
|
||||
"Literal[regex]"(node) {
|
||||
if (!regex.test(node.regex.pattern)) {
|
||||
context.report({ node, messageId: "unexpected" });
|
||||
const { pattern, flags } = node.regex;
|
||||
|
||||
if (!QUICK_TEST_REGEX.test(pattern)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let regExpAST;
|
||||
|
||||
try {
|
||||
regExpAST = parser.parsePattern(pattern, 0, pattern.length, {
|
||||
unicode: flags.includes("u"),
|
||||
unicodeSets: flags.includes("v")
|
||||
});
|
||||
} catch {
|
||||
|
||||
// Ignore regular expressions that regexpp cannot parse
|
||||
return;
|
||||
}
|
||||
|
||||
visitRegExpAST(regExpAST, {
|
||||
onCharacterClassEnter(characterClass) {
|
||||
if (!characterClass.negate && characterClass.elements.length === 0) {
|
||||
context.report({ node, messageId: "unexpected" });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
41
node_modules/eslint/lib/rules/no-empty-pattern.js
generated
vendored
41
node_modules/eslint/lib/rules/no-empty-pattern.js
generated
vendored
|
|
@ -4,6 +4,8 @@
|
|||
*/
|
||||
"use strict";
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -19,7 +21,18 @@ module.exports = {
|
|||
url: "https://eslint.org/docs/latest/rules/no-empty-pattern"
|
||||
},
|
||||
|
||||
schema: [],
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
allowObjectPatternsAsParameters: {
|
||||
type: "boolean",
|
||||
default: false
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
],
|
||||
|
||||
messages: {
|
||||
unexpected: "Unexpected empty {{type}} pattern."
|
||||
|
|
@ -27,11 +40,33 @@ module.exports = {
|
|||
},
|
||||
|
||||
create(context) {
|
||||
const options = context.options[0] || {},
|
||||
allowObjectPatternsAsParameters = options.allowObjectPatternsAsParameters || false;
|
||||
|
||||
return {
|
||||
ObjectPattern(node) {
|
||||
if (node.properties.length === 0) {
|
||||
context.report({ node, messageId: "unexpected", data: { type: "object" } });
|
||||
|
||||
if (node.properties.length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Allow {} and {} = {} empty object patterns as parameters when allowObjectPatternsAsParameters is true
|
||||
if (
|
||||
allowObjectPatternsAsParameters &&
|
||||
(
|
||||
astUtils.isFunction(node.parent) ||
|
||||
(
|
||||
node.parent.type === "AssignmentPattern" &&
|
||||
astUtils.isFunction(node.parent.parent) &&
|
||||
node.parent.right.type === "ObjectExpression" &&
|
||||
node.parent.right.properties.length === 0
|
||||
)
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
context.report({ node, messageId: "unexpected", data: { type: "object" } });
|
||||
},
|
||||
ArrayPattern(node) {
|
||||
if (node.elements.length === 0) {
|
||||
|
|
|
|||
29
node_modules/eslint/lib/rules/no-invalid-regexp.js
generated
vendored
29
node_modules/eslint/lib/rules/no-invalid-regexp.js
generated
vendored
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
const RegExpValidator = require("@eslint-community/regexpp").RegExpValidator;
|
||||
const validator = new RegExpValidator();
|
||||
const validFlags = /[dgimsuy]/gu;
|
||||
const validFlags = /[dgimsuvy]/gu;
|
||||
const undefined1 = void 0;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -108,12 +108,14 @@ module.exports = {
|
|||
/**
|
||||
* Check syntax error in a given pattern.
|
||||
* @param {string} pattern The RegExp pattern to validate.
|
||||
* @param {boolean} uFlag The Unicode flag.
|
||||
* @param {Object} flags The RegExp flags to validate.
|
||||
* @param {boolean} [flags.unicode] The Unicode flag.
|
||||
* @param {boolean} [flags.unicodeSets] The UnicodeSets flag.
|
||||
* @returns {string|null} The syntax error.
|
||||
*/
|
||||
function validateRegExpPattern(pattern, uFlag) {
|
||||
function validateRegExpPattern(pattern, flags) {
|
||||
try {
|
||||
validator.validatePattern(pattern, undefined1, undefined1, uFlag);
|
||||
validator.validatePattern(pattern, undefined1, undefined1, flags);
|
||||
return null;
|
||||
} catch (err) {
|
||||
return err.message;
|
||||
|
|
@ -131,10 +133,19 @@ module.exports = {
|
|||
}
|
||||
try {
|
||||
validator.validateFlags(flags);
|
||||
return null;
|
||||
} catch {
|
||||
return `Invalid flags supplied to RegExp constructor '${flags}'`;
|
||||
}
|
||||
|
||||
/*
|
||||
* `regexpp` checks the combination of `u` and `v` flags when parsing `Pattern` according to `ecma262`,
|
||||
* but this rule may check only the flag when the pattern is unidentifiable, so check it here.
|
||||
* https://tc39.es/ecma262/multipage/text-processing.html#sec-parsepattern
|
||||
*/
|
||||
if (flags.includes("u") && flags.includes("v")) {
|
||||
return "Regex 'u' and 'v' flags cannot be used together";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
@ -166,8 +177,12 @@ module.exports = {
|
|||
|
||||
// If flags are unknown, report the regex only if its pattern is invalid both with and without the "u" flag
|
||||
flags === null
|
||||
? validateRegExpPattern(pattern, true) && validateRegExpPattern(pattern, false)
|
||||
: validateRegExpPattern(pattern, flags.includes("u"))
|
||||
? (
|
||||
validateRegExpPattern(pattern, { unicode: true, unicodeSets: false }) &&
|
||||
validateRegExpPattern(pattern, { unicode: false, unicodeSets: true }) &&
|
||||
validateRegExpPattern(pattern, { unicode: false, unicodeSets: false })
|
||||
)
|
||||
: validateRegExpPattern(pattern, { unicode: flags.includes("u"), unicodeSets: flags.includes("v") })
|
||||
);
|
||||
|
||||
if (message) {
|
||||
|
|
|
|||
2
node_modules/eslint/lib/rules/no-loop-func.js
generated
vendored
2
node_modules/eslint/lib/rules/no-loop-func.js
generated
vendored
|
|
@ -186,7 +186,7 @@ module.exports = {
|
|||
}
|
||||
|
||||
const references = sourceCode.getScope(node).through;
|
||||
const unsafeRefs = references.filter(r => !isSafe(loopNode, r)).map(r => r.identifier.name);
|
||||
const unsafeRefs = references.filter(r => r.resolved && !isSafe(loopNode, r)).map(r => r.identifier.name);
|
||||
|
||||
if (unsafeRefs.length > 0) {
|
||||
context.report({
|
||||
|
|
|
|||
10
node_modules/eslint/lib/rules/no-misleading-character-class.js
generated
vendored
10
node_modules/eslint/lib/rules/no-misleading-character-class.js
generated
vendored
|
|
@ -18,7 +18,7 @@ const { isValidWithUnicodeFlag } = require("./utils/regular-expressions");
|
|||
*
|
||||
* CharacterClassRange syntax can steal a part of character sequence,
|
||||
* so this function reverts CharacterClassRange syntax and restore the sequence.
|
||||
* @param {regexpp.AST.CharacterClassElement[]} nodes The node list to iterate character sequences.
|
||||
* @param {import('@eslint-community/regexpp').AST.CharacterClassElement[]} nodes The node list to iterate character sequences.
|
||||
* @returns {IterableIterator<number[]>} The list of character sequences.
|
||||
*/
|
||||
function *iterateCharacterSequence(nodes) {
|
||||
|
|
@ -37,6 +37,9 @@ function *iterateCharacterSequence(nodes) {
|
|||
break;
|
||||
|
||||
case "CharacterSet":
|
||||
case "CharacterClass": // [[]] nesting character class
|
||||
case "ClassStringDisjunction": // \q{...}
|
||||
case "ExpressionCharacterClass": // [A--B]
|
||||
if (seq.length > 0) {
|
||||
yield seq;
|
||||
seq = [];
|
||||
|
|
@ -144,7 +147,10 @@ module.exports = {
|
|||
pattern,
|
||||
0,
|
||||
pattern.length,
|
||||
flags.includes("u")
|
||||
{
|
||||
unicode: flags.includes("u"),
|
||||
unicodeSets: flags.includes("v")
|
||||
}
|
||||
);
|
||||
} catch {
|
||||
|
||||
|
|
|
|||
21
node_modules/eslint/lib/rules/no-regex-spaces.js
generated
vendored
21
node_modules/eslint/lib/rules/no-regex-spaces.js
generated
vendored
|
|
@ -77,7 +77,7 @@ module.exports = {
|
|||
let regExpAST;
|
||||
|
||||
try {
|
||||
regExpAST = regExpParser.parsePattern(pattern, 0, pattern.length, flags.includes("u"));
|
||||
regExpAST = regExpParser.parsePattern(pattern, 0, pattern.length, { unicode: flags.includes("u"), unicodeSets: flags.includes("v") });
|
||||
} catch {
|
||||
|
||||
// Ignore regular expressions with syntax errors
|
||||
|
|
@ -155,13 +155,28 @@ module.exports = {
|
|||
const regExpVar = astUtils.getVariableByName(scope, "RegExp");
|
||||
const shadowed = regExpVar && regExpVar.defs.length > 0;
|
||||
const patternNode = node.arguments[0];
|
||||
const flagsNode = node.arguments[1];
|
||||
|
||||
if (node.callee.type === "Identifier" && node.callee.name === "RegExp" && isString(patternNode) && !shadowed) {
|
||||
const pattern = patternNode.value;
|
||||
const rawPattern = patternNode.raw.slice(1, -1);
|
||||
const rawPatternStartRange = patternNode.range[0] + 1;
|
||||
const flags = isString(flagsNode) ? flagsNode.value : "";
|
||||
let flags;
|
||||
|
||||
if (node.arguments.length < 2) {
|
||||
|
||||
// It has no flags.
|
||||
flags = "";
|
||||
} else {
|
||||
const flagsNode = node.arguments[1];
|
||||
|
||||
if (isString(flagsNode)) {
|
||||
flags = flagsNode.value;
|
||||
} else {
|
||||
|
||||
// The flags cannot be determined.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
checkRegex(
|
||||
node,
|
||||
|
|
|
|||
5
node_modules/eslint/lib/rules/no-return-await.js
generated
vendored
5
node_modules/eslint/lib/rules/no-return-await.js
generated
vendored
|
|
@ -1,6 +1,7 @@
|
|||
/**
|
||||
* @fileoverview Disallows unnecessary `return await`
|
||||
* @author Jordan Harband
|
||||
* @deprecated in ESLint v8.46.0
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
|
|
@ -26,6 +27,10 @@ module.exports = {
|
|||
|
||||
fixable: null,
|
||||
|
||||
deprecated: true,
|
||||
|
||||
replacedBy: [],
|
||||
|
||||
schema: [
|
||||
],
|
||||
|
||||
|
|
|
|||
2
node_modules/eslint/lib/rules/no-useless-backreference.js
generated
vendored
2
node_modules/eslint/lib/rules/no-useless-backreference.js
generated
vendored
|
|
@ -95,7 +95,7 @@ module.exports = {
|
|||
let regExpAST;
|
||||
|
||||
try {
|
||||
regExpAST = parser.parsePattern(pattern, 0, pattern.length, flags.includes("u"));
|
||||
regExpAST = parser.parsePattern(pattern, 0, pattern.length, { unicode: flags.includes("u"), unicodeSets: flags.includes("v") });
|
||||
} catch {
|
||||
|
||||
// Ignore regular expressions with syntax errors
|
||||
|
|
|
|||
235
node_modules/eslint/lib/rules/no-useless-escape.js
generated
vendored
235
node_modules/eslint/lib/rules/no-useless-escape.js
generated
vendored
|
|
@ -6,7 +6,12 @@
|
|||
"use strict";
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
const { RegExpParser, visitRegExpAST } = require("@eslint-community/regexpp");
|
||||
|
||||
/**
|
||||
* @typedef {import('@eslint-community/regexpp').AST.CharacterClass} CharacterClass
|
||||
* @typedef {import('@eslint-community/regexpp').AST.ExpressionCharacterClass} ExpressionCharacterClass
|
||||
*/
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -28,55 +33,17 @@ const VALID_STRING_ESCAPES = union(new Set("\\nrvtbfux"), astUtils.LINEBREAKS);
|
|||
const REGEX_GENERAL_ESCAPES = new Set("\\bcdDfnpPrsStvwWxu0123456789]");
|
||||
const REGEX_NON_CHARCLASS_ESCAPES = union(REGEX_GENERAL_ESCAPES, new Set("^/.$*+?[{}|()Bk"));
|
||||
|
||||
/**
|
||||
* Parses a regular expression into a list of characters with character class info.
|
||||
* @param {string} regExpText The raw text used to create the regular expression
|
||||
* @returns {Object[]} A list of characters, each with info on escaping and whether they're in a character class.
|
||||
* @example
|
||||
*
|
||||
* parseRegExp("a\\b[cd-]");
|
||||
*
|
||||
* // returns:
|
||||
* [
|
||||
* { text: "a", index: 0, escaped: false, inCharClass: false, startsCharClass: false, endsCharClass: false },
|
||||
* { text: "b", index: 2, escaped: true, inCharClass: false, startsCharClass: false, endsCharClass: false },
|
||||
* { text: "c", index: 4, escaped: false, inCharClass: true, startsCharClass: true, endsCharClass: false },
|
||||
* { text: "d", index: 5, escaped: false, inCharClass: true, startsCharClass: false, endsCharClass: false },
|
||||
* { text: "-", index: 6, escaped: false, inCharClass: true, startsCharClass: false, endsCharClass: false }
|
||||
* ];
|
||||
*
|
||||
/*
|
||||
* Set of characters that require escaping in character classes in `unicodeSets` mode.
|
||||
* ( ) [ ] { } / - \ | are ClassSetSyntaxCharacter
|
||||
*/
|
||||
function parseRegExp(regExpText) {
|
||||
const charList = [];
|
||||
const REGEX_CLASSSET_CHARACTER_ESCAPES = union(REGEX_GENERAL_ESCAPES, new Set("q/[{}|()-"));
|
||||
|
||||
regExpText.split("").reduce((state, char, index) => {
|
||||
if (!state.escapeNextChar) {
|
||||
if (char === "\\") {
|
||||
return Object.assign(state, { escapeNextChar: true });
|
||||
}
|
||||
if (char === "[" && !state.inCharClass) {
|
||||
return Object.assign(state, { inCharClass: true, startingCharClass: true });
|
||||
}
|
||||
if (char === "]" && state.inCharClass) {
|
||||
if (charList.length && charList[charList.length - 1].inCharClass) {
|
||||
charList[charList.length - 1].endsCharClass = true;
|
||||
}
|
||||
return Object.assign(state, { inCharClass: false, startingCharClass: false });
|
||||
}
|
||||
}
|
||||
charList.push({
|
||||
text: char,
|
||||
index,
|
||||
escaped: state.escapeNextChar,
|
||||
inCharClass: state.inCharClass,
|
||||
startsCharClass: state.startingCharClass,
|
||||
endsCharClass: false
|
||||
});
|
||||
return Object.assign(state, { escapeNextChar: false, startingCharClass: false });
|
||||
}, { escapeNextChar: false, inCharClass: false, startingCharClass: false });
|
||||
|
||||
return charList;
|
||||
}
|
||||
/*
|
||||
* A single character set of ClassSetReservedDoublePunctuator.
|
||||
* && !! ## $$ %% ** ++ ,, .. :: ;; << == >> ?? @@ ^^ `` ~~ are ClassSetReservedDoublePunctuator
|
||||
*/
|
||||
const REGEX_CLASS_SET_RESERVED_DOUBLE_PUNCTUATOR = new Set("!#$%&*+,.:;<=>?@^`~");
|
||||
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
|
|
@ -103,15 +70,17 @@ module.exports = {
|
|||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
const parser = new RegExpParser();
|
||||
|
||||
/**
|
||||
* Reports a node
|
||||
* @param {ASTNode} node The node to report
|
||||
* @param {number} startOffset The backslash's offset from the start of the node
|
||||
* @param {string} character The uselessly escaped character (not including the backslash)
|
||||
* @param {boolean} [disableEscapeBackslashSuggest] `true` if escapeBackslash suggestion should be turned off.
|
||||
* @returns {void}
|
||||
*/
|
||||
function report(node, startOffset, character) {
|
||||
function report(node, startOffset, character, disableEscapeBackslashSuggest) {
|
||||
const rangeStart = node.range[0] + startOffset;
|
||||
const range = [rangeStart, rangeStart + 1];
|
||||
const start = sourceCode.getLocFromIndex(rangeStart);
|
||||
|
|
@ -134,12 +103,16 @@ module.exports = {
|
|||
return fixer.removeRange(range);
|
||||
}
|
||||
},
|
||||
{
|
||||
messageId: "escapeBackslash",
|
||||
fix(fixer) {
|
||||
return fixer.insertTextBeforeRange(range, "\\");
|
||||
}
|
||||
}
|
||||
...disableEscapeBackslashSuggest
|
||||
? []
|
||||
: [
|
||||
{
|
||||
messageId: "escapeBackslash",
|
||||
fix(fixer) {
|
||||
return fixer.insertTextBeforeRange(range, "\\");
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
});
|
||||
}
|
||||
|
|
@ -182,6 +155,133 @@ module.exports = {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the escape character in given regexp is unnecessary.
|
||||
* @private
|
||||
* @param {ASTNode} node node to validate.
|
||||
* @returns {void}
|
||||
*/
|
||||
function validateRegExp(node) {
|
||||
const { pattern, flags } = node.regex;
|
||||
let patternNode;
|
||||
const unicode = flags.includes("u");
|
||||
const unicodeSets = flags.includes("v");
|
||||
|
||||
try {
|
||||
patternNode = parser.parsePattern(pattern, 0, pattern.length, { unicode, unicodeSets });
|
||||
} catch {
|
||||
|
||||
// Ignore regular expressions with syntax errors
|
||||
return;
|
||||
}
|
||||
|
||||
/** @type {(CharacterClass | ExpressionCharacterClass)[]} */
|
||||
const characterClassStack = [];
|
||||
|
||||
visitRegExpAST(patternNode, {
|
||||
onCharacterClassEnter: characterClassNode => characterClassStack.unshift(characterClassNode),
|
||||
onCharacterClassLeave: () => characterClassStack.shift(),
|
||||
onExpressionCharacterClassEnter: characterClassNode => characterClassStack.unshift(characterClassNode),
|
||||
onExpressionCharacterClassLeave: () => characterClassStack.shift(),
|
||||
onCharacterEnter(characterNode) {
|
||||
if (!characterNode.raw.startsWith("\\")) {
|
||||
|
||||
// It's not an escaped character.
|
||||
return;
|
||||
}
|
||||
|
||||
const escapedChar = characterNode.raw.slice(1);
|
||||
|
||||
if (escapedChar !== String.fromCodePoint(characterNode.value)) {
|
||||
|
||||
// It's a valid escape.
|
||||
return;
|
||||
}
|
||||
let allowedEscapes;
|
||||
|
||||
if (characterClassStack.length) {
|
||||
allowedEscapes = unicodeSets ? REGEX_CLASSSET_CHARACTER_ESCAPES : REGEX_GENERAL_ESCAPES;
|
||||
} else {
|
||||
allowedEscapes = REGEX_NON_CHARCLASS_ESCAPES;
|
||||
}
|
||||
if (allowedEscapes.has(escapedChar)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const reportedIndex = characterNode.start + 1;
|
||||
let disableEscapeBackslashSuggest = false;
|
||||
|
||||
if (characterClassStack.length) {
|
||||
const characterClassNode = characterClassStack[0];
|
||||
|
||||
if (escapedChar === "^") {
|
||||
|
||||
/*
|
||||
* The '^' character is also a special case; it must always be escaped outside of character classes, but
|
||||
* it only needs to be escaped in character classes if it's at the beginning of the character class. To
|
||||
* account for this, consider it to be a valid escape character outside of character classes, and filter
|
||||
* out '^' characters that appear at the start of a character class.
|
||||
*/
|
||||
if (characterClassNode.start + 1 === characterNode.start) {
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!unicodeSets) {
|
||||
if (escapedChar === "-") {
|
||||
|
||||
/*
|
||||
* The '-' character is a special case, because it's only valid to escape it if it's in a character
|
||||
* class, and is not at either edge of the character class. To account for this, don't consider '-'
|
||||
* characters to be valid in general, and filter out '-' characters that appear in the middle of a
|
||||
* character class.
|
||||
*/
|
||||
if (characterClassNode.start + 1 !== characterNode.start && characterNode.end !== characterClassNode.end - 1) {
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else { // unicodeSets mode
|
||||
if (REGEX_CLASS_SET_RESERVED_DOUBLE_PUNCTUATOR.has(escapedChar)) {
|
||||
|
||||
// Escaping is valid if it is a ClassSetReservedDoublePunctuator.
|
||||
if (pattern[characterNode.end] === escapedChar) {
|
||||
return;
|
||||
}
|
||||
if (pattern[characterNode.start - 1] === escapedChar) {
|
||||
if (escapedChar !== "^") {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the previous character is a `negate` caret(`^`), escape to caret is unnecessary.
|
||||
|
||||
if (!characterClassNode.negate) {
|
||||
return;
|
||||
}
|
||||
const negateCaretIndex = characterClassNode.start + 1;
|
||||
|
||||
if (negateCaretIndex < characterNode.start - 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (characterNode.parent.type === "ClassIntersection" || characterNode.parent.type === "ClassSubtraction") {
|
||||
disableEscapeBackslashSuggest = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
report(
|
||||
node,
|
||||
reportedIndex,
|
||||
escapedChar,
|
||||
disableEscapeBackslashSuggest
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a node has an escape.
|
||||
* @param {ASTNode} node node to check.
|
||||
|
|
@ -220,32 +320,7 @@ module.exports = {
|
|||
validateString(node, match);
|
||||
}
|
||||
} else if (node.regex) {
|
||||
parseRegExp(node.regex.pattern)
|
||||
|
||||
/*
|
||||
* The '-' character is a special case, because it's only valid to escape it if it's in a character
|
||||
* class, and is not at either edge of the character class. To account for this, don't consider '-'
|
||||
* characters to be valid in general, and filter out '-' characters that appear in the middle of a
|
||||
* character class.
|
||||
*/
|
||||
.filter(charInfo => !(charInfo.text === "-" && charInfo.inCharClass && !charInfo.startsCharClass && !charInfo.endsCharClass))
|
||||
|
||||
/*
|
||||
* The '^' character is also a special case; it must always be escaped outside of character classes, but
|
||||
* it only needs to be escaped in character classes if it's at the beginning of the character class. To
|
||||
* account for this, consider it to be a valid escape character outside of character classes, and filter
|
||||
* out '^' characters that appear at the start of a character class.
|
||||
*/
|
||||
.filter(charInfo => !(charInfo.text === "^" && charInfo.startsCharClass))
|
||||
|
||||
// Filter out characters that aren't escaped.
|
||||
.filter(charInfo => charInfo.escaped)
|
||||
|
||||
// Filter out characters that are valid to escape, based on their position in the regular expression.
|
||||
.filter(charInfo => !(charInfo.inCharClass ? REGEX_GENERAL_ESCAPES : REGEX_NON_CHARCLASS_ESCAPES).has(charInfo.text))
|
||||
|
||||
// Report all the remaining characters.
|
||||
.forEach(charInfo => report(node, charInfo.index, charInfo.text));
|
||||
validateRegExp(node);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
13
node_modules/eslint/lib/rules/prefer-named-capture-group.js
generated
vendored
13
node_modules/eslint/lib/rules/prefer-named-capture-group.js
generated
vendored
|
|
@ -112,14 +112,17 @@ module.exports = {
|
|||
* @param {string} pattern The regular expression pattern to be checked.
|
||||
* @param {ASTNode} node AST node which contains the regular expression or a call/new expression.
|
||||
* @param {ASTNode} regexNode AST node which contains the regular expression.
|
||||
* @param {boolean} uFlag Flag indicates whether unicode mode is enabled or not.
|
||||
* @param {string|null} flags The regular expression flags to be checked.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkRegex(pattern, node, regexNode, uFlag) {
|
||||
function checkRegex(pattern, node, regexNode, flags) {
|
||||
let ast;
|
||||
|
||||
try {
|
||||
ast = parser.parsePattern(pattern, 0, pattern.length, uFlag);
|
||||
ast = parser.parsePattern(pattern, 0, pattern.length, {
|
||||
unicode: Boolean(flags && flags.includes("u")),
|
||||
unicodeSets: Boolean(flags && flags.includes("v"))
|
||||
});
|
||||
} catch {
|
||||
|
||||
// ignore regex syntax errors
|
||||
|
|
@ -148,7 +151,7 @@ module.exports = {
|
|||
return {
|
||||
Literal(node) {
|
||||
if (node.regex) {
|
||||
checkRegex(node.regex.pattern, node, node, node.regex.flags.includes("u"));
|
||||
checkRegex(node.regex.pattern, node, node, node.regex.flags);
|
||||
}
|
||||
},
|
||||
Program(node) {
|
||||
|
|
@ -166,7 +169,7 @@ module.exports = {
|
|||
const flags = getStringIfConstant(refNode.arguments[1]);
|
||||
|
||||
if (regex) {
|
||||
checkRegex(regex, refNode, refNode.arguments[0], flags && flags.includes("u"));
|
||||
checkRegex(regex, refNode, refNode.arguments[0], flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
12
node_modules/eslint/lib/rules/prefer-regex-literals.js
generated
vendored
12
node_modules/eslint/lib/rules/prefer-regex-literals.js
generated
vendored
|
|
@ -241,7 +241,7 @@ module.exports = {
|
|||
/**
|
||||
* Returns a ecmaVersion compatible for regexpp.
|
||||
* @param {number} ecmaVersion The ecmaVersion to convert.
|
||||
* @returns {import("regexpp/ecma-versions").EcmaVersion} The resulting ecmaVersion compatible for regexpp.
|
||||
* @returns {import("@eslint-community/regexpp/ecma-versions").EcmaVersion} The resulting ecmaVersion compatible for regexpp.
|
||||
*/
|
||||
function getRegexppEcmaVersion(ecmaVersion) {
|
||||
if (ecmaVersion <= 5) {
|
||||
|
|
@ -297,7 +297,10 @@ module.exports = {
|
|||
const validator = new RegExpValidator({ ecmaVersion: regexppEcmaVersion });
|
||||
|
||||
try {
|
||||
validator.validatePattern(pattern, 0, pattern.length, flags ? flags.includes("u") : false);
|
||||
validator.validatePattern(pattern, 0, pattern.length, {
|
||||
unicode: flags ? flags.includes("u") : false,
|
||||
unicodeSets: flags ? flags.includes("v") : false
|
||||
});
|
||||
if (flags) {
|
||||
validator.validateFlags(flags);
|
||||
}
|
||||
|
|
@ -461,7 +464,10 @@ module.exports = {
|
|||
if (regexContent && !noFix) {
|
||||
let charIncrease = 0;
|
||||
|
||||
const ast = new RegExpParser({ ecmaVersion: regexppEcmaVersion }).parsePattern(regexContent, 0, regexContent.length, flags ? flags.includes("u") : false);
|
||||
const ast = new RegExpParser({ ecmaVersion: regexppEcmaVersion }).parsePattern(regexContent, 0, regexContent.length, {
|
||||
unicode: flags ? flags.includes("u") : false,
|
||||
unicodeSets: flags ? flags.includes("v") : false
|
||||
});
|
||||
|
||||
visitRegExpAST(ast, {
|
||||
onCharacterEnter(characterNode) {
|
||||
|
|
|
|||
6
node_modules/eslint/lib/rules/require-unicode-regexp.js
generated
vendored
6
node_modules/eslint/lib/rules/require-unicode-regexp.js
generated
vendored
|
|
@ -28,7 +28,7 @@ module.exports = {
|
|||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "Enforce the use of `u` flag on RegExp",
|
||||
description: "Enforce the use of `u` or `v` flag on RegExp",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/require-unicode-regexp"
|
||||
},
|
||||
|
|
@ -51,7 +51,7 @@ module.exports = {
|
|||
"Literal[regex]"(node) {
|
||||
const flags = node.regex.flags || "";
|
||||
|
||||
if (!flags.includes("u")) {
|
||||
if (!flags.includes("u") && !flags.includes("v")) {
|
||||
context.report({
|
||||
messageId: "requireUFlag",
|
||||
node,
|
||||
|
|
@ -85,7 +85,7 @@ module.exports = {
|
|||
const pattern = getStringIfConstant(patternNode, scope);
|
||||
const flags = getStringIfConstant(flagsNode, scope);
|
||||
|
||||
if (!flagsNode || (typeof flags === "string" && !flags.includes("u"))) {
|
||||
if (!flagsNode || (typeof flags === "string" && !flags.includes("u") && !flags.includes("v"))) {
|
||||
context.report({
|
||||
messageId: "requireUFlag",
|
||||
node: refNode,
|
||||
|
|
|
|||
4
node_modules/eslint/lib/rules/utils/regular-expressions.js
generated
vendored
4
node_modules/eslint/lib/rules/utils/regular-expressions.js
generated
vendored
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
const { RegExpValidator } = require("@eslint-community/regexpp");
|
||||
|
||||
const REGEXPP_LATEST_ECMA_VERSION = 2022;
|
||||
const REGEXPP_LATEST_ECMA_VERSION = 2024;
|
||||
|
||||
/**
|
||||
* Checks if the given regular expression pattern would be valid with the `u` flag.
|
||||
|
|
@ -28,7 +28,7 @@ function isValidWithUnicodeFlag(ecmaVersion, pattern) {
|
|||
});
|
||||
|
||||
try {
|
||||
validator.validatePattern(pattern, void 0, void 0, /* uFlag = */ true);
|
||||
validator.validatePattern(pattern, void 0, void 0, { unicode: /* uFlag = */ true });
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue