eslint-cdk-plugin 1.1.0 → 2.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-cdk-plugin",
3
- "version": "1.1.0",
3
+ "version": "2.0.0",
4
4
  "description": "eslint plugin for AWS CDK projects",
5
5
  "main": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
@@ -20,7 +20,8 @@
20
20
  "build": "sh scripts/build.sh",
21
21
  "test": "vitest --run",
22
22
  "lint": "eslint --fix --config eslint.config.js",
23
- "type-check": "tsc --noEmit",
23
+ "check": "tsc --noEmit",
24
+ "pack": "pnpm run build && npm pack",
24
25
  "release:minor": "standard-version --release-as minor",
25
26
  "release:major": "standard-version --release-as major",
26
27
  "release:patch": "standard-version --release-as patch",
@@ -29,23 +30,23 @@
29
30
  "docs:preview": "cd ./docs && pnpm install && pnpm run preview"
30
31
  },
31
32
  "devDependencies": {
32
- "@eslint/js": "^9.15.0",
33
- "@types/estree": "^1.0.6",
34
- "@types/node": "^22.9.0",
35
- "@typescript-eslint/rule-tester": "^8.14.0",
36
- "eslint": "9.10.0",
33
+ "@eslint/js": "^9.22.0",
34
+ "@types/node": "^22.13.10",
35
+ "@typescript-eslint/rule-tester": "^8.26.0",
36
+ "eslint": "9.22.0",
37
37
  "eslint-plugin-import": "^2.31.0",
38
- "pkgroll": "^2.6.0",
38
+ "pkgroll": "^2.11.2",
39
39
  "standard-version": "^9.5.0",
40
- "typescript": "^5.6.3",
41
- "typescript-eslint": "^8.14.0",
42
- "vitest": "^2.1.5"
40
+ "typescript": "^5.8.2",
41
+ "typescript-eslint": "^8.26.0",
42
+ "vitest": "^3.0.8"
43
43
  },
44
44
  "dependencies": {
45
- "@typescript-eslint/utils": "^8.14.0"
45
+ "@typescript-eslint/parser": "^8.26.0",
46
+ "@typescript-eslint/utils": "^8.26.0"
46
47
  },
47
48
  "volta": {
48
- "node": "22.11.0"
49
+ "node": "22.14.0"
49
50
  },
