eslint-cdk-plugin 3.0.3 → 3.1.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
@@ -35,29 +35,34 @@ Note: This plugin uses typescript type information and must be used in conjuncti
35
35
 
36
36
  ```js
37
37
  // eslint.config.mjs
38
+ import eslint from "@eslint/js";
39
+ import { defineConfig } from "eslint/config";
40
+ import tseslint from "typescript-eslint";
38
41
  import cdkPlugin from "eslint-cdk-plugin";
39
- import tsEslint from "typescript-eslint";
40
42
 
41
- export default [
42
- ...tsEslint.configs.recommended,
43
- // ✅ Add plugins
44
- cdkPlugin.configs.recommended,
43
+ export default defineConfig([
44
+ eslint.configs.recommended,
45
+ ...tseslint.configs.recommended,
45
46
  {
46
47
  files: ["lib/**/*.ts", "bin/*.ts"],
47
- // ... some configs
48
+ // Add plugins
49
+ extends: [cdkPlugin.configs.recommended],
48
50
  },
49
- ];
51
+ ]);
50
52
  ```
51
53
 
52
54
  ### When using custom config
53
55
 
54
56
  ```js
55
57
  // eslint.config.mjs
56
- import tsEslint from "typescript-eslint";
58
+ import eslint from "@eslint/js";
59
+ import { defineConfig } from "eslint/config";
60
+ import tseslint from "typescript-eslint";
57
61
  import cdkPlugin from "eslint-cdk-plugin";
58
62
 
59
- export default [
60
- ...tsEslint.configs.recommended,
63
+ export default defineConfig([
64
+ eslint.configs.recommended,
65
+ ...tseslint.configs.recommended,
61
66
  {
62
67
  files: ["lib/**/*.ts", "bin/*.ts"],
63
68
  languageOptions: {
@@ -77,7 +82,7 @@ export default [
77
82
  "cdk/no-parent-name-construct-id-match": "error",
78
83
  },
79
84
  },
80
- ];
85
+ ]);
81
86
  ```
82
87
 
83
88
  ## ❗ Issue
package/dist/index.cjs CHANGED
@@ -26,7 +26,7 @@ function _interopNamespaceDefault(e) {
26
26
  var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
27
27
 
28
28
  var name = "eslint-cdk-plugin";
29
- var version = "3.0.3";
29
+ var version = "3.1.0";
30
30
 
31
31
  const createRule = utils.ESLintUtils.RuleCreator(
32
32
  (name) => `https://eslint-cdk-plugin.dev/rules/${name}`
@@ -46,7 +46,7 @@ const isConstructType = (type, ignoredClasses = ["App", "Stage", "Stack"]) => {
46
46
  };
47
47
  const isTargetSuperClassType = (type, targetSuperClasses, typeCheckFunction) => {
48
48
  if (!type.symbol) return false;
49
- if (targetSuperClasses.some((suffix) => type.symbol.name.endsWith(suffix))) {
49
+ if (targetSuperClasses.some((suffix) => type.symbol.name === suffix)) {
50
50
  return true;
51
51
  }
52
52
  const baseTypes = type.getBaseTypes() ?? [];
@@ -61,7 +61,9 @@ const constructConstructorProperty = createRule({
61
61
  description: "Enforces that constructors of classes extending Construct have the property names 'scope, id' or 'scope, id, props'"
62
62
  },
63
63
  messages: {
64
- invalidConstructorProperty: "Constructor of a class extending Construct must have the property names 'scope, id' or 'scope, id, props'"
64
+ invalidConstructorProperty: "Constructor of a class extending Construct must have the property names 'scope, id' or 'scope, id, props'",
65
+ invalidConstructorType: "Constructor of a class extending Construct must have the type 'Construct' for the first parameter",
66
+ invalidConstructorIdType: "Constructor of a class extending Construct must have the type 'string' for the second parameter"
65
67
  },
66
68
  schema: []
67
69
  },
@@ -76,12 +78,12 @@ const constructConstructorProperty = createRule({
76
78
  (member) => member.type === utils.AST_NODE_TYPES.MethodDefinition && member.kind === "constructor"
77
79
  );
78
80
  if (!constructor) return;
79
- validateConstructorProperty(constructor, context);
81
+ validateConstructorProperty(constructor, context, parserServices);
80
82
  }
81
83
  };
82
84
  }
83
85
  });
