Skip to content

Commit

Permalink
fix: check property names during instantiation (#94)
Browse files Browse the repository at this point in the history
* fix: require-passing-this

* fix: check property name

* chore: delete unwanted diffs

* docs: add jsDoc
  • Loading branch information
ren-yamanashi authored Jan 17, 2025
1 parent 33583e1 commit 4143df2
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 2 deletions.
13 changes: 11 additions & 2 deletions src/__tests__/no-construct-stack-suffix.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,31 @@ ruleTester.run("no-construct-stack-suffix", noConstructStackSuffix, {
{
code: `
class TestClass {
constructor(public id: string) {}
constructor(props: any, id: string) {}
}
const test = new TestClass("test", "SampleConstruct");
`,
},
{
code: `
class TestClass {
constructor(public id: string) {}
constructor(props: any, id: string) {}
}
class Sample {
constructor() {
const test = new TestClass("test", "SampleConstruct");
}
}`,
},
// WHEN: property name is not `id`
{
code: `
class TestClass {
constructor(props: any, validId: string) {}
}
const test = new TestClass("test", "SampleConstruct");
`,
},
],
invalid: [
// WHEN: construct id has "Construct" suffix, and extends Construct
Expand Down
17 changes: 17 additions & 0 deletions src/__tests__/no-variable-construct-id.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,23 @@ ruleTester.run("no-variable-construct-id", noVariableConstructId, {
}
`,
},
// WHEN: property name is not `id`
{
code: `
class Construct {}
class TargetConstruct extends Construct {
constructor(scope: Construct, validId: string) {
super(scope, validId);
}
}
class SampleConstruct extends Construct {
constructor(scope: Construct, id: string) {
super(scope, id);
new TargetConstruct(this, id);
}
}
`,
},
],
invalid: [
// WHEN: id is variable
Expand Down
11 changes: 11 additions & 0 deletions src/__tests__/pascal-case-construct-id.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,17 @@ ruleTester.run("pascal-case-construct-id", pascalCaseConstructId, {
}
const test = new TestClass('test', 'ValidId');`,
},
// WHEN: property name is not `id`
{
code: `
class Construct {}
class TestClass extends Construct {
constructor(props: any, validId: string) {
super(props, validId);
}
}
const test = new TestClass("test", "invalid_id");`,
},
],
invalid: [
// WHEN: id is snake_case(double quote)
Expand Down
17 changes: 17 additions & 0 deletions src/__tests__/require-passing-this.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,23 @@ ruleTester.run("require-passing-this", requirePassingThis, {
}
`,
},
// WHEN: property name is not `scope`
{
code: `
class Construct {}
class SampleConstruct extends Construct {
constructor(validProperty: Construct, id: string) {
super(validProperty, id);
}
}
class TestConstruct extends Construct {
constructor(scope: Construct, id: string) {
super(scope, id);
new SampleConstruct(scope, "ValidId");
}
}
`,
},
],
invalid: [
// WHEN: not passing `this` to a constructor
Expand Down
5 changes: 5 additions & 0 deletions src/rules/no-construct-stack-suffix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
} from "@typescript-eslint/utils";

import { toPascalCase } from "../utils/convertString";
import { getConstructorPropertyNames } from "../utils/parseType";
import { isConstructOrStackType } from "../utils/typeCheck";

type Context = TSESLint.RuleContext<"noConstructStackSuffix", []>;
Expand Down Expand Up @@ -38,6 +39,10 @@ export const noConstructStackSuffix = ESLintUtils.RuleCreator.withoutDocs({
if (!isConstructOrStackType(type) || node.arguments.length < 2) {
return;
}

const constructorPropertyNames = getConstructorPropertyNames(type);
if (constructorPropertyNames[1] !== "id") return;

validateConstructId(node, context);
},
};
Expand Down
4 changes: 4 additions & 0 deletions src/rules/no-variable-construct-id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
TSESTree,
} from "@typescript-eslint/utils";

import { getConstructorPropertyNames } from "../utils/parseType";
import { isConstructType, isStackType } from "../utils/typeCheck";

type Context = TSESLint.RuleContext<"noVariableConstructId", []>;
Expand Down Expand Up @@ -40,6 +41,9 @@ export const noVariableConstructId = ESLintUtils.RuleCreator.withoutDocs({
return;
}

const constructorPropertyNames = getConstructorPropertyNames(type);
if (constructorPropertyNames[1] !== "id") return;

validateConstructId(node, context);
},
};
Expand Down
5 changes: 5 additions & 0 deletions src/rules/pascal-case-construct-id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
} from "@typescript-eslint/utils";

import { toPascalCase } from "../utils/convertString";
import { getConstructorPropertyNames } from "../utils/parseType";
import { isConstructOrStackType } from "../utils/typeCheck";

const QUOTE_TYPE = {
Expand Down Expand Up @@ -45,6 +46,10 @@ export const pascalCaseConstructId = ESLintUtils.RuleCreator.withoutDocs({
if (!isConstructOrStackType(type) || node.arguments.length < 2) {
return;
}

const constructorPropertyNames = getConstructorPropertyNames(type);
if (constructorPropertyNames[1] !== "id") return;

validateConstructId(node, context);
},
};
Expand Down
4 changes: 4 additions & 0 deletions src/rules/require-passing-this.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";

import { getConstructorPropertyNames } from "../utils/parseType";
import { isConstructType, isStackType } from "../utils/typeCheck";

/**
Expand Down Expand Up @@ -38,6 +39,9 @@ export const requirePassingThis = ESLintUtils.RuleCreator.withoutDocs({
const argument = node.arguments[0];
if (argument.type === AST_NODE_TYPES.ThisExpression) return;

const constructorPropertyNames = getConstructorPropertyNames(type);
if (constructorPropertyNames[0] !== "scope") return;

context.report({
node,
messageId: "requirePassingThis",
Expand Down
20 changes: 20 additions & 0 deletions src/utils/parseType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { isClassDeclaration, isConstructorDeclaration, Type } from "typescript";

/**
* Parses type to get the property names of the class constructor.
* @returns The property names of the class constructor.
*/
export const getConstructorPropertyNames = (type: Type): string[] => {
const declarations = type.symbol?.declarations;
if (!declarations?.length) return [];

const classDeclaration = declarations[0];
if (!isClassDeclaration(classDeclaration)) return [];

const constructor = classDeclaration.members.find((member) =>
isConstructorDeclaration(member)
);
if (!constructor?.parameters.length) return [];

return constructor.parameters.map((param) => param.name.getText());
};

0 comments on commit 4143df2

Please # to comment.