eslint-plugin-no-excess-properties 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -1
- package/dist/object-literal.d.ts +1 -1
- package/dist/object-literal.js +86 -46
- package/dist/object-literal.js.map +1 -1
- package/package.json +1 -1
- package/src/object-literal.test.ts +97 -22
- package/src/object-literal.ts +131 -59
package/dist/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ declare const plugin: {
|
|
|
14
14
|
version: string;
|
|
15
15
|
};
|
|
16
16
|
rules: {
|
|
17
|
-
"object-literal": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noExcessProperties", [], import("./object-literal").PluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
17
|
+
"object-literal": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noExcessProperties" | "noExcessProperty", [], import("./object-literal").PluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
18
18
|
};
|
|
19
19
|
};
|
|
20
20
|
export = plugin;
|
package/dist/object-literal.d.ts
CHANGED
|
@@ -4,5 +4,5 @@ export interface PluginDocs {
|
|
|
4
4
|
recommended?: boolean;
|
|
5
5
|
requiresTypeChecking?: boolean;
|
|
6
6
|
}
|
|
7
|
-
declare const noExcessProperties: ESLintUtils.RuleModule<"noExcessProperties", [], PluginDocs, ESLintUtils.RuleListener>;
|
|
7
|
+
declare const noExcessProperties: ESLintUtils.RuleModule<"noExcessProperties" | "noExcessProperty", [], PluginDocs, ESLintUtils.RuleListener>;
|
|
8
8
|
export default noExcessProperties;
|
package/dist/object-literal.js
CHANGED
|
@@ -44,56 +44,95 @@ function isObjectLiteral(type) {
|
|
|
44
44
|
return (type.symbol !== undefined &&
|
|
45
45
|
tsutils.isSymbolFlagSet(type.symbol, typescript_1.default.SymbolFlags.ObjectLiteral));
|
|
46
46
|
}
|
|
47
|
-
function
|
|
48
|
-
let
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
47
|
+
function isChildNode(node, parentNode) {
|
|
48
|
+
let parent = node;
|
|
49
|
+
do {
|
|
50
|
+
parent = parent.parent;
|
|
51
|
+
if (parent === parentNode) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
} while (parent);
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
function splitTypes(types) {
|
|
58
|
+
const result = {
|
|
59
|
+
advancedTypes: [[], []],
|
|
60
|
+
basicTypes: [],
|
|
61
|
+
};
|
|
62
|
+
for (const type of types) {
|
|
63
|
+
const callSignatures = type.getCallSignatures();
|
|
64
|
+
if (callSignatures.length === 1) {
|
|
65
|
+
result.advancedTypes[0].push(callSignatures[0].getReturnType());
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const arrayType = type.getNumberIndexType();
|
|
69
|
+
if (arrayType && type.symbol?.name === "Array") {
|
|
70
|
+
result.advancedTypes[1].push(arrayType);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
result.basicTypes.push(type);
|
|
56
74
|
}
|
|
57
|
-
return
|
|
75
|
+
return result;
|
|
58
76
|
}
|
|
59
|
-
function
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
77
|
+
function report(properties, parentNode, context, services) {
|
|
78
|
+
const propertyNodes = properties.map((p) => p.valueDeclaration
|
|
79
|
+
? services.tsNodeToESTreeNodeMap.get(p.valueDeclaration)
|
|
80
|
+
: null);
|
|
81
|
+
if (propertyNodes.every((p) => p && isChildNode(p, parentNode))) {
|
|
82
|
+
for (let i = 0; i < properties.length; i++) {
|
|
83
|
+
context.report({
|
|
84
|
+
data: { excessPropertyName: properties[i].name },
|
|
85
|
+
messageId: "noExcessProperty",
|
|
86
|
+
node: propertyNodes[i] ?? parentNode,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (properties.length > 1) {
|
|
92
|
+
context.report({
|
|
93
|
+
data: { excessPropertyNames: properties.map((p) => p.name).join(", ") },
|
|
94
|
+
messageId: "noExcessProperties",
|
|
95
|
+
node: parentNode,
|
|
96
|
+
});
|
|
65
97
|
return;
|
|
66
98
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
99
|
+
context.report({
|
|
100
|
+
data: { excessPropertyName: properties[0].name },
|
|
101
|
+
messageId: "noExcessProperty",
|
|
102
|
+
node: parentNode,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function compareTypes(leftTypes, rightTypes, rightNode, context, services) {
|
|
106
|
+
const allLeftTypes = splitTypes(leftTypes.flatMap((t) => tsutils.unionConstituents(t)));
|
|
107
|
+
const allRightTypes = splitTypes(rightTypes.flatMap((t) => tsutils.unionConstituents(t)));
|
|
108
|
+
for (let i = 0; i < allLeftTypes.advancedTypes.length; i++) {
|
|
109
|
+
if (allLeftTypes.advancedTypes[i].length > 0 &&
|
|
110
|
+
allRightTypes.advancedTypes[i].length > 0) {
|
|
111
|
+
compareTypes(allLeftTypes.advancedTypes[i], allRightTypes.advancedTypes[i], rightNode, context, services);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (const rightType of allRightTypes.basicTypes) {
|
|
115
|
+
if (!isObjectLiteral(rightType)) {
|
|
70
116
|
continue;
|
|
71
117
|
}
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const
|
|
118
|
+
const rightProperties = rightType.getProperties();
|
|
119
|
+
let bestMatchExcessProperties = null;
|
|
120
|
+
for (const leftType of allLeftTypes.basicTypes) {
|
|
121
|
+
const leftPropertyNames = leftType.getProperties().map((p) => p.name);
|
|
122
|
+
if (leftType.getStringIndexType() !== undefined ||
|
|
123
|
+
leftType.getNumberIndexType() !== undefined) {
|
|
124
|
+
bestMatchExcessProperties = null;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
const excessProperties = rightProperties.filter((p) => !leftPropertyNames.includes(p.name));
|
|
82
128
|
if (leftPropertyNames.length > 0 &&
|
|
83
|
-
(
|
|
84
|
-
|
|
85
|
-
|
|
129
|
+
(bestMatchExcessProperties === null ||
|
|
130
|
+
excessProperties.length < bestMatchExcessProperties.length)) {
|
|
131
|
+
bestMatchExcessProperties = excessProperties;
|
|
86
132
|
}
|
|
87
133
|
}
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
-
context.report({
|
|
91
|
-
data: {
|
|
92
|
-
excessPropertyNames: bestMatchExcessPropertyNames.join(", "),
|
|
93
|
-
},
|
|
94
|
-
messageId: "noExcessProperties",
|
|
95
|
-
node: rightNode,
|
|
96
|
-
});
|
|
134
|
+
if (bestMatchExcessProperties && bestMatchExcessProperties.length > 0) {
|
|
135
|
+
report(bestMatchExcessProperties, rightNode, context, services);
|
|
97
136
|
}
|
|
98
137
|
}
|
|
99
138
|
}
|
|
@@ -105,7 +144,7 @@ const noExcessProperties = createRule({
|
|
|
105
144
|
AssignmentExpression(node) {
|
|
106
145
|
const leftType = services.getTypeAtLocation(node.left);
|
|
107
146
|
const rightType = services.getTypeAtLocation(node.right);
|
|
108
|
-
compareTypes(leftType, rightType, node.right, context);
|
|
147
|
+
compareTypes([leftType], [rightType], node.right, context, services);
|
|
109
148
|
},
|
|
110
149
|
CallExpression(node) {
|
|
111
150
|
if (node.arguments.length <= 0) {
|
|
@@ -129,7 +168,7 @@ const noExcessProperties = createRule({
|
|
|
129
168
|
paramType = arrayType;
|
|
130
169
|
}
|
|
131
170
|
}
|
|
132
|
-
compareTypes(paramType, argType, node.arguments[i], context);
|
|
171
|
+
compareTypes([paramType], [argType], node.arguments[i], context, services);
|
|
133
172
|
}
|
|
134
173
|
},
|
|
135
174
|
Property(node) {
|
|
@@ -142,7 +181,7 @@ const noExcessProperties = createRule({
|
|
|
142
181
|
if (!leftType) {
|
|
143
182
|
return;
|
|
144
183
|
}
|
|
145
|
-
compareTypes(leftType, rightType, node, context);
|
|
184
|
+
compareTypes([leftType], [rightType], node, context, services);
|
|
146
185
|
},
|
|
147
186
|
ReturnStatement(node) {
|
|
148
187
|
if (!node.argument) {
|
|
@@ -164,7 +203,7 @@ const noExcessProperties = createRule({
|
|
|
164
203
|
}
|
|
165
204
|
}
|
|
166
205
|
const argType = services.getTypeAtLocation(node.argument);
|
|
167
|
-
compareTypes(returnType, argType, node.argument, context);
|
|
206
|
+
compareTypes([returnType], [argType], node.argument, context, services);
|
|
168
207
|
},
|
|
169
208
|
VariableDeclarator(node) {
|
|
170
209
|
if (!node.id.typeAnnotation || !node.init) {
|
|
@@ -172,7 +211,7 @@ const noExcessProperties = createRule({
|
|
|
172
211
|
}
|
|
173
212
|
const leftType = services.getTypeAtLocation(node.id.typeAnnotation.typeAnnotation);
|
|
174
213
|
const rightType = services.getTypeAtLocation(node.init);
|
|
175
|
-
compareTypes(leftType, rightType, node.init, context);
|
|
214
|
+
compareTypes([leftType], [rightType], node.init, context, services);
|
|
176
215
|
},
|
|
177
216
|
};
|
|
178
217
|
},
|
|
@@ -184,6 +223,7 @@ const noExcessProperties = createRule({
|
|
|
184
223
|
requiresTypeChecking: true,
|
|
185
224
|
},
|
|
186
225
|
messages: {
|
|
226
|
+
noExcessProperty: "Excess property '{{ excessPropertyName }}' found",
|
|
187
227
|
noExcessProperties: "Excess properties '{{ excessPropertyNames }}' found",
|
|
188
228
|
},
|
|
189
229
|
schema: [],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"object-literal.js","sourceRoot":"","sources":["../src/object-literal.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"object-literal.js","sourceRoot":"","sources":["../src/object-literal.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "eslint-plugin-no-excess-properties",
|
|
3
3
|
"description": "Excess properties are not allowed on object literals",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.9",
|
|
6
6
|
"homepage": "https://bitbucket.org/unimorphic/eslint-plugin-no-excess-properties",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"eslint-plugin",
|
|
@@ -8,18 +8,19 @@ RuleTester.it = vitest.it;
|
|
|
8
8
|
RuleTester.itOnly = vitest.it.only;
|
|
9
9
|
RuleTester.describe = vitest.describe;
|
|
10
10
|
|
|
11
|
-
function createError(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
function createError(
|
|
12
|
+
props: Partial<TestCaseError<"noExcessProperties" | "noExcessProperty">> & {
|
|
13
|
+
line: number;
|
|
14
|
+
column: number;
|
|
15
|
+
endColumn: number;
|
|
16
|
+
isMulti?: boolean;
|
|
17
|
+
},
|
|
18
|
+
): TestCaseError<"noExcessProperties" | "noExcessProperty"> {
|
|
19
|
+
const { endLine, isMulti, ...otherProps } = props;
|
|
17
20
|
return {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
line: props.line,
|
|
22
|
-
messageId: "noExcessProperties",
|
|
21
|
+
...otherProps,
|
|
22
|
+
endLine: endLine ?? props.line,
|
|
23
|
+
messageId: isMulti ? "noExcessProperties" : "noExcessProperty",
|
|
23
24
|
};
|
|
24
25
|
}
|
|
25
26
|
|
|
@@ -87,7 +88,7 @@ ruleTester.run("object-literal", objectLiteral, {
|
|
|
87
88
|
code: `
|
|
88
89
|
const test: () => { prop1: number; } = () => ({ prop1: 1, prop2: 2 })
|
|
89
90
|
`,
|
|
90
|
-
errors: [createError({ column:
|
|
91
|
+
errors: [createError({ column: 67, endColumn: 75, line: 2 })],
|
|
91
92
|
},
|
|
92
93
|
{
|
|
93
94
|
code: `
|
|
@@ -127,21 +128,21 @@ ruleTester.run("object-literal", objectLiteral, {
|
|
|
127
128
|
function test(param1: { prop1: number }) {}
|
|
128
129
|
test({ prop1: 1, prop2: 2 });
|
|
129
130
|
`,
|
|
130
|
-
errors: [createError({ column:
|
|
131
|
+
errors: [createError({ column: 26, endColumn: 34, line: 3 })],
|
|
131
132
|
},
|
|
132
133
|
{
|
|
133
134
|
code: `
|
|
134
135
|
function test(param1: () => { prop1: number }) {}
|
|
135
136
|
test(() => ({ prop1: 1, prop2: 2 }));
|
|
136
137
|
`,
|
|
137
|
-
errors: [createError({ column:
|
|
138
|
+
errors: [createError({ column: 33, endColumn: 41, line: 3 })],
|
|
138
139
|
},
|
|
139
140
|
{
|
|
140
141
|
code: `
|
|
141
142
|
function test(param1: number, param2: { prop1: number } | null) {}
|
|
142
143
|
test(1, true ? { prop1: 1, prop2: 2 } : null);
|
|
143
144
|
`,
|
|
144
|
-
errors: [createError({ column:
|
|
145
|
+
errors: [createError({ column: 36, endColumn: 44, line: 3 })],
|
|
145
146
|
},
|
|
146
147
|
],
|
|
147
148
|
});
|
|
@@ -190,14 +191,14 @@ ruleTester.run("object-literal", objectLiteral, {
|
|
|
190
191
|
code: `
|
|
191
192
|
const test1: { prop1: 1 }[] = [{ prop1: 1 }].map(a => ({ ...a, prop2: 2 }))
|
|
192
193
|
`,
|
|
193
|
-
errors: [createError({ column:
|
|
194
|
+
errors: [createError({ column: 72, endColumn: 80, line: 2 })],
|
|
194
195
|
},
|
|
195
196
|
{
|
|
196
197
|
code: `
|
|
197
198
|
const test: { prop1: number; }[] = [];
|
|
198
199
|
test.push({ prop1: 1, prop: 2 })
|
|
199
200
|
`,
|
|
200
|
-
errors: [createError({ column:
|
|
201
|
+
errors: [createError({ column: 31, endColumn: 38, line: 3 })],
|
|
201
202
|
},
|
|
202
203
|
],
|
|
203
204
|
});
|
|
@@ -227,28 +228,28 @@ ruleTester.run("object-literal", objectLiteral, {
|
|
|
227
228
|
function test(param1: { prop1: number }[] | (() => void)) {}
|
|
228
229
|
test([{ prop1: 1, prop2: 2 }]);
|
|
229
230
|
`,
|
|
230
|
-
errors: [createError({ column:
|
|
231
|
+
errors: [createError({ column: 27, endColumn: 35, line: 3 })],
|
|
231
232
|
},
|
|
232
233
|
{
|
|
233
234
|
code: `
|
|
234
235
|
function test(param1: { prop1: number }[] | (() => { prop1: number })) {}
|
|
235
236
|
test(() => ({ prop1: 1, prop2: 2 }));
|
|
236
237
|
`,
|
|
237
|
-
errors: [createError({ column:
|
|
238
|
+
errors: [createError({ column: 33, endColumn: 41, line: 3 })],
|
|
238
239
|
},
|
|
239
240
|
{
|
|
240
241
|
code: `
|
|
241
242
|
function test(param1: { prop1: number } | { prop1: number, prop2: number }) {}
|
|
242
243
|
test({ prop1: 1, prop2: 2, prop3: 3 });
|
|
243
244
|
`,
|
|
244
|
-
errors: [createError({ column:
|
|
245
|
+
errors: [createError({ column: 36, endColumn: 44, line: 3 })],
|
|
245
246
|
},
|
|
246
247
|
{
|
|
247
248
|
code: `
|
|
248
249
|
function test(param1: { prop1: number } | { prop2: number }) {}
|
|
249
250
|
test({ prop1: 1, prop2: 2 });
|
|
250
251
|
`,
|
|
251
|
-
errors: [createError({ column:
|
|
252
|
+
errors: [createError({ column: 26, endColumn: 34, line: 3 })],
|
|
252
253
|
},
|
|
253
254
|
],
|
|
254
255
|
});
|
|
@@ -266,7 +267,78 @@ ruleTester.run("object-literal", objectLiteral, {
|
|
|
266
267
|
function test(param1: { prop1: number } & { prop2: number }) {}
|
|
267
268
|
test({ prop1: 1, prop2: 2, prop3: 3 });
|
|
268
269
|
`,
|
|
269
|
-
errors: [createError({ column:
|
|
270
|
+
errors: [createError({ column: 36, endColumn: 44, line: 3 })],
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
ruleTester.run("object-literal", objectLiteral, {
|
|
276
|
+
valid: [
|
|
277
|
+
`
|
|
278
|
+
function test(param1: ({ prop1: number } | { prop2: number })[]) {}
|
|
279
|
+
test([{ prop2: 2 }]);
|
|
280
|
+
`,
|
|
281
|
+
`
|
|
282
|
+
function test(param1: () => ({ prop1: number } | { prop2: number } | null)[]) {}
|
|
283
|
+
test(() => [true ? { prop2: 2 } : null]);
|
|
284
|
+
`,
|
|
285
|
+
],
|
|
286
|
+
invalid: [
|
|
287
|
+
{
|
|
288
|
+
code: `
|
|
289
|
+
function test(param1: ({ prop1: number } | { prop2: number })[]) {}
|
|
290
|
+
test([{ prop1: 1, prop2: 2 }]);
|
|
291
|
+
`,
|
|
292
|
+
errors: [createError({ column: 27, endColumn: 35, line: 3 })],
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
code: `
|
|
296
|
+
function test(param1: () => ({ prop1: number } | { prop2: number } | null)[]) {}
|
|
297
|
+
test(() => [true ? { prop1: 1, prop2: 2 } : null]);
|
|
298
|
+
`,
|
|
299
|
+
errors: [createError({ column: 40, endColumn: 48, line: 3 })],
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
ruleTester.run("object-literal", objectLiteral, {
|
|
305
|
+
valid: [],
|
|
306
|
+
invalid: [
|
|
307
|
+
{
|
|
308
|
+
code: `
|
|
309
|
+
function test(param1: { prop1: number }) {}
|
|
310
|
+
test({ prop1: 1, prop2: 2, prop3: 3 });
|
|
311
|
+
`,
|
|
312
|
+
errors: [
|
|
313
|
+
createError({
|
|
314
|
+
column: 26,
|
|
315
|
+
data: { excessPropertyName: "prop2" },
|
|
316
|
+
endColumn: 34,
|
|
317
|
+
line: 3,
|
|
318
|
+
}),
|
|
319
|
+
createError({
|
|
320
|
+
column: 36,
|
|
321
|
+
data: { excessPropertyName: "prop3" },
|
|
322
|
+
endColumn: 44,
|
|
323
|
+
line: 3,
|
|
324
|
+
}),
|
|
325
|
+
],
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
code: `
|
|
329
|
+
let test1: { prop1: number; } = { prop1: 1 };
|
|
330
|
+
const test2 = { prop1: 2, prop2: 3, prop3: 4 };
|
|
331
|
+
test1 = test2;
|
|
332
|
+
`,
|
|
333
|
+
errors: [
|
|
334
|
+
createError({
|
|
335
|
+
column: 17,
|
|
336
|
+
data: { excessPropertyNames: "prop2, prop3" },
|
|
337
|
+
endColumn: 22,
|
|
338
|
+
line: 4,
|
|
339
|
+
isMulti: true,
|
|
340
|
+
}),
|
|
341
|
+
],
|
|
270
342
|
},
|
|
271
343
|
],
|
|
272
344
|
});
|
|
@@ -291,6 +363,9 @@ ruleTester.run("object-literal", objectLiteral, {
|
|
|
291
363
|
`
|
|
292
364
|
Object.keys({ prop1: 1 })
|
|
293
365
|
`,
|
|
366
|
+
`
|
|
367
|
+
const test: { prop1: number, [property: string]: number; }[] = [{ prop2: 1 }];
|
|
368
|
+
`,
|
|
294
369
|
],
|
|
295
370
|
invalid: [],
|
|
296
371
|
});
|
package/src/object-literal.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
ASTUtils,
|
|
3
|
+
ESLintUtils,
|
|
4
|
+
ParserServicesWithTypeInformation,
|
|
5
|
+
TSESTree,
|
|
6
|
+
} from "@typescript-eslint/utils";
|
|
2
7
|
import { RuleContext } from "@typescript-eslint/utils/ts-eslint";
|
|
3
8
|
import ts from "typescript";
|
|
4
9
|
import * as tsutils from "ts-api-utils";
|
|
@@ -24,84 +29,144 @@ function isObjectLiteral(type: ts.Type): boolean {
|
|
|
24
29
|
);
|
|
25
30
|
}
|
|
26
31
|
|
|
27
|
-
function
|
|
28
|
-
let
|
|
32
|
+
function isChildNode(node: TSESTree.Node, parentNode: TSESTree.Node) {
|
|
33
|
+
let parent: TSESTree.Node | undefined = node;
|
|
34
|
+
do {
|
|
35
|
+
parent = parent.parent;
|
|
36
|
+
if (parent === parentNode) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
} while (parent);
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function splitTypes(types: ts.Type[]) {
|
|
44
|
+
const result = {
|
|
45
|
+
advancedTypes: [[], []] as ts.Type[][],
|
|
46
|
+
basicTypes: [] as ts.Type[],
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
for (const type of types) {
|
|
50
|
+
const callSignatures = type.getCallSignatures();
|
|
51
|
+
if (callSignatures.length === 1) {
|
|
52
|
+
result.advancedTypes[0].push(callSignatures[0].getReturnType());
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
29
55
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
56
|
+
const arrayType = type.getNumberIndexType();
|
|
57
|
+
if (arrayType && (type as TypeOptionalSymbol).symbol?.name === "Array") {
|
|
58
|
+
result.advancedTypes[1].push(arrayType);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
result.basicTypes.push(type);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function report(
|
|
69
|
+
properties: ts.Symbol[],
|
|
70
|
+
parentNode: TSESTree.Node,
|
|
71
|
+
context: Readonly<RuleContext<"noExcessProperties" | "noExcessProperty", []>>,
|
|
72
|
+
services: ParserServicesWithTypeInformation,
|
|
73
|
+
) {
|
|
74
|
+
const propertyNodes = properties.map((p) =>
|
|
75
|
+
p.valueDeclaration
|
|
76
|
+
? services.tsNodeToESTreeNodeMap.get(p.valueDeclaration)
|
|
77
|
+
: null,
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
if (propertyNodes.every((p) => p && isChildNode(p, parentNode))) {
|
|
81
|
+
for (let i = 0; i < properties.length; i++) {
|
|
82
|
+
context.report({
|
|
83
|
+
data: { excessPropertyName: properties[i].name },
|
|
84
|
+
messageId: "noExcessProperty",
|
|
85
|
+
node: propertyNodes[i] ?? parentNode,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return;
|
|
33
89
|
}
|
|
34
90
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
91
|
+
if (properties.length > 1) {
|
|
92
|
+
context.report({
|
|
93
|
+
data: { excessPropertyNames: properties.map((p) => p.name).join(", ") },
|
|
94
|
+
messageId: "noExcessProperties",
|
|
95
|
+
node: parentNode,
|
|
96
|
+
});
|
|
97
|
+
return;
|
|
38
98
|
}
|
|
39
99
|
|
|
40
|
-
|
|
100
|
+
context.report({
|
|
101
|
+
data: { excessPropertyName: properties[0].name },
|
|
102
|
+
messageId: "noExcessProperty",
|
|
103
|
+
node: parentNode,
|
|
104
|
+
});
|
|
41
105
|
}
|
|
42
106
|
|
|
43
107
|
function compareTypes(
|
|
44
|
-
|
|
45
|
-
|
|
108
|
+
leftTypes: ts.Type[],
|
|
109
|
+
rightTypes: ts.Type[],
|
|
46
110
|
rightNode: TSESTree.Node,
|
|
47
|
-
context: Readonly<RuleContext<"noExcessProperties", []>>,
|
|
111
|
+
context: Readonly<RuleContext<"noExcessProperties" | "noExcessProperty", []>>,
|
|
112
|
+
services: ParserServicesWithTypeInformation,
|
|
48
113
|
): void {
|
|
49
|
-
const allLeftTypes =
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
t.getStringIndexType() !== undefined ||
|
|
56
|
-
(t.getNumberIndexType() !== undefined &&
|
|
57
|
-
(t as TypeOptionalSymbol).symbol?.name !== "Array"),
|
|
58
|
-
)
|
|
59
|
-
) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
114
|
+
const allLeftTypes = splitTypes(
|
|
115
|
+
leftTypes.flatMap((t) => tsutils.unionConstituents(t)),
|
|
116
|
+
);
|
|
117
|
+
const allRightTypes = splitTypes(
|
|
118
|
+
rightTypes.flatMap((t) => tsutils.unionConstituents(t)),
|
|
119
|
+
);
|
|
62
120
|
|
|
63
|
-
for (
|
|
64
|
-
|
|
121
|
+
for (let i = 0; i < allLeftTypes.advancedTypes.length; i++) {
|
|
122
|
+
if (
|
|
123
|
+
allLeftTypes.advancedTypes[i].length > 0 &&
|
|
124
|
+
allRightTypes.advancedTypes[i].length > 0
|
|
125
|
+
) {
|
|
126
|
+
compareTypes(
|
|
127
|
+
allLeftTypes.advancedTypes[i],
|
|
128
|
+
allRightTypes.advancedTypes[i],
|
|
129
|
+
rightNode,
|
|
130
|
+
context,
|
|
131
|
+
services,
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
65
135
|
|
|
66
|
-
|
|
136
|
+
for (const rightType of allRightTypes.basicTypes) {
|
|
137
|
+
if (!isObjectLiteral(rightType)) {
|
|
67
138
|
continue;
|
|
68
139
|
}
|
|
69
140
|
|
|
70
|
-
const
|
|
71
|
-
.getProperties()
|
|
72
|
-
.map((p) => p.name);
|
|
141
|
+
const rightProperties = rightType.getProperties();
|
|
73
142
|
|
|
74
|
-
let
|
|
75
|
-
for (const leftType of allLeftTypes) {
|
|
76
|
-
const
|
|
77
|
-
const leftPropertyNames = leftResolvedType
|
|
78
|
-
.getProperties()
|
|
79
|
-
.map((p) => p.name);
|
|
143
|
+
let bestMatchExcessProperties: ts.Symbol[] | null = null;
|
|
144
|
+
for (const leftType of allLeftTypes.basicTypes) {
|
|
145
|
+
const leftPropertyNames = leftType.getProperties().map((p) => p.name);
|
|
80
146
|
|
|
81
|
-
|
|
82
|
-
(
|
|
147
|
+
if (
|
|
148
|
+
leftType.getStringIndexType() !== undefined ||
|
|
149
|
+
leftType.getNumberIndexType() !== undefined
|
|
150
|
+
) {
|
|
151
|
+
bestMatchExcessProperties = null;
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const excessProperties = rightProperties.filter(
|
|
156
|
+
(p) => !leftPropertyNames.includes(p.name),
|
|
83
157
|
);
|
|
84
158
|
|
|
85
159
|
if (
|
|
86
160
|
leftPropertyNames.length > 0 &&
|
|
87
|
-
(
|
|
88
|
-
|
|
161
|
+
(bestMatchExcessProperties === null ||
|
|
162
|
+
excessProperties.length < bestMatchExcessProperties.length)
|
|
89
163
|
) {
|
|
90
|
-
|
|
164
|
+
bestMatchExcessProperties = excessProperties;
|
|
91
165
|
}
|
|
92
166
|
}
|
|
93
167
|
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
bestMatchExcessPropertyNames.length > 0
|
|
97
|
-
) {
|
|
98
|
-
context.report({
|
|
99
|
-
data: {
|
|
100
|
-
excessPropertyNames: bestMatchExcessPropertyNames.join(", "),
|
|
101
|
-
},
|
|
102
|
-
messageId: "noExcessProperties",
|
|
103
|
-
node: rightNode,
|
|
104
|
-
});
|
|
168
|
+
if (bestMatchExcessProperties && bestMatchExcessProperties.length > 0) {
|
|
169
|
+
report(bestMatchExcessProperties, rightNode, context, services);
|
|
105
170
|
}
|
|
106
171
|
}
|
|
107
172
|
}
|
|
@@ -116,7 +181,7 @@ const noExcessProperties = createRule({
|
|
|
116
181
|
const leftType = services.getTypeAtLocation(node.left);
|
|
117
182
|
const rightType = services.getTypeAtLocation(node.right);
|
|
118
183
|
|
|
119
|
-
compareTypes(leftType, rightType, node.right, context);
|
|
184
|
+
compareTypes([leftType], [rightType], node.right, context, services);
|
|
120
185
|
},
|
|
121
186
|
CallExpression(node) {
|
|
122
187
|
if (node.arguments.length <= 0) {
|
|
@@ -152,7 +217,13 @@ const noExcessProperties = createRule({
|
|
|
152
217
|
}
|
|
153
218
|
}
|
|
154
219
|
|
|
155
|
-
compareTypes(
|
|
220
|
+
compareTypes(
|
|
221
|
+
[paramType],
|
|
222
|
+
[argType],
|
|
223
|
+
node.arguments[i],
|
|
224
|
+
context,
|
|
225
|
+
services,
|
|
226
|
+
);
|
|
156
227
|
}
|
|
157
228
|
},
|
|
158
229
|
Property(node) {
|
|
@@ -169,7 +240,7 @@ const noExcessProperties = createRule({
|
|
|
169
240
|
return;
|
|
170
241
|
}
|
|
171
242
|
|
|
172
|
-
compareTypes(leftType, rightType, node, context);
|
|
243
|
+
compareTypes([leftType], [rightType], node, context, services);
|
|
173
244
|
},
|
|
174
245
|
ReturnStatement(node) {
|
|
175
246
|
if (!node.argument) {
|
|
@@ -200,7 +271,7 @@ const noExcessProperties = createRule({
|
|
|
200
271
|
|
|
201
272
|
const argType = services.getTypeAtLocation(node.argument);
|
|
202
273
|
|
|
203
|
-
compareTypes(returnType, argType, node.argument, context);
|
|
274
|
+
compareTypes([returnType], [argType], node.argument, context, services);
|
|
204
275
|
},
|
|
205
276
|
VariableDeclarator(node) {
|
|
206
277
|
if (!node.id.typeAnnotation || !node.init) {
|
|
@@ -212,7 +283,7 @@ const noExcessProperties = createRule({
|
|
|
212
283
|
);
|
|
213
284
|
const rightType = services.getTypeAtLocation(node.init);
|
|
214
285
|
|
|
215
|
-
compareTypes(leftType, rightType, node.init, context);
|
|
286
|
+
compareTypes([leftType], [rightType], node.init, context, services);
|
|
216
287
|
},
|
|
217
288
|
};
|
|
218
289
|
},
|
|
@@ -224,6 +295,7 @@ const noExcessProperties = createRule({
|
|
|
224
295
|
requiresTypeChecking: true,
|
|
225
296
|
},
|
|
226
297
|
messages: {
|
|
298
|
+
noExcessProperty: "Excess property '{{ excessPropertyName }}' found",
|
|
227
299
|
noExcessProperties: "Excess properties '{{ excessPropertyNames }}' found",
|
|
228
300
|
},
|
|
229
301
|
schema: [],
|