Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add transformer option to zod #672

Merged
merged 1 commit into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion packages/generator/src/Generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
TypeParameterDeclarationStructure,
VariableDeclarationKind,
} from 'ts-morph'
import { InstructionSourceType } from './runtypes'
import { InstructionSourceType, InstructionTypeTransformers } from './runtypes'
import {
CanDeclareStatics,
DeclareAndUse,
Expand Down Expand Up @@ -54,6 +54,7 @@ export type GeneratorOptions = GeneratorOptionsBase & {
targetFile: string
typeFormat?: string
typeWriters: TypeWriters
transformers: InstructionTypeTransformers
}

export type ImportSpec = Omit<ImportSpecifierStructure, 'kind'> & {
Expand All @@ -69,6 +70,7 @@ export default class Generator {
#project: Project
#imports: ImportSpec[] = []
#targetFile: SourceCodeFile
#transformers: InstructionTypeTransformers

constructor(options: GeneratorOptions) {
this.#typeWriters = options.typeWriters
Expand Down Expand Up @@ -101,6 +103,7 @@ export default class Generator {

this.#formatRuntypeName = typeNameFormatter(options.runtypeFormat)
this.#formatTypeName = typeNameFormatter(options.typeFormat)
this.#transformers = options.transformers
}

get project() {
Expand Down Expand Up @@ -248,6 +251,9 @@ export default class Generator {
this.#typeWriters.typeWriter(typeDeclaration.getType(), {
circular: !!circular,
recursive,
transformer: typeDeclaration.getName()
? this.#transformers[typeDeclaration.getName()!]
: undefined,
})
)

Expand Down
9 changes: 8 additions & 1 deletion packages/generator/src/TypeWriters.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Symbol as CompilerSymbol, SymbolFlags, ts, Type } from 'ts-morph'
import { Tuple } from '.'
import { InstructionTypeTransformer, Tuple } from '.'
import { getArrayElementType, isArray } from './array'
import {
escapeQuottedPropName,
Expand All @@ -23,9 +23,11 @@ export default abstract class TypeWriters {
{
recursive = false,
circular = false,
transformer,
}: {
recursive?: boolean
circular?: boolean
transformer?: InstructionTypeTransformer
} = {}
): TypeWriter {
const closeGenericFunction =
Expand Down Expand Up @@ -133,9 +135,14 @@ export default abstract class TypeWriters {
break
}

if (transformer)
yield* this.attachTransformer(transformer.file, transformer.export)

if (closeGenericFunction) yield* closeGenericFunction()
}

*attachTransformer(_fileName: string, _exportName: string): TypeWriter {}

#requiresGenericFunction(type: Type) {
try {
getTypeName(type)
Expand Down
2 changes: 2 additions & 0 deletions packages/generator/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@ export default async function cli(
targetFile,
sourceTypes,
runtypeFormat,
transformers,
typeFormat,
} of castArray(buildInstructions)) {
const generator = new Generator({
typeWriters,
runtypeFormat,
targetFile,
tsConfigFile: argv.project,
transformers: transformers || {},
typeFormat,
})
const file = await generator.generate(sourceTypes)
Expand Down
16 changes: 16 additions & 0 deletions packages/generator/src/runtypes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
import * as z from 'zod'

export const InstructionTypeTransformer = z.object({
file: z.string(),
export: z.string(),
})

export type InstructionTypeTransformer = z.infer<
typeof InstructionTypeTransformer
>

export const InstructionTypeTransformers = z.record(InstructionTypeTransformer)

export type InstructionTypeTransformers = z.infer<
typeof InstructionTypeTransformers
>

export const InstructionSourceType = z.object({
file: z.string(),
exportStaticType: z.boolean().optional(),
Expand All @@ -12,6 +27,7 @@ export const Instruction = z.object({
runtypeFormat: z.string().optional(),
sourceTypes: InstructionSourceType.or(z.array(InstructionSourceType)),
targetFile: z.string(),
transformers: InstructionTypeTransformers.optional(),
typeFormat: z.string().optional(),
})

Expand Down
7 changes: 7 additions & 0 deletions packages/io-ts/fixtures/transformer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { string, TypeOf } from 'io-ts';

// This file is generated by runtyping (https://github.com/johngeorgewright/runtyping).
// Manual changes might be lost - proceed with caution!
export const TransformStringToNumber = string;

export type TransformStringToNumber = TypeOf<typeof TransformStringToNumber>;
1 change: 1 addition & 0 deletions packages/io-ts/test/typewriter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ testTypeWriter<t.Type<any>>({
createNumberValidator: () => t.number,
createStringValidator: () => t.string,
createObjectValidator: t.type,
ignore: ['transformer'],
typeWriters: new IoTsTypeWriters(),
validate(validator, data) {
pipe(
Expand Down
7 changes: 7 additions & 0 deletions packages/runtypes/fixtures/transformer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Static, String } from 'runtypes';

// This file is generated by runtyping (https://github.com/johngeorgewright/runtyping).
// Manual changes might be lost - proceed with caution!
export const TransformStringToNumber = String;

export type TransformStringToNumber = Static<typeof TransformStringToNumber>;
1 change: 1 addition & 0 deletions packages/runtypes/test/typewriters.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ testTypeWriters<Runtype>({
createNumberValidator: () => Number,
createStringValidator: () => String,
createObjectValidator: Record,
ignore: ['transformer'],
typeWriters: new RuntypesTypeWriters(),
validate(validator, data) {
validator.check(data)
Expand Down
7 changes: 7 additions & 0 deletions packages/test-type-writers/fixtures/data/transformer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { TestData } from '../../src/types'
import * as T from '../source/transformer'

export const TransformStringToNumber: TestData<T.TransformStringToNumber> = {
success: ['123'],
failure: [123],
}
1 change: 1 addition & 0 deletions packages/test-type-writers/fixtures/source/transformer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type TransformStringToNumber = string
6 changes: 6 additions & 0 deletions packages/test-type-writers/src/fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ async function generate(
typeWriters,
targetFile: pathHelper.join(fixturesDestDir, `${testName}.ts`),
project,
transformers: {
TransformStringToNumber: {
file: '@runtyping/test-type-writers/dist/transformers/stringToNumber',
export: 'stringToNumber',
},
},
...generatorOpts,
})

Expand Down
6 changes: 6 additions & 0 deletions packages/test-type-writers/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ export default function testTypeWriters<Validator>(
const generator = new Generator({
typeWriters: props.typeWriters,
targetFile: pathHelper.join(fixturesDestDir, 'without-static-types.ts'),
transformers: {
TransformStringToNumber: {
file: '@runtyping/test-type-writers/dist/transformers/stringToNumber',
export: 'stringToNumber',
},
},
})
const sourceFile = await generator.generate([
{
Expand Down
3 changes: 3 additions & 0 deletions packages/test-type-writers/src/transformers/stringToNumber.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function stringToNumber(x: string): number {
return Number(x)
}
4 changes: 4 additions & 0 deletions packages/zod/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ npm install -D @runtyping/zod

targetFile: ./src/other-runtypes.ts # The file to create
runtypeFormat: {type}Rt # Optional: use a custom name format for the created runtype
transformers: # Optional: specify a transformer for a type
[TYPENAME]:
file: /path/to/transformer
export: exportNameOfTranformer
typeFormat: {type}Type # Optional: use a custom name format for the created type
sourceTypes:
exportStaticType: true # Optional: export static types as well (true by default)
Expand Down
6 changes: 3 additions & 3 deletions packages/zod/fixtures/array.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { array, infer as Infer, number, object, string } from 'zod';
import { array, number, object, output, string } from 'zod';

// This file is generated by runtyping (https://github.com/johngeorgewright/runtyping).
// Manual changes might be lost - proceed with caution!
export const A = object({ foo: string(), });

export type A = Infer<typeof A>;
export type A = output<typeof A>;

export const B = array(string().or(number()).or(A));

export type B = Infer<typeof B>;
export type B = output<typeof B>;
4 changes: 2 additions & 2 deletions packages/zod/fixtures/boolean.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { boolean, infer as Infer } from 'zod';
import { boolean, output } from 'zod';

// This file is generated by runtyping (https://github.com/johngeorgewright/runtyping).
// Manual changes might be lost - proceed with caution!
export const A = boolean();

export type A = Infer<typeof A>;
export type A = output<typeof A>;
4 changes: 2 additions & 2 deletions packages/zod/fixtures/builtin.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { infer as Infer, instanceof as InstanceOf, object } from 'zod';
import { instanceof as InstanceOf, object, output } from 'zod';

// This file is generated by runtyping (https://github.com/johngeorgewright/runtyping).
// Manual changes might be lost - proceed with caution!
export const A = object({ a: InstanceOf(Uint8Array), });

export type A = Infer<typeof A>;
export type A = output<typeof A>;
8 changes: 4 additions & 4 deletions packages/zod/fixtures/circular-references.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { array, infer as Infer, lazy, literal, object, undefined as Undefined, ZodType } from 'zod';
import { array, lazy, literal, object, output, undefined as Undefined, ZodType } from 'zod';
import { Student as _Student, Teacher as _Teacher } from '../../../.yarn/__virtual__/@runtyping-test-type-writers-virtual-f1a80c3a62/1/packages/test-type-writers/fixtures/source/circular-references';

// This file is generated by runtyping (https://github.com/johngeorgewright/runtyping).
// Manual changes might be lost - proceed with caution!
export const Teacher: ZodType<_Teacher> = lazy(() => object({ type: literal("teacher"), students: array(Student).or(Undefined()).optional(), reportsTo: Teacher.or(Undefined()).optional(), }));

export type Teacher = Infer<typeof Teacher>;
export type Teacher = output<typeof Teacher>;

export const Student: ZodType<_Student> = lazy(() => object({ type: literal("student"), teacher: Teacher, }));

export type Student = Infer<typeof Student>;
export type Student = output<typeof Student>;

export const User = Student.or(Teacher);

export type User = Infer<typeof User>;
export type User = output<typeof User>;
6 changes: 3 additions & 3 deletions packages/zod/fixtures/duplicate-references.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { infer as Infer, null as Null, object, string } from 'zod';
import { null as Null, object, output, string } from 'zod';

// This file is generated by runtyping (https://github.com/johngeorgewright/runtyping).
// Manual changes might be lost - proceed with caution!
export const FooType = Null().or(string());

export type FooType = Infer<typeof FooType>;
export type FooType = output<typeof FooType>;

export const HorseType = object({ a: FooType, b: FooType, });

export type HorseType = Infer<typeof HorseType>;
export type HorseType = output<typeof HorseType>;
14 changes: 7 additions & 7 deletions packages/zod/fixtures/enum.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import { infer as Infer, literal, nativeEnum, string } from 'zod';
import { literal, nativeEnum, output, string } from 'zod';
import { A as _A, B as _B, C as _C, E as _E } from '../../../.yarn/__virtual__/@runtyping-test-type-writers-virtual-f1a80c3a62/1/packages/test-type-writers/fixtures/source/enum';

// This file is generated by runtyping (https://github.com/johngeorgewright/runtyping).
// Manual changes might be lost - proceed with caution!
export const A = nativeEnum(_A);

export type A = Infer<typeof A>;
export type A = output<typeof A>;

export const B = nativeEnum(_B);

export type B = Infer<typeof B>;
export type B = output<typeof B>;

export const C = nativeEnum(_C);

export type C = Infer<typeof C>;
export type C = output<typeof C>;

export const D = literal(_C.A3).or(literal(_C.B3));

export type D = Infer<typeof D>;
export type D = output<typeof D>;

export const F = string().or(literal(_E.S));

export type F = Infer<typeof F>;
export type F = output<typeof F>;

export const G = literal(_C.A3).or(literal(_C.B3)).or(literal(_C.C3)).or(literal(_E.S));

export type G = Infer<typeof G>;
export type G = output<typeof G>;
22 changes: 11 additions & 11 deletions packages/zod/fixtures/generics.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
import { infer as Infer, number, object, string, ZodType } from 'zod';
import { number, object, output, string, ZodType } from 'zod';

// This file is generated by runtyping (https://github.com/johngeorgewright/runtyping).
// Manual changes might be lost - proceed with caution!
export const A = <T extends any,>(T: ZodType<T>,) => object({ type: T, });

export type A<T> = Infer<ReturnType<typeof A<T>>>;
export type A<T> = output<ReturnType<typeof A<T>>>;

export const B = <T extends string,>(T: ZodType<T>,) => object({ type: T, });

export type B<T extends string> = Infer<ReturnType<typeof B<T>>>;
export type B<T extends string> = output<ReturnType<typeof B<T>>>;

export const C = <T extends any,>(T: ZodType<T>,) => string().or(T);

export type C<T> = Infer<ReturnType<typeof C<T>>>;
export type C<T> = output<ReturnType<typeof C<T>>>;

export const D = <T extends number,>(T: ZodType<T>,) => object({ type: T, });

export type D<T extends number> = Infer<ReturnType<typeof D<T>>>;
export type D<T extends number> = output<ReturnType<typeof D<T>>>;

export const E = object({ foo: string(), });

export type E = Infer<typeof E>;
export type E = output<typeof E>;

export const F = <T extends Infer<typeof E>,>(T: ZodType<T>,) => object({ type: T, });
export const F = <T extends output<typeof E>,>(T: ZodType<T>,) => object({ type: T, });

export type F<T extends E> = Infer<ReturnType<typeof F<T>>>;
export type F<T extends E> = output<ReturnType<typeof F<T>>>;

export const G = object({ abc: A(object({ data: string(), }),), });

export type G = Infer<typeof G>;
export type G = output<typeof G>;

export const Test = <T extends any,>(T: ZodType<T>,) => T.and(object({ count: number(), }));

export type Test<T> = Infer<ReturnType<typeof Test<T>>>;
export type Test<T> = output<ReturnType<typeof Test<T>>>;

export const Foo = object({ abc: Test(object({ data: string(), }),), });

export type Foo = Infer<typeof Foo>;
export type Foo = output<typeof Foo>;
Loading
Loading