eslint-cdk-plugin 3.0.2 → 3.0.3

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.
@@ -5,6 +5,7 @@ import {
5
5
  TSESTree,
6
6
  } from "@typescript-eslint/utils";
7
7
 
8
+ import { createRule } from "../utils/createRule";
8
9
  import { isConstructType } from "../utils/typeCheck";
9
10
 
10
11
  type Context = TSESLint.RuleContext<"invalidConstructorProperty", []>;
@@ -13,47 +14,44 @@ type Context = TSESLint.RuleContext<"invalidConstructorProperty", []>;
13
14
  * Enforces that constructors of classes extending Construct have the property names 'scope, id' or 'scope, id, props'
14
15
  * @param context - The rule context provided by ESLint
15
16
  * @returns An object containing the AST visitor functions
16
- * @see {@link https://eslint-cdk-plugin.dev/rules/construct-constructor-property} - Documentation
17
17
  */
18
- export const constructConstructorProperty = ESLintUtils.RuleCreator.withoutDocs(
19
- {
20
- meta: {
21
- type: "problem",
22
- docs: {
23
- description:
24
- "Enforces that constructors of classes extending Construct have the property names 'scope, id' or 'scope, id, props'",
25
- },
26
- messages: {
27
- invalidConstructorProperty:
28
- "Constructor of a class extending Construct must have the property names 'scope, id' or 'scope, id, props'",
29
- },
30
- schema: [],
18
+ export const constructConstructorProperty = createRule({
19
+ name: "construct-constructor-property",
20
+ meta: {
21
+ type: "problem",
22
+ docs: {
23
+ description:
24
+ "Enforces that constructors of classes extending Construct have the property names 'scope, id' or 'scope, id, props'",
31
25
  },
32
- defaultOptions: [],
33
- create(context) {
34
- const parserServices = ESLintUtils.getParserServices(context);
35
-
36
- return {
37
- ClassDeclaration(node) {
38
- const type = parserServices.getTypeAtLocation(node);
39
- if (!isConstructType(type)) return;
26
+ messages: {
27
+ invalidConstructorProperty:
28
+ "Constructor of a class extending Construct must have the property names 'scope, id' or 'scope, id, props'",
29
+ },
30
+ schema: [],
31
+ },
32
+ defaultOptions: [],
33
+ create(context) {
34
+ const parserServices = ESLintUtils.getParserServices(context);
35
+ return {
36
+ ClassDeclaration(node) {
37
+ const type = parserServices.getTypeAtLocation(node);
38
+ if (!isConstructType(type)) return;
40
39
 
41
- // NOTE: Find the constructor method
42
- const constructor = node.body.body.find(
43
- (member): member is TSESTree.MethodDefinition =>
44
- member.type === AST_NODE_TYPES.MethodDefinition &&
45
- member.kind === "constructor"
46
- );
40
+ // NOTE: Find the constructor method
41
+ const constructor = node.body.body.find(
42
+ (member): member is TSESTree.MethodDefinition =>
43
+ member.type === AST_NODE_TYPES.MethodDefinition &&
44
+ member.kind === "constructor"
45
+ );
47
46
 
48
- // NOTE: Skip if there's no constructor
49
- if (!constructor) return;
47
+ // NOTE: Skip if there's no constructor
48
+ if (!constructor) return;
50
49
 
51
- validateConstructorProperty(constructor, context);
52
- },
53
- };
54
- },
55
- }
56
- );
50
+ validateConstructorProperty(constructor, context);
51
+ },
52
+ };
53
+ },
54
+ });
57
55
 
58
56
  /**
59
57
  * Validates that the constructor has the property names "scope, id" or "scope, id, props"
@@ -1,15 +1,16 @@
1
1
  import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
2
2
 
3
3
  import { SYMBOL_FLAGS } from "../constants/tsInternalFlags";
4
+ import { createRule } from "../utils/createRule";
4
5
  import { isConstructOrStackType } from "../utils/typeCheck";
5
6
 
6
7
  /**
7
8
  * Enforces the use of interface types instead of CDK Construct types in interface properties
8
9
  * @param context - The rule context provided by ESLint
9
10
  * @returns An object containing the AST visitor functions
10
- * @see {@link https://eslint-cdk-plugin.dev/rules/no-class-in-interface} - Documentation
11
11
  */
12
- export const noConstructInInterface = ESLintUtils.RuleCreator.withoutDocs({
12
+ export const noConstructInInterface = createRule({
13
+ name: "no-construct-in-interface",
13
14
  meta: {
14
15
  type: "problem",
15
16
  docs: {
@@ -7,6 +7,7 @@ import {
7
7
  } from "@typescript-eslint/utils";
8
8
 
9
9
  import { SYMBOL_FLAGS } from "../constants/tsInternalFlags";
10
+ import { createRule } from "../utils/createRule";
10
11
  import { isConstructOrStackType } from "../utils/typeCheck";
11
12
 
12
13
  type Context = TSESLint.RuleContext<"invalidPublicPropertyOfConstruct", []>;
@@ -15,54 +16,53 @@ type Context = TSESLint.RuleContext<"invalidPublicPropertyOfConstruct", []>;
15
16
  * Disallow Construct types in public property of Construct
16
17
  * @param context - The rule context provided by ESLint
17
18
  * @returns An object containing the AST visitor functions
18
- * @see {@link https://eslint-cdk-plugin.dev/rules/no-construct-in-public-property-of-construct} - Documentation
19
19
  */
20
- export const noConstructInPublicPropertyOfConstruct =
21
- ESLintUtils.RuleCreator.withoutDocs({
22
- meta: {
23
- type: "problem",
24
- docs: {
25
- description: "Disallow Construct types in public property of Construct",
26
- },
27
- messages: {
28
- invalidPublicPropertyOfConstruct:
29
- "Public property '{{ propertyName }}' of Construct should not use Construct type '{{ typeName }}'. Consider using an interface or type alias instead.",
30
- },
31
- schema: [],
20
+ export const noConstructInPublicPropertyOfConstruct = createRule({
21
+ name: "no-construct-in-public-property-of-construct",
22
+ meta: {
23
+ type: "problem",
24
+ docs: {
25
+ description: "Disallow Construct types in public property of Construct",
32
26
  },
33
- defaultOptions: [],
34
- create(context) {
35
- const parserServices = ESLintUtils.getParserServices(context);
36
- return {
37
- ClassDeclaration(node) {
38
- const type = parserServices.getTypeAtLocation(node);
39
- if (!isConstructOrStackType(type)) return;
40
-
41
- // NOTE: Check class members
42
- validatePublicPropertyOfConstruct(node, context, parserServices);
43
-
44
- // NOTE: Check constructor parameter properties
45
- const constructor = node.body.body.find(
46
- (member): member is TSESTree.MethodDefinition =>
47
- member.type === AST_NODE_TYPES.MethodDefinition &&
48
- member.kind === "constructor"
49
- );
50
- if (
51
- !constructor ||
52
- constructor.value.type !== AST_NODE_TYPES.FunctionExpression
53
- ) {
54
- return;
55
- }
56
-
57
- validateConstructorParameterProperty(
58
- constructor,
59
- context,
60
- parserServices
61
- );
62
- },
63
- };
27
+ messages: {
28
+ invalidPublicPropertyOfConstruct:
29
+ "Public property '{{ propertyName }}' of Construct should not use Construct type '{{ typeName }}'. Consider using an interface or type alias instead.",
64
30
  },
65
- });
31
+ schema: [],
32
+ },
33
+ defaultOptions: [],
34
+ create(context) {
35
+ const parserServices = ESLintUtils.getParserServices(context);
36
+ return {
37
+ ClassDeclaration(node) {
38
+ const type = parserServices.getTypeAtLocation(node);
39
+ if (!isConstructOrStackType(type)) return;
40
+
41
+ // NOTE: Check class members
42
+ validatePublicPropertyOfConstruct(node, context, parserServices);
43
+
44
+ // NOTE: Check constructor parameter properties
45
+ const constructor = node.body.body.find(
46
+ (member): member is TSESTree.MethodDefinition =>
47
+ member.type === AST_NODE_TYPES.MethodDefinition &&
48
+ member.kind === "constructor"
49
+ );
50
+ if (
51
+ !constructor ||
52
+ constructor.value.type !== AST_NODE_TYPES.FunctionExpression
53
+ ) {
54
+ return;
55
+ }
56
+
57
+ validateConstructorParameterProperty(
58
+ constructor,
59
+ context,
60
+ parserServices
61
+ );
62
+ },
63
+ };
64
+ },
65
+ });
66
66
 
67
67
  /**
68
68
  * check the public property of Construct
@@ -6,6 +6,7 @@ import {
6
6
  } from "@typescript-eslint/utils";
7
7
 
8
8
  import { toPascalCase } from "../utils/convertString";
9
+ import { createRule } from "../utils/createRule";
9
10
  import { getConstructorPropertyNames } from "../utils/parseType";
10
11
  import { isConstructOrStackType } from "../utils/typeCheck";
11
12
 
@@ -28,9 +29,9 @@ type Context = TSESLint.RuleContext<"invalidConstructId", Options>;
28
29
  * Enforces that Construct IDs do not end with 'Construct' or 'Stack' suffix
29
30
  * @param context - The rule context provided by ESLint
30
31
  * @returns An object containing the AST visitor functions
31
- * @see {@link https://eslint-cdk-plugin.dev/rules/no-construct-stack-suffix} - Documentation
32
32
  */
33
- export const noConstructStackSuffix = ESLintUtils.RuleCreator.withoutDocs({
33
+ export const noConstructStackSuffix = createRule({
34
+ name: "no-construct-stack-suffix",
34
35
  meta: {
35
36
  type: "problem",
36
37
  docs: {
@@ -6,12 +6,12 @@ import { Rule } from "eslint";
6
6
  * Disallow importing modules from private directories at different levels of the hierarchy.
7
7
  * @param context - The rule context provided by ESLint
8
8
  * @returns An object containing the AST visitor functions
9
- * @see {@link https://eslint-cdk-plugin.dev/rules/no-import-private} - Documentation
10
9
  */
11
10
  export const noImportPrivate: Rule.RuleModule = {
12
11
  meta: {
13
12
  type: "problem",
14
13
  docs: {
14
+ url: "https://eslint-cdk-plugin.dev/rules/no-import-private",
15
15
  description:
16
16
  "Cannot import modules from private dir at different levels of the hierarchy.",
17
17
  },
@@ -1,60 +1,60 @@
1
- import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
1
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
2
+
3
+ import { createRule } from "../utils/createRule";
2
4
 
3
5
  /**
4
6
  * Disallow mutable properties of Construct Props (interface)
5
7
  * @param context - The rule context provided by ESLint
6
8
  * @returns An object containing the AST visitor functions
7
- * @see {@link https://eslint-cdk-plugin.dev/rules/no-mutable-property-of-props-interface} - Documentation
8
9
  */
9
- export const noMutablePropertyOfPropsInterface =
10
- ESLintUtils.RuleCreator.withoutDocs({
11
- meta: {
12
- type: "problem",
13
- docs: {
14
- description:
15
- "Disallow mutable properties of Construct Props (interface)",
16
- },
17
- fixable: "code",
18
- messages: {
19
- invalidPropertyOfPropsInterface:
20
- "Property '{{ propertyName }}' of Construct Props should be readonly.",
21
- },
22
- schema: [],
10
+ export const noMutablePropertyOfPropsInterface = createRule({
11
+ name: "no-mutable-property-of-props-interface",
12
+ meta: {
13
+ type: "problem",
14
+ docs: {
15
+ description: "Disallow mutable properties of Construct Props (interface)",
16
+ },
17
+ fixable: "code",
18
+ messages: {
19
+ invalidPropertyOfPropsInterface:
20
+ "Property '{{ propertyName }}' of Construct Props should be readonly.",
23
21
  },
24
- defaultOptions: [],
25
- create(context) {
26
- return {
27
- TSInterfaceDeclaration(node) {
28
- const sourceCode = context.sourceCode;
22
+ schema: [],
23
+ },
24
+ defaultOptions: [],
25
+ create(context) {
26
+ return {
27
+ TSInterfaceDeclaration(node) {
28
+ const sourceCode = context.sourceCode;
29
29
 
30
- // NOTE: Interface name check for "Props"
31
- if (!node.id.name.endsWith("Props")) return;
30
+ // NOTE: Interface name check for "Props"
31
+ if (!node.id.name.endsWith("Props")) return;
32
32
 
33
- for (const property of node.body.body) {
34
- // NOTE: check property signature
35
- if (
36
- property.type !== AST_NODE_TYPES.TSPropertySignature ||
37
- property.key.type !== AST_NODE_TYPES.Identifier
38
- ) {
39
- continue;
40
- }
33
+ for (const property of node.body.body) {
34
+ // NOTE: check property signature
35
+ if (
36
+ property.type !== AST_NODE_TYPES.TSPropertySignature ||
37
+ property.key.type !== AST_NODE_TYPES.Identifier
38
+ ) {
39
+ continue;
40
+ }
41
41
 
42
- // NOTE: Skip if already readonly
43
- if (property.readonly) continue;
42
+ // NOTE: Skip if already readonly
43
+ if (property.readonly) continue;
44
44
 
45
- context.report({
46
- node: property,
47
- messageId: "invalidPropertyOfPropsInterface",
48
- data: {
49
- propertyName: property.key.name,
50
- },
51
- fix: (fixer) => {
52
- const propertyText = sourceCode.getText(property);
53
- return fixer.replaceText(property, `readonly ${propertyText}`);
54
- },
55
- });
56
- }
57
- },
58
- };
59
- },
60
- });
45
+ context.report({
46
+ node: property,
47
+ messageId: "invalidPropertyOfPropsInterface",
48
+ data: {
49
+ propertyName: property.key.name,
50
+ },
51
+ fix: (fixer) => {
52
+ const propertyText = sourceCode.getText(property);
53
+ return fixer.replaceText(property, `readonly ${propertyText}`);
54
+ },
55
+ });
56
+ }
57
+ },
58
+ };
59
+ },
60
+ });
@@ -1,76 +1,76 @@
1
1
  import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
2
2
 
3
+ import { createRule } from "../utils/createRule";
3
4
  import { isConstructOrStackType } from "../utils/typeCheck";
4
5
 
5
6
  /**
6
7
  * Disallow mutable public properties of Construct
7
8
  * @param context - The rule context provided by ESLint
8
9
  * @returns An object containing the AST visitor functions
9
- * @see {@link https://eslint-cdk-plugin.dev/rules/no-mutable-public-property-of-construct} - Documentation
10
10
  */
11
- export const noMutablePublicPropertyOfConstruct =
12
- ESLintUtils.RuleCreator.withoutDocs({
13
- meta: {
14
- type: "problem",
15
- docs: {
16
- description: "Disallow mutable public properties of Construct",
17
- },
18
- fixable: "code",
19
- messages: {
20
- invalidPublicPropertyOfConstruct:
21
- "Public property '{{ propertyName }}' should be readonly. Consider adding the 'readonly' modifier.",
22
- },
23
- schema: [],
11
+ export const noMutablePublicPropertyOfConstruct = createRule({
12
+ name: "no-mutable-public-property-of-construct",
13
+ meta: {
14
+ type: "problem",
15
+ docs: {
16
+ description: "Disallow mutable public properties of Construct",
24
17
  },
25
- defaultOptions: [],
26
- create(context) {
27
- const parserServices = ESLintUtils.getParserServices(context);
18
+ fixable: "code",
19
+ messages: {
20
+ invalidPublicPropertyOfConstruct:
21
+ "Public property '{{ propertyName }}' should be readonly. Consider adding the 'readonly' modifier.",
22
+ },
23
+ schema: [],
24
+ },
25
+ defaultOptions: [],
26
+ create(context) {
27
+ const parserServices = ESLintUtils.getParserServices(context);
28
28
 
29
- return {
30
- ClassDeclaration(node) {
31
- const sourceCode = context.sourceCode;
32
- const type = parserServices.getTypeAtLocation(node);
33
- if (!isConstructOrStackType(type)) return;
29
+ return {
30
+ ClassDeclaration(node) {
31
+ const sourceCode = context.sourceCode;
32
+ const type = parserServices.getTypeAtLocation(node);
33
+ if (!isConstructOrStackType(type)) return;
34
34
 
35
- for (const member of node.body.body) {
36
- // NOTE: check property definition
37
- if (
38
- member.type !== AST_NODE_TYPES.PropertyDefinition ||
39
- member.key.type !== AST_NODE_TYPES.Identifier
40
- ) {
41
- continue;
42
- }
35
+ for (const member of node.body.body) {
36
+ // NOTE: check property definition
37
+ if (
38
+ member.type !== AST_NODE_TYPES.PropertyDefinition ||
39
+ member.key.type !== AST_NODE_TYPES.Identifier
40
+ ) {
41
+ continue;
42
+ }
43
43
 
44
- // NOTE: Skip private and protected fields
45
- if (["private", "protected"].includes(member.accessibility ?? "")) {
46
- continue;
47
- }
44
+ // NOTE: Skip private and protected fields
45
+ if (["private", "protected"].includes(member.accessibility ?? "")) {
46
+ continue;
47
+ }
48
48
 
49
- // NOTE: Skip if readonly is present
50
- if (member.readonly) continue;
49
+ // NOTE: Skip if readonly is present
50
+ if (member.readonly) continue;
51
51
 
52
- context.report({
53
- node: member,
54
- messageId: "invalidPublicPropertyOfConstruct",
55
- data: {
56
- propertyName: member.key.name,
57
- },
58
- fix: (fixer) => {
59
- const accessibility = member.accessibility ? "public " : "";
60
- const paramText = sourceCode.getText(member);
61
- const [key, value] = paramText.split(":");
62
- const replacedKey = key.startsWith("public ")
63
- ? key.replace("public ", "")
64
- : key;
52
+ context.report({
53
+ node: member,
54
+ messageId: "invalidPublicPropertyOfConstruct",
55
+ data: {
56
+ propertyName: member.key.name,
57
+ },
58
+ fix: (fixer) => {
59
+ const accessibility = member.accessibility ? "public " : "";
60
+ const paramText = sourceCode.getText(member);
61
+ const [key, value] = paramText.split(":");
62
+ const replacedKey = key.startsWith("public ")
63
+ ? key.replace("public ", "")
64
+ : key;
65
65
 
66
- return fixer.replaceText(
67
- member,
68
- `${accessibility}readonly ${replacedKey}:${value}`
69
- );
70
- },
71
- });
72
- }
73
- },
74
- };
75
- },
76
- });
66
+ return fixer.replaceText(
67
+ member,
68
+ `${accessibility}readonly ${replacedKey}:${value}`
69
+ );
70
+ },
71
+ });
72
+ }
73
+ },
74
+ };
75
+ },
76
+ });
@@ -7,6 +7,7 @@ import {
7
7
  } from "@typescript-eslint/utils";
8
8
 
9
9
  import { toPascalCase } from "../utils/convertString";
10
+ import { createRule } from "../utils/createRule";
10
11
  import { isConstructOrStackType, isConstructType } from "../utils/typeCheck";
11
12
 
12
13
  type Options = [
@@ -37,78 +38,76 @@ type ValidateExpressionArgs<T extends TSESTree.Expression> = {
37
38
  * Enforce that construct IDs does not match the parent construct name.
38
39
  * @param context - The rule context provided by ESLint
39
40
  * @returns An object containing the AST visitor functions
40
- * @see {@link https://eslint-cdk-plugin.dev/rules/no-parent-name-construct-id-match} - Documentation
41
41
  */
42
- export const noParentNameConstructIdMatch = ESLintUtils.RuleCreator.withoutDocs(
43
- {
44
- meta: {
45
- type: "problem",
46
- docs: {
47
- description:
48
- "Enforce that construct IDs does not match the parent construct name.",
49
- },
50
- messages: {
51
- invalidConstructId:
52
- "Construct ID '{{ constructId }}' should not match parent construct name '{{ parentConstructName }}'. Use a more specific identifier.",
53
- },
54
- schema: [
55
- {
56
- type: "object",
57
- properties: {
58
- disallowContainingParentName: {
59
- type: "boolean",
60
- default: false,
61
- },
62
- },
63
- additionalProperties: false,
64
- },
65
- ],
42
+ export const noParentNameConstructIdMatch = createRule({
43
+ name: "no-parent-name-construct-id-match",
44
+ meta: {
45
+ type: "problem",
46
+ docs: {
47
+ description:
48
+ "Enforce that construct IDs does not match the parent construct name.",
66
49
  },
67
- defaultOptions: [
50
+ messages: {
51
+ invalidConstructId:
52
+ "Construct ID '{{ constructId }}' should not match parent construct name '{{ parentConstructName }}'. Use a more specific identifier.",
53
+ },
54
+ schema: [
68
55
  {
69
- disallowContainingParentName: false,
56
+ type: "object",
57
+ properties: {
58
+ disallowContainingParentName: {
59
+ type: "boolean",
60
+ default: false,
61
+ },
62
+ },
63
+ additionalProperties: false,
70
64
  },
71
65
  ],
66
+ },
67
+ defaultOptions: [
68
+ {
69
+ disallowContainingParentName: false,
70
+ },
71
+ ],
72
72
 
73
- create(context: Context) {
74
- const option = context.options[0] || {
75
- disallowContainingParentName: false,
76
- };
77
- const parserServices = ESLintUtils.getParserServices(context);
78
- return {
79
- ClassBody(node) {
80
- const type = parserServices.getTypeAtLocation(node);
73
+ create(context: Context) {
74
+ const option = context.options[0] || {
75
+ disallowContainingParentName: false,
76
+ };
77
+ const parserServices = ESLintUtils.getParserServices(context);
78
+ return {
79
+ ClassBody(node) {
80
+ const type = parserServices.getTypeAtLocation(node);
81
81
 
82
- if (!isConstructOrStackType(type)) return;
82
+ if (!isConstructOrStackType(type)) return;
83
83
 
84
- const parent = node.parent;
85
- if (parent?.type !== AST_NODE_TYPES.ClassDeclaration) return;
84
+ const parent = node.parent;
85
+ if (parent?.type !== AST_NODE_TYPES.ClassDeclaration) return;
86
86
 
87
- const parentClassName = parent.id?.name;
88
- if (!parentClassName) return;
87
+ const parentClassName = parent.id?.name;
88
+ if (!parentClassName) return;
89
89
 
90
- for (const body of node.body) {
91
- // NOTE: Ignore if neither method nor constructor.
92
- if (
93
- body.type !== AST_NODE_TYPES.MethodDefinition ||
94
- !["method", "constructor"].includes(body.kind) ||
95
- body.value.type !== AST_NODE_TYPES.FunctionExpression
96
- ) {
97
- continue;
98
- }
99
- validateConstructorBody({
100
- expression: body.value,
101
- parentClassName,
102
- context,
103
- parserServices,
104
- option,
105
- });
90
+ for (const body of node.body) {
91
+ // NOTE: Ignore if neither method nor constructor.
92
+ if (
93
+ body.type !== AST_NODE_TYPES.MethodDefinition ||
94
+ !["method", "constructor"].includes(body.kind) ||
95
+ body.value.type !== AST_NODE_TYPES.FunctionExpression
96
+ ) {
97
+ continue;
106
98
  }
107
- },
108
- };
109
- },
110
- }
111
- );
99
+ validateConstructorBody({
100
+ expression: body.value,
101
+ parentClassName,
102
+ context,
103
+ parserServices,
104
+ option,
105
+ });
106
+ }
107
+ },
108
+ };
109
+ },
110
+ });
112
111
 
113
112
  /**
114
113
  * Validate the constructor body for the parent class
@@ -5,6 +5,7 @@ import {
5
5
  TSESTree,
6
6
  } from "@typescript-eslint/utils";
7
7
 
8
+ import { createRule } from "../utils/createRule";
8
9
  import { getConstructorPropertyNames } from "../utils/parseType";
9
10
  import { isConstructType } from "../utils/typeCheck";
10
11
 
@@ -15,7 +16,8 @@ type Context = TSESLint.RuleContext<"invalidConstructId", []>;
15
16
  * @param context - The rule context provided by ESLint
16
17
  * @returns An object containing the AST visitor functions
17
18
  */
18
- export const noVariableConstructId = ESLintUtils.RuleCreator.withoutDocs({
19
+ export const noVariableConstructId = createRule({
20
+ name: "no-variable-construct-id",
19
21
  meta: {
20
22
  type: "problem",
21
23
  docs: {