eslint-cdk-plugin 3.4.6 → 3.4.9
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 +2 -1
- package/dist/index.cjs +16397 -8491
- package/dist/index.d.cts +7599 -27
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +7599 -27
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +16392 -8488
- package/dist/index.mjs.map +1 -1
- package/package.json +46 -51
- package/src/configs/flat-config.ts +3 -9
- package/src/core/ast-node/finder/constructor.ts +2 -3
- package/src/core/ast-node/finder/property-name.ts +3 -4
- package/src/core/ast-node/finder/public-property.ts +7 -15
- package/src/core/cdk-construct/type-checker/is-construct-or-stack.ts +2 -6
- package/src/core/cdk-construct/type-checker/is-construct.ts +1 -6
- package/src/core/cdk-construct/type-checker/is-resource-with-readonly-interface.ts +6 -17
- package/src/core/cdk-construct/type-checker/is-resource.ts +1 -1
- package/src/core/cdk-construct/type-finder/index.ts +4 -12
- package/src/core/ts-type/checker/is-extends-target-super-class.ts +1 -1
- package/src/core/ts-type/finder/array-element.ts +0 -1
- package/src/core/ts-type/finder/constructor-property-name.ts +1 -4
- package/src/core/ts-type/finder/generics-type-argument.ts +1 -5
- package/src/rules/construct-constructor-property.ts +10 -30
- package/src/rules/index.ts +1 -2
- package/src/rules/no-construct-in-public-property-of-construct.ts +1 -1
- package/src/rules/no-construct-stack-suffix.ts +5 -18
- package/src/rules/no-import-private.ts +3 -7
- package/src/rules/no-mutable-public-property-of-construct.ts +3 -8
- package/src/rules/no-parent-name-construct-id-match.ts +2 -6
- package/src/rules/no-unused-props/index.ts +4 -6
- package/src/rules/no-unused-props/props-usage-analyzer.ts +15 -34
- package/src/rules/no-unused-props/props-usage-tracker.ts +10 -17
- package/src/rules/no-unused-props/visitor/direct-props-usage-visitor.ts +1 -2
- package/src/rules/no-unused-props/visitor/instance-variable-usage-visitor.ts +3 -10
- package/src/rules/no-unused-props/visitor/method-call-collector-visitor.ts +2 -3
- package/src/rules/no-unused-props/visitor/props-alias-visitor.ts +1 -2
- package/src/rules/no-unused-props/visitor/traverse-nodes.ts +1 -5
- package/src/rules/no-variable-construct-id.ts +7 -27
- package/src/rules/pascal-case-construct-id.ts +4 -17
- package/src/rules/props-name-convention.ts +1 -2
- package/src/rules/require-jsdoc.ts +4 -11
- package/src/rules/require-passing-this.ts +2 -9
- package/src/rules/require-props-default-doc.ts +1 -1
- package/src/shared/converter/to-pascal-case.ts +1 -3
- package/src/shared/create-rule.ts +1 -1
- package/bin/index.mjs +0 -4318
- package/bin/prompt-DVcPfS2N.mjs +0 -847
package/package.json
CHANGED
|
@@ -1,10 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-cdk-plugin",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.9",
|
|
4
4
|
"description": "eslint plugin for AWS CDK projects",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"aws",
|
|
7
|
+
"cdk",
|
|
8
|
+
"eslint",
|
|
9
|
+
"eslint-plugin",
|
|
10
|
+
"eslintplugin"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://eslint-cdk-plugin.dev/",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"author": {
|
|
15
|
+
"name": "ren-yamanashi"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/ren-yamanashi/eslint-plugin-awscdk.git"
|
|
20
|
+
},
|
|
21
|
+
"bin": {
|
|
22
|
+
"migrate-cdk-plugin": "./bin/index.mjs"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"bin",
|
|
26
|
+
"dist",
|
|
27
|
+
"src",
|
|
28
|
+
"!src/__tests__",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"type": "module",
|
|
5
33
|
"main": "./dist/index.mjs",
|
|
6
34
|
"types": "./dist/index.d.ts",
|
|
7
|
-
"type": "module",
|
|
8
35
|
"exports": {
|
|
9
36
|
"types": "./dist/index.d.ts",
|
|
10
37
|
"require": {
|
|
@@ -16,69 +43,37 @@
|
|
|
16
43
|
"default": "./dist/index.mjs"
|
|
17
44
|
}
|
|
18
45
|
},
|
|
19
|
-
"
|
|
20
|
-
"
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
21
48
|
},
|
|
22
49
|
"scripts": {
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"test
|
|
26
|
-
"
|
|
27
|
-
"check": "tsc --noEmit",
|
|
28
|
-
"pack": "pnpm run build && npm pack",
|
|
29
|
-
"docs": "pnpm run --filter=@eslint-cdk-plugin/docs",
|
|
30
|
-
"example:flat-config": "pnpm run --filter=@eslint-cdk-plugin/example-flat-config"
|
|
50
|
+
"pack": "vp pack",
|
|
51
|
+
"check": "vp check",
|
|
52
|
+
"test": "vp test --run",
|
|
53
|
+
"docs": "vp run -F @eslint-plugin-awscdk/docs"
|
|
31
54
|
},
|
|
32
55
|
"devDependencies": {
|
|
33
|
-
"@eslint/js": "^
|
|
34
|
-
"@secretlint/secretlint-rule-preset-recommend": "
|
|
35
|
-
"@types/node": "
|
|
36
|
-
"@typescript-eslint/parser": "^8.
|
|
56
|
+
"@eslint/js": "^10.0.1",
|
|
57
|
+
"@secretlint/secretlint-rule-preset-recommend": "latest",
|
|
58
|
+
"@types/node": "latest",
|
|
59
|
+
"@typescript-eslint/parser": "^8.58.0",
|
|
37
60
|
"@typescript-eslint/rule-tester": "^8.48.1",
|
|
38
61
|
"@typescript-eslint/utils": "^8.48.1",
|
|
62
|
+
"@voidzero-dev/vite-plus-core": "^0.1.11",
|
|
39
63
|
"commander": "^14.0.2",
|
|
40
64
|
"consola": "^3.4.2",
|
|
41
|
-
"eslint": "^
|
|
42
|
-
"eslint-plugin-import": "^2.32.0",
|
|
65
|
+
"eslint": "^10.0.0",
|
|
43
66
|
"secretlint": "^11.2.5",
|
|
44
|
-
"tsdown": "^0.17.0",
|
|
45
67
|
"typescript": "^5.9.3",
|
|
46
|
-
"typescript-eslint": "
|
|
47
|
-
"
|
|
68
|
+
"typescript-eslint": "latest",
|
|
69
|
+
"vite-plus": "^0.1.11"
|
|
48
70
|
},
|
|
49
71
|
"peerDependencies": {
|
|
50
|
-
"eslint": "^8.57.0 || ^9.0.0",
|
|
51
|
-
"typescript": ">=4.8.4 <6.
|
|
72
|
+
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
|
73
|
+
"typescript": ">=4.8.4 <6.1.0"
|
|
52
74
|
},
|
|
53
75
|
"engines": {
|
|
54
76
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
|
55
77
|
},
|
|
56
|
-
"packageManager": "pnpm@10.
|
|
57
|
-
"files": [
|
|
58
|
-
"bin",
|
|
59
|
-
"dist",
|
|
60
|
-
"src",
|
|
61
|
-
"!src/__tests__",
|
|
62
|
-
"README.md",
|
|
63
|
-
"LICENSE"
|
|
64
|
-
],
|
|
65
|
-
"keywords": [
|
|
66
|
-
"eslint",
|
|
67
|
-
"eslintplugin",
|
|
68
|
-
"eslint-plugin",
|
|
69
|
-
"aws",
|
|
70
|
-
"cdk"
|
|
71
|
-
],
|
|
72
|
-
"homepage": "https://eslint-cdk-plugin.dev/",
|
|
73
|
-
"repository": {
|
|
74
|
-
"type": "git",
|
|
75
|
-
"url": "https://github.com/ren-yamanashi/eslint-cdk-plugin.git"
|
|
76
|
-
},
|
|
77
|
-
"author": {
|
|
78
|
-
"name": "ren-yamanashi"
|
|
79
|
-
},
|
|
80
|
-
"publishConfig": {
|
|
81
|
-
"access": "public"
|
|
82
|
-
},
|
|
83
|
-
"license": "MIT"
|
|
78
|
+
"packageManager": "pnpm@10.29.3"
|
|
84
79
|
}
|
|
@@ -10,7 +10,7 @@ const cdk = {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
const createFlatConfig = (
|
|
13
|
-
rules: FlatConfig.Rules
|
|
13
|
+
rules: FlatConfig.Rules,
|
|
14
14
|
): {
|
|
15
15
|
languageOptions: FlatConfig.LanguageOptions;
|
|
16
16
|
plugins: FlatConfig.Plugins;
|
|
@@ -37,10 +37,7 @@ export const recommended = createFlatConfig({
|
|
|
37
37
|
"cdk/no-construct-stack-suffix": "error",
|
|
38
38
|
"cdk/no-mutable-property-of-props-interface": "warn",
|
|
39
39
|
"cdk/no-mutable-public-property-of-construct": "warn",
|
|
40
|
-
"cdk/no-parent-name-construct-id-match": [
|
|
41
|
-
"error",
|
|
42
|
-
{ disallowContainingParentName: false },
|
|
43
|
-
],
|
|
40
|
+
"cdk/no-parent-name-construct-id-match": ["error", { disallowContainingParentName: false }],
|
|
44
41
|
"cdk/no-unused-props": "error",
|
|
45
42
|
"cdk/no-variable-construct-id": "error",
|
|
46
43
|
"cdk/pascal-case-construct-id": "error",
|
|
@@ -55,10 +52,7 @@ export const strict = createFlatConfig({
|
|
|
55
52
|
"cdk/no-import-private": "error",
|
|
56
53
|
"cdk/no-mutable-property-of-props-interface": "error",
|
|
57
54
|
"cdk/no-mutable-public-property-of-construct": "error",
|
|
58
|
-
"cdk/no-parent-name-construct-id-match": [
|
|
59
|
-
"error",
|
|
60
|
-
{ disallowContainingParentName: true },
|
|
61
|
-
],
|
|
55
|
+
"cdk/no-parent-name-construct-id-match": ["error", { disallowContainingParentName: true }],
|
|
62
56
|
"cdk/no-unused-props": "error",
|
|
63
57
|
"cdk/no-variable-construct-id": "error",
|
|
64
58
|
"cdk/pascal-case-construct-id": "error",
|
|
@@ -6,11 +6,10 @@ import { AST_NODE_TYPES, TSESTree } from "@typescript-eslint/utils";
|
|
|
6
6
|
* @returns The constructor method definition or undefined if not found
|
|
7
7
|
*/
|
|
8
8
|
export const findConstructor = (
|
|
9
|
-
node: TSESTree.ClassDeclaration
|
|
9
|
+
node: TSESTree.ClassDeclaration,
|
|
10
10
|
): TSESTree.MethodDefinition | undefined => {
|
|
11
11
|
return node.body.body.find(
|
|
12
12
|
(member): member is TSESTree.MethodDefinition =>
|
|
13
|
-
member.type === AST_NODE_TYPES.MethodDefinition &&
|
|
14
|
-
member.kind === "constructor"
|
|
13
|
+
member.type === AST_NODE_TYPES.MethodDefinition && member.kind === "constructor",
|
|
15
14
|
);
|
|
16
15
|
};
|
|
@@ -7,14 +7,13 @@ import { AST_NODE_TYPES, TSESTree } from "@typescript-eslint/utils";
|
|
|
7
7
|
* @returns An array of property names.
|
|
8
8
|
*/
|
|
9
9
|
export const findPropertyNames = (
|
|
10
|
-
properties: (TSESTree.Property | TSESTree.RestElement)[]
|
|
10
|
+
properties: (TSESTree.Property | TSESTree.RestElement)[],
|
|
11
11
|
): string[] => {
|
|
12
12
|
return properties.reduce<string[]>(
|
|
13
13
|
(acc, prop) =>
|
|
14
|
-
prop.type === AST_NODE_TYPES.Property &&
|
|
15
|
-
prop.key.type === AST_NODE_TYPES.Identifier
|
|
14
|
+
prop.type === AST_NODE_TYPES.Property && prop.key.type === AST_NODE_TYPES.Identifier
|
|
16
15
|
? [...acc, prop.key.name]
|
|
17
16
|
: acc,
|
|
18
|
-
[]
|
|
17
|
+
[],
|
|
19
18
|
);
|
|
20
19
|
};
|
|
@@ -16,32 +16,24 @@ export type PublicProperty = {
|
|
|
16
16
|
| TSESTree.TSParameterProperty;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
export const findPublicPropertiesInClass = (
|
|
20
|
-
node: TSESTree.ClassDeclaration
|
|
21
|
-
): PublicProperty[] => {
|
|
19
|
+
export const findPublicPropertiesInClass = (node: TSESTree.ClassDeclaration): PublicProperty[] => {
|
|
22
20
|
const constructorProperties = findPropertiesInConstructor(node);
|
|
23
21
|
const classElementProperties = findPropertiesInClassElement(node);
|
|
24
22
|
return [...constructorProperties, ...classElementProperties];
|
|
25
|
-
}
|
|
23
|
+
};
|
|
26
24
|
|
|
27
|
-
const findPropertiesInConstructor = (
|
|
28
|
-
node: TSESTree.ClassDeclaration
|
|
29
|
-
) => {
|
|
25
|
+
const findPropertiesInConstructor = (node: TSESTree.ClassDeclaration) => {
|
|
30
26
|
const constructor = findConstructor(node);
|
|
31
27
|
if (!constructor) return [];
|
|
32
|
-
return constructor.value.params.flatMap(
|
|
33
|
-
|
|
34
|
-
);
|
|
35
|
-
}
|
|
28
|
+
return constructor.value.params.flatMap((property) => findPublicProperty(property) ?? []);
|
|
29
|
+
};
|
|
36
30
|
|
|
37
31
|
const findPropertiesInClassElement = (node: TSESTree.ClassDeclaration): PublicProperty[] => {
|
|
38
|
-
return node.body.body.flatMap(
|
|
39
|
-
(property) => findPublicProperty(property) ?? []
|
|
40
|
-
);
|
|
32
|
+
return node.body.body.flatMap((property) => findPublicProperty(property) ?? []);
|
|
41
33
|
};
|
|
42
34
|
|
|
43
35
|
const findPublicProperty = (
|
|
44
|
-
property: TSESTree.Parameter | TSESTree.ClassElement
|
|
36
|
+
property: TSESTree.Parameter | TSESTree.ClassElement,
|
|
45
37
|
): PublicProperty | undefined => {
|
|
46
38
|
switch (property.type) {
|
|
47
39
|
// NOTE: get from constructor
|
|
@@ -10,12 +10,8 @@ import { isExtendsFromTargetSuperClass } from "../../ts-type/checker/is-extends-
|
|
|
10
10
|
*/
|
|
11
11
|
export const isConstructOrStackType = (
|
|
12
12
|
type: Type,
|
|
13
|
-
ignoredClasses: readonly string[] = ["App", "Stage", "CfnOutput"] as const
|
|
13
|
+
ignoredClasses: readonly string[] = ["App", "Stage", "CfnOutput"] as const,
|
|
14
14
|
): boolean => {
|
|
15
15
|
if (ignoredClasses.includes(type.symbol?.name ?? "")) return false;
|
|
16
|
-
return isExtendsFromTargetSuperClass(
|
|
17
|
-
type,
|
|
18
|
-
["Construct", "Stack"],
|
|
19
|
-
isConstructOrStackType
|
|
20
|
-
);
|
|
16
|
+
return isExtendsFromTargetSuperClass(type, ["Construct", "Stack"], isConstructOrStackType);
|
|
21
17
|
};
|
|
@@ -10,12 +10,7 @@ import { isExtendsFromTargetSuperClass } from "../../ts-type/checker/is-extends-
|
|
|
10
10
|
*/
|
|
11
11
|
export const isConstructType = (
|
|
12
12
|
type: Type,
|
|
13
|
-
ignoredClasses: readonly string[] = [
|
|
14
|
-
"App",
|
|
15
|
-
"Stage",
|
|
16
|
-
"CfnOutput",
|
|
17
|
-
"Stack",
|
|
18
|
-
] as const
|
|
13
|
+
ignoredClasses: readonly string[] = ["App", "Stage", "CfnOutput", "Stack"] as const,
|
|
19
14
|
): boolean => {
|
|
20
15
|
if (ignoredClasses.includes(type.symbol?.name ?? "")) return false;
|
|
21
16
|
return isExtendsFromTargetSuperClass(type, ["Construct"], isConstructType);
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
} from "typescript";
|
|
8
8
|
|
|
9
9
|
import { isClassType } from "../../ts-type/checker/is-class";
|
|
10
|
-
|
|
11
10
|
import { isResourceType } from "./is-resource";
|
|
12
11
|
|
|
13
12
|
/**
|
|
@@ -65,16 +64,14 @@ const hasMatchingInterfaceInHierarchy = (type: Type): boolean => {
|
|
|
65
64
|
// NOTE: Check if any interface matches this class name
|
|
66
65
|
if (
|
|
67
66
|
directInterfaces.some((interfaceName) =>
|
|
68
|
-
checkInterfaceMatchClassName(interfaceName, currentClassName)
|
|
67
|
+
checkInterfaceMatchClassName(interfaceName, currentClassName),
|
|
69
68
|
)
|
|
70
69
|
) {
|
|
71
70
|
return true;
|
|
72
71
|
}
|
|
73
72
|
|
|
74
73
|
const baseTypes = currentType.getBaseTypes?.() ?? [];
|
|
75
|
-
return baseTypes.some(
|
|
76
|
-
(baseType) => isClassType(baseType) && checkTypeAndBases(baseType)
|
|
77
|
-
);
|
|
74
|
+
return baseTypes.some((baseType) => isClassType(baseType) && checkTypeAndBases(baseType));
|
|
78
75
|
};
|
|
79
76
|
|
|
80
77
|
return checkTypeAndBases(type);
|
|
@@ -92,12 +89,9 @@ const hasMatchingInterfaceInHierarchy = (type: Type): boolean => {
|
|
|
92
89
|
* @param classname - The name of the class to compare against
|
|
93
90
|
* @returns boolean - true if the interface name matches the class name patterns, false otherwise
|
|
94
91
|
*/
|
|
95
|
-
const checkInterfaceMatchClassName = (
|
|
96
|
-
interfaceName: string,
|
|
97
|
-
classname: string
|
|
98
|
-
) => {
|
|
92
|
+
const checkInterfaceMatchClassName = (interfaceName: string, classname: string) => {
|
|
99
93
|
const simpleInterfaceName = interfaceName.includes(".")
|
|
100
|
-
? interfaceName.split(".").pop() ?? interfaceName
|
|
94
|
+
? (interfaceName.split(".").pop() ?? interfaceName)
|
|
101
95
|
: interfaceName;
|
|
102
96
|
|
|
103
97
|
// Pattern 1: Class name with I prefix
|
|
@@ -105,10 +99,7 @@ const checkInterfaceMatchClassName = (
|
|
|
105
99
|
|
|
106
100
|
// Pattern 2: Class name without Base suffix/prefix with I prefix
|
|
107
101
|
const classNameWithoutBase = classname.replace(/^Base|Base$/g, "");
|
|
108
|
-
if (
|
|
109
|
-
classNameWithoutBase &&
|
|
110
|
-
simpleInterfaceName === `I${classNameWithoutBase}`
|
|
111
|
-
) {
|
|
102
|
+
if (classNameWithoutBase && simpleInterfaceName === `I${classNameWithoutBase}`) {
|
|
112
103
|
return true;
|
|
113
104
|
}
|
|
114
105
|
|
|
@@ -129,9 +120,7 @@ const getDirectImplementedInterfaceNames = (type: Type): string[] => {
|
|
|
129
120
|
const symbol = type.getSymbol?.() ?? type.symbol;
|
|
130
121
|
if (!symbol?.name) return [];
|
|
131
122
|
|
|
132
|
-
const declarations = symbol.getDeclarations
|
|
133
|
-
? symbol.getDeclarations()
|
|
134
|
-
: symbol.declarations;
|
|
123
|
+
const declarations = symbol.getDeclarations ? symbol.getDeclarations() : symbol.declarations;
|
|
135
124
|
if (!declarations?.length) return [];
|
|
136
125
|
|
|
137
126
|
return declarations.reduce<string[]>((acc, decl) => {
|
|
@@ -10,7 +10,7 @@ import { isExtendsFromTargetSuperClass } from "../../ts-type/checker/is-extends-
|
|
|
10
10
|
*/
|
|
11
11
|
export const isResourceType = (
|
|
12
12
|
type: Type,
|
|
13
|
-
ignoredClasses: readonly string[] = [] // App, Stage, CfnOutput, Stack are not extended Resource, so no need to ignore them
|
|
13
|
+
ignoredClasses: readonly string[] = [], // App, Stage, CfnOutput, Stack are not extended Resource, so no need to ignore them
|
|
14
14
|
): boolean => {
|
|
15
15
|
if (ignoredClasses.includes(type.symbol?.name ?? "")) return false;
|
|
16
16
|
return isExtendsFromTargetSuperClass(type, ["Resource"], isResourceType);
|
|
@@ -23,9 +23,7 @@ export const findTypeOfCdkConstruct = (type: Type): Type | undefined => {
|
|
|
23
23
|
/**
|
|
24
24
|
* Find Construct type from an array type (e.g. s3.Bucket[])
|
|
25
25
|
*/
|
|
26
|
-
const findFromArray = (
|
|
27
|
-
type: Type
|
|
28
|
-
): Type | undefined => {
|
|
26
|
+
const findFromArray = (type: Type): Type | undefined => {
|
|
29
27
|
const arrElementType = findArrayElementType(type);
|
|
30
28
|
if (!arrElementType) return undefined;
|
|
31
29
|
|
|
@@ -35,9 +33,7 @@ const findFromArray = (
|
|
|
35
33
|
/**
|
|
36
34
|
* Find Construct type from a generics type (e.g. Array<s3.Bucket>, Promise<s3.Bucket[]>)
|
|
37
35
|
*/
|
|
38
|
-
const findFromGenerics = (
|
|
39
|
-
type: Type
|
|
40
|
-
): Type | undefined => {
|
|
36
|
+
const findFromGenerics = (type: Type): Type | undefined => {
|
|
41
37
|
const genericsArgument = findGenericsTypeArgument(type);
|
|
42
38
|
if (!genericsArgument) return undefined;
|
|
43
39
|
|
|
@@ -47,9 +43,7 @@ const findFromGenerics = (
|
|
|
47
43
|
/**
|
|
48
44
|
* Find Construct type from a union type (e.g. s3.Bucket | string)
|
|
49
45
|
*/
|
|
50
|
-
const findFromUnion = (
|
|
51
|
-
type: Type
|
|
52
|
-
): Type | undefined => {
|
|
46
|
+
const findFromUnion = (type: Type): Type | undefined => {
|
|
53
47
|
if (!type.isUnion()) return undefined;
|
|
54
48
|
|
|
55
49
|
for (const unionType of type.types) {
|
|
@@ -61,9 +55,7 @@ const findFromUnion = (
|
|
|
61
55
|
/**
|
|
62
56
|
* Find Construct type from an intersection type (e.g. s3.Bucket & { customProp: string })
|
|
63
57
|
*/
|
|
64
|
-
const findFromIntersection = (
|
|
65
|
-
type: Type
|
|
66
|
-
): Type | undefined => {
|
|
58
|
+
const findFromIntersection = (type: Type): Type | undefined => {
|
|
67
59
|
if (!type.isIntersection()) return undefined;
|
|
68
60
|
|
|
69
61
|
for (const intersectionType of type.types) {
|
|
@@ -9,7 +9,7 @@ import { Type } from "typescript";
|
|
|
9
9
|
export const isExtendsFromTargetSuperClass = (
|
|
10
10
|
type: Type,
|
|
11
11
|
targetSuperClasses: string[],
|
|
12
|
-
typeCheckFunction: (type: Type) => boolean
|
|
12
|
+
typeCheckFunction: (type: Type) => boolean,
|
|
13
13
|
): boolean => {
|
|
14
14
|
if (!type.symbol) return false;
|
|
15
15
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { isClassDeclaration, isConstructorDeclaration, Type } from "typescript";
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
/**
|
|
5
4
|
* Parses type to get the property names of the class constructor.
|
|
6
5
|
* @returns The property names of the class constructor.
|
|
@@ -12,9 +11,7 @@ export const findConstructorPropertyNames = (type: Type): string[] => {
|
|
|
12
11
|
const classDeclaration = declarations[0];
|
|
13
12
|
if (!isClassDeclaration(classDeclaration)) return [];
|
|
14
13
|
|
|
15
|
-
const constructor = classDeclaration.members.find((member) =>
|
|
16
|
-
isConstructorDeclaration(member)
|
|
17
|
-
);
|
|
14
|
+
const constructor = classDeclaration.members.find((member) => isConstructorDeclaration(member));
|
|
18
15
|
if (!constructor?.parameters.length) return [];
|
|
19
16
|
|
|
20
17
|
return constructor.parameters.map((param) => param.name.getText());
|
|
@@ -18,11 +18,7 @@ export const findGenericsTypeArgument = (type: Type): Type | undefined => {
|
|
|
18
18
|
|
|
19
19
|
// NOTE: Check if type has typeArguments (generics types like Array<T>, etc.)
|
|
20
20
|
// This works for TypeReference types
|
|
21
|
-
if (
|
|
22
|
-
"typeArguments" in type &&
|
|
23
|
-
Array.isArray(type.typeArguments) &&
|
|
24
|
-
type.typeArguments?.length
|
|
25
|
-
) {
|
|
21
|
+
if ("typeArguments" in type && Array.isArray(type.typeArguments) && type.typeArguments?.length) {
|
|
26
22
|
return type.typeArguments[0] as Type;
|
|
27
23
|
}
|
|
28
24
|
|
|
@@ -11,16 +11,14 @@ import { isConstructType } from "../core/cdk-construct/type-checker/is-construct
|
|
|
11
11
|
import { createRule } from "../shared/create-rule";
|
|
12
12
|
|
|
13
13
|
type Context = TSESLint.RuleContext<
|
|
14
|
-
| "
|
|
15
|
-
| "invalidConstructorType"
|
|
16
|
-
| "invalidConstructorIdType",
|
|
14
|
+
"invalidConstructorProperty" | "invalidConstructorType" | "invalidConstructorIdType",
|
|
17
15
|
[]
|
|
18
16
|
>;
|
|
19
17
|
|
|
20
18
|
type ConstructorProperties = [
|
|
21
19
|
TSESTree.Parameter,
|
|
22
20
|
TSESTree.Parameter,
|
|
23
|
-
TSESTree.Parameter | undefined
|
|
21
|
+
TSESTree.Parameter | undefined,
|
|
24
22
|
];
|
|
25
23
|
|
|
26
24
|
/**
|
|
@@ -73,7 +71,7 @@ export const constructConstructorProperty = createRule({
|
|
|
73
71
|
*/
|
|
74
72
|
const checkNumOfConstructorProperty = (
|
|
75
73
|
constructor: TSESTree.MethodDefinition,
|
|
76
|
-
context: Context
|
|
74
|
+
context: Context,
|
|
77
75
|
): ConstructorProperties | undefined => {
|
|
78
76
|
const params = constructor.value.params;
|
|
79
77
|
if (params.length < 2) {
|
|
@@ -92,12 +90,9 @@ const checkNumOfConstructorProperty = (
|
|
|
92
90
|
const checkFirstParamIsScope = (
|
|
93
91
|
firstParam: ConstructorProperties[0],
|
|
94
92
|
context: Context,
|
|
95
|
-
parserServices: ParserServicesWithTypeInformation
|
|
93
|
+
parserServices: ParserServicesWithTypeInformation,
|
|
96
94
|
) => {
|
|
97
|
-
if (
|
|
98
|
-
firstParam.type !== AST_NODE_TYPES.Identifier ||
|
|
99
|
-
firstParam.name !== "scope"
|
|
100
|
-
) {
|
|
95
|
+
if (firstParam.type !== AST_NODE_TYPES.Identifier || firstParam.name !== "scope") {
|
|
101
96
|
context.report({
|
|
102
97
|
node: firstParam,
|
|
103
98
|
messageId: "invalidConstructorProperty",
|
|
@@ -113,22 +108,13 @@ const checkFirstParamIsScope = (
|
|
|
113
108
|
/**
|
|
114
109
|
* Checks if the second parameter is named "id" and of type string
|
|
115
110
|
*/
|
|
116
|
-
const checkSecondParamIsId = (
|
|
117
|
-
secondParam
|
|
118
|
-
context: Context
|
|
119
|
-
) => {
|
|
120
|
-
if (
|
|
121
|
-
secondParam.type !== AST_NODE_TYPES.Identifier ||
|
|
122
|
-
secondParam.name !== "id"
|
|
123
|
-
) {
|
|
111
|
+
const checkSecondParamIsId = (secondParam: ConstructorProperties[1], context: Context) => {
|
|
112
|
+
if (secondParam.type !== AST_NODE_TYPES.Identifier || secondParam.name !== "id") {
|
|
124
113
|
context.report({
|
|
125
114
|
node: secondParam,
|
|
126
115
|
messageId: "invalidConstructorProperty",
|
|
127
116
|
});
|
|
128
|
-
} else if (
|
|
129
|
-
secondParam.typeAnnotation?.typeAnnotation.type !==
|
|
130
|
-
AST_NODE_TYPES.TSStringKeyword
|
|
131
|
-
) {
|
|
117
|
+
} else if (secondParam.typeAnnotation?.typeAnnotation.type !== AST_NODE_TYPES.TSStringKeyword) {
|
|
132
118
|
context.report({
|
|
133
119
|
node: secondParam,
|
|
134
120
|
messageId: "invalidConstructorIdType",
|
|
@@ -139,15 +125,9 @@ const checkSecondParamIsId = (
|
|
|
139
125
|
/**
|
|
140
126
|
* Checks if the third parameter is named "props"
|
|
141
127
|
*/
|
|
142
|
-
const checkThirdParamIsProps = (
|
|
143
|
-
thirdParam: ConstructorProperties[2],
|
|
144
|
-
context: Context
|
|
145
|
-
) => {
|
|
128
|
+
const checkThirdParamIsProps = (thirdParam: ConstructorProperties[2], context: Context) => {
|
|
146
129
|
if (!thirdParam) return;
|
|
147
|
-
if (
|
|
148
|
-
thirdParam.type !== AST_NODE_TYPES.Identifier ||
|
|
149
|
-
thirdParam.name !== "props"
|
|
150
|
-
) {
|
|
130
|
+
if (thirdParam.type !== AST_NODE_TYPES.Identifier || thirdParam.name !== "props") {
|
|
151
131
|
context.report({
|
|
152
132
|
node: thirdParam,
|
|
153
133
|
messageId: "invalidConstructorProperty",
|
package/src/rules/index.ts
CHANGED
|
@@ -17,8 +17,7 @@ import { requirePropsDefaultDoc } from "./require-props-default-doc";
|
|
|
17
17
|
export const rules = {
|
|
18
18
|
"construct-constructor-property": constructConstructorProperty,
|
|
19
19
|
"no-construct-in-interface": noConstructInInterface,
|
|
20
|
-
"no-construct-in-public-property-of-construct":
|
|
21
|
-
noConstructInPublicPropertyOfConstruct,
|
|
20
|
+
"no-construct-in-public-property-of-construct": noConstructInPublicPropertyOfConstruct,
|
|
22
21
|
"no-construct-stack-suffix": noConstructStackSuffix,
|
|
23
22
|
"no-import-private": noImportPrivate,
|
|
24
23
|
"no-mutable-property-of-props-interface": noMutablePropertyOfPropsInterface,
|
|
@@ -54,7 +54,7 @@ export const noConstructInPublicPropertyOfConstruct = createRule({
|
|
|
54
54
|
const validatePublicProperty = (
|
|
55
55
|
publicProperty: PublicProperty,
|
|
56
56
|
context: Context,
|
|
57
|
-
parserServices: ParserServicesWithTypeInformation
|
|
57
|
+
parserServices: ParserServicesWithTypeInformation,
|
|
58
58
|
) => {
|
|
59
59
|
const type = parserServices.getTypeAtLocation(publicProperty.node);
|
|
60
60
|
const constructType = findTypeOfCdkConstruct(type);
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AST_NODE_TYPES,
|
|
3
|
-
ESLintUtils,
|
|
4
|
-
TSESLint,
|
|
5
|
-
TSESTree,
|
|
6
|
-
} from "@typescript-eslint/utils";
|
|
1
|
+
import { AST_NODE_TYPES, ESLintUtils, TSESLint, TSESTree } from "@typescript-eslint/utils";
|
|
7
2
|
|
|
8
3
|
import { isConstructOrStackType } from "../core/cdk-construct/type-checker/is-construct-or-stack";
|
|
9
4
|
import { findConstructorPropertyNames } from "../core/ts-type/finder/constructor-property-name";
|
|
@@ -37,12 +32,10 @@ export const noConstructStackSuffix = createRule({
|
|
|
37
32
|
meta: {
|
|
38
33
|
type: "problem",
|
|
39
34
|
docs: {
|
|
40
|
-
description:
|
|
41
|
-
"Effort to avoid using 'Construct' and 'Stack' suffix in construct id.",
|
|
35
|
+
description: "Effort to avoid using 'Construct' and 'Stack' suffix in construct id.",
|
|
42
36
|
},
|
|
43
37
|
messages: {
|
|
44
|
-
invalidConstructId:
|
|
45
|
-
"{{ classType }} ID '{{ id }}' should not include {{ suffix }} suffix.",
|
|
38
|
+
invalidConstructId: "{{ classType }} ID '{{ id }}' should not include {{ suffix }} suffix.",
|
|
46
39
|
},
|
|
47
40
|
schema: [
|
|
48
41
|
{
|
|
@@ -84,18 +77,12 @@ export const noConstructStackSuffix = createRule({
|
|
|
84
77
|
/**
|
|
85
78
|
* Validate that construct ID does not end with "Construct" or "Stack"
|
|
86
79
|
*/
|
|
87
|
-
const validateConstructId = (
|
|
88
|
-
node: TSESTree.NewExpression,
|
|
89
|
-
context: Context
|
|
90
|
-
): void => {
|
|
80
|
+
const validateConstructId = (node: TSESTree.NewExpression, context: Context): void => {
|
|
91
81
|
const options = context.options[0] ?? defaultOption;
|
|
92
82
|
|
|
93
83
|
// NOTE: Treat the second argument as ID
|
|
94
84
|
const secondArg = node.arguments[1];
|
|
95
|
-
if (
|
|
96
|
-
secondArg.type !== AST_NODE_TYPES.Literal ||
|
|
97
|
-
typeof secondArg.value !== "string"
|
|
98
|
-
) {
|
|
85
|
+
if (secondArg.type !== AST_NODE_TYPES.Literal || typeof secondArg.value !== "string") {
|
|
99
86
|
return;
|
|
100
87
|
}
|
|
101
88
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import * as path from "path";
|
|
2
|
-
|
|
3
1
|
import { Rule } from "eslint";
|
|
2
|
+
import * as path from "path";
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Disallow importing modules from private directories at different levels of the hierarchy.
|
|
@@ -12,8 +11,7 @@ export const noImportPrivate: Rule.RuleModule = {
|
|
|
12
11
|
type: "problem",
|
|
13
12
|
docs: {
|
|
14
13
|
url: "https://eslint-cdk-plugin.dev/rules/no-import-private",
|
|
15
|
-
description:
|
|
16
|
-
"Cannot import modules from private dir at different levels of the hierarchy.",
|
|
14
|
+
description: "Cannot import modules from private dir at different levels of the hierarchy.",
|
|
17
15
|
},
|
|
18
16
|
messages: {
|
|
19
17
|
invalidImportPath:
|
|
@@ -39,9 +37,7 @@ export const noImportPrivate: Rule.RuleModule = {
|
|
|
39
37
|
const importDirSegments = getDirSegments(importDirBeforePrivate);
|
|
40
38
|
if (
|
|
41
39
|
currentDirSegments.length !== importDirSegments.length ||
|
|
42
|
-
currentDirSegments.some(
|
|
43
|
-
(segment, index) => segment !== importDirSegments[index]
|
|
44
|
-
)
|
|
40
|
+
currentDirSegments.some((segment, index) => segment !== importDirSegments[index])
|
|
45
41
|
) {
|
|
46
42
|
context.report({ node, messageId: "invalidImportPath" });
|
|
47
43
|
}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ESLintUtils,
|
|
3
|
-
TSESLint
|
|
4
|
-
} from "@typescript-eslint/utils";
|
|
1
|
+
import { ESLintUtils, TSESLint } from "@typescript-eslint/utils";
|
|
5
2
|
|
|
6
3
|
import {
|
|
7
4
|
findPublicPropertiesInClass,
|
|
@@ -72,12 +69,10 @@ const validatePublicProperty = (args: {
|
|
|
72
69
|
const accessibility = publicProperty.node.accessibility ? "public " : "";
|
|
73
70
|
const paramText = sourceCode.getText(publicProperty.node);
|
|
74
71
|
const [key, value] = paramText.split(":");
|
|
75
|
-
const replacedKey = key.startsWith("public ")
|
|
76
|
-
? key.replace("public ", "")
|
|
77
|
-
: key;
|
|
72
|
+
const replacedKey = key.startsWith("public ") ? key.replace("public ", "") : key;
|
|
78
73
|
return fixer.replaceText(
|
|
79
74
|
publicProperty.node,
|
|
80
|
-
`${accessibility}readonly ${replacedKey}:${value}
|
|
75
|
+
`${accessibility}readonly ${replacedKey}:${value}`,
|
|
81
76
|
);
|
|
82
77
|
},
|
|
83
78
|
});
|
|
@@ -47,8 +47,7 @@ export const noParentNameConstructIdMatch = createRule({
|
|
|
47
47
|
meta: {
|
|
48
48
|
type: "problem",
|
|
49
49
|
docs: {
|
|
50
|
-
description:
|
|
51
|
-
"Enforce that construct IDs does not match the parent construct name.",
|
|
50
|
+
description: "Enforce that construct IDs does not match the parent construct name.",
|
|
52
51
|
},
|
|
53
52
|
messages: {
|
|
54
53
|
invalidConstructId:
|
|
@@ -342,10 +341,7 @@ const validateConstructId = ({
|
|
|
342
341
|
|
|
343
342
|
// NOTE: Treat the second argument as ID
|
|
344
343
|
const secondArg = expression.arguments[1];
|
|
345
|
-
if (
|
|
346
|
-
secondArg.type !== AST_NODE_TYPES.Literal ||
|
|
347
|
-
typeof secondArg.value !== "string"
|
|
348
|
-
) {
|
|
344
|
+
if (secondArg.type !== AST_NODE_TYPES.Literal || typeof secondArg.value !== "string") {
|
|
349
345
|
return;
|
|
350
346
|
}
|
|
351
347
|
|