84
- const validateConstructorProperty = (constructor, context) => {
86
+ const validateConstructorProperty = (constructor, context, parserServices) => {
85
87
  const params = constructor.value.params;
86
88
  if (params.length < 2) {
87
89
  context.report({
@@ -91,24 +93,35 @@ const validateConstructorProperty = (constructor, context) => {
91
93
  return;
92
94
  }
93
95
  const firstParam = params[0];
94
- if (firstParam.type === utils.AST_NODE_TYPES.Identifier && firstParam.name !== "scope") {
96
+ if (firstParam.type !== utils.AST_NODE_TYPES.Identifier || firstParam.name !== "scope") {
95
97
  context.report({
96
98
  node: firstParam,
97
99
  messageId: "invalidConstructorProperty"
98
100
  });
99
- return;
101
+ } else if (!isConstructType(parserServices.getTypeAtLocation(firstParam))) {
102
+ context.report({
103
+ node: firstParam,
104
+ messageId: "invalidConstructorType"
105
+ });
100
106
  }
101
107
  const secondParam = params[1];
102
- if (secondParam.type === utils.AST_NODE_TYPES.Identifier && secondParam.name !== "id") {
108
+ if (secondParam.type !== utils.AST_NODE_TYPES.Identifier || secondParam.name !== "id") {
103
109
  context.report({
104
110
  node: secondParam,
105
111
  messageId: "invalidConstructorProperty"
106
112
  });
107
113
  return;
114
+ } else if (secondParam.typeAnnotation?.typeAnnotation.type !== utils.AST_NODE_TYPES.TSStringKeyword) {
115
+ context.report({
116
+ node: secondParam,
117
+ messageId: "invalidConstructorIdType"
118
+ });
119
+ return;
108
120
  }
109
- if (params.length < 3) return;
121
+ if (params.length < 3)
122
+ return;
110
123
  const thirdParam = params[2];
111
- if (thirdParam.type === utils.AST_NODE_TYPES.Identifier && thirdParam.name !== "props") {
124
+ if (thirdParam.type !== utils.AST_NODE_TYPES.Identifier || thirdParam.name !== "props") {
112
125
  context.report({
113
126
  node: thirdParam,
114
127
  messageId: "invalidConstructorProperty"
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import tsParser from "@typescript-eslint/parser";
2
2
  declare const rules: {
3
- "construct-constructor-property": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidConstructorProperty", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
3
+ "construct-constructor-property": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidConstructorProperty" | "invalidConstructorType" | "invalidConstructorIdType", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
4
4
  "no-construct-in-interface": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidInterfaceProperty", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
5
5
  "no-construct-in-public-property-of-construct": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidPublicPropertyOfConstruct", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
6
6
  "no-construct-stack-suffix": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidConstructId", [{
@@ -36,7 +36,7 @@ declare const configs: {
36
36
  version: string;
37
37
  };
38
38
  rules: {
39
- "construct-constructor-property": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidConstructorProperty", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
39
+ "construct-constructor-property": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidConstructorProperty" | "invalidConstructorType" | "invalidConstructorIdType", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
40
40
  "no-construct-in-interface": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidInterfaceProperty", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
41
41
  "no-construct-in-public-property-of-construct": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidPublicPropertyOfConstruct", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
42
42
  "no-construct-stack-suffix": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidConstructId", [{
@@ -75,7 +75,7 @@ declare const configs: {
75
75
  version: string;
76
76
  };
77
77
  rules: {
78
- "construct-constructor-property": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidConstructorProperty", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
78
+ "construct-constructor-property": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidConstructorProperty" | "invalidConstructorType" | "invalidConstructorIdType", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
79
79
  "no-construct-in-interface": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidInterfaceProperty", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
80
80
  "no-construct-in-public-property-of-construct": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidPublicPropertyOfConstruct", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
81
81
  "no-construct-stack-suffix": import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidConstructId", [{
package/dist/index.mjs CHANGED
@@ -3,7 +3,7 @@ import { ESLintUtils, AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint
3
3
  import * as path from 'path';
4
4
 
5
5
  var name = "eslint-cdk-plugin";
6
- var version = "3.0.3";
6
+ var version = "3.1.0";
7
7
 
8
8
  const createRule = ESLintUtils.RuleCreator(
9
9
  (name) => `https://eslint-cdk-plugin.dev/rules/${name}`
@@ -23,7 +23,7 @@ const isConstructType = (type, ignoredClasses = ["App", "Stage", "Stack"]) => {
23
23
  };
24
24
  const isTargetSuperClassType = (type, targetSuperClasses, typeCheckFunction) => {
25
25
  if (!type.symbol) return false;
26
- if (targetSuperClasses.some((suffix) => type.symbol.name.endsWith(suffix))) {
26
+ if (targetSuperClasses.some((suffix) => type.symbol.name === suffix)) {
27
27
  return true;
28
28
  }
29
29
  const baseTypes = type.getBaseTypes() ?? [];
@@ -38,7 +38,9 @@ const constructConstructorProperty = createRule({
38
38
  description: "Enforces that constructors of classes extending Construct have the property names 'scope, id' or 'scope, id, props'"
39
39
  },
40
40
  messages: {
41
- invalidConstructorProperty: "Constructor of a class extending Construct must have the property names 'scope, id' or 'scope, id, props'"
41
+ invalidConstructorProperty: "Constructor of a class extending Construct must have the property names 'scope, id' or 'scope, id, props'",
42
+ invalidConstructorType: "Constructor of a class extending Construct must have the type 'Construct' for the first parameter",
43
+ invalidConstructorIdType: "Constructor of a class extending Construct must have the type 'string' for the second parameter"
42
44
  },
43
45
  schema: []
44
46
  },
@@ -53,12 +55,12 @@ const constructConstructorProperty = createRule({
53
55
  (member) => member.type === AST_NODE_TYPES.MethodDefinition && member.kind === "constructor"
54
56
  );
55
57
  if (!constructor) return;
56
- validateConstructorProperty(constructor, context);
58
+ validateConstructorProperty(constructor, context, parserServices);
57
59
  }
58
60
  };
59
61
  }
60
62
  });
61
- const validateConstructorProperty = (constructor, context) => {
63
+ const validateConstructorProperty = (constructor, context, parserServices) => {
62
64
  const params = constructor.value.params;
63
65
  if (params.length < 2) {
64
66
  context.report({
@@ -68,24 +70,35 @@ const validateConstructorProperty = (constructor, context) => {
68
70
  return;
69
71
  }
70
72
  const firstParam = params[0];
71
- if (firstParam.type === AST_NODE_TYPES.Identifier && firstParam.name !== "scope") {
73
+ if (firstParam.type !== AST_NODE_TYPES.Identifier || firstParam.name !== "scope") {
72
74
  context.report({
73
75
  node: firstParam,
74
76
  messageId: "invalidConstructorProperty"
75
77
  });
76
- return;
78
+ } else if (!isConstructType(parserServices.getTypeAtLocation(firstParam))) {
79
+ context.report({
80
+ node: firstParam,
81
+ messageId: "invalidConstructorType"
82
+ });
77
83
  }
78
84
  const secondParam = params[1];
79
- if (secondParam.type === AST_NODE_TYPES.Identifier && secondParam.name !== "id") {
85
+ if (secondParam.type !== AST_NODE_TYPES.Identifier || secondParam.name !== "id") {
80
86
  context.report({
81
87
  node: secondParam,
82
88
  messageId: "invalidConstructorProperty"
83
89
  });
84
90
  return;
91
+ } else if (secondParam.typeAnnotation?.typeAnnotation.type !== AST_NODE_TYPES.TSStringKeyword) {
92
+ context.report({
93
+ node: secondParam,
94
+ messageId: "invalidConstructorIdType"
95
+ });
96
+ return;
85
97
  }
86
- if (params.length < 3) return;
98
+ if (params.length < 3)
99
+ return;
87
100
  const thirdParam = params[2];
88
- if (thirdParam.type === AST_NODE_TYPES.Identifier && thirdParam.name !== "props") {
101
+ if (thirdParam.type !== AST_NODE_TYPES.Identifier || thirdParam.name !== "props") {
89
102
  context.report({
90
103
  node: thirdParam,
91
104
  messageId: "invalidConstructorProperty"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-cdk-plugin",
3
- "version": "3.0.3",
3
+ "version": "3.1.0",
4
4
  "description": "eslint plugin for AWS CDK projects",
5
5
  "main": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
@@ -39,7 +39,6 @@
39
39
  "standard-version": "^9.5.0",
40
40
  "typescript": "^5.8.3",
41
41
  "typescript-eslint": "^8.32.1",
42
- "vitepress-plugin-llms": "^1.1.4",
43
42
  "vitest": "^3.1.3"
44
43
  },
45
44
  "dependencies": {
@@ -47,8 +46,7 @@
47
46
  "@typescript-eslint/utils": "^8.32.1"
48
47
  },
49
48
  "volta": {
50
- "node": "22.15.0",
51
- "pnpm": "10.10.0"
49
+ "node": "22.15.0"
52
50
  },
53
51
  "files": [
54
52
  "dist",
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  AST_NODE_TYPES,
3
3
  ESLintUtils,
4
+ ParserServicesWithTypeInformation,
4
5
  TSESLint,
5
6
  TSESTree,
6
7
  } from "@typescript-eslint/utils";
@@ -8,7 +9,12 @@ import {
8
9
  import { createRule } from "../utils/createRule";
9
10
  import { isConstructType } from "../utils/typeCheck";
10
11
 
11
- type Context = TSESLint.RuleContext<"invalidConstructorProperty", []>;
12
+ type Context = TSESLint.RuleContext<
13
+ | "invalidConstructorProperty"
14
+ | "invalidConstructorType"
15
+ | "invalidConstructorIdType",
16
+ []
17
+ >;
12
18
 
13
19
  /**
14
20
  * Enforces that constructors of classes extending Construct have the property names 'scope, id' or 'scope, id, props'
@@ -26,6 +32,10 @@ export const constructConstructorProperty = createRule({
26
32
  messages: {
27
33
  invalidConstructorProperty:
28
34
  "Constructor of a class extending Construct must have the property names 'scope, id' or 'scope, id, props'",
35
+ invalidConstructorType:
36
+ "Constructor of a class extending Construct must have the type 'Construct' for the first parameter",
37
+ invalidConstructorIdType:
38
+ "Constructor of a class extending Construct must have the type 'string' for the second parameter",
29
39
  },
30
40
  schema: [],
31
41
  },
@@ -47,7 +57,7 @@ export const constructConstructorProperty = createRule({
47
57
  // NOTE: Skip if there's no constructor
48
58
  if (!constructor) return;
49
59
 
50
- validateConstructorProperty(constructor, context);
60
+ validateConstructorProperty(constructor, context, parserServices);
51
61
  },
52
62
  };
53
63
  },
@@ -58,7 +68,8 @@ export const constructConstructorProperty = createRule({
58
68
  */
59
69
  const validateConstructorProperty = (
60
70
  constructor: TSESTree.MethodDefinition,
61
- context: Context
71
+ context: Context,
72
+ parserServices: ParserServicesWithTypeInformation
62
73
  ): void => {
63
74
  const params = constructor.value.params;
64
75
 
@@ -74,20 +85,24 @@ const validateConstructorProperty = (
74
85
  // NOTE: Check if the first parameter is named "scope"
75
86
  const firstParam = params[0];
76
87
  if (
77
- firstParam.type === AST_NODE_TYPES.Identifier &&
88
+ firstParam.type !== AST_NODE_TYPES.Identifier ||
78
89
  firstParam.name !== "scope"
79
90
  ) {
80
91
  context.report({
81
92
  node: firstParam,
82
93
  messageId: "invalidConstructorProperty",
83
94
  });
84
- return;
95
+ } else if (!isConstructType(parserServices.getTypeAtLocation(firstParam))) {
96
+ context.report({
97
+ node: firstParam,
98
+ messageId: "invalidConstructorType",
99
+ });
85
100
  }
86
101
 
87
102
  // NOTE: Check if the second parameter is named "id"
88
103
  const secondParam = params[1];
89
104
  if (
90
- secondParam.type === AST_NODE_TYPES.Identifier &&
105
+ secondParam.type !== AST_NODE_TYPES.Identifier ||
91
106
  secondParam.name !== "id"
92
107
  ) {
93
108
  context.report({
@@ -95,15 +110,25 @@ const validateConstructorProperty = (
95
110
  messageId: "invalidConstructorProperty",
96
111
  });
97
112
  return;
113
+ } else if (
114
+ secondParam.typeAnnotation?.typeAnnotation.type !==
115
+ AST_NODE_TYPES.TSStringKeyword
116
+ ) {
117
+ context.report({
118
+ node: secondParam,
119
+ messageId: "invalidConstructorIdType",
120
+ });
121
+ return;
98
122
  }
99
123
 
100
- // NOTE: If there's no third parameter, return
101
- if (params.length < 3) return;
124
+ if (params.length < 3)
125
+ // NOTE: If there's no third parameter, return
126
+ return;
102
127
 
103
128
  // NOTE: Check if the third parameter is named "props"
104
129
  const thirdParam = params[2];
105
130
  if (
106
- thirdParam.type === AST_NODE_TYPES.Identifier &&
131
+ thirdParam.type !== AST_NODE_TYPES.Identifier ||
107
132
  thirdParam.name !== "props"
108
133
  ) {
109
134
  context.report({
@@ -48,7 +48,7 @@ const isTargetSuperClassType = (
48
48
  if (!type.symbol) return false;
49
49
 
50
50
  // NOTE: Check if the current type ends in target super class
51
- if (targetSuperClasses.some((suffix) => type.symbol.name.endsWith(suffix))) {
51
+ if (targetSuperClasses.some((suffix) => type.symbol.name === suffix)) {
52
52
  return true;
53
53
  }
54
54