eslint-cdk-plugin 3.4.4 → 3.4.6

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.
Files changed (62) hide show
  1. package/bin/index.mjs +4318 -0
  2. package/bin/prompt-DVcPfS2N.mjs +847 -0
  3. package/dist/index.cjs +26648 -1606
  4. package/dist/index.d.cts +55 -0
  5. package/dist/index.d.cts.map +1 -0
  6. package/dist/index.d.mts +55 -0
  7. package/dist/index.d.mts.map +1 -0
  8. package/dist/index.mjs +26650 -1584
  9. package/dist/index.mjs.map +1 -0
  10. package/package.json +20 -22
  11. package/src/configs/flat-config.ts +69 -0
  12. package/src/configs/index.ts +6 -0
  13. package/src/{utils/get-child-nodes.ts → core/ast-node/finder/child-nodes.ts} +2 -2
  14. package/src/{utils/getConstructor.ts → core/ast-node/finder/constructor.ts} +1 -1
  15. package/src/core/ast-node/finder/property-name.ts +20 -0
  16. package/src/core/ast-node/finder/public-property.ts +76 -0
  17. package/src/core/cdk-construct/type-checker/is-construct-or-stack.ts +21 -0
  18. package/src/core/cdk-construct/type-checker/is-construct.ts +22 -0
  19. package/src/{utils → core/cdk-construct/type-checker}/is-resource-with-readonly-interface.ts +5 -4
  20. package/src/core/cdk-construct/type-checker/is-resource.ts +17 -0
  21. package/src/core/cdk-construct/type-finder/index.ts +73 -0
  22. package/src/{utils/typecheck/ts-type.ts → core/ts-type/checker/is-array.ts} +2 -8
  23. package/src/core/ts-type/checker/is-class.ts +7 -0
  24. package/src/core/ts-type/checker/is-extends-target-super-class.ts +24 -0
  25. package/src/core/ts-type/checker/private/get-symbol.ts +5 -0
  26. package/src/core/ts-type/finder/array-element.ts +20 -0
  27. package/src/core/ts-type/finder/constructor-property-name.ts +21 -0
  28. package/src/{utils/getGenericTypeArgument.ts → core/ts-type/finder/generics-type-argument.ts} +5 -5
  29. package/src/index.ts +6 -108
  30. package/src/rules/construct-constructor-property.ts +48 -26
  31. package/src/rules/index.ts +34 -0
  32. package/src/rules/no-construct-in-interface.ts +5 -51
  33. package/src/rules/no-construct-in-public-property-of-construct.ts +20 -143
  34. package/src/rules/no-construct-stack-suffix.ts +5 -5
  35. package/src/rules/no-mutable-property-of-props-interface.ts +1 -1
  36. package/src/rules/no-mutable-public-property-of-construct.ts +47 -39
  37. package/src/rules/no-parent-name-construct-id-match.ts +4 -6
  38. package/src/rules/no-unused-props/index.ts +19 -10
  39. package/src/rules/no-unused-props/props-usage-analyzer.ts +207 -190
  40. package/src/rules/no-unused-props/props-usage-tracker.ts +4 -3
  41. package/src/rules/no-unused-props/visitor/direct-props-usage-visitor.ts +145 -0
  42. package/src/rules/no-unused-props/visitor/index.ts +5 -0
  43. package/src/rules/no-unused-props/visitor/instance-variable-usage-visitor.ts +117 -0
  44. package/src/rules/no-unused-props/visitor/interface/node-visitor.ts +9 -0
  45. package/src/rules/no-unused-props/visitor/method-call-collector-visitor.ts +60 -0
  46. package/src/rules/no-unused-props/visitor/props-alias-visitor.ts +81 -0
  47. package/src/rules/no-unused-props/visitor/traverse-nodes.ts +38 -0
  48. package/src/rules/no-variable-construct-id.ts +4 -4
  49. package/src/rules/pascal-case-construct-id.ts +5 -5
  50. package/src/rules/props-name-convention.ts +4 -4
  51. package/src/rules/require-jsdoc.ts +2 -2
  52. package/src/rules/require-passing-this.ts +4 -4
  53. package/src/rules/require-props-default-doc.ts +1 -1
  54. package/bin/migration.mjs +0 -100
  55. package/dist/index.d.ts +0 -47
  56. package/dist/index.d.ts.map +0 -1
  57. package/src/utils/getArrayElementType.ts +0 -14
  58. package/src/utils/getPropertyNames.ts +0 -41
  59. package/src/utils/typecheck/cdk.ts +0 -71
  60. package/src/utils/typecheck/ts-node.ts +0 -7
  61. /package/src/{utils/convertString.ts → shared/converter/to-pascal-case.ts} +0 -0
  62. /package/src/{utils/createRule.ts → shared/create-rule.ts} +0 -0
