eslint-config-typed 3.7.1 → 3.8.0
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/plugins/ts-restrictions/rules/check-destructuring-completeness.d.mts +11 -0
- package/dist/plugins/ts-restrictions/rules/check-destructuring-completeness.d.mts.map +1 -0
- package/dist/plugins/ts-restrictions/rules/check-destructuring-completeness.mjs +217 -0
- package/dist/plugins/ts-restrictions/rules/check-destructuring-completeness.mjs.map +1 -0
- package/dist/plugins/ts-restrictions/rules/rules.d.mts +4 -0
- package/dist/plugins/ts-restrictions/rules/rules.d.mts.map +1 -1
- package/dist/plugins/ts-restrictions/rules/rules.mjs +2 -0
- package/dist/plugins/ts-restrictions/rules/rules.mjs.map +1 -1
- package/dist/rules/eslint-ts-restrictions-rules.d.mts +1 -0
- package/dist/rules/eslint-ts-restrictions-rules.d.mts.map +1 -1
- package/dist/rules/eslint-ts-restrictions-rules.mjs +3 -0
- package/dist/rules/eslint-ts-restrictions-rules.mjs.map +1 -1
- package/dist/types/rules/eslint-ts-restrictions-rules.d.mts +50 -0
- package/dist/types/rules/eslint-ts-restrictions-rules.d.mts.map +1 -1
- package/package.json +1 -1
- package/src/plugins/ts-restrictions/rules/check-destructuring-completeness.mts +306 -0
- package/src/plugins/ts-restrictions/rules/check-destructuring-completeness.test.mts +158 -0
- package/src/plugins/ts-restrictions/rules/rules.mts +2 -0
- package/src/rules/eslint-ts-restrictions-rules.mts +6 -1
- package/src/types/rules/eslint-ts-restrictions-rules.mts +55 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type TSESLint } from '@typescript-eslint/utils';
|
|
2
|
+
type Options = readonly [
|
|
3
|
+
Readonly<{
|
|
4
|
+
alwaysCheckReactComponentProps?: boolean;
|
|
5
|
+
directiveKeyword?: string;
|
|
6
|
+
}>?
|
|
7
|
+
];
|
|
8
|
+
type MessageIds = 'incompleteDestructuring';
|
|
9
|
+
export declare const checkDestructuringCompleteness: TSESLint.RuleModule<MessageIds, Options>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=check-destructuring-completeness.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-destructuring-completeness.d.mts","sourceRoot":"","sources":["../../../../src/plugins/ts-restrictions/rules/check-destructuring-completeness.mts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EAEd,MAAM,0BAA0B,CAAC;AAGlC,KAAK,OAAO,GAAG,SAAS;IACtB,QAAQ,CAAC;QACP,8BAA8B,CAAC,EAAE,OAAO,CAAC;QACzC,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC,CAAC;CACJ,CAAC;AAEF,KAAK,UAAU,GAAG,yBAAyB,CAAC;AA8D5C,eAAO,MAAM,8BAA8B,EAAE,QAAQ,CAAC,UAAU,CAC9D,UAAU,EACV,OAAO,CAmOR,CAAC"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_DIRECTIVE_KEYWORD = '@check-destructuring-completeness';
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
5
|
+
const getObjectTypeProperties = (type) => {
|
|
6
|
+
try {
|
|
7
|
+
const properties = type.getProperties();
|
|
8
|
+
// Limit to reasonable number of properties to avoid hangs
|
|
9
|
+
if (properties.length > 1000) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
return properties
|
|
13
|
+
.map((prop) => prop.name)
|
|
14
|
+
.filter((name) =>
|
|
15
|
+
// Filter out symbol properties and internal properties
|
|
16
|
+
!name.startsWith('__') &&
|
|
17
|
+
// Only include string property names
|
|
18
|
+
typeof name === 'string' &&
|
|
19
|
+
name.length > 0);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// If there's any error getting properties, return empty array
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const isReactComponentFunction = (node) => {
|
|
27
|
+
if (node === undefined || node === null)
|
|
28
|
+
return false;
|
|
29
|
+
// Arrow function component
|
|
30
|
+
if (node.type === AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
31
|
+
const { body } = node;
|
|
32
|
+
if (body.type === AST_NODE_TYPES.BlockStatement) {
|
|
33
|
+
return body.body.some((statement) => {
|
|
34
|
+
if (statement.type !== AST_NODE_TYPES.ReturnStatement)
|
|
35
|
+
return false;
|
|
36
|
+
const { argument } = statement;
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
38
|
+
if (argument === null || argument === undefined)
|
|
39
|
+
return false;
|
|
40
|
+
const argType = argument.type;
|
|
41
|
+
return argType === 'JSXElement' || argType === 'JSXFragment';
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
const bodyType = body.type;
|
|
45
|
+
return bodyType === 'JSXElement' || bodyType === 'JSXFragment';
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
};
|
|
49
|
+
const checkDestructuringCompleteness = {
|
|
50
|
+
meta: {
|
|
51
|
+
type: 'suggestion',
|
|
52
|
+
docs: {
|
|
53
|
+
description: 'Ensure all properties are destructured from an object when explicitly requested',
|
|
54
|
+
},
|
|
55
|
+
schema: [
|
|
56
|
+
{
|
|
57
|
+
type: 'object',
|
|
58
|
+
properties: {
|
|
59
|
+
alwaysCheckReactComponentProps: {
|
|
60
|
+
type: 'boolean',
|
|
61
|
+
description: 'Always check React component props destructuring without directive keyword',
|
|
62
|
+
},
|
|
63
|
+
directiveKeyword: {
|
|
64
|
+
type: 'string',
|
|
65
|
+
description: 'Custom directive keyword to enable checking (default: "@check-destructuring-completeness")',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
additionalProperties: false,
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
messages: {
|
|
72
|
+
incompleteDestructuring: 'Not all properties are destructured. Missing: {{missingProps}}',
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
create: (context) => {
|
|
76
|
+
const parserServices = context.sourceCode.parserServices;
|
|
77
|
+
if (parserServices?.program === undefined ||
|
|
78
|
+
parserServices.program === null ||
|
|
79
|
+
parserServices.esTreeNodeToTSNodeMap === undefined) {
|
|
80
|
+
return {};
|
|
81
|
+
}
|
|
82
|
+
const options = context.options[0] ?? {};
|
|
83
|
+
const alwaysCheckReactComponentProps = options.alwaysCheckReactComponentProps ?? true;
|
|
84
|
+
const directiveKeyword = options.directiveKeyword ?? DEFAULT_DIRECTIVE_KEYWORD;
|
|
85
|
+
const typeChecker = parserServices.program.getTypeChecker();
|
|
86
|
+
const esTreeNodeToTSNodeMap = parserServices.esTreeNodeToTSNodeMap;
|
|
87
|
+
const sourceCode = context.sourceCode;
|
|
88
|
+
const hasDirectiveComment = (node) => {
|
|
89
|
+
// Get the parent VariableDeclaration
|
|
90
|
+
const parent = node.parent;
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
92
|
+
if (parent?.type !== AST_NODE_TYPES.VariableDeclaration) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
96
|
+
const comments = sourceCode.getCommentsBefore(parent);
|
|
97
|
+
return comments.some((comment) => comment.value.includes(directiveKeyword));
|
|
98
|
+
};
|
|
99
|
+
const isReactComponentPropsDestructuring = (node) => {
|
|
100
|
+
if (!alwaysCheckReactComponentProps)
|
|
101
|
+
return false;
|
|
102
|
+
const parent = node.parent;
|
|
103
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
104
|
+
if (parent === undefined)
|
|
105
|
+
return false;
|
|
106
|
+
// Case 1: const { a, b } = props; inside component
|
|
107
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
108
|
+
if (parent.type === AST_NODE_TYPES.VariableDeclaration) {
|
|
109
|
+
const grandParent = parent.parent;
|
|
110
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
111
|
+
if (grandParent === undefined)
|
|
112
|
+
return false;
|
|
113
|
+
// Check if we're inside a BlockStatement of an arrow function component
|
|
114
|
+
if (grandParent.type === AST_NODE_TYPES.BlockStatement) {
|
|
115
|
+
const greatGrandParent = grandParent.parent;
|
|
116
|
+
if (
|
|
117
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
118
|
+
greatGrandParent?.type === AST_NODE_TYPES.ArrowFunctionExpression &&
|
|
119
|
+
node.init?.type === AST_NODE_TYPES.Identifier) {
|
|
120
|
+
const initName =
|
|
121
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
122
|
+
node.init.type === AST_NODE_TYPES.Identifier
|
|
123
|
+
? node.init.name
|
|
124
|
+
: undefined;
|
|
125
|
+
if (initName !== undefined &&
|
|
126
|
+
greatGrandParent.params.some((param) => param.type === AST_NODE_TYPES.Identifier &&
|
|
127
|
+
param.name === initName)) {
|
|
128
|
+
return isReactComponentFunction(greatGrandParent);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (grandParent.type === AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
133
|
+
return isReactComponentFunction(grandParent);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
};
|
|
138
|
+
const checkNode = (node) => {
|
|
139
|
+
if (node.id.type !== AST_NODE_TYPES.ObjectPattern)
|
|
140
|
+
return;
|
|
141
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
142
|
+
if (node.init === undefined || node.init === null)
|
|
143
|
+
return;
|
|
144
|
+
const shouldCheck = hasDirectiveComment(node) || isReactComponentPropsDestructuring(node);
|
|
145
|
+
if (!shouldCheck)
|
|
146
|
+
return;
|
|
147
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
148
|
+
const tsNode = esTreeNodeToTSNodeMap.get(node.init);
|
|
149
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
150
|
+
if (tsNode === undefined)
|
|
151
|
+
return;
|
|
152
|
+
const type = typeChecker.getTypeAtLocation(tsNode);
|
|
153
|
+
const objectProps = getObjectTypeProperties(type);
|
|
154
|
+
const destructuredProps = new Set();
|
|
155
|
+
for (const prop of node.id.properties) {
|
|
156
|
+
if (prop.type === AST_NODE_TYPES.Property &&
|
|
157
|
+
prop.key.type === AST_NODE_TYPES.Identifier) {
|
|
158
|
+
// eslint-disable-next-line functional/immutable-data
|
|
159
|
+
destructuredProps.add(prop.key.name);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const missingProps = objectProps.filter((prop) => !destructuredProps.has(prop));
|
|
163
|
+
if (missingProps.length > 0) {
|
|
164
|
+
context.report({
|
|
165
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
166
|
+
node: node.id,
|
|
167
|
+
messageId: 'incompleteDestructuring',
|
|
168
|
+
data: {
|
|
169
|
+
missingProps: missingProps.join(', '),
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
return {
|
|
175
|
+
VariableDeclarator: checkNode,
|
|
176
|
+
ArrowFunctionExpression: (node) => {
|
|
177
|
+
if (!alwaysCheckReactComponentProps)
|
|
178
|
+
return;
|
|
179
|
+
if (!isReactComponentFunction(node))
|
|
180
|
+
return;
|
|
181
|
+
for (const param of node.params) {
|
|
182
|
+
if (param.type === AST_NODE_TYPES.ObjectPattern) {
|
|
183
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
184
|
+
const tsNode = esTreeNodeToTSNodeMap.get(param);
|
|
185
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
186
|
+
if (tsNode === undefined)
|
|
187
|
+
continue;
|
|
188
|
+
const type = typeChecker.getTypeAtLocation(tsNode);
|
|
189
|
+
const objectProps = getObjectTypeProperties(type);
|
|
190
|
+
const destructuredProps = new Set();
|
|
191
|
+
for (const prop of param.properties) {
|
|
192
|
+
if (prop.type === AST_NODE_TYPES.Property &&
|
|
193
|
+
prop.key.type === AST_NODE_TYPES.Identifier) {
|
|
194
|
+
// eslint-disable-next-line functional/immutable-data
|
|
195
|
+
destructuredProps.add(prop.key.name);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const missingProps = objectProps.filter((prop) => !destructuredProps.has(prop));
|
|
199
|
+
if (missingProps.length > 0) {
|
|
200
|
+
context.report({
|
|
201
|
+
node: param,
|
|
202
|
+
messageId: 'incompleteDestructuring',
|
|
203
|
+
data: {
|
|
204
|
+
missingProps: missingProps.join(', '),
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
},
|
|
213
|
+
defaultOptions: [],
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
export { checkDestructuringCompleteness };
|
|
217
|
+
//# sourceMappingURL=check-destructuring-completeness.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-destructuring-completeness.mjs","sources":["../../../../src/plugins/ts-restrictions/rules/check-destructuring-completeness.mts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export declare const tsRestrictionsRules: {
|
|
2
|
+
readonly 'check-destructuring-completeness': import("@typescript-eslint/utils/ts-eslint").RuleModule<"incompleteDestructuring", readonly [(Readonly<{
|
|
3
|
+
alwaysCheckReactComponentProps?: boolean;
|
|
4
|
+
directiveKeyword?: string;
|
|
5
|
+
}> | undefined)?], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
2
6
|
readonly 'no-restricted-cast-name': import("@typescript-eslint/utils/ts-eslint").RuleModule<"restrictedCast", readonly (string | Readonly<{
|
|
3
7
|
name: string;
|
|
4
8
|
fixWith?: Readonly<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.d.mts","sourceRoot":"","sources":["../../../../src/plugins/ts-restrictions/rules/rules.mts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rules.d.mts","sourceRoot":"","sources":["../../../../src/plugins/ts-restrictions/rules/rules.mts"],"names":[],"mappings":"AAKA,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;CAIU,CAAC"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { checkDestructuringCompleteness } from './check-destructuring-completeness.mjs';
|
|
1
2
|
import { noRestrictedCastName } from './no-restricted-cast-name.mjs';
|
|
2
3
|
import { noRestrictedSyntax } from './no-restricted-syntax.mjs';
|
|
3
4
|
|
|
4
5
|
const tsRestrictionsRules = {
|
|
6
|
+
'check-destructuring-completeness': checkDestructuringCompleteness,
|
|
5
7
|
'no-restricted-cast-name': noRestrictedCastName,
|
|
6
8
|
'no-restricted-syntax': noRestrictedSyntax,
|
|
7
9
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.mjs","sources":["../../../../src/plugins/ts-restrictions/rules/rules.mts"],"sourcesContent":[null],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rules.mjs","sources":["../../../../src/plugins/ts-restrictions/rules/rules.mts"],"sourcesContent":[null],"names":[],"mappings":";;;;AAKO,MAAM,mBAAmB,GAAG;AACjC,IAAA,kCAAkC,EAAE,8BAA8B;AAClE,IAAA,yBAAyB,EAAE,oBAAoB;AAC/C,IAAA,sBAAsB,EAAE,kBAAkB;;;;;"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare const eslintTsRestrictionsRules: {
|
|
2
2
|
readonly 'ts-restrictions/no-restricted-syntax': "off";
|
|
3
3
|
readonly 'ts-restrictions/no-restricted-cast-name': "off";
|
|
4
|
+
readonly 'ts-restrictions/check-destructuring-completeness': 2 | 1;
|
|
4
5
|
};
|
|
5
6
|
//# sourceMappingURL=eslint-ts-restrictions-rules.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eslint-ts-restrictions-rules.d.mts","sourceRoot":"","sources":["../../src/rules/eslint-ts-restrictions-rules.mts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"eslint-ts-restrictions-rules.d.mts","sourceRoot":"","sources":["../../src/rules/eslint-ts-restrictions-rules.mts"],"names":[],"mappings":"AAKA,eAAO,MAAM,yBAAyB;;;;CAKQ,CAAC"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { withDefaultOption } from '../types/rule-severity-with-default-option.mjs';
|
|
2
|
+
|
|
1
3
|
const eslintTsRestrictionsRules = {
|
|
2
4
|
'ts-restrictions/no-restricted-syntax': 'off',
|
|
3
5
|
'ts-restrictions/no-restricted-cast-name': 'off',
|
|
6
|
+
'ts-restrictions/check-destructuring-completeness': withDefaultOption('error'),
|
|
4
7
|
};
|
|
5
8
|
|
|
6
9
|
export { eslintTsRestrictionsRules };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eslint-ts-restrictions-rules.mjs","sources":["../../src/rules/eslint-ts-restrictions-rules.mts"],"sourcesContent":[null],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"eslint-ts-restrictions-rules.mjs","sources":["../../src/rules/eslint-ts-restrictions-rules.mts"],"sourcesContent":[null],"names":[],"mappings":";;AAKO,MAAM,yBAAyB,GAAG;AACvC,IAAA,sCAAsC,EAAE,KAAK;AAC7C,IAAA,yCAAyC,EAAE,KAAK;AAChD,IAAA,kDAAkD,EAChD,iBAAiB,CAAC,OAAO,CAAC;;;;;"}
|
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
import { type Linter } from 'eslint';
|
|
2
2
|
type SpreadOptionsIfIsArray<T extends readonly [Linter.StringSeverity, unknown]> = T[1] extends readonly unknown[] ? readonly [Linter.StringSeverity, ...T[1]] : T;
|
|
3
|
+
/**
|
|
4
|
+
* Ensure all properties are destructured from an object when explicitly
|
|
5
|
+
* requested
|
|
6
|
+
*
|
|
7
|
+
* ```md
|
|
8
|
+
* | key | value |
|
|
9
|
+
* | :--------- | :--------- |
|
|
10
|
+
* | type | suggestion |
|
|
11
|
+
* | deprecated | false |
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
declare namespace CheckDestructuringCompleteness {
|
|
15
|
+
/**
|
|
16
|
+
* ### schema
|
|
17
|
+
*
|
|
18
|
+
* ```json
|
|
19
|
+
* [
|
|
20
|
+
* {
|
|
21
|
+
* "type": "object",
|
|
22
|
+
* "properties": {
|
|
23
|
+
* "alwaysCheckReactComponentProps": {
|
|
24
|
+
* "type": "boolean",
|
|
25
|
+
* "description": "Always check React component props destructuring without directive keyword"
|
|
26
|
+
* },
|
|
27
|
+
* "directiveKeyword": {
|
|
28
|
+
* "type": "string",
|
|
29
|
+
* "description": "Custom directive keyword to enable checking (default: \"@check-destructuring-completeness\")"
|
|
30
|
+
* }
|
|
31
|
+
* },
|
|
32
|
+
* "additionalProperties": false
|
|
33
|
+
* }
|
|
34
|
+
* ]
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
type Options = {
|
|
38
|
+
/**
|
|
39
|
+
* Always check React component props destructuring without directive
|
|
40
|
+
* keyword
|
|
41
|
+
*/
|
|
42
|
+
readonly alwaysCheckReactComponentProps?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Custom directive keyword to enable checking (default:
|
|
45
|
+
* "@check-destructuring-completeness")
|
|
46
|
+
*/
|
|
47
|
+
readonly directiveKeyword?: string;
|
|
48
|
+
};
|
|
49
|
+
type RuleEntry = Linter.Severity | SpreadOptionsIfIsArray<readonly [Linter.StringSeverity, Options]> | 'off';
|
|
50
|
+
}
|
|
3
51
|
/**
|
|
4
52
|
* Disallow type assertions with specified type names
|
|
5
53
|
*
|
|
@@ -139,10 +187,12 @@ declare namespace NoRestrictedSyntax {
|
|
|
139
187
|
type RuleEntry = Linter.Severity | SpreadOptionsIfIsArray<readonly [Linter.StringSeverity, Options]> | 'off';
|
|
140
188
|
}
|
|
141
189
|
export type EslintTsRestrictionsRules = {
|
|
190
|
+
readonly 'ts-restrictions/check-destructuring-completeness': CheckDestructuringCompleteness.RuleEntry;
|
|
142
191
|
readonly 'ts-restrictions/no-restricted-cast-name': NoRestrictedCastName.RuleEntry;
|
|
143
192
|
readonly 'ts-restrictions/no-restricted-syntax': NoRestrictedSyntax.RuleEntry;
|
|
144
193
|
};
|
|
145
194
|
export type EslintTsRestrictionsRulesOption = {
|
|
195
|
+
readonly 'ts-restrictions/check-destructuring-completeness': CheckDestructuringCompleteness.Options;
|
|
146
196
|
readonly 'ts-restrictions/no-restricted-cast-name': NoRestrictedCastName.Options;
|
|
147
197
|
readonly 'ts-restrictions/no-restricted-syntax': NoRestrictedSyntax.Options;
|
|
148
198
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eslint-ts-restrictions-rules.d.mts","sourceRoot":"","sources":["../../../src/types/rules/eslint-ts-restrictions-rules.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,KAAK,sBAAsB,CACzB,CAAC,SAAS,SAAS,CAAC,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,IACjD,CAAC,CAAC,CAAC,CAAC,SAAS,SAAS,OAAO,EAAE,GAC/B,SAAS,CAAC,MAAM,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GACzC,CAAC,CAAC;AAEN;;;;;;;;;;GAUG;AACH,kBAAU,oBAAoB,CAAC;IAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4DG;IACH,kBAAkB;IAClB,KAAY,OAAO,GAAG,SAAS,CAC3B,MAAM,GACN;QACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,OAAO,CAAC,EACb;YACE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;YAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;SACvB,GACD;YACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;YACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;SACvB,CAAC;KACP,CACJ,EAAE,CAAC;IAEJ,KAAY,SAAS,GACjB,MAAM,CAAC,QAAQ,GACf,sBAAsB,CAAC,SAAS,CAAC,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,GACjE,KAAK,CAAC;CACX;AAED;;;;;;;;;;;;GAYG;AACH,kBAAU,kBAAkB,CAAC;IAC3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACH,kBAAkB;IAClB,KAAY,OAAO,GAAG,SAAS,CAC3B,MAAM,GACN;QACE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;KAC3B,CACJ,EAAE,CAAC;IAEJ,KAAY,SAAS,GACjB,MAAM,CAAC,QAAQ,GACf,sBAAsB,CAAC,SAAS,CAAC,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,GACjE,KAAK,CAAC;CACX;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,CAAC,yCAAyC,EAAE,oBAAoB,CAAC,SAAS,CAAC;IACnF,QAAQ,CAAC,sCAAsC,EAAE,kBAAkB,CAAC,SAAS,CAAC;CAC/E,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,QAAQ,CAAC,yCAAyC,EAAE,oBAAoB,CAAC,OAAO,CAAC;IACjF,QAAQ,CAAC,sCAAsC,EAAE,kBAAkB,CAAC,OAAO,CAAC;CAC7E,CAAC"}
|
|
1
|
+
{"version":3,"file":"eslint-ts-restrictions-rules.d.mts","sourceRoot":"","sources":["../../../src/types/rules/eslint-ts-restrictions-rules.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,KAAK,sBAAsB,CACzB,CAAC,SAAS,SAAS,CAAC,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,IACjD,CAAC,CAAC,CAAC,CAAC,SAAS,SAAS,OAAO,EAAE,GAC/B,SAAS,CAAC,MAAM,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GACzC,CAAC,CAAC;AAEN;;;;;;;;;;GAUG;AACH,kBAAU,8BAA8B,CAAC;IACvC;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,KAAY,OAAO,GAAG;QACpB;;;WAGG;QACH,QAAQ,CAAC,8BAA8B,CAAC,EAAE,OAAO,CAAC;QAClD;;;WAGG;QACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;KACpC,CAAC;IAEF,KAAY,SAAS,GACjB,MAAM,CAAC,QAAQ,GACf,sBAAsB,CAAC,SAAS,CAAC,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,GACjE,KAAK,CAAC;CACX;AAED;;;;;;;;;;GAUG;AACH,kBAAU,oBAAoB,CAAC;IAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4DG;IACH,kBAAkB;IAClB,KAAY,OAAO,GAAG,SAAS,CAC3B,MAAM,GACN;QACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,OAAO,CAAC,EACb;YACE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;YAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;SACvB,GACD;YACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;YACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;SACvB,CAAC;KACP,CACJ,EAAE,CAAC;IAEJ,KAAY,SAAS,GACjB,MAAM,CAAC,QAAQ,GACf,sBAAsB,CAAC,SAAS,CAAC,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,GACjE,KAAK,CAAC;CACX;AAED;;;;;;;;;;;;GAYG;AACH,kBAAU,kBAAkB,CAAC;IAC3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACH,kBAAkB;IAClB,KAAY,OAAO,GAAG,SAAS,CAC3B,MAAM,GACN;QACE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;KAC3B,CACJ,EAAE,CAAC;IAEJ,KAAY,SAAS,GACjB,MAAM,CAAC,QAAQ,GACf,sBAAsB,CAAC,SAAS,CAAC,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,GACjE,KAAK,CAAC;CACX;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,CAAC,kDAAkD,EAAE,8BAA8B,CAAC,SAAS,CAAC;IACtG,QAAQ,CAAC,yCAAyC,EAAE,oBAAoB,CAAC,SAAS,CAAC;IACnF,QAAQ,CAAC,sCAAsC,EAAE,kBAAkB,CAAC,SAAS,CAAC;CAC/E,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,QAAQ,CAAC,kDAAkD,EAAE,8BAA8B,CAAC,OAAO,CAAC;IACpG,QAAQ,CAAC,yCAAyC,EAAE,oBAAoB,CAAC,OAAO,CAAC;IACjF,QAAQ,CAAC,sCAAsC,EAAE,kBAAkB,CAAC,OAAO,CAAC;CAC7E,CAAC"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AST_NODE_TYPES,
|
|
3
|
+
type TSESLint,
|
|
4
|
+
type TSESTree,
|
|
5
|
+
} from '@typescript-eslint/utils';
|
|
6
|
+
import type * as ts from 'typescript';
|
|
7
|
+
|
|
8
|
+
type Options = readonly [
|
|
9
|
+
Readonly<{
|
|
10
|
+
alwaysCheckReactComponentProps?: boolean;
|
|
11
|
+
directiveKeyword?: string;
|
|
12
|
+
}>?,
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
type MessageIds = 'incompleteDestructuring';
|
|
16
|
+
|
|
17
|
+
const DEFAULT_DIRECTIVE_KEYWORD = '@check-destructuring-completeness';
|
|
18
|
+
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
20
|
+
const getObjectTypeProperties = (type: ts.Type): readonly string[] => {
|
|
21
|
+
try {
|
|
22
|
+
const properties = type.getProperties();
|
|
23
|
+
|
|
24
|
+
// Limit to reasonable number of properties to avoid hangs
|
|
25
|
+
if (properties.length > 1000) {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return properties
|
|
30
|
+
.map((prop) => prop.name)
|
|
31
|
+
.filter(
|
|
32
|
+
(name) =>
|
|
33
|
+
// Filter out symbol properties and internal properties
|
|
34
|
+
!name.startsWith('__') &&
|
|
35
|
+
// Only include string property names
|
|
36
|
+
typeof name === 'string' &&
|
|
37
|
+
name.length > 0,
|
|
38
|
+
);
|
|
39
|
+
} catch {
|
|
40
|
+
// If there's any error getting properties, return empty array
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const isReactComponentFunction = (
|
|
46
|
+
node: DeepReadonly<TSESTree.Node> | undefined | null,
|
|
47
|
+
): boolean => {
|
|
48
|
+
if (node === undefined || node === null) return false;
|
|
49
|
+
|
|
50
|
+
// Arrow function component
|
|
51
|
+
if (node.type === AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
52
|
+
const { body } = node;
|
|
53
|
+
|
|
54
|
+
if (body.type === AST_NODE_TYPES.BlockStatement) {
|
|
55
|
+
return body.body.some((statement) => {
|
|
56
|
+
if (statement.type !== AST_NODE_TYPES.ReturnStatement) return false;
|
|
57
|
+
|
|
58
|
+
const { argument } = statement;
|
|
59
|
+
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
61
|
+
if (argument === null || argument === undefined) return false;
|
|
62
|
+
|
|
63
|
+
const argType = (argument as { type?: string }).type;
|
|
64
|
+
|
|
65
|
+
return argType === 'JSXElement' || argType === 'JSXFragment';
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const bodyType = (body as { type?: string }).type;
|
|
70
|
+
|
|
71
|
+
return bodyType === 'JSXElement' || bodyType === 'JSXFragment';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return false;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const checkDestructuringCompleteness: TSESLint.RuleModule<
|
|
78
|
+
MessageIds,
|
|
79
|
+
Options
|
|
80
|
+
> = {
|
|
81
|
+
meta: {
|
|
82
|
+
type: 'suggestion',
|
|
83
|
+
docs: {
|
|
84
|
+
description:
|
|
85
|
+
'Ensure all properties are destructured from an object when explicitly requested',
|
|
86
|
+
},
|
|
87
|
+
schema: [
|
|
88
|
+
{
|
|
89
|
+
type: 'object',
|
|
90
|
+
properties: {
|
|
91
|
+
alwaysCheckReactComponentProps: {
|
|
92
|
+
type: 'boolean',
|
|
93
|
+
description:
|
|
94
|
+
'Always check React component props destructuring without directive keyword',
|
|
95
|
+
},
|
|
96
|
+
directiveKeyword: {
|
|
97
|
+
type: 'string',
|
|
98
|
+
description:
|
|
99
|
+
'Custom directive keyword to enable checking (default: "@check-destructuring-completeness")',
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
additionalProperties: false,
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
messages: {
|
|
106
|
+
incompleteDestructuring:
|
|
107
|
+
'Not all properties are destructured. Missing: {{missingProps}}',
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
create: (context) => {
|
|
112
|
+
const parserServices = context.sourceCode.parserServices;
|
|
113
|
+
|
|
114
|
+
if (
|
|
115
|
+
parserServices?.program === undefined ||
|
|
116
|
+
parserServices.program === null ||
|
|
117
|
+
parserServices.esTreeNodeToTSNodeMap === undefined
|
|
118
|
+
) {
|
|
119
|
+
return {};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const options = context.options[0] ?? {};
|
|
123
|
+
|
|
124
|
+
const alwaysCheckReactComponentProps =
|
|
125
|
+
options.alwaysCheckReactComponentProps ?? true;
|
|
126
|
+
|
|
127
|
+
const directiveKeyword =
|
|
128
|
+
options.directiveKeyword ?? DEFAULT_DIRECTIVE_KEYWORD;
|
|
129
|
+
|
|
130
|
+
const typeChecker = parserServices.program.getTypeChecker();
|
|
131
|
+
const esTreeNodeToTSNodeMap = parserServices.esTreeNodeToTSNodeMap;
|
|
132
|
+
const sourceCode = context.sourceCode;
|
|
133
|
+
|
|
134
|
+
const hasDirectiveComment = (
|
|
135
|
+
node: DeepReadonly<TSESTree.VariableDeclarator>,
|
|
136
|
+
): boolean => {
|
|
137
|
+
// Get the parent VariableDeclaration
|
|
138
|
+
const parent = node.parent;
|
|
139
|
+
|
|
140
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
141
|
+
if (parent?.type !== AST_NODE_TYPES.VariableDeclaration) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
146
|
+
const comments = sourceCode.getCommentsBefore(parent as never);
|
|
147
|
+
|
|
148
|
+
return comments.some((comment) =>
|
|
149
|
+
comment.value.includes(directiveKeyword),
|
|
150
|
+
);
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const isReactComponentPropsDestructuring = (
|
|
154
|
+
node: DeepReadonly<TSESTree.VariableDeclarator>,
|
|
155
|
+
): boolean => {
|
|
156
|
+
if (!alwaysCheckReactComponentProps) return false;
|
|
157
|
+
|
|
158
|
+
const parent = node.parent;
|
|
159
|
+
|
|
160
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
161
|
+
if (parent === undefined) return false;
|
|
162
|
+
|
|
163
|
+
// Case 1: const { a, b } = props; inside component
|
|
164
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
165
|
+
if (parent.type === AST_NODE_TYPES.VariableDeclaration) {
|
|
166
|
+
const grandParent = parent.parent;
|
|
167
|
+
|
|
168
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
169
|
+
if (grandParent === undefined) return false;
|
|
170
|
+
|
|
171
|
+
// Check if we're inside a BlockStatement of an arrow function component
|
|
172
|
+
if (grandParent.type === AST_NODE_TYPES.BlockStatement) {
|
|
173
|
+
const greatGrandParent = grandParent.parent;
|
|
174
|
+
|
|
175
|
+
if (
|
|
176
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
177
|
+
greatGrandParent?.type === AST_NODE_TYPES.ArrowFunctionExpression &&
|
|
178
|
+
node.init?.type === AST_NODE_TYPES.Identifier
|
|
179
|
+
) {
|
|
180
|
+
const initName =
|
|
181
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
182
|
+
node.init.type === AST_NODE_TYPES.Identifier
|
|
183
|
+
? node.init.name
|
|
184
|
+
: undefined;
|
|
185
|
+
|
|
186
|
+
if (
|
|
187
|
+
initName !== undefined &&
|
|
188
|
+
greatGrandParent.params.some(
|
|
189
|
+
(param) =>
|
|
190
|
+
param.type === AST_NODE_TYPES.Identifier &&
|
|
191
|
+
param.name === initName,
|
|
192
|
+
)
|
|
193
|
+
) {
|
|
194
|
+
return isReactComponentFunction(greatGrandParent);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (grandParent.type === AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
200
|
+
return isReactComponentFunction(grandParent);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return false;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
const checkNode = (
|
|
208
|
+
node: DeepReadonly<TSESTree.VariableDeclarator>,
|
|
209
|
+
): void => {
|
|
210
|
+
if (node.id.type !== AST_NODE_TYPES.ObjectPattern) return;
|
|
211
|
+
|
|
212
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
213
|
+
if (node.init === undefined || node.init === null) return;
|
|
214
|
+
|
|
215
|
+
const shouldCheck =
|
|
216
|
+
hasDirectiveComment(node) || isReactComponentPropsDestructuring(node);
|
|
217
|
+
|
|
218
|
+
if (!shouldCheck) return;
|
|
219
|
+
|
|
220
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
221
|
+
const tsNode = esTreeNodeToTSNodeMap.get(node.init as never);
|
|
222
|
+
|
|
223
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
224
|
+
if (tsNode === undefined) return;
|
|
225
|
+
|
|
226
|
+
const type = typeChecker.getTypeAtLocation(tsNode);
|
|
227
|
+
|
|
228
|
+
const objectProps = getObjectTypeProperties(type);
|
|
229
|
+
const destructuredProps = new Set<string>();
|
|
230
|
+
|
|
231
|
+
for (const prop of node.id.properties) {
|
|
232
|
+
if (
|
|
233
|
+
prop.type === AST_NODE_TYPES.Property &&
|
|
234
|
+
prop.key.type === AST_NODE_TYPES.Identifier
|
|
235
|
+
) {
|
|
236
|
+
// eslint-disable-next-line functional/immutable-data
|
|
237
|
+
destructuredProps.add(prop.key.name);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const missingProps = objectProps.filter(
|
|
242
|
+
(prop) => !destructuredProps.has(prop),
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
if (missingProps.length > 0) {
|
|
246
|
+
context.report({
|
|
247
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
248
|
+
node: node.id as never,
|
|
249
|
+
messageId: 'incompleteDestructuring',
|
|
250
|
+
data: {
|
|
251
|
+
missingProps: missingProps.join(', '),
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
return {
|
|
258
|
+
VariableDeclarator: checkNode,
|
|
259
|
+
ArrowFunctionExpression: (node) => {
|
|
260
|
+
if (!alwaysCheckReactComponentProps) return;
|
|
261
|
+
|
|
262
|
+
if (!isReactComponentFunction(node)) return;
|
|
263
|
+
|
|
264
|
+
for (const param of node.params) {
|
|
265
|
+
if (param.type === AST_NODE_TYPES.ObjectPattern) {
|
|
266
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
267
|
+
const tsNode = esTreeNodeToTSNodeMap.get(param as never);
|
|
268
|
+
|
|
269
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
270
|
+
if (tsNode === undefined) continue;
|
|
271
|
+
|
|
272
|
+
const type = typeChecker.getTypeAtLocation(tsNode);
|
|
273
|
+
|
|
274
|
+
const objectProps = getObjectTypeProperties(type);
|
|
275
|
+
const destructuredProps = new Set<string>();
|
|
276
|
+
|
|
277
|
+
for (const prop of param.properties) {
|
|
278
|
+
if (
|
|
279
|
+
prop.type === AST_NODE_TYPES.Property &&
|
|
280
|
+
prop.key.type === AST_NODE_TYPES.Identifier
|
|
281
|
+
) {
|
|
282
|
+
// eslint-disable-next-line functional/immutable-data
|
|
283
|
+
destructuredProps.add(prop.key.name);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const missingProps = objectProps.filter(
|
|
288
|
+
(prop) => !destructuredProps.has(prop),
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
if (missingProps.length > 0) {
|
|
292
|
+
context.report({
|
|
293
|
+
node: param,
|
|
294
|
+
messageId: 'incompleteDestructuring',
|
|
295
|
+
data: {
|
|
296
|
+
missingProps: missingProps.join(', '),
|
|
297
|
+
},
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
};
|
|
304
|
+
},
|
|
305
|
+
defaultOptions: [],
|
|
306
|
+
};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import parser from '@typescript-eslint/parser';
|
|
2
|
+
import { RuleTester } from '@typescript-eslint/rule-tester';
|
|
3
|
+
import dedent from 'dedent';
|
|
4
|
+
import { checkDestructuringCompleteness } from './check-destructuring-completeness.mjs';
|
|
5
|
+
|
|
6
|
+
const tester = new RuleTester({
|
|
7
|
+
languageOptions: {
|
|
8
|
+
parser,
|
|
9
|
+
parserOptions: {
|
|
10
|
+
ecmaVersion: 2020,
|
|
11
|
+
sourceType: 'module',
|
|
12
|
+
ecmaFeatures: {
|
|
13
|
+
jsx: true,
|
|
14
|
+
},
|
|
15
|
+
projectService: {
|
|
16
|
+
allowDefaultProject: ['*.ts*'],
|
|
17
|
+
},
|
|
18
|
+
tsconfigRootDir: `${import.meta.dirname}/../../../..`,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('check-destructuring-completeness', () => {
|
|
24
|
+
tester.run(
|
|
25
|
+
'check-destructuring-completeness',
|
|
26
|
+
checkDestructuringCompleteness,
|
|
27
|
+
{
|
|
28
|
+
valid: [
|
|
29
|
+
{
|
|
30
|
+
name: 'ignore incomplete destructuring without directive comment',
|
|
31
|
+
code: dedent`
|
|
32
|
+
const obj = { a: 1, b: 2, c: 3 };
|
|
33
|
+
const { a } = obj;
|
|
34
|
+
`,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'validates destructuring with default directive - complete',
|
|
38
|
+
code: dedent`
|
|
39
|
+
const obj = { a: 1, b: 2, c: 3 };
|
|
40
|
+
// @check-destructuring-completeness
|
|
41
|
+
const { a, b, c } = obj;
|
|
42
|
+
`,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'validates destructuring with unknown directive',
|
|
46
|
+
code: dedent`
|
|
47
|
+
const obj: { a: number; b: string; c: boolean } = { a: 1, b: 'hello', c: true };
|
|
48
|
+
// @unknown-directive
|
|
49
|
+
const { a, b } = obj;
|
|
50
|
+
`,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'works with custom directive keyword - custom check',
|
|
54
|
+
code: dedent`
|
|
55
|
+
const obj: { a: number; b: string } = { a: 1, b: 'hello' };
|
|
56
|
+
// @custom-check
|
|
57
|
+
const { a, b } = obj;
|
|
58
|
+
`,
|
|
59
|
+
options: [{ directiveKeyword: '@custom-check' }],
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'custom directive ignores default directive',
|
|
63
|
+
code: dedent`
|
|
64
|
+
const obj = { a: 1, b: 2, c: 3 };
|
|
65
|
+
// @check-destructuring-completeness
|
|
66
|
+
const { a, b } = obj;
|
|
67
|
+
`,
|
|
68
|
+
options: [{ directiveKeyword: '@custom-check' }],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'custom directive ignores unknown directive',
|
|
72
|
+
code: dedent`
|
|
73
|
+
const obj: { a: number; b: string; c: boolean } = { a: 1, b: 'hello', c: true };
|
|
74
|
+
// @unknown-directive
|
|
75
|
+
const { a, b } = obj;
|
|
76
|
+
`,
|
|
77
|
+
options: [{ directiveKeyword: '@custom-check' }],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'checks React component props - parameter destructuring',
|
|
81
|
+
code: dedent`
|
|
82
|
+
type Props = { a: number; b: string };
|
|
83
|
+
const MyComponent = ({ a, b }: Props) => <div>{a}{b}</div>;
|
|
84
|
+
`,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'checks React component props - internal destructuring',
|
|
88
|
+
code: dedent`
|
|
89
|
+
type Props = { a: number; b: string };
|
|
90
|
+
const MyComponent = (props: Props) => {
|
|
91
|
+
const { a, b } = props;
|
|
92
|
+
return <div>{a}{b}</div>;
|
|
93
|
+
};
|
|
94
|
+
`,
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'does not check React component props when disabled - parameter',
|
|
98
|
+
code: dedent`
|
|
99
|
+
type Props = { a: number; b: string; c: boolean };
|
|
100
|
+
const MyComponent = ({ a, b }: Props) => <div>{a}{b}</div>;
|
|
101
|
+
`,
|
|
102
|
+
options: [{ alwaysCheckReactComponentProps: false }],
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'does not check React component props when disabled - internal',
|
|
106
|
+
code: dedent`
|
|
107
|
+
type Props = { a: number; b: string; c: boolean };
|
|
108
|
+
const MyComponent = (props: Props) => {
|
|
109
|
+
const { a, b } = props;
|
|
110
|
+
return <div>{a}{b}</div>;
|
|
111
|
+
};
|
|
112
|
+
`,
|
|
113
|
+
options: [{ alwaysCheckReactComponentProps: false }],
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
invalid: [
|
|
117
|
+
{
|
|
118
|
+
name: 'validates destructuring with default directive - incomplete',
|
|
119
|
+
code: dedent`
|
|
120
|
+
const obj: { a: number; b: string; c: boolean } = { a: 1, b: 'hello', c: true };
|
|
121
|
+
// @check-destructuring-completeness
|
|
122
|
+
const { a, b } = obj;
|
|
123
|
+
`,
|
|
124
|
+
errors: [{ messageId: 'incompleteDestructuring' }],
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: 'custom directive catches incomplete',
|
|
128
|
+
code: dedent`
|
|
129
|
+
const obj: { a: number; b: string } = { a: 1, b: 'hello' };
|
|
130
|
+
// @custom-check
|
|
131
|
+
const { a } = obj;
|
|
132
|
+
`,
|
|
133
|
+
options: [{ directiveKeyword: '@custom-check' }],
|
|
134
|
+
errors: [{ messageId: 'incompleteDestructuring' }],
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: 'checks React component props - parameter destructuring incomplete',
|
|
138
|
+
code: dedent`
|
|
139
|
+
type Props = { a: number; b: string; c: boolean };
|
|
140
|
+
const MyComponent = ({ a, b }: Props) => <div>{a}{b}</div>;
|
|
141
|
+
`,
|
|
142
|
+
errors: [{ messageId: 'incompleteDestructuring' }],
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
name: 'checks React component props - internal destructuring incomplete',
|
|
146
|
+
code: dedent`
|
|
147
|
+
type Props = { a: number; b: string; c: boolean };
|
|
148
|
+
const MyComponent = (props: Props) => {
|
|
149
|
+
const { a, b } = props;
|
|
150
|
+
return <div>{a}{b}</div>;
|
|
151
|
+
};
|
|
152
|
+
`,
|
|
153
|
+
errors: [{ messageId: 'incompleteDestructuring' }],
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
},
|
|
157
|
+
);
|
|
158
|
+
}, 20000);
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { type ESLintPlugin } from '../../../types/index.mjs';
|
|
2
|
+
import { checkDestructuringCompleteness } from './check-destructuring-completeness.mjs';
|
|
2
3
|
import { noRestrictedCastName } from './no-restricted-cast-name.mjs';
|
|
3
4
|
import { noRestrictedSyntax } from './no-restricted-syntax.mjs';
|
|
4
5
|
|
|
5
6
|
export const tsRestrictionsRules = {
|
|
7
|
+
'check-destructuring-completeness': checkDestructuringCompleteness,
|
|
6
8
|
'no-restricted-cast-name': noRestrictedCastName,
|
|
7
9
|
'no-restricted-syntax': noRestrictedSyntax,
|
|
8
10
|
} as const satisfies ESLintPlugin['rules'];
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type EslintTsRestrictionsRules,
|
|
3
|
+
withDefaultOption,
|
|
4
|
+
} from '../types/index.mjs';
|
|
2
5
|
|
|
3
6
|
export const eslintTsRestrictionsRules = {
|
|
4
7
|
'ts-restrictions/no-restricted-syntax': 'off',
|
|
5
8
|
'ts-restrictions/no-restricted-cast-name': 'off',
|
|
9
|
+
'ts-restrictions/check-destructuring-completeness':
|
|
10
|
+
withDefaultOption('error'),
|
|
6
11
|
} as const satisfies EslintTsRestrictionsRules;
|
|
@@ -7,6 +7,59 @@ type SpreadOptionsIfIsArray<
|
|
|
7
7
|
? readonly [Linter.StringSeverity, ...T[1]]
|
|
8
8
|
: T;
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Ensure all properties are destructured from an object when explicitly
|
|
12
|
+
* requested
|
|
13
|
+
*
|
|
14
|
+
* ```md
|
|
15
|
+
* | key | value |
|
|
16
|
+
* | :--------- | :--------- |
|
|
17
|
+
* | type | suggestion |
|
|
18
|
+
* | deprecated | false |
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
namespace CheckDestructuringCompleteness {
|
|
22
|
+
/**
|
|
23
|
+
* ### schema
|
|
24
|
+
*
|
|
25
|
+
* ```json
|
|
26
|
+
* [
|
|
27
|
+
* {
|
|
28
|
+
* "type": "object",
|
|
29
|
+
* "properties": {
|
|
30
|
+
* "alwaysCheckReactComponentProps": {
|
|
31
|
+
* "type": "boolean",
|
|
32
|
+
* "description": "Always check React component props destructuring without directive keyword"
|
|
33
|
+
* },
|
|
34
|
+
* "directiveKeyword": {
|
|
35
|
+
* "type": "string",
|
|
36
|
+
* "description": "Custom directive keyword to enable checking (default: \"@check-destructuring-completeness\")"
|
|
37
|
+
* }
|
|
38
|
+
* },
|
|
39
|
+
* "additionalProperties": false
|
|
40
|
+
* }
|
|
41
|
+
* ]
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export type Options = {
|
|
45
|
+
/**
|
|
46
|
+
* Always check React component props destructuring without directive
|
|
47
|
+
* keyword
|
|
48
|
+
*/
|
|
49
|
+
readonly alwaysCheckReactComponentProps?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Custom directive keyword to enable checking (default:
|
|
52
|
+
* "@check-destructuring-completeness")
|
|
53
|
+
*/
|
|
54
|
+
readonly directiveKeyword?: string;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export type RuleEntry =
|
|
58
|
+
| Linter.Severity
|
|
59
|
+
| SpreadOptionsIfIsArray<readonly [Linter.StringSeverity, Options]>
|
|
60
|
+
| 'off';
|
|
61
|
+
}
|
|
62
|
+
|
|
10
63
|
/**
|
|
11
64
|
* Disallow type assertions with specified type names
|
|
12
65
|
*
|
|
@@ -164,11 +217,13 @@ namespace NoRestrictedSyntax {
|
|
|
164
217
|
}
|
|
165
218
|
|
|
166
219
|
export type EslintTsRestrictionsRules = {
|
|
220
|
+
readonly 'ts-restrictions/check-destructuring-completeness': CheckDestructuringCompleteness.RuleEntry;
|
|
167
221
|
readonly 'ts-restrictions/no-restricted-cast-name': NoRestrictedCastName.RuleEntry;
|
|
168
222
|
readonly 'ts-restrictions/no-restricted-syntax': NoRestrictedSyntax.RuleEntry;
|
|
169
223
|
};
|
|
170
224
|
|
|
171
225
|
export type EslintTsRestrictionsRulesOption = {
|
|
226
|
+
readonly 'ts-restrictions/check-destructuring-completeness': CheckDestructuringCompleteness.Options;
|
|
172
227
|
readonly 'ts-restrictions/no-restricted-cast-name': NoRestrictedCastName.Options;
|
|
173
228
|
readonly 'ts-restrictions/no-restricted-syntax': NoRestrictedSyntax.Options;
|
|
174
229
|
};
|