build: update npm install command to use --legacy-peer-deps
This change modifies the build scripts to use --legacy-peer-deps flag when installing npm dependencies to resolve potential peer dependency conflicts during the build process. The change is applied to both bash (build.sh) and batch (build.bat) build scripts.
This commit is contained in:
+119
-188
@@ -9,12 +9,7 @@
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const {
|
||||
CALL,
|
||||
CONSTRUCT,
|
||||
ReferenceTracker,
|
||||
getStringIfConstant,
|
||||
} = require("@eslint-community/eslint-utils");
|
||||
const { CALL, CONSTRUCT, ReferenceTracker, getStringIfConstant } = require("@eslint-community/eslint-utils");
|
||||
const { RegExpParser, visitRegExpAST } = require("@eslint-community/regexpp");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -29,15 +24,15 @@ const parser = new RegExpParser();
|
||||
* @returns {regexpp.Node[]} Array that starts with the given node and ends with the root node.
|
||||
*/
|
||||
function getPathToRoot(node) {
|
||||
const path = [];
|
||||
let current = node;
|
||||
const path = [];
|
||||
let current = node;
|
||||
|
||||
do {
|
||||
path.push(current);
|
||||
current = current.parent;
|
||||
} while (current);
|
||||
do {
|
||||
path.push(current);
|
||||
current = current.parent;
|
||||
} while (current);
|
||||
|
||||
return path;
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,10 +41,8 @@ function getPathToRoot(node) {
|
||||
* @returns {boolean} `true` if it is a lookaround node.
|
||||
*/
|
||||
function isLookaround(node) {
|
||||
return (
|
||||
node.type === "Assertion" &&
|
||||
(node.kind === "lookahead" || node.kind === "lookbehind")
|
||||
);
|
||||
return node.type === "Assertion" &&
|
||||
(node.kind === "lookahead" || node.kind === "lookbehind");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,206 +51,144 @@ function isLookaround(node) {
|
||||
* @returns {boolean} `true` if it is a negative lookaround node.
|
||||
*/
|
||||
function isNegativeLookaround(node) {
|
||||
return isLookaround(node) && node.negate;
|
||||
return isLookaround(node) && node.negate;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
meta: {
|
||||
type: "problem",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Disallow useless backreferences in regular expressions",
|
||||
recommended: true,
|
||||
url: "https://eslint.org/docs/latest/rules/no-useless-backreference",
|
||||
},
|
||||
docs: {
|
||||
description: "Disallow useless backreferences in regular expressions",
|
||||
recommended: true,
|
||||
url: "https://eslint.org/docs/latest/rules/no-useless-backreference"
|
||||
},
|
||||
|
||||
schema: [],
|
||||
schema: [],
|
||||
|
||||
messages: {
|
||||
nested: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}'{{ otherGroups }} from within that group.",
|
||||
forward:
|
||||
"Backreference '{{ bref }}' will be ignored. It references group '{{ group }}'{{ otherGroups }} which appears later in the pattern.",
|
||||
backward:
|
||||
"Backreference '{{ bref }}' will be ignored. It references group '{{ group }}'{{ otherGroups }} which appears before in the same lookbehind.",
|
||||
disjunctive:
|
||||
"Backreference '{{ bref }}' will be ignored. It references group '{{ group }}'{{ otherGroups }} which is in another alternative.",
|
||||
intoNegativeLookaround:
|
||||
"Backreference '{{ bref }}' will be ignored. It references group '{{ group }}'{{ otherGroups }} which is in a negative lookaround.",
|
||||
},
|
||||
},
|
||||
messages: {
|
||||
nested: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}' from within that group.",
|
||||
forward: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}' which appears later in the pattern.",
|
||||
backward: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}' which appears before in the same lookbehind.",
|
||||
disjunctive: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}' which is in another alternative.",
|
||||
intoNegativeLookaround: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}' which is in a negative lookaround."
|
||||
}
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
create(context) {
|
||||
|
||||
/**
|
||||
* Checks and reports useless backreferences in the given regular expression.
|
||||
* @param {ASTNode} node Node that represents regular expression. A regex literal or RegExp constructor call.
|
||||
* @param {string} pattern Regular expression pattern.
|
||||
* @param {string} flags Regular expression flags.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkRegex(node, pattern, flags) {
|
||||
let regExpAST;
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
try {
|
||||
regExpAST = parser.parsePattern(pattern, 0, pattern.length, {
|
||||
unicode: flags.includes("u"),
|
||||
unicodeSets: flags.includes("v"),
|
||||
});
|
||||
} catch {
|
||||
// Ignore regular expressions with syntax errors
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Checks and reports useless backreferences in the given regular expression.
|
||||
* @param {ASTNode} node Node that represents regular expression. A regex literal or RegExp constructor call.
|
||||
* @param {string} pattern Regular expression pattern.
|
||||
* @param {string} flags Regular expression flags.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkRegex(node, pattern, flags) {
|
||||
let regExpAST;
|
||||
|
||||
visitRegExpAST(regExpAST, {
|
||||
onBackreferenceEnter(bref) {
|
||||
const groups = [bref.resolved].flat(),
|
||||
brefPath = getPathToRoot(bref);
|
||||
try {
|
||||
regExpAST = parser.parsePattern(pattern, 0, pattern.length, { unicode: flags.includes("u"), unicodeSets: flags.includes("v") });
|
||||
} catch {
|
||||
|
||||
const problems = groups.map(group => {
|
||||
const groupPath = getPathToRoot(group);
|
||||
// Ignore regular expressions with syntax errors
|
||||
return;
|
||||
}
|
||||
|
||||
if (brefPath.includes(group)) {
|
||||
// group is bref's ancestor => bref is nested ('nested reference') => group hasn't matched yet when bref starts to match.
|
||||
return {
|
||||
messageId: "nested",
|
||||
group,
|
||||
};
|
||||
}
|
||||
visitRegExpAST(regExpAST, {
|
||||
onBackreferenceEnter(bref) {
|
||||
const group = bref.resolved,
|
||||
brefPath = getPathToRoot(bref),
|
||||
groupPath = getPathToRoot(group);
|
||||
let messageId = null;
|
||||
|
||||
// Start from the root to find the lowest common ancestor.
|
||||
let i = brefPath.length - 1,
|
||||
j = groupPath.length - 1;
|
||||
if (brefPath.includes(group)) {
|
||||
|
||||
do {
|
||||
i--;
|
||||
j--;
|
||||
} while (brefPath[i] === groupPath[j]);
|
||||
// group is bref's ancestor => bref is nested ('nested reference') => group hasn't matched yet when bref starts to match.
|
||||
messageId = "nested";
|
||||
} else {
|
||||
|
||||
const indexOfLowestCommonAncestor = j + 1,
|
||||
groupCut = groupPath.slice(
|
||||
0,
|
||||
indexOfLowestCommonAncestor,
|
||||
),
|
||||
commonPath = groupPath.slice(
|
||||
indexOfLowestCommonAncestor,
|
||||
),
|
||||
lowestCommonLookaround =
|
||||
commonPath.find(isLookaround),
|
||||
isMatchingBackward =
|
||||
lowestCommonLookaround &&
|
||||
lowestCommonLookaround.kind === "lookbehind";
|
||||
// Start from the root to find the lowest common ancestor.
|
||||
let i = brefPath.length - 1,
|
||||
j = groupPath.length - 1;
|
||||
|
||||
if (groupCut.at(-1).type === "Alternative") {
|
||||
// group's and bref's ancestor nodes below the lowest common ancestor are sibling alternatives => they're disjunctive.
|
||||
return {
|
||||
messageId: "disjunctive",
|
||||
group,
|
||||
};
|
||||
}
|
||||
if (!isMatchingBackward && bref.end <= group.start) {
|
||||
// bref is left, group is right ('forward reference') => group hasn't matched yet when bref starts to match.
|
||||
return {
|
||||
messageId: "forward",
|
||||
group,
|
||||
};
|
||||
}
|
||||
if (isMatchingBackward && group.end <= bref.start) {
|
||||
// the opposite of the previous when the regex is matching backward in a lookbehind context.
|
||||
return {
|
||||
messageId: "backward",
|
||||
group,
|
||||
};
|
||||
}
|
||||
if (groupCut.some(isNegativeLookaround)) {
|
||||
// group is in a negative lookaround which isn't bref's ancestor => group has already failed when bref starts to match.
|
||||
return {
|
||||
messageId: "intoNegativeLookaround",
|
||||
group,
|
||||
};
|
||||
}
|
||||
do {
|
||||
i--;
|
||||
j--;
|
||||
} while (brefPath[i] === groupPath[j]);
|
||||
|
||||
return null;
|
||||
});
|
||||
const indexOfLowestCommonAncestor = j + 1,
|
||||
groupCut = groupPath.slice(0, indexOfLowestCommonAncestor),
|
||||
commonPath = groupPath.slice(indexOfLowestCommonAncestor),
|
||||
lowestCommonLookaround = commonPath.find(isLookaround),
|
||||
isMatchingBackward = lowestCommonLookaround && lowestCommonLookaround.kind === "lookbehind";
|
||||
|
||||
if (
|
||||
problems.length === 0 ||
|
||||
problems.some(problem => !problem)
|
||||
) {
|
||||
// If there are no problems or no problems with any group then do not report it.
|
||||
return;
|
||||
}
|
||||
if (!isMatchingBackward && bref.end <= group.start) {
|
||||
|
||||
let problemsToReport;
|
||||
// bref is left, group is right ('forward reference') => group hasn't matched yet when bref starts to match.
|
||||
messageId = "forward";
|
||||
} else if (isMatchingBackward && group.end <= bref.start) {
|
||||
|
||||
// Gets problems that appear in the same disjunction.
|
||||
const problemsInSameDisjunction = problems.filter(
|
||||
problem => problem.messageId !== "disjunctive",
|
||||
);
|
||||
// the opposite of the previous when the regex is matching backward in a lookbehind context.
|
||||
messageId = "backward";
|
||||
} else if (groupCut[groupCut.length - 1].type === "Alternative") {
|
||||
|
||||
if (problemsInSameDisjunction.length) {
|
||||
// Only report problems that appear in the same disjunction.
|
||||
problemsToReport = problemsInSameDisjunction;
|
||||
} else {
|
||||
// If all groups appear in different disjunctions, report it.
|
||||
problemsToReport = problems;
|
||||
}
|
||||
// group's and bref's ancestor nodes below the lowest common ancestor are sibling alternatives => they're disjunctive.
|
||||
messageId = "disjunctive";
|
||||
} else if (groupCut.some(isNegativeLookaround)) {
|
||||
|
||||
const [{ messageId, group }, ...other] = problemsToReport;
|
||||
let otherGroups = "";
|
||||
// group is in a negative lookaround which isn't bref's ancestor => group has already failed when bref starts to match.
|
||||
messageId = "intoNegativeLookaround";
|
||||
}
|
||||
}
|
||||
|
||||
if (other.length === 1) {
|
||||
otherGroups = " and another group";
|
||||
} else if (other.length > 1) {
|
||||
otherGroups = ` and other ${other.length} groups`;
|
||||
}
|
||||
context.report({
|
||||
node,
|
||||
messageId,
|
||||
data: {
|
||||
bref: bref.raw,
|
||||
group: group.raw,
|
||||
otherGroups,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
if (messageId) {
|
||||
context.report({
|
||||
node,
|
||||
messageId,
|
||||
data: {
|
||||
bref: bref.raw,
|
||||
group: group.raw
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
"Literal[regex]"(node) {
|
||||
const { pattern, flags } = node.regex;
|
||||
return {
|
||||
"Literal[regex]"(node) {
|
||||
const { pattern, flags } = node.regex;
|
||||
|
||||
checkRegex(node, pattern, flags);
|
||||
},
|
||||
Program(node) {
|
||||
const scope = sourceCode.getScope(node),
|
||||
tracker = new ReferenceTracker(scope),
|
||||
traceMap = {
|
||||
RegExp: {
|
||||
[CALL]: true,
|
||||
[CONSTRUCT]: true,
|
||||
},
|
||||
};
|
||||
checkRegex(node, pattern, flags);
|
||||
},
|
||||
Program(node) {
|
||||
const scope = sourceCode.getScope(node),
|
||||
tracker = new ReferenceTracker(scope),
|
||||
traceMap = {
|
||||
RegExp: {
|
||||
[CALL]: true,
|
||||
[CONSTRUCT]: true
|
||||
}
|
||||
};
|
||||
|
||||
for (const { node: refNode } of tracker.iterateGlobalReferences(
|
||||
traceMap,
|
||||
)) {
|
||||
const [patternNode, flagsNode] = refNode.arguments,
|
||||
pattern = getStringIfConstant(patternNode, scope),
|
||||
flags = getStringIfConstant(flagsNode, scope);
|
||||
for (const { node: refNode } of tracker.iterateGlobalReferences(traceMap)) {
|
||||
const [patternNode, flagsNode] = refNode.arguments,
|
||||
pattern = getStringIfConstant(patternNode, scope),
|
||||
flags = getStringIfConstant(flagsNode, scope);
|
||||
|
||||
if (typeof pattern === "string") {
|
||||
checkRegex(refNode, pattern, flags || "");
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
if (typeof pattern === "string") {
|
||||
checkRegex(refNode, pattern, flags || "");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user