Skip to content

Commit

Permalink
fix(collection-of): fix issue when the linter fix rules
Browse files Browse the repository at this point in the history
  • Loading branch information
Romakita committed Mar 30, 2024
1 parent 147da76 commit 0f3c947
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,27 @@ describe("explicitCollectionOfDecorator", () => {
thisIsAStringProp?: Map<string, string>;
}`
},
{
code: `
import {MapOf, Property} from "@tsed/schema";
class TestClass {
@MapOf(String)
@Property()
thisIsAStringProp?: Map<string, string>;
}`,
errors: [
{
messageId: "unnecessary-property-of-decorator",
},
],
output: `
import {MapOf, Property} from "@tsed/schema";
class TestClass {
@MapOf(String)
thisIsAStringProp?: Map<string, string>;
}`
},
{
code: `
import {CollectionOf} from "@tsed/schema";
Expand All @@ -138,6 +159,44 @@ describe("explicitCollectionOfDecorator", () => {
thisIsAStringProp?: string;
}`,
},
{
code: `
import {MapOf} from "@tsed/schema";
class TestClass {
@MapOf(String)
thisIsAStringProp?: string;
}`,
errors: [
{
messageId: "unnecessary-map-of-decorator",
},
],
output: `
import {MapOf} from "@tsed/schema";
class TestClass {
thisIsAStringProp?: string;
}`,
},
{
code: `
import {ArrayOf} from "@tsed/schema";
class TestClass {
@ArrayOf(String)
thisIsAStringProp?: string;
}`,
errors: [
{
messageId: "unnecessary-array-of-decorator",
},
],
output: `
import {ArrayOf} from "@tsed/schema";
class TestClass {
thisIsAStringProp?: string;
}`,
},
{
code: `
import {Property} from "@tsed/schema";
Expand All @@ -154,6 +213,7 @@ describe("explicitCollectionOfDecorator", () => {
import {Property, ArrayOf} from "@tsed/schema";
class TestClass {
@ArrayOf(String)
@Property()
thisIsAStringProp?: string[]
}`
},
Expand Down Expand Up @@ -217,6 +277,26 @@ describe("explicitCollectionOfDecorator", () => {
thisIsAStringProp?: Map<string, string>;
}`,
},
{
code: `
import {MapOf} from "@tsed/schema";
class TestClass {
@MapOf(String)
thisIsAStringProp?: string[];
}`,
errors: [
{
messageId: "unexpected-map-of-decorator",
},
],
output: `
import {MapOf, ArrayOf} from "@tsed/schema";
class TestClass {
@ArrayOf(String)
thisIsAStringProp?: string[];
}`
},
],
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ import {addImportSpecifier} from "../../utils/addImportSpecifier";

type RULES =
| "missing-collection-of-decorator"
| "unnecessary-array-of-decorator"
| "unnecessary-map-of-decorator"
| "unnecessary-property-of-decorator"
| "unnecessary-collection-of-decorator";
| "unnecessary-collection-of-decorator"
| "unexpected-map-of-decorator";

type DECORATORS_TYPES = "Property" | "CollectionOf" | "MapOf" | "ArrayOf";
const DECORATORS: DECORATORS_TYPES[] = ["Property", "CollectionOf", "MapOf", "ArrayOf"];
Expand All @@ -23,25 +26,42 @@ const TYPES_TO_DECORATORS: Record<string, DECORATORS_TYPES> = {

interface CollectionOfDecoratorsStatus extends DecoratorsStatus<DECORATORS_TYPES> {
isCollection: boolean;
collectionType: string;
}

const RULES_CHECK: RuleOptions<RULES, CollectionOfDecoratorsStatus>[] = [
{
messageId: "unnecessary-property-of-decorator",
message: "Unnecessary Property decorator over a Property returning Array, Set or Map",
test: ({decorators, isCollection}) =>
messageId: "unexpected-map-of-decorator",
message: "Unexpected MapOf decorator over a property not returning Map",
test: ({decorators, isCollection, collectionType}) =>
isCollection
&& decorators.has("Property")
&& (decorators.has("CollectionOf") || decorators.has("MapOf") || decorators.has("ArrayOf")),
fix({fixer, node}) {
const propertyDecorator = findPropertyDecorator(node, "Property");
&& decorators.has("MapOf") && collectionType !== "Map",
*fix({fixer, node}) {
const {itemType, collectionType} = getTypes(node);
const collectionOfDecorator = findPropertyDecorator(node, "MapOf");
const decoratorName = TYPES_TO_DECORATORS[collectionType as string];

return propertyDecorator ? fixer.remove(propertyDecorator) : null;
yield* addImportSpecifier(node, fixer, "@tsed/schema", decoratorName!);

yield fixer.replaceText(collectionOfDecorator!, `@${decoratorName}(${itemType})\n${getWhiteSpaces(node)}`);
}
},
{
messageId: "missing-collection-of-decorator",
message: "Property returning Array, Set or Map must set CollectionOf decorator",
test: ({decorators, isCollection}) =>
isCollection && !(decorators.has("CollectionOf") || decorators.has("MapOf") || decorators.has("ArrayOf")),
* fix({fixer, node}) {
const {itemType, collectionType} = getTypes(node);
const decoratorName = TYPES_TO_DECORATORS[collectionType as string];

yield* addImportSpecifier(node, fixer, "@tsed/schema", decoratorName!);
yield fixer.insertTextBefore(node, `@${decoratorName}(${itemType})\n${getWhiteSpaces(node)}`);
}
},
{
messageId: "unnecessary-collection-of-decorator",
message: "Unexpected CollectionOf decorator over a Property not returning Array, Set or Map",
message: "Unnecessary CollectionOf decorator over a Property not returning Array, Set or Map",
test: ({decorators, isCollection}) =>
!isCollection
&& decorators.has("CollectionOf"),
Expand All @@ -52,27 +72,41 @@ const RULES_CHECK: RuleOptions<RULES, CollectionOfDecoratorsStatus>[] = [
}
},
{
messageId: "missing-collection-of-decorator",
message: "Property returning Array, Set or Map must set CollectionOf decorator",
messageId: "unnecessary-array-of-decorator",
message: "Unnecessary ArrayOf decorator over a Property not returning Array",
test: ({decorators, isCollection}) =>
isCollection && !decorators.has("CollectionOf"),
* fix({fixer, node}) {
const {itemType, collectionType} = getTypes(node);

const propertyDecorator = findPropertyDecorator(node, "Property");
const decoratorName = TYPES_TO_DECORATORS[collectionType as string];
!isCollection
&& decorators.has("ArrayOf"),
fix({fixer, node}) {
const collectionOfDecorator = findPropertyDecorator(node, "ArrayOf");

yield* addImportSpecifier(node, fixer, "@tsed/schema", decoratorName!);
return collectionOfDecorator ? fixer.remove(collectionOfDecorator) : null;
}
},
{
messageId: "unnecessary-map-of-decorator",
message: "Unnecessary MapOf decorator over a Property not returning Map",
test: ({decorators, isCollection}) =>
!isCollection
&& decorators.has("MapOf"),
fix({fixer, node}) {
const collectionOfDecorator = findPropertyDecorator(node, "MapOf");

if (propertyDecorator) {
yield fixer.replaceText(propertyDecorator, `@${decoratorName}(${itemType})`);
return;
}
return collectionOfDecorator ? fixer.remove(collectionOfDecorator) : null;
}
},
{
messageId: "unnecessary-property-of-decorator",
message: "Unnecessary Property decorator over a Property returning Array, Set or Map",
test: ({decorators, isCollection}) =>
isCollection
&& decorators.has("Property"),
fix({fixer, node}) {
const propertyDecorator = findPropertyDecorator(node, "Property");

yield fixer.insertTextBefore(node, `@${decoratorName}(${itemType})\n${getWhiteSpaces(node)}`);
return;
return propertyDecorator ? fixer.remove(propertyDecorator) : null;
}
}
},
];

function create(context: Readonly<RuleContext<RULES, []>>) {
Expand All @@ -89,10 +123,11 @@ function create(context: Readonly<RuleContext<RULES, []>>) {
return;
}

decoratorsStatus.isCollection = AST_NODE_TYPES.TSArrayType === node.typeAnnotation?.typeAnnotation?.type as AST_NODE_TYPES.TSArrayType
|| ["Array", "Map", "Set"].includes(
(node.typeAnnotation?.typeAnnotation as any | undefined)?.typeName?.name
);
let type = AST_NODE_TYPES.TSArrayType === node.typeAnnotation?.typeAnnotation?.type as AST_NODE_TYPES.TSArrayType ? "Array" :
(node.typeAnnotation?.typeAnnotation as any | undefined)?.typeName?.name;

decoratorsStatus.isCollection = ["Array", "Map", "Set"].includes(type);
decoratorsStatus.collectionType = type;

RULES_CHECK
.some(({messageId, test, fix}) => {
Expand Down

0 comments on commit 0f3c947

Please sign in to comment.