-
Notifications
You must be signed in to change notification settings - Fork 151
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(cli): support generics in fern definition (#4512)
* ready to go, merge from main * prettier * do not match on reserved keywords * addressed comments * no unused generic rule * uncomment tests * add no unused generics * added rule for all non-aliases and all non-alias type contained values * more test cases * consolidate logic * remove one more regex * add more validation rules -- for number of applied arguments and if no arguments are applied * add a couple more rules around number of args, no applied args * chore(cli): reduce duplication with generic checks (#4525) * addressed comments * slightly cleaner error message * added documentation and changelog version * more real world example * remove inlined literal * more tangible example --------- Co-authored-by: Deep Singhvi <[email protected]>
- Loading branch information
1 parent
55e30cc
commit 4a6682a
Showing
39 changed files
with
2,857 additions
and
30 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
9 changes: 9 additions & 0 deletions
9
packages/cli/fern-definition/schema/src/utils/RawContainerType.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,9 @@ | ||
export const RawContainerType = { | ||
optional: "optional", | ||
set: "set", | ||
list: "list", | ||
map: "map", | ||
literal: "literal" | ||
} as const; | ||
|
||
export const RawContanerTypes: Set<string> = new Set(Object.values(RawContainerType)); | ||
2 changes: 2 additions & 0 deletions
2
packages/cli/fern-definition/schema/src/utils/generics/index.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,2 @@ | ||
export { parseGeneric } from "./parseGeneric"; | ||
export { isGeneric } from "./isGeneric"; |
5 changes: 5 additions & 0 deletions
5
packages/cli/fern-definition/schema/src/utils/generics/isGeneric.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,5 @@ | ||
import { parseGeneric } from "./parseGeneric"; | ||
|
||
export function isGeneric(name: string): boolean { | ||
return parseGeneric(name) != null; | ||
} |
26 changes: 26 additions & 0 deletions
26
packages/cli/fern-definition/schema/src/utils/generics/parseGeneric.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,26 @@ | ||
import { RawContanerTypes } from "../RawContainerType"; | ||
|
||
export declare namespace ParseGeneric { | ||
interface Return { | ||
name: string; | ||
arguments: string[]; | ||
} | ||
} | ||
|
||
export function parseGeneric(name: string): ParseGeneric.Return | undefined { | ||
const genericMatch = name.match(/([\w.]+)<([\w,\s]+)>/); | ||
|
||
if ( | ||
genericMatch?.[0] != null && | ||
genericMatch[1] != null && | ||
genericMatch[2] != null && | ||
!RawContanerTypes.has(genericMatch[1].trim()) | ||
) { | ||
return { | ||
name: genericMatch[1].trim(), | ||
arguments: genericMatch[2].split(",").map((arg) => arg.trim()) | ||
}; | ||
} | ||
|
||
return undefined; | ||
} |
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
8 changes: 8 additions & 0 deletions
8
...tor/src/rules/no-undefined-type-reference/__test__/fixtures/simple/definition/generic.yml
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,8 @@ | ||
types: | ||
GenericApplication: | ||
type: GenericUsedType<string> | ||
|
||
GenericUsedType<T>: | ||
properties: | ||
foo: T | ||
bar: string |
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
12 changes: 12 additions & 0 deletions
12
...efinition/validator/src/rules/no-unused-generic/__test__/fixtures/simple/definition/1.yml
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,12 @@ | ||
# yaml-language-server: $schema=https://raw.githubusercontent.com/fern-api/fern/main/fern.schema.json | ||
imports: | ||
two: ./2.yml | ||
|
||
types: | ||
GenericApplication: | ||
type: two.GenericUsedType<string> | ||
|
||
AnotherGenericUnusedType<T>: | ||
properties: | ||
foo: T | ||
bar: list<string> |
10 changes: 10 additions & 0 deletions
10
...efinition/validator/src/rules/no-unused-generic/__test__/fixtures/simple/definition/2.yml
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,10 @@ | ||
types: | ||
GenericUsedType<T>: | ||
properties: | ||
foo: T | ||
bar: string | ||
|
||
GenericUnusedType<T>: | ||
properties: | ||
foo: T | ||
bar: number |
1 change: 1 addition & 0 deletions
1
...inition/validator/src/rules/no-unused-generic/__test__/fixtures/simple/definition/api.yml
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 @@ | ||
name: simple-api |
1 change: 1 addition & 0 deletions
1
...-definition/validator/src/rules/no-unused-generic/__test__/fixtures/simple/generators.yml
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 @@ | ||
{} |
31 changes: 31 additions & 0 deletions
31
.../fern-definition/validator/src/rules/no-unused-generic/__test__/no-unused-generic.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,31 @@ | ||
import { AbsoluteFilePath, join, RelativeFilePath } from "@fern-api/fs-utils"; | ||
import { getViolationsForRule } from "../../../testing-utils/getViolationsForRule"; | ||
import { NoUnusedGenericRule } from "../no-unused-generic"; | ||
|
||
describe("no-unused-generic", () => { | ||
it("simple", async () => { | ||
const violations = await getViolationsForRule({ | ||
rule: NoUnusedGenericRule, | ||
absolutePathToWorkspace: join( | ||
AbsoluteFilePath.of(__dirname), | ||
RelativeFilePath.of("fixtures"), | ||
RelativeFilePath.of("simple") | ||
) | ||
}); | ||
|
||
expect(violations).toEqual([ | ||
{ | ||
message: 'Generic "AnotherGenericUnusedType<T>" is declared but never used.', | ||
nodePath: ["types", "AnotherGenericUnusedType<T>"], | ||
relativeFilepath: RelativeFilePath.of("1.yml"), | ||
severity: "error" | ||
}, | ||
{ | ||
message: 'Generic "GenericUnusedType<T>" is declared but never used.', | ||
nodePath: ["types", "GenericUnusedType<T>"], | ||
relativeFilepath: RelativeFilePath.of("2.yml"), | ||
severity: "error" | ||
} | ||
]); | ||
}); | ||
}); |
1 change: 1 addition & 0 deletions
1
packages/cli/fern-definition/validator/src/rules/no-unused-generic/index.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 @@ | ||
export { NoUnusedGenericRule } from "./no-unused-generic"; |
57 changes: 57 additions & 0 deletions
57
packages/cli/fern-definition/validator/src/rules/no-unused-generic/no-unused-generic.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,57 @@ | ||
/* eslint-disable @typescript-eslint/no-empty-function */ | ||
import { visitAllDefinitionFiles } from "@fern-api/workspace-loader"; | ||
import { visitDefinitionFileYamlAst } from "../../ast"; | ||
import { Rule, RuleViolation } from "../../Rule"; | ||
import { visitRawTypeDeclaration, parseGeneric } from "@fern-api/fern-definition-schema"; | ||
|
||
export const NoUnusedGenericRule: Rule = { | ||
name: "no-unused-generic", | ||
create: async ({ workspace }) => { | ||
const instantiations = new Set(); | ||
|
||
await visitAllDefinitionFiles(workspace, async (_, file) => { | ||
await visitDefinitionFileYamlAst(file, { | ||
typeDeclaration: (type) => { | ||
visitRawTypeDeclaration(type.declaration, { | ||
alias: (alias) => { | ||
const maybeGenericDeclaration = parseGeneric( | ||
typeof alias === "string" ? alias : alias.type | ||
); | ||
if (maybeGenericDeclaration != null && maybeGenericDeclaration.name) { | ||
const [maybeTypeName, typeName, ..._rest] = maybeGenericDeclaration.name.split("."); | ||
const key = typeName ?? maybeTypeName; | ||
if (key) { | ||
instantiations.add(key); | ||
} | ||
} | ||
}, | ||
enum: () => {}, | ||
object: () => {}, | ||
discriminatedUnion: () => {}, | ||
undiscriminatedUnion: () => {} | ||
}); | ||
} | ||
}); | ||
}); | ||
|
||
return { | ||
definitionFile: { | ||
typeName: (name): RuleViolation[] => { | ||
const maybeGenericDeclaration = parseGeneric(name); | ||
if (maybeGenericDeclaration == null) { | ||
return []; | ||
} | ||
|
||
return maybeGenericDeclaration.name && instantiations.has(maybeGenericDeclaration.name) | ||
? [] | ||
: [ | ||
{ | ||
severity: "error", | ||
message: `Generic "${name}" is declared but never used.` | ||
} | ||
]; | ||
} | ||
} | ||
}; | ||
} | ||
}; |
Oops, something went wrong.