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:
+249
-313
@@ -5,359 +5,295 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
defaultOptions: [
|
||||
"^.+$",
|
||||
{
|
||||
classFields: false,
|
||||
ignoreDestructuring: false,
|
||||
onlyDeclarations: false,
|
||||
properties: false,
|
||||
},
|
||||
],
|
||||
docs: {
|
||||
description: "Require identifiers to match a specified regular expression",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/id-match"
|
||||
},
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Require identifiers to match a specified regular expression",
|
||||
recommended: false,
|
||||
frozen: true,
|
||||
url: "https://eslint.org/docs/latest/rules/id-match",
|
||||
},
|
||||
schema: [
|
||||
{
|
||||
type: "string"
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
properties: {
|
||||
type: "boolean",
|
||||
default: false
|
||||
},
|
||||
classFields: {
|
||||
type: "boolean",
|
||||
default: false
|
||||
},
|
||||
onlyDeclarations: {
|
||||
type: "boolean",
|
||||
default: false
|
||||
},
|
||||
ignoreDestructuring: {
|
||||
type: "boolean",
|
||||
default: false
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
],
|
||||
messages: {
|
||||
notMatch: "Identifier '{{name}}' does not match the pattern '{{pattern}}'.",
|
||||
notMatchPrivate: "Identifier '#{{name}}' does not match the pattern '{{pattern}}'."
|
||||
}
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
properties: {
|
||||
type: "boolean",
|
||||
},
|
||||
classFields: {
|
||||
type: "boolean",
|
||||
},
|
||||
onlyDeclarations: {
|
||||
type: "boolean",
|
||||
},
|
||||
ignoreDestructuring: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
messages: {
|
||||
notMatch:
|
||||
"Identifier '{{name}}' does not match the pattern '{{pattern}}'.",
|
||||
notMatchPrivate:
|
||||
"Identifier '#{{name}}' does not match the pattern '{{pattern}}'.",
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
|
||||
create(context) {
|
||||
//--------------------------------------------------------------------------
|
||||
// Options
|
||||
//--------------------------------------------------------------------------
|
||||
const [
|
||||
pattern,
|
||||
{
|
||||
classFields: checkClassFields,
|
||||
ignoreDestructuring,
|
||||
onlyDeclarations,
|
||||
properties: checkProperties,
|
||||
},
|
||||
] = context.options;
|
||||
const regexp = new RegExp(pattern, "u");
|
||||
//--------------------------------------------------------------------------
|
||||
// Options
|
||||
//--------------------------------------------------------------------------
|
||||
const pattern = context.options[0] || "^.+$",
|
||||
regexp = new RegExp(pattern, "u");
|
||||
|
||||
const sourceCode = context.sourceCode;
|
||||
let globalScope;
|
||||
const options = context.options[1] || {},
|
||||
checkProperties = !!options.properties,
|
||||
checkClassFields = !!options.classFields,
|
||||
onlyDeclarations = !!options.onlyDeclarations,
|
||||
ignoreDestructuring = !!options.ignoreDestructuring;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//--------------------------------------------------------------------------
|
||||
const sourceCode = context.sourceCode;
|
||||
let globalScope;
|
||||
|
||||
// contains reported nodes to avoid reporting twice on destructuring with shorthand notation
|
||||
const reportedNodes = new Set();
|
||||
const ALLOWED_PARENT_TYPES = new Set([
|
||||
"CallExpression",
|
||||
"NewExpression",
|
||||
]);
|
||||
const DECLARATION_TYPES = new Set([
|
||||
"FunctionDeclaration",
|
||||
"VariableDeclarator",
|
||||
]);
|
||||
const IMPORT_TYPES = new Set([
|
||||
"ImportSpecifier",
|
||||
"ImportNamespaceSpecifier",
|
||||
"ImportDefaultSpecifier",
|
||||
]);
|
||||
//--------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks whether the given node represents a reference to a global variable that is not declared in the source code.
|
||||
* These identifiers will be allowed, as it is assumed that user has no control over the names of external global variables.
|
||||
* @param {ASTNode} node `Identifier` node to check.
|
||||
* @returns {boolean} `true` if the node is a reference to a global variable.
|
||||
*/
|
||||
function isReferenceToGlobalVariable(node) {
|
||||
const variable = globalScope.set.get(node.name);
|
||||
// contains reported nodes to avoid reporting twice on destructuring with shorthand notation
|
||||
const reportedNodes = new Set();
|
||||
const ALLOWED_PARENT_TYPES = new Set(["CallExpression", "NewExpression"]);
|
||||
const DECLARATION_TYPES = new Set(["FunctionDeclaration", "VariableDeclarator"]);
|
||||
const IMPORT_TYPES = new Set(["ImportSpecifier", "ImportNamespaceSpecifier", "ImportDefaultSpecifier"]);
|
||||
|
||||
return (
|
||||
variable &&
|
||||
variable.defs.length === 0 &&
|
||||
variable.references.some(ref => ref.identifier === node)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Checks whether the given node represents a reference to a global variable that is not declared in the source code.
|
||||
* These identifiers will be allowed, as it is assumed that user has no control over the names of external global variables.
|
||||
* @param {ASTNode} node `Identifier` node to check.
|
||||
* @returns {boolean} `true` if the node is a reference to a global variable.
|
||||
*/
|
||||
function isReferenceToGlobalVariable(node) {
|
||||
const variable = globalScope.set.get(node.name);
|
||||
|
||||
/**
|
||||
* Checks if a string matches the provided pattern
|
||||
* @param {string} name The string to check.
|
||||
* @returns {boolean} if the string is a match
|
||||
* @private
|
||||
*/
|
||||
function isInvalid(name) {
|
||||
return !regexp.test(name);
|
||||
}
|
||||
return variable && variable.defs.length === 0 &&
|
||||
variable.references.some(ref => ref.identifier === node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a parent of a node is an ObjectPattern.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {boolean} if the node is inside an ObjectPattern
|
||||
* @private
|
||||
*/
|
||||
function isInsideObjectPattern(node) {
|
||||
let { parent } = node;
|
||||
/**
|
||||
* Checks if a string matches the provided pattern
|
||||
* @param {string} name The string to check.
|
||||
* @returns {boolean} if the string is a match
|
||||
* @private
|
||||
*/
|
||||
function isInvalid(name) {
|
||||
return !regexp.test(name);
|
||||
}
|
||||
|
||||
while (parent) {
|
||||
if (parent.type === "ObjectPattern") {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Checks if a parent of a node is an ObjectPattern.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {boolean} if the node is inside an ObjectPattern
|
||||
* @private
|
||||
*/
|
||||
function isInsideObjectPattern(node) {
|
||||
let { parent } = node;
|
||||
|
||||
parent = parent.parent;
|
||||
}
|
||||
while (parent) {
|
||||
if (parent.type === "ObjectPattern") {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
parent = parent.parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if we should report an error or not based on the effective
|
||||
* parent node and the identifier name.
|
||||
* @param {ASTNode} effectiveParent The effective parent node of the node to be reported
|
||||
* @param {string} name The identifier name of the identifier node
|
||||
* @returns {boolean} whether an error should be reported or not
|
||||
*/
|
||||
function shouldReport(effectiveParent, name) {
|
||||
return (
|
||||
(!onlyDeclarations ||
|
||||
DECLARATION_TYPES.has(effectiveParent.type)) &&
|
||||
!ALLOWED_PARENT_TYPES.has(effectiveParent.type) &&
|
||||
isInvalid(name)
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an AST node as a rule violation.
|
||||
* @param {ASTNode} node The node to report.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function report(node) {
|
||||
/*
|
||||
* We used the range instead of the node because it's possible
|
||||
* for the same identifier to be represented by two different
|
||||
* nodes, with the most clear example being shorthand properties:
|
||||
* { foo }
|
||||
* In this case, "foo" is represented by one node for the name
|
||||
* and one for the value. The only way to know they are the same
|
||||
* is to look at the range.
|
||||
*/
|
||||
if (!reportedNodes.has(node.range.toString())) {
|
||||
const messageId =
|
||||
node.type === "PrivateIdentifier"
|
||||
? "notMatchPrivate"
|
||||
: "notMatch";
|
||||
/**
|
||||
* Verifies if we should report an error or not based on the effective
|
||||
* parent node and the identifier name.
|
||||
* @param {ASTNode} effectiveParent The effective parent node of the node to be reported
|
||||
* @param {string} name The identifier name of the identifier node
|
||||
* @returns {boolean} whether an error should be reported or not
|
||||
*/
|
||||
function shouldReport(effectiveParent, name) {
|
||||
return (!onlyDeclarations || DECLARATION_TYPES.has(effectiveParent.type)) &&
|
||||
!ALLOWED_PARENT_TYPES.has(effectiveParent.type) && isInvalid(name);
|
||||
}
|
||||
|
||||
context.report({
|
||||
node,
|
||||
messageId,
|
||||
data: {
|
||||
name: node.name,
|
||||
pattern,
|
||||
},
|
||||
});
|
||||
reportedNodes.add(node.range.toString());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Reports an AST node as a rule violation.
|
||||
* @param {ASTNode} node The node to report.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function report(node) {
|
||||
|
||||
return {
|
||||
Program(node) {
|
||||
globalScope = sourceCode.getScope(node);
|
||||
},
|
||||
/*
|
||||
* We used the range instead of the node because it's possible
|
||||
* for the same identifier to be represented by two different
|
||||
* nodes, with the most clear example being shorthand properties:
|
||||
* { foo }
|
||||
* In this case, "foo" is represented by one node for the name
|
||||
* and one for the value. The only way to know they are the same
|
||||
* is to look at the range.
|
||||
*/
|
||||
if (!reportedNodes.has(node.range.toString())) {
|
||||
|
||||
Identifier(node) {
|
||||
const name = node.name,
|
||||
parent = node.parent,
|
||||
effectiveParent =
|
||||
parent.type === "MemberExpression"
|
||||
? parent.parent
|
||||
: parent;
|
||||
const messageId = (node.type === "PrivateIdentifier")
|
||||
? "notMatchPrivate" : "notMatch";
|
||||
|
||||
if (
|
||||
isReferenceToGlobalVariable(node) ||
|
||||
astUtils.isImportAttributeKey(node)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
context.report({
|
||||
node,
|
||||
messageId,
|
||||
data: {
|
||||
name: node.name,
|
||||
pattern
|
||||
}
|
||||
});
|
||||
reportedNodes.add(node.range.toString());
|
||||
}
|
||||
}
|
||||
|
||||
if (parent.type === "MemberExpression") {
|
||||
if (!checkProperties) {
|
||||
return;
|
||||
}
|
||||
return {
|
||||
|
||||
// Always check object names
|
||||
if (
|
||||
parent.object.type === "Identifier" &&
|
||||
parent.object.name === name
|
||||
) {
|
||||
if (isInvalid(name)) {
|
||||
report(node);
|
||||
}
|
||||
Program(node) {
|
||||
globalScope = sourceCode.getScope(node);
|
||||
},
|
||||
|
||||
// Report AssignmentExpressions left side's assigned variable id
|
||||
} else if (
|
||||
effectiveParent.type === "AssignmentExpression" &&
|
||||
effectiveParent.left.type === "MemberExpression" &&
|
||||
effectiveParent.left.property.name === node.name
|
||||
) {
|
||||
if (isInvalid(name)) {
|
||||
report(node);
|
||||
}
|
||||
Identifier(node) {
|
||||
const name = node.name,
|
||||
parent = node.parent,
|
||||
effectiveParent = (parent.type === "MemberExpression") ? parent.parent : parent;
|
||||
|
||||
// Report AssignmentExpressions only if they are the left side of the assignment
|
||||
} else if (
|
||||
effectiveParent.type === "AssignmentExpression" &&
|
||||
effectiveParent.right.type !== "MemberExpression"
|
||||
) {
|
||||
if (isInvalid(name)) {
|
||||
report(node);
|
||||
}
|
||||
}
|
||||
if (isReferenceToGlobalVariable(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For https://github.com/eslint/eslint/issues/15123
|
||||
} else if (
|
||||
parent.type === "Property" &&
|
||||
parent.parent.type === "ObjectExpression" &&
|
||||
parent.key === node &&
|
||||
!parent.computed
|
||||
) {
|
||||
if (checkProperties && isInvalid(name)) {
|
||||
report(node);
|
||||
}
|
||||
if (parent.type === "MemberExpression") {
|
||||
|
||||
/*
|
||||
* Properties have their own rules, and
|
||||
* AssignmentPattern nodes can be treated like Properties:
|
||||
* e.g.: const { no_camelcased = false } = bar;
|
||||
*/
|
||||
} else if (
|
||||
parent.type === "Property" ||
|
||||
parent.type === "AssignmentPattern"
|
||||
) {
|
||||
if (
|
||||
parent.parent &&
|
||||
parent.parent.type === "ObjectPattern"
|
||||
) {
|
||||
if (
|
||||
!ignoreDestructuring &&
|
||||
parent.shorthand &&
|
||||
parent.value.left &&
|
||||
isInvalid(name)
|
||||
) {
|
||||
report(node);
|
||||
}
|
||||
if (!checkProperties) {
|
||||
return;
|
||||
}
|
||||
|
||||
const assignmentKeyEqualsValue =
|
||||
parent.key.name === parent.value.name;
|
||||
// Always check object names
|
||||
if (parent.object.type === "Identifier" &&
|
||||
parent.object.name === name) {
|
||||
if (isInvalid(name)) {
|
||||
report(node);
|
||||
}
|
||||
|
||||
// prevent checking righthand side of destructured object
|
||||
if (!assignmentKeyEqualsValue && parent.key === node) {
|
||||
return;
|
||||
}
|
||||
// Report AssignmentExpressions left side's assigned variable id
|
||||
} else if (effectiveParent.type === "AssignmentExpression" &&
|
||||
effectiveParent.left.type === "MemberExpression" &&
|
||||
effectiveParent.left.property.name === node.name) {
|
||||
if (isInvalid(name)) {
|
||||
report(node);
|
||||
}
|
||||
|
||||
const valueIsInvalid =
|
||||
parent.value.name && isInvalid(name);
|
||||
// Report AssignmentExpressions only if they are the left side of the assignment
|
||||
} else if (effectiveParent.type === "AssignmentExpression" && effectiveParent.right.type !== "MemberExpression") {
|
||||
if (isInvalid(name)) {
|
||||
report(node);
|
||||
}
|
||||
}
|
||||
|
||||
// ignore destructuring if the option is set, unless a new identifier is created
|
||||
if (
|
||||
valueIsInvalid &&
|
||||
!(assignmentKeyEqualsValue && ignoreDestructuring)
|
||||
) {
|
||||
report(node);
|
||||
}
|
||||
}
|
||||
// For https://github.com/eslint/eslint/issues/15123
|
||||
} else if (
|
||||
parent.type === "Property" &&
|
||||
parent.parent.type === "ObjectExpression" &&
|
||||
parent.key === node &&
|
||||
!parent.computed
|
||||
) {
|
||||
if (checkProperties && isInvalid(name)) {
|
||||
report(node);
|
||||
}
|
||||
|
||||
// never check properties or always ignore destructuring
|
||||
if (
|
||||
(!checkProperties && !parent.computed) ||
|
||||
(ignoreDestructuring && isInsideObjectPattern(node))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Properties have their own rules, and
|
||||
* AssignmentPattern nodes can be treated like Properties:
|
||||
* e.g.: const { no_camelcased = false } = bar;
|
||||
*/
|
||||
} else if (parent.type === "Property" || parent.type === "AssignmentPattern") {
|
||||
|
||||
// don't check right hand side of AssignmentExpression to prevent duplicate warnings
|
||||
if (
|
||||
parent.right !== node &&
|
||||
shouldReport(effectiveParent, name)
|
||||
) {
|
||||
report(node);
|
||||
}
|
||||
if (parent.parent && parent.parent.type === "ObjectPattern") {
|
||||
if (!ignoreDestructuring && parent.shorthand && parent.value.left && isInvalid(name)) {
|
||||
report(node);
|
||||
}
|
||||
|
||||
// Check if it's an import specifier
|
||||
} else if (IMPORT_TYPES.has(parent.type)) {
|
||||
// Report only if the local imported identifier is invalid
|
||||
if (
|
||||
parent.local &&
|
||||
parent.local.name === node.name &&
|
||||
isInvalid(name)
|
||||
) {
|
||||
report(node);
|
||||
}
|
||||
} else if (parent.type === "PropertyDefinition") {
|
||||
if (checkClassFields && isInvalid(name)) {
|
||||
report(node);
|
||||
}
|
||||
const assignmentKeyEqualsValue = parent.key.name === parent.value.name;
|
||||
|
||||
// Report anything that is invalid that isn't a CallExpression
|
||||
} else if (shouldReport(effectiveParent, name)) {
|
||||
report(node);
|
||||
}
|
||||
},
|
||||
// prevent checking righthand side of destructured object
|
||||
if (!assignmentKeyEqualsValue && parent.key === node) {
|
||||
return;
|
||||
}
|
||||
|
||||
PrivateIdentifier(node) {
|
||||
const isClassField = node.parent.type === "PropertyDefinition";
|
||||
const valueIsInvalid = parent.value.name && isInvalid(name);
|
||||
|
||||
if (isClassField && !checkClassFields) {
|
||||
return;
|
||||
}
|
||||
// ignore destructuring if the option is set, unless a new identifier is created
|
||||
if (valueIsInvalid && !(assignmentKeyEqualsValue && ignoreDestructuring)) {
|
||||
report(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (isInvalid(node.name)) {
|
||||
report(node);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
// never check properties or always ignore destructuring
|
||||
if ((!checkProperties && !parent.computed) || (ignoreDestructuring && isInsideObjectPattern(node))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// don't check right hand side of AssignmentExpression to prevent duplicate warnings
|
||||
if (parent.right !== node && shouldReport(effectiveParent, name)) {
|
||||
report(node);
|
||||
}
|
||||
|
||||
// Check if it's an import specifier
|
||||
} else if (IMPORT_TYPES.has(parent.type)) {
|
||||
|
||||
// Report only if the local imported identifier is invalid
|
||||
if (parent.local && parent.local.name === node.name && isInvalid(name)) {
|
||||
report(node);
|
||||
}
|
||||
|
||||
} else if (parent.type === "PropertyDefinition") {
|
||||
|
||||
if (checkClassFields && isInvalid(name)) {
|
||||
report(node);
|
||||
}
|
||||
|
||||
// Report anything that is invalid that isn't a CallExpression
|
||||
} else if (shouldReport(effectiveParent, name)) {
|
||||
report(node);
|
||||
}
|
||||
},
|
||||
|
||||
"PrivateIdentifier"(node) {
|
||||
|
||||
const isClassField = node.parent.type === "PropertyDefinition";
|
||||
|
||||
if (isClassField && !checkClassFields) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isInvalid(node.name)) {
|
||||
report(node);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user