diff --git a/README.md b/README.md index d91e653..fafbc95 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,167 @@ -# @duplojs/data-parser-tools -[![NPM version](https://img.shields.io/npm/v/@duplojs/data-parser-tools)](https://www.npmjs.com/package/@duplojs/data-parser-tools) \ No newline at end of file + + +

+ logo +

+

+ DataParser Tools +

+

+ + coverage + + + lang + + + lang + +

+ +`@duplojs/data-parser-tools` is a library that convert `dataParser` schema to choice format (typescript, jsonSchema) + +## Installation + +To consume `@duplojs/data-parser-tools`, you need to install the npm package and zod. +```bash +npm install @duplojs/data-parser-tools@0 @duplojs/utils@1 @duplojs/server-utils@0 +``` + +## Usage + +The library exposes two converters: +- `@duplojs/data-parser-tools/toTypescript` +- `@duplojs/data-parser-tools/toJsonSchema` + +### 1) Generate a TypeScript type with `render` + +```ts +import { DPE } from "@duplojs/utils"; +import { render, defaultTransformers } from "@duplojs/data-parser-tools/toTypescript"; + +const userSchema = DPE.object({ + id: DPE.number(), + name: DPE.string(), +}).addIdentifier("User"); + +const tsType = render(userSchema, { + identifier: "User", + mode: "out", + transformers: defaultTransformers, +}); + +console.log(tsType); +// export type User = { id: number; name: string; }; +``` + +`identifier` is the final exported name. +`mode` can be: +- `"out"`: output format (strict) +- `"in"`: input format (includes accepted input variants, for example date/time) + +### 2) Generate a JSON Schema + +```ts +import { DPE } from "@duplojs/utils"; +import { render, defaultTransformers } from "@duplojs/data-parser-tools/toJsonSchema"; + +const userSchema = DPE.object({ + id: DPE.number(), + name: DPE.string(), +}).addIdentifier("User"); + +const jsonSchema = render(userSchema, { + identifier: "User", + mode: "out", + transformers: defaultTransformers, + version: "jsonSchema7", // jsonSchema4 | jsonSchema7 | jsonSchema202012 | openApi3 | openApi31 +}); + +console.log(jsonSchema.$ref); // "#/definitions/User" +``` + +### 3) Add an identifier to a schema (`addIdentifier`) + +`addIdentifier` clones the schema and attaches an internal reusable name during rendering. + +```ts +const base = DPE.object({ value: DPE.string() }); +const named = base.addIdentifier("MyNamedSchema"); +``` + +If the name passed to `render({ identifier })` differs from the schema identifier, an alias is generated (for example: `export type PublicName = MyNamedSchema;`). + +### 4) Use hooks + +Hooks let you intercept/replace a schema before transformation. +- `output("next", schema)`: continue the hook chain +- `output("stop", schema)`: stop the chain and transform this schema + +```ts +import { DPE } from "@duplojs/utils"; +import { render, defaultTransformers, type TransformerHook } from "@duplojs/data-parser-tools/toTypescript"; + +const forceStringHook: TransformerHook = ({ output }) => output("stop", DPE.string()); + +const result = render(DPE.number(), { + identifier: "HookExample", + mode: "out", + transformers: defaultTransformers, + hooks: [forceStringHook], +}); + +console.log(result); +// export type HookExample = string; +``` + +### 5) Recursive schemas + +Recursive references are supported through `DPE.lazy(...)`. + +```ts +import { DPE } from "@duplojs/utils"; +import { render, defaultTransformers } from "@duplojs/data-parser-tools/toTypescript"; + +type Node = { children: Node[] }; + +const nodeSchema: DPE.Contract = DPE.object({ + children: DPE.array(DPE.lazy(() => nodeSchema)), +}).addIdentifier("Node"); + +const result = render(nodeSchema, { + identifier: "Node", + mode: "out", + transformers: defaultTransformers, +}); +``` + +### 6) Custom types: `date`, `time`, `file` + +```ts +import { DPE } from "@duplojs/utils"; +import { SDP } from "@duplojs/server-utils"; +import { render, defaultTransformers } from "@duplojs/data-parser-tools/toTypescript"; + +const schema = DPE.object({ + createdAt: DPE.date(), + startAt: DPE.time(), + avatar: SDP.file(), +}); + +const outType = render(schema, { + identifier: "PayloadOut", + mode: "out", + transformers: defaultTransformers, +}); + +const inType = render(schema, { + identifier: "PayloadIn", + mode: "in", + transformers: defaultTransformers, +}); +``` + +In practice: +- `date` / `time` in `"out"` produce template-literals (`date...`, `time...`) +- `date` / `time` in `"in"` also accept additional input variants +- `file` maps to `FileInterface` (imported from `@duplojs/server-utils/file`) diff --git a/integration/toJsonSchema/__snapshots__/index.test.ts.snap b/integration/toJsonSchema/__snapshots__/index.test.ts.snap index c548c68..1df5202 100644 --- a/integration/toJsonSchema/__snapshots__/index.test.ts.snap +++ b/integration/toJsonSchema/__snapshots__/index.test.ts.snap @@ -75,7 +75,6 @@ exports[`integration 1`] = ` "createdAt": { "anyOf": [ { - "format": "date-time", "pattern": "^date-?(?\\d{1,16})(?[+-])$", "type": "string", }, diff --git a/integration/toTypescript/__snapshots__/index.test.ts.snap b/integration/toTypescript/__snapshots__/index.test.ts.snap index b94ec95..cd43b6b 100644 --- a/integration/toTypescript/__snapshots__/index.test.ts.snap +++ b/integration/toTypescript/__snapshots__/index.test.ts.snap @@ -1,7 +1,9 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`integration 1`] = ` -"export type UserProfile = { +"import type { TheDate, TheTime } from "@duplojs/utils/date"; + +export type UserProfile = { id: \`user-\${number}-db1\`; name: string; email: string; @@ -29,7 +31,7 @@ exports[`integration 1`] = ` number, number ]; - createdAt: \`date\${number}\${"-" | "+"}\`; - startAt: \`time\${number}\${"-" | "+"}\`; + createdAt: TheDate; + startAt: TheTime; };" `; diff --git a/package-lock.json b/package-lock.json index a3b6eeb..7761ee0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,7 +38,8 @@ "node": ">=22.15.1" }, "peerDependencies": { - "@duplojs/utils": ">=1.4.36 <2.0.0" + "@duplojs/server-utils": ">=0.1.4 < 1.0.0", + "@duplojs/utils": ">=1.5.1 <2.0.0" } }, "docs": {}, @@ -962,10 +963,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@duplojs/server-utils": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@duplojs/server-utils/-/server-utils-0.1.4.tgz", + "integrity": "sha512-xs7Prh4RaurUm4BcqIU6ilvDMkQThTUhcb3dUX60gu5m4r7Qlnrn5MwReQ2T7RcvZFsVLLBzkQljTPEshVcFTQ==", + "license": "MIT", + "peer": true, + "workspaces": [ + "integration", + "docs" + ], + "engines": { + "node": ">=22.15.1" + }, + "peerDependencies": { + "@duplojs/utils": ">=1.4.53 <2.0.0" + } + }, "node_modules/@duplojs/utils": { - "version": "1.4.36", - "resolved": "https://registry.npmjs.org/@duplojs/utils/-/utils-1.4.36.tgz", - "integrity": "sha512-czOHa4vc1Y+pS6jBnOMj03NkMJyCat27hipXEa4gehisKinhu6cnKsEwwglHVJE5iXnwKcJcTy6rh8sY3Xp9kQ==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@duplojs/utils/-/utils-1.5.1.tgz", + "integrity": "sha512-1BHngmR/9MAtPoMMpuWTXBHp1/qyTyggc4PtPzme1OWNWlt9ueTuftJoLQYut0quXnddmqwD2SI8u4QEATIgCQ==", "license": "MIT", "peer": true, "workspaces": [ diff --git a/package.json b/package.json index 87234c8..4743acd 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,8 @@ "vitest": "3.2.4" }, "peerDependencies": { - "@duplojs/utils": ">=1.4.36 <2.0.0" + "@duplojs/utils": ">=1.5.1 <2.0.0", + "@duplojs/server-utils": ">=0.1.4 < 1.0.0" }, "dependencies": { "typescript": "5.9.2" diff --git a/scripts/toJsonSchema/render.ts b/scripts/toJsonSchema/render.ts index 26980ff..14d476a 100644 --- a/scripts/toJsonSchema/render.ts +++ b/scripts/toJsonSchema/render.ts @@ -7,10 +7,11 @@ import { type TransformerMode, type TransformerHook, type createTransformer, - type SupportedVersions, + type MapperSupportedVersions, type JsonSchema, supportedVersions, buildRef, + type SupportedVersions, } from "./transformer"; import { createToJsonSchemaKind } from "./kind"; import { getRecursiveDataParser } from "@scripts/utils/getRecursiveDataParser"; @@ -29,7 +30,7 @@ export class DataParserToJsonSchemaRenderError extends kindHeritage( } export interface RenderParams< - GenericVersion extends unknown, + GenericVersion extends SupportedVersions, > { readonly identifier: string; readonly transformers: readonly ReturnType[]; @@ -40,14 +41,14 @@ export interface RenderParams< } type RenderResult< - GenericVersion extends keyof SupportedVersions, + GenericVersion extends SupportedVersions, > = Or<[ IsEqual, IsEqual, ]> extends true ? { $ref: `#/components/schemas/${string}`; - openapi: SupportedVersions[GenericVersion]; + openapi: MapperSupportedVersions[GenericVersion]; components: { schemas: Record; }; @@ -58,25 +59,24 @@ type RenderResult< ]> extends true ? { $ref: `#/$defs/${string}`; - $schema: SupportedVersions[GenericVersion]; + $schema: MapperSupportedVersions[GenericVersion]; definitions: Record; } : IsEqual extends true ? { $ref: `#/definitions/${string}`; - $schema: SupportedVersions[GenericVersion]; + $schema: MapperSupportedVersions[GenericVersion]; $defs: Record; } : never; export function render< - GenericVersion extends keyof SupportedVersions, + GenericVersion extends SupportedVersions, >( schema: DP.DataParsers, params: RenderParams, ): RenderResult { const context: MapContext = new Map(params.context); - const version = supportedVersions[params.version]; const result = transformer( schema, @@ -85,7 +85,7 @@ export function render< context, mode: params.mode ?? "out", hooks: params.hooks ?? [], - version, + version: params.version, recursiveDataParsers: getRecursiveDataParser(schema), }, ); @@ -118,29 +118,29 @@ export function render< }; if ( - version === supportedVersions.openApi3 - || version === supportedVersions.openApi31 + params.version === "openApi3" + || params.version === "openApi31" ) { return { - $ref: buildRef(params.identifier, version), - openapi: version, + $ref: buildRef(params.identifier, params.version), + openapi: supportedVersions[params.version], components: { schemas: definitionsWithIdentifier, }, } as never; } - if (version === supportedVersions.jsonSchema202012) { + if (params.version === "jsonSchema202012") { return { - $ref: buildRef(params.identifier, version), - $schema: version, + $ref: buildRef(params.identifier, params.version), + $schema: params.version, $defs: definitionsWithIdentifier, } as never; } return { - $ref: buildRef(params.identifier, version), - $schema: version, + $ref: buildRef(params.identifier, params.version), + $schema: supportedVersions[params.version], definitions: definitionsWithIdentifier, } as never; } diff --git a/scripts/toJsonSchema/transformer/create.ts b/scripts/toJsonSchema/transformer/create.ts index 2b711e0..c8e8c48 100644 --- a/scripts/toJsonSchema/transformer/create.ts +++ b/scripts/toJsonSchema/transformer/create.ts @@ -18,6 +18,7 @@ import type { JsonSchemaUnknown, JsonSchemaTime, } from "./defaults"; +import { type OpenapiJsonSchemaFile } from "./defaults/file"; export interface JsonSchemaRef { $ref: string; @@ -46,7 +47,8 @@ export type JsonSchema = | JsonSchemaTuple | JsonSchemaUnion | JsonSchemaUnknown - | JsonSchemaTime; + | JsonSchemaTime + | OpenapiJsonSchemaFile; export interface TransformerSuccess { readonly schema: JsonSchema; @@ -85,13 +87,14 @@ export const supportedVersions = { openApi31: "https://spec.openapis.org/oas/3.1.0", } as const; -export type SupportedVersions = typeof supportedVersions; -export type SupportedVersionsUrl = typeof supportedVersions[keyof SupportedVersions]; +export type MapperSupportedVersions = typeof supportedVersions; +export type SupportedVersions = keyof typeof supportedVersions; +export type SupportedVersionsUrl = typeof supportedVersions[SupportedVersions]; export interface TransformerParams { readonly mode: TransformerMode; readonly context: MapContext; - readonly version: SupportedVersionsUrl; + readonly version: SupportedVersions; transformer( schema: DP.DataParser, diff --git a/scripts/toJsonSchema/transformer/defaults/date.ts b/scripts/toJsonSchema/transformer/defaults/date.ts index ca8766f..cd77bf1 100644 --- a/scripts/toJsonSchema/transformer/defaults/date.ts +++ b/scripts/toJsonSchema/transformer/defaults/date.ts @@ -18,8 +18,7 @@ export const dateTransformer = createTransformer( ) => { const base = { type: "string", - pattern: D.theDateRegex.source, - format: "date-time", + pattern: D.serializeTheDateRegex.source, }; if (mode === "in" && schema.definition.coerce) { diff --git a/scripts/toJsonSchema/transformer/defaults/file.ts b/scripts/toJsonSchema/transformer/defaults/file.ts new file mode 100644 index 0000000..fe3503b --- /dev/null +++ b/scripts/toJsonSchema/transformer/defaults/file.ts @@ -0,0 +1,31 @@ +import { SDP } from "@duplojs/server-utils"; +import { createTransformer } from "../create"; + +export interface OpenapiJsonSchemaFile { + type: "string"; + format: "binary"; +} + +export const fileTransformer = createTransformer( + SDP.fileKind.has, + ( + schema, + { + success, + version, + buildError, + }, + ) => { + if ( + version !== "openApi3" + && version !== "openApi31" + ) { + return buildError(); + } + + return success({ + type: "string", + format: "binary", + }); + }, +); diff --git a/scripts/toJsonSchema/transformer/defaults/index.ts b/scripts/toJsonSchema/transformer/defaults/index.ts index 8ae1f3e..0e025f9 100644 --- a/scripts/toJsonSchema/transformer/defaults/index.ts +++ b/scripts/toJsonSchema/transformer/defaults/index.ts @@ -45,6 +45,7 @@ import { tupleTransformer } from "./tuple"; import { unionTransformer } from "./union"; import { unknownTransformer } from "./unknown"; import { timeTransformer } from "./time"; +import { fileTransformer } from "./file"; export const defaultTransformers = [ arrayTransformer, @@ -69,4 +70,5 @@ export const defaultTransformers = [ unionTransformer, unknownTransformer, timeTransformer, + fileTransformer, ] as const satisfies readonly ReturnType[]; diff --git a/scripts/toJsonSchema/transformer/defaults/literal.ts b/scripts/toJsonSchema/transformer/defaults/literal.ts index 15857d2..911ae8b 100644 --- a/scripts/toJsonSchema/transformer/defaults/literal.ts +++ b/scripts/toJsonSchema/transformer/defaults/literal.ts @@ -1,5 +1,5 @@ import { A, DP, isType, justReturn, P, pipe } from "@duplojs/utils"; -import { createTransformer, type SupportedVersionsUrl } from "../create"; +import { createTransformer, type SupportedVersions, type SupportedVersionsUrl } from "../create"; type JsonPrimitive = string | number | boolean | null; type JsonType = "string" | "number" | "integer" | "boolean" | "null"; @@ -20,15 +20,15 @@ interface ReduceResult { } type OldVersions = - | "http://json-schema.org/draft-04/schema#" - | "https://spec.openapis.org/oas/3.0.3"; + | "jsonSchema4" + | "openApi3"; function isOldVersion( - version: SupportedVersionsUrl, + version: SupportedVersions, ): version is OldVersions { return ( - version === "http://json-schema.org/draft-04/schema#" - || version === "https://spec.openapis.org/oas/3.0.3" + version === "jsonSchema4" + || version === "openApi3" ); } @@ -154,13 +154,13 @@ export const literalTransformer = createTransformer( lastValue.literals, P.match(version) .with( - "https://spec.openapis.org/oas/3.0.3", + "openApi3", justReturn({ enum: [null], }), ) .with( - "http://json-schema.org/draft-04/schema#", + "jsonSchema4", justReturn({ type: "null", enum: [null], diff --git a/scripts/toJsonSchema/transformer/defaults/time.ts b/scripts/toJsonSchema/transformer/defaults/time.ts index 457c93a..19b02f0 100644 --- a/scripts/toJsonSchema/transformer/defaults/time.ts +++ b/scripts/toJsonSchema/transformer/defaults/time.ts @@ -18,7 +18,7 @@ export const timeTransformer = createTransformer( ) => { const base = { type: "string", - pattern: D.theTimeRegex.source, + pattern: D.serializeTheTimeRegex.source, }; if (mode === "in" && schema.definition.coerce) { diff --git a/scripts/toJsonSchema/transformer/transformer.ts b/scripts/toJsonSchema/transformer/transformer.ts index 13acc62..1ad7a40 100644 --- a/scripts/toJsonSchema/transformer/transformer.ts +++ b/scripts/toJsonSchema/transformer/transformer.ts @@ -5,9 +5,9 @@ import { type TransformerParams, type createTransformer, type TransformerMode, - type SupportedVersionsUrl, - type JsonSchema, type DataParserErrorEither, + type SupportedVersions, + supportedVersions, } from "./create"; import { type TransformerHook } from "./hook"; @@ -15,23 +15,23 @@ export interface TransformerFunctionParams { readonly transformers: readonly ReturnType[]; readonly context: MapContext; readonly mode: TransformerMode; - readonly version: SupportedVersionsUrl; + readonly version: SupportedVersions; readonly hooks: readonly TransformerHook[]; readonly recursiveDataParsers: DP.DataParser[]; } export function buildRef( name: string, - version: SupportedVersionsUrl, + version: SupportedVersions, ) { if ( - version === "https://spec.openapis.org/oas/3.0.3" - || version === "https://spec.openapis.org/oas/3.1.0" + version === "openApi3" + || version === "openApi31" ) { return `#/components/schemas/${name}`; } - if (version === "https://json-schema.org/draft/2020-12/schema") { + if (version === "jsonSchema202012") { return `#/$defs/${name}`; } diff --git a/scripts/toTypescript/render.ts b/scripts/toTypescript/render.ts index 8fdae2a..fe5f3d9 100644 --- a/scripts/toTypescript/render.ts +++ b/scripts/toTypescript/render.ts @@ -1,8 +1,9 @@ import { DP, unwrap, E, pipe, G, A, S, kindHeritage } from "@duplojs/utils"; -import { type DataParserErrorEither, type DataParserNotSupportedEither, transformer, type MapContext, type TransformerMode, type TransformerHook, type createTransformer } from "./transformer"; +import { type DataParserErrorEither, type DataParserNotSupportedEither, transformer, type MapContext, type TransformerMode, type TransformerHook, type createTransformer, type SupportedDataParsers, type MapImportType } from "./transformer"; import { createPrinter, createSourceFile, EmitHint, factory, ScriptKind, ScriptTarget, SyntaxKind } from "typescript"; import { createToTypescriptKind } from "./kind"; import { getRecursiveDataParser } from "@scripts/utils/getRecursiveDataParser"; +import { importTypesTransformer } from "./transformer/importTypesTransformer"; export interface RenderParams { readonly identifier: string; @@ -10,6 +11,7 @@ export interface RenderParams { readonly context?: MapContext; readonly mode?: TransformerMode; readonly hooks?: readonly TransformerHook[]; + readonly importType?: MapImportType; } export class DataParserToTypescriptRenderError extends kindHeritage( @@ -18,15 +20,16 @@ export class DataParserToTypescriptRenderError extends kindHeritage( Error, ) { public constructor( - public schema: DP.DataParsers, + public schema: SupportedDataParsers, public error: DataParserNotSupportedEither | DataParserErrorEither, ) { super({}, ["Error during the render of dataParser in typescript type."]); } } -export function render(schema: DP.DataParsers, params: RenderParams) { +export function render(schema: SupportedDataParsers, params: RenderParams) { const context: MapContext = new Map(params.context); + const importType: MapImportType = new Map(params.importType); const result = transformer( schema, @@ -36,6 +39,7 @@ export function render(schema: DP.DataParsers, params: RenderParams) { mode: params.mode ?? "out", hooks: params.hooks ?? [], recursiveDataParsers: getRecursiveDataParser(schema), + importType, }, ); @@ -74,7 +78,10 @@ export function render(schema: DP.DataParsers, params: RenderParams) { const printer = createPrinter(); return pipe( - context.values(), + [ + ...importTypesTransformer(importType), + ...context.values(), + ], G.map( (value) => printer.printNode( EmitHint.Unspecified, diff --git a/scripts/toTypescript/transformer/create.ts b/scripts/toTypescript/transformer/create.ts index f15fb6c..4ebacfe 100644 --- a/scripts/toTypescript/transformer/create.ts +++ b/scripts/toTypescript/transformer/create.ts @@ -1,16 +1,21 @@ import { type TypeAliasDeclaration, type TypeNode } from "typescript"; import { type DP, E } from "@duplojs/utils"; +import { type SDP } from "@duplojs/server-utils"; export type TransformerSuccessEither< -> = E.EitherRight<"buildSuccess", TypeNode>; +> = E.Right<"buildSuccess", TypeNode>; export type DataParserNotSupportedEither< -> = E.EitherLeft<"dataParserNotSupport", DP.DataParser>; +> = E.Left<"dataParserNotSupport", DP.DataParser>; export type DataParserErrorEither< -> = E.EitherLeft<"buildDataParserError", DP.DataParser>; +> = E.Left<"buildDataParserError", DP.DataParser>; -export type MapContext = Map; +export type SupportedDataParsers = DP.DataParsers | SDP.DataParserFile; + +export type MapContext = Map; + +export type MapImportType = Map; export type MaybeTransformerEither = | TransformerSuccessEither @@ -22,6 +27,7 @@ export type TransformerMode = "in" | "out"; export interface TransformerParams { readonly mode: TransformerMode; readonly context: MapContext; + readonly importType: MapImportType; transformer( schema: DP.DataParser, @@ -32,19 +38,20 @@ export interface TransformerParams { ): TransformerSuccessEither; buildError(): DataParserErrorEither; + addImport(path: string, typeName: string): void; } export function createTransformer< - GenericDataParser extends DP.DataParsers, + GenericDataParser extends SupportedDataParsers, >( - support: (schema: DP.DataParsers) => schema is GenericDataParser, + support: (schema: SupportedDataParsers) => schema is GenericDataParser, builder: ( schema: GenericDataParser, params: TransformerParams, ) => MaybeTransformerEither, ) { return ( - schema: DP.DataParsers, + schema: SupportedDataParsers, params: TransformerParams, ): MaybeTransformerEither => support(schema) ? builder( diff --git a/scripts/toTypescript/transformer/defaults/date.ts b/scripts/toTypescript/transformer/defaults/date.ts index 91e155a..b93b1f9 100644 --- a/scripts/toTypescript/transformer/defaults/date.ts +++ b/scripts/toTypescript/transformer/defaults/date.ts @@ -1,37 +1,51 @@ -import { DP } from "@duplojs/utils"; -import { factory, SyntaxKind } from "typescript"; +import { DP, P } from "@duplojs/utils"; +import { factory } from "typescript"; import { createTransformer } from "../create"; +const theDate = factory.createTypeReferenceNode( + factory.createIdentifier("TheDate"), +); + +const serializedTheDate = factory.createTypeReferenceNode( + factory.createIdentifier("SerializedTheDate"), +); + +const nativeDate = factory.createTypeReferenceNode( + factory.createIdentifier("Date"), + undefined, +); + export const dateTransformer = createTransformer( DP.dateKind.has, ( __schema, - { success }, - ) => success( - factory.createTemplateLiteralType( - factory.createTemplateHead( - "date", - "date", - ), - [ - factory.createTemplateLiteralTypeSpan( - factory.createKeywordTypeNode(SyntaxKind.NumberKeyword), - factory.createTemplateMiddle( - "", - "", - ), - ), - factory.createTemplateLiteralTypeSpan( - factory.createUnionTypeNode([ - factory.createLiteralTypeNode(factory.createStringLiteral("-")), - factory.createLiteralTypeNode(factory.createStringLiteral("+")), - ]), - factory.createTemplateTail( - "", - "", - ), - ), - ], - ), - ), + { + mode, + success, + addImport, + }, + ) => { + addImport("@duplojs/utils/date", "TheDate"); + + return P.match(mode) + .with( + "out", + () => success(theDate), + ) + .with( + "in", + () => { + addImport("@duplojs/utils/date", "SerializedTheDate"); + + return success( + factory.createUnionTypeNode([ + theDate, + nativeDate, + serializedTheDate, + ]), + ); + }, + ) + .exhaustive(); + }, ); diff --git a/scripts/toTypescript/transformer/defaults/file.ts b/scripts/toTypescript/transformer/defaults/file.ts new file mode 100644 index 0000000..b27450c --- /dev/null +++ b/scripts/toTypescript/transformer/defaults/file.ts @@ -0,0 +1,24 @@ +import { pipe } from "@duplojs/utils"; +import { SDP } from "@duplojs/server-utils"; +import { factory } from "typescript"; +import { createTransformer } from "../create"; + +export const fileTransformer = createTransformer( + SDP.fileKind.has, + ( + schema, + { + success, + addImport, + }, + ) => { + addImport("@duplojs/server-utils/file", "FileInterface"); + + return pipe( + "FileInterface", + factory.createIdentifier, + factory.createTypeReferenceNode, + success, + ); + }, +); diff --git a/scripts/toTypescript/transformer/defaults/index.ts b/scripts/toTypescript/transformer/defaults/index.ts index 9e2007a..accede4 100644 --- a/scripts/toTypescript/transformer/defaults/index.ts +++ b/scripts/toTypescript/transformer/defaults/index.ts @@ -44,6 +44,7 @@ import { unionTransformer } from "./union"; import { unknownTransformer } from "./unknown"; import { dateTransformer } from "./date"; import { timeTransformer } from "./time"; +import { fileTransformer } from "./file"; export const defaultTransformers = [ arrayTransformer, @@ -68,4 +69,5 @@ export const defaultTransformers = [ unknownTransformer, dateTransformer, timeTransformer, + fileTransformer, ] as const satisfies readonly ReturnType[]; diff --git a/scripts/toTypescript/transformer/defaults/record.ts b/scripts/toTypescript/transformer/defaults/record.ts index 6d36803..5d57a9d 100644 --- a/scripts/toTypescript/transformer/defaults/record.ts +++ b/scripts/toTypescript/transformer/defaults/record.ts @@ -1,5 +1,5 @@ import { DP, E, pipe, unwrap, when } from "@duplojs/utils"; -import { factory, type TypeNode } from "typescript"; +import { factory } from "typescript"; import { createTransformer } from "../create"; import { includesUndefinedTypeNode } from "../includesUndefinedTypeNode"; diff --git a/scripts/toTypescript/transformer/defaults/time.ts b/scripts/toTypescript/transformer/defaults/time.ts index 33db792..0804daf 100644 --- a/scripts/toTypescript/transformer/defaults/time.ts +++ b/scripts/toTypescript/transformer/defaults/time.ts @@ -1,37 +1,48 @@ -import { DP } from "@duplojs/utils"; +import { DP, P } from "@duplojs/utils"; import { factory, SyntaxKind } from "typescript"; import { createTransformer } from "../create"; +const theTime = factory.createTypeReferenceNode( + factory.createIdentifier("TheTime"), +); + +const serializedTheTime = factory.createTypeReferenceNode( + factory.createIdentifier("SerializedTheTime"), +); + +const number = factory.createKeywordTypeNode(SyntaxKind.NumberKeyword); + export const timeTransformer = createTransformer( DP.timeKind.has, ( __schema, - { success }, - ) => success( - factory.createTemplateLiteralType( - factory.createTemplateHead( - "time", - "time", - ), - [ - factory.createTemplateLiteralTypeSpan( - factory.createKeywordTypeNode(SyntaxKind.NumberKeyword), - factory.createTemplateMiddle( - "", - "", - ), - ), - factory.createTemplateLiteralTypeSpan( - factory.createUnionTypeNode([ - factory.createLiteralTypeNode(factory.createStringLiteral("-")), - factory.createLiteralTypeNode(factory.createStringLiteral("+")), - ]), - factory.createTemplateTail( - "", - "", - ), - ), - ], - ), - ), + { + mode, + success, + addImport, + }, + ) => { + addImport("@duplojs/utils/date", "TheTime"); + + return P.match(mode) + .with( + "out", + () => success(theTime), + ) + .with( + "in", + () => { + addImport("@duplojs/utils/date", "SerializedTheTime"); + + return success( + factory.createUnionTypeNode([ + serializedTheTime, + number, + theTime, + ]), + ); + }, + ) + .exhaustive(); + }, ); diff --git a/scripts/toTypescript/transformer/hook.ts b/scripts/toTypescript/transformer/hook.ts index 1e5de5d..4878942 100644 --- a/scripts/toTypescript/transformer/hook.ts +++ b/scripts/toTypescript/transformer/hook.ts @@ -1,5 +1,5 @@ -import { type DP } from "@duplojs/utils"; -import { type MapContext } from "./create"; +import type { DP } from "@duplojs/utils"; +import type { MapContext, MapImportType } from "./create"; export type TransformerHookAction = "stop" | "next"; @@ -11,6 +11,8 @@ export interface TransformerHookOutput { export interface TransformerHookParams { schema: DP.DataParsers; context: MapContext; + importType: MapImportType; + output( action: TransformerHookAction, schema: DP.DataParsers diff --git a/scripts/toTypescript/transformer/importTypesTransformer.ts b/scripts/toTypescript/transformer/importTypesTransformer.ts new file mode 100644 index 0000000..befe51b --- /dev/null +++ b/scripts/toTypescript/transformer/importTypesTransformer.ts @@ -0,0 +1,30 @@ +import { pipe, G, A } from "@duplojs/utils"; +import type { MapImportType } from "./create"; +import { factory, SyntaxKind } from "typescript"; + +export function importTypesTransformer(importTypes: MapImportType) { + return pipe( + importTypes, + G.map( + ([path, types]) => factory.createImportDeclaration( + undefined, + factory.createImportClause( + SyntaxKind.TypeKeyword, + undefined, + factory.createNamedImports( + A.map( + types, + (type) => factory.createImportSpecifier( + false, + undefined, + factory.createIdentifier(type), + ), + ), + ), + ), + factory.createStringLiteral(path), + undefined, + ), + ), + ); +} diff --git a/scripts/toTypescript/transformer/transformer.ts b/scripts/toTypescript/transformer/transformer.ts index 51a7306..ddd5f46 100644 --- a/scripts/toTypescript/transformer/transformer.ts +++ b/scripts/toTypescript/transformer/transformer.ts @@ -1,14 +1,15 @@ import { A, E, justReturn, unwrap, whenElse, type DP } from "@duplojs/utils"; -import { type MapContext, type DataParserNotSupportedEither, type TransformerParams, type createTransformer, type TransformerMode, type DataParserErrorEither } from "./create"; +import type { MapContext, DataParserNotSupportedEither, TransformerParams, createTransformer, TransformerMode, DataParserErrorEither, MapImportType, SupportedDataParsers } from "./create"; import { factory, SyntaxKind } from "typescript"; -import { type TransformerHook } from "./hook"; +import type { TransformerHook } from "./hook"; export interface TransformerFunctionParams { readonly transformers: readonly ReturnType[]; readonly context: MapContext; readonly mode: TransformerMode; readonly hooks: readonly TransformerHook[]; - readonly recursiveDataParsers: DP.DataParser[]; + readonly recursiveDataParsers: SupportedDataParsers[]; + readonly importType: MapImportType; } export function transformer( @@ -22,6 +23,7 @@ export function transformer( const result = hook({ schema: lastValue, context: params.context, + importType: params.importType, output: (action, schema) => ({ schema, action, @@ -84,6 +86,14 @@ export function transformer( buildError() { return E.left("buildDataParserError"); }, + importType: params.importType, + addImport(path, typeName) { + const types = params.importType.get(path) ?? []; + + if (!A.includes(types, typeName)) { + params.importType.set(path, A.push(types, typeName)); + } + }, }; const result = A.reduce( diff --git a/tests/toJsonSchema/transformers/__snapshots__/date.test.ts.snap b/tests/toJsonSchema/transformers/__snapshots__/date.test.ts.snap index a903359..540988e 100644 --- a/tests/toJsonSchema/transformers/__snapshots__/date.test.ts.snap +++ b/tests/toJsonSchema/transformers/__snapshots__/date.test.ts.snap @@ -8,7 +8,6 @@ exports[`date > allows coercion on input 1`] = ` "DateSchema": { "anyOf": [ { - "format": "date-time", "pattern": "^date-?(?\\d{1,16})(?[+-])$", "type": "string", }, @@ -35,7 +34,6 @@ exports[`date > renders out mode pattern 1`] = ` "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { "DateSchema": { - "format": "date-time", "pattern": "^date-?(?\\d{1,16})(?[+-])$", "type": "string", }, diff --git a/tests/toJsonSchema/transformers/__snapshots__/file.test.ts.snap b/tests/toJsonSchema/transformers/__snapshots__/file.test.ts.snap new file mode 100644 index 0000000..860543f --- /dev/null +++ b/tests/toJsonSchema/transformers/__snapshots__/file.test.ts.snap @@ -0,0 +1,16 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`file > renders schema 1`] = ` +{ + "$ref": "#/components/schemas/FileSchema", + "components": { + "schemas": { + "FileSchema": { + "format": "binary", + "type": "string", + }, + }, + }, + "openapi": "https://spec.openapis.org/oas/3.0.3", +} +`; diff --git a/tests/toJsonSchema/transformers/array.test.ts b/tests/toJsonSchema/transformers/array.test.ts index b13e6df..988ff40 100644 --- a/tests/toJsonSchema/transformers/array.test.ts +++ b/tests/toJsonSchema/transformers/array.test.ts @@ -13,7 +13,7 @@ function buildTransformerParams( return { mode: "out", context: new Map(), - version: supportedVersions.jsonSchema7, + version: "jsonSchema7", transformer, success(result, isOptional = false) { return E.right("buildSuccess", { diff --git a/tests/toJsonSchema/transformers/file.test.ts b/tests/toJsonSchema/transformers/file.test.ts new file mode 100644 index 0000000..ff93dde --- /dev/null +++ b/tests/toJsonSchema/transformers/file.test.ts @@ -0,0 +1,36 @@ +import { render, defaultTransformers, DataParserToJsonSchemaRenderError } from "@scripts/toJsonSchema"; +import { SDP } from "@duplojs/server-utils"; + +describe("file", () => { + it("renders schema", () => { + const schema = SDP.file(); + + expect( + render( + schema, + { + identifier: "FileSchema", + transformers: defaultTransformers, + mode: "out", + version: "openApi3", + }, + ), + ).toMatchSnapshot(); + }); + + it("error on version jsonSchema", () => { + const schema = SDP.file(); + + expect( + () => render( + schema, + { + identifier: "FileSchema", + transformers: defaultTransformers, + mode: "in", + version: "jsonSchema7", + }, + ), + ).toThrowError(DataParserToJsonSchemaRenderError); + }); +}); diff --git a/tests/toJsonSchema/transformers/nullable.test.ts b/tests/toJsonSchema/transformers/nullable.test.ts index 9ee718c..5525b29 100644 --- a/tests/toJsonSchema/transformers/nullable.test.ts +++ b/tests/toJsonSchema/transformers/nullable.test.ts @@ -1,7 +1,6 @@ import { render, defaultTransformers } from "@scripts/toJsonSchema"; import { nullableTransformer } from "@scripts/toJsonSchema/transformer/defaults"; import { - supportedVersions, type TransformerParams, } from "@scripts/toJsonSchema/transformer/create"; import { type DP, DPE, E } from "@duplojs/utils"; @@ -13,7 +12,7 @@ function buildTransformerParams( return { mode: "out", context: new Map(), - version: supportedVersions.jsonSchema7, + version: "jsonSchema7", transformer, success(result, isOptional = false) { return E.right("buildSuccess", { diff --git a/tests/toJsonSchema/transformers/object.test.ts b/tests/toJsonSchema/transformers/object.test.ts index f24fd58..62a0bce 100644 --- a/tests/toJsonSchema/transformers/object.test.ts +++ b/tests/toJsonSchema/transformers/object.test.ts @@ -13,7 +13,7 @@ function buildTransformerParams( return { mode: "out", context: new Map(), - version: supportedVersions.jsonSchema7, + version: "jsonSchema7", transformer, success(result, isOptional = false) { return E.right("buildSuccess", { diff --git a/tests/toJsonSchema/transformers/record.test.ts b/tests/toJsonSchema/transformers/record.test.ts index f46b7ff..f83b9b0 100644 --- a/tests/toJsonSchema/transformers/record.test.ts +++ b/tests/toJsonSchema/transformers/record.test.ts @@ -14,7 +14,7 @@ function buildTransformerParams( return { mode: "out", context: new Map(), - version: supportedVersions.jsonSchema7, + version: "jsonSchema7", transformer, success(result, isOptional = false) { return E.right("buildSuccess", { diff --git a/tests/toJsonSchema/transformers/recover.test.ts b/tests/toJsonSchema/transformers/recover.test.ts index 0c6827f..e040d23 100644 --- a/tests/toJsonSchema/transformers/recover.test.ts +++ b/tests/toJsonSchema/transformers/recover.test.ts @@ -13,7 +13,7 @@ function buildTransformerParams( return { mode: "out", context: new Map(), - version: supportedVersions.jsonSchema7, + version: "jsonSchema7", transformer, success(result, isOptional = false) { return E.right("buildSuccess", { @@ -31,7 +31,7 @@ describe("recover", () => { it("in mode produces unknown", () => { expect( render( - DPE.recover(DPE.string(), undefined), + DPE.recover(DPE.string(), "value"), { identifier: "RecoverSchema", transformers: defaultTransformers, @@ -45,7 +45,7 @@ describe("recover", () => { it("out mode uses inner schema", () => { expect( render( - DPE.recover(DPE.string(), undefined), + DPE.recover(DPE.string(), "value"), { identifier: "RecoverSchema", transformers: defaultTransformers, @@ -57,7 +57,7 @@ describe("recover", () => { }); it("returns left when inner transform fails", () => { - const schema = DPE.recover(DPE.string(), ""); + const schema = DPE.recover(DPE.string(), "value"); const params = buildTransformerParams( schema, () => E.left("dataParserNotSupport", schema.definition.inner), diff --git a/tests/toJsonSchema/transformers/tuple.test.ts b/tests/toJsonSchema/transformers/tuple.test.ts index 2d678b4..0cc23d5 100644 --- a/tests/toJsonSchema/transformers/tuple.test.ts +++ b/tests/toJsonSchema/transformers/tuple.test.ts @@ -13,7 +13,7 @@ function buildTransformerParams( return { mode: "out", context: new Map(), - version: supportedVersions.jsonSchema7, + version: "jsonSchema7", transformer, success(result, isOptional = false) { return E.right("buildSuccess", { diff --git a/tests/toJsonSchema/transformers/union.test.ts b/tests/toJsonSchema/transformers/union.test.ts index c09c4a0..15b72d1 100644 --- a/tests/toJsonSchema/transformers/union.test.ts +++ b/tests/toJsonSchema/transformers/union.test.ts @@ -13,7 +13,7 @@ function buildTransformerParams( return { mode: "out", context: new Map(), - version: supportedVersions.jsonSchema7, + version: "jsonSchema7", transformer, success(result, isOptional = false) { return E.right("buildSuccess", { diff --git a/tests/toTypescript/transfomers/__snapshots__/date.test.ts.snap b/tests/toTypescript/transfomers/__snapshots__/date.test.ts.snap index a04f844..fbdb74f 100644 --- a/tests/toTypescript/transfomers/__snapshots__/date.test.ts.snap +++ b/tests/toTypescript/transfomers/__snapshots__/date.test.ts.snap @@ -1,5 +1,31 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`date > string array 1`] = `"export type Date = \`date\${number}\${"-" | "+"}\`;"`; +exports[`date > mode in 1`] = ` +"import type { TheDate, SerializedTheDate } from "@duplojs/utils/date"; -exports[`date > string array 2`] = `"export type DateIdentifier = \`date\${number}\${"-" | "+"}\`;"`; +export type Date = TheDate | Date | SerializedTheDate;" +`; + +exports[`date > mode in 2`] = ` +"import type { TheDate, SerializedTheDate } from "@duplojs/utils/date"; + +export type DateIdentifier = TheDate | Date | SerializedTheDate;" +`; + +exports[`date > mode out 1`] = ` +"import type { TheDate } from "@duplojs/utils/date"; + +export type Date = TheDate;" +`; + +exports[`date > mode out 2`] = ` +"import type { TheDate } from "@duplojs/utils/date"; + +export type DateIdentifier = TheDate;" +`; + +exports[`date > with preset importType 1`] = ` +"import type { TheDate, SerializedTheDate } from "@duplojs/utils/date"; + +export type Date = TheDate | Date | SerializedTheDate;" +`; diff --git a/tests/toTypescript/transfomers/__snapshots__/file.test.ts.snap b/tests/toTypescript/transfomers/__snapshots__/file.test.ts.snap new file mode 100644 index 0000000..0e0facf --- /dev/null +++ b/tests/toTypescript/transfomers/__snapshots__/file.test.ts.snap @@ -0,0 +1,19 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`file > basic 1`] = ` +"import type { FileInterface } from "@duplojs/server-utils/file"; + +export type File = FileInterface;" +`; + +exports[`file > basic 2`] = ` +"import type { FileInterface } from "@duplojs/server-utils/file"; + +export type FileIdentifier = FileInterface;" +`; + +exports[`file > with preset importType 1`] = ` +"import type { FileInterface } from "@duplojs/server-utils/file"; + +export type File = FileInterface;" +`; diff --git a/tests/toTypescript/transfomers/__snapshots__/time.test.ts.snap b/tests/toTypescript/transfomers/__snapshots__/time.test.ts.snap index c9ff595..316a410 100644 --- a/tests/toTypescript/transfomers/__snapshots__/time.test.ts.snap +++ b/tests/toTypescript/transfomers/__snapshots__/time.test.ts.snap @@ -1,5 +1,31 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`time > string array 1`] = `"export type Time = \`time\${number}\${"-" | "+"}\`;"`; +exports[`time > mode in 1`] = ` +"import type { TheTime, SerializedTheTime } from "@duplojs/utils/date"; -exports[`time > string array 2`] = `"export type TimeIdentifier = \`time\${number}\${"-" | "+"}\`;"`; +export type Time = SerializedTheTime | number | TheTime;" +`; + +exports[`time > mode in 2`] = ` +"import type { TheTime, SerializedTheTime } from "@duplojs/utils/date"; + +export type TimeIdentifier = SerializedTheTime | number | TheTime;" +`; + +exports[`time > mode out 1`] = ` +"import type { TheTime } from "@duplojs/utils/date"; + +export type Time = TheTime;" +`; + +exports[`time > mode out 2`] = ` +"import type { TheTime } from "@duplojs/utils/date"; + +export type TimeIdentifier = TheTime;" +`; + +exports[`time > with preset importType 1`] = ` +"import type { TheTime, SerializedTheTime } from "@duplojs/utils/date"; + +export type Time = SerializedTheTime | number | TheTime;" +`; diff --git a/tests/toTypescript/transfomers/date.test.ts b/tests/toTypescript/transfomers/date.test.ts index b34f1fa..966b220 100644 --- a/tests/toTypescript/transfomers/date.test.ts +++ b/tests/toTypescript/transfomers/date.test.ts @@ -1,8 +1,8 @@ import { DPE } from "@duplojs/utils"; -import { defaultTransformers, render } from "@scripts/toTypescript"; +import { defaultTransformers, type MapImportType, render } from "@scripts/toTypescript"; describe("date", () => { - it("string array", () => { + it("mode out", () => { expect( render( DPE.date(), @@ -27,4 +27,47 @@ describe("date", () => { ), ).toMatchSnapshot(); }); + + it("mode in", () => { + expect( + render( + DPE.date(), + { + identifier: "Date", + transformers: defaultTransformers, + mode: "in", + }, + ), + ).toMatchSnapshot(); + + const schema = DPE.date().addIdentifier("DateIdentifier"); + + expect( + render( + schema, + { + identifier: "DateIdentifier", + transformers: defaultTransformers, + mode: "in", + }, + ), + ).toMatchSnapshot(); + }); + + it("with preset importType", () => { + const importType: MapImportType = new Map(); + importType.set("@duplojs/utils/date", ["TheDate"]); + + expect( + render( + DPE.date(), + { + identifier: "Date", + transformers: defaultTransformers, + mode: "in", + importType, + }, + ), + ).toMatchSnapshot(); + }); }); diff --git a/tests/toTypescript/transfomers/file.test.ts b/tests/toTypescript/transfomers/file.test.ts new file mode 100644 index 0000000..8c056d7 --- /dev/null +++ b/tests/toTypescript/transfomers/file.test.ts @@ -0,0 +1,47 @@ +import { SDP } from "@duplojs/server-utils"; +import { defaultTransformers, type MapImportType, render } from "@scripts/toTypescript"; + +describe("file", () => { + it("basic", () => { + expect( + render( + SDP.file(), + { + identifier: "File", + transformers: defaultTransformers, + mode: "out", + }, + ), + ).toMatchSnapshot(); + + const schema = SDP.file().addIdentifier("FileIdentifier"); + + expect( + render( + schema, + { + identifier: "FileIdentifier", + transformers: defaultTransformers, + mode: "out", + }, + ), + ).toMatchSnapshot(); + }); + + it("with preset importType", () => { + const importType: MapImportType = new Map(); + importType.set("@duplojs/server-utils/file", ["FileInterface"]); + + expect( + render( + SDP.file(), + { + identifier: "File", + transformers: defaultTransformers, + mode: "in", + importType, + }, + ), + ).toMatchSnapshot(); + }); +}); diff --git a/tests/toTypescript/transfomers/object.test.ts b/tests/toTypescript/transfomers/object.test.ts index 84becf2..3aa4007 100644 --- a/tests/toTypescript/transfomers/object.test.ts +++ b/tests/toTypescript/transfomers/object.test.ts @@ -10,7 +10,7 @@ describe("object", () => { literalUndefined: DPE.literal(["value", undefined]), unionWithOptional: DPE.union([DPE.number(), DPE.optional(DPE.string())]), pipeToRequired: DPE.pipe(DPE.optional(DPE.string()), DPE.number()), - recoverUndefined: DPE.recover(DPE.boolean(), undefined), + recoverUndefined: DPE.recover(DPE.boolean(), false), transformOptional: DPE.transform( DPE.optional(DPE.string()), (value: string | undefined) => value ?? "", diff --git a/tests/toTypescript/transfomers/recover.test.ts b/tests/toTypescript/transfomers/recover.test.ts index a54e057..05c781e 100644 --- a/tests/toTypescript/transfomers/recover.test.ts +++ b/tests/toTypescript/transfomers/recover.test.ts @@ -3,7 +3,7 @@ import { DPE } from "@duplojs/utils"; describe("recover", () => { it("keeps inner for input and recovered for output", () => { - const schema = DPE.recover(DPE.string(), { message: "ko" }); + const schema = DPE.recover(DPE.string(), "ko"); expect( render( diff --git a/tests/toTypescript/transfomers/templateLiteral.test.ts b/tests/toTypescript/transfomers/templateLiteral.test.ts index 23e91f9..25edf7c 100644 --- a/tests/toTypescript/transfomers/templateLiteral.test.ts +++ b/tests/toTypescript/transfomers/templateLiteral.test.ts @@ -87,6 +87,10 @@ describe("templateLiteral", () => { buildError: () => E.left("buildDataParserError"), mode: "out", context: new Map(), + importType: new Map(), + addImport(path, typeName) { + return; + }, }, ); @@ -107,6 +111,10 @@ describe("templateLiteral", () => { buildError: () => E.left("buildDataParserError"), mode: "out", context: new Map(), + importType: new Map(), + addImport(path, typeName) { + return; + }, }, ); diff --git a/tests/toTypescript/transfomers/time.test.ts b/tests/toTypescript/transfomers/time.test.ts index 3479287..7833df5 100644 --- a/tests/toTypescript/transfomers/time.test.ts +++ b/tests/toTypescript/transfomers/time.test.ts @@ -1,8 +1,8 @@ import { DPE } from "@duplojs/utils"; -import { defaultTransformers, render } from "@scripts/toTypescript"; +import { defaultTransformers, type MapImportType, render } from "@scripts/toTypescript"; describe("time", () => { - it("string array", () => { + it("mode out", () => { expect( render( DPE.time(), @@ -27,4 +27,47 @@ describe("time", () => { ), ).toMatchSnapshot(); }); + + it("mode in", () => { + expect( + render( + DPE.time(), + { + identifier: "Time", + transformers: defaultTransformers, + mode: "in", + }, + ), + ).toMatchSnapshot(); + + const schema = DPE.time().addIdentifier("TimeIdentifier"); + + expect( + render( + schema, + { + identifier: "TimeIdentifier", + transformers: defaultTransformers, + mode: "in", + }, + ), + ).toMatchSnapshot(); + }); + + it("with preset importType", () => { + const importType: MapImportType = new Map(); + importType.set("@duplojs/utils/date", ["TheTime"]); + + expect( + render( + DPE.time(), + { + identifier: "Time", + transformers: defaultTransformers, + mode: "in", + importType, + }, + ), + ).toMatchSnapshot(); + }); });