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.
198 lines
6.4 KiB
JavaScript
198 lines
6.4 KiB
JavaScript
/**
|
|
* @fileoverview Rule to count multiple spaces in regular expressions
|
|
* @author Matt DuVall <http://www.mattduvall.com/>
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Requirements
|
|
//------------------------------------------------------------------------------
|
|
|
|
const astUtils = require("./utils/ast-utils");
|
|
const regexpp = require("@eslint-community/regexpp");
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Helpers
|
|
//------------------------------------------------------------------------------
|
|
|
|
const regExpParser = new regexpp.RegExpParser();
|
|
const DOUBLE_SPACE = / {2}/u;
|
|
|
|
/**
|
|
* Check if node is a string
|
|
* @param {ASTNode} node node to evaluate
|
|
* @returns {boolean} True if its a string
|
|
* @private
|
|
*/
|
|
function isString(node) {
|
|
return node && node.type === "Literal" && typeof node.value === "string";
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Rule Definition
|
|
//------------------------------------------------------------------------------
|
|
|
|
/** @type {import('../shared/types').Rule} */
|
|
module.exports = {
|
|
meta: {
|
|
type: "suggestion",
|
|
|
|
docs: {
|
|
description: "Disallow multiple spaces in regular expressions",
|
|
recommended: true,
|
|
url: "https://eslint.org/docs/latest/rules/no-regex-spaces"
|
|
},
|
|
|
|
schema: [],
|
|
fixable: "code",
|
|
|
|
messages: {
|
|
multipleSpaces: "Spaces are hard to count. Use {{{length}}}."
|
|
}
|
|
},
|
|
|
|
create(context) {
|
|
|
|
const sourceCode = context.sourceCode;
|
|
|
|
/**
|
|
* Validate regular expression
|
|
* @param {ASTNode} nodeToReport Node to report.
|
|
* @param {string} pattern Regular expression pattern to validate.
|
|
* @param {string} rawPattern Raw representation of the pattern in the source code.
|
|
* @param {number} rawPatternStartRange Start range of the pattern in the source code.
|
|
* @param {string} flags Regular expression flags.
|
|
* @returns {void}
|
|
* @private
|
|
*/
|
|
function checkRegex(nodeToReport, pattern, rawPattern, rawPatternStartRange, flags) {
|
|
|
|
// Skip if there are no consecutive spaces in the source code, to avoid reporting e.g., RegExp(' \ ').
|
|
if (!DOUBLE_SPACE.test(rawPattern)) {
|
|
return;
|
|
}
|
|
|
|
const characterClassNodes = [];
|
|
let regExpAST;
|
|
|
|
try {
|
|
regExpAST = regExpParser.parsePattern(pattern, 0, pattern.length, { unicode: flags.includes("u"), unicodeSets: flags.includes("v") });
|
|
} catch {
|
|
|
|
// Ignore regular expressions with syntax errors
|
|
return;
|
|
}
|
|
|
|
regexpp.visitRegExpAST(regExpAST, {
|
|
onCharacterClassEnter(ccNode) {
|
|
characterClassNodes.push(ccNode);
|
|
}
|
|
});
|
|
|
|
const spacesPattern = /( {2,})(?: [+*{?]|[^+*{?]|$)/gu;
|
|
let match;
|
|
|
|
while ((match = spacesPattern.exec(pattern))) {
|
|
const { 1: { length }, index } = match;
|
|
|
|
// Report only consecutive spaces that are not in character classes.
|
|
if (
|
|
characterClassNodes.every(({ start, end }) => index < start || end <= index)
|
|
) {
|
|
context.report({
|
|
node: nodeToReport,
|
|
messageId: "multipleSpaces",
|
|
data: { length },
|
|
fix(fixer) {
|
|
if (pattern !== rawPattern) {
|
|
return null;
|
|
}
|
|
return fixer.replaceTextRange(
|
|
[rawPatternStartRange + index, rawPatternStartRange + index + length],
|
|
` {${length}}`
|
|
);
|
|
}
|
|
});
|
|
|
|
// Report only the first occurrence of consecutive spaces
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate regular expression literals
|
|
* @param {ASTNode} node node to validate
|
|
* @returns {void}
|
|
* @private
|
|
*/
|
|
function checkLiteral(node) {
|
|
if (node.regex) {
|
|
const pattern = node.regex.pattern;
|
|
const rawPattern = node.raw.slice(1, node.raw.lastIndexOf("/"));
|
|
const rawPatternStartRange = node.range[0] + 1;
|
|
const flags = node.regex.flags;
|
|
|
|
checkRegex(
|
|
node,
|
|
pattern,
|
|
rawPattern,
|
|
rawPatternStartRange,
|
|
flags
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate strings passed to the RegExp constructor
|
|
* @param {ASTNode} node node to validate
|
|
* @returns {void}
|
|
* @private
|
|
*/
|
|
function checkFunction(node) {
|
|
const scope = sourceCode.getScope(node);
|
|
const regExpVar = astUtils.getVariableByName(scope, "RegExp");
|
|
const shadowed = regExpVar && regExpVar.defs.length > 0;
|
|
const patternNode = node.arguments[0];
|
|
|
|
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;
|
|
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,
|
|
pattern,
|
|
rawPattern,
|
|
rawPatternStartRange,
|
|
flags
|
|
);
|
|
}
|
|
}
|
|
|
|
return {
|
|
Literal: checkLiteral,
|
|
CallExpression: checkFunction,
|
|
NewExpression: checkFunction
|
|
};
|
|
}
|
|
};
|