/
no-import-assign.js
95 lines (82 loc) · 2.96 KB
/
no-import-assign.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/**
* @fileoverview Rule to flag updates of imported bindings.
* @author Toru Nagashima <https://github.com/mysticatea>
*/
"use strict";
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
/**
* Check if the identifier node is placed at to update members.
* @param {ASTNode} id The Identifier node to check.
* @returns {boolean} `true` if the member of `id` was updated.
*/
function isMemberUpdate(id) {
const parent = id.parent;
const grandparent = parent.parent;
return (
parent.type === "MemberExpression" &&
parent.object === id &&
(
(
grandparent.type === "AssignmentExpression" &&
grandparent.left === parent
) ||
(
grandparent.type === "UpdateExpression" &&
grandparent.argument === parent
) ||
(
grandparent.type === "UnaryExpression" &&
grandparent.operator === "delete" &&
grandparent.argument === parent
)
)
);
}
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
meta: {
type: "problem",
docs: {
description: "disallow assigning to imported bindings",
category: "Possible Errors",
recommended: false,
url: "https://eslint.org/docs/rules/no-import-assign"
},
schema: [],
messages: {
readonly: "'{{name}}' is read-only.",
readonlyMember: "The members of '{{name}}' are read-only."
}
},
create(context) {
return {
ImportDeclaration(node) {
for (const variable of context.getDeclaredVariables(node)) {
const shouldCheckMembers = variable.defs.some(
d => d.node.type === "ImportNamespaceSpecifier"
);
for (const reference of variable.references) {
const idNode = reference.identifier;
if (reference.isWrite()) {
context.report({
node: idNode.parent,
messageId: "readonly",
data: { name: idNode.name }
});
} else if (shouldCheckMembers && isMemberUpdate(idNode)) {
context.report({
node: idNode.parent.parent,
messageId: "readonlyMember",
data: { name: idNode.name }
});
}
}
}
}
};
}
};