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:
+190
-223
@@ -21,7 +21,7 @@ const astUtils = require("./utils/ast-utils");
|
||||
* @returns {boolean} `true` if the variable is a global variable.
|
||||
*/
|
||||
function isGlobal(variable) {
|
||||
return Boolean(variable.scope) && variable.scope.type === "global";
|
||||
return Boolean(variable.scope) && variable.scope.type === "global";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,12 +32,12 @@ function isGlobal(variable) {
|
||||
* scope.
|
||||
*/
|
||||
function getEnclosingFunctionScope(scope) {
|
||||
let currentScope = scope;
|
||||
let currentScope = scope;
|
||||
|
||||
while (currentScope.type !== "function" && currentScope.type !== "global") {
|
||||
currentScope = currentScope.upper;
|
||||
}
|
||||
return currentScope;
|
||||
while (currentScope.type !== "function" && currentScope.type !== "global") {
|
||||
currentScope = currentScope.upper;
|
||||
}
|
||||
return currentScope;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,13 +47,10 @@ function getEnclosingFunctionScope(scope) {
|
||||
* @returns {boolean} `true` if the variable is used from a closure.
|
||||
*/
|
||||
function isReferencedInClosure(variable) {
|
||||
const enclosingFunctionScope = getEnclosingFunctionScope(variable.scope);
|
||||
const enclosingFunctionScope = getEnclosingFunctionScope(variable.scope);
|
||||
|
||||
return variable.references.some(
|
||||
reference =>
|
||||
getEnclosingFunctionScope(reference.from) !==
|
||||
enclosingFunctionScope,
|
||||
);
|
||||
return variable.references.some(reference =>
|
||||
getEnclosingFunctionScope(reference.from) !== enclosingFunctionScope);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,11 +60,8 @@ function isReferencedInClosure(variable) {
|
||||
* iteration.
|
||||
*/
|
||||
function isLoopAssignee(node) {
|
||||
return (
|
||||
(node.parent.type === "ForOfStatement" ||
|
||||
node.parent.type === "ForInStatement") &&
|
||||
node === node.parent.left
|
||||
);
|
||||
return (node.parent.type === "ForOfStatement" || node.parent.type === "ForInStatement") &&
|
||||
node === node.parent.left;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,11 +70,10 @@ function isLoopAssignee(node) {
|
||||
* @returns {boolean} `true` if the declaration has an initializer.
|
||||
*/
|
||||
function isDeclarationInitialized(node) {
|
||||
return node.declarations.every(declarator => declarator.init !== null);
|
||||
return node.declarations.every(declarator => declarator.init !== null);
|
||||
}
|
||||
|
||||
const SCOPE_NODE_TYPE =
|
||||
/^(?:Program|BlockStatement|SwitchStatement|ForStatement|ForInStatement|ForOfStatement)$/u;
|
||||
const SCOPE_NODE_TYPE = /^(?:Program|BlockStatement|SwitchStatement|ForStatement|ForInStatement|ForOfStatement)$/u;
|
||||
|
||||
/**
|
||||
* Gets the scope node which directly contains a given node.
|
||||
@@ -91,18 +84,14 @@ const SCOPE_NODE_TYPE =
|
||||
* `ForOfStatement`.
|
||||
*/
|
||||
function getScopeNode(node) {
|
||||
for (
|
||||
let currentNode = node;
|
||||
currentNode;
|
||||
currentNode = currentNode.parent
|
||||
) {
|
||||
if (SCOPE_NODE_TYPE.test(currentNode.type)) {
|
||||
return currentNode;
|
||||
}
|
||||
}
|
||||
for (let currentNode = node; currentNode; currentNode = currentNode.parent) {
|
||||
if (SCOPE_NODE_TYPE.test(currentNode.type)) {
|
||||
return currentNode;
|
||||
}
|
||||
}
|
||||
|
||||
/* c8 ignore next */
|
||||
return null;
|
||||
/* c8 ignore next */
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,7 +100,7 @@ function getScopeNode(node) {
|
||||
* @returns {boolean} `true` if the variable is redeclared.
|
||||
*/
|
||||
function isRedeclared(variable) {
|
||||
return variable.defs.length >= 2;
|
||||
return variable.defs.length >= 2;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,22 +110,23 @@ function isRedeclared(variable) {
|
||||
* variable is used from outside of the specified scope.
|
||||
*/
|
||||
function isUsedFromOutsideOf(scopeNode) {
|
||||
/**
|
||||
* Checks whether a given reference is inside of the specified scope or not.
|
||||
* @param {eslint-scope.Reference} reference A reference to check.
|
||||
* @returns {boolean} `true` if the reference is inside of the specified
|
||||
* scope.
|
||||
*/
|
||||
function isOutsideOfScope(reference) {
|
||||
const scope = scopeNode.range;
|
||||
const id = reference.identifier.range;
|
||||
|
||||
return id[0] < scope[0] || id[1] > scope[1];
|
||||
}
|
||||
/**
|
||||
* Checks whether a given reference is inside of the specified scope or not.
|
||||
* @param {eslint-scope.Reference} reference A reference to check.
|
||||
* @returns {boolean} `true` if the reference is inside of the specified
|
||||
* scope.
|
||||
*/
|
||||
function isOutsideOfScope(reference) {
|
||||
const scope = scopeNode.range;
|
||||
const id = reference.identifier.range;
|
||||
|
||||
return function (variable) {
|
||||
return variable.references.some(isOutsideOfScope);
|
||||
};
|
||||
return id[0] < scope[0] || id[1] > scope[1];
|
||||
}
|
||||
|
||||
return function(variable) {
|
||||
return variable.references.some(isOutsideOfScope);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,33 +142,27 @@ function isUsedFromOutsideOf(scopeNode) {
|
||||
* @private
|
||||
*/
|
||||
function hasReferenceInTDZ(node) {
|
||||
const initStart = node.range[0];
|
||||
const initEnd = node.range[1];
|
||||
const initStart = node.range[0];
|
||||
const initEnd = node.range[1];
|
||||
|
||||
return variable => {
|
||||
const id = variable.defs[0].name;
|
||||
const idStart = id.range[0];
|
||||
const defaultValue =
|
||||
id.parent.type === "AssignmentPattern" ? id.parent.right : null;
|
||||
const defaultStart = defaultValue && defaultValue.range[0];
|
||||
const defaultEnd = defaultValue && defaultValue.range[1];
|
||||
return variable => {
|
||||
const id = variable.defs[0].name;
|
||||
const idStart = id.range[0];
|
||||
const defaultValue = (id.parent.type === "AssignmentPattern" ? id.parent.right : null);
|
||||
const defaultStart = defaultValue && defaultValue.range[0];
|
||||
const defaultEnd = defaultValue && defaultValue.range[1];
|
||||
|
||||
return variable.references.some(reference => {
|
||||
const start = reference.identifier.range[0];
|
||||
const end = reference.identifier.range[1];
|
||||
return variable.references.some(reference => {
|
||||
const start = reference.identifier.range[0];
|
||||
const end = reference.identifier.range[1];
|
||||
|
||||
return (
|
||||
!reference.init &&
|
||||
(start < idStart ||
|
||||
(defaultValue !== null &&
|
||||
start >= defaultStart &&
|
||||
end <= defaultEnd) ||
|
||||
(!astUtils.isFunction(node) &&
|
||||
start >= initStart &&
|
||||
end <= initEnd))
|
||||
);
|
||||
});
|
||||
};
|
||||
return !reference.init && (
|
||||
start < idStart ||
|
||||
(defaultValue !== null && start >= defaultStart && end <= defaultEnd) ||
|
||||
(!astUtils.isFunction(node) && start >= initStart && end <= initEnd)
|
||||
);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,180 +172,163 @@ function hasReferenceInTDZ(node) {
|
||||
* @returns {boolean} `true` if the variable has a disallowed name.
|
||||
*/
|
||||
function hasNameDisallowedForLetDeclarations(variable) {
|
||||
return variable.name === "let";
|
||||
return variable.name === "let";
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
/** @type {import('../shared/types').Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
dialects: ["typescript", "javascript"],
|
||||
language: "javascript",
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "Require `let` or `const` instead of `var`",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/no-var",
|
||||
},
|
||||
docs: {
|
||||
description: "Require `let` or `const` instead of `var`",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/no-var"
|
||||
},
|
||||
|
||||
schema: [],
|
||||
fixable: "code",
|
||||
schema: [],
|
||||
fixable: "code",
|
||||
|
||||
messages: {
|
||||
unexpectedVar: "Unexpected var, use let or const instead.",
|
||||
},
|
||||
},
|
||||
messages: {
|
||||
unexpectedVar: "Unexpected var, use let or const instead."
|
||||
}
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Checks whether the variables which are defined by the given declarator node have their references in TDZ.
|
||||
* @param {ASTNode} declarator The VariableDeclarator node to check.
|
||||
* @returns {boolean} `true` if one of the variables which are defined by the given declarator node have their references in TDZ.
|
||||
*/
|
||||
function hasSelfReferenceInTDZ(declarator) {
|
||||
if (!declarator.init) {
|
||||
return false;
|
||||
}
|
||||
const variables = sourceCode.getDeclaredVariables(declarator);
|
||||
/**
|
||||
* Checks whether the variables which are defined by the given declarator node have their references in TDZ.
|
||||
* @param {ASTNode} declarator The VariableDeclarator node to check.
|
||||
* @returns {boolean} `true` if one of the variables which are defined by the given declarator node have their references in TDZ.
|
||||
*/
|
||||
function hasSelfReferenceInTDZ(declarator) {
|
||||
if (!declarator.init) {
|
||||
return false;
|
||||
}
|
||||
const variables = sourceCode.getDeclaredVariables(declarator);
|
||||
|
||||
return variables.some(hasReferenceInTDZ(declarator.init));
|
||||
}
|
||||
return variables.some(hasReferenceInTDZ(declarator.init));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether it can fix a given variable declaration or not.
|
||||
* It cannot fix if the following cases:
|
||||
*
|
||||
* - A variable is a global variable.
|
||||
* - A variable is declared on a SwitchCase node.
|
||||
* - A variable is redeclared.
|
||||
* - A variable is used from outside the scope.
|
||||
* - A variable is used from a closure within a loop.
|
||||
* - A variable might be used before it is assigned within a loop.
|
||||
* - A variable might be used in TDZ.
|
||||
* - A variable is declared in statement position (e.g. a single-line `IfStatement`)
|
||||
* - A variable has name that is disallowed for `let` declarations.
|
||||
*
|
||||
* ## A variable is declared on a SwitchCase node.
|
||||
*
|
||||
* If this rule modifies 'var' declarations on a SwitchCase node, it
|
||||
* would generate the warnings of 'no-case-declarations' rule. And the
|
||||
* 'eslint:recommended' preset includes 'no-case-declarations' rule, so
|
||||
* this rule doesn't modify those declarations.
|
||||
*
|
||||
* ## A variable is redeclared.
|
||||
*
|
||||
* The language spec disallows redeclarations of `let` declarations.
|
||||
* Those variables would cause syntax errors.
|
||||
*
|
||||
* ## A variable is used from outside the scope.
|
||||
*
|
||||
* The language spec disallows accesses from outside of the scope for
|
||||
* `let` declarations. Those variables would cause reference errors.
|
||||
*
|
||||
* ## A variable is used from a closure within a loop.
|
||||
*
|
||||
* A `var` declaration within a loop shares the same variable instance
|
||||
* across all loop iterations, while a `let` declaration creates a new
|
||||
* instance for each iteration. This means if a variable in a loop is
|
||||
* referenced by any closure, changing it from `var` to `let` would
|
||||
* change the behavior in a way that is generally unsafe.
|
||||
*
|
||||
* ## A variable might be used before it is assigned within a loop.
|
||||
*
|
||||
* Within a loop, a `let` declaration without an initializer will be
|
||||
* initialized to null, while a `var` declaration will retain its value
|
||||
* from the previous iteration, so it is only safe to change `var` to
|
||||
* `let` if we can statically determine that the variable is always
|
||||
* assigned a value before its first access in the loop body. To keep
|
||||
* the implementation simple, we only convert `var` to `let` within
|
||||
* loops when the variable is a loop assignee or the declaration has an
|
||||
* initializer.
|
||||
* @param {ASTNode} node A variable declaration node to check.
|
||||
* @returns {boolean} `true` if it can fix the node.
|
||||
*/
|
||||
function canFix(node) {
|
||||
const variables = sourceCode.getDeclaredVariables(node);
|
||||
const scopeNode = getScopeNode(node);
|
||||
/**
|
||||
* Checks whether it can fix a given variable declaration or not.
|
||||
* It cannot fix if the following cases:
|
||||
*
|
||||
* - A variable is a global variable.
|
||||
* - A variable is declared on a SwitchCase node.
|
||||
* - A variable is redeclared.
|
||||
* - A variable is used from outside the scope.
|
||||
* - A variable is used from a closure within a loop.
|
||||
* - A variable might be used before it is assigned within a loop.
|
||||
* - A variable might be used in TDZ.
|
||||
* - A variable is declared in statement position (e.g. a single-line `IfStatement`)
|
||||
* - A variable has name that is disallowed for `let` declarations.
|
||||
*
|
||||
* ## A variable is declared on a SwitchCase node.
|
||||
*
|
||||
* If this rule modifies 'var' declarations on a SwitchCase node, it
|
||||
* would generate the warnings of 'no-case-declarations' rule. And the
|
||||
* 'eslint:recommended' preset includes 'no-case-declarations' rule, so
|
||||
* this rule doesn't modify those declarations.
|
||||
*
|
||||
* ## A variable is redeclared.
|
||||
*
|
||||
* The language spec disallows redeclarations of `let` declarations.
|
||||
* Those variables would cause syntax errors.
|
||||
*
|
||||
* ## A variable is used from outside the scope.
|
||||
*
|
||||
* The language spec disallows accesses from outside of the scope for
|
||||
* `let` declarations. Those variables would cause reference errors.
|
||||
*
|
||||
* ## A variable is used from a closure within a loop.
|
||||
*
|
||||
* A `var` declaration within a loop shares the same variable instance
|
||||
* across all loop iterations, while a `let` declaration creates a new
|
||||
* instance for each iteration. This means if a variable in a loop is
|
||||
* referenced by any closure, changing it from `var` to `let` would
|
||||
* change the behavior in a way that is generally unsafe.
|
||||
*
|
||||
* ## A variable might be used before it is assigned within a loop.
|
||||
*
|
||||
* Within a loop, a `let` declaration without an initializer will be
|
||||
* initialized to null, while a `var` declaration will retain its value
|
||||
* from the previous iteration, so it is only safe to change `var` to
|
||||
* `let` if we can statically determine that the variable is always
|
||||
* assigned a value before its first access in the loop body. To keep
|
||||
* the implementation simple, we only convert `var` to `let` within
|
||||
* loops when the variable is a loop assignee or the declaration has an
|
||||
* initializer.
|
||||
* @param {ASTNode} node A variable declaration node to check.
|
||||
* @returns {boolean} `true` if it can fix the node.
|
||||
*/
|
||||
function canFix(node) {
|
||||
const variables = sourceCode.getDeclaredVariables(node);
|
||||
const scopeNode = getScopeNode(node);
|
||||
|
||||
if (
|
||||
node.parent.type === "SwitchCase" ||
|
||||
node.declarations.some(hasSelfReferenceInTDZ) ||
|
||||
variables.some(isGlobal) ||
|
||||
variables.some(isRedeclared) ||
|
||||
variables.some(isUsedFromOutsideOf(scopeNode)) ||
|
||||
variables.some(hasNameDisallowedForLetDeclarations)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (node.parent.type === "SwitchCase" ||
|
||||
node.declarations.some(hasSelfReferenceInTDZ) ||
|
||||
variables.some(isGlobal) ||
|
||||
variables.some(isRedeclared) ||
|
||||
variables.some(isUsedFromOutsideOf(scopeNode)) ||
|
||||
variables.some(hasNameDisallowedForLetDeclarations)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (astUtils.isInLoop(node)) {
|
||||
if (variables.some(isReferencedInClosure)) {
|
||||
return false;
|
||||
}
|
||||
if (!isLoopAssignee(node) && !isDeclarationInitialized(node)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (astUtils.isInLoop(node)) {
|
||||
if (variables.some(isReferencedInClosure)) {
|
||||
return false;
|
||||
}
|
||||
if (!isLoopAssignee(node) && !isDeclarationInitialized(node)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
!isLoopAssignee(node) &&
|
||||
!(
|
||||
node.parent.type === "ForStatement" &&
|
||||
node.parent.init === node
|
||||
) &&
|
||||
!astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type)
|
||||
) {
|
||||
// If the declaration is not in a block, e.g. `if (foo) var bar = 1;`, then it can't be fixed.
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
!isLoopAssignee(node) &&
|
||||
!(node.parent.type === "ForStatement" && node.parent.init === node) &&
|
||||
!astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type)
|
||||
) {
|
||||
|
||||
return true;
|
||||
}
|
||||
// If the declaration is not in a block, e.g. `if (foo) var bar = 1;`, then it can't be fixed.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports a given variable declaration node.
|
||||
* @param {ASTNode} node A variable declaration node to report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function report(node) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "unexpectedVar",
|
||||
return true;
|
||||
}
|
||||
|
||||
fix(fixer) {
|
||||
const varToken = sourceCode.getFirstToken(node, {
|
||||
filter: t => t.value === "var",
|
||||
});
|
||||
/**
|
||||
* Reports a given variable declaration node.
|
||||
* @param {ASTNode} node A variable declaration node to report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function report(node) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "unexpectedVar",
|
||||
|
||||
return canFix(node)
|
||||
? fixer.replaceText(varToken, "let")
|
||||
: null;
|
||||
},
|
||||
});
|
||||
}
|
||||
fix(fixer) {
|
||||
const varToken = sourceCode.getFirstToken(node, { filter: t => t.value === "var" });
|
||||
|
||||
return {
|
||||
"VariableDeclaration:exit"(node) {
|
||||
if (node.kind !== "var") {
|
||||
return;
|
||||
}
|
||||
return canFix(node)
|
||||
? fixer.replaceText(varToken, "let")
|
||||
: null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
node.parent.type === "TSModuleBlock" &&
|
||||
node.parent.parent.type === "TSModuleDeclaration" &&
|
||||
node.parent.parent.global
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
report(node);
|
||||
},
|
||||
};
|
||||
},
|
||||
return {
|
||||
"VariableDeclaration:exit"(node) {
|
||||
if (node.kind === "var") {
|
||||
report(node);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user