Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8e74dce
commit f638921
Showing
6 changed files
with
225 additions
and
6 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import { resolveDefaultProperties } from "./resolveDefaultProperties"; | ||
|
||
describe("resolveDefaultProperties", () => { | ||
it("should remove the question mark if @default is defined (interface)", () => { | ||
const sourceText = ` | ||
/** | ||
* A citizen | ||
*/ | ||
export interface Citizen { | ||
name: string; | ||
/** | ||
* @default true | ||
*/ | ||
isVillain?: boolean; | ||
} | ||
`; | ||
expect(resolveDefaultProperties(sourceText)).toMatchInlineSnapshot(` | ||
"/** | ||
* A citizen | ||
*/ | ||
export interface Citizen { | ||
name: string; | ||
/** | ||
* @default true | ||
*/ | ||
isVillain: boolean; | ||
} | ||
" | ||
`); | ||
}); | ||
|
||
it("should remove the question mark if @default is defined (type)", () => { | ||
const sourceText = ` | ||
/** | ||
* A citizen | ||
*/ | ||
export type Citizen = { | ||
name: string; | ||
/** | ||
* @default true | ||
*/ | ||
isVillain?: boolean; | ||
}; | ||
`; | ||
expect(resolveDefaultProperties(sourceText)).toMatchInlineSnapshot(` | ||
"/** | ||
* A citizen | ||
*/ | ||
export type Citizen = { | ||
name: string; | ||
/** | ||
* @default true | ||
*/ | ||
isVillain: boolean; | ||
}; | ||
" | ||
`); | ||
}); | ||
|
||
it("should remove `undefined` if @default is defined", () => { | ||
const sourceText = ` | ||
/** | ||
* A citizen | ||
*/ | ||
export interface Citizen { | ||
name: string; | ||
/** | ||
* @default true | ||
*/ | ||
isVillain: boolean | undefined; | ||
} | ||
`; | ||
expect(resolveDefaultProperties(sourceText)).toMatchInlineSnapshot(` | ||
"/** | ||
* A citizen | ||
*/ | ||
export interface Citizen { | ||
name: string; | ||
/** | ||
* @default true | ||
*/ | ||
isVillain: boolean; | ||
} | ||
" | ||
`); | ||
}); | ||
|
||
it("should do nothing if no @default", () => { | ||
const sourceText = ` | ||
/** | ||
* A citizen | ||
*/ | ||
export interface Citizen { | ||
name: string; | ||
isVillain?: boolean; | ||
} | ||
`; | ||
expect(resolveDefaultProperties(sourceText)).toMatchInlineSnapshot(` | ||
"/** | ||
* A citizen | ||
*/ | ||
export interface Citizen { | ||
name: string; | ||
isVillain?: 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import ts from "typescript"; | ||
import { getJSDocTags } from "../core/jsDocTags"; | ||
|
||
/** | ||
* Remove optional properties when `@default` jsdoc tag is defined. | ||
* | ||
* Indeed, `z.{type}().optional().default({value})` will be | ||
* compile as a non-optional type. | ||
*/ | ||
export function resolveDefaultProperties(sourceText: string) { | ||
const sourceFile = ts.createSourceFile( | ||
"index.ts", | ||
sourceText, | ||
ts.ScriptTarget.Latest | ||
); | ||
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); | ||
|
||
const removeOptionalTransformer: ts.TransformerFactory<ts.SourceFile> = ( | ||
context | ||
) => { | ||
const visit: ts.Visitor = (node) => { | ||
node = ts.visitEachChild(node, visit, context); | ||
|
||
if (ts.isPropertySignature(node)) { | ||
const jsDocTags = getJSDocTags(node, sourceFile); | ||
if (jsDocTags.default !== undefined) { | ||
const type = node.type | ||
? ts.visitEachChild(node.type, omitUndefinedKeyword, context) | ||
: undefined; | ||
return ts.factory.createPropertySignature( | ||
node.modifiers, | ||
node.name, | ||
undefined, // Remove `questionToken` | ||
type | ||
); | ||
} | ||
} | ||
return node; | ||
}; | ||
|
||
return (node) => ts.visitNode(node, visit); | ||
}; | ||
|
||
const outputFile = ts.transform(sourceFile, [removeOptionalTransformer]); | ||
|
||
return printer.printFile(outputFile.transformed[0]); | ||
} | ||
|
||
function omitUndefinedKeyword(node: ts.Node) { | ||
if (node.kind === ts.SyntaxKind.UndefinedKeyword) { | ||
return undefined; | ||
} | ||
return node; | ||
} |
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