Skip to content

Commit

Permalink
Add support for AssignmentPattern to *-prototype-* rules (#222)
Browse files Browse the repository at this point in the history
  • Loading branch information
ota-meshi authored Nov 18, 2024
1 parent cc04f67 commit 9d6df9c
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 6 deletions.
5 changes: 4 additions & 1 deletion lib/util/define-nonstandard-properties-handler/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,10 @@ function defineNonstandardPropertiesHandler(
} of extractNonstandardProperties(parent.id)) {
report(reportNode, path, propertyName)
}
} else if (parent.type === "AssignmentExpression") {
} else if (
parent.type === "AssignmentExpression" ||
parent.type === "AssignmentPattern"
) {
if (
parent.right !== node ||
parent.left.type !== "ObjectPattern"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ function defineNonstandardPrototypePropertiesHandler(
[[
"VariableDeclarator > ObjectPattern.id > Property.properties",
"AssignmentExpression > ObjectPattern.left > Property.properties",
"AssignmentPattern > ObjectPattern.left > Property.properties",
].join(",")](node) {
const propertyName = getPropertyName(
node,
Expand All @@ -86,7 +87,7 @@ function defineNonstandardPrototypePropertiesHandler(
) {
return
}
/** @type {import("estree").VariableDeclarator | import("estree").AssignmentExpression} */
/** @type {import("estree").VariableDeclarator | import("estree").AssignmentExpression | import("estree").AssignmentPattern} */
const assignmentNode = node.parent.parent
const objectNode =
assignmentNode.type === "VariableDeclarator"
Expand Down
6 changes: 4 additions & 2 deletions lib/util/define-prototype-method-handler/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ function definePrototypeMethodHandler(context, nameMap, options) {
[[
"VariableDeclarator > ObjectPattern.id > Property.properties",
"AssignmentExpression > ObjectPattern.left > Property.properties",
"AssignmentPattern > ObjectPattern.left > Property.properties",
].join(",")](node) {
const propertyName = getPropertyName(
node,
Expand All @@ -97,7 +98,7 @@ function definePrototypeMethodHandler(context, nameMap, options) {
if (propertyName == null) {
return
}
/** @type {import("estree").VariableDeclarator | import("estree").AssignmentExpression} */
/** @type {import("estree").VariableDeclarator | import("estree").AssignmentExpression | import("estree").AssignmentPattern} */
const assignmentNode = node.parent.parent
const objectNode =
assignmentNode.type === "VariableDeclarator"
Expand Down Expand Up @@ -147,6 +148,7 @@ function definePrototypeMethodHandler(context, nameMap, options) {
[[
"VariableDeclarator > ObjectPattern.id > Property.properties",
"AssignmentExpression > ObjectPattern.left > Property.properties",
"AssignmentPattern > ObjectPattern.left > Property.properties",
].join(",")](node) {
const propertyName = getPropertyName(
node,
Expand All @@ -155,7 +157,7 @@ function definePrototypeMethodHandler(context, nameMap, options) {
if (propertyName == null) {
return
}
/** @type {import("estree").VariableDeclarator | import("estree").AssignmentExpression} */
/** @type {import("estree").VariableDeclarator | import("estree").AssignmentExpression | import("estree").AssignmentPattern} */
const assignmentNode = node.parent.parent
const objectNode =
assignmentNode.type === "VariableDeclarator"
Expand Down
48 changes: 46 additions & 2 deletions lib/util/type-checker/object-type-checker.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ function buildExpressionTypeProviderImpl(context) {
/** @type {Record<Expression['type']|'FunctionDeclaration', (node: Expression|FunctionDeclaration) => TypeInfo | null>} */
const GET_TYPE_INFOS = {
ArrayExpression: () => ({ type: "Array" }),
ObjectExpression: () => ({ type: "Object" }),
ObjectExpression: getObjectExpressionTypeInfo,
FunctionDeclaration: getFunctionTypeInfo,
ArrowFunctionExpression: getFunctionTypeInfo,
FunctionExpression: getFunctionTypeInfo,
Expand Down Expand Up @@ -248,7 +248,10 @@ function buildExpressionTypeProviderImpl(context) {
return null // unknown
}
typeInfos.push(typeInfo)
} else if (parent.type === "AssignmentExpression") {
} else if (
parent.type === "AssignmentExpression" ||
parent.type === "AssignmentPattern"
) {
if (reference.writeExpr !== parent.right) {
return null // unknown
}
Expand All @@ -265,6 +268,8 @@ function buildExpressionTypeProviderImpl(context) {
return null // unknown
}
typeInfos.push(typeInfo)
} else {
return null // unknown
}
}
const firstTypeInfo = typeInfos.shift()
Expand Down Expand Up @@ -292,6 +297,45 @@ function buildExpressionTypeProviderImpl(context) {
return null
}

/**
* @param {import("estree").ObjectExpression} node
* @returns {TypeInfo}
*/
function getObjectExpressionTypeInfo(node) {
/**
* @type {TypeInfo['properties']}
*/
let properties = null
return {
type: "Object",
get properties() {
if (properties) {
return properties
}

properties = {}
for (const prop of node.properties) {
if (prop.type !== "Property") {
return (properties = {})
}
const propertyName = getPropertyName(
prop,
getSourceCode(context).getScope(node),
)
if (propertyName == null) {
continue
}
Object.defineProperty(properties, propertyName, {
get() {
return getTypeInfo(prop.value)
},
})
}
return properties
},
}
}

/**
* @param {import("estree").BinaryOperator
* | import("estree").LogicalOperator
Expand Down
8 changes: 8 additions & 0 deletions tests/lib/rules/no-array-from.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,13 @@ new RuleTester().run("no-array-from", rule, {
code: "Array.from",
errors: ["ES2015 'Array.from' method is forbidden."],
},
{
code: "const {from} = Array",
errors: ["ES2015 'Array.from' method is forbidden."],
},
{
code: "const {a:{from} = Array} = {}",
errors: ["ES2015 'Array.from' method is forbidden."],
},
],
})
9 changes: 9 additions & 0 deletions tests/lib/rules/no-array-prototype-at.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ new RuleTester().run(ruleId, rule, {
code: "const { at } = Array.prototype;",
errors: ["ES2022 'Array.prototype.at' method is forbidden."],
},
{
code: "const { a: {at}=[] } = {};",
errors: ["ES2022 'Array.prototype.at' method is forbidden."],
},
],
})

Expand Down Expand Up @@ -270,5 +274,10 @@ new RuleTester({
code: "const { at } = Array.prototype;",
errors: ["ES2022 'Array.prototype.at' method is forbidden."],
},
{
filename,
code: "const { a: {at}=[] } = {};",
errors: ["ES2022 'Array.prototype.at' method is forbidden."],
},
],
})
4 changes: 4 additions & 0 deletions tests/lib/rules/no-nonstandard-array-properties.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,9 @@ new RuleTester().run("no-nonstandard-array-properties", rule, {
code: ";({ foo } = Array);",
errors: ["Non-standard 'Array.foo' property is forbidden."],
},
{
code: "const { a: {foo}=Array } = {};",
errors: ["Non-standard 'Array.foo' property is forbidden."],
},
],
})
13 changes: 13 additions & 0 deletions tests/lib/rules/no-nonstandard-array-prototype-properties.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ new RuleTester().run(ruleId, rule, {
"Non-standard 'Array.prototype.foo' property is forbidden.",
],
},
{
code: "const { a: {foo}=[] } = {};",
errors: [
"Non-standard 'Array.prototype.foo' property is forbidden.",
],
},
],
})

Expand Down Expand Up @@ -186,5 +192,12 @@ new RuleTester({
"Non-standard 'Array.prototype.foo' property is forbidden.",
],
},
{
filename,
code: "const { a: {foo}=[] } = {};",
errors: [
"Non-standard 'Array.prototype.foo' property is forbidden.",
],
},
],
})
8 changes: 8 additions & 0 deletions tests/lib/util/type-checker/object-type-checker.js
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,14 @@ describe("define-prototype-method-handler/object-type-checker", () => {
`,
result: [null],
},
{
code: `
let {a=Number.isFinite} = {a:Number.isInteger};
a = Number.isNaN;
target(a(foo));
`,
result: ["Boolean"],
},
]) {
;(only ? it.only : it)(code, () => {
deepStrictEqual(
Expand Down

0 comments on commit 9d6df9c

Please sign in to comment.