package/src/index.ts CHANGED
@@ -1,112 +1,7 @@
1
- import tsParser from "@typescript-eslint/parser";
2
1
  import { FlatConfig } from "@typescript-eslint/utils/ts-eslint";
3
2
 
4
- import { name, version } from "../package.json";
5
-
6
- import { constructConstructorProperty } from "./rules/construct-constructor-property";
7
- import { noConstructInInterface } from "./rules/no-construct-in-interface";
8
- import { noConstructInPublicPropertyOfConstruct } from "./rules/no-construct-in-public-property-of-construct";
9
- import { noConstructStackSuffix } from "./rules/no-construct-stack-suffix";
10
- import { noImportPrivate } from "./rules/no-import-private";
11
- import { noMutablePropertyOfPropsInterface } from "./rules/no-mutable-property-of-props-interface";
12
- import { noMutablePublicPropertyOfConstruct } from "./rules/no-mutable-public-property-of-construct";
13
- import { noParentNameConstructIdMatch } from "./rules/no-parent-name-construct-id-match";
14
- import { noUnusedProps } from "./rules/no-unused-props";
15
- import { noVariableConstructId } from "./rules/no-variable-construct-id";
16
- import { pascalCaseConstructId } from "./rules/pascal-case-construct-id";
17
- import { propsNameConvention } from "./rules/props-name-convention";
18
- import { requireJSDoc } from "./rules/require-jsdoc";
19
- import { requirePassingThis } from "./rules/require-passing-this";
20
- import { requirePropsDefaultDoc } from "./rules/require-props-default-doc";
21
-
22
- const rules = {
23
- "construct-constructor-property": constructConstructorProperty,
24
- "no-construct-in-interface": noConstructInInterface,
25
- "no-construct-in-public-property-of-construct":
26
- noConstructInPublicPropertyOfConstruct,
27
- "no-construct-stack-suffix": noConstructStackSuffix,
28
- "no-import-private": noImportPrivate,
29
- "no-mutable-property-of-props-interface": noMutablePropertyOfPropsInterface,
30
- "no-mutable-public-property-of-construct": noMutablePublicPropertyOfConstruct,
31
- "no-parent-name-construct-id-match": noParentNameConstructIdMatch,
32
- "no-unused-props": noUnusedProps,
33
- "no-variable-construct-id": noVariableConstructId,
34
- "pascal-case-construct-id": pascalCaseConstructId,
35
- "props-name-convention": propsNameConvention,
36
- "require-jsdoc": requireJSDoc,
37
- "require-passing-this": requirePassingThis,
38
- "require-props-default-doc": requirePropsDefaultDoc,
39
- };
40
-
41
- const cdkPlugin = {
42
- meta: { name, version },
43
- rules,
44
- };
45
-
46
- const createFlatConfig = (
47
- rules: FlatConfig.Rules
48
- ): {
49
- languageOptions: FlatConfig.LanguageOptions;
50
- plugins: FlatConfig.Plugins;
51
- rules: FlatConfig.Rules;
52
- } => {
53
- return {
54
- languageOptions: {
55
- parser: tsParser,
56
- parserOptions: {
57
- projectService: true,
58
- },
59
- },
60
- plugins: {
61
- cdk: cdkPlugin,
62
- },
63
- rules,
64
- };
65
- };
66
-
67
- const recommended = createFlatConfig({
68
- "cdk/construct-constructor-property": "error",
69
- "cdk/no-construct-in-interface": "error",
70
- "cdk/no-construct-in-public-property-of-construct": "error",
71
- "cdk/no-construct-stack-suffix": "error",
72
- "cdk/no-mutable-property-of-props-interface": "warn",
73
- "cdk/no-mutable-public-property-of-construct": "warn",
74
- "cdk/no-parent-name-construct-id-match": [
75
- "error",
76
- { disallowContainingParentName: false },
77
- ],
78
- // TODO: Enable this rule at v4.0.0
79
- // "cdk/no-unused-props": "error",
80
- "cdk/no-variable-construct-id": "error",
81
- "cdk/pascal-case-construct-id": "error",
82
- "cdk/require-passing-this": ["error", { allowNonThisAndDisallowScope: true }],
83
- });
84
-
85
- const strict = createFlatConfig({
86
- "cdk/construct-constructor-property": "error",
87
- "cdk/no-construct-in-interface": "error",
88
- "cdk/no-construct-in-public-property-of-construct": "error",
89
- "cdk/no-construct-stack-suffix": "error",
90
- "cdk/no-import-private": "error",
91
- "cdk/no-mutable-property-of-props-interface": "error",
92
- "cdk/no-mutable-public-property-of-construct": "error",
93
- "cdk/no-parent-name-construct-id-match": [
94
- "error",
95
- { disallowContainingParentName: true },
96
- ],
97
- "cdk/no-unused-props": "error",
98
- "cdk/no-variable-construct-id": "error",
99
- "cdk/pascal-case-construct-id": "error",
100
- "cdk/props-name-convention": "error",
101
- "cdk/require-jsdoc": "error",
102
- "cdk/require-passing-this": "error",
103
- "cdk/require-props-default-doc": "error",
104
- });
105
-
106
- const configs = {
107
- recommended,
108
- strict,
109
- };
3
+ import { configs } from "./configs";
4
+ import { rules } from "./rules";
110
5
 
