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:
Luiz Costa
2025-11-18 10:23:55 -03:00
parent 20129a1ac7
commit ac4f232e5e
787 changed files with 82341 additions and 121690 deletions
+226 -314
View File
@@ -12,7 +12,22 @@ const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------
const INDEX_OF_PATTERN = /^(?:i|lastI)ndexOf$/u;
const ALLOWABLE_OPERATORS = ["~", "!!", "+", "- -", "-", "*"];
const ALLOWABLE_OPERATORS = ["~", "!!", "+", "*"];
/**
* Parses and normalizes an option object.
* @param {Object} options An option object to parse.
* @returns {Object} The parsed and normalized option object.
*/
function parseOptions(options) {
return {
boolean: "boolean" in options ? options.boolean : true,
number: "number" in options ? options.number : true,
string: "string" in options ? options.string : true,
disallowTemplateShorthand: "disallowTemplateShorthand" in options ? options.disallowTemplateShorthand : false,
allow: options.allow || []
};
}
/**
* Checks whether or not a node is a double logical negating.
@@ -20,11 +35,11 @@ const ALLOWABLE_OPERATORS = ["~", "!!", "+", "- -", "-", "*"];
* @returns {boolean} Whether or not the node is a double logical negating.
*/
function isDoubleLogicalNegating(node) {
return (
node.operator === "!" &&
node.argument.type === "UnaryExpression" &&
node.argument.operator === "!"
);
return (
node.operator === "!" &&
node.argument.type === "UnaryExpression" &&
node.argument.operator === "!"
);
}
/**
@@ -33,15 +48,15 @@ function isDoubleLogicalNegating(node) {
* @returns {boolean} Whether or not the node is a binary negating of `.indexOf()` method calling.
*/
function isBinaryNegatingOfIndexOf(node) {
if (node.operator !== "~") {
return false;
}
const callNode = astUtils.skipChainExpression(node.argument);
if (node.operator !== "~") {
return false;
}
const callNode = astUtils.skipChainExpression(node.argument);
return (
callNode.type === "CallExpression" &&
astUtils.isSpecificMemberAccess(callNode.callee, null, INDEX_OF_PATTERN)
);
return (
callNode.type === "CallExpression" &&
astUtils.isSpecificMemberAccess(callNode.callee, null, INDEX_OF_PATTERN)
);
}
/**
@@ -50,11 +65,10 @@ function isBinaryNegatingOfIndexOf(node) {
* @returns {boolean} Whether or not the node is a multiplying by one.
*/
function isMultiplyByOne(node) {
return (
node.operator === "*" &&
((node.left.type === "Literal" && node.left.value === 1) ||
(node.right.type === "Literal" && node.right.value === 1))
);
return node.operator === "*" && (
node.left.type === "Literal" && node.left.value === 1 ||
node.right.type === "Literal" && node.right.value === 1
);
}
/**
@@ -66,16 +80,13 @@ function isMultiplyByOne(node) {
* @returns {boolean} Whether or not the node is a multiplying by a fraction of `1`.
*/
function isMultiplyByFractionOfOne(node, sourceCode) {
return (
node.type === "BinaryExpression" &&
node.operator === "*" &&
node.right.type === "Literal" &&
node.right.value === 1 &&
node.parent.type === "BinaryExpression" &&
node.parent.operator === "/" &&
node.parent.left === node &&
!astUtils.isParenthesised(sourceCode, node)
);
return node.type === "BinaryExpression" &&
node.operator === "*" &&
(node.right.type === "Literal" && node.right.value === 1) &&
node.parent.type === "BinaryExpression" &&
node.parent.operator === "/" &&
node.parent.left === node &&
!astUtils.isParenthesised(sourceCode, node);
}
/**
@@ -84,13 +95,14 @@ function isMultiplyByFractionOfOne(node, sourceCode) {
* @returns {boolean} true if the node is a number literal or a `Number()`, `parseInt` or `parseFloat` call
*/
function isNumeric(node) {
return (
(node.type === "Literal" && typeof node.value === "number") ||
(node.type === "CallExpression" &&
(node.callee.name === "Number" ||
node.callee.name === "parseInt" ||
node.callee.name === "parseFloat"))
);
return (
node.type === "Literal" && typeof node.value === "number" ||
node.type === "CallExpression" && (
node.callee.name === "Number" ||
node.callee.name === "parseInt" ||
node.callee.name === "parseFloat"
)
);
}
/**
@@ -101,18 +113,18 @@ function isNumeric(node) {
* @returns {ASTNode|null} The first non-numeric item in the BinaryExpression tree or null
*/
function getNonNumericOperand(node) {
const left = node.left,
right = node.right;
const left = node.left,
right = node.right;
if (right.type !== "BinaryExpression" && !isNumeric(right)) {
return right;
}
if (right.type !== "BinaryExpression" && !isNumeric(right)) {
return right;
}
if (left.type !== "BinaryExpression" && !isNumeric(left)) {
return left;
}
if (left.type !== "BinaryExpression" && !isNumeric(left)) {
return left;
}
return null;
return null;
}
/**
@@ -121,12 +133,12 @@ function getNonNumericOperand(node) {
* @returns {boolean} Whether or not the expression evaluates to a string.
*/
function isStringType(node) {
return (
astUtils.isStringLiteral(node) ||
(node.type === "CallExpression" &&
node.callee.type === "Identifier" &&
node.callee.name === "String")
);
return astUtils.isStringLiteral(node) ||
(
node.type === "CallExpression" &&
node.callee.type === "Identifier" &&
node.callee.name === "String"
);
}
/**
@@ -136,13 +148,7 @@ function isStringType(node) {
* empty string literal or not.
*/
function isEmptyString(node) {
return (
astUtils.isStringLiteral(node) &&
(node.value === "" ||
(node.type === "TemplateLiteral" &&
node.quasis.length === 1 &&
node.quasis[0].value.cooked === ""))
);
return astUtils.isStringLiteral(node) && (node.value === "" || (node.type === "TemplateLiteral" && node.quasis.length === 1 && node.quasis[0].value.cooked === ""));
}
/**
@@ -151,11 +157,10 @@ function isEmptyString(node) {
* @returns {boolean} Whether or not the node is a concatenating with an empty string.
*/
function isConcatWithEmptyString(node) {
return (
node.operator === "+" &&
((isEmptyString(node.left) && !isStringType(node.right)) ||
(isEmptyString(node.right) && !isStringType(node.left)))
);
return node.operator === "+" && (
(isEmptyString(node.left) && !isStringType(node.right)) ||
(isEmptyString(node.right) && !isStringType(node.left))
);
}
/**
@@ -164,7 +169,7 @@ function isConcatWithEmptyString(node) {
* @returns {boolean} Whether or not the node is appended with an empty string.
*/
function isAppendEmptyString(node) {
return node.operator === "+=" && isEmptyString(node.right);
return node.operator === "+=" && isEmptyString(node.right);
}
/**
@@ -173,296 +178,203 @@ function isAppendEmptyString(node) {
* @returns {ASTNode} The operand that is not an empty string from a flagged BinaryExpression.
*/
function getNonEmptyOperand(node) {
return isEmptyString(node.left) ? node.right : node.left;
return isEmptyString(node.left) ? node.right : node.left;
}
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../types').Rule.RuleModule} */
/** @type {import('../shared/types').Rule} */
module.exports = {
meta: {
hasSuggestions: true,
type: "suggestion",
meta: {
type: "suggestion",
docs: {
description: "Disallow shorthand type conversions",
recommended: false,
frozen: true,
url: "https://eslint.org/docs/latest/rules/no-implicit-coercion",
},
docs: {
description: "Disallow shorthand type conversions",
recommended: false,
url: "https://eslint.org/docs/latest/rules/no-implicit-coercion"
},
fixable: "code",
fixable: "code",
schema: [
{
type: "object",
properties: {
boolean: {
type: "boolean",
},
number: {
type: "boolean",
},
string: {
type: "boolean",
},
disallowTemplateShorthand: {
type: "boolean",
},
allow: {
type: "array",
items: {
enum: ALLOWABLE_OPERATORS,
},
uniqueItems: true,
},
},
additionalProperties: false,
},
],
schema: [{
type: "object",
properties: {
boolean: {
type: "boolean",
default: true
},
number: {
type: "boolean",
default: true
},
string: {
type: "boolean",
default: true
},
disallowTemplateShorthand: {
type: "boolean",
default: false
},
allow: {
type: "array",
items: {
enum: ALLOWABLE_OPERATORS
},
uniqueItems: true
}
},
additionalProperties: false
}],
defaultOptions: [
{
allow: [],
boolean: true,
disallowTemplateShorthand: false,
number: true,
string: true,
},
],
messages: {
useRecommendation: "use `{{recommendation}}` instead."
}
},
messages: {
implicitCoercion:
"Unexpected implicit coercion encountered. Use `{{recommendation}}` instead.",
useRecommendation: "Use `{{recommendation}}` instead.",
},
},
create(context) {
const options = parseOptions(context.options[0] || {});
const sourceCode = context.sourceCode;
create(context) {
const [options] = context.options;
const sourceCode = context.sourceCode;
/**
* Reports an error and autofixes the node
* @param {ASTNode} node An ast node to report the error on.
* @param {string} recommendation The recommended code for the issue
* @param {bool} shouldFix Whether this report should fix the node
* @returns {void}
*/
function report(node, recommendation, shouldFix) {
context.report({
node,
messageId: "useRecommendation",
data: {
recommendation
},
fix(fixer) {
if (!shouldFix) {
return null;
}
/**
* Reports an error and autofixes the node
* @param {ASTNode} node An ast node to report the error on.
* @param {string} recommendation The recommended code for the issue
* @param {bool} shouldSuggest Whether this report should offer a suggestion
* @param {bool} shouldFix Whether this report should fix the node
* @returns {void}
*/
function report(node, recommendation, shouldSuggest, shouldFix) {
/**
* Fix function
* @param {RuleFixer} fixer The fixer to fix.
* @returns {Fix} The fix object.
*/
function fix(fixer) {
const tokenBefore = sourceCode.getTokenBefore(node);
const tokenBefore = sourceCode.getTokenBefore(node);
if (
tokenBefore?.range[1] === node.range[0] &&
!astUtils.canTokensBeAdjacent(tokenBefore, recommendation)
) {
return fixer.replaceText(node, ` ${recommendation}`);
}
if (
tokenBefore &&
tokenBefore.range[1] === node.range[0] &&
!astUtils.canTokensBeAdjacent(tokenBefore, recommendation)
) {
return fixer.replaceText(node, ` ${recommendation}`);
}
return fixer.replaceText(node, recommendation);
}
});
}
return fixer.replaceText(node, recommendation);
}
return {
UnaryExpression(node) {
let operatorAllowed;
context.report({
node,
messageId: "implicitCoercion",
data: { recommendation },
fix(fixer) {
if (!shouldFix) {
return null;
}
// !!foo
operatorAllowed = options.allow.includes("!!");
if (!operatorAllowed && options.boolean && isDoubleLogicalNegating(node)) {
const recommendation = `Boolean(${sourceCode.getText(node.argument.argument)})`;
return fix(fixer);
},
suggest: [
{
messageId: "useRecommendation",
data: { recommendation },
fix(fixer) {
if (shouldFix || !shouldSuggest) {
return null;
}
report(node, recommendation, true);
}
return fix(fixer);
},
},
],
});
}
// ~foo.indexOf(bar)
operatorAllowed = options.allow.includes("~");
if (!operatorAllowed && options.boolean && isBinaryNegatingOfIndexOf(node)) {
return {
UnaryExpression(node) {
let operatorAllowed;
// `foo?.indexOf(bar) !== -1` will be true (== found) if the `foo` is nullish. So use `>= 0` in that case.
const comparison = node.argument.type === "ChainExpression" ? ">= 0" : "!== -1";
const recommendation = `${sourceCode.getText(node.argument)} ${comparison}`;
// !!foo
operatorAllowed = options.allow.includes("!!");
if (
!operatorAllowed &&
options.boolean &&
isDoubleLogicalNegating(node)
) {
const recommendation = `Boolean(${sourceCode.getText(node.argument.argument)})`;
const variable = astUtils.getVariableByName(
sourceCode.getScope(node),
"Boolean",
);
const booleanExists = variable?.identifiers.length === 0;
report(node, recommendation, false);
}
report(node, recommendation, true, booleanExists);
}
// +foo
operatorAllowed = options.allow.includes("+");
if (!operatorAllowed && options.number && node.operator === "+" && !isNumeric(node.argument)) {
const recommendation = `Number(${sourceCode.getText(node.argument)})`;
// ~foo.indexOf(bar)
operatorAllowed = options.allow.includes("~");
if (
!operatorAllowed &&
options.boolean &&
isBinaryNegatingOfIndexOf(node)
) {
// `foo?.indexOf(bar) !== -1` will be true (== found) if the `foo` is nullish. So use `>= 0` in that case.
const comparison =
node.argument.type === "ChainExpression"
? ">= 0"
: "!== -1";
const recommendation = `${sourceCode.getText(node.argument)} ${comparison}`;
report(node, recommendation, true);
}
},
report(node, recommendation, false, false);
}
// Use `:exit` to prevent double reporting
"BinaryExpression:exit"(node) {
let operatorAllowed;
// +foo
operatorAllowed = options.allow.includes("+");
if (
!operatorAllowed &&
options.number &&
node.operator === "+" &&
!isNumeric(node.argument)
) {
const recommendation = `Number(${sourceCode.getText(node.argument)})`;
// 1 * foo
operatorAllowed = options.allow.includes("*");
const nonNumericOperand = !operatorAllowed && options.number && isMultiplyByOne(node) && !isMultiplyByFractionOfOne(node, sourceCode) &&
getNonNumericOperand(node);
report(node, recommendation, true, false);
}
if (nonNumericOperand) {
const recommendation = `Number(${sourceCode.getText(nonNumericOperand)})`;
// -(-foo)
operatorAllowed = options.allow.includes("- -");
if (
!operatorAllowed &&
options.number &&
node.operator === "-" &&
node.argument.type === "UnaryExpression" &&
node.argument.operator === "-" &&
!isNumeric(node.argument.argument)
) {
const recommendation = `Number(${sourceCode.getText(node.argument.argument)})`;
report(node, recommendation, true);
}
report(node, recommendation, true, false);
}
},
// "" + foo
operatorAllowed = options.allow.includes("+");
if (!operatorAllowed && options.string && isConcatWithEmptyString(node)) {
const recommendation = `String(${sourceCode.getText(getNonEmptyOperand(node))})`;
// Use `:exit` to prevent double reporting
"BinaryExpression:exit"(node) {
let operatorAllowed;
report(node, recommendation, true);
}
},
// 1 * foo
operatorAllowed = options.allow.includes("*");
const nonNumericOperand =
!operatorAllowed &&
options.number &&
isMultiplyByOne(node) &&
!isMultiplyByFractionOfOne(node, sourceCode) &&
getNonNumericOperand(node);
AssignmentExpression(node) {
if (nonNumericOperand) {
const recommendation = `Number(${sourceCode.getText(nonNumericOperand)})`;
// foo += ""
const operatorAllowed = options.allow.includes("+");
report(node, recommendation, true, false);
}
if (!operatorAllowed && options.string && isAppendEmptyString(node)) {
const code = sourceCode.getText(getNonEmptyOperand(node));
const recommendation = `${code} = String(${code})`;
// foo - 0
operatorAllowed = options.allow.includes("-");
if (
!operatorAllowed &&
options.number &&
node.operator === "-" &&
node.right.type === "Literal" &&
node.right.value === 0 &&
!isNumeric(node.left)
) {
const recommendation = `Number(${sourceCode.getText(node.left)})`;
report(node, recommendation, true);
}
},
report(node, recommendation, true, false);
}
TemplateLiteral(node) {
if (!options.disallowTemplateShorthand) {
return;
}
// "" + foo
operatorAllowed = options.allow.includes("+");
if (
!operatorAllowed &&
options.string &&
isConcatWithEmptyString(node)
) {
const recommendation = `String(${sourceCode.getText(getNonEmptyOperand(node))})`;
// tag`${foo}`
if (node.parent.type === "TaggedTemplateExpression") {
return;
}
report(node, recommendation, true, false);
}
},
// `` or `${foo}${bar}`
if (node.expressions.length !== 1) {
return;
}
AssignmentExpression(node) {
// foo += ""
const operatorAllowed = options.allow.includes("+");
if (
!operatorAllowed &&
options.string &&
isAppendEmptyString(node)
) {
const code = sourceCode.getText(getNonEmptyOperand(node));
const recommendation = `${code} = String(${code})`;
// `prefix${foo}`
if (node.quasis[0].value.cooked !== "") {
return;
}
report(node, recommendation, true, false);
}
},
// `${foo}postfix`
if (node.quasis[1].value.cooked !== "") {
return;
}
TemplateLiteral(node) {
if (!options.disallowTemplateShorthand) {
return;
}
// if the expression is already a string, then this isn't a coercion
if (isStringType(node.expressions[0])) {
return;
}
// tag`${foo}`
if (node.parent.type === "TaggedTemplateExpression") {
return;
}
const code = sourceCode.getText(node.expressions[0]);
const recommendation = `String(${code})`;
// `` or `${foo}${bar}`
if (node.expressions.length !== 1) {
return;
}
// `prefix${foo}`
if (node.quasis[0].value.cooked !== "") {
return;
}
// `${foo}postfix`
if (node.quasis[1].value.cooked !== "") {
return;
}
// if the expression is already a string, then this isn't a coercion
if (isStringType(node.expressions[0])) {
return;
}
const code = sourceCode.getText(node.expressions[0]);
const recommendation = `String(${code})`;
report(node, recommendation, true, false);
},
};
},
report(node, recommendation, true);
}
};
}
};