eslint-cdk-plugin 3.4.0 → 3.4.2
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/README.md +27 -0
- package/bin/migration.mjs +89 -0
- package/dist/index.cjs +136 -57
- package/dist/index.d.ts +5 -5
- package/dist/index.mjs +136 -57
- package/package.json +19 -13
- package/src/rules/no-construct-in-interface.ts +54 -9
- package/src/rules/no-construct-in-public-property-of-construct.ts +66 -13
- package/src/rules/no-construct-stack-suffix.ts +15 -19
- package/src/rules/no-parent-name-construct-id-match.ts +12 -16
- package/src/rules/require-passing-this.ts +10 -14
- package/src/utils/getArrayElementType.ts +14 -0
- package/src/utils/getGenericTypeArgument.ts +47 -0
- package/src/utils/typecheck/ts-type.ts +12 -0
package/dist/index.cjs
CHANGED
|
@@ -26,7 +26,7 @@ function _interopNamespaceDefault(e) {
|
|
|
26
26
|
var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
|
|
27
27
|
|
|
28
28
|
var name = "eslint-cdk-plugin";
|
|
29
|
-
var version = "3.4.
|
|
29
|
+
var version = "3.4.2";
|
|
30
30
|
|
|
31
31
|
const createRule = utils.ESLintUtils.RuleCreator(
|
|
32
32
|
(name) => `https://eslint-cdk-plugin.dev/rules/${name}`
|
|
@@ -153,6 +153,46 @@ const SYNTAX_KIND = {
|
|
|
153
153
|
PROPERTY_ACCESS_EXPRESSION: 211
|
|
154
154
|
};
|
|
155
155
|
|
|
156
|
+
const getSymbol = (type) => {
|
|
157
|
+
return type.getSymbol?.() ?? type.symbol;
|
|
158
|
+
};
|
|
159
|
+
const isClassType = (type) => {
|
|
160
|
+
return getSymbol(type)?.flags === SYMBOL_FLAGS.CLASS;
|
|
161
|
+
};
|
|
162
|
+
const isArrayType = (type) => {
|
|
163
|
+
const symbol = getSymbol(type);
|
|
164
|
+
if (symbol?.name === "Array") return true;
|
|
165
|
+
if ("target" in type && type.target) {
|
|
166
|
+
const targetSymbol = getSymbol(type.target);
|
|
167
|
+
return targetSymbol?.name === "Array";
|
|
168
|
+
}
|
|
169
|
+
return false;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const getArrayElementType = (type) => {
|
|
173
|
+
if (!isArrayType(type)) return void 0;
|
|
174
|
+
if ("typeArguments" in type && Array.isArray(type.typeArguments)) {
|
|
175
|
+
return type.typeArguments[0];
|
|
176
|
+
}
|
|
177
|
+
return void 0;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const getGenericTypeArgument = (type) => {
|
|
181
|
+
if ("aliasSymbol" in type && type.aliasSymbol && "aliasTypeArguments" in type && type.aliasTypeArguments?.length) {
|
|
182
|
+
return type.aliasTypeArguments[0];
|
|
183
|
+
}
|
|
184
|
+
if ("typeArguments" in type && Array.isArray(type.typeArguments) && type.typeArguments?.length) {
|
|
185
|
+
return type.typeArguments[0];
|
|
186
|
+
}
|
|
187
|
+
if ("target" in type && type.target && "typeArguments" in type && Array.isArray(type.typeArguments) && type.typeArguments?.length) {
|
|
188
|
+
return type.typeArguments[0];
|
|
189
|
+
}
|
|
190
|
+
if ("modifiersType" in type && type.modifiersType) {
|
|
191
|
+
return type.modifiersType;
|
|
192
|
+
}
|
|
193
|
+
return void 0;
|
|
194
|
+
};
|
|
195
|
+
|
|
156
196
|
const isClassDeclaration = (node) => {
|
|
157
197
|
return node.kind === SYNTAX_KIND.CLASS_DECLARATION;
|
|
158
198
|
};
|
|
@@ -169,13 +209,6 @@ const isConstructorDeclaration = (node) => {
|
|
|
169
209
|
return node.kind === SYNTAX_KIND.CONSTRUCTOR;
|
|
170
210
|
};
|
|
171
211
|
|
|
172
|
-
const getSymbol = (type) => {
|
|
173
|
-
return type.getSymbol?.() ?? type.symbol;
|
|
174
|
-
};
|
|
175
|
-
const isClassType = (type) => {
|
|
176
|
-
return getSymbol(type)?.flags === SYMBOL_FLAGS.CLASS;
|
|
177
|
-
};
|
|
178
|
-
|
|
179
212
|
const isResourceWithReadonlyInterface = (type) => {
|
|
180
213
|
if (!isResourceType(type) || !type.symbol?.name) return false;
|
|
181
214
|
if (isIgnoreClass(type.symbol.name)) return false;
|
|
@@ -267,17 +300,45 @@ const noConstructInInterface = createRule({
|
|
|
267
300
|
continue;
|
|
268
301
|
}
|
|
269
302
|
const type = parserServices.getTypeAtLocation(property);
|
|
270
|
-
if (
|
|
303
|
+
if (isClassType(type) && isResourceWithReadonlyInterface(type)) {
|
|
304
|
+
context.report({
|
|
305
|
+
node: property,
|
|
306
|
+
messageId: "invalidInterfaceProperty",
|
|
307
|
+
data: {
|
|
308
|
+
propertyName: property.key.name,
|
|
309
|
+
typeName: type.symbol.name
|
|
310
|
+
}
|
|
311
|
+
});
|
|
271
312
|
continue;
|
|
272
313
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
314
|
+
const elementType = getArrayElementType(type);
|
|
315
|
+
if (elementType && isClassType(elementType) && isResourceWithReadonlyInterface(elementType)) {
|
|
316
|
+
context.report({
|
|
317
|
+
node: property,
|
|
318
|
+
messageId: "invalidInterfaceProperty",
|
|
319
|
+
data: {
|
|
320
|
+
propertyName: property.key.name,
|
|
321
|
+
typeName: `${elementType.symbol.name}[]`
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
const genericArgument = getGenericTypeArgument(type);
|
|
327
|
+
if (genericArgument && isClassType(genericArgument) && isResourceWithReadonlyInterface(genericArgument)) {
|
|
328
|
+
const wrapperName = (() => {
|
|
329
|
+
if (type.aliasSymbol) return type.aliasSymbol.name;
|
|
330
|
+
if (type.symbol?.name) return type.symbol.name;
|
|
331
|
+
return void 0;
|
|
332
|
+
})();
|
|
333
|
+
context.report({
|
|
334
|
+
node: property,
|
|
335
|
+
messageId: "invalidInterfaceProperty",
|
|
336
|
+
data: {
|
|
337
|
+
propertyName: property.key.name,
|
|
338
|
+
typeName: wrapperName ? `${wrapperName}<${genericArgument.symbol.name}>` : genericArgument.symbol.name
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
}
|
|
281
342
|
}
|
|
282
343
|
}
|
|
283
344
|
};
|
|
@@ -327,15 +388,7 @@ const validatePublicPropertyOfConstruct = (node, context, parserServices) => {
|
|
|
327
388
|
}
|
|
328
389
|
if (!property.typeAnnotation) continue;
|
|
329
390
|
const type = parserServices.getTypeAtLocation(property);
|
|
330
|
-
|
|
331
|
-
context.report({
|
|
332
|
-
node: property,
|
|
333
|
-
messageId: "invalidPublicPropertyOfConstruct",
|
|
334
|
-
data: {
|
|
335
|
-
propertyName: property.key.name,
|
|
336
|
-
typeName: type.symbol.name
|
|
337
|
-
}
|
|
338
|
-
});
|
|
391
|
+
checkAndReportConstructType(type, property, property.key.name, context);
|
|
339
392
|
}
|
|
340
393
|
};
|
|
341
394
|
const validateConstructorParameterProperty = (constructor, context, parserServices) => {
|
|
@@ -348,15 +401,50 @@ const validateConstructorParameterProperty = (constructor, context, parserServic
|
|
|
348
401
|
}
|
|
349
402
|
if (!param.parameter.typeAnnotation) continue;
|
|
350
403
|
const type = parserServices.getTypeAtLocation(param);
|
|
351
|
-
|
|
404
|
+
checkAndReportConstructType(type, param, param.parameter.name, context);
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
const checkAndReportConstructType = (type, node, propertyName, context) => {
|
|
408
|
+
if (isClassType(type) && isResourceWithReadonlyInterface(type)) {
|
|
352
409
|
context.report({
|
|
353
|
-
node
|
|
410
|
+
node,
|
|
354
411
|
messageId: "invalidPublicPropertyOfConstruct",
|
|
355
412
|
data: {
|
|
356
|
-
propertyName
|
|
413
|
+
propertyName,
|
|
357
414
|
typeName: type.symbol.name
|
|
358
415
|
}
|
|
359
416
|
});
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
const elementType = getArrayElementType(type);
|
|
420
|
+
if (elementType && isClassType(elementType) && isResourceWithReadonlyInterface(elementType)) {
|
|
421
|
+
context.report({
|
|
422
|
+
node,
|
|
423
|
+
messageId: "invalidPublicPropertyOfConstruct",
|
|
424
|
+
data: {
|
|
425
|
+
propertyName,
|
|
426
|
+
typeName: `${elementType.symbol.name}[]`
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
const genericArgument = getGenericTypeArgument(type);
|
|
432
|
+
if (genericArgument && isClassType(genericArgument) && isResourceWithReadonlyInterface(genericArgument)) {
|
|
433
|
+
const wrapperName = (() => {
|
|
434
|
+
if ("aliasSymbol" in type && type.aliasSymbol) {
|
|
435
|
+
return type.aliasSymbol.name;
|
|
436
|
+
}
|
|
437
|
+
if (type.symbol?.name) return type.symbol.name;
|
|
438
|
+
return void 0;
|
|
439
|
+
})();
|
|
440
|
+
context.report({
|
|
441
|
+
node,
|
|
442
|
+
messageId: "invalidPublicPropertyOfConstruct",
|
|
443
|
+
data: {
|
|
444
|
+
propertyName,
|
|
445
|
+
typeName: wrapperName ? `${wrapperName}<${genericArgument.symbol.name}>` : genericArgument.symbol.name
|
|
446
|
+
}
|
|
447
|
+
});
|
|
360
448
|
}
|
|
361
449
|
};
|
|
362
450
|
|
|
@@ -390,6 +478,9 @@ const SUFFIX_TYPE = {
|
|
|
390
478
|
CONSTRUCT: "Construct",
|
|
391
479
|
STACK: "Stack"
|
|
392
480
|
};
|
|
481
|
+
const defaultOption$2 = {
|
|
482
|
+
disallowedSuffixes: [SUFFIX_TYPE.CONSTRUCT, SUFFIX_TYPE.STACK]
|
|
483
|
+
};
|
|
393
484
|
const noConstructStackSuffix = createRule({
|
|
394
485
|
name: "no-construct-stack-suffix",
|
|
395
486
|
meta: {
|
|
@@ -417,16 +508,9 @@ const noConstructStackSuffix = createRule({
|
|
|
417
508
|
}
|
|
418
509
|
]
|
|
419
510
|
},
|
|
420
|
-
defaultOptions: [
|
|
421
|
-
{
|
|
422
|
-
disallowedSuffixes: [SUFFIX_TYPE.CONSTRUCT, SUFFIX_TYPE.STACK]
|
|
423
|
-
}
|
|
424
|
-
],
|
|
511
|
+
defaultOptions: [defaultOption$2],
|
|
425
512
|
create(context) {
|
|
426
513
|
const parserServices = utils.ESLintUtils.getParserServices(context);
|
|
427
|
-
const options = context.options[0] ?? {
|
|
428
|
-
disallowedSuffixes: [SUFFIX_TYPE.CONSTRUCT, SUFFIX_TYPE.STACK]
|
|
429
|
-
};
|
|
430
514
|
return {
|
|
431
515
|
NewExpression(node) {
|
|
432
516
|
const type = parserServices.getTypeAtLocation(node);
|
|
@@ -435,19 +519,20 @@ const noConstructStackSuffix = createRule({
|
|
|
435
519
|
}
|
|
436
520
|
const constructorPropertyNames = getConstructorPropertyNames(type);
|
|
437
521
|
if (constructorPropertyNames[1] !== "id") return;
|
|
438
|
-
validateConstructId$3(node, context
|
|
522
|
+
validateConstructId$3(node, context);
|
|
439
523
|
}
|
|
440
524
|
};
|
|
441
525
|
}
|
|
442
526
|
});
|
|
443
|
-
const validateConstructId$3 = (node, context
|
|
527
|
+
const validateConstructId$3 = (node, context) => {
|
|
528
|
+
const options = context.options[0] ?? defaultOption$2;
|
|
444
529
|
const secondArg = node.arguments[1];
|
|
445
530
|
if (secondArg.type !== utils.AST_NODE_TYPES.Literal || typeof secondArg.value !== "string") {
|
|
446
531
|
return;
|
|
447
532
|
}
|
|
448
533
|
const formattedConstructId = toPascalCase(secondArg.value);
|
|
449
534
|
const disallowedSuffixes = options.disallowedSuffixes;
|
|
450
|
-
if (disallowedSuffixes
|
|
535
|
+
if (disallowedSuffixes?.includes(SUFFIX_TYPE.CONSTRUCT) && formattedConstructId.endsWith(SUFFIX_TYPE.CONSTRUCT)) {
|
|
451
536
|
context.report({
|
|
452
537
|
node: secondArg,
|
|
453
538
|
messageId: "invalidConstructId",
|
|
@@ -457,7 +542,7 @@ const validateConstructId$3 = (node, context, options) => {
|
|
|
457
542
|
suffix: SUFFIX_TYPE.CONSTRUCT
|
|
458
543
|
}
|
|
459
544
|
});
|
|
460
|
-
} else if (disallowedSuffixes
|
|
545
|
+
} else if (disallowedSuffixes?.includes(SUFFIX_TYPE.STACK) && formattedConstructId.endsWith(SUFFIX_TYPE.STACK)) {
|
|
461
546
|
context.report({
|
|
462
547
|
node: secondArg,
|
|
463
548
|
messageId: "invalidConstructId",
|
|
@@ -600,6 +685,9 @@ const noMutablePublicPropertyOfConstruct = createRule({
|
|
|
600
685
|
}
|
|
601
686
|
});
|
|
602
687
|
|
|
688
|
+
const defaultOption$1 = {
|
|
689
|
+
disallowContainingParentName: false
|
|
690
|
+
};
|
|
603
691
|
const noParentNameConstructIdMatch = createRule({
|
|
604
692
|
name: "no-parent-name-construct-id-match",
|
|
605
693
|
meta: {
|
|
@@ -623,15 +711,9 @@ const noParentNameConstructIdMatch = createRule({
|
|
|
623
711
|
}
|
|
624
712
|
]
|
|
625
713
|
},
|
|
626
|
-
defaultOptions: [
|
|
627
|
-
{
|
|
628
|
-
disallowContainingParentName: false
|
|
629
|
-
}
|
|
630
|
-
],
|
|
714
|
+
defaultOptions: [defaultOption$1],
|
|
631
715
|
create(context) {
|
|
632
|
-
const option = context.options[0] ||
|
|
633
|
-
disallowContainingParentName: false
|
|
634
|
-
};
|
|
716
|
+
const option = context.options[0] || defaultOption$1;
|
|
635
717
|
const parserServices = utils.ESLintUtils.getParserServices(context);
|
|
636
718
|
return {
|
|
637
719
|
ClassBody(node) {
|
|
@@ -1290,6 +1372,9 @@ const requireJSDoc = createRule({
|
|
|
1290
1372
|
}
|
|
1291
1373
|
});
|
|
1292
1374
|
|
|
1375
|
+
const defaultOption = {
|
|
1376
|
+
allowNonThisAndDisallowScope: true
|
|
1377
|
+
};
|
|
1293
1378
|
const requirePassingThis = createRule({
|
|
1294
1379
|
name: "require-passing-this",
|
|
1295
1380
|
meta: {
|
|
@@ -1314,15 +1399,9 @@ const requirePassingThis = createRule({
|
|
|
1314
1399
|
],
|
|
1315
1400
|
fixable: "code"
|
|
1316
1401
|
},
|
|
1317
|
-
defaultOptions: [
|
|
1318
|
-
{
|
|
1319
|
-
allowNonThisAndDisallowScope: false
|
|
1320
|
-
}
|
|
1321
|
-
],
|
|
1402
|
+
defaultOptions: [defaultOption],
|
|
1322
1403
|
create(context) {
|
|
1323
|
-
const options = context.options[0] ||
|
|
1324
|
-
allowNonThisAndDisallowScope: false
|
|
1325
|
-
};
|
|
1404
|
+
const options = context.options[0] || defaultOption;
|
|
1326
1405
|
const parserServices = utils.ESLintUtils.getParserServices(context);
|
|
1327
1406
|
return {
|
|
1328
1407
|
NewExpression(node) {
|
package/dist/index.d.ts
CHANGED
|
@@ -4,22 +4,22 @@ declare const rules: {
|
|
|
4
4
|
"no-construct-in-interface": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidInterfaceProperty", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
5
5
|
"no-construct-in-public-property-of-construct": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidPublicPropertyOfConstruct", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
6
6
|
"no-construct-stack-suffix": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidConstructId", [{
|
|
7
|
-
disallowedSuffixes
|
|
7
|
+
disallowedSuffixes?: ("Construct" | "Stack")[];
|
|
8
8
|
}], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
9
9
|
"no-import-private": import("eslint").Rule.RuleModule;
|
|
10
10
|
"no-mutable-property-of-props-interface": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidPropertyOfPropsInterface", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
11
11
|
"no-mutable-public-property-of-construct": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidPublicPropertyOfConstruct", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
12
|
-
"no-parent-name-construct-id-match": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidConstructId",
|
|
12
|
+
"no-parent-name-construct-id-match": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidConstructId", {
|
|
13
13
|
disallowContainingParentName?: boolean;
|
|
14
|
-
}], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
14
|
+
}[], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
15
15
|
"no-unused-props": import("@typescript-eslint/utils/ts-eslint").RuleModule<"unusedProp", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
16
16
|
"no-variable-construct-id": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidConstructId", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
17
17
|
"pascal-case-construct-id": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidConstructId", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
18
18
|
"props-name-convention": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidPropsName", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
19
19
|
"require-jsdoc": import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingJSDoc", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
20
|
-
"require-passing-this": import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingPassingThis",
|
|
20
|
+
"require-passing-this": import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingPassingThis", {
|
|
21
21
|
allowNonThisAndDisallowScope?: boolean;
|
|
22
|
-
}], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
22
|
+
}[], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
23
23
|
"require-props-default-doc": import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingDefaultDoc", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
24
24
|
};
|
|
25
25
|
declare const configs: {
|
package/dist/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { ESLintUtils, AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint
|
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
|
|
5
5
|
var name = "eslint-cdk-plugin";
|
|
6
|
-
var version = "3.4.
|
|
6
|
+
var version = "3.4.2";
|
|
7
7
|
|
|
8
8
|
const createRule = ESLintUtils.RuleCreator(
|
|
9
9
|
(name) => `https://eslint-cdk-plugin.dev/rules/${name}`
|
|
@@ -130,6 +130,46 @@ const SYNTAX_KIND = {
|
|
|
130
130
|
PROPERTY_ACCESS_EXPRESSION: 211
|
|
131
131
|
};
|
|
132
132
|
|
|
133
|
+
const getSymbol = (type) => {
|
|
134
|
+
return type.getSymbol?.() ?? type.symbol;
|
|
135
|
+
};
|
|
136
|
+
const isClassType = (type) => {
|
|
137
|
+
return getSymbol(type)?.flags === SYMBOL_FLAGS.CLASS;
|
|
138
|
+
};
|
|
139
|
+
const isArrayType = (type) => {
|
|
140
|
+
const symbol = getSymbol(type);
|
|
141
|
+
if (symbol?.name === "Array") return true;
|
|
142
|
+
if ("target" in type && type.target) {
|
|
143
|
+
const targetSymbol = getSymbol(type.target);
|
|
144
|
+
return targetSymbol?.name === "Array";
|
|
145
|
+
}
|
|
146
|
+
return false;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const getArrayElementType = (type) => {
|
|
150
|
+
if (!isArrayType(type)) return void 0;
|
|
151
|
+
if ("typeArguments" in type && Array.isArray(type.typeArguments)) {
|
|
152
|
+
return type.typeArguments[0];
|
|
153
|
+
}
|
|
154
|
+
return void 0;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const getGenericTypeArgument = (type) => {
|
|
158
|
+
if ("aliasSymbol" in type && type.aliasSymbol && "aliasTypeArguments" in type && type.aliasTypeArguments?.length) {
|
|
159
|
+
return type.aliasTypeArguments[0];
|
|
160
|
+
}
|
|
161
|
+
if ("typeArguments" in type && Array.isArray(type.typeArguments) && type.typeArguments?.length) {
|
|
162
|
+
return type.typeArguments[0];
|
|
163
|
+
}
|
|
164
|
+
if ("target" in type && type.target && "typeArguments" in type && Array.isArray(type.typeArguments) && type.typeArguments?.length) {
|
|
165
|
+
return type.typeArguments[0];
|
|
166
|
+
}
|
|
167
|
+
if ("modifiersType" in type && type.modifiersType) {
|
|
168
|
+
return type.modifiersType;
|
|
169
|
+
}
|
|
170
|
+
return void 0;
|
|
171
|
+
};
|
|
172
|
+
|
|
133
173
|
const isClassDeclaration = (node) => {
|
|
134
174
|
return node.kind === SYNTAX_KIND.CLASS_DECLARATION;
|
|
135
175
|
};
|
|
@@ -146,13 +186,6 @@ const isConstructorDeclaration = (node) => {
|
|
|
146
186
|
return node.kind === SYNTAX_KIND.CONSTRUCTOR;
|
|
147
187
|
};
|
|
148
188
|
|
|
149
|
-
const getSymbol = (type) => {
|
|
150
|
-
return type.getSymbol?.() ?? type.symbol;
|
|
151
|
-
};
|
|
152
|
-
const isClassType = (type) => {
|
|
153
|
-
return getSymbol(type)?.flags === SYMBOL_FLAGS.CLASS;
|
|
154
|
-
};
|
|
155
|
-
|
|
156
189
|
const isResourceWithReadonlyInterface = (type) => {
|
|
157
190
|
if (!isResourceType(type) || !type.symbol?.name) return false;
|
|
158
191
|
if (isIgnoreClass(type.symbol.name)) return false;
|
|
@@ -244,17 +277,45 @@ const noConstructInInterface = createRule({
|
|
|
244
277
|
continue;
|
|
245
278
|
}
|
|
246
279
|
const type = parserServices.getTypeAtLocation(property);
|
|
247
|
-
if (
|
|
280
|
+
if (isClassType(type) && isResourceWithReadonlyInterface(type)) {
|
|
281
|
+
context.report({
|
|
282
|
+
node: property,
|
|
283
|
+
messageId: "invalidInterfaceProperty",
|
|
284
|
+
data: {
|
|
285
|
+
propertyName: property.key.name,
|
|
286
|
+
typeName: type.symbol.name
|
|
287
|
+
}
|
|
288
|
+
});
|
|
248
289
|
continue;
|
|
249
290
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
291
|
+
const elementType = getArrayElementType(type);
|
|
292
|
+
if (elementType && isClassType(elementType) && isResourceWithReadonlyInterface(elementType)) {
|
|
293
|
+
context.report({
|
|
294
|
+
node: property,
|
|
295
|
+
messageId: "invalidInterfaceProperty",
|
|
296
|
+
data: {
|
|
297
|
+
propertyName: property.key.name,
|
|
298
|
+
typeName: `${elementType.symbol.name}[]`
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
const genericArgument = getGenericTypeArgument(type);
|
|
304
|
+
if (genericArgument && isClassType(genericArgument) && isResourceWithReadonlyInterface(genericArgument)) {
|
|
305
|
+
const wrapperName = (() => {
|
|
306
|
+
if (type.aliasSymbol) return type.aliasSymbol.name;
|
|
307
|
+
if (type.symbol?.name) return type.symbol.name;
|
|
308
|
+
return void 0;
|
|
309
|
+
})();
|
|
310
|
+
context.report({
|
|
311
|
+
node: property,
|
|
312
|
+
messageId: "invalidInterfaceProperty",
|
|
313
|
+
data: {
|
|
314
|
+
propertyName: property.key.name,
|
|
315
|
+
typeName: wrapperName ? `${wrapperName}<${genericArgument.symbol.name}>` : genericArgument.symbol.name
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
}
|
|
258
319
|
}
|
|
259
320
|
}
|
|
260
321
|
};
|
|
@@ -304,15 +365,7 @@ const validatePublicPropertyOfConstruct = (node, context, parserServices) => {
|
|
|
304
365
|
}
|
|
305
366
|
if (!property.typeAnnotation) continue;
|
|
306
367
|
const type = parserServices.getTypeAtLocation(property);
|
|
307
|
-
|
|
308
|
-
context.report({
|
|
309
|
-
node: property,
|
|
310
|
-
messageId: "invalidPublicPropertyOfConstruct",
|
|
311
|
-
data: {
|
|
312
|
-
propertyName: property.key.name,
|
|
313
|
-
typeName: type.symbol.name
|
|
314
|
-
}
|
|
315
|
-
});
|
|
368
|
+
checkAndReportConstructType(type, property, property.key.name, context);
|
|
316
369
|
}
|
|
317
370
|
};
|
|
318
371
|
const validateConstructorParameterProperty = (constructor, context, parserServices) => {
|
|
@@ -325,15 +378,50 @@ const validateConstructorParameterProperty = (constructor, context, parserServic
|
|
|
325
378
|
}
|
|
326
379
|
if (!param.parameter.typeAnnotation) continue;
|
|
327
380
|
const type = parserServices.getTypeAtLocation(param);
|
|
328
|
-
|
|
381
|
+
checkAndReportConstructType(type, param, param.parameter.name, context);
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
const checkAndReportConstructType = (type, node, propertyName, context) => {
|
|
385
|
+
if (isClassType(type) && isResourceWithReadonlyInterface(type)) {
|
|
329
386
|
context.report({
|
|
330
|
-
node
|
|
387
|
+
node,
|
|
331
388
|
messageId: "invalidPublicPropertyOfConstruct",
|
|
332
389
|
data: {
|
|
333
|
-
propertyName
|
|
390
|
+
propertyName,
|
|
334
391
|
typeName: type.symbol.name
|
|
335
392
|
}
|
|
336
393
|
});
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
const elementType = getArrayElementType(type);
|
|
397
|
+
if (elementType && isClassType(elementType) && isResourceWithReadonlyInterface(elementType)) {
|
|
398
|
+
context.report({
|
|
399
|
+
node,
|
|
400
|
+
messageId: "invalidPublicPropertyOfConstruct",
|
|
401
|
+
data: {
|
|
402
|
+
propertyName,
|
|
403
|
+
typeName: `${elementType.symbol.name}[]`
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
const genericArgument = getGenericTypeArgument(type);
|
|
409
|
+
if (genericArgument && isClassType(genericArgument) && isResourceWithReadonlyInterface(genericArgument)) {
|
|
410
|
+
const wrapperName = (() => {
|
|
411
|
+
if ("aliasSymbol" in type && type.aliasSymbol) {
|
|
412
|
+
return type.aliasSymbol.name;
|
|
413
|
+
}
|
|
414
|
+
if (type.symbol?.name) return type.symbol.name;
|
|
415
|
+
return void 0;
|
|
416
|
+
})();
|
|
417
|
+
context.report({
|
|
418
|
+
node,
|
|
419
|
+
messageId: "invalidPublicPropertyOfConstruct",
|
|
420
|
+
data: {
|
|
421
|
+
propertyName,
|
|
422
|
+
typeName: wrapperName ? `${wrapperName}<${genericArgument.symbol.name}>` : genericArgument.symbol.name
|
|
423
|
+
}
|
|
424
|
+
});
|
|
337
425
|
}
|
|
338
426
|
};
|
|
339
427
|
|
|
@@ -367,6 +455,9 @@ const SUFFIX_TYPE = {
|
|
|
367
455
|
CONSTRUCT: "Construct",
|
|
368
456
|
STACK: "Stack"
|
|
369
457
|
};
|
|
458
|
+
const defaultOption$2 = {
|
|
459
|
+
disallowedSuffixes: [SUFFIX_TYPE.CONSTRUCT, SUFFIX_TYPE.STACK]
|
|
460
|
+
};
|
|
370
461
|
const noConstructStackSuffix = createRule({
|
|
371
462
|
name: "no-construct-stack-suffix",
|
|
372
463
|
meta: {
|
|
@@ -394,16 +485,9 @@ const noConstructStackSuffix = createRule({
|
|
|
394
485
|
}
|
|
395
486
|
]
|
|
396
487
|
},
|
|
397
|
-
defaultOptions: [
|
|
398
|
-
{
|
|
399
|
-
disallowedSuffixes: [SUFFIX_TYPE.CONSTRUCT, SUFFIX_TYPE.STACK]
|
|
400
|
-
}
|
|
401
|
-
],
|
|
488
|
+
defaultOptions: [defaultOption$2],
|
|
402
489
|
create(context) {
|
|
403
490
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
404
|
-
const options = context.options[0] ?? {
|
|
405
|
-
disallowedSuffixes: [SUFFIX_TYPE.CONSTRUCT, SUFFIX_TYPE.STACK]
|
|
406
|
-
};
|
|
407
491
|
return {
|
|
408
492
|
NewExpression(node) {
|
|
409
493
|
const type = parserServices.getTypeAtLocation(node);
|
|
@@ -412,19 +496,20 @@ const noConstructStackSuffix = createRule({
|
|
|
412
496
|
}
|
|
413
497
|
const constructorPropertyNames = getConstructorPropertyNames(type);
|
|
414
498
|
if (constructorPropertyNames[1] !== "id") return;
|
|
415
|
-
validateConstructId$3(node, context
|
|
499
|
+
validateConstructId$3(node, context);
|
|
416
500
|
}
|
|
417
501
|
};
|
|
418
502
|
}
|
|
419
503
|
});
|
|
420
|
-
const validateConstructId$3 = (node, context
|
|
504
|
+
const validateConstructId$3 = (node, context) => {
|
|
505
|
+
const options = context.options[0] ?? defaultOption$2;
|
|
421
506
|
const secondArg = node.arguments[1];
|
|
422
507
|
if (secondArg.type !== AST_NODE_TYPES.Literal || typeof secondArg.value !== "string") {
|
|
423
508
|
return;
|
|
424
509
|
}
|
|
425
510
|
const formattedConstructId = toPascalCase(secondArg.value);
|
|
426
511
|
const disallowedSuffixes = options.disallowedSuffixes;
|
|
427
|
-
if (disallowedSuffixes
|
|
512
|
+
if (disallowedSuffixes?.includes(SUFFIX_TYPE.CONSTRUCT) && formattedConstructId.endsWith(SUFFIX_TYPE.CONSTRUCT)) {
|
|
428
513
|
context.report({
|
|
429
514
|
node: secondArg,
|
|
430
515
|
messageId: "invalidConstructId",
|
|
@@ -434,7 +519,7 @@ const validateConstructId$3 = (node, context, options) => {
|
|
|
434
519
|
suffix: SUFFIX_TYPE.CONSTRUCT
|
|
435
520
|
}
|
|
436
521
|
});
|
|
437
|
-
} else if (disallowedSuffixes
|
|
522
|
+
} else if (disallowedSuffixes?.includes(SUFFIX_TYPE.STACK) && formattedConstructId.endsWith(SUFFIX_TYPE.STACK)) {
|
|
438
523
|
context.report({
|
|
439
524
|
node: secondArg,
|
|
440
525
|
messageId: "invalidConstructId",
|
|
@@ -577,6 +662,9 @@ const noMutablePublicPropertyOfConstruct = createRule({
|
|
|
577
662
|
}
|
|
578
663
|
});
|
|
579
664
|
|
|
665
|
+
const defaultOption$1 = {
|
|
666
|
+
disallowContainingParentName: false
|
|
667
|
+
};
|
|
580
668
|
const noParentNameConstructIdMatch = createRule({
|
|
581
669
|
name: "no-parent-name-construct-id-match",
|
|
582
670
|
meta: {
|
|
@@ -600,15 +688,9 @@ const noParentNameConstructIdMatch = createRule({
|
|
|
600
688
|
}
|
|
601
689
|
]
|
|
602
690
|
},
|
|
603
|
-
defaultOptions: [
|
|
604
|
-
{
|
|
605
|
-
disallowContainingParentName: false
|
|
606
|
-
}
|
|
607
|
-
],
|
|
691
|
+
defaultOptions: [defaultOption$1],
|
|
608
692
|
create(context) {
|
|
609
|
-
const option = context.options[0] ||
|
|
610
|
-
disallowContainingParentName: false
|
|
611
|
-
};
|
|
693
|
+
const option = context.options[0] || defaultOption$1;
|
|
612
694
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
613
695
|
return {
|
|
614
696
|
ClassBody(node) {
|
|
@@ -1267,6 +1349,9 @@ const requireJSDoc = createRule({
|
|
|
1267
1349
|
}
|
|
1268
1350
|
});
|
|
1269
1351
|
|
|
1352
|
+
const defaultOption = {
|
|
1353
|
+
allowNonThisAndDisallowScope: true
|
|
1354
|
+
};
|
|
1270
1355
|
const requirePassingThis = createRule({
|
|
1271
1356
|
name: "require-passing-this",
|
|
1272
1357
|
meta: {
|
|
@@ -1291,15 +1376,9 @@ const requirePassingThis = createRule({
|
|
|
1291
1376
|
],
|
|
1292
1377
|
fixable: "code"
|
|
1293
1378
|
},
|
|
1294
|
-
defaultOptions: [
|
|
1295
|
-
{
|
|
1296
|
-
allowNonThisAndDisallowScope: false
|
|
1297
|
-
}
|
|
1298
|
-
],
|
|
1379
|
+
defaultOptions: [defaultOption],
|
|
1299
1380
|
create(context) {
|
|
1300
|
-
const options = context.options[0] ||
|
|
1301
|
-
allowNonThisAndDisallowScope: false
|
|
1302
|
-
};
|
|
1381
|
+
const options = context.options[0] || defaultOption;
|
|
1303
1382
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
1304
1383
|
return {
|
|
1305
1384
|
NewExpression(node) {
|