Skip to content

Commit 9d6df9c

Browse files
authored
Add support for AssignmentPattern to *-prototype-* rules (#222)
1 parent cc04f67 commit 9d6df9c

File tree

9 files changed

+98
-6
lines changed

9 files changed

+98
-6
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,10 @@ function defineNonstandardPropertiesHandler(
109109
} of extractNonstandardProperties(parent.id)) {
110110
report(reportNode, path, propertyName)
111111
}
112-
} else if (parent.type === "AssignmentExpression") {
112+
} else if (
113+
parent.type === "AssignmentExpression" ||
114+
parent.type === "AssignmentPattern"
115+
) {
113116
if (
114117
parent.right !== node ||
115118
parent.left.type !== "ObjectPattern"

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ function defineNonstandardPrototypePropertiesHandler(
7474
[[
7575
"VariableDeclarator > ObjectPattern.id > Property.properties",
7676
"AssignmentExpression > ObjectPattern.left > Property.properties",
77+
"AssignmentPattern > ObjectPattern.left > Property.properties",
7778
].join(",")](node) {
7879
const propertyName = getPropertyName(
7980
node,
@@ -86,7 +87,7 @@ function defineNonstandardPrototypePropertiesHandler(
8687
) {
8788
return
8889
}
89-
/** @type {import("estree").VariableDeclarator | import("estree").AssignmentExpression} */
90+
/** @type {import("estree").VariableDeclarator | import("estree").AssignmentExpression | import("estree").AssignmentPattern} */
9091
const assignmentNode = node.parent.parent
9192
const objectNode =
9293
assignmentNode.type === "VariableDeclarator"

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ function definePrototypeMethodHandler(context, nameMap, options) {
8989
[[
9090
"VariableDeclarator > ObjectPattern.id > Property.properties",
9191
"AssignmentExpression > ObjectPattern.left > Property.properties",
92+
"AssignmentPattern > ObjectPattern.left > Property.properties",
9293
].join(",")](node) {
9394
const propertyName = getPropertyName(
9495
node,
@@ -97,7 +98,7 @@ function definePrototypeMethodHandler(context, nameMap, options) {
9798
if (propertyName == null) {
9899
return
99100
}
100-
/** @type {import("estree").VariableDeclarator | import("estree").AssignmentExpression} */
101+
/** @type {import("estree").VariableDeclarator | import("estree").AssignmentExpression | import("estree").AssignmentPattern} */
101102
const assignmentNode = node.parent.parent
102103
const objectNode =
103104
assignmentNode.type === "VariableDeclarator"
@@ -147,6 +148,7 @@ function definePrototypeMethodHandler(context, nameMap, options) {
147148
[[
148149
"VariableDeclarator > ObjectPattern.id > Property.properties",
149150
"AssignmentExpression > ObjectPattern.left > Property.properties",
151+
"AssignmentPattern > ObjectPattern.left > Property.properties",
150152
].join(",")](node) {
151153
const propertyName = getPropertyName(
152154
node,
@@ -155,7 +157,7 @@ function definePrototypeMethodHandler(context, nameMap, options) {
155157
if (propertyName == null) {
156158
return
157159
}
158-
/** @type {import("estree").VariableDeclarator | import("estree").AssignmentExpression} */
160+
/** @type {import("estree").VariableDeclarator | import("estree").AssignmentExpression | import("estree").AssignmentPattern} */
159161
const assignmentNode = node.parent.parent
160162
const objectNode =
161163
assignmentNode.type === "VariableDeclarator"

lib/util/type-checker/object-type-checker.js

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ function buildExpressionTypeProviderImpl(context) {
7070
/** @type {Record<Expression['type']|'FunctionDeclaration', (node: Expression|FunctionDeclaration) => TypeInfo | null>} */
7171
const GET_TYPE_INFOS = {
7272
ArrayExpression: () => ({ type: "Array" }),
73-
ObjectExpression: () => ({ type: "Object" }),
73+
ObjectExpression: getObjectExpressionTypeInfo,
7474
FunctionDeclaration: getFunctionTypeInfo,
7575
ArrowFunctionExpression: getFunctionTypeInfo,
7676
FunctionExpression: getFunctionTypeInfo,
@@ -248,7 +248,10 @@ function buildExpressionTypeProviderImpl(context) {
248248
return null // unknown
249249
}
250250
typeInfos.push(typeInfo)
251-
} else if (parent.type === "AssignmentExpression") {
251+
} else if (
252+
parent.type === "AssignmentExpression" ||
253+
parent.type === "AssignmentPattern"
254+
) {
252255
if (reference.writeExpr !== parent.right) {
253256
return null // unknown
254257
}
@@ -265,6 +268,8 @@ function buildExpressionTypeProviderImpl(context) {
265268
return null // unknown
266269
}
267270
typeInfos.push(typeInfo)
271+
} else {
272+
return null // unknown
268273
}
269274
}
270275
const firstTypeInfo = typeInfos.shift()
@@ -292,6 +297,45 @@ function buildExpressionTypeProviderImpl(context) {
292297
return null
293298
}
294299

300+
/**
301+
* @param {import("estree").ObjectExpression} node
302+
* @returns {TypeInfo}
303+
*/
304+
function getObjectExpressionTypeInfo(node) {
305+
/**
306+
* @type {TypeInfo['properties']}
307+
*/
308+
let properties = null
309+
return {
310+
type: "Object",
311+
get properties() {
312+
if (properties) {
313+
return properties
314+
}
315+
316+
properties = {}
317+
for (const prop of node.properties) {
318+
if (prop.type !== "Property") {
319+
return (properties = {})
320+
}
321+
const propertyName = getPropertyName(
322+
prop,
323+
getSourceCode(context).getScope(node),
324+
)
325+
if (propertyName == null) {
326+
continue
327+
}
328+
Object.defineProperty(properties, propertyName, {
329+
get() {
330+
return getTypeInfo(prop.value)
331+
},
332+
})
333+
}
334+
return properties
335+
},
336+
}
337+
}
338+
295339
/**
296340
* @param {import("estree").BinaryOperator
297341
* | import("estree").LogicalOperator

tests/lib/rules/no-array-from.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,13 @@ new RuleTester().run("no-array-from", rule, {
1414
code: "Array.from",
1515
errors: ["ES2015 'Array.from' method is forbidden."],
1616
},
17+
{
18+
code: "const {from} = Array",
19+
errors: ["ES2015 'Array.from' method is forbidden."],
20+
},
21+
{
22+
code: "const {a:{from} = Array} = {}",
23+
errors: ["ES2015 'Array.from' method is forbidden."],
24+
},
1725
],
1826
})

tests/lib/rules/no-array-prototype-at.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ new RuleTester().run(ruleId, rule, {
5454
code: "const { at } = Array.prototype;",
5555
errors: ["ES2022 'Array.prototype.at' method is forbidden."],
5656
},
57+
{
58+
code: "const { a: {at}=[] } = {};",
59+
errors: ["ES2022 'Array.prototype.at' method is forbidden."],
60+
},
5761
],
5862
})
5963

@@ -270,5 +274,10 @@ new RuleTester({
270274
code: "const { at } = Array.prototype;",
271275
errors: ["ES2022 'Array.prototype.at' method is forbidden."],
272276
},
277+
{
278+
filename,
279+
code: "const { a: {at}=[] } = {};",
280+
errors: ["ES2022 'Array.prototype.at' method is forbidden."],
281+
},
273282
],
274283
})

tests/lib/rules/no-nonstandard-array-properties.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,9 @@ new RuleTester().run("no-nonstandard-array-properties", rule, {
3030
code: ";({ foo } = Array);",
3131
errors: ["Non-standard 'Array.foo' property is forbidden."],
3232
},
33+
{
34+
code: "const { a: {foo}=Array } = {};",
35+
errors: ["Non-standard 'Array.foo' property is forbidden."],
36+
},
3337
],
3438
})

tests/lib/rules/no-nonstandard-array-prototype-properties.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ new RuleTester().run(ruleId, rule, {
7878
"Non-standard 'Array.prototype.foo' property is forbidden.",
7979
],
8080
},
81+
{
82+
code: "const { a: {foo}=[] } = {};",
83+
errors: [
84+
"Non-standard 'Array.prototype.foo' property is forbidden.",
85+
],
86+
},
8187
],
8288
})
8389

@@ -186,5 +192,12 @@ new RuleTester({
186192
"Non-standard 'Array.prototype.foo' property is forbidden.",
187193
],
188194
},
195+
{
196+
filename,
197+
code: "const { a: {foo}=[] } = {};",
198+
errors: [
199+
"Non-standard 'Array.prototype.foo' property is forbidden.",
200+
],
201+
},
189202
],
190203
})

tests/lib/util/type-checker/object-type-checker.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,14 @@ describe("define-prototype-method-handler/object-type-checker", () => {
479479
`,
480480
result: [null],
481481
},
482+
{
483+
code: `
484+
let {a=Number.isFinite} = {a:Number.isInteger};
485+
a = Number.isNaN;
486+
target(a(foo));
487+
`,
488+
result: ["Boolean"],
489+
},
482490
]) {
483491
;(only ? it.only : it)(code, () => {
484492
deepStrictEqual(

0 commit comments

Comments
 (0)