Skip to content

Commit cc04f67

Browse files
authored
Add support for destructuring and prototype property to *-prototype-* rules (#221)
1 parent 05205be commit cc04f67

File tree

8 files changed

+286
-56
lines changed

8 files changed

+286
-56
lines changed

lib/util/define-nonstandard-prototype-properties-handler/index.js

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@ function defineNonstandardPrototypePropertiesHandler(
3838
const classNames = Array.isArray(classNameOrClassNames)
3939
? classNameOrClassNames
4040
: [classNameOrClassNames]
41+
42+
function report(node, className, propertyName) {
43+
context.report({
44+
node,
45+
messageId: "forbidden",
46+
data: {
47+
name: `${className}.prototype.${propertyName}`,
48+
},
49+
})
50+
}
51+
4152
return {
4253
MemberExpression(node) {
4354
const propertyName = getPropertyName(
@@ -52,16 +63,41 @@ function defineNonstandardPrototypePropertiesHandler(
5263
return
5364
}
5465
for (const className of classNames) {
55-
if (!objectTypeChecker(node, className)) {
66+
if (!objectTypeChecker(node, node.object, className)) {
67+
continue
68+
}
69+
report(node, className, propertyName)
70+
break
71+
}
72+
},
73+
/** @param {import("estree").Property} node */
74+
[[
75+
"VariableDeclarator > ObjectPattern.id > Property.properties",
76+
"AssignmentExpression > ObjectPattern.left > Property.properties",
77+
].join(",")](node) {
78+
const propertyName = getPropertyName(
79+
node,
80+
sourceCode.getScope(node),
81+
)
82+
if (
83+
propertyName == null ||
84+
options?.allowsPropertyName?.(propertyName) ||
85+
propertyNamesSet.has(propertyName)
86+
) {
87+
return
88+
}
89+
/** @type {import("estree").VariableDeclarator | import("estree").AssignmentExpression} */
90+
const assignmentNode = node.parent.parent
91+
const objectNode =
92+
assignmentNode.type === "VariableDeclarator"
93+
? assignmentNode.init
94+
: assignmentNode.right
95+
96+
for (const className of classNames) {
97+
if (!objectTypeChecker(node, objectNode, className)) {
5698
continue
5799
}
58-
context.report({
59-
node,
60-
messageId: "forbidden",
61-
data: {
62-
name: `${className}.prototype.${propertyName}`,
63-
},
64-
})
100+
report(node, className, propertyName)
65101
break
66102
}
67103
},

lib/util/define-prototype-method-handler/index.js

Lines changed: 100 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -40,70 +40,138 @@ function definePrototypeMethodHandler(context, nameMap, options) {
4040
buildObjectTypeCheckerForTS(context, aggressiveResult) ||
4141
buildObjectTypeChecker(context, aggressiveResult)
4242

43+
function report(node, className, propertyName, objectTypeResult) {
44+
context.report({
45+
node,
46+
messageId: "forbidden",
47+
data: {
48+
name: `${className}.prototype.${propertyName}`,
49+
},
50+
...((options &&
51+
options.createReport &&
52+
options.createReport({
53+
objectTypeResult,
54+
className,
55+
propertyName,
56+
node,
57+
})) ||
58+
{}),
59+
})
60+
}
61+
4362
// For performance
4463
const nameMapEntries = Object.entries(nameMap)
4564
if (nameMapEntries.length === 1) {
4665
const [[className, methodNames]] = nameMapEntries
4766
return {
67+
/** @param {MemberExpression} node */
4868
MemberExpression(node) {
4969
const propertyName = getPropertyName(
5070
node,
5171
sourceCode.getScope(node),
5272
)
73+
if (propertyName == null) {
74+
return
75+
}
5376
let objectTypeResult = undefined
5477
if (
5578
methodNames.includes(propertyName) &&
56-
(objectTypeResult = objectTypeChecker(node, className))
79+
(objectTypeResult = objectTypeChecker(
80+
node,
81+
node.object,
82+
className,
83+
))
5784
) {
58-
context.report({
85+
report(node, className, propertyName, objectTypeResult)
86+
}
87+
},
88+
/** @param {import("estree").Property} node */
89+
[[
90+
"VariableDeclarator > ObjectPattern.id > Property.properties",
91+
"AssignmentExpression > ObjectPattern.left > Property.properties",
92+
].join(",")](node) {
93+
const propertyName = getPropertyName(
94+
node,
95+
sourceCode.getScope(node),
96+
)
97+
if (propertyName == null) {
98+
return
99+
}
100+
/** @type {import("estree").VariableDeclarator | import("estree").AssignmentExpression} */
101+
const assignmentNode = node.parent.parent
102+
const objectNode =
103+
assignmentNode.type === "VariableDeclarator"
104+
? assignmentNode.init
105+
: assignmentNode.right
106+
let objectTypeResult = undefined
107+
if (
108+
methodNames.includes(propertyName) &&
109+
(objectTypeResult = objectTypeChecker(
59110
node,
60-
messageId: "forbidden",
61-
data: {
62-
name: `${className}.prototype.${propertyName}`,
63-
},
64-
...((options &&
65-
options.createReport &&
66-
options.createReport({
67-
objectTypeResult,
68-
className,
69-
propertyName,
70-
node,
71-
})) ||
72-
{}),
73-
})
111+
objectNode,
112+
className,
113+
))
114+
) {
115+
report(node, className, propertyName, objectTypeResult)
74116
}
75117
},
76118
}
77119
}
78120

79121
return {
122+
/** @param {MemberExpression} node */
80123
MemberExpression(node) {
81124
const propertyName = getPropertyName(
82125
node,
83126
sourceCode.getScope(node),
84127
)
128+
if (propertyName == null) {
129+
return
130+
}
85131
for (const [className, methodNames] of nameMapEntries) {
86132
let objectTypeResult = undefined
87133
if (
88134
methodNames.includes(propertyName) &&
89-
(objectTypeResult = objectTypeChecker(node, className))
135+
(objectTypeResult = objectTypeChecker(
136+
node,
137+
node.object,
138+
className,
139+
))
90140
) {
91-
context.report({
141+
report(node, className, propertyName, objectTypeResult)
142+
return
143+
}
144+
}
145+
},
146+
/** @param {import("estree").Property} node */
147+
[[
148+
"VariableDeclarator > ObjectPattern.id > Property.properties",
149+
"AssignmentExpression > ObjectPattern.left > Property.properties",
150+
].join(",")](node) {
151+
const propertyName = getPropertyName(
152+
node,
153+
sourceCode.getScope(node),
154+
)
155+
if (propertyName == null) {
156+
return
157+
}
158+
/** @type {import("estree").VariableDeclarator | import("estree").AssignmentExpression} */
159+
const assignmentNode = node.parent.parent
160+
const objectNode =
161+
assignmentNode.type === "VariableDeclarator"
162+
? assignmentNode.init
163+
: assignmentNode.right
164+
for (const [className, methodNames] of nameMapEntries) {
165+
let objectTypeResult = undefined
166+
if (
167+
methodNames.includes(propertyName) &&
168+
(objectTypeResult = objectTypeChecker(
92169
node,
93-
messageId: "forbidden",
94-
data: {
95-
name: `${className}.prototype.${propertyName}`,
96-
},
97-
...((options &&
98-
options.createReport &&
99-
options.createReport({
100-
objectTypeResult,
101-
className,
102-
propertyName,
103-
node,
104-
})) ||
105-
{}),
106-
})
170+
objectNode,
171+
className,
172+
))
173+
) {
174+
report(node, className, propertyName, objectTypeResult)
107175
return
108176
}
109177
}

0 commit comments

Comments
 (0)