eslint-cdk-plugin 0.1.0 → 0.4.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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # eslint-plugin-cdk
1
+ # eslint-cdk-plugin
2
2
 
3
3
  ESLint plugin for [AWS CDK](https://github.com/aws/aws-cdk).
4
4
 
@@ -6,13 +6,13 @@ ESLint plugin for [AWS CDK](https://github.com/aws/aws-cdk).
6
6
 
7
7
  ```bash
8
8
  # npm
9
- npm install -D @nigg/eslint-plugin-cdk
9
+ npm install --save-dev eslint-cdk-plugin
10
10
 
11
11
  # yarn
12
- yarn add -D @nigg/eslint-plugin-cdk
12
+ yarn add -D eslint-cdk-plugin
13
13
 
14
14
  # pnpm
15
- pnpm install -D @nigg/eslint-plugin-cdk
15
+ pnpm install -D eslint-cdk-plugin
16
16
  ```
17
17
 
18
18
  ## Usage
@@ -21,17 +21,17 @@ pnpm install -D @nigg/eslint-plugin-cdk
21
21
 
22
22
  ```js
23
23
  // eslint.config.mjs
24
- import eslintPluginCdk from "@nigg/eslint-plugin-cdk";
24
+ import eslintCdkPlugin from "eslint-cdk-plugin";
25
25
  export default [
26
26
  {
27
27
  plugins: {
28
- cdk: eslintPluginCdk,
28
+ cdk: eslintCdkPlugin,
29
29
  },
30
30
  rules: {
31
- ...eslintPluginCdk.configs.recommended.rules,
31
+ ...eslintCdkPlugin.configs.recommended.rules,
32
32
  },
33
33
  },
34
34
  ];
35
35
  ```
36
36
 
37
- ### For more detailed documentation, see [docs for eslint-plugin-cdk](https://eslint-plugin-cdk.dev/)
37
+ ### For more detailed documentation, see [docs for eslint-cdk-plugin](https://eslint-cdk-plugin.dev/)
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { noClassInInterfaceProps } from "./no-class-in-interface.mjs";
1
+ import { noClassInInterfaceProps } from "./no-class-in-interface-props.mjs";
2
2
  import { noConstructStackSuffix } from "./no-construct-stack-suffix.mjs";
3
3
  import { noImportPrivate } from "./no-import-private.mjs";
4
4
  import { noMutablePropsInterface } from "./no-mutable-props-interface.mjs";
@@ -1,5 +1,11 @@
1
- import { ESLintUtils } from "@typescript-eslint/utils";
1
+ import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
2
2
  import { SymbolFlags } from "typescript";
3
+ /**
4
+ * Enforces the use of interface types instead of class in interface properties
5
+ * @param context - The rule context provided by ESLint
6
+ * @returns An object containing the AST visitor functions
7
+ * @see {@link https://eslint-cdk-plugin.dev/rules/no-class-in-interface} - Documentation
8
+ */
3
9
  export var noClassInInterfaceProps = ESLintUtils.RuleCreator.withoutDocs({
4
10
  meta: {
5
11
  type: "problem",
@@ -19,8 +25,9 @@ export var noClassInInterfaceProps = ESLintUtils.RuleCreator.withoutDocs({
19
25
  TSInterfaceDeclaration: function (node) {
20
26
  for (var _i = 0, _a = node.body.body; _i < _a.length; _i++) {
21
27
  var property = _a[_i];
22
- if (property.type !== "TSPropertySignature" ||
23
- property.key.type !== "Identifier") {
28
+ // NOTE: check property signature
29
+ if (property.type !== AST_NODE_TYPES.TSPropertySignature ||
30
+ property.key.type !== AST_NODE_TYPES.Identifier) {
24
31
  continue;
25
32
  }
26
33
  var tsNode = parserServices.esTreeNodeToTSNodeMap.get(property);
@@ -1,5 +1,12 @@
1
- import { ESLintUtils } from "@typescript-eslint/utils";
1
+ import { AST_NODE_TYPES, ESLintUtils, } from "@typescript-eslint/utils";
2
2
  import { toPascalCase } from "./utils/convertString.mjs";
3
+ import { isConstructOrStackType } from "./utils/isConstructOrStackType.mjs";
4
+ /**
5
+ * Enforces that Construct IDs do not end with 'Construct' or 'Stack' suffix
6
+ * @param context - The rule context provided by ESLint
7
+ * @returns An object containing the AST visitor functions
8
+ * @see {@link https://eslint-cdk-plugin.dev/rules/no-construct-stack-suffix} - Documentation
9
+ */
3
10
  export var noConstructStackSuffix = ESLintUtils.RuleCreator.withoutDocs({
4
11
  meta: {
5
12
  type: "problem",
@@ -13,148 +20,21 @@ export var noConstructStackSuffix = ESLintUtils.RuleCreator.withoutDocs({
13
20
  },
14
21
  defaultOptions: [],
15
22
  create: function (context) {
23
+ var parserServices = ESLintUtils.getParserServices(context);
24
+ var checker = parserServices.program.getTypeChecker();
16
25
  return {
17
- ClassBody: function (node) {
18
- var _a;
19
- var parent = node.parent;
20
- if ((parent === null || parent === void 0 ? void 0 : parent.type) !== "ClassDeclaration")
21
- return;
22
- var className = (_a = parent.id) === null || _a === void 0 ? void 0 : _a.name;
23
- if (!className)
26
+ NewExpression: function (node) {
27
+ var type = checker.getTypeAtLocation(parserServices.esTreeNodeToTSNodeMap.get(node));
28
+ if (!isConstructOrStackType(type)) {
24
29
  return;
25
- for (var _i = 0, _b = node.body; _i < _b.length; _i++) {
26
- var body = _b[_i];
27
- if (body.type !== "MethodDefinition" ||
28
- !["method", "constructor"].includes(body.kind) ||
29
- body.value.type !== "FunctionExpression") {
30
- continue;
31
- }
32
- validateConstructorBody(node, body.value, context);
33
30
  }
31
+ if (node.arguments.length < 2)
32
+ return;
33
+ validateConstructId(node, context, node);
34
34
  },
35
35
  };
36
36
  },
37
37
  });
38
- /**
39
- * Validate the constructor body for the parent class
40
- * - validate each statement in the constructor body
41
- */
42
- var validateConstructorBody = function (node, expression, context) {
43
- var _a;
44
- for (var _i = 0, _b = expression.body.body; _i < _b.length; _i++) {
45
- var statement = _b[_i];
46
- switch (statement.type) {
47
- case "VariableDeclaration": {
48
- var newExpression = statement.declarations[0].init;
49
- if ((newExpression === null || newExpression === void 0 ? void 0 : newExpression.type) !== "NewExpression")
50
- continue;
51
- validateConstructId(node, context, newExpression);
52
- break;
53
- }
54
- case "ExpressionStatement": {
55
- if (((_a = statement.expression) === null || _a === void 0 ? void 0 : _a.type) !== "NewExpression")
56
- break;
57
- validateStatement(node, statement, context);
58
- break;
59
- }
60
- case "IfStatement": {
61
- traverseStatements(node, statement.consequent, context);
62
- break;
63
- }
64
- case "SwitchStatement": {
65
- for (var _c = 0, _d = statement.cases; _c < _d.length; _c++) {
66
- var switchCase = _d[_c];
67
- for (var _e = 0, _f = switchCase.consequent; _e < _f.length; _e++) {
68
- var statement_1 = _f[_e];
69
- traverseStatements(node, statement_1, context);
70
- }
71
- }
72
- break;
73
- }
74
- }
75
- }
76
- };
77
- /**
78
- * Recursively traverse and validate statements in the AST
79
- * - Handles BlockStatement, ExpressionStatement, and VariableDeclaration
80
- * - Validates construct IDs
81
- */
82
- var traverseStatements = function (node, statement, context) {
83
- switch (statement.type) {
84
- case "BlockStatement": {
85
- for (var _i = 0, _a = statement.body; _i < _a.length; _i++) {
86
- var body = _a[_i];
87
- validateStatement(node, body, context);
88
- }
89
- break;
90
- }
91
- case "ExpressionStatement": {
92
- var newExpression = statement.expression;
93
- if ((newExpression === null || newExpression === void 0 ? void 0 : newExpression.type) !== "NewExpression")
94
- break;
95
- validateStatement(node, statement, context);
96
- break;
97
- }
98
- case "VariableDeclaration": {
99
- var newExpression = statement.declarations[0].init;
100
- if ((newExpression === null || newExpression === void 0 ? void 0 : newExpression.type) !== "NewExpression")
101
- break;
102
- validateConstructId(node, context, newExpression);
103
- break;
104
- }
105
- }
106
- };
107
- /**
108
- * Validate a single statement in the AST
109
- * - Handles different types of statements (Variable, Expression, If, Switch)
110
- * - Extracts and validates construct IDs from new expressions
111
- */
112
- var validateStatement = function (node, body, context) {
113
- switch (body.type) {
114
- case "VariableDeclaration": {
115
- var newExpression = body.declarations[0].init;
116
- if ((newExpression === null || newExpression === void 0 ? void 0 : newExpression.type) !== "NewExpression")
117
- break;
118
- validateConstructId(node, context, newExpression);
119
- break;
120
- }
121
- case "ExpressionStatement": {
122
- var newExpression = body.expression;
123
- if ((newExpression === null || newExpression === void 0 ? void 0 : newExpression.type) !== "NewExpression")
124
- break;
125
- validateConstructId(node, context, newExpression);
126
- break;
127
- }
128
- case "IfStatement": {
129
- validateIfStatement(node, body, context);
130
- break;
131
- }
132
- case "SwitchStatement": {
133
- validateSwitchStatement(node, body, context);
134
- break;
135
- }
136
- }
137
- };
138
- /**
139
- * Validate the `if` statement
140
- * - Validate recursively if `if` statements are nested
141
- */
142
- var validateIfStatement = function (node, ifStatement, context) {
143
- traverseStatements(node, ifStatement.consequent, context);
144
- };
145
- /**
146
- * Validate the `switch` statement
147
- * - Validate recursively if `switch` statements are nested
148
- */
149
- var validateSwitchStatement = function (node, switchStatement, context) {
150
- for (var _i = 0, _a = switchStatement.cases; _i < _a.length; _i++) {
151
- var statement = _a[_i];
152
- for (var _b = 0, _c = statement.consequent; _b < _c.length; _b++) {
153
- var _consequent = _c[_b];
154
- traverseStatements(node, _consequent, context);
155
- }
156
- }
157
- };
158
38
  /**
159
39
  * Validate that construct ID does not end with "Construct" or "Stack"
160
40
  */
@@ -163,7 +43,8 @@ var validateConstructId = function (node, context, expression) {
163
43
  return;
164
44
  // NOTE: Treat the second argument as ID
165
45
  var secondArg = expression.arguments[1];
166
- if (secondArg.type !== "Literal" || typeof secondArg.value !== "string") {
46
+ if (secondArg.type !== AST_NODE_TYPES.Literal ||
47
+ typeof secondArg.value !== "string") {
167
48
  return;
168
49
  }
169
50
  var formattedConstructId = toPascalCase(secondArg.value);
@@ -1,12 +1,10 @@
1
1
  import * as path from "path";
2
2
  /**
3
- * Split the directory path into segments (split at `/`)
4
- * @param dirPath - The directory path to split
5
- * @returns The segments of the directory path
3
+ * Disallow importing modules from private directories at different levels of the hierarchy.
4
+ * @param context - The rule context provided by ESLint
5
+ * @returns An object containing the AST visitor functions
6
+ * @see {@link https://eslint-cdk-plugin.dev/rules/no-import-private} - Documentation
6
7
  */
7
- var getDirSegments = function (dirPath) {
8
- return dirPath.split(path.sep).filter(function (segment) { return segment !== ""; });
9
- };
10
8
  export var noImportPrivate = {
11
9
  meta: {
12
10
  type: "problem",
@@ -41,3 +39,11 @@ export var noImportPrivate = {
41
39
  };
42
40
  },
43
41
  };
42
+ /**
43
+ * Split the directory path into segments (split at `/`)
44
+ * @param dirPath - The directory path to split
45
+ * @returns The segments of the directory path
46
+ */
47
+ var getDirSegments = function (dirPath) {
48
+ return dirPath.split(path.sep).filter(function (segment) { return segment !== ""; });
49
+ };
@@ -1,4 +1,10 @@
1
- import { ESLintUtils } from "@typescript-eslint/utils";
1
+ import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
2
+ /**
3
+ * Disallow mutable properties in Props interfaces
4
+ * @param context - The rule context provided by ESLint
5
+ * @returns An object containing the AST visitor functions
6
+ * @see {@link https://eslint-cdk-plugin.dev/rules/no-mutable-props-interface} - Documentation
7
+ */
2
8
  export var noMutablePropsInterface = ESLintUtils.RuleCreator.withoutDocs({
3
9
  meta: {
4
10
  type: "problem",
@@ -20,8 +26,9 @@ export var noMutablePropsInterface = ESLintUtils.RuleCreator.withoutDocs({
20
26
  if (!node.id.name.endsWith("Props"))
21
27
  return;
22
28
  var _loop_1 = function (property) {
23
- if (property.type !== "TSPropertySignature" ||
24
- property.key.type !== "Identifier") {
29
+ // NOTE: check property signature
30
+ if (property.type !== AST_NODE_TYPES.TSPropertySignature ||
31
+ property.key.type !== AST_NODE_TYPES.Identifier) {
25
32
  return "continue";
26
33
  }
27
34
  // NOTE: Skip if already readonly
@@ -1,4 +1,11 @@
1
- import { ESLintUtils } from "@typescript-eslint/utils";
1
+ import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
2
+ import { isConstructOrStackType } from "./utils/isConstructOrStackType.mjs";
3
+ /**
4
+ * Disallow mutable public class fields
5
+ * @param context - The rule context provided by ESLint
6
+ * @returns An object containing the AST visitor functions
7
+ * @see {@link https://eslint-cdk-plugin.dev/rules/no-mutable-public-fields} - Documentation
8
+ */
2
9
  export var noMutablePublicFields = ESLintUtils.RuleCreator.withoutDocs({
3
10
  meta: {
4
11
  type: "problem",
@@ -13,13 +20,20 @@ export var noMutablePublicFields = ESLintUtils.RuleCreator.withoutDocs({
13
20
  },
14
21
  defaultOptions: [],
15
22
  create: function (context) {
23
+ var parserServices = ESLintUtils.getParserServices(context);
24
+ var checker = parserServices.program.getTypeChecker();
16
25
  var sourceCode = context.sourceCode;
17
26
  return {
18
27
  ClassDeclaration: function (node) {
19
28
  var _a;
29
+ var type = checker.getTypeAtLocation(parserServices.esTreeNodeToTSNodeMap.get(node));
30
+ if (!isConstructOrStackType(type)) {
31
+ return;
32
+ }
20
33
  var _loop_1 = function (member) {
21
- if (member.type !== "PropertyDefinition" ||
22
- member.key.type !== "Identifier") {
34
+ // NOTE: check property definition
35
+ if (member.type !== AST_NODE_TYPES.PropertyDefinition ||
36
+ member.key.type !== AST_NODE_TYPES.Identifier) {
23
37
  return "continue";
24
38
  }
25
39
  // NOTE: Skip private and protected fields
@@ -1,5 +1,11 @@
1
- import { ESLintUtils } from "@typescript-eslint/utils";
1
+ import { AST_NODE_TYPES, ESLintUtils, } from "@typescript-eslint/utils";
2
2
  import { toPascalCase } from "./utils/convertString.mjs";
3
+ /**
4
+ * Enforce that construct IDs does not match the parent construct name.
5
+ * @param context - The rule context provided by ESLint
6
+ * @returns An object containing the AST visitor functions
7
+ * @see {@link https://eslint-cdk-plugin.dev/rules/no-parent-name-construct-id-match} - Documentation
8
+ */
3
9
  export var noParentNameConstructIdMatch = ESLintUtils.RuleCreator.withoutDocs({
4
10
  meta: {
5
11
  type: "problem",
@@ -17,16 +23,17 @@ export var noParentNameConstructIdMatch = ESLintUtils.RuleCreator.withoutDocs({
17
23
  ClassBody: function (node) {
18
24
  var _a;
19
25
  var parent = node.parent;
20
- if ((parent === null || parent === void 0 ? void 0 : parent.type) !== "ClassDeclaration")
26
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) !== AST_NODE_TYPES.ClassDeclaration)
21
27
  return;
22
28
  var parentClassName = (_a = parent.id) === null || _a === void 0 ? void 0 : _a.name;
23
29
  if (!parentClassName)
24
30
  return;
25
31
  for (var _i = 0, _b = node.body; _i < _b.length; _i++) {
26
32
  var body = _b[_i];
27
- if (body.type !== "MethodDefinition" ||
33
+ // NOTE: Ignore if neither method nor constructor.
34
+ if (body.type !== AST_NODE_TYPES.MethodDefinition ||
28
35
  !["method", "constructor"].includes(body.kind) ||
29
- body.value.type !== "FunctionExpression") {
36
+ body.value.type !== AST_NODE_TYPES.FunctionExpression) {
30
37
  continue;
31
38
  }
32
39
  validateConstructorBody({
@@ -50,9 +57,9 @@ var validateConstructorBody = function (_a) {
50
57
  for (var _i = 0, _c = expression.body.body; _i < _c.length; _i++) {
51
58
  var statement = _c[_i];
52
59
  switch (statement.type) {
53
- case "VariableDeclaration": {
60
+ case AST_NODE_TYPES.VariableDeclaration: {
54
61
  var newExpression = statement.declarations[0].init;
55
- if ((newExpression === null || newExpression === void 0 ? void 0 : newExpression.type) !== "NewExpression")
62
+ if ((newExpression === null || newExpression === void 0 ? void 0 : newExpression.type) !== AST_NODE_TYPES.NewExpression)
56
63
  continue;
57
64
  validateConstructId({
58
65
  node: node,
@@ -62,18 +69,18 @@ var validateConstructorBody = function (_a) {
62
69
  });
63
70
  break;
64
71
  }
65
- case "ExpressionStatement": {
66
- if (((_b = statement.expression) === null || _b === void 0 ? void 0 : _b.type) !== "NewExpression")
72
+ case AST_NODE_TYPES.ExpressionStatement: {
73
+ if (((_b = statement.expression) === null || _b === void 0 ? void 0 : _b.type) !== AST_NODE_TYPES.NewExpression)
67
74
  break;
68
75
  validateStatement({
69
76
  node: node,
70
- body: statement,
77
+ statement: statement,
71
78
  parentClassName: parentClassName,
72
79
  context: context,
73
80
  });
74
81
  break;
75
82
  }
76
- case "IfStatement": {
83
+ case AST_NODE_TYPES.IfStatement: {
77
84
  traverseStatements({
78
85
  node: node,
79
86
  context: context,
@@ -82,7 +89,7 @@ var validateConstructorBody = function (_a) {
82
89
  });
83
90
  break;
84
91
  }
85
- case "SwitchStatement": {
92
+ case AST_NODE_TYPES.SwitchStatement: {
86
93
  for (var _d = 0, _e = statement.cases; _d < _e.length; _d++) {
87
94
  var switchCase = _e[_d];
88
95
  for (var _f = 0, _g = switchCase.consequent; _f < _g.length; _f++) {
@@ -108,33 +115,33 @@ var validateConstructorBody = function (_a) {
108
115
  var traverseStatements = function (_a) {
109
116
  var node = _a.node, statement = _a.statement, parentClassName = _a.parentClassName, context = _a.context;
110
117
  switch (statement.type) {
111
- case "BlockStatement": {
118
+ case AST_NODE_TYPES.BlockStatement: {
112
119
  for (var _i = 0, _b = statement.body; _i < _b.length; _i++) {
113
120
  var body = _b[_i];
114
121
  validateStatement({
115
122
  node: node,
116
- body: body,
123
+ statement: body,
117
124
  parentClassName: parentClassName,
118
125
  context: context,
119
126
  });
120
127
  }
121
128
  break;
122
129
  }
123
- case "ExpressionStatement": {
130
+ case AST_NODE_TYPES.ExpressionStatement: {
124
131
  var newExpression = statement.expression;
125
- if ((newExpression === null || newExpression === void 0 ? void 0 : newExpression.type) !== "NewExpression")
132
+ if ((newExpression === null || newExpression === void 0 ? void 0 : newExpression.type) !== AST_NODE_TYPES.NewExpression)
126
133
  break;
127
134
  validateStatement({
128
135
  node: node,
129
- body: statement,
136
+ statement: statement,
130
137
  parentClassName: parentClassName,
131
138
  context: context,
132
139
  });
133
140
  break;
134
141
  }
135
- case "VariableDeclaration": {
142
+ case AST_NODE_TYPES.VariableDeclaration: {
136
143
  var newExpression = statement.declarations[0].init;
137
- if ((newExpression === null || newExpression === void 0 ? void 0 : newExpression.type) !== "NewExpression")
144
+ if ((newExpression === null || newExpression === void 0 ? void 0 : newExpression.type) !== AST_NODE_TYPES.NewExpression)
138
145
  break;
139
146
  validateConstructId({
140
147
  node: node,
@@ -152,11 +159,11 @@ var traverseStatements = function (_a) {
152
159
  * - Extracts and validates construct IDs from new expressions
153
160
  */
154
161
  var validateStatement = function (_a) {
155
- var node = _a.node, body = _a.body, parentClassName = _a.parentClassName, context = _a.context;
156
- switch (body.type) {
157
- case "VariableDeclaration": {
158
- var newExpression = body.declarations[0].init;
159
- if ((newExpression === null || newExpression === void 0 ? void 0 : newExpression.type) !== "NewExpression")
162
+ var node = _a.node, statement = _a.statement, parentClassName = _a.parentClassName, context = _a.context;
163
+ switch (statement.type) {
164
+ case AST_NODE_TYPES.VariableDeclaration: {
165
+ var newExpression = statement.declarations[0].init;
166
+ if ((newExpression === null || newExpression === void 0 ? void 0 : newExpression.type) !== AST_NODE_TYPES.NewExpression)
160
167
  break;
161
168
  validateConstructId({
162
169
  node: node,
@@ -166,9 +173,9 @@ var validateStatement = function (_a) {
166
173
  });
167
174
  break;
168
175
  }
169
- case "ExpressionStatement": {
170
- var newExpression = body.expression;
171
- if ((newExpression === null || newExpression === void 0 ? void 0 : newExpression.type) !== "NewExpression")
176
+ case AST_NODE_TYPES.ExpressionStatement: {
177
+ var newExpression = statement.expression;
178
+ if ((newExpression === null || newExpression === void 0 ? void 0 : newExpression.type) !== AST_NODE_TYPES.NewExpression)
172
179
  break;
173
180
  validateConstructId({
174
181
  node: node,
@@ -178,19 +185,19 @@ var validateStatement = function (_a) {
178
185
  });
179
186
  break;
180
187
  }
181
- case "IfStatement": {
188
+ case AST_NODE_TYPES.IfStatement: {
182
189
  validateIfStatement({
183
190
  node: node,
184
- ifStatement: body,
191
+ statement: statement,
185
192
  parentClassName: parentClassName,
186
193
  context: context,
187
194
  });
188
195
  break;
189
196
  }
190
- case "SwitchStatement": {
197
+ case AST_NODE_TYPES.SwitchStatement: {
191
198
  validateSwitchStatement({
192
199
  node: node,
193
- switchStatement: body,
200
+ statement: statement,
194
201
  parentClassName: parentClassName,
195
202
  context: context,
196
203
  });
@@ -203,12 +210,12 @@ var validateStatement = function (_a) {
203
210
  * - Validate recursively if `if` statements are nested
204
211
  */
205
212
  var validateIfStatement = function (_a) {
206
- var node = _a.node, ifStatement = _a.ifStatement, parentClassName = _a.parentClassName, context = _a.context;
213
+ var node = _a.node, statement = _a.statement, parentClassName = _a.parentClassName, context = _a.context;
207
214
  traverseStatements({
208
215
  node: node,
209
216
  context: context,
210
217
  parentClassName: parentClassName,
211
- statement: ifStatement.consequent,
218
+ statement: statement.consequent,
212
219
  });
213
220
  };
214
221
  /**
@@ -216,10 +223,10 @@ var validateIfStatement = function (_a) {
216
223
  * - Validate recursively if `switch` statements are nested
217
224
  */
218
225
  var validateSwitchStatement = function (_a) {
219
- var node = _a.node, switchStatement = _a.switchStatement, parentClassName = _a.parentClassName, context = _a.context;
220
- for (var _i = 0, _b = switchStatement.cases; _i < _b.length; _i++) {
221
- var statement = _b[_i];
222
- for (var _c = 0, _d = statement.consequent; _c < _d.length; _c++) {
226
+ var node = _a.node, statement = _a.statement, parentClassName = _a.parentClassName, context = _a.context;
227
+ for (var _i = 0, _b = statement.cases; _i < _b.length; _i++) {
228
+ var caseStatement = _b[_i];
229
+ for (var _c = 0, _d = caseStatement.consequent; _c < _d.length; _c++) {
223
230
  var _consequent = _d[_c];
224
231
  traverseStatements({
225
232
  node: node,
@@ -239,7 +246,8 @@ var validateConstructId = function (_a) {
239
246
  return;
240
247
  // NOTE: Treat the second argument as ID
241
248
  var secondArg = expression.arguments[1];
242
- if (secondArg.type !== "Literal" || typeof secondArg.value !== "string") {
249
+ if (secondArg.type !== AST_NODE_TYPES.Literal ||
250
+ typeof secondArg.value !== "string") {
243
251
  return;
244
252
  }
245
253
  var formattedConstructId = toPascalCase(secondArg.value);
@@ -1,5 +1,12 @@
1
- import { ESLintUtils, } from "@typescript-eslint/utils";
1
+ import { AST_NODE_TYPES, ESLintUtils, } from "@typescript-eslint/utils";
2
2
  import { SymbolFlags } from "typescript";
3
+ import { isConstructOrStackType } from "./utils/isConstructOrStackType.mjs";
4
+ /**
5
+ * Disallow class types in public class fields
6
+ * @param context - The rule context provided by ESLint
7
+ * @returns An object containing the AST visitor functions
8
+ * @see {@link https://eslint-cdk-plugin.dev/rules/no-public-class-fields} - Documentation
9
+ */
3
10
  export var noPublicClassFields = ESLintUtils.RuleCreator.withoutDocs({
4
11
  meta: {
5
12
  type: "problem",
@@ -17,6 +24,10 @@ export var noPublicClassFields = ESLintUtils.RuleCreator.withoutDocs({
17
24
  var typeChecker = parserServices.program.getTypeChecker();
18
25
  return {
19
26
  ClassDeclaration: function (node) {
27
+ var type = typeChecker.getTypeAtLocation(parserServices.esTreeNodeToTSNodeMap.get(node));
28
+ if (!isConstructOrStackType(type)) {
29
+ return;
30
+ }
20
31
  // NOTE: Check class members
21
32
  validateClassMember({
22
33
  node: node,
@@ -26,9 +37,11 @@ export var noPublicClassFields = ESLintUtils.RuleCreator.withoutDocs({
26
37
  });
27
38
  // NOTE: Check constructor parameter properties
28
39
  var constructor = node.body.body.find(function (member) {
29
- return member.type === "MethodDefinition" && member.kind === "constructor";
40
+ return member.type === AST_NODE_TYPES.MethodDefinition &&
41
+ member.kind === "constructor";
30
42
  });
31
- if (!constructor || constructor.value.type !== "FunctionExpression") {
43
+ if (!constructor ||
44
+ constructor.value.type !== AST_NODE_TYPES.FunctionExpression) {
32
45
  return;
33
46
  }
34
47
  validateConstructorParameterProperty({
@@ -41,13 +54,17 @@ export var noPublicClassFields = ESLintUtils.RuleCreator.withoutDocs({
41
54
  };
42
55
  },
43
56
  });
57
+ /**
58
+ * check the public variable of the class
59
+ * - if it is a class type, report an error
60
+ */
44
61
  var validateClassMember = function (_a) {
45
62
  var _b;
46
63
  var node = _a.node, context = _a.context, parserServices = _a.parserServices, typeChecker = _a.typeChecker;
47
64
  for (var _i = 0, _c = node.body.body; _i < _c.length; _i++) {
48
65
  var member = _c[_i];
49
- if (member.type !== "PropertyDefinition" ||
50
- member.key.type !== "Identifier") {
66
+ if (member.type !== AST_NODE_TYPES.PropertyDefinition ||
67
+ member.key.type !== AST_NODE_TYPES.Identifier) {
51
68
  continue;
52
69
  }
53
70
  // NOTE: Skip private and protected fields
@@ -75,13 +92,17 @@ var validateClassMember = function (_a) {
75
92
  });
76
93
  }
77
94
  };
95
+ /**
96
+ * check the constructor parameter property
97
+ * - if it is a class type, report an error
98
+ */
78
99
  var validateConstructorParameterProperty = function (_a) {
79
100
  var _b;
80
101
  var constructor = _a.constructor, context = _a.context, parserServices = _a.parserServices, typeChecker = _a.typeChecker;
81
102
  for (var _i = 0, _c = constructor.value.params; _i < _c.length; _i++) {
82
103
  var param = _c[_i];
83
- if (param.type !== "TSParameterProperty" ||
84
- param.parameter.type !== "Identifier") {
104
+ if (param.type !== AST_NODE_TYPES.TSParameterProperty ||
105
+ param.parameter.type !== AST_NODE_TYPES.Identifier) {
85
106
  continue;
86
107
  }
87
108
  // NOTE: Skip private and protected parameters
@@ -1,8 +1,57 @@
1
+ import { AST_NODE_TYPES, ESLintUtils, } from "@typescript-eslint/utils";
1
2
  import { toPascalCase } from "./utils/convertString.mjs";
3
+ import { isConstructOrStackType } from "./utils/isConstructOrStackType.mjs";
2
4
  var QUOTE_TYPE = {
3
5
  SINGLE: "'",
4
6
  DOUBLE: '"',
5
7
  };
8
+ /**
9
+ /**
10
+ * Enforce PascalCase for Construct ID.
11
+ * @param context - The rule context provided by ESLint
12
+ * @returns An object containing the AST visitor functions
13
+ * @see {@link https://eslint-cdk-plugin.dev/rules/pascal-case-construct-id} - Documentation
14
+ */
15
+ export var pascalCaseConstructId = ESLintUtils.RuleCreator.withoutDocs({
16
+ meta: {
17
+ type: "problem",
18
+ docs: {
19
+ description: "Enforce PascalCase for Construct ID.",
20
+ },
21
+ messages: {
22
+ pascalCaseConstructId: "Construct ID must be PascalCase.",
23
+ },
24
+ schema: [],
25
+ fixable: "code",
26
+ },
27
+ defaultOptions: [],
28
+ create: function (context) {
29
+ var parserServices = ESLintUtils.getParserServices(context);
30
+ var checker = parserServices.program.getTypeChecker();
31
+ return {
32
+ // ExpressionStatement(node) {
33
+ // if (node.expression.type !== AST_NODE_TYPES.NewExpression) return;
34
+ // validateConstructId(node, context, node.expression.arguments);
35
+ // },
36
+ // VariableDeclaration(node) {
37
+ // if (!node.declarations.length) return;
38
+ // for (const declaration of node.declarations) {
39
+ // if (declaration.init?.type !== AST_NODE_TYPES.NewExpression) return;
40
+ // validateConstructId(node, context, declaration.init.arguments);
41
+ // }
42
+ // },
43
+ NewExpression: function (node) {
44
+ var type = checker.getTypeAtLocation(parserServices.esTreeNodeToTSNodeMap.get(node));
45
+ if (!isConstructOrStackType(type)) {
46
+ return;
47
+ }
48
+ if (node.arguments.length < 2)
49
+ return;
50
+ validateConstructId(node, context, node);
51
+ },
52
+ };
53
+ },
54
+ });
6
55
  /**
7
56
  * check if the string is PascalCase
8
57
  * @param str - The string to check
@@ -11,13 +60,17 @@ var QUOTE_TYPE = {
11
60
  var isPascalCase = function (str) {
12
61
  return /^[A-Z][a-zA-Z0-9]*$/.test(str);
13
62
  };
14
- var validateConstructId = function (node, context, args) {
63
+ /**
64
+ * Check the construct ID is PascalCase
65
+ */
66
+ var validateConstructId = function (node, context, expression) {
15
67
  var _a;
16
- if (args.length < 2)
68
+ if (expression.arguments.length < 2)
17
69
  return;
18
70
  // NOTE: Treat the second argument as ID
19
- var secondArg = args[1];
20
- if (secondArg.type !== "Literal" || typeof secondArg.value !== "string") {
71
+ var secondArg = expression.arguments[1];
72
+ if (secondArg.type !== AST_NODE_TYPES.Literal ||
73
+ typeof secondArg.value !== "string") {
21
74
  return;
22
75
  }
23
76
  var quote = ((_a = secondArg.raw) === null || _a === void 0 ? void 0 : _a.startsWith('"'))
@@ -34,36 +87,3 @@ var validateConstructId = function (node, context, args) {
34
87
  });
35
88
  }
36
89
  };
37
- export var pascalCaseConstructId = {
38
- meta: {
39
- type: "problem",
40
- docs: {
41
- description: "Enforce PascalCase for Construct ID.",
42
- },
43
- messages: {
44
- pascalCaseConstructId: "Construct ID must be PascalCase.",
45
- },
46
- schema: [],
47
- fixable: "code",
48
- },
49
- create: function (context) {
50
- return {
51
- ExpressionStatement: function (node) {
52
- if (node.expression.type !== "NewExpression")
53
- return;
54
- validateConstructId(node, context, node.expression.arguments);
55
- },
56
- VariableDeclaration: function (node) {
57
- var _a;
58
- if (!node.declarations.length)
59
- return;
60
- for (var _i = 0, _b = node.declarations; _i < _b.length; _i++) {
61
- var declaration = _b[_i];
62
- if (((_a = declaration.init) === null || _a === void 0 ? void 0 : _a.type) !== "NewExpression")
63
- return;
64
- validateConstructId(node, context, declaration.init.arguments);
65
- }
66
- },
67
- };
68
- },
69
- };
@@ -0,0 +1,19 @@
1
+ export var SUPPORTED_SUPER_CLASS_SUFFIXES = ["Construct", "Stack"];
2
+ /**
3
+ * Check if the type extends Construct or Stack
4
+ * @param type - The type to check
5
+ * @returns True if the type extends Construct or Stack, otherwise false
6
+ */
7
+ export var isConstructOrStackType = function (type) {
8
+ if (!type.symbol)
9
+ return false;
10
+ // NOTE: Check if the current type ends in Construct or Stack
11
+ if (SUPPORTED_SUPER_CLASS_SUFFIXES.some(function (suffix) {
12
+ return type.symbol.name.endsWith(suffix);
13
+ })) {
14
+ return true;
15
+ }
16
+ // NOTE: Check the base type
17
+ var baseTypes = type.getBaseTypes() || [];
18
+ return baseTypes.some(function (baseType) { return isConstructOrStackType(baseType); });
19
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-cdk-plugin",
3
- "version": "0.1.0",
3
+ "version": "0.4.0",
4
4
  "description": "eslint plugin for AWS CDK projects",
5
5
  "main": "dist/index.mjs",
6
6
  "type": "module",
@@ -45,10 +45,10 @@
45
45
  "aws",
46
46
  "cdk"
47
47
  ],
48
- "homepage": "https://eslint-plugin-cdk.dev/",
48
+ "homepage": "https://eslint-cdk-plugin.dev/",
49
49
  "repository": {
50
50
  "type": "git",
51
- "url": "https://github.com/ren-yamanashi/eslint-plugin-cdk.git"
51
+ "url": "https://github.com/ren-yamanashi/eslint-cdk-plugin.git"
52
52
  },
53
53
  "engines": {
54
54
  "node": "^18.18.0 || ^20.9.0 || >=21.1.0"