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:
+248
-351
@@ -18,403 +18,300 @@ const precedence = astUtils.getPrecedence;
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
defaultOptions: [{}],
|
||||
docs: {
|
||||
description: "Disallow unnecessary boolean casts",
|
||||
recommended: true,
|
||||
url: "https://eslint.org/docs/latest/rules/no-extra-boolean-cast"
|
||||
},
|
||||
|
||||
docs: {
|
||||
description: "Disallow unnecessary boolean casts",
|
||||
recommended: true,
|
||||
frozen: true,
|
||||
url: "https://eslint.org/docs/latest/rules/no-extra-boolean-cast",
|
||||
},
|
||||
schema: [{
|
||||
type: "object",
|
||||
properties: {
|
||||
enforceForLogicalOperands: {
|
||||
type: "boolean",
|
||||
default: false
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}],
|
||||
fixable: "code",
|
||||
|
||||
schema: [
|
||||
{
|
||||
anyOf: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
enforceForInnerExpressions: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
messages: {
|
||||
unexpectedCall: "Redundant Boolean call.",
|
||||
unexpectedNegation: "Redundant double negation."
|
||||
}
|
||||
},
|
||||
|
||||
// deprecated
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
enforceForLogicalOperands: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
fixable: "code",
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
messages: {
|
||||
unexpectedCall: "Redundant Boolean call.",
|
||||
unexpectedNegation: "Redundant double negation.",
|
||||
},
|
||||
},
|
||||
// Node types which have a test which will coerce values to booleans.
|
||||
const BOOLEAN_NODE_TYPES = new Set([
|
||||
"IfStatement",
|
||||
"DoWhileStatement",
|
||||
"WhileStatement",
|
||||
"ConditionalExpression",
|
||||
"ForStatement"
|
||||
]);
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
const [{ enforceForLogicalOperands, enforceForInnerExpressions }] =
|
||||
context.options;
|
||||
/**
|
||||
* Check if a node is a Boolean function or constructor.
|
||||
* @param {ASTNode} node the node
|
||||
* @returns {boolean} If the node is Boolean function or constructor
|
||||
*/
|
||||
function isBooleanFunctionOrConstructorCall(node) {
|
||||
|
||||
// Node types which have a test which will coerce values to booleans.
|
||||
const BOOLEAN_NODE_TYPES = new Set([
|
||||
"IfStatement",
|
||||
"DoWhileStatement",
|
||||
"WhileStatement",
|
||||
"ConditionalExpression",
|
||||
"ForStatement",
|
||||
]);
|
||||
// Boolean(<bool>) and new Boolean(<bool>)
|
||||
return (node.type === "CallExpression" || node.type === "NewExpression") &&
|
||||
node.callee.type === "Identifier" &&
|
||||
node.callee.name === "Boolean";
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a node is a Boolean function or constructor.
|
||||
* @param {ASTNode} node the node
|
||||
* @returns {boolean} If the node is Boolean function or constructor
|
||||
*/
|
||||
function isBooleanFunctionOrConstructorCall(node) {
|
||||
// Boolean(<bool>) and new Boolean(<bool>)
|
||||
return (
|
||||
(node.type === "CallExpression" ||
|
||||
node.type === "NewExpression") &&
|
||||
node.callee.type === "Identifier" &&
|
||||
node.callee.name === "Boolean"
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Checks whether the node is a logical expression and that the option is enabled
|
||||
* @param {ASTNode} node the node
|
||||
* @returns {boolean} if the node is a logical expression and option is enabled
|
||||
*/
|
||||
function isLogicalContext(node) {
|
||||
return node.type === "LogicalExpression" &&
|
||||
(node.operator === "||" || node.operator === "&&") &&
|
||||
(context.options.length && context.options[0].enforceForLogicalOperands === true);
|
||||
|
||||
/**
|
||||
* Check if a node is in a context where its value would be coerced to a boolean at runtime.
|
||||
* @param {ASTNode} node The node
|
||||
* @returns {boolean} If it is in a boolean context
|
||||
*/
|
||||
function isInBooleanContext(node) {
|
||||
return (
|
||||
(isBooleanFunctionOrConstructorCall(node.parent) &&
|
||||
node === node.parent.arguments[0]) ||
|
||||
(BOOLEAN_NODE_TYPES.has(node.parent.type) &&
|
||||
node === node.parent.test) ||
|
||||
// !<bool>
|
||||
(node.parent.type === "UnaryExpression" &&
|
||||
node.parent.operator === "!")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the node is a context that should report an error
|
||||
* Acts recursively if it is in a logical context
|
||||
* @param {ASTNode} node the node
|
||||
* @returns {boolean} If the node is in one of the flagged contexts
|
||||
*/
|
||||
function isInFlaggedContext(node) {
|
||||
if (node.parent.type === "ChainExpression") {
|
||||
return isInFlaggedContext(node.parent);
|
||||
}
|
||||
|
||||
/*
|
||||
* legacy behavior - enforceForLogicalOperands will only recurse on
|
||||
* logical expressions, not on other contexts.
|
||||
* enforceForInnerExpressions will recurse on logical expressions
|
||||
* as well as the other recursive syntaxes.
|
||||
*/
|
||||
/**
|
||||
* Check if a node is in a context where its value would be coerced to a boolean at runtime.
|
||||
* @param {ASTNode} node The node
|
||||
* @returns {boolean} If it is in a boolean context
|
||||
*/
|
||||
function isInBooleanContext(node) {
|
||||
return (
|
||||
(isBooleanFunctionOrConstructorCall(node.parent) &&
|
||||
node === node.parent.arguments[0]) ||
|
||||
|
||||
if (enforceForLogicalOperands || enforceForInnerExpressions) {
|
||||
if (node.parent.type === "LogicalExpression") {
|
||||
if (
|
||||
node.parent.operator === "||" ||
|
||||
node.parent.operator === "&&"
|
||||
) {
|
||||
return isInFlaggedContext(node.parent);
|
||||
}
|
||||
(BOOLEAN_NODE_TYPES.has(node.parent.type) &&
|
||||
node === node.parent.test) ||
|
||||
|
||||
// Check the right hand side of a `??` operator.
|
||||
if (
|
||||
enforceForInnerExpressions &&
|
||||
node.parent.operator === "??" &&
|
||||
node.parent.right === node
|
||||
) {
|
||||
return isInFlaggedContext(node.parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
// !<bool>
|
||||
(node.parent.type === "UnaryExpression" &&
|
||||
node.parent.operator === "!")
|
||||
);
|
||||
}
|
||||
|
||||
if (enforceForInnerExpressions) {
|
||||
if (
|
||||
node.parent.type === "ConditionalExpression" &&
|
||||
(node.parent.consequent === node ||
|
||||
node.parent.alternate === node)
|
||||
) {
|
||||
return isInFlaggedContext(node.parent);
|
||||
}
|
||||
/**
|
||||
* Checks whether the node is a context that should report an error
|
||||
* Acts recursively if it is in a logical context
|
||||
* @param {ASTNode} node the node
|
||||
* @returns {boolean} If the node is in one of the flagged contexts
|
||||
*/
|
||||
function isInFlaggedContext(node) {
|
||||
if (node.parent.type === "ChainExpression") {
|
||||
return isInFlaggedContext(node.parent);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check last expression only in a sequence, i.e. if ((1, 2, Boolean(3))) {}, since
|
||||
* the others don't affect the result of the expression.
|
||||
*/
|
||||
if (
|
||||
node.parent.type === "SequenceExpression" &&
|
||||
node.parent.expressions.at(-1) === node
|
||||
) {
|
||||
return isInFlaggedContext(node.parent);
|
||||
}
|
||||
}
|
||||
return isInBooleanContext(node) ||
|
||||
(isLogicalContext(node.parent) &&
|
||||
|
||||
return isInBooleanContext(node);
|
||||
}
|
||||
// For nested logical statements
|
||||
isInFlaggedContext(node.parent)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a node has comments inside.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {boolean} `true` if it has comments inside.
|
||||
*/
|
||||
function hasCommentsInside(node) {
|
||||
return Boolean(sourceCode.getCommentsInside(node).length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given node is wrapped in grouping parentheses. Parentheses for constructs such as if() don't count.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {boolean} `true` if the node is parenthesized.
|
||||
* @private
|
||||
*/
|
||||
function isParenthesized(node) {
|
||||
return eslintUtils.isParenthesized(1, node, sourceCode);
|
||||
}
|
||||
/**
|
||||
* Check if a node has comments inside.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {boolean} `true` if it has comments inside.
|
||||
*/
|
||||
function hasCommentsInside(node) {
|
||||
return Boolean(sourceCode.getCommentsInside(node).length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given node needs to be parenthesized when replacing the previous node.
|
||||
* It assumes that `previousNode` is the node to be reported by this rule, so it has a limited list
|
||||
* of possible parent node types. By the same assumption, the node's role in a particular parent is already known.
|
||||
* @param {ASTNode} previousNode Previous node.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @throws {Error} (Unreachable.)
|
||||
* @returns {boolean} `true` if the node needs to be parenthesized.
|
||||
*/
|
||||
function needsParens(previousNode, node) {
|
||||
if (previousNode.parent.type === "ChainExpression") {
|
||||
return needsParens(previousNode.parent, node);
|
||||
}
|
||||
/**
|
||||
* Checks if the given node is wrapped in grouping parentheses. Parentheses for constructs such as if() don't count.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {boolean} `true` if the node is parenthesized.
|
||||
* @private
|
||||
*/
|
||||
function isParenthesized(node) {
|
||||
return eslintUtils.isParenthesized(1, node, sourceCode);
|
||||
}
|
||||
|
||||
if (isParenthesized(previousNode)) {
|
||||
// parentheses around the previous node will stay, so there is no need for an additional pair
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Determines whether the given node needs to be parenthesized when replacing the previous node.
|
||||
* It assumes that `previousNode` is the node to be reported by this rule, so it has a limited list
|
||||
* of possible parent node types. By the same assumption, the node's role in a particular parent is already known.
|
||||
* For example, if the parent is `ConditionalExpression`, `previousNode` must be its `test` child.
|
||||
* @param {ASTNode} previousNode Previous node.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @throws {Error} (Unreachable.)
|
||||
* @returns {boolean} `true` if the node needs to be parenthesized.
|
||||
*/
|
||||
function needsParens(previousNode, node) {
|
||||
if (previousNode.parent.type === "ChainExpression") {
|
||||
return needsParens(previousNode.parent, node);
|
||||
}
|
||||
if (isParenthesized(previousNode)) {
|
||||
|
||||
// parent of the previous node will become parent of the replacement node
|
||||
const parent = previousNode.parent;
|
||||
// parentheses around the previous node will stay, so there is no need for an additional pair
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (parent.type) {
|
||||
case "CallExpression":
|
||||
case "NewExpression":
|
||||
return node.type === "SequenceExpression";
|
||||
case "IfStatement":
|
||||
case "DoWhileStatement":
|
||||
case "WhileStatement":
|
||||
case "ForStatement":
|
||||
case "SequenceExpression":
|
||||
return false;
|
||||
case "ConditionalExpression":
|
||||
if (previousNode === parent.test) {
|
||||
return precedence(node) <= precedence(parent);
|
||||
}
|
||||
if (
|
||||
previousNode === parent.consequent ||
|
||||
previousNode === parent.alternate
|
||||
) {
|
||||
return (
|
||||
precedence(node) <
|
||||
precedence({ type: "AssignmentExpression" })
|
||||
);
|
||||
}
|
||||
// parent of the previous node will become parent of the replacement node
|
||||
const parent = previousNode.parent;
|
||||
|
||||
/* c8 ignore next */
|
||||
throw new Error(
|
||||
"Ternary child must be test, consequent, or alternate.",
|
||||
);
|
||||
case "UnaryExpression":
|
||||
return precedence(node) < precedence(parent);
|
||||
case "LogicalExpression":
|
||||
if (
|
||||
astUtils.isMixedLogicalAndCoalesceExpressions(
|
||||
node,
|
||||
parent,
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (previousNode === parent.left) {
|
||||
return precedence(node) < precedence(parent);
|
||||
}
|
||||
return precedence(node) <= precedence(parent);
|
||||
switch (parent.type) {
|
||||
case "CallExpression":
|
||||
case "NewExpression":
|
||||
return node.type === "SequenceExpression";
|
||||
case "IfStatement":
|
||||
case "DoWhileStatement":
|
||||
case "WhileStatement":
|
||||
case "ForStatement":
|
||||
return false;
|
||||
case "ConditionalExpression":
|
||||
return precedence(node) <= precedence(parent);
|
||||
case "UnaryExpression":
|
||||
return precedence(node) < precedence(parent);
|
||||
case "LogicalExpression":
|
||||
if (astUtils.isMixedLogicalAndCoalesceExpressions(node, parent)) {
|
||||
return true;
|
||||
}
|
||||
if (previousNode === parent.left) {
|
||||
return precedence(node) < precedence(parent);
|
||||
}
|
||||
return precedence(node) <= precedence(parent);
|
||||
|
||||
/* c8 ignore next */
|
||||
default:
|
||||
throw new Error(`Unexpected parent type: ${parent.type}`);
|
||||
}
|
||||
}
|
||||
/* c8 ignore next */
|
||||
default:
|
||||
throw new Error(`Unexpected parent type: ${parent.type}`);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
UnaryExpression(node) {
|
||||
const parent = node.parent;
|
||||
return {
|
||||
UnaryExpression(node) {
|
||||
const parent = node.parent;
|
||||
|
||||
// Exit early if it's guaranteed not to match
|
||||
if (
|
||||
node.operator !== "!" ||
|
||||
parent.type !== "UnaryExpression" ||
|
||||
parent.operator !== "!"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isInFlaggedContext(parent)) {
|
||||
context.report({
|
||||
node: parent,
|
||||
messageId: "unexpectedNegation",
|
||||
fix(fixer) {
|
||||
if (hasCommentsInside(parent)) {
|
||||
return null;
|
||||
}
|
||||
// Exit early if it's guaranteed not to match
|
||||
if (node.operator !== "!" ||
|
||||
parent.type !== "UnaryExpression" ||
|
||||
parent.operator !== "!") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (needsParens(parent, node.argument)) {
|
||||
return fixer.replaceText(
|
||||
parent,
|
||||
`(${sourceCode.getText(node.argument)})`,
|
||||
);
|
||||
}
|
||||
|
||||
let prefix = "";
|
||||
const tokenBefore =
|
||||
sourceCode.getTokenBefore(parent);
|
||||
const firstReplacementToken =
|
||||
sourceCode.getFirstToken(node.argument);
|
||||
if (isInFlaggedContext(parent)) {
|
||||
context.report({
|
||||
node: parent,
|
||||
messageId: "unexpectedNegation",
|
||||
fix(fixer) {
|
||||
if (hasCommentsInside(parent)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (
|
||||
tokenBefore &&
|
||||
tokenBefore.range[1] === parent.range[0] &&
|
||||
!astUtils.canTokensBeAdjacent(
|
||||
tokenBefore,
|
||||
firstReplacementToken,
|
||||
)
|
||||
) {
|
||||
prefix = " ";
|
||||
}
|
||||
if (needsParens(parent, node.argument)) {
|
||||
return fixer.replaceText(parent, `(${sourceCode.getText(node.argument)})`);
|
||||
}
|
||||
|
||||
return fixer.replaceText(
|
||||
parent,
|
||||
prefix + sourceCode.getText(node.argument),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
let prefix = "";
|
||||
const tokenBefore = sourceCode.getTokenBefore(parent);
|
||||
const firstReplacementToken = sourceCode.getFirstToken(node.argument);
|
||||
|
||||
CallExpression(node) {
|
||||
if (
|
||||
node.callee.type !== "Identifier" ||
|
||||
node.callee.name !== "Boolean"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
tokenBefore &&
|
||||
tokenBefore.range[1] === parent.range[0] &&
|
||||
!astUtils.canTokensBeAdjacent(tokenBefore, firstReplacementToken)
|
||||
) {
|
||||
prefix = " ";
|
||||
}
|
||||
|
||||
if (isInFlaggedContext(node)) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "unexpectedCall",
|
||||
fix(fixer) {
|
||||
const parent = node.parent;
|
||||
return fixer.replaceText(parent, prefix + sourceCode.getText(node.argument));
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
if (node.arguments.length === 0) {
|
||||
if (
|
||||
parent.type === "UnaryExpression" &&
|
||||
parent.operator === "!"
|
||||
) {
|
||||
/*
|
||||
* !Boolean() -> true
|
||||
*/
|
||||
CallExpression(node) {
|
||||
if (node.callee.type !== "Identifier" || node.callee.name !== "Boolean") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasCommentsInside(parent)) {
|
||||
return null;
|
||||
}
|
||||
if (isInFlaggedContext(node)) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "unexpectedCall",
|
||||
fix(fixer) {
|
||||
const parent = node.parent;
|
||||
|
||||
const replacement = "true";
|
||||
let prefix = "";
|
||||
const tokenBefore =
|
||||
sourceCode.getTokenBefore(parent);
|
||||
if (node.arguments.length === 0) {
|
||||
if (parent.type === "UnaryExpression" && parent.operator === "!") {
|
||||
|
||||
if (
|
||||
tokenBefore &&
|
||||
tokenBefore.range[1] ===
|
||||
parent.range[0] &&
|
||||
!astUtils.canTokensBeAdjacent(
|
||||
tokenBefore,
|
||||
replacement,
|
||||
)
|
||||
) {
|
||||
prefix = " ";
|
||||
}
|
||||
/*
|
||||
* !Boolean() -> true
|
||||
*/
|
||||
|
||||
return fixer.replaceText(
|
||||
parent,
|
||||
prefix + replacement,
|
||||
);
|
||||
}
|
||||
if (hasCommentsInside(parent)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Boolean() -> false
|
||||
*/
|
||||
const replacement = "true";
|
||||
let prefix = "";
|
||||
const tokenBefore = sourceCode.getTokenBefore(parent);
|
||||
|
||||
if (hasCommentsInside(node)) {
|
||||
return null;
|
||||
}
|
||||
if (
|
||||
tokenBefore &&
|
||||
tokenBefore.range[1] === parent.range[0] &&
|
||||
!astUtils.canTokensBeAdjacent(tokenBefore, replacement)
|
||||
) {
|
||||
prefix = " ";
|
||||
}
|
||||
|
||||
return fixer.replaceText(node, "false");
|
||||
}
|
||||
return fixer.replaceText(parent, prefix + replacement);
|
||||
}
|
||||
|
||||
if (node.arguments.length === 1) {
|
||||
const argument = node.arguments[0];
|
||||
/*
|
||||
* Boolean() -> false
|
||||
*/
|
||||
|
||||
if (
|
||||
argument.type === "SpreadElement" ||
|
||||
hasCommentsInside(node)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
if (hasCommentsInside(node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Boolean(expression) -> expression
|
||||
*/
|
||||
return fixer.replaceText(node, "false");
|
||||
}
|
||||
|
||||
if (needsParens(node, argument)) {
|
||||
return fixer.replaceText(
|
||||
node,
|
||||
`(${sourceCode.getText(argument)})`,
|
||||
);
|
||||
}
|
||||
if (node.arguments.length === 1) {
|
||||
const argument = node.arguments[0];
|
||||
|
||||
return fixer.replaceText(
|
||||
node,
|
||||
sourceCode.getText(argument),
|
||||
);
|
||||
}
|
||||
if (argument.type === "SpreadElement" || hasCommentsInside(node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// two or more arguments
|
||||
return null;
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
/*
|
||||
* Boolean(expression) -> expression
|
||||
*/
|
||||
|
||||
if (needsParens(node, argument)) {
|
||||
return fixer.replaceText(node, `(${sourceCode.getText(argument)})`);
|
||||
}
|
||||
|
||||
return fixer.replaceText(node, sourceCode.getText(argument));
|
||||
}
|
||||
|
||||
// two or more arguments
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user