Skip to content

Commit

Permalink
update no-import-assign
Browse files Browse the repository at this point in the history
  • Loading branch information
mysticatea committed Jun 16, 2020
1 parent 248faf1 commit b3dee67
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 29 deletions.
56 changes: 27 additions & 29 deletions lib/rules/no-import-assign.js
Expand Up @@ -9,16 +9,12 @@
// Helpers
//------------------------------------------------------------------------------

const { findVariable, getPropertyName } = require("eslint-utils");

const MutationMethods = {
Object: new Set([
"assign", "defineProperties", "defineProperty", "freeze",
"setPrototypeOf"
]),
Reflect: new Set([
"defineProperty", "deleteProperty", "set", "setPrototypeOf"
])
const { findVariable } = require("eslint-utils");
const astUtils = require("./utils/ast-utils");

const WellKnownMutationFunctions = {
Object: /^(?:assign|definePropert(?:y|ies)|freeze|setPrototypeOf)$/u,
Reflect: /^(?:(?:define|delete)Property|set(?:PrototypeOf)?)$/u
};

/**
Expand Down Expand Up @@ -92,35 +88,37 @@ function isIterationVariable(node) {
}

/**
* Check if a given node is the iteration variable of `for-in`/`for-of` syntax.
* Check if a given node is at the first argument of a well-known mutation function.
* - `Object.assign`
* - `Object.defineProperty`
* - `Object.defineProperties`
* - `Object.freeze`
* - `Object.setPrototypeOf`
* - `Refrect.defineProperty`
* - `Refrect.deleteProperty`
* - `Refrect.set`
* - `Refrect.setPrototypeOf`
* @param {ASTNode} node The node to check.
* @param {Scope} scope A `escope.Scope` object to find variable (whichever).
* @returns {boolean} `true` if the node is the iteration variable.
* @returns {boolean} `true` if the node is at the first argument of a well-known mutation function.
*/
function isArgumentOfWellKnownMutationFunction(node, scope) {
const { parent } = node;

if (parent.type !== "CallExpression" || parent.arguments[0] !== node) {
return false;
}
const callee = astUtils.skipChainExpression(parent.callee);

if (
parent.type === "CallExpression" &&
parent.arguments[0] === node &&
parent.callee.type === "MemberExpression" &&
parent.callee.object.type === "Identifier"
!astUtils.isSpecificMemberAccess(callee, "Object", WellKnownMutationFunctions.Object) &&
!astUtils.isSpecificMemberAccess(callee, "Reflect", WellKnownMutationFunctions.Reflect)
) {
const { callee } = parent;
const { object } = callee;

if (Object.keys(MutationMethods).includes(object.name)) {
const variable = findVariable(scope, object);

return (
variable !== null &&
variable.scope.type === "global" &&
MutationMethods[object.name].has(getPropertyName(callee, scope))
);
}
return false;
}
const variable = findVariable(scope, callee.object);

return false;
return variable !== null && variable.scope.type === "global";
}

/**
Expand Down
12 changes: 12 additions & 0 deletions tests/lib/rules/no-import-assign.js
Expand Up @@ -310,6 +310,18 @@ ruleTester.run("no-import-assign", rule, {
{
code: "import mod, * as mod_ns from 'mod'; mod.prop = 0; mod_ns.prop = 0",
errors: [{ messageId: "readonlyMember", data: { name: "mod_ns" }, column: 51 }]
},

// Optional chaining
{
code: "import * as mod from 'mod'; Object?.defineProperty(mod, key, d)",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "readonlyMember", data: { name: "mod" }, column: 29 }]
},
{
code: "import * as mod from 'mod'; (Object?.defineProperty)(mod, key, d)",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "readonlyMember", data: { name: "mod" }, column: 29 }]
}
]
});

0 comments on commit b3dee67

Please sign in to comment.