eslint-cdk-plugin 2.2.0 → 3.0.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 +1 -1
- package/dist/index.cjs +149 -169
- package/dist/index.d.ts +39 -39
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +149 -169
- package/package.json +12 -11
- package/src/index.ts +29 -28
- package/src/rules/construct-constructor-property.ts +4 -4
- package/src/rules/{no-class-in-interface.ts → no-construct-in-interface.ts} +8 -7
- package/src/rules/no-construct-in-public-property-of-construct.ts +155 -0
- package/src/rules/no-construct-stack-suffix.ts +6 -6
- package/src/rules/no-import-private.ts +2 -2
- package/src/rules/no-mutable-property-of-props-interface.ts +60 -0
- package/src/rules/no-mutable-public-property-of-construct.ts +76 -0
- package/src/rules/no-parent-name-construct-id-match.ts +6 -28
- package/src/rules/no-variable-construct-id.ts +4 -4
- package/src/rules/pascal-case-construct-id.ts +4 -4
- package/src/rules/require-passing-this.ts +6 -6
- package/src/rules/no-mutable-props-interface.ts +0 -58
- package/src/rules/no-mutable-public-fields.ts +0 -75
- package/src/rules/no-public-class-fields.ts +0 -154
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 = "
|
|
6
|
+
var version = "3.0.1";
|
|
7
7
|
|
|
8
8
|
const isConstructOrStackType = (type, ignoredClasses = ["App", "Stage"]) => {
|
|
9
9
|
if (ignoredClasses.includes(type.symbol?.name ?? "")) return false;
|
|
@@ -59,7 +59,7 @@ const validateConstructorProperty = (constructor, context) => {
|
|
|
59
59
|
const params = constructor.value.params;
|
|
60
60
|
if (params.length < 2) {
|
|
61
61
|
context.report({
|
|
62
|
-
node: constructor,
|
|
62
|
+
node: constructor.value,
|
|
63
63
|
messageId: "invalidConstructorProperty"
|
|
64
64
|
});
|
|
65
65
|
return;
|
|
@@ -67,7 +67,7 @@ const validateConstructorProperty = (constructor, context) => {
|
|
|
67
67
|
const firstParam = params[0];
|
|
68
68
|
if (firstParam.type === AST_NODE_TYPES.Identifier && firstParam.name !== "scope") {
|
|
69
69
|
context.report({
|
|
70
|
-
node:
|
|
70
|
+
node: firstParam,
|
|
71
71
|
messageId: "invalidConstructorProperty"
|
|
72
72
|
});
|
|
73
73
|
return;
|
|
@@ -75,7 +75,7 @@ const validateConstructorProperty = (constructor, context) => {
|
|
|
75
75
|
const secondParam = params[1];
|
|
76
76
|
if (secondParam.type === AST_NODE_TYPES.Identifier && secondParam.name !== "id") {
|
|
77
77
|
context.report({
|
|
78
|
-
node:
|
|
78
|
+
node: secondParam,
|
|
79
79
|
messageId: "invalidConstructorProperty"
|
|
80
80
|
});
|
|
81
81
|
return;
|
|
@@ -84,7 +84,7 @@ const validateConstructorProperty = (constructor, context) => {
|
|
|
84
84
|
const thirdParam = params[2];
|
|
85
85
|
if (thirdParam.type === AST_NODE_TYPES.Identifier && thirdParam.name !== "props") {
|
|
86
86
|
context.report({
|
|
87
|
-
node:
|
|
87
|
+
node: thirdParam,
|
|
88
88
|
messageId: "invalidConstructorProperty"
|
|
89
89
|
});
|
|
90
90
|
return;
|
|
@@ -99,14 +99,14 @@ const SYNTAX_KIND = {
|
|
|
99
99
|
CONSTRUCTOR: 176
|
|
100
100
|
};
|
|
101
101
|
|
|
102
|
-
const
|
|
102
|
+
const noConstructInInterface = ESLintUtils.RuleCreator.withoutDocs({
|
|
103
103
|
meta: {
|
|
104
104
|
type: "problem",
|
|
105
105
|
docs: {
|
|
106
|
-
description: "Disallow
|
|
106
|
+
description: "Disallow CDK Construct types in interface properties"
|
|
107
107
|
},
|
|
108
108
|
messages: {
|
|
109
|
-
|
|
109
|
+
invalidInterfaceProperty: "Interface property '{{ propertyName }}' should not use CDK Construct type '{{ typeName }}'. Consider using an interface or type alias instead."
|
|
110
110
|
},
|
|
111
111
|
schema: []
|
|
112
112
|
},
|
|
@@ -120,12 +120,12 @@ const noClassInInterface = ESLintUtils.RuleCreator.withoutDocs({
|
|
|
120
120
|
continue;
|
|
121
121
|
}
|
|
122
122
|
const type = parserServices.getTypeAtLocation(property);
|
|
123
|
-
if (!type
|
|
123
|
+
if (!isConstructOrStackType(type)) continue;
|
|
124
124
|
const isClass = type.symbol.flags === SYMBOL_FLAGS.CLASS;
|
|
125
125
|
if (!isClass) continue;
|
|
126
126
|
context.report({
|
|
127
127
|
node: property,
|
|
128
|
-
messageId: "
|
|
128
|
+
messageId: "invalidInterfaceProperty",
|
|
129
129
|
data: {
|
|
130
130
|
propertyName: property.key.name,
|
|
131
131
|
typeName: type.symbol.name
|
|
@@ -137,6 +137,87 @@ const noClassInInterface = ESLintUtils.RuleCreator.withoutDocs({
|
|
|
137
137
|
}
|
|
138
138
|
});
|
|
139
139
|
|
|
140
|
+
const noConstructInPublicPropertyOfConstruct = ESLintUtils.RuleCreator.withoutDocs({
|
|
141
|
+
meta: {
|
|
142
|
+
type: "problem",
|
|
143
|
+
docs: {
|
|
144
|
+
description: "Disallow Construct types in public property of Construct"
|
|
145
|
+
},
|
|
146
|
+
messages: {
|
|
147
|
+
invalidPublicPropertyOfConstruct: "Public property '{{ propertyName }}' of Construct should not use Construct type '{{ typeName }}'. Consider using an interface or type alias instead."
|
|
148
|
+
},
|
|
149
|
+
schema: []
|
|
150
|
+
},
|
|
151
|
+
defaultOptions: [],
|
|
152
|
+
create(context) {
|
|
153
|
+
const parserServices = ESLintUtils.getParserServices(context);
|
|
154
|
+
return {
|
|
155
|
+
ClassDeclaration(node) {
|
|
156
|
+
const type = parserServices.getTypeAtLocation(node);
|
|
157
|
+
if (!isConstructOrStackType(type)) return;
|
|
158
|
+
validatePublicPropertyOfConstruct(node, context, parserServices);
|
|
159
|
+
const constructor = node.body.body.find(
|
|
160
|
+
(member) => member.type === AST_NODE_TYPES.MethodDefinition && member.kind === "constructor"
|
|
161
|
+
);
|
|
162
|
+
if (!constructor || constructor.value.type !== AST_NODE_TYPES.FunctionExpression) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
validateConstructorParameterProperty(
|
|
166
|
+
constructor,
|
|
167
|
+
context,
|
|
168
|
+
parserServices
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
const validatePublicPropertyOfConstruct = (node, context, parserServices) => {
|
|
175
|
+
for (const property of node.body.body) {
|
|
176
|
+
if (property.type !== AST_NODE_TYPES.PropertyDefinition || property.key.type !== AST_NODE_TYPES.Identifier) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (["private", "protected"].includes(property.accessibility ?? "")) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
if (!property.typeAnnotation) continue;
|
|
183
|
+
const type = parserServices.getTypeAtLocation(property);
|
|
184
|
+
if (!isConstructOrStackType(type)) continue;
|
|
185
|
+
const isClass = type.symbol.flags === SYMBOL_FLAGS.CLASS;
|
|
186
|
+
if (!isClass) continue;
|
|
187
|
+
context.report({
|
|
188
|
+
node: property,
|
|
189
|
+
messageId: "invalidPublicPropertyOfConstruct",
|
|
190
|
+
data: {
|
|
191
|
+
propertyName: property.key.name,
|
|
192
|
+
typeName: type.symbol.name
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
const validateConstructorParameterProperty = (constructor, context, parserServices) => {
|
|
198
|
+
for (const param of constructor.value.params) {
|
|
199
|
+
if (param.type !== AST_NODE_TYPES.TSParameterProperty || param.parameter.type !== AST_NODE_TYPES.Identifier) {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (["private", "protected"].includes(param.accessibility ?? "")) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
if (!param.parameter.typeAnnotation) continue;
|
|
206
|
+
const type = parserServices.getTypeAtLocation(param);
|
|
207
|
+
if (!isConstructOrStackType(type)) continue;
|
|
208
|
+
const isClass = type.symbol.flags === SYMBOL_FLAGS.CLASS;
|
|
209
|
+
if (!isClass) continue;
|
|
210
|
+
context.report({
|
|
211
|
+
node: param,
|
|
212
|
+
messageId: "invalidPublicPropertyOfConstruct",
|
|
213
|
+
data: {
|
|
214
|
+
propertyName: param.parameter.name,
|
|
215
|
+
typeName: type.symbol.name
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
140
221
|
const toPascalCase = (str) => {
|
|
141
222
|
return str.split(/[-_\s]/).map((word) => {
|
|
142
223
|
return word.replace(/([A-Z])/g, " $1").split(/\s+/).map(
|
|
@@ -174,7 +255,7 @@ const noConstructStackSuffix = ESLintUtils.RuleCreator.withoutDocs({
|
|
|
174
255
|
description: "Effort to avoid using 'Construct' and 'Stack' suffix in construct id."
|
|
175
256
|
},
|
|
176
257
|
messages: {
|
|
177
|
-
|
|
258
|
+
invalidConstructId: "{{ classType }} ID '{{ id }}' should not include {{ suffix }} suffix."
|
|
178
259
|
},
|
|
179
260
|
schema: [
|
|
180
261
|
{
|
|
@@ -225,8 +306,8 @@ const validateConstructId$3 = (node, context, options) => {
|
|
|
225
306
|
const disallowedSuffixes = options.disallowedSuffixes;
|
|
226
307
|
if (disallowedSuffixes.includes(SUFFIX_TYPE.CONSTRUCT) && formattedConstructId.endsWith(SUFFIX_TYPE.CONSTRUCT)) {
|
|
227
308
|
context.report({
|
|
228
|
-
node,
|
|
229
|
-
messageId: "
|
|
309
|
+
node: secondArg,
|
|
310
|
+
messageId: "invalidConstructId",
|
|
230
311
|
data: {
|
|
231
312
|
classType: "Construct",
|
|
232
313
|
id: secondArg.value,
|
|
@@ -235,8 +316,8 @@ const validateConstructId$3 = (node, context, options) => {
|
|
|
235
316
|
});
|
|
236
317
|
} else if (disallowedSuffixes.includes(SUFFIX_TYPE.STACK) && formattedConstructId.endsWith(SUFFIX_TYPE.STACK)) {
|
|
237
318
|
context.report({
|
|
238
|
-
node,
|
|
239
|
-
messageId: "
|
|
319
|
+
node: secondArg,
|
|
320
|
+
messageId: "invalidConstructId",
|
|
240
321
|
data: {
|
|
241
322
|
classType: "Stack",
|
|
242
323
|
id: secondArg.value,
|
|
@@ -253,7 +334,7 @@ const noImportPrivate = {
|
|
|
253
334
|
description: "Cannot import modules from private dir at different levels of the hierarchy."
|
|
254
335
|
},
|
|
255
336
|
messages: {
|
|
256
|
-
|
|
337
|
+
invalidImportPath: "Cannot import modules from private dir at different levels of the hierarchy."
|
|
257
338
|
},
|
|
258
339
|
schema: []
|
|
259
340
|
},
|
|
@@ -272,7 +353,7 @@ const noImportPrivate = {
|
|
|
272
353
|
if (currentDirSegments.length !== importDirSegments.length || currentDirSegments.some(
|
|
273
354
|
(segment, index) => segment !== importDirSegments[index]
|
|
274
355
|
)) {
|
|
275
|
-
context.report({ node, messageId: "
|
|
356
|
+
context.report({ node, messageId: "invalidImportPath" });
|
|
276
357
|
}
|
|
277
358
|
}
|
|
278
359
|
};
|
|
@@ -282,15 +363,15 @@ const getDirSegments = (dirPath) => {
|
|
|
282
363
|
return dirPath.split(path.sep).filter((segment) => segment !== "");
|
|
283
364
|
};
|
|
284
365
|
|
|
285
|
-
const
|
|
366
|
+
const noMutablePropertyOfPropsInterface = ESLintUtils.RuleCreator.withoutDocs({
|
|
286
367
|
meta: {
|
|
287
368
|
type: "problem",
|
|
288
369
|
docs: {
|
|
289
|
-
description: "Disallow mutable properties
|
|
370
|
+
description: "Disallow mutable properties of Construct Props (interface)"
|
|
290
371
|
},
|
|
291
372
|
fixable: "code",
|
|
292
373
|
messages: {
|
|
293
|
-
|
|
374
|
+
invalidPropertyOfPropsInterface: "Property '{{ propertyName }}' of Construct Props should be readonly."
|
|
294
375
|
},
|
|
295
376
|
schema: []
|
|
296
377
|
},
|
|
@@ -307,7 +388,7 @@ const noMutablePropsInterface = ESLintUtils.RuleCreator.withoutDocs({
|
|
|
307
388
|
if (property.readonly) continue;
|
|
308
389
|
context.report({
|
|
309
390
|
node: property,
|
|
310
|
-
messageId: "
|
|
391
|
+
messageId: "invalidPropertyOfPropsInterface",
|
|
311
392
|
data: {
|
|
312
393
|
propertyName: property.key.name
|
|
313
394
|
},
|
|
@@ -322,15 +403,15 @@ const noMutablePropsInterface = ESLintUtils.RuleCreator.withoutDocs({
|
|
|
322
403
|
}
|
|
323
404
|
});
|
|
324
405
|
|
|
325
|
-
const
|
|
406
|
+
const noMutablePublicPropertyOfConstruct = ESLintUtils.RuleCreator.withoutDocs({
|
|
326
407
|
meta: {
|
|
327
408
|
type: "problem",
|
|
328
409
|
docs: {
|
|
329
|
-
description: "Disallow mutable public
|
|
410
|
+
description: "Disallow mutable public properties of Construct"
|
|
330
411
|
},
|
|
331
412
|
fixable: "code",
|
|
332
413
|
messages: {
|
|
333
|
-
|
|
414
|
+
invalidPublicPropertyOfConstruct: "Public property '{{ propertyName }}' should be readonly. Consider adding the 'readonly' modifier."
|
|
334
415
|
},
|
|
335
416
|
schema: []
|
|
336
417
|
},
|
|
@@ -352,7 +433,7 @@ const noMutablePublicFields = ESLintUtils.RuleCreator.withoutDocs({
|
|
|
352
433
|
if (member.readonly) continue;
|
|
353
434
|
context.report({
|
|
354
435
|
node: member,
|
|
355
|
-
messageId: "
|
|
436
|
+
messageId: "invalidPublicPropertyOfConstruct",
|
|
356
437
|
data: {
|
|
357
438
|
propertyName: member.key.name
|
|
358
439
|
},
|
|
@@ -381,7 +462,7 @@ const noParentNameConstructIdMatch = ESLintUtils.RuleCreator.withoutDocs(
|
|
|
381
462
|
description: "Enforce that construct IDs does not match the parent construct name."
|
|
382
463
|
},
|
|
383
464
|
messages: {
|
|
384
|
-
|
|
465
|
+
invalidConstructId: "Construct ID '{{ constructId }}' should not match parent construct name '{{ parentConstructName }}'. Use a more specific identifier."
|
|
385
466
|
},
|
|
386
467
|
schema: [
|
|
387
468
|
{
|
|
@@ -419,7 +500,6 @@ const noParentNameConstructIdMatch = ESLintUtils.RuleCreator.withoutDocs(
|
|
|
419
500
|
continue;
|
|
420
501
|
}
|
|
421
502
|
validateConstructorBody({
|
|
422
|
-
node,
|
|
423
503
|
expression: body.value,
|
|
424
504
|
parentClassName,
|
|
425
505
|
context,
|
|
@@ -433,7 +513,6 @@ const noParentNameConstructIdMatch = ESLintUtils.RuleCreator.withoutDocs(
|
|
|
433
513
|
}
|
|
434
514
|
);
|
|
435
515
|
const validateConstructorBody = ({
|
|
436
|
-
node,
|
|
437
516
|
expression,
|
|
438
517
|
parentClassName,
|
|
439
518
|
context,
|
|
@@ -446,7 +525,6 @@ const validateConstructorBody = ({
|
|
|
446
525
|
const newExpression = statement.declarations[0].init;
|
|
447
526
|
if (newExpression?.type !== AST_NODE_TYPES.NewExpression) continue;
|
|
448
527
|
validateConstructId$2({
|
|
449
|
-
node,
|
|
450
528
|
context,
|
|
451
529
|
expression: newExpression,
|
|
452
530
|
parentClassName,
|
|
@@ -458,7 +536,6 @@ const validateConstructorBody = ({
|
|
|
458
536
|
case AST_NODE_TYPES.ExpressionStatement: {
|
|
459
537
|
if (statement.expression?.type !== AST_NODE_TYPES.NewExpression) break;
|
|
460
538
|
validateStatement({
|
|
461
|
-
node,
|
|
462
539
|
statement,
|
|
463
540
|
parentClassName,
|
|
464
541
|
context,
|
|
@@ -469,7 +546,6 @@ const validateConstructorBody = ({
|
|
|
469
546
|
}
|
|
470
547
|
case AST_NODE_TYPES.IfStatement: {
|
|
471
548
|
traverseStatements({
|
|
472
|
-
node,
|
|
473
549
|
context,
|
|
474
550
|
parentClassName,
|
|
475
551
|
statement: statement.consequent,
|
|
@@ -482,7 +558,6 @@ const validateConstructorBody = ({
|
|
|
482
558
|
for (const switchCase of statement.cases) {
|
|
483
559
|
for (const statement2 of switchCase.consequent) {
|
|
484
560
|
traverseStatements({
|
|
485
|
-
node,
|
|
486
561
|
context,
|
|
487
562
|
parentClassName,
|
|
488
563
|
statement: statement2,
|
|
@@ -497,7 +572,6 @@ const validateConstructorBody = ({
|
|
|
497
572
|
}
|
|
498
573
|
};
|
|
499
574
|
const traverseStatements = ({
|
|
500
|
-
node,
|
|
501
575
|
statement,
|
|
502
576
|
parentClassName,
|
|
503
577
|
context,
|
|
@@ -508,7 +582,6 @@ const traverseStatements = ({
|
|
|
508
582
|
case AST_NODE_TYPES.BlockStatement: {
|
|
509
583
|
for (const body of statement.body) {
|
|
510
584
|
validateStatement({
|
|
511
|
-
node,
|
|
512
585
|
statement: body,
|
|
513
586
|
parentClassName,
|
|
514
587
|
context,
|
|
@@ -522,7 +595,6 @@ const traverseStatements = ({
|
|
|
522
595
|
const newExpression = statement.expression;
|
|
523
596
|
if (newExpression?.type !== AST_NODE_TYPES.NewExpression) break;
|
|
524
597
|
validateStatement({
|
|
525
|
-
node,
|
|
526
598
|
statement,
|
|
527
599
|
parentClassName,
|
|
528
600
|
context,
|
|
@@ -535,7 +607,6 @@ const traverseStatements = ({
|
|
|
535
607
|
const newExpression = statement.declarations[0].init;
|
|
536
608
|
if (newExpression?.type !== AST_NODE_TYPES.NewExpression) break;
|
|
537
609
|
validateConstructId$2({
|
|
538
|
-
node,
|
|
539
610
|
context,
|
|
540
611
|
expression: newExpression,
|
|
541
612
|
parentClassName,
|
|
@@ -547,7 +618,6 @@ const traverseStatements = ({
|
|
|
547
618
|
}
|
|
548
619
|
};
|
|
549
620
|
const validateStatement = ({
|
|
550
|
-
node,
|
|
551
621
|
statement,
|
|
552
622
|
parentClassName,
|
|
553
623
|
context,
|
|
@@ -559,7 +629,6 @@ const validateStatement = ({
|
|
|
559
629
|
const newExpression = statement.declarations[0].init;
|
|
560
630
|
if (newExpression?.type !== AST_NODE_TYPES.NewExpression) break;
|
|
561
631
|
validateConstructId$2({
|
|
562
|
-
node,
|
|
563
632
|
context,
|
|
564
633
|
expression: newExpression,
|
|
565
634
|
parentClassName,
|
|
@@ -572,7 +641,6 @@ const validateStatement = ({
|
|
|
572
641
|
const newExpression = statement.expression;
|
|
573
642
|
if (newExpression?.type !== AST_NODE_TYPES.NewExpression) break;
|
|
574
643
|
validateConstructId$2({
|
|
575
|
-
node,
|
|
576
644
|
context,
|
|
577
645
|
expression: newExpression,
|
|
578
646
|
parentClassName,
|
|
@@ -583,7 +651,6 @@ const validateStatement = ({
|
|
|
583
651
|
}
|
|
584
652
|
case AST_NODE_TYPES.IfStatement: {
|
|
585
653
|
validateIfStatement({
|
|
586
|
-
node,
|
|
587
654
|
statement,
|
|
588
655
|
parentClassName,
|
|
589
656
|
context,
|
|
@@ -594,7 +661,6 @@ const validateStatement = ({
|
|
|
594
661
|
}
|
|
595
662
|
case AST_NODE_TYPES.SwitchStatement: {
|
|
596
663
|
validateSwitchStatement({
|
|
597
|
-
node,
|
|
598
664
|
statement,
|
|
599
665
|
parentClassName,
|
|
600
666
|
context,
|
|
@@ -606,7 +672,6 @@ const validateStatement = ({
|
|
|
606
672
|
}
|
|
607
673
|
};
|
|
608
674
|
const validateIfStatement = ({
|
|
609
|
-
node,
|
|
610
675
|
statement,
|
|
611
676
|
parentClassName,
|
|
612
677
|
context,
|
|
@@ -614,7 +679,6 @@ const validateIfStatement = ({
|
|
|
614
679
|
option
|
|
615
680
|
}) => {
|
|
616
681
|
traverseStatements({
|
|
617
|
-
node,
|
|
618
682
|
context,
|
|
619
683
|
parentClassName,
|
|
620
684
|
statement: statement.consequent,
|
|
@@ -623,7 +687,6 @@ const validateIfStatement = ({
|
|
|
623
687
|
});
|
|
624
688
|
};
|
|
625
689
|
const validateSwitchStatement = ({
|
|
626
|
-
node,
|
|
627
690
|
statement,
|
|
628
691
|
parentClassName,
|
|
629
692
|
context,
|
|
@@ -633,7 +696,6 @@ const validateSwitchStatement = ({
|
|
|
633
696
|
for (const caseStatement of statement.cases) {
|
|
634
697
|
for (const _consequent of caseStatement.consequent) {
|
|
635
698
|
traverseStatements({
|
|
636
|
-
node,
|
|
637
699
|
context,
|
|
638
700
|
parentClassName,
|
|
639
701
|
statement: _consequent,
|
|
@@ -644,7 +706,6 @@ const validateSwitchStatement = ({
|
|
|
644
706
|
}
|
|
645
707
|
};
|
|
646
708
|
const validateConstructId$2 = ({
|
|
647
|
-
node,
|
|
648
709
|
context,
|
|
649
710
|
expression,
|
|
650
711
|
parentClassName,
|
|
@@ -662,8 +723,8 @@ const validateConstructId$2 = ({
|
|
|
662
723
|
if (!isConstructType(type)) return;
|
|
663
724
|
if (option.disallowContainingParentName && formattedConstructId.includes(formattedParentClassName)) {
|
|
664
725
|
context.report({
|
|
665
|
-
node,
|
|
666
|
-
messageId: "
|
|
726
|
+
node: secondArg,
|
|
727
|
+
messageId: "invalidConstructId",
|
|
667
728
|
data: {
|
|
668
729
|
constructId: secondArg.value,
|
|
669
730
|
parentConstructName: parentClassName
|
|
@@ -673,8 +734,8 @@ const validateConstructId$2 = ({
|
|
|
673
734
|
}
|
|
674
735
|
if (formattedParentClassName === formattedConstructId) {
|
|
675
736
|
context.report({
|
|
676
|
-
node,
|
|
677
|
-
messageId: "
|
|
737
|
+
node: secondArg,
|
|
738
|
+
messageId: "invalidConstructId",
|
|
678
739
|
data: {
|
|
679
740
|
constructId: secondArg.value,
|
|
680
741
|
parentConstructName: parentClassName
|
|
@@ -683,87 +744,6 @@ const validateConstructId$2 = ({
|
|
|
683
744
|
}
|
|
684
745
|
};
|
|
685
746
|
|
|
686
|
-
const noPublicClassFields = ESLintUtils.RuleCreator.withoutDocs({
|
|
687
|
-
meta: {
|
|
688
|
-
type: "problem",
|
|
689
|
-
docs: {
|
|
690
|
-
description: "Disallow class types in public class fields"
|
|
691
|
-
},
|
|
692
|
-
messages: {
|
|
693
|
-
noPublicClassFields: "Public field '{{ propertyName }}' should not use class type '{{ typeName }}'. Consider using an interface or type alias instead."
|
|
694
|
-
},
|
|
695
|
-
schema: []
|
|
696
|
-
},
|
|
697
|
-
defaultOptions: [],
|
|
698
|
-
create(context) {
|
|
699
|
-
const parserServices = ESLintUtils.getParserServices(context);
|
|
700
|
-
return {
|
|
701
|
-
ClassDeclaration(node) {
|
|
702
|
-
const type = parserServices.getTypeAtLocation(node);
|
|
703
|
-
if (!isConstructOrStackType(type)) return;
|
|
704
|
-
validateClassMember(node, context, parserServices);
|
|
705
|
-
const constructor = node.body.body.find(
|
|
706
|
-
(member) => member.type === AST_NODE_TYPES.MethodDefinition && member.kind === "constructor"
|
|
707
|
-
);
|
|
708
|
-
if (!constructor || constructor.value.type !== AST_NODE_TYPES.FunctionExpression) {
|
|
709
|
-
return;
|
|
710
|
-
}
|
|
711
|
-
validateConstructorParameterProperty(
|
|
712
|
-
constructor,
|
|
713
|
-
context,
|
|
714
|
-
parserServices
|
|
715
|
-
);
|
|
716
|
-
}
|
|
717
|
-
};
|
|
718
|
-
}
|
|
719
|
-
});
|
|
720
|
-
const validateClassMember = (node, context, parserServices) => {
|
|
721
|
-
for (const member of node.body.body) {
|
|
722
|
-
if (member.type !== AST_NODE_TYPES.PropertyDefinition || member.key.type !== AST_NODE_TYPES.Identifier) {
|
|
723
|
-
continue;
|
|
724
|
-
}
|
|
725
|
-
if (["private", "protected"].includes(member.accessibility ?? "")) {
|
|
726
|
-
continue;
|
|
727
|
-
}
|
|
728
|
-
if (!member.typeAnnotation) continue;
|
|
729
|
-
const type = parserServices.getTypeAtLocation(member);
|
|
730
|
-
if (!type.symbol) continue;
|
|
731
|
-
const isClass = type.symbol.flags === SYMBOL_FLAGS.CLASS;
|
|
732
|
-
if (!isClass) continue;
|
|
733
|
-
context.report({
|
|
734
|
-
node: member,
|
|
735
|
-
messageId: "noPublicClassFields",
|
|
736
|
-
data: {
|
|
737
|
-
propertyName: member.key.name,
|
|
738
|
-
typeName: type.symbol.name
|
|
739
|
-
}
|
|
740
|
-
});
|
|
741
|
-
}
|
|
742
|
-
};
|
|
743
|
-
const validateConstructorParameterProperty = (constructor, context, parserServices) => {
|
|
744
|
-
for (const param of constructor.value.params) {
|
|
745
|
-
if (param.type !== AST_NODE_TYPES.TSParameterProperty || param.parameter.type !== AST_NODE_TYPES.Identifier) {
|
|
746
|
-
continue;
|
|
747
|
-
}
|
|
748
|
-
if (["private", "protected"].includes(param.accessibility ?? "")) {
|
|
749
|
-
continue;
|
|
750
|
-
}
|
|
751
|
-
if (!param.parameter.typeAnnotation) continue;
|
|
752
|
-
const type = parserServices.getTypeAtLocation(param);
|
|
753
|
-
if (!type.symbol) continue;
|
|
754
|
-
const isClass = type.symbol.flags === SYMBOL_FLAGS.CLASS;
|
|
755
|
-
if (!isClass) continue;
|
|
756
|
-
context.report({
|
|
757
|
-
node: param,
|
|
758
|
-
messageId: "noPublicClassFields",
|
|
759
|
-
data: {
|
|
760
|
-
propertyName: param.parameter.name,
|
|
761
|
-
typeName: type.symbol.name
|
|
762
|
-
}
|
|
763
|
-
});
|
|
764
|
-
}
|
|
765
|
-
};
|
|
766
|
-
|
|
767
747
|
const noVariableConstructId = ESLintUtils.RuleCreator.withoutDocs({
|
|
768
748
|
meta: {
|
|
769
749
|
type: "problem",
|
|
@@ -771,7 +751,7 @@ const noVariableConstructId = ESLintUtils.RuleCreator.withoutDocs({
|
|
|
771
751
|
description: `Enforce using literal strings for Construct ID.`
|
|
772
752
|
},
|
|
773
753
|
messages: {
|
|
774
|
-
|
|
754
|
+
invalidConstructId: "Shouldn't use a parameter as a Construct ID."
|
|
775
755
|
},
|
|
776
756
|
schema: []
|
|
777
757
|
},
|
|
@@ -799,8 +779,8 @@ const validateConstructId$1 = (node, context) => {
|
|
|
799
779
|
return;
|
|
800
780
|
}
|
|
801
781
|
context.report({
|
|
802
|
-
node,
|
|
803
|
-
messageId: "
|
|
782
|
+
node: secondArg,
|
|
783
|
+
messageId: "invalidConstructId"
|
|
804
784
|
});
|
|
805
785
|
};
|
|
806
786
|
const isInsideLoop = (node) => {
|
|
@@ -836,7 +816,7 @@ const pascalCaseConstructId = ESLintUtils.RuleCreator.withoutDocs({
|
|
|
836
816
|
description: "Enforce PascalCase for Construct ID."
|
|
837
817
|
},
|
|
838
818
|
messages: {
|
|
839
|
-
|
|
819
|
+
invalidConstructId: "Construct ID must be PascalCase."
|
|
840
820
|
},
|
|
841
821
|
schema: [],
|
|
842
822
|
fixable: "code"
|
|
@@ -869,8 +849,8 @@ const validateConstructId = (node, context) => {
|
|
|
869
849
|
const quote = secondArg.raw?.startsWith('"') ? QUOTE_TYPE.DOUBLE : QUOTE_TYPE.SINGLE;
|
|
870
850
|
if (isPascalCase(secondArg.value)) return;
|
|
871
851
|
context.report({
|
|
872
|
-
node,
|
|
873
|
-
messageId: "
|
|
852
|
+
node: secondArg,
|
|
853
|
+
messageId: "invalidConstructId",
|
|
874
854
|
fix: (fixer) => {
|
|
875
855
|
const pascalCaseValue = toPascalCase(secondArg.value);
|
|
876
856
|
return fixer.replaceText(secondArg, `${quote}${pascalCaseValue}${quote}`);
|
|
@@ -997,7 +977,7 @@ const requirePassingThis = ESLintUtils.RuleCreator.withoutDocs({
|
|
|
997
977
|
description: "Require passing `this` in a constructor."
|
|
998
978
|
},
|
|
999
979
|
messages: {
|
|
1000
|
-
|
|
980
|
+
missingPassingThis: "Require passing `this` in a constructor."
|
|
1001
981
|
},
|
|
1002
982
|
schema: [
|
|
1003
983
|
{
|
|
@@ -1033,8 +1013,8 @@ const requirePassingThis = ESLintUtils.RuleCreator.withoutDocs({
|
|
|
1033
1013
|
if (constructorPropertyNames[0] !== "scope") return;
|
|
1034
1014
|
if (!options.allowNonThisAndDisallowScope) {
|
|
1035
1015
|
context.report({
|
|
1036
|
-
node,
|
|
1037
|
-
messageId: "
|
|
1016
|
+
node: argument,
|
|
1017
|
+
messageId: "missingPassingThis",
|
|
1038
1018
|
fix: (fixer) => {
|
|
1039
1019
|
return fixer.replaceText(argument, "this");
|
|
1040
1020
|
}
|
|
@@ -1043,8 +1023,8 @@ const requirePassingThis = ESLintUtils.RuleCreator.withoutDocs({
|
|
|
1043
1023
|
}
|
|
1044
1024
|
if (argument.type === AST_NODE_TYPES.Identifier && argument.name === "scope") {
|
|
1045
1025
|
context.report({
|
|
1046
|
-
node,
|
|
1047
|
-
messageId: "
|
|
1026
|
+
node: argument,
|
|
1027
|
+
messageId: "missingPassingThis",
|
|
1048
1028
|
fix: (fixer) => {
|
|
1049
1029
|
return fixer.replaceText(argument, "this");
|
|
1050
1030
|
}
|
|
@@ -1098,20 +1078,20 @@ const requirePropsDefaultDoc = ESLintUtils.RuleCreator.withoutDocs({
|
|
|
1098
1078
|
});
|
|
1099
1079
|
|
|
1100
1080
|
const rules = {
|
|
1101
|
-
"
|
|
1081
|
+
"construct-constructor-property": constructConstructorProperty,
|
|
1082
|
+
"no-construct-in-interface": noConstructInInterface,
|
|
1083
|
+
"no-construct-in-public-property-of-construct": noConstructInPublicPropertyOfConstruct,
|
|
1102
1084
|
"no-construct-stack-suffix": noConstructStackSuffix,
|
|
1085
|
+
"no-import-private": noImportPrivate,
|
|
1086
|
+
"no-mutable-property-of-props-interface": noMutablePropertyOfPropsInterface,
|
|
1087
|
+
"no-mutable-public-property-of-construct": noMutablePublicPropertyOfConstruct,
|
|
1103
1088
|
"no-parent-name-construct-id-match": noParentNameConstructIdMatch,
|
|
1104
|
-
"no-public-class-fields": noPublicClassFields,
|
|
1105
|
-
"pascal-case-construct-id": pascalCaseConstructId,
|
|
1106
|
-
"require-passing-this": requirePassingThis,
|
|
1107
1089
|
"no-variable-construct-id": noVariableConstructId,
|
|
1108
|
-
"
|
|
1109
|
-
"no-mutable-props-interface": noMutablePropsInterface,
|
|
1110
|
-
"construct-constructor-property": constructConstructorProperty,
|
|
1111
|
-
"require-jsdoc": requireJSDoc,
|
|
1112
|
-
"require-props-default-doc": requirePropsDefaultDoc,
|
|
1090
|
+
"pascal-case-construct-id": pascalCaseConstructId,
|
|
1113
1091
|
"props-name-convention": propsNameConvention,
|
|
1114
|
-
"
|
|
1092
|
+
"require-jsdoc": requireJSDoc,
|
|
1093
|
+
"require-passing-this": requirePassingThis,
|
|
1094
|
+
"require-props-default-doc": requirePropsDefaultDoc
|
|
1115
1095
|
};
|
|
1116
1096
|
const cdkPlugin = {
|
|
1117
1097
|
meta: { name, version },
|
|
@@ -1132,38 +1112,38 @@ const createFlatConfig = (rules2) => {
|
|
|
1132
1112
|
};
|
|
1133
1113
|
};
|
|
1134
1114
|
const recommended = createFlatConfig({
|
|
1135
|
-
"cdk/
|
|
1115
|
+
"cdk/construct-constructor-property": "error",
|
|
1116
|
+
"cdk/no-construct-in-interface": "error",
|
|
1117
|
+
"cdk/no-construct-in-public-property-of-construct": "error",
|
|
1136
1118
|
"cdk/no-construct-stack-suffix": "error",
|
|
1119
|
+
"cdk/no-mutable-property-of-props-interface": "warn",
|
|
1120
|
+
"cdk/no-mutable-public-property-of-construct": "warn",
|
|
1137
1121
|
"cdk/no-parent-name-construct-id-match": [
|
|
1138
1122
|
"error",
|
|
1139
1123
|
{ disallowContainingParentName: false }
|
|
1140
1124
|
],
|
|
1141
|
-
"cdk/no-public-class-fields": "error",
|
|
1142
|
-
"cdk/pascal-case-construct-id": "error",
|
|
1143
|
-
"cdk/require-passing-this": ["error", { allowNonThisAndDisallowScope: true }],
|
|
1144
1125
|
"cdk/no-variable-construct-id": "error",
|
|
1145
|
-
"cdk/
|
|
1146
|
-
"cdk/
|
|
1147
|
-
"cdk/construct-constructor-property": "error"
|
|
1126
|
+
"cdk/pascal-case-construct-id": "error",
|
|
1127
|
+
"cdk/require-passing-this": ["error", { allowNonThisAndDisallowScope: true }]
|
|
1148
1128
|
});
|
|
1149
1129
|
const strict = createFlatConfig({
|
|
1150
|
-
"cdk/
|
|
1130
|
+
"cdk/construct-constructor-property": "error",
|
|
1131
|
+
"cdk/no-construct-in-interface": "error",
|
|
1132
|
+
"cdk/no-construct-in-public-property-of-construct": "error",
|
|
1151
1133
|
"cdk/no-construct-stack-suffix": "error",
|
|
1134
|
+
"cdk/no-import-private": "error",
|
|
1135
|
+
"cdk/no-mutable-property-of-props-interface": "error",
|
|
1136
|
+
"cdk/no-mutable-public-property-of-construct": "error",
|
|
1152
1137
|
"cdk/no-parent-name-construct-id-match": [
|
|
1153
1138
|
"error",
|
|
1154
1139
|
{ disallowContainingParentName: true }
|
|
1155
1140
|
],
|
|
1156
|
-
"cdk/no-public-class-fields": "error",
|
|
1157
|
-
"cdk/pascal-case-construct-id": "error",
|
|
1158
|
-
"cdk/require-passing-this": "error",
|
|
1159
1141
|
"cdk/no-variable-construct-id": "error",
|
|
1160
|
-
"cdk/
|
|
1161
|
-
"cdk/no-mutable-props-interface": "error",
|
|
1162
|
-
"cdk/construct-constructor-property": "error",
|
|
1163
|
-
"cdk/require-jsdoc": "error",
|
|
1164
|
-
"cdk/require-props-default-doc": "error",
|
|
1142
|
+
"cdk/pascal-case-construct-id": "error",
|
|
1165
1143
|
"cdk/props-name-convention": "error",
|
|
1166
|
-
"cdk/
|
|
1144
|
+
"cdk/require-jsdoc": "error",
|
|
1145
|
+
"cdk/require-passing-this": "error",
|
|
1146
|
+
"cdk/require-props-default-doc": "error"
|
|
1167
1147
|
});
|
|
1168
1148
|
const configs = {
|
|
1169
1149
|
recommended,
|