50
51
  "files": [
51
52
  "dist",
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Implementing `SymbolFlags` defined in typescript on your own, in order not to include TypeScript in dependencies
3
+ */
4
+ export const SYMBOL_FLAGS = {
5
+ CLASS: 32,
6
+ } as const;
7
+
8
+ /**
9
+ * Implementing `SyntaxKind` defined in typescript on your own, in order not to include TypeScript in dependencies
10
+ */
11
+ export const SYNTAX_KIND = {
12
+ CLASS_DECLARATION: 263,
13
+ CONSTRUCTOR: 176,
14
+ } as const;
package/src/index.ts CHANGED
@@ -1,3 +1,8 @@
1
+ import tsParser from "@typescript-eslint/parser";
2
+
3
+ import { name, version } from "../package.json";
4
+
5
+ import { constructConstructorProperty } from "./rules/construct-constructor-property";
1
6
  import { noClassInInterface } from "./rules/no-class-in-interface";
2
7
  import { noConstructStackSuffix } from "./rules/no-construct-stack-suffix";
3
8
  import { noImportPrivate } from "./rules/no-import-private";
@@ -18,50 +23,71 @@ const rules = {
18
23
  "no-parent-name-construct-id-match": noParentNameConstructIdMatch,
19
24
  "no-public-class-fields": noPublicClassFields,
20
25
  "pascal-case-construct-id": pascalCaseConstructId,
21
- "no-mutable-public-fields": noMutablePublicFields,
22
- "no-mutable-props-interface": noMutablePropsInterface,
23
26
  "require-passing-this": requirePassingThis,
24
27
  "no-variable-construct-id": noVariableConstructId,
28
+ "no-mutable-public-fields": noMutablePublicFields,
29
+ "no-mutable-props-interface": noMutablePropsInterface,
30
+ "construct-constructor-property": constructConstructorProperty,
25
31
  "require-jsdoc": requireJSDoc,
26
32
  "require-props-default-doc": requirePropsDefaultDoc,
27
33
  "props-name-convention": propsNameConvention,
28
34
  "no-import-private": noImportPrivate,
29
35
  };
30
36
 
31
- const configs = {
32
- recommended: {
33
- plugins: ["cdk"],
34
- rules: {
35
- "cdk/no-class-in-interface": "error",
36
- "cdk/no-construct-stack-suffix": "error",
37
- "cdk/no-parent-name-construct-id-match": "error",
38
- "cdk/no-public-class-fields": "error",
39
- "cdk/pascal-case-construct-id": "error",
40
- "cdk/require-passing-this": "error",
41
- "cdk/no-variable-construct-id": "error",
42
- "cdk/no-mutable-public-fields": "warn",
43
- "cdk/no-mutable-props-interface": "warn",
44
- "cdk/props-name-convention": "warn",
37
+ const cdkPlugin = {
38
+ meta: { name, version },
39
+ rules,
40
+ };
41
+
42
+ const createFlatConfig = (rules: Record<string, unknown>) => {
43
+ return {
44
+ languageOptions: {
45
+ parserOptions: {
46
+ projectService: true,
47
+ parser: tsParser,
48
+ sourceType: "module",
49
+ },
45
50
  },
46
- },
47
- strict: {
48
- plugins: ["cdk"],
49
- rules: {
50
- "cdk/no-class-in-interface": "error",
51
- "cdk/no-construct-stack-suffix": "error",
52
- "cdk/no-parent-name-construct-id-match": "error",
53
- "cdk/no-public-class-fields": "error",
54
- "cdk/pascal-case-construct-id": "error",
55
- "cdk/require-passing-this": "error",
56
- "cdk/no-variable-construct-id": "error",
57
- "cdk/no-mutable-public-fields": "error",
58
- "cdk/no-mutable-props-interface": "error",
59
- "cdk/no-import-private": "error",
60
- "cdk/require-props-default-doc": "error",
61
- "cdk/props-name-convention": "error",
62
- "cdk/require-jsdoc": "error",
51
+ plugins: {
52
+ cdk: cdkPlugin,
63
53
  },
64
- },
54
+ rules,
55
+ };
56
+ };
57
+
58
+ const recommended = createFlatConfig({
59
+ "cdk/no-class-in-interface": "error",
60
+ "cdk/no-construct-stack-suffix": "error",
61
+ "cdk/no-parent-name-construct-id-match": "error",
62
+ "cdk/no-public-class-fields": "error",
63
+ "cdk/pascal-case-construct-id": "error",
64
+ "cdk/require-passing-this": ["error", { allowNonThisAndDisallowScope: true }],
65
+ "cdk/no-variable-construct-id": "error",
66
+ "cdk/no-mutable-public-fields": "warn",
67
+ "cdk/no-mutable-props-interface": "warn",
68
+ "cdk/construct-constructor-property": "error",
69
+ });
70
+
71
+ const strict = createFlatConfig({
72
+ "cdk/no-class-in-interface": "error",
73
+ "cdk/no-construct-stack-suffix": "error",
74
+ "cdk/no-parent-name-construct-id-match": "error",
75
+ "cdk/no-public-class-fields": "error",
76
+ "cdk/pascal-case-construct-id": "error",
77
+ "cdk/require-passing-this": "error",
78
+ "cdk/no-variable-construct-id": "error",
79
+ "cdk/no-mutable-public-fields": "error",
80
+ "cdk/no-mutable-props-interface": "error",
81
+ "cdk/construct-constructor-property": "error",
82
+ "cdk/require-jsdoc": "error",
83
+ "cdk/require-props-default-doc": "error",
84
+ "cdk/props-name-convention": "error",
85
+ "cdk/no-import-private": "error",
86
+ });
87
+
88
+ const configs = {
89
+ recommended,
90
+ strict,
65
91
  };
66
92
 
67
93
  export { configs, rules };
@@ -0,0 +1,117 @@
1
+ import {
2
+ AST_NODE_TYPES,
3
+ ESLintUtils,
4
+ TSESLint,
5
+ TSESTree,
6
+ } from "@typescript-eslint/utils";
7
+
8
+ import { isConstructType } from "../utils/typeCheck";
9
+
10
+ type Context = TSESLint.RuleContext<"invalidConstructorProperty", []>;
11
+
12
+ /**
13
+ * Enforces that constructors of classes extending Construct have the property names 'scope, id' or 'scope, id, props'
14
+ * @param context - The rule context provided by ESLint
15
+ * @returns An object containing the AST visitor functions
16
+ * @see {@link https://eslint-cdk-plugin.dev/rules/construct-constructor-property} - Documentation
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: [],
31
+ },
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;
40
+
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
+ );
47
+
48
+ // NOTE: Skip if there's no constructor
49
+ if (!constructor) return;
50
+
51
+ validateConstructorProperty(constructor, context);
52
+ },
53
+ };
54
+ },
55
+ }
56
+ );
57
+
58
+ /**
59
+ * Validates that the constructor has the property names "scope, id" or "scope, id, props"
60
+ */
61
+ const validateConstructorProperty = (
62
+ constructor: TSESTree.MethodDefinition,
63
+ context: Context
64
+ ): void => {
65
+ const params = constructor.value.params;
66
+
67
+ // NOTE: Check if the constructor has at least 2 parameters
68
+ if (params.length < 2) {
69
+ context.report({
70
+ node: constructor,
71
+ messageId: "invalidConstructorProperty",
72
+ });
73
+ return;
74
+ }
75
+
76
+ // NOTE: Check if the first parameter is named "scope"
77
+ const firstParam = params[0];
78
+ if (
79
+ firstParam.type === AST_NODE_TYPES.Identifier &&
80
+ firstParam.name !== "scope"
81
+ ) {
82
+ context.report({
83
+ node: constructor,
84
+ messageId: "invalidConstructorProperty",
85
+ });
86
+ return;
87
+ }
88
+
89
+ // NOTE: Check if the second parameter is named "id"
90
+ const secondParam = params[1];
91
+ if (
92
+ secondParam.type === AST_NODE_TYPES.Identifier &&
93
+ secondParam.name !== "id"
94
+ ) {
95
+ context.report({
96
+ node: constructor,
97
+ messageId: "invalidConstructorProperty",
98
+ });
99
+ return;
100
+ }
101
+
102
+ // NOTE: If there's no third parameter, return
103
+ if (params.length < 3) return;
104
+
105
+ // NOTE: Check if the third parameter is named "props"
106
+ const thirdParam = params[2];
107
+ if (
108
+ thirdParam.type === AST_NODE_TYPES.Identifier &&
109
+ thirdParam.name !== "props"
110
+ ) {
111
+ context.report({
112
+ node: constructor,
113
+ messageId: "invalidConstructorProperty",
114
+ });
115
+ return;
116
+ }
117
+ };
@@ -1,6 +1,6 @@
1
1
  import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
2
2
 
3
- import { SymbolFlags } from "../types/symbolFlags";
3
+ import { SYMBOL_FLAGS } from "../constants/tsInternalFlags";
4
4
 
5
5
  /**
6
6
  * Enforces the use of interface types instead of class in interface properties
@@ -37,8 +37,10 @@ export const noClassInInterface = ESLintUtils.RuleCreator.withoutDocs({
37
37
  const type = parserServices.getTypeAtLocation(property);
38
38
  if (!type.symbol) continue;
39
39
 
40
- // NOTE: check class type
41
- const isClass = type.symbol.flags === SymbolFlags.Class;
40
+ // NOTE: In order not to make it dependent on the typescript library, it defines its own unions.
41
+ // Therefore, the type information structures do not match.
42
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
43
+ const isClass = type.symbol.flags === SYMBOL_FLAGS.CLASS;
42
44
  if (!isClass) continue;
43
45
 
44
46
  context.report({
@@ -9,7 +9,20 @@ import { toPascalCase } from "../utils/convertString";
9
9
  import { getConstructorPropertyNames } from "../utils/parseType";
10
10
  import { isConstructOrStackType } from "../utils/typeCheck";
11
11
 
12
- type Context = TSESLint.RuleContext<"noConstructStackSuffix", []>;
12
+ const SUFFIX_TYPE = {
13
+ CONSTRUCT: "Construct",
14
+ STACK: "Stack",
15
+ } as const;
16
+
17
+ type SuffixType = (typeof SUFFIX_TYPE)[keyof typeof SUFFIX_TYPE];
18
+
19
+ type Options = [
20
+ {
21
+ disallowedSuffixes?: SuffixType[];
22
+ }
23
+ ];
24
+
25
+ type Context = TSESLint.RuleContext<"noConstructStackSuffix", Options>;
13
26
 
14
27
  /**
15
28
  * Enforces that Construct IDs do not end with 'Construct' or 'Stack' suffix
@@ -28,11 +41,34 @@ export const noConstructStackSuffix = ESLintUtils.RuleCreator.withoutDocs({
28
41
  noConstructStackSuffix:
29
42
  "{{ classType }} ID '{{ id }}' should not include {{ suffix }} suffix.",
30
43
  },
31
- schema: [],
44
+ schema: [
45
+ {
46
+ type: "object",
47
+ properties: {
48
+ disallowedSuffixes: {
49
+ type: "array",
50
+ items: {
51
+ type: "string",
52
+ enum: [SUFFIX_TYPE.CONSTRUCT, SUFFIX_TYPE.STACK],
53
+ },
54
+ uniqueItems: true,
55
+ },
56
+ },
57
+ additionalProperties: false,
58
+ },
59
+ ],
32
60
  },
33
- defaultOptions: [],
61
+ defaultOptions: [
62
+ {
63
+ disallowedSuffixes: [SUFFIX_TYPE.CONSTRUCT, SUFFIX_TYPE.STACK],
64
+ },
65
+ ],
34
66
  create(context) {
35
67
  const parserServices = ESLintUtils.getParserServices(context);
68
+ const options = context.options[0] ?? {
69
+ disallowedSuffixes: [SUFFIX_TYPE.CONSTRUCT, SUFFIX_TYPE.STACK],
70
+ };
71
+
36
72
  return {
37
73
  NewExpression(node) {
38
74
  const type = parserServices.getTypeAtLocation(node);
@@ -43,7 +79,7 @@ export const noConstructStackSuffix = ESLintUtils.RuleCreator.withoutDocs({
43
79
  const constructorPropertyNames = getConstructorPropertyNames(type);
44
80
  if (constructorPropertyNames[1] !== "id") return;
45
81
 
46
- validateConstructId(node, context);
82
+ validateConstructId(node, context, options);
47
83
  },
48
84
  };
49
85
  },
@@ -54,7 +90,8 @@ export const noConstructStackSuffix = ESLintUtils.RuleCreator.withoutDocs({
54
90
  */
55
91
  const validateConstructId = (
56
92
  node: TSESTree.NewExpression,
57
- context: Context
93
+ context: Context,
94
+ options: { disallowedSuffixes: SuffixType[] }
58
95
  ): void => {
59
96
  // NOTE: Treat the second argument as ID
60
97
  const secondArg = node.arguments[1];
@@ -66,25 +103,32 @@ const validateConstructId = (
66
103
  }
67
104
 
68
105
  const formattedConstructId = toPascalCase(secondArg.value);
106
+ const disallowedSuffixes = options.disallowedSuffixes;
69
107
 
70
- if (formattedConstructId.endsWith("Construct")) {
108
+ if (
109
+ disallowedSuffixes.includes(SUFFIX_TYPE.CONSTRUCT) &&
110
+ formattedConstructId.endsWith(SUFFIX_TYPE.CONSTRUCT)
111
+ ) {
71
112
  context.report({
72
113
  node,
73
114
  messageId: "noConstructStackSuffix",
74
115
  data: {
75
116
  classType: "Construct",
76
117
  id: secondArg.value,
77
- suffix: "Construct",
118
+ suffix: SUFFIX_TYPE.CONSTRUCT,
78
119
  },
79
120
  });
80
- } else if (formattedConstructId.endsWith("Stack")) {
121
+ } else if (
122
+ disallowedSuffixes.includes(SUFFIX_TYPE.STACK) &&
123
+ formattedConstructId.endsWith(SUFFIX_TYPE.STACK)
124
+ ) {
81
125
  context.report({
82
126
  node,
83
127
  messageId: "noConstructStackSuffix",
84
128
  data: {
85
129
  classType: "Stack",
86
130
  id: secondArg.value,
87
- suffix: "Stack",
131
+ suffix: SUFFIX_TYPE.STACK,
88
132
  },
89
133
  });
90
134
  }
@@ -297,7 +297,7 @@ const validateConstructId = ({
297
297
  return;
298
298
  }
299
299
 
300
- const formattedConstructId = toPascalCase(secondArg.value as string);
300
+ const formattedConstructId = toPascalCase(secondArg.value);
301
301
  const formattedParentClassName = toPascalCase(parentClassName);
302
302
  if (formattedParentClassName !== formattedConstructId) return;
303
303
 
@@ -6,7 +6,7 @@ import {
6
6
  TSESTree,
7
7
  } from "@typescript-eslint/utils";
8
8
 
9
- import { SymbolFlags } from "../types/symbolFlags";
9
+ import { SYMBOL_FLAGS } from "../constants/tsInternalFlags";
10
10
  import { isConstructOrStackType } from "../utils/typeCheck";
11
11
 
12
12
  type Context = TSESLint.RuleContext<"noPublicClassFields", []>;
@@ -91,7 +91,10 @@ const validateClassMember = (
91
91
  const type = parserServices.getTypeAtLocation(member);
92
92
  if (!type.symbol) continue;
93
93
 
94
- const isClass = type.symbol.flags === SymbolFlags.Class;
94
+ // NOTE: In order not to make it dependent on the typescript library, it defines its own unions.
95
+ // Therefore, the type information structures do not match.
96
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
97
+ const isClass = type.symbol.flags === SYMBOL_FLAGS.CLASS;
95
98
  if (!isClass) continue;
96
99
 
97
100
  context.report({
@@ -133,7 +136,10 @@ const validateConstructorParameterProperty = (
133
136
  const type = parserServices.getTypeAtLocation(param);
134
137
  if (!type.symbol) continue;
135
138
 
136
- const isClass = type.symbol.flags === SymbolFlags.Class;
139
+ // NOTE: In order not to make it dependent on the typescript library, it defines its own unions.
140
+ // Therefore, the type information structures do not match.
141
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
142
+ const isClass = type.symbol.flags === SYMBOL_FLAGS.CLASS;
137
143
  if (!isClass) continue;
138
144
 
139
145
  context.report({
@@ -93,6 +93,25 @@ const isInsideLoop = (node: TSESTree.Node): boolean => {
93
93
  ) {
94
94
  return true;
95
95
  }
96
+
97
+ // NOTE: Check for array methods like forEach, map, etc.
98
+ if (
99
+ current.type === AST_NODE_TYPES.CallExpression &&
100
+ current.callee.type === AST_NODE_TYPES.MemberExpression &&
101
+ current.callee.property.type === AST_NODE_TYPES.Identifier &&
102
+ [
103
+ "forEach",
104
+ "map",
105
+ "filter",
106
+ "reduce",
107
+ "flatMap",
108
+ "some",
109
+ "every",
110
+ ].includes(current.callee.property.name)
111
+ ) {
112
+ return true;
113
+ }
114
+
96
115
  current = current.parent;
97
116
  }
98
117
  return false;
@@ -93,7 +93,7 @@ const validateConstructId = (
93
93
  node,
94
94
  messageId: "pascalCaseConstructId",
95
95
  fix: (fixer) => {
96
- const pascalCaseValue = toPascalCase(secondArg.value as string);
96
+ const pascalCaseValue = toPascalCase(secondArg.value);
97
97
  return fixer.replaceText(secondArg, `${quote}${pascalCaseValue}${quote}`);
98
98
  },
99
99
  });
@@ -1,8 +1,20 @@
1
- import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
1
+ import {
2
+ AST_NODE_TYPES,
3
+ ESLintUtils,
4
+ TSESLint,
5
+ } from "@typescript-eslint/utils";
2
6
 
3
7
  import { getConstructorPropertyNames } from "../utils/parseType";
4
8
  import { isConstructType } from "../utils/typeCheck";
5
9
 
10
+ type Options = [
11
+ {
12
+ allowNonThisAndDisallowScope?: boolean;
13
+ }
14
+ ];
15
+
16
+ type Context = TSESLint.RuleContext<"requirePassingThis", Options>;
17
+
6
18
  /**
7
19
  * Enforces that `this` is passed to the constructor
8
20
  * @param context - The rule context provided by ESLint
@@ -18,11 +30,29 @@ export const requirePassingThis = ESLintUtils.RuleCreator.withoutDocs({
18
30
  messages: {
19
31
  requirePassingThis: "Require passing `this` in a constructor.",
20
32
  },
21
- schema: [],
33
+ schema: [
34
+ {
35
+ type: "object",
36
+ properties: {
37
+ allowNonThisAndDisallowScope: {
38
+ type: "boolean",
39
+ default: false,
40
+ },
41
+ },
42
+ additionalProperties: false,
43
+ },
44
+ ],
22
45
  fixable: "code",
23
46
  },
24
- defaultOptions: [],
25
- create(context) {
47
+ defaultOptions: [
48
+ {
49
+ allowNonThisAndDisallowScope: false,
50
+ },
51
+ ],
52
+ create(context: Context) {
53
+ const options = context.options[0] || {
54
+ allowNonThisAndDisallowScope: false,
55
+ };
26
56
  const parserServices = ESLintUtils.getParserServices(context);
27
57
  return {
28
58
  NewExpression(node) {
@@ -31,18 +61,39 @@ export const requirePassingThis = ESLintUtils.RuleCreator.withoutDocs({
31
61
  if (!isConstructType(type) || !node.arguments.length) return;
32
62
 
33
63
  const argument = node.arguments[0];
64
+
65
+ // NOTE: If the first argument is already `this`, it's valid
34
66
  if (argument.type === AST_NODE_TYPES.ThisExpression) return;
35
67
 
68
+ // NOTE: If the first argument is not `scope`, it's valid
36
69
  const constructorPropertyNames = getConstructorPropertyNames(type);
37
70
  if (constructorPropertyNames[0] !== "scope") return;
38
71
 
39
- context.report({
40
- node,
41
- messageId: "requirePassingThis",
42
- fix: (fixer) => {
43
- return fixer.replaceText(argument, "this");
44
- },
45
- });
72
+ // NOTE: If `allowNonThisAndDisallowScope` is false, require `this` for all cases
73
+ if (!options.allowNonThisAndDisallowScope) {
74
+ context.report({
75
+ node,
76
+ messageId: "requirePassingThis",
77
+ fix: (fixer) => {
78
+ return fixer.replaceText(argument, "this");
79
+ },
80
+ });
81
+ return;
82
+ }
83
+ // NOTE: If `allowNonThisAndDisallowScope` is true, allow non-`this` values except `scope` variable
84
+ // Check if the argument is the `scope` variable
85
+ if (
86
+ argument.type === AST_NODE_TYPES.Identifier &&
87
+ argument.name === "scope"
88
+ ) {
89
+ context.report({
90
+ node,
91
+ messageId: "requirePassingThis",
92
+ fix: (fixer) => {
93
+ return fixer.replaceText(argument, "this");
94
+ },
95
+ });
96
+ }
46
97
  },
47
98
  };
48
99
  },
@@ -1,4 +1,12 @@
1
- import { isClassDeclaration, isConstructorDeclaration, Type } from "typescript";
1
+ import {
2
+ ClassDeclaration,
3
+ ConstructorDeclaration,
4
+ Declaration,
5
+ Node,
6
+ Type,
7
+ } from "typescript";
8
+
9
+ import { SYNTAX_KIND } from "../constants/tsInternalFlags";
2
10
 
3
11
  /**
4
12
  * Parses type to get the property names of the class constructor.
@@ -18,3 +26,27 @@ export const getConstructorPropertyNames = (type: Type): string[] => {
18
26
 
19
27
  return constructor.parameters.map((param) => param.name.getText());
20
28
  };
29
+
30
+ /**
31
+ * Implementing `isClassDeclaration` defined in typescript on your own, in order not to include TypeScript in dependencies
32
+ */
33
+ const isClassDeclaration = (
34
+ declaration: Declaration
35
+ ): declaration is ClassDeclaration => {
36
+ // NOTE: In order not to make it dependent on the typescript library, it defines its own unions.
37
+ // Therefore, the type information structures do not match.
38
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
39
+ return declaration.kind === SYNTAX_KIND.CLASS_DECLARATION;
40
+ };
41
+
42
+ /**
43
+ * Implementing `isConstructorDeclaration` defined in typescript on your own, in order not to include TypeScript in dependencies
44
+ */
45
+ const isConstructorDeclaration = (
46
+ node: Node
47
+ ): node is ConstructorDeclaration => {
48
+ // NOTE: In order not to make it dependent on the typescript library, it defines its own unions.
49
+ // Therefore, the type information structures do not match.
50
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
51
+ return node.kind === SYNTAX_KIND.CONSTRUCTOR;
52
+ };
@@ -53,6 +53,6 @@ const isTargetSuperClassType = (
53
53
  }
54
54
 
55
55
  // NOTE: Check the base type
56
- const baseTypes = type.getBaseTypes() || [];
56
+ const baseTypes = type.getBaseTypes() ?? [];
57
57
  return baseTypes.some((baseType) => typeCheckFunction(baseType));
58
58
  };
@@ -1,6 +0,0 @@
1
- /**
2
- * Implementing `SymbolFlags` defined in typescript on your own, in order not to include TypeScript in dependencies
3
- */
4
- export enum SymbolFlags {
5
- Class = 32,
6
- }