eslint-cdk-plugin 2.1.0 → 2.2.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/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 = "2.0.1";
29
+ var version = "2.2.0";
30
30
 
31
31
  const isConstructOrStackType = (type, ignoredClasses = ["App", "Stage"]) => {
32
32
  if (ignoredClasses.includes(type.symbol?.name ?? "")) return false;
@@ -406,10 +406,28 @@ const noParentNameConstructIdMatch = utils.ESLintUtils.RuleCreator.withoutDocs(
406
406
  messages: {
407
407
  noParentNameConstructIdMatch: "Construct ID '{{ constructId }}' should not match parent construct name '{{ parentConstructName }}'. Use a more specific identifier."
408
408
  },
409
- schema: []
409
+ schema: [
410
+ {
411
+ type: "object",
412
+ properties: {
413
+ disallowContainingParentName: {
414
+ type: "boolean",
415
+ default: false
416
+ }
417
+ },
418
+ additionalProperties: false
419
+ }
420
+ ]
410
421
  },
411
- defaultOptions: [],
422
+ defaultOptions: [
423
+ {
424
+ disallowContainingParentName: false
425
+ }
426
+ ],
412
427
  create(context) {
428
+ const option = context.options[0] || {
429
+ disallowContainingParentName: false
430
+ };
413
431
  const parserServices = utils.ESLintUtils.getParserServices(context);
414
432
  return {
415
433
  ClassBody(node) {
@@ -428,7 +446,8 @@ const noParentNameConstructIdMatch = utils.ESLintUtils.RuleCreator.withoutDocs(
428
446
  expression: body.value,
429
447
  parentClassName,
430
448
  context,
431
- parserServices
449
+ parserServices,
450
+ option
432
451
  });
433
452
  }
434
453
  }
@@ -441,7 +460,8 @@ const validateConstructorBody = ({
441
460
  expression,
442
461
  parentClassName,
443
462
  context,
444
- parserServices
463
+ parserServices,
464
+ option
445
465
  }) => {
446
466
  for (const statement of expression.body.body) {
447
467
  switch (statement.type) {
@@ -453,7 +473,8 @@ const validateConstructorBody = ({
453
473
  context,
454
474
  expression: newExpression,
455
475
  parentClassName,
456
- parserServices
476
+ parserServices,
477
+ option
457
478
  });
458
479
  break;
459
480
  }
@@ -464,7 +485,8 @@ const validateConstructorBody = ({
464
485
  statement,
465
486
  parentClassName,
466
487
  context,
467
- parserServices
488
+ parserServices,
489
+ option
468
490
  });
469
491
  break;
470
492
  }
@@ -474,7 +496,8 @@ const validateConstructorBody = ({
474
496
  context,
475
497
  parentClassName,
476
498
  statement: statement.consequent,
477
- parserServices
499
+ parserServices,
500
+ option
478
501
  });
479
502
  break;
480
503
  }
@@ -486,7 +509,8 @@ const validateConstructorBody = ({
486
509
  context,
487
510
  parentClassName,
488
511
  statement: statement2,
489
- parserServices
512
+ parserServices,
513
+ option
490
514
  });
491
515
  }
492
516
  }
@@ -500,7 +524,8 @@ const traverseStatements = ({
500
524
  statement,
501
525
  parentClassName,
502
526
  context,
503
- parserServices
527
+ parserServices,
528
+ option
504
529
  }) => {
505
530
  switch (statement.type) {
506
531
  case utils.AST_NODE_TYPES.BlockStatement: {
@@ -510,7 +535,8 @@ const traverseStatements = ({
510
535
  statement: body,
511
536
  parentClassName,
512
537
  context,
513
- parserServices
538
+ parserServices,
539
+ option
514
540
  });
515
541
  }
516
542
  break;
@@ -523,7 +549,8 @@ const traverseStatements = ({
523
549
  statement,
524
550
  parentClassName,
525
551
  context,
526
- parserServices
552
+ parserServices,
553
+ option
527
554
  });
528
555
  break;
529
556
  }
@@ -535,7 +562,8 @@ const traverseStatements = ({
535
562
  context,
536
563
  expression: newExpression,
537
564
  parentClassName,
538
- parserServices
565
+ parserServices,
566
+ option
539
567
  });
540
568
  break;
541
569
  }
@@ -546,7 +574,8 @@ const validateStatement = ({
546
574
  statement,
547
575
  parentClassName,
548
576
  context,
549
- parserServices
577
+ parserServices,
578
+ option
550
579
  }) => {
551
580
  switch (statement.type) {
552
581
  case utils.AST_NODE_TYPES.VariableDeclaration: {
@@ -557,7 +586,8 @@ const validateStatement = ({
557
586
  context,
558
587
  expression: newExpression,
559
588
  parentClassName,
560
- parserServices
589
+ parserServices,
590
+ option
561
591
  });
562
592
  break;
563
593
  }
@@ -569,7 +599,8 @@ const validateStatement = ({
569
599
  context,
570
600
  expression: newExpression,
571
601
  parentClassName,
572
- parserServices
602
+ parserServices,
603
+ option
573
604
  });
574
605
  break;
575
606
  }
@@ -579,7 +610,8 @@ const validateStatement = ({
579
610
  statement,
580
611
  parentClassName,
581
612
  context,
582
- parserServices
613
+ parserServices,
614
+ option
583
615
  });
584
616
  break;
585
617
  }
@@ -589,7 +621,8 @@ const validateStatement = ({
589
621
  statement,
590
622
  parentClassName,
591
623
  context,
592
- parserServices
624
+ parserServices,
625
+ option
593
626
  });
594
627
  break;
595
628
  }
@@ -600,14 +633,16 @@ const validateIfStatement = ({
600
633
  statement,
601
634
  parentClassName,
602
635
  context,
603
- parserServices
636
+ parserServices,
637
+ option
604
638
  }) => {
605
639
  traverseStatements({
606
640
  node,
607
641
  context,
608
642
  parentClassName,
609
643
  statement: statement.consequent,
610
- parserServices
644
+ parserServices,
645
+ option
611
646
  });
612
647
  };
613
648
  const validateSwitchStatement = ({
@@ -615,7 +650,8 @@ const validateSwitchStatement = ({
615
650
  statement,
616
651
  parentClassName,
617
652
  context,
618
- parserServices
653
+ parserServices,
654
+ option
619
655
  }) => {
620
656
  for (const caseStatement of statement.cases) {
621
657
  for (const _consequent of caseStatement.consequent) {
@@ -624,7 +660,8 @@ const validateSwitchStatement = ({
624
660
  context,
625
661
  parentClassName,
626
662
  statement: _consequent,
627
- parserServices
663
+ parserServices,
664
+ option
628
665
  });
629
666
  }
630
667
  }
@@ -634,7 +671,8 @@ const validateConstructId$2 = ({
634
671
  context,
635
672
  expression,
636
673
  parentClassName,
637
- parserServices
674
+ parserServices,
675
+ option
638
676
  }) => {
639
677
  const type = parserServices.getTypeAtLocation(expression);
640
678
  if (expression.arguments.length < 2) return;
@@ -645,7 +683,18 @@ const validateConstructId$2 = ({
645
683
  const formattedConstructId = toPascalCase(secondArg.value);
646
684
  const formattedParentClassName = toPascalCase(parentClassName);
647
685
  if (!isConstructType(type)) return;
648
- if (formattedConstructId.includes(formattedParentClassName)) {
686
+ if (option.disallowContainingParentName && formattedConstructId.includes(formattedParentClassName)) {
687
+ context.report({
688
+ node,
689
+ messageId: "noParentNameConstructIdMatch",
690
+ data: {
691
+ constructId: secondArg.value,
692
+ parentConstructName: parentClassName
693
+ }
694
+ });
695
+ return;
696
+ }
697
+ if (formattedParentClassName === formattedConstructId) {
649
698
  context.report({
650
699
  node,
651
700
  messageId: "noParentNameConstructIdMatch",
@@ -1108,7 +1157,10 @@ const createFlatConfig = (rules2) => {
1108
1157
  const recommended = createFlatConfig({
1109
1158
  "cdk/no-class-in-interface": "error",
1110
1159
  "cdk/no-construct-stack-suffix": "error",
1111
- "cdk/no-parent-name-construct-id-match": "error",
1160
+ "cdk/no-parent-name-construct-id-match": [
1161
+ "error",
1162
+ { disallowContainingParentName: false }
1163
+ ],
1112
1164
  "cdk/no-public-class-fields": "error",
1113
1165
  "cdk/pascal-case-construct-id": "error",
1114
1166
  "cdk/require-passing-this": ["error", { allowNonThisAndDisallowScope: true }],
@@ -1120,7 +1172,10 @@ const recommended = createFlatConfig({
1120
1172
  const strict = createFlatConfig({
1121
1173
  "cdk/no-class-in-interface": "error",
1122
1174
  "cdk/no-construct-stack-suffix": "error",
1123
- "cdk/no-parent-name-construct-id-match": "error",
1175
+ "cdk/no-parent-name-construct-id-match": [
1176
+ "error",
1177
+ { disallowContainingParentName: true }
1178
+ ],
1124
1179
  "cdk/no-public-class-fields": "error",
1125
1180
  "cdk/pascal-case-construct-id": "error",
1126
1181
  "cdk/require-passing-this": "error",
package/dist/index.d.ts CHANGED
@@ -4,7 +4,9 @@ declare const rules: {
4
4
  "no-construct-stack-suffix": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noConstructStackSuffix", [{
5
5
  disallowedSuffixes: ("Construct" | "Stack")[];
6
6
  }], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
7
- "no-parent-name-construct-id-match": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noParentNameConstructIdMatch", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
7
+ "no-parent-name-construct-id-match": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noParentNameConstructIdMatch", [{
8
+ disallowContainingParentName?: boolean;
9
+ }], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
8
10
  "no-public-class-fields": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noPublicClassFields", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
9
11
  "pascal-case-construct-id": import("@typescript-eslint/utils/ts-eslint").RuleModule<"pascalCaseConstructId", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
10
12
  "require-passing-this": import("@typescript-eslint/utils/ts-eslint").RuleModule<"requirePassingThis", [{
@@ -38,7 +40,9 @@ declare const configs: {
38
40
  "no-construct-stack-suffix": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noConstructStackSuffix", [{
39
41
  disallowedSuffixes: ("Construct" | "Stack")[];
40
42
  }], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
41
- "no-parent-name-construct-id-match": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noParentNameConstructIdMatch", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
43
+ "no-parent-name-construct-id-match": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noParentNameConstructIdMatch", [{
44
+ disallowContainingParentName?: boolean;
45
+ }], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
42
46
  "no-public-class-fields": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noPublicClassFields", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
43
47
  "pascal-case-construct-id": import("@typescript-eslint/utils/ts-eslint").RuleModule<"pascalCaseConstructId", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
44
48
  "require-passing-this": import("@typescript-eslint/utils/ts-eslint").RuleModule<"requirePassingThis", [{
@@ -75,7 +79,9 @@ declare const configs: {
75
79
  "no-construct-stack-suffix": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noConstructStackSuffix", [{
76
80
  disallowedSuffixes: ("Construct" | "Stack")[];
77
81
  }], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
78
- "no-parent-name-construct-id-match": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noParentNameConstructIdMatch", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
82
+ "no-parent-name-construct-id-match": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noParentNameConstructIdMatch", [{
83
+ disallowContainingParentName?: boolean;
84
+ }], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
79
85
  "no-public-class-fields": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noPublicClassFields", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
80
86
  "pascal-case-construct-id": import("@typescript-eslint/utils/ts-eslint").RuleModule<"pascalCaseConstructId", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
81
87
  "require-passing-this": import("@typescript-eslint/utils/ts-eslint").RuleModule<"requirePassingThis", [{
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,2BAA2B,CAAC;AAmBjD,QAAA,MAAM,KAAK;;;;;;;;;;;;;;;;;;;CAeV,CAAC;AAoDF,QAAA,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGZ,CAAC;AAEF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAE1B,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,OAAO,EAAE,OAAO,OAAO,CAAC;CACzB;AAED,QAAA,MAAM,eAAe,EAAE,eAGtB,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,2BAA2B,CAAC;AAmBjD,QAAA,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;CAeV,CAAC;AA0DF,QAAA,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGZ,CAAC;AAEF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAE1B,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,OAAO,EAAE,OAAO,OAAO,CAAC;CACzB;AAED,QAAA,MAAM,eAAe,EAAE,eAGtB,CAAC;AAEF,eAAe,eAAe,CAAC"}
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 = "2.0.1";
6
+ var version = "2.2.0";
7
7
 
8
8
  const isConstructOrStackType = (type, ignoredClasses = ["App", "Stage"]) => {
9
9
  if (ignoredClasses.includes(type.symbol?.name ?? "")) return false;
@@ -383,10 +383,28 @@ const noParentNameConstructIdMatch = ESLintUtils.RuleCreator.withoutDocs(
383
383
  messages: {
384
384
  noParentNameConstructIdMatch: "Construct ID '{{ constructId }}' should not match parent construct name '{{ parentConstructName }}'. Use a more specific identifier."
385
385
  },
386
- schema: []
386
+ schema: [
387
+ {
388
+ type: "object",
389
+ properties: {
390
+ disallowContainingParentName: {
391
+ type: "boolean",
392
+ default: false
393
+ }
394
+ },
395
+ additionalProperties: false
396
+ }
397
+ ]
387
398
  },
388
- defaultOptions: [],
399
+ defaultOptions: [
400
+ {
401
+ disallowContainingParentName: false
402
+ }
403
+ ],
389
404
  create(context) {
405
+ const option = context.options[0] || {
406
+ disallowContainingParentName: false
407
+ };
390
408
  const parserServices = ESLintUtils.getParserServices(context);
391
409
  return {
392
410
  ClassBody(node) {
@@ -405,7 +423,8 @@ const noParentNameConstructIdMatch = ESLintUtils.RuleCreator.withoutDocs(
405
423
  expression: body.value,
406
424
  parentClassName,
407
425
  context,
408
- parserServices
426
+ parserServices,
427
+ option
409
428
  });
410
429
  }
411
430
  }
@@ -418,7 +437,8 @@ const validateConstructorBody = ({
418
437
  expression,
419
438
  parentClassName,
420
439
  context,
421
- parserServices
440
+ parserServices,
441
+ option
422
442
  }) => {
423
443
  for (const statement of expression.body.body) {
424
444
  switch (statement.type) {
@@ -430,7 +450,8 @@ const validateConstructorBody = ({
430
450
  context,
431
451
  expression: newExpression,
432
452
  parentClassName,
433
- parserServices
453
+ parserServices,
454
+ option
434
455
  });
435
456
  break;
436
457
  }
@@ -441,7 +462,8 @@ const validateConstructorBody = ({
441
462
  statement,
442
463
  parentClassName,
443
464
  context,
444
- parserServices
465
+ parserServices,
466
+ option
445
467
  });
446
468
  break;
447
469
  }
@@ -451,7 +473,8 @@ const validateConstructorBody = ({
451
473
  context,
452
474
  parentClassName,
453
475
  statement: statement.consequent,
454
- parserServices
476
+ parserServices,
477
+ option
455
478
  });
456
479
  break;
457
480
  }
@@ -463,7 +486,8 @@ const validateConstructorBody = ({
463
486
  context,
464
487
  parentClassName,
465
488
  statement: statement2,
466
- parserServices
489
+ parserServices,
490
+ option
467
491
  });
468
492
  }
469
493
  }
@@ -477,7 +501,8 @@ const traverseStatements = ({
477
501
  statement,
478
502
  parentClassName,
479
503
  context,
480
- parserServices
504
+ parserServices,
505
+ option
481
506
  }) => {
482
507
  switch (statement.type) {
483
508
  case AST_NODE_TYPES.BlockStatement: {
@@ -487,7 +512,8 @@ const traverseStatements = ({
487
512
  statement: body,
488
513
  parentClassName,
489
514
  context,
490
- parserServices
515
+ parserServices,
516
+ option
491
517
  });
492
518
  }
493
519
  break;
@@ -500,7 +526,8 @@ const traverseStatements = ({
500
526
  statement,
501
527
  parentClassName,
502
528
  context,
503
- parserServices
529
+ parserServices,
530
+ option
504
531
  });
505
532
  break;
506
533
  }
@@ -512,7 +539,8 @@ const traverseStatements = ({
512
539
  context,
513
540
  expression: newExpression,
514
541
  parentClassName,
515
- parserServices
542
+ parserServices,
543
+ option
516
544
  });
517
545
  break;
518
546
  }
@@ -523,7 +551,8 @@ const validateStatement = ({
523
551
  statement,
524
552
  parentClassName,
525
553
  context,
526
- parserServices
554
+ parserServices,
555
+ option
527
556
  }) => {
528
557
  switch (statement.type) {
529
558
  case AST_NODE_TYPES.VariableDeclaration: {
@@ -534,7 +563,8 @@ const validateStatement = ({
534
563
  context,
535
564
  expression: newExpression,
536
565
  parentClassName,
537
- parserServices
566
+ parserServices,
567
+ option
538
568
  });
539
569
  break;
540
570
  }
@@ -546,7 +576,8 @@ const validateStatement = ({
546
576
  context,
547
577
  expression: newExpression,
548
578
  parentClassName,
549
- parserServices
579
+ parserServices,
580
+ option
550
581
  });
551
582
  break;
552
583
  }
@@ -556,7 +587,8 @@ const validateStatement = ({
556
587
  statement,
557
588
  parentClassName,
558
589
  context,
559
- parserServices
590
+ parserServices,
591
+ option
560
592
  });
561
593
  break;
562
594
  }
@@ -566,7 +598,8 @@ const validateStatement = ({
566
598
  statement,
567
599
  parentClassName,
568
600
  context,
569
- parserServices
601
+ parserServices,
602
+ option
570
603
  });
571
604
  break;
572
605
  }
@@ -577,14 +610,16 @@ const validateIfStatement = ({
577
610
  statement,
578
611
  parentClassName,
579
612
  context,
580
- parserServices
613
+ parserServices,
614
+ option
581
615
  }) => {
582
616
  traverseStatements({
583
617
  node,
584
618
  context,
585
619
  parentClassName,
586
620
  statement: statement.consequent,
587
- parserServices
621
+ parserServices,
622
+ option
588
623
  });
589
624
  };
590
625
  const validateSwitchStatement = ({
@@ -592,7 +627,8 @@ const validateSwitchStatement = ({
592
627
  statement,
593
628
  parentClassName,
594
629
  context,
595
- parserServices
630
+ parserServices,
631
+ option
596
632
  }) => {
597
633
  for (const caseStatement of statement.cases) {
598
634
  for (const _consequent of caseStatement.consequent) {
@@ -601,7 +637,8 @@ const validateSwitchStatement = ({
601
637
  context,
602
638
  parentClassName,
603
639
  statement: _consequent,
604
- parserServices
640
+ parserServices,
641
+ option
605
642
  });
606
643
  }
607
644
  }
@@ -611,7 +648,8 @@ const validateConstructId$2 = ({
611
648
  context,
612
649
  expression,
613
650
  parentClassName,
614
- parserServices
651
+ parserServices,
652
+ option
615
653
  }) => {
616
654
  const type = parserServices.getTypeAtLocation(expression);
617
655
  if (expression.arguments.length < 2) return;
@@ -622,7 +660,18 @@ const validateConstructId$2 = ({
622
660
  const formattedConstructId = toPascalCase(secondArg.value);
623
661
  const formattedParentClassName = toPascalCase(parentClassName);
624
662
  if (!isConstructType(type)) return;
625
- if (formattedConstructId.includes(formattedParentClassName)) {
663
+ if (option.disallowContainingParentName && formattedConstructId.includes(formattedParentClassName)) {
664
+ context.report({
665
+ node,
666
+ messageId: "noParentNameConstructIdMatch",
667
+ data: {
668
+ constructId: secondArg.value,
669
+ parentConstructName: parentClassName
670
+ }
671
+ });
672
+ return;
673
+ }
674
+ if (formattedParentClassName === formattedConstructId) {
626
675
  context.report({
627
676
  node,
628
677
  messageId: "noParentNameConstructIdMatch",
@@ -1085,7 +1134,10 @@ const createFlatConfig = (rules2) => {
1085
1134
  const recommended = createFlatConfig({
1086
1135
  "cdk/no-class-in-interface": "error",
1087
1136
  "cdk/no-construct-stack-suffix": "error",
1088
- "cdk/no-parent-name-construct-id-match": "error",
1137
+ "cdk/no-parent-name-construct-id-match": [
1138
+ "error",
1139
+ { disallowContainingParentName: false }
1140
+ ],
1089
1141
  "cdk/no-public-class-fields": "error",
1090
1142
  "cdk/pascal-case-construct-id": "error",
1091
1143
  "cdk/require-passing-this": ["error", { allowNonThisAndDisallowScope: true }],
@@ -1097,7 +1149,10 @@ const recommended = createFlatConfig({
1097
1149
  const strict = createFlatConfig({
1098
1150
  "cdk/no-class-in-interface": "error",
1099
1151
  "cdk/no-construct-stack-suffix": "error",
1100
- "cdk/no-parent-name-construct-id-match": "error",
1152
+ "cdk/no-parent-name-construct-id-match": [
1153
+ "error",
1154
+ { disallowContainingParentName: true }
1155
+ ],
1101
1156
  "cdk/no-public-class-fields": "error",
1102
1157
  "cdk/pascal-case-construct-id": "error",
1103
1158
  "cdk/require-passing-this": "error",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-cdk-plugin",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "eslint plugin for AWS CDK projects",
5
5
  "main": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
package/src/index.ts CHANGED
@@ -57,7 +57,10 @@ const createFlatConfig = (rules: Record<string, unknown>) => {
57
57
  const recommended = createFlatConfig({
58
58
  "cdk/no-class-in-interface": "error",
59
59
  "cdk/no-construct-stack-suffix": "error",
60
- "cdk/no-parent-name-construct-id-match": "error",
60
+ "cdk/no-parent-name-construct-id-match": [
61
+ "error",
62
+ { disallowContainingParentName: false },
63
+ ],
61
64
  "cdk/no-public-class-fields": "error",
62
65
  "cdk/pascal-case-construct-id": "error",
63
66
  "cdk/require-passing-this": ["error", { allowNonThisAndDisallowScope: true }],
@@ -70,7 +73,10 @@ const recommended = createFlatConfig({
70
73
  const strict = createFlatConfig({
71
74
  "cdk/no-class-in-interface": "error",
72
75
  "cdk/no-construct-stack-suffix": "error",
73
- "cdk/no-parent-name-construct-id-match": "error",
76
+ "cdk/no-parent-name-construct-id-match": [
77
+ "error",
78
+ { disallowContainingParentName: true },
79
+ ],
74
80
  "cdk/no-public-class-fields": "error",
75
81
  "cdk/pascal-case-construct-id": "error",
76
82
  "cdk/require-passing-this": "error",
@@ -9,7 +9,13 @@ import {
9
9
  import { toPascalCase } from "../utils/convertString";
10
10
  import { isConstructOrStackType, isConstructType } from "../utils/typeCheck";
11
11
 
12
- type Context = TSESLint.RuleContext<"noParentNameConstructIdMatch", []>;
12
+ type Options = [
13
+ {
14
+ disallowContainingParentName?: boolean;
15
+ }
16
+ ];
17
+
18
+ type Context = TSESLint.RuleContext<"noParentNameConstructIdMatch", Options>;
13
19
 
14
20
  type ValidateStatementArgs<T extends TSESTree.Statement> = {
15
21
  node: TSESTree.ClassBody;
@@ -17,6 +23,7 @@ type ValidateStatementArgs<T extends TSESTree.Statement> = {
17
23
  parentClassName: string;
18
24
  context: Context;
19
25
  parserServices: ParserServicesWithTypeInformation;
26
+ option: Options[0];
20
27
  };
21
28
 
22
29
  type ValidateExpressionArgs<T extends TSESTree.Expression> = {
@@ -25,6 +32,7 @@ type ValidateExpressionArgs<T extends TSESTree.Expression> = {
25
32
  parentClassName: string;
26
33
  context: Context;
27
34
  parserServices: ParserServicesWithTypeInformation;
35
+ option: Options[0];
28
36
  };
29
37
 
30
38
  /**
@@ -45,10 +53,29 @@ export const noParentNameConstructIdMatch = ESLintUtils.RuleCreator.withoutDocs(
45
53
  noParentNameConstructIdMatch:
46
54
  "Construct ID '{{ constructId }}' should not match parent construct name '{{ parentConstructName }}'. Use a more specific identifier.",
47
55
  },
48
- schema: [],
56
+ schema: [
57
+ {
58
+ type: "object",
59
+ properties: {
60
+ disallowContainingParentName: {
61
+ type: "boolean",
62
+ default: false,
63
+ },
64
+ },
65
+ additionalProperties: false,
66
+ },
67
+ ],
49
68
  },
50
- defaultOptions: [],
51
- create(context) {
69
+ defaultOptions: [
70
+ {
71
+ disallowContainingParentName: false,
72
+ },
73
+ ],
74
+
75
+ create(context: Context) {
76
+ const option = context.options[0] || {
77
+ disallowContainingParentName: false,
78
+ };
52
79
  const parserServices = ESLintUtils.getParserServices(context);
53
80
  return {
54
81
  ClassBody(node) {
@@ -77,6 +104,7 @@ export const noParentNameConstructIdMatch = ESLintUtils.RuleCreator.withoutDocs(
77
104
  parentClassName,
78
105
  context,
79
106
  parserServices,
107
+ option,
80
108
  });
81
109
  }
82
110
  },
@@ -95,6 +123,7 @@ const validateConstructorBody = ({
95
123
  parentClassName,
96
124
  context,
97
125
  parserServices,
126
+ option,
98
127
  }: ValidateExpressionArgs<TSESTree.FunctionExpression>): void => {
99
128
  for (const statement of expression.body.body) {
100
129
  switch (statement.type) {
@@ -107,6 +136,7 @@ const validateConstructorBody = ({
107
136
  expression: newExpression,
108
137
  parentClassName,
109
138
  parserServices,
139
+ option,
110
140
  });
111
141
  break;
112
142
  }
@@ -118,6 +148,7 @@ const validateConstructorBody = ({
118
148
  parentClassName,
119
149
  context,
120
150
  parserServices,
151
+ option,
121
152
  });
122
153
  break;
123
154
  }
@@ -128,6 +159,7 @@ const validateConstructorBody = ({
128
159
  parentClassName,
129
160
  statement: statement.consequent,
130
161
  parserServices,
162
+ option,
131
163
  });
132
164
  break;
133
165
  }
@@ -140,6 +172,7 @@ const validateConstructorBody = ({
140
172
  parentClassName,
141
173
  statement,
142
174
  parserServices,
175
+ option,
143
176
  });
144
177
  }
145
178
  }
@@ -160,6 +193,7 @@ const traverseStatements = ({
160
193
  parentClassName,
161
194
  context,
162
195
  parserServices,
196
+ option,
163
197
  }: ValidateStatementArgs<TSESTree.Statement>) => {
164
198
  switch (statement.type) {
165
199
  case AST_NODE_TYPES.BlockStatement: {
@@ -170,6 +204,7 @@ const traverseStatements = ({
170
204
  parentClassName,
171
205
  context,
172
206
  parserServices,
207
+ option,
173
208
  });
174
209
  }
175
210
  break;
@@ -183,6 +218,7 @@ const traverseStatements = ({
183
218
  parentClassName,
184
219
  context,
185
220
  parserServices,
221
+ option,
186
222
  });
187
223
  break;
188
224
  }
@@ -195,6 +231,7 @@ const traverseStatements = ({
195
231
  expression: newExpression,
196
232
  parentClassName,
197
233
  parserServices,
234
+ option,
198
235
  });
199
236
  break;
200
237
  }
@@ -212,6 +249,7 @@ const validateStatement = ({
212
249
  parentClassName,
213
250
  context,
214
251
  parserServices,
252
+ option,
215
253
  }: ValidateStatementArgs<TSESTree.Statement>): void => {
216
254
  switch (statement.type) {
217
255
  case AST_NODE_TYPES.VariableDeclaration: {
@@ -223,6 +261,7 @@ const validateStatement = ({
223
261
  expression: newExpression,
224
262
  parentClassName,
225
263
  parserServices,
264
+ option,
226
265
  });
227
266
  break;
228
267
  }
@@ -235,6 +274,7 @@ const validateStatement = ({
235
274
  expression: newExpression,
236
275
  parentClassName,
237
276
  parserServices,
277
+ option,
238
278
  });
239
279
  break;
240
280
  }
@@ -245,6 +285,7 @@ const validateStatement = ({
245
285
  parentClassName,
246
286
  context,
247
287
  parserServices,
288
+ option,
248
289
  });
249
290
  break;
250
291
  }
@@ -255,6 +296,7 @@ const validateStatement = ({
255
296
  parentClassName,
256
297
  context,
257
298
  parserServices,
299
+ option,
258
300
  });
259
301
  break;
260
302
  }
@@ -271,6 +313,7 @@ const validateIfStatement = ({
271
313
  parentClassName,
272
314
  context,
273
315
  parserServices,
316
+ option,
274
317
  }: ValidateStatementArgs<TSESTree.IfStatement>): void => {
275
318
  traverseStatements({
276
319
  node,
@@ -278,6 +321,7 @@ const validateIfStatement = ({
278
321
  parentClassName,
279
322
  statement: statement.consequent,
280
323
  parserServices,
324
+ option,
281
325
  });
282
326
  };
283
327
 
@@ -291,6 +335,7 @@ const validateSwitchStatement = ({
291
335
  parentClassName,
292
336
  context,
293
337
  parserServices,
338
+ option,
294
339
  }: ValidateStatementArgs<TSESTree.SwitchStatement>): void => {
295
340
  for (const caseStatement of statement.cases) {
296
341
  for (const _consequent of caseStatement.consequent) {
@@ -300,6 +345,7 @@ const validateSwitchStatement = ({
300
345
  parentClassName,
301
346
  statement: _consequent,
302
347
  parserServices,
348
+ option,
303
349
  });
304
350
  }
305
351
  }
@@ -314,6 +360,7 @@ const validateConstructId = ({
314
360
  expression,
315
361
  parentClassName,
316
362
  parserServices,
363
+ option,
317
364
  }: ValidateExpressionArgs<TSESTree.NewExpression>): void => {
318
365
  const type = parserServices.getTypeAtLocation(expression);
319
366
 
@@ -333,7 +380,21 @@ const validateConstructId = ({
333
380
 
334
381
  if (!isConstructType(type)) return;
335
382
 
336
- if (formattedConstructId.includes(formattedParentClassName)) {
383
+ if (
384
+ option.disallowContainingParentName &&
385
+ formattedConstructId.includes(formattedParentClassName)
386
+ ) {
387
+ context.report({
388
+ node,
389
+ messageId: "noParentNameConstructIdMatch",
390
+ data: {
391
+ constructId: secondArg.value,
392
+ parentConstructName: parentClassName,
393
+ },
394
+ });
395
+ return;
396
+ }
397
+ if (formattedParentClassName === formattedConstructId) {
337
398
  context.report({
338
399
  node,
339
400
  messageId: "noParentNameConstructIdMatch",