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.
400 lines
14 KiB
JavaScript
400 lines
14 KiB
JavaScript
/**
|
|
* @fileoverview Rule to flag non-camelcased identifiers
|
|
* @author Nicholas C. Zakas
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Requirements
|
|
//------------------------------------------------------------------------------
|
|
|
|
const astUtils = require("./utils/ast-utils");
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Rule Definition
|
|
//------------------------------------------------------------------------------
|
|
|
|
/** @type {import('../shared/types').Rule} */
|
|
module.exports = {
|
|
meta: {
|
|
type: "suggestion",
|
|
|
|
docs: {
|
|
description: "Enforce camelcase naming convention",
|
|
recommended: false,
|
|
url: "https://eslint.org/docs/latest/rules/camelcase"
|
|
},
|
|
|
|
schema: [
|
|
{
|
|
type: "object",
|
|
properties: {
|
|
ignoreDestructuring: {
|
|
type: "boolean",
|
|
default: false
|
|
},
|
|
ignoreImports: {
|
|
type: "boolean",
|
|
default: false
|
|
},
|
|
ignoreGlobals: {
|
|
type: "boolean",
|
|
default: false
|
|
},
|
|
properties: {
|
|
enum: ["always", "never"]
|
|
},
|
|
allow: {
|
|
type: "array",
|
|
items: [
|
|
{
|
|
type: "string"
|
|
}
|
|
],
|
|
minItems: 0,
|
|
uniqueItems: true
|
|
}
|
|
},
|
|
additionalProperties: false
|
|
}
|
|
],
|
|
|
|
messages: {
|
|
notCamelCase: "Identifier '{{name}}' is not in camel case.",
|
|
notCamelCasePrivate: "#{{name}} is not in camel case."
|
|
}
|
|
},
|
|
|
|
create(context) {
|
|
const options = context.options[0] || {};
|
|
const properties = options.properties === "never" ? "never" : "always";
|
|
const ignoreDestructuring = options.ignoreDestructuring;
|
|
const ignoreImports = options.ignoreImports;
|
|
const ignoreGlobals = options.ignoreGlobals;
|
|
const allow = options.allow || [];
|
|
const sourceCode = context.sourceCode;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Helpers
|
|
//--------------------------------------------------------------------------
|
|
|
|
// contains reported nodes to avoid reporting twice on destructuring with shorthand notation
|
|
const reported = new Set();
|
|
|
|
/**
|
|
* Checks if a string contains an underscore and isn't all upper-case
|
|
* @param {string} name The string to check.
|
|
* @returns {boolean} if the string is underscored
|
|
* @private
|
|
*/
|
|
function isUnderscored(name) {
|
|
const nameBody = name.replace(/^_+|_+$/gu, "");
|
|
|
|
// if there's an underscore, it might be A_CONSTANT, which is okay
|
|
return nameBody.includes("_") && nameBody !== nameBody.toUpperCase();
|
|
}
|
|
|
|
/**
|
|
* Checks if a string match the ignore list
|
|
* @param {string} name The string to check.
|
|
* @returns {boolean} if the string is ignored
|
|
* @private
|
|
*/
|
|
function isAllowed(name) {
|
|
return allow.some(
|
|
entry => name === entry || name.match(new RegExp(entry, "u"))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Checks if a given name is good or not.
|
|
* @param {string} name The name to check.
|
|
* @returns {boolean} `true` if the name is good.
|
|
* @private
|
|
*/
|
|
function isGoodName(name) {
|
|
return !isUnderscored(name) || isAllowed(name);
|
|
}
|
|
|
|
/**
|
|
* Checks if a given identifier reference or member expression is an assignment
|
|
* target.
|
|
* @param {ASTNode} node The node to check.
|
|
* @returns {boolean} `true` if the node is an assignment target.
|
|
*/
|
|
function isAssignmentTarget(node) {
|
|
const parent = node.parent;
|
|
|
|
switch (parent.type) {
|
|
case "AssignmentExpression":
|
|
case "AssignmentPattern":
|
|
return parent.left === node;
|
|
|
|
case "Property":
|
|
return (
|
|
parent.parent.type === "ObjectPattern" &&
|
|
parent.value === node
|
|
);
|
|
case "ArrayPattern":
|
|
case "RestElement":
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks if a given binding identifier uses the original name as-is.
|
|
* - If it's in object destructuring or object expression, the original name is its property name.
|
|
* - If it's in import declaration, the original name is its exported name.
|
|
* @param {ASTNode} node The `Identifier` node to check.
|
|
* @returns {boolean} `true` if the identifier uses the original name as-is.
|
|
*/
|
|
function equalsToOriginalName(node) {
|
|
const localName = node.name;
|
|
const valueNode = node.parent.type === "AssignmentPattern"
|
|
? node.parent
|
|
: node;
|
|
const parent = valueNode.parent;
|
|
|
|
switch (parent.type) {
|
|
case "Property":
|
|
return (
|
|
(parent.parent.type === "ObjectPattern" || parent.parent.type === "ObjectExpression") &&
|
|
parent.value === valueNode &&
|
|
!parent.computed &&
|
|
parent.key.type === "Identifier" &&
|
|
parent.key.name === localName
|
|
);
|
|
|
|
case "ImportSpecifier":
|
|
return (
|
|
parent.local === node &&
|
|
astUtils.getModuleExportName(parent.imported) === localName
|
|
);
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reports an AST node as a rule violation.
|
|
* @param {ASTNode} node The node to report.
|
|
* @returns {void}
|
|
* @private
|
|
*/
|
|
function report(node) {
|
|
if (reported.has(node.range[0])) {
|
|
return;
|
|
}
|
|
reported.add(node.range[0]);
|
|
|
|
// Report it.
|
|
context.report({
|
|
node,
|
|
messageId: node.type === "PrivateIdentifier"
|
|
? "notCamelCasePrivate"
|
|
: "notCamelCase",
|
|
data: { name: node.name }
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Reports an identifier reference or a binding identifier.
|
|
* @param {ASTNode} node The `Identifier` node to report.
|
|
* @returns {void}
|
|
*/
|
|
function reportReferenceId(node) {
|
|
|
|
/*
|
|
* For backward compatibility, if it's in callings then ignore it.
|
|
* Not sure why it is.
|
|
*/
|
|
if (
|
|
node.parent.type === "CallExpression" ||
|
|
node.parent.type === "NewExpression"
|
|
) {
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* For backward compatibility, if it's a default value of
|
|
* destructuring/parameters then ignore it.
|
|
* Not sure why it is.
|
|
*/
|
|
if (
|
|
node.parent.type === "AssignmentPattern" &&
|
|
node.parent.right === node
|
|
) {
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* The `ignoreDestructuring` flag skips the identifiers that uses
|
|
* the property name as-is.
|
|
*/
|
|
if (ignoreDestructuring && equalsToOriginalName(node)) {
|
|
return;
|
|
}
|
|
|
|
report(node);
|
|
}
|
|
|
|
return {
|
|
|
|
// Report camelcase of global variable references ------------------
|
|
Program(node) {
|
|
const scope = sourceCode.getScope(node);
|
|
|
|
if (!ignoreGlobals) {
|
|
|
|
// Defined globals in config files or directive comments.
|
|
for (const variable of scope.variables) {
|
|
if (
|
|
variable.identifiers.length > 0 ||
|
|
isGoodName(variable.name)
|
|
) {
|
|
continue;
|
|
}
|
|
for (const reference of variable.references) {
|
|
|
|
/*
|
|
* For backward compatibility, this rule reports read-only
|
|
* references as well.
|
|
*/
|
|
reportReferenceId(reference.identifier);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Undefined globals.
|
|
for (const reference of scope.through) {
|
|
const id = reference.identifier;
|
|
|
|
if (isGoodName(id.name)) {
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* For backward compatibility, this rule reports read-only
|
|
* references as well.
|
|
*/
|
|
reportReferenceId(id);
|
|
}
|
|
},
|
|
|
|
// Report camelcase of declared variables --------------------------
|
|
[[
|
|
"VariableDeclaration",
|
|
"FunctionDeclaration",
|
|
"FunctionExpression",
|
|
"ArrowFunctionExpression",
|
|
"ClassDeclaration",
|
|
"ClassExpression",
|
|
"CatchClause"
|
|
]](node) {
|
|
for (const variable of sourceCode.getDeclaredVariables(node)) {
|
|
if (isGoodName(variable.name)) {
|
|
continue;
|
|
}
|
|
const id = variable.identifiers[0];
|
|
|
|
// Report declaration.
|
|
if (!(ignoreDestructuring && equalsToOriginalName(id))) {
|
|
report(id);
|
|
}
|
|
|
|
/*
|
|
* For backward compatibility, report references as well.
|
|
* It looks unnecessary because declarations are reported.
|
|
*/
|
|
for (const reference of variable.references) {
|
|
if (reference.init) {
|
|
continue; // Skip the write references of initializers.
|
|
}
|
|
reportReferenceId(reference.identifier);
|
|
}
|
|
}
|
|
},
|
|
|
|
// Report camelcase in properties ----------------------------------
|
|
[[
|
|
"ObjectExpression > Property[computed!=true] > Identifier.key",
|
|
"MethodDefinition[computed!=true] > Identifier.key",
|
|
"PropertyDefinition[computed!=true] > Identifier.key",
|
|
"MethodDefinition > PrivateIdentifier.key",
|
|
"PropertyDefinition > PrivateIdentifier.key"
|
|
]](node) {
|
|
if (properties === "never" || isGoodName(node.name)) {
|
|
return;
|
|
}
|
|
report(node);
|
|
},
|
|
"MemberExpression[computed!=true] > Identifier.property"(node) {
|
|
if (
|
|
properties === "never" ||
|
|
!isAssignmentTarget(node.parent) || // ← ignore read-only references.
|
|
isGoodName(node.name)
|
|
) {
|
|
return;
|
|
}
|
|
report(node);
|
|
},
|
|
|
|
// Report camelcase in import --------------------------------------
|
|
ImportDeclaration(node) {
|
|
for (const variable of sourceCode.getDeclaredVariables(node)) {
|
|
if (isGoodName(variable.name)) {
|
|
continue;
|
|
}
|
|
const id = variable.identifiers[0];
|
|
|
|
// Report declaration.
|
|
if (!(ignoreImports && equalsToOriginalName(id))) {
|
|
report(id);
|
|
}
|
|
|
|
/*
|
|
* For backward compatibility, report references as well.
|
|
* It looks unnecessary because declarations are reported.
|
|
*/
|
|
for (const reference of variable.references) {
|
|
reportReferenceId(reference.identifier);
|
|
}
|
|
}
|
|
},
|
|
|
|
// Report camelcase in re-export -----------------------------------
|
|
[[
|
|
"ExportAllDeclaration > Identifier.exported",
|
|
"ExportSpecifier > Identifier.exported"
|
|
]](node) {
|
|
if (isGoodName(node.name)) {
|
|
return;
|
|
}
|
|
report(node);
|
|
},
|
|
|
|
// Report camelcase in labels --------------------------------------
|
|
[[
|
|
"LabeledStatement > Identifier.label",
|
|
|
|
/*
|
|
* For backward compatibility, report references as well.
|
|
* It looks unnecessary because declarations are reported.
|
|
*/
|
|
"BreakStatement > Identifier.label",
|
|
"ContinueStatement > Identifier.label"
|
|
]](node) {
|
|
if (isGoodName(node.name)) {
|
|
return;
|
|
}
|
|
report(node);
|
|
}
|
|
};
|
|
}
|
|
};
|