eslint-cdk-plugin 0.3.2 → 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 +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{no-class-in-interface.mjs → no-class-in-interface-props.mjs} +10 -3
- package/dist/no-construct-stack-suffix.mjs +18 -137
- package/dist/no-import-private.mjs +12 -6
- package/dist/no-mutable-props-interface.mjs +10 -3
- package/dist/no-mutable-public-fields.mjs +17 -3
- package/dist/no-parent-name-construct-id-match.mjs +45 -37
- package/dist/no-public-class-fields.mjs +28 -7
- package/dist/pascal-case-construct-id.mjs +57 -37
- package/dist/utils/isConstructOrStackType.mjs +19 -0
- package/package.json +1 -1
package/README.md
CHANGED
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
|
-
|
|
23
|
-
|
|
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
|
-
|
|
18
|
-
var
|
|
19
|
-
|
|
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 !==
|
|
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
|
-
*
|
|
4
|
-
* @param
|
|
5
|
-
* @returns
|
|
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
|
-
|
|
24
|
-
|
|
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
|
-
|
|
22
|
-
|
|
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) !==
|
|
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
|
|
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 !==
|
|
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
|
|
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) !==
|
|
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
|
|
66
|
-
if (((_b = statement.expression) === null || _b === void 0 ? void 0 : _b.type) !==
|
|
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
|
-
|
|
77
|
+
statement: statement,
|
|
71
78
|
parentClassName: parentClassName,
|
|
72
79
|
context: context,
|
|
73
80
|
});
|
|
74
81
|
break;
|
|
75
82
|
}
|
|
76
|
-
case
|
|
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
|
|
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
|
|
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
|
-
|
|
123
|
+
statement: body,
|
|
117
124
|
parentClassName: parentClassName,
|
|
118
125
|
context: context,
|
|
119
126
|
});
|
|
120
127
|
}
|
|
121
128
|
break;
|
|
122
129
|
}
|
|
123
|
-
case
|
|
130
|
+
case AST_NODE_TYPES.ExpressionStatement: {
|
|
124
131
|
var newExpression = statement.expression;
|
|
125
|
-
if ((newExpression === null || newExpression === void 0 ? void 0 : newExpression.type) !==
|
|
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
|
-
|
|
136
|
+
statement: statement,
|
|
130
137
|
parentClassName: parentClassName,
|
|
131
138
|
context: context,
|
|
132
139
|
});
|
|
133
140
|
break;
|
|
134
141
|
}
|
|
135
|
-
case
|
|
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) !==
|
|
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,
|
|
156
|
-
switch (
|
|
157
|
-
case
|
|
158
|
-
var newExpression =
|
|
159
|
-
if ((newExpression === null || newExpression === void 0 ? void 0 : newExpression.type) !==
|
|
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
|
|
170
|
-
var newExpression =
|
|
171
|
-
if ((newExpression === null || newExpression === void 0 ? void 0 : newExpression.type) !==
|
|
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
|
|
188
|
+
case AST_NODE_TYPES.IfStatement: {
|
|
182
189
|
validateIfStatement({
|
|
183
190
|
node: node,
|
|
184
|
-
|
|
191
|
+
statement: statement,
|
|
185
192
|
parentClassName: parentClassName,
|
|
186
193
|
context: context,
|
|
187
194
|
});
|
|
188
195
|
break;
|
|
189
196
|
}
|
|
190
|
-
case
|
|
197
|
+
case AST_NODE_TYPES.SwitchStatement: {
|
|
191
198
|
validateSwitchStatement({
|
|
192
199
|
node: node,
|
|
193
|
-
|
|
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,
|
|
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:
|
|
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,
|
|
220
|
-
for (var _i = 0, _b =
|
|
221
|
-
var
|
|
222
|
-
for (var _c = 0, _d =
|
|
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 !==
|
|
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 ===
|
|
40
|
+
return member.type === AST_NODE_TYPES.MethodDefinition &&
|
|
41
|
+
member.kind === "constructor";
|
|
30
42
|
});
|
|
31
|
-
if (!constructor ||
|
|
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 !==
|
|
50
|
-
member.key.type !==
|
|
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 !==
|
|
84
|
-
param.parameter.type !==
|
|
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
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Check the construct ID is PascalCase
|
|
65
|
+
*/
|
|
66
|
+
var validateConstructId = function (node, context, expression) {
|
|
15
67
|
var _a;
|
|
16
|
-
if (
|
|
68
|
+
if (expression.arguments.length < 2)
|
|
17
69
|
return;
|
|
18
70
|
// NOTE: Treat the second argument as ID
|
|
19
|
-
var secondArg =
|
|
20
|
-
if (secondArg.type !==
|
|
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
|
+
};
|