-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from darraghoriordan/feat/two-new-swagger-rules
feat: two new swagger rules
- Loading branch information
Showing
19 changed files
with
528 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
96 changes: 96 additions & 0 deletions
96
src/rules/apiEnumPropertyBestPractices/apiEnumPropertyBestPractices.test-data.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
export const testCases = [ | ||
{ | ||
moduleCode: `enum MyEnum{ | ||
ValA, | ||
ValB | ||
} | ||
class MyClass { | ||
@ApiProperty({ | ||
type: BizTaskUiCollectionEnum, | ||
enum: BizTaskUiCollectionEnum, | ||
}) | ||
public myProperty!:MyEnum | ||
}`, | ||
needsEnumNameProperty: true, | ||
needsTypeRemoved: true, | ||
message: "type is present, no enum name", | ||
}, | ||
{ | ||
moduleCode: `enum MyEnum{ | ||
ValA, | ||
ValB | ||
} | ||
class MyClass { | ||
@ApiProperty({ | ||
enumName: BizTaskUiCollectionEnum, | ||
enum: BizTaskUiCollectionEnum, | ||
}) | ||
public myProperty!:MyEnum | ||
}`, | ||
needsEnumNameProperty: false, | ||
needsTypeRemoved: false, | ||
message: "perfect", | ||
}, | ||
{ | ||
moduleCode: `enum MyEnum{ | ||
ValA, | ||
ValB | ||
} | ||
class MyClass { | ||
@ApiProperty({ | ||
enum: BizTaskUiCollectionEnum, | ||
}) | ||
public myProperty!:MyEnum | ||
}`, | ||
needsEnumNameProperty: true, | ||
needsTypeRemoved: false, | ||
message: "optional everywhere", | ||
}, | ||
{ | ||
moduleCode: `enum MyEnum{ | ||
ValA, | ||
ValB | ||
} | ||
class MyClass { | ||
@ApiProperty({ | ||
type: BizTaskUiCollectionEnum, | ||
}) | ||
public myProperty!:MyEnum | ||
}`, | ||
needsEnumNameProperty: false, | ||
needsTypeRemoved: false, | ||
message: "not an enum", | ||
}, | ||
{ | ||
moduleCode: `enum MyEnum{ | ||
ValA, | ||
ValB | ||
} | ||
class MyClass { | ||
@ApiProperty() | ||
public myProperty!:MyEnum | ||
}`, | ||
needsEnumNameProperty: false, | ||
needsTypeRemoved: false, | ||
message: "not an enum", | ||
}, | ||
{ | ||
moduleCode: `enum MyEnum{ | ||
ValA, | ||
ValB | ||
} | ||
class MyClass { | ||
@ApiProperty({}) | ||
public myProperty!:MyEnum | ||
}`, | ||
needsEnumNameProperty: false, | ||
needsTypeRemoved: false, | ||
message: "not an enum", | ||
}, | ||
]; |
39 changes: 39 additions & 0 deletions
39
src/rules/apiEnumPropertyBestPractices/apiEnumPropertyBestPractices.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import {hasEnumSpecifiedCorrectly} from "./apiEnumPropertyBestPractices"; | ||
import {testCases} from "./apiEnumPropertyBestPractices.test-data"; | ||
import {typedTokenHelpers} from "../../utils/typedTokenHelpers"; | ||
import { | ||
fakeContext, | ||
fakeFilePath, | ||
} from "../../utils/nestModules/nestProvidedInjectableMapper.test-date"; | ||
import {TSESTree} from "@typescript-eslint/types"; | ||
|
||
// should probably be split up into multiple tests | ||
describe("apiEnumPropertyBestPractices", () => { | ||
test.each(testCases)( | ||
"is an expected response for %#", | ||
(testCase: { | ||
moduleCode: string; | ||
needsEnumNameProperty: boolean; | ||
needsTypeRemoved: boolean; | ||
message: string; | ||
}) => { | ||
const ast = typedTokenHelpers.parseStringToAst( | ||
testCase.moduleCode, | ||
fakeFilePath, | ||
fakeContext | ||
); | ||
|
||
const hasValidEnumSpecResult = hasEnumSpecifiedCorrectly( | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
(ast.body[1] as TSESTree.ClassDeclaration).body | ||
.body[0] as TSESTree.ClassProperty | ||
); | ||
expect(hasValidEnumSpecResult.needsEnumNameAdded).toEqual( | ||
testCase.needsEnumNameProperty | ||
); | ||
expect(hasValidEnumSpecResult.needsTypeRemoved).toEqual( | ||
testCase.needsTypeRemoved | ||
); | ||
} | ||
); | ||
}); |
95 changes: 95 additions & 0 deletions
95
src/rules/apiEnumPropertyBestPractices/apiEnumPropertyBestPractices.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import {TSESTree} from "@typescript-eslint/types"; | ||
import {createRule} from "../../utils/createRule"; | ||
import {typedTokenHelpers} from "../../utils/typedTokenHelpers"; | ||
import {EnumTestResultModel} from "./enumTestResultModel"; | ||
|
||
export const hasEnumSpecifiedCorrectly = ( | ||
node: TSESTree.ClassProperty | ||
): EnumTestResultModel => { | ||
const decorators = typedTokenHelpers.getDecoratorsNamed(node, [ | ||
"ApiPropertyOptional", | ||
"ApiProperty", | ||
]); | ||
|
||
if (decorators.length === 0) { | ||
return new EnumTestResultModel(false, false); | ||
} | ||
|
||
const firstArgument = (decorators[0].expression as TSESTree.CallExpression) | ||
.arguments[0] as TSESTree.ObjectExpression; | ||
if (!firstArgument) { | ||
return new EnumTestResultModel(false, false); | ||
} | ||
// is it an enum prop? | ||
// OK so this could be changed later to actually parse the property type for an enum | ||
// and so check if enum: is needed too. However we don't do this yet so we depend on enum having | ||
// been added already and this rule just recommends keeping it tidy. So, you will still have to at | ||
// least remember to add "enum: Blah" to your api decorator. | ||
const hasEnumProperty = | ||
firstArgument.properties.find( | ||
(p) => | ||
((p as TSESTree.Property).key as TSESTree.Identifier).name === | ||
"enum" | ||
) !== undefined; | ||
|
||
if (!hasEnumProperty) { | ||
return new EnumTestResultModel(false, false); | ||
} | ||
const hasTypeProperty = | ||
firstArgument.properties.find( | ||
(p) => | ||
((p as TSESTree.Property).key as TSESTree.Identifier).name === | ||
"type" | ||
) !== undefined; | ||
const hasEnumNameProperty = | ||
firstArgument.properties.find( | ||
(p) => | ||
((p as TSESTree.Property).key as TSESTree.Identifier).name === | ||
"enumName" | ||
) !== undefined; | ||
|
||
return new EnumTestResultModel(hasTypeProperty, !hasEnumNameProperty); | ||
}; | ||
|
||
const rule = createRule({ | ||
name: "api-enum-property-best-practices", | ||
meta: { | ||
docs: { | ||
description: | ||
"Enums should use the best practices for api documentation", | ||
category: "Best Practices", | ||
recommended: false, | ||
requiresTypeChecking: false, | ||
}, | ||
messages: { | ||
needsEnumNameAdded: `Properties with enum should also specify an enumName property to keep generated models clean`, | ||
needsTypeRemoved: `Properties with enum should not specify a type property`, | ||
}, | ||
schema: [], | ||
type: "suggestion", | ||
}, | ||
defaultOptions: [], | ||
|
||
create(context) { | ||
return { | ||
// eslint-disable-next-line @typescript-eslint/naming-convention | ||
ClassProperty(node: TSESTree.ClassProperty): void { | ||
const result = hasEnumSpecifiedCorrectly(node); | ||
if (result.needsEnumNameAdded) { | ||
context.report({ | ||
node: node, | ||
messageId: "needsEnumNameAdded", | ||
}); | ||
} | ||
if (result.needsTypeRemoved) { | ||
context.report({ | ||
node: node, | ||
messageId: "needsTypeRemoved", | ||
}); | ||
} | ||
}, | ||
}; | ||
}, | ||
}); | ||
|
||
export default rule; |
6 changes: 6 additions & 0 deletions
6
src/rules/apiEnumPropertyBestPractices/enumTestResultModel.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export class EnumTestResultModel { | ||
constructor( | ||
public needsTypeRemoved: boolean, | ||
public needsEnumNameAdded: boolean | ||
) {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.