111
6
  export { configs, rules };
112
7
 
@@ -120,7 +15,10 @@ export interface EslintCdkPlugin {
120
15
 
121
16
  const eslintCdkPlugin: EslintCdkPlugin = {
122
17
  rules,
123
- configs,
18
+ configs: {
19
+ recommended: configs.recommended,
20
+ strict: configs.strict,
21
+ },
124
22
  };
125
23
 
126
24
  export default eslintCdkPlugin;
@@ -6,9 +6,9 @@ import {
6
6
  TSESTree,
7
7
  } from "@typescript-eslint/utils";
8
8
 
9
- import { createRule } from "../utils/createRule";
10
- import { getConstructor } from "../utils/getConstructor";
11
- import { isConstructType } from "../utils/typecheck/cdk";
9
+ import { findConstructor } from "../core/ast-node/finder/constructor";
10
+ import { isConstructType } from "../core/cdk-construct/type-checker/is-construct";
11
+ import { createRule } from "../shared/create-rule";
12
12
 
13
13
  type Context = TSESLint.RuleContext<
14
14
  | "invalidConstructorProperty"
@@ -17,6 +17,12 @@ type Context = TSESLint.RuleContext<
17
17
  []
18
18
  >;
19
19
 
20
+ type ConstructorProperties = [
21
+ TSESTree.Parameter,
22
+ TSESTree.Parameter,
23
+ TSESTree.Parameter | undefined
24
+ ];
25
+
20
26
  /**
21
27
  * Enforces that constructors of classes extending Construct have the property names 'scope, id' or 'scope, id, props'
22
28
  * @param context - The rule context provided by ESLint
@@ -48,36 +54,46 @@ export const constructConstructorProperty = createRule({
48
54
  const type = parserServices.getTypeAtLocation(node);
49
55
  if (!isConstructType(type)) return;
50
56
 
51
- const constructor = getConstructor(node);
57
+ const constructor = findConstructor(node);
52
58
  if (!constructor) return;
53
59
 
54
- validateConstructorProperty(constructor, context, parserServices);
60
+ const params = checkNumOfConstructorProperty(constructor, context);
61
+ if (params) {
62
+ checkFirstParamIsScope(params[0], context, parserServices);
63
+ checkSecondParamIsId(params[1], context);
64
+ checkThirdParamIsProps(params[2], context);
65
+ }
55
66
  },
56
67
  };
57
68
  },
58
69
  });
59
70
 
60
71
  /**
61
- * Validates that the constructor has the property names "scope, id" or "scope, id, props"
72
+ * Checks if the number of constructor properties is valid (at least 2)
62
73
  */
63
- const validateConstructorProperty = (
74
+ const checkNumOfConstructorProperty = (
64
75
  constructor: TSESTree.MethodDefinition,
65
- context: Context,
66
- parserServices: ParserServicesWithTypeInformation
67
- ): void => {
76
+ context: Context
77
+ ): ConstructorProperties | undefined => {
68
78
  const params = constructor.value.params;
69
-
70
- // NOTE: Check if the constructor has at least 2 parameters
71
79
  if (params.length < 2) {
72
80
  context.report({
73
81
  node: constructor.value,
74
82
  messageId: "invalidConstructorProperty",
75
83
  });
76
- return;
84
+ return undefined;
77
85
  }
86
+ return [params[0], params[1], params[2]];
87
+ };
78
88
 
79
- // NOTE: Check if the first parameter is named "scope"
80
- const firstParam = params[0];
89
+ /**
90
+ * Checks if the first parameter is named "scope" and of type Construct
91
+ */
92
+ const checkFirstParamIsScope = (
93
+ firstParam: ConstructorProperties[0],
94
+ context: Context,
95
+ parserServices: ParserServicesWithTypeInformation
96
+ ) => {
81
97
  if (
82
98
  firstParam.type !== AST_NODE_TYPES.Identifier ||
83
99
  firstParam.name !== "scope"
@@ -92,9 +108,15 @@ const validateConstructorProperty = (
92
108
  messageId: "invalidConstructorType",
93
109
  });
94
110
  }
111
+ };
95
112
 
96
- // NOTE: Check if the second parameter is named "id"
97
- const secondParam = params[1];
113
+ /**
114
+ * Checks if the second parameter is named "id" and of type string
115
+ */
116
+ const checkSecondParamIsId = (
117
+ secondParam: ConstructorProperties[1],
118
+ context: Context
119
+ ) => {
98
120
  if (
99
121
  secondParam.type !== AST_NODE_TYPES.Identifier ||
100
122
  secondParam.name !== "id"
@@ -103,7 +125,6 @@ const validateConstructorProperty = (
103
125
  node: secondParam,
104
126
  messageId: "invalidConstructorProperty",
105
127
  });
106
- return;
107
128
  } else if (
108
129
  secondParam.typeAnnotation?.typeAnnotation.type !==
109
130
  AST_NODE_TYPES.TSStringKeyword
@@ -112,15 +133,17 @@ const validateConstructorProperty = (
112
133
  node: secondParam,
113
134
  messageId: "invalidConstructorIdType",
114
135
  });
115
- return;
116
136
  }
137
+ };
117
138
 
118
- if (params.length < 3)
119
- // NOTE: If there's no third parameter, return
120
- return;
121
-
122
- // NOTE: Check if the third parameter is named "props"
123
- const thirdParam = params[2];
139
+ /**
140
+ * Checks if the third parameter is named "props"
141
+ */
142
+ const checkThirdParamIsProps = (
143
+ thirdParam: ConstructorProperties[2],
144
+ context: Context
145
+ ) => {
146
+ if (!thirdParam) return;
124
147
  if (
125
148
  thirdParam.type !== AST_NODE_TYPES.Identifier ||
126
149
  thirdParam.name !== "props"
@@ -129,6 +152,5 @@ const validateConstructorProperty = (
129
152
  node: thirdParam,
130
153
  messageId: "invalidConstructorProperty",
131
154
  });
132
- return;
133
155
  }
134
156
  };
@@ -0,0 +1,34 @@
1
+ import { constructConstructorProperty } from "./construct-constructor-property";
2
+ import { noConstructInInterface } from "./no-construct-in-interface";
3
+ import { noConstructInPublicPropertyOfConstruct } from "./no-construct-in-public-property-of-construct";
4
+ import { noConstructStackSuffix } from "./no-construct-stack-suffix";
5
+ import { noImportPrivate } from "./no-import-private";
6
+ import { noMutablePropertyOfPropsInterface } from "./no-mutable-property-of-props-interface";
7
+ import { noMutablePublicPropertyOfConstruct } from "./no-mutable-public-property-of-construct";
8
+ import { noParentNameConstructIdMatch } from "./no-parent-name-construct-id-match";
9
+ import { noUnusedProps } from "./no-unused-props";
10
+ import { noVariableConstructId } from "./no-variable-construct-id";
11
+ import { pascalCaseConstructId } from "./pascal-case-construct-id";
12
+ import { propsNameConvention } from "./props-name-convention";
13
+ import { requireJSDoc } from "./require-jsdoc";
14
+ import { requirePassingThis } from "./require-passing-this";
15
+ import { requirePropsDefaultDoc } from "./require-props-default-doc";
16
+
17
+ export const rules = {
18
+ "construct-constructor-property": constructConstructorProperty,
19
+ "no-construct-in-interface": noConstructInInterface,
20
+ "no-construct-in-public-property-of-construct":
21
+ noConstructInPublicPropertyOfConstruct,
22
+ "no-construct-stack-suffix": noConstructStackSuffix,
23
+ "no-import-private": noImportPrivate,
24
+ "no-mutable-property-of-props-interface": noMutablePropertyOfPropsInterface,
25
+ "no-mutable-public-property-of-construct": noMutablePublicPropertyOfConstruct,
26
+ "no-parent-name-construct-id-match": noParentNameConstructIdMatch,
27
+ "no-unused-props": noUnusedProps,
28
+ "no-variable-construct-id": noVariableConstructId,
29
+ "pascal-case-construct-id": pascalCaseConstructId,
30
+ "props-name-convention": propsNameConvention,
31
+ "require-jsdoc": requireJSDoc,
32
+ "require-passing-this": requirePassingThis,
33
+ "require-props-default-doc": requirePropsDefaultDoc,
34
+ };
@@ -1,10 +1,7 @@
1
1
  import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
2
2
 
3
- import { createRule } from "../utils/createRule";
4
- import { getArrayElementType } from "../utils/getArrayElementType";
5
- import { getGenericTypeArgument } from "../utils/getGenericTypeArgument";
6
- import { isResourceWithReadonlyInterface } from "../utils/is-resource-with-readonly-interface";
7
- import { isClassType } from "../utils/typecheck/ts-type";
3
+ import { findTypeOfCdkConstruct } from "../core/cdk-construct/type-finder";
4
+ import { createRule } from "../shared/create-rule";
8
5
 
9
6
  /**
10
7
  * Enforces the use of interface types instead of CDK Construct types in interface properties
@@ -38,58 +35,15 @@ export const noConstructInInterface = createRule({
38
35
  }
39
36
 
40
37
  const type = parserServices.getTypeAtLocation(property);
38
+ const result = findTypeOfCdkConstruct(type);
41
39
 
42
- // NOTE: Check if it's a direct class type
43
- if (isClassType(type) && isResourceWithReadonlyInterface(type)) {
40
+ if (result) {
44
41
  context.report({
45
42
  node: property,
46
43
  messageId: "invalidInterfaceProperty",
47
44
  data: {
48
45
  propertyName: property.key.name,
49
- typeName: type.symbol.name,
50
- },
51
- });
52
- continue;
53
- }
54
-
55
- // NOTE: Check if it's an array of class types
56
- const elementType = getArrayElementType(type);
57
- if (
58
- elementType &&
59
- isClassType(elementType) &&
60
- isResourceWithReadonlyInterface(elementType)
61
- ) {
62
- context.report({
63
- node: property,
64
- messageId: "invalidInterfaceProperty",
65
- data: {
66
- propertyName: property.key.name,
67
- typeName: `${elementType.symbol.name}[]`,
68
- },
69
- });
70
- continue;
71
- }
72
-
73
- // NOTE: Check if it's a generic type wrapping a class type
74
- const genericArgument = getGenericTypeArgument(type);
75
- if (
76
- genericArgument &&
77
- isClassType(genericArgument) &&
78
- isResourceWithReadonlyInterface(genericArgument)
79
- ) {
80
- const wrapperName = (() => {
81
- if (type.aliasSymbol) return type.aliasSymbol.name; // For type aliases like Readonly<T>, Partial<T>
82
- if (type.symbol?.name) return type.symbol.name; // For other generic types like Array<T>
83
- return undefined;
84
- })();
85
- context.report({
86
- node: property,
87
- messageId: "invalidInterfaceProperty",
88
- data: {
89
- propertyName: property.key.name,
90
- typeName: wrapperName
91
- ? `${wrapperName}<${genericArgument.symbol.name}>`
92
- : genericArgument.symbol.name,
46
+ typeName: result.symbol.name,
93
47
  },
94
48
  });
95
49
  }
@@ -1,22 +1,22 @@
1
1
  import {
2
- AST_NODE_TYPES,
3
2
  ESLintUtils,
4
3
  ParserServicesWithTypeInformation,
5
4
  TSESLint,
6
5
  TSESTree,
7
6
  } from "@typescript-eslint/utils";
8
- import { Type } from "typescript";
9
7
 
10
- import { createRule } from "../utils/createRule";
11
- import { getArrayElementType } from "../utils/getArrayElementType";
12
- import { getConstructor } from "../utils/getConstructor";
13
- import { getGenericTypeArgument } from "../utils/getGenericTypeArgument";
14
- import { isResourceWithReadonlyInterface } from "../utils/is-resource-with-readonly-interface";
15
- import { isConstructOrStackType } from "../utils/typecheck/cdk";
16
- import { isClassType } from "../utils/typecheck/ts-type";
8
+ import { findPublicPropertiesInClass } from "../core/ast-node/finder/public-property";
9
+ import { isConstructOrStackType } from "../core/cdk-construct/type-checker/is-construct-or-stack";
10
+ import { findTypeOfCdkConstruct } from "../core/cdk-construct/type-finder";
11
+ import { createRule } from "../shared/create-rule";
17
12
 
18
13
  type Context = TSESLint.RuleContext<"invalidPublicPropertyOfConstruct", []>;
19
14
 
15
+ type PublicProperty = {
16
+ name: string;
17
+ node: TSESTree.Parameter | TSESTree.ClassElement;
18
+ };
19
+
20
20
  /**
21
21
  * Disallow Construct types in public property of Construct
22
22
  * @param context - The rule context provided by ESLint
@@ -42,152 +42,29 @@ export const noConstructInPublicPropertyOfConstruct = createRule({
42
42
  ClassDeclaration(node) {
43
43
  const type = parserServices.getTypeAtLocation(node);
44
44
  if (!isConstructOrStackType(type)) return;
45
-
46
- // NOTE: Check class members
47
- validatePublicPropertyOfConstruct(node, context, parserServices);
48
-
49
- // NOTE: Check constructor parameter properties
50
- const constructor = getConstructor(node);
51
- if (
52
- !constructor ||
53
- constructor.value.type !== AST_NODE_TYPES.FunctionExpression
54
- ) {
55
- return;
45
+ const publicProperties = findPublicPropertiesInClass(node);
46
+ for (const publicProperty of publicProperties) {
47
+ validatePublicProperty(publicProperty, context, parserServices);
56
48
  }
57
-
58
- validateConstructorParameterProperty(
59
- constructor,
60
- context,
61
- parserServices
62
- );
63
49
  },
64
50
  };
65
51
  },
66
52
  });
67
53
 
68
- /**
69
- * check the public property of Construct
70
- * - if it is a Construct type, report an error
71
- */
72
- const validatePublicPropertyOfConstruct = (
73
- node: TSESTree.ClassDeclaration,
54
+ const validatePublicProperty = (
55
+ publicProperty: PublicProperty,
74
56
  context: Context,
75
57
  parserServices: ParserServicesWithTypeInformation
76
58
  ) => {
77
- for (const property of node.body.body) {
78
- if (
79
- property.type !== AST_NODE_TYPES.PropertyDefinition ||
80
- property.key.type !== AST_NODE_TYPES.Identifier
81
- ) {
82
- continue;
83
- }
84
-
85
- // NOTE: Skip private and protected fields
86
- if (["private", "protected"].includes(property.accessibility ?? "")) {
87
- continue;
88
- }
89
-
90
- // NOTE: Skip fields without type annotation
91
- if (!property.typeAnnotation) continue;
92
-
93
- const type = parserServices.getTypeAtLocation(property);
94
- checkAndReportConstructType(type, property, property.key.name, context);
95
- }
96
- };
97
-
98
- /**
99
- * check the constructor parameter property
100
- * - if it is a Construct type, report an error
101
- */
102
- const validateConstructorParameterProperty = (
103
- constructor: TSESTree.MethodDefinition,
104
- context: Context,
105
- parserServices: ParserServicesWithTypeInformation
106
- ) => {
107
- for (const param of constructor.value.params) {
108
- if (
109
- param.type !== AST_NODE_TYPES.TSParameterProperty ||
110
- param.parameter.type !== AST_NODE_TYPES.Identifier
111
- ) {
112
- continue;
113
- }
114
-
115
- // NOTE: Skip private and protected parameters
116
- if (["private", "protected"].includes(param.accessibility ?? "")) {
117
- continue;
118
- }
119
-
120
- // NOTE: Skip parameters without type annotation
121
- if (!param.parameter.typeAnnotation) continue;
122
-
123
- const type = parserServices.getTypeAtLocation(param);
124
- checkAndReportConstructType(type, param, param.parameter.name, context);
125
- }
126
- };
127
-
128
- /**
129
- * Common validation logic for checking if a type is a Construct type
130
- */
131
- const checkAndReportConstructType = (
132
- type: Type,
133
- node: TSESTree.Node,
134
- propertyName: string,
135
- context: Context
136
- ): void => {
137
- // NOTE: Check if it's a direct class type
138
- if (isClassType(type) && isResourceWithReadonlyInterface(type)) {
139
- context.report({
140
- node,
141
- messageId: "invalidPublicPropertyOfConstruct",
142
- data: {
143
- propertyName,
144
- typeName: type.symbol.name,
145
- },
146
- });
147
- return;
148
- }
149
-
150
- // NOTE: Check if it's an array of class types
151
- const elementType = getArrayElementType(type);
152
- if (
153
- elementType &&
154
- isClassType(elementType) &&
155
- isResourceWithReadonlyInterface(elementType)
156
- ) {
157
- context.report({
158
- node,
159
- messageId: "invalidPublicPropertyOfConstruct",
160
- data: {
161
- propertyName,
162
- typeName: `${elementType.symbol.name}[]`,
163
- },
164
- });
165
- return;
166
- }
167
-
168
- // NOTE: Check if it's a generic type wrapping a class type
169
- const genericArgument = getGenericTypeArgument(type);
170
- if (
171
- genericArgument &&
172
- isClassType(genericArgument) &&
173
- isResourceWithReadonlyInterface(genericArgument)
174
- ) {
175
- const wrapperName = (() => {
176
- if ("aliasSymbol" in type && type.aliasSymbol) {
177
- return type.aliasSymbol.name; // For type aliases like Readonly<T>, Partial<T>
178
- }
179
- if (type.symbol?.name) return type.symbol.name; // For other generic types like Array<T>
180
- return undefined;
181
- })();
182
-
59
+ const type = parserServices.getTypeAtLocation(publicProperty.node);
60
+ const constructType = findTypeOfCdkConstruct(type);
61
+ if (constructType) {
183
62
  context.report({
184
- node,
63
+ node: publicProperty.node,
185
64
  messageId: "invalidPublicPropertyOfConstruct",
186
65
  data: {
187
- propertyName,
188
- typeName: wrapperName
189
- ? `${wrapperName}<${genericArgument.symbol.name}>`
190
- : genericArgument.symbol.name,
66
+ propertyName: publicProperty.name,
67
+ typeName: constructType.symbol.name,
191
68
  },
192
69
  });
193
70
  }
@@ -5,10 +5,10 @@ import {
5
5
  TSESTree,
6
6
  } from "@typescript-eslint/utils";
7
7
 
8
- import { toPascalCase } from "../utils/convertString";
9
- import { createRule } from "../utils/createRule";
10
- import { getConstructorPropertyNames } from "../utils/getPropertyNames";
11
- import { isConstructOrStackType } from "../utils/typecheck/cdk";
8
+ import { isConstructOrStackType } from "../core/cdk-construct/type-checker/is-construct-or-stack";
9
+ import { findConstructorPropertyNames } from "../core/ts-type/finder/constructor-property-name";
10
+ import { toPascalCase } from "../shared/converter/to-pascal-case";
11
+ import { createRule } from "../shared/create-rule";
12
12
 
13
13
  const SUFFIX_TYPE = {
14
14
  CONSTRUCT: "Construct",
@@ -72,7 +72,7 @@ export const noConstructStackSuffix = createRule({
72
72
  return;
73
73
  }
74
74
 
75
- const constructorPropertyNames = getConstructorPropertyNames(type);
75
+ const constructorPropertyNames = findConstructorPropertyNames(type);
76
76
  if (constructorPropertyNames[1] !== "id") return;
77
77
 
78
78
  validateConstructId(node, context);
@@ -1,6 +1,6 @@
1
1
  import { AST_NODE_TYPES } from "@typescript-eslint/utils";
2
2
 
3
- import { createRule } from "../utils/createRule";
3
+ import { createRule } from "../shared/create-rule";
4
4
 
5
5
  /**
6
6
  * Disallow mutable properties of Construct Props (interface)