From c3d515c359133d986f98986d92790d44d2c07000 Mon Sep 17 00:00:00 2001 From: ZeRiix Date: Tue, 19 May 2026 16:46:37 +0200 Subject: [PATCH 01/16] feat(06): add checker transformer --- .../toDataParser/checkerTransformer/create.ts | 70 +++++++++++ .../defaults/array/index.ts | 2 + .../checkerTransformer/defaults/array/max.ts | 28 +++++ .../checkerTransformer/defaults/array/min.ts | 28 +++++ .../defaults/bigint/index.ts | 2 + .../checkerTransformer/defaults/bigint/max.ts | 28 +++++ .../checkerTransformer/defaults/bigint/min.ts | 28 +++++ .../checkerTransformer/defaults/index.ts | 36 ++++++ .../defaults/number/index.ts | 3 + .../checkerTransformer/defaults/number/int.ts | 25 ++++ .../checkerTransformer/defaults/number/max.ts | 39 ++++++ .../checkerTransformer/defaults/number/min.ts | 39 ++++++ .../checkerTransformer/defaults/refine.ts | 61 ++++++++++ .../defaults/string/email.ts | 25 ++++ .../defaults/string/index.ts | 6 + .../checkerTransformer/defaults/string/max.ts | 28 +++++ .../checkerTransformer/defaults/string/min.ts | 28 +++++ .../defaults/string/regex.ts | 32 +++++ .../checkerTransformer/defaults/string/url.ts | 58 +++++++++ .../defaults/string/uuid.ts | 25 ++++ .../checkerTransformer/defaults/time/index.ts | 2 + .../checkerTransformer/defaults/time/max.ts | 38 ++++++ .../checkerTransformer/defaults/time/min.ts | 38 ++++++ .../toDataParser/checkerTransformer/index.ts | 3 + .../checkerTransformer/transformer.ts | 71 +++++++++++ .../__snapshots__/arrayMax.test.ts.snap | 3 + .../__snapshots__/arrayMin.test.ts.snap | 3 + .../__snapshots__/bigintMax.test.ts.snap | 3 + .../__snapshots__/bigintMin.test.ts.snap | 3 + .../__snapshots__/email.test.ts.snap | 3 + .../__snapshots__/int.test.ts.snap | 3 + .../__snapshots__/numberMax.test.ts.snap | 5 + .../__snapshots__/numberMin.test.ts.snap | 5 + .../__snapshots__/refine.test.ts.snap | 3 + .../__snapshots__/regex.test.ts.snap | 3 + .../__snapshots__/stringMax.test.ts.snap | 3 + .../__snapshots__/stringMin.test.ts.snap | 3 + .../__snapshots__/timeMax.test.ts.snap | 3 + .../__snapshots__/timeMin.test.ts.snap | 3 + .../__snapshots__/url.test.ts.snap | 5 + .../__snapshots__/uuid.test.ts.snap | 3 + .../checkerTransfomers/arrayMax.test.ts | 15 +++ .../checkerTransfomers/arrayMin.test.ts | 15 +++ .../checkerTransfomers/bigintMax.test.ts | 15 +++ .../checkerTransfomers/bigintMin.test.ts | 15 +++ .../checkerTransfomers/email.test.ts | 15 +++ .../checkerTransfomers/int.test.ts | 15 +++ .../checkerTransfomers/numberMax.test.ts | 25 ++++ .../checkerTransfomers/numberMin.test.ts | 25 ++++ .../checkerTransfomers/refine.test.ts | 113 ++++++++++++++++++ .../checkerTransfomers/regex.test.ts | 15 +++ .../checkerTransfomers/stringMax.test.ts | 15 +++ .../checkerTransfomers/stringMin.test.ts | 15 +++ .../checkerTransfomers/timeMax.test.ts | 15 +++ .../checkerTransfomers/timeMin.test.ts | 15 +++ .../checkerTransfomers/url.test.ts | 29 +++++ .../toDataParser/checkerTransfomers/utils.ts | 7 ++ .../checkerTransfomers/uuid.test.ts | 15 +++ 58 files changed, 1176 insertions(+) create mode 100644 scripts/toDataParser/checkerTransformer/create.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/array/index.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/array/max.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/array/min.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/bigint/index.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/bigint/max.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/bigint/min.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/index.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/number/index.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/number/int.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/number/max.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/number/min.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/refine.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/string/email.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/string/index.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/string/max.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/string/min.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/string/regex.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/string/url.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/string/uuid.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/time/index.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/time/max.ts create mode 100644 scripts/toDataParser/checkerTransformer/defaults/time/min.ts create mode 100644 scripts/toDataParser/checkerTransformer/index.ts create mode 100644 scripts/toDataParser/checkerTransformer/transformer.ts create mode 100644 tests/toDataParser/checkerTransfomers/__snapshots__/arrayMax.test.ts.snap create mode 100644 tests/toDataParser/checkerTransfomers/__snapshots__/arrayMin.test.ts.snap create mode 100644 tests/toDataParser/checkerTransfomers/__snapshots__/bigintMax.test.ts.snap create mode 100644 tests/toDataParser/checkerTransfomers/__snapshots__/bigintMin.test.ts.snap create mode 100644 tests/toDataParser/checkerTransfomers/__snapshots__/email.test.ts.snap create mode 100644 tests/toDataParser/checkerTransfomers/__snapshots__/int.test.ts.snap create mode 100644 tests/toDataParser/checkerTransfomers/__snapshots__/numberMax.test.ts.snap create mode 100644 tests/toDataParser/checkerTransfomers/__snapshots__/numberMin.test.ts.snap create mode 100644 tests/toDataParser/checkerTransfomers/__snapshots__/refine.test.ts.snap create mode 100644 tests/toDataParser/checkerTransfomers/__snapshots__/regex.test.ts.snap create mode 100644 tests/toDataParser/checkerTransfomers/__snapshots__/stringMax.test.ts.snap create mode 100644 tests/toDataParser/checkerTransfomers/__snapshots__/stringMin.test.ts.snap create mode 100644 tests/toDataParser/checkerTransfomers/__snapshots__/timeMax.test.ts.snap create mode 100644 tests/toDataParser/checkerTransfomers/__snapshots__/timeMin.test.ts.snap create mode 100644 tests/toDataParser/checkerTransfomers/__snapshots__/url.test.ts.snap create mode 100644 tests/toDataParser/checkerTransfomers/__snapshots__/uuid.test.ts.snap create mode 100644 tests/toDataParser/checkerTransfomers/arrayMax.test.ts create mode 100644 tests/toDataParser/checkerTransfomers/arrayMin.test.ts create mode 100644 tests/toDataParser/checkerTransfomers/bigintMax.test.ts create mode 100644 tests/toDataParser/checkerTransfomers/bigintMin.test.ts create mode 100644 tests/toDataParser/checkerTransfomers/email.test.ts create mode 100644 tests/toDataParser/checkerTransfomers/int.test.ts create mode 100644 tests/toDataParser/checkerTransfomers/numberMax.test.ts create mode 100644 tests/toDataParser/checkerTransfomers/numberMin.test.ts create mode 100644 tests/toDataParser/checkerTransfomers/refine.test.ts create mode 100644 tests/toDataParser/checkerTransfomers/regex.test.ts create mode 100644 tests/toDataParser/checkerTransfomers/stringMax.test.ts create mode 100644 tests/toDataParser/checkerTransfomers/stringMin.test.ts create mode 100644 tests/toDataParser/checkerTransfomers/timeMax.test.ts create mode 100644 tests/toDataParser/checkerTransfomers/timeMin.test.ts create mode 100644 tests/toDataParser/checkerTransfomers/url.test.ts create mode 100644 tests/toDataParser/checkerTransfomers/utils.ts create mode 100644 tests/toDataParser/checkerTransfomers/uuid.test.ts diff --git a/scripts/toDataParser/checkerTransformer/create.ts b/scripts/toDataParser/checkerTransformer/create.ts new file mode 100644 index 0000000..1def70c --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/create.ts @@ -0,0 +1,70 @@ +import type { CallExpression, ObjectLiteralExpression, PropertyAssignment } from "typescript"; +import { type DP, E } from "@duplojs/utils"; + +export type CheckerTransformerSuccessEither = E.Right<"buildSuccess", CallExpression>; + +export type CheckerTransformerCheckerNotSupportedEither = E.Left<"checkerNotSupport", DP.DataParserChecker>; + +export type CheckerTransformerBuildErrorEither = E.Left<"buildCheckerError", DP.DataParserChecker>; + +export type CheckerTransformerEither = + | CheckerTransformerSuccessEither + | CheckerTransformerCheckerNotSupportedEither + | CheckerTransformerBuildErrorEither; + +export interface CheckerTransformerParams { + success( + result: CallExpression, + ): CheckerTransformerSuccessEither; + buildError(): CheckerTransformerBuildErrorEither; + getDefinition( + customProperties?: readonly PropertyAssignment[] + ): readonly [ObjectLiteralExpression] | readonly []; +} + +/** + * @deprecated + */ +export type DataParserCheckers = ( + | DP.DataParserChecker + | DP.DataParserCheckerArrayMax + | DP.DataParserCheckerArrayMin + | DP.DataParserCheckerBigIntMax + | DP.DataParserCheckerBigIntMin + | DP.DataParserCheckerNumberMax + | DP.DataParserCheckerNumberMin + | DP.DataParserCheckerInt + | DP.DataParserCheckerStringMax + | DP.DataParserCheckerStringMin + | DP.DataParserCheckerEmail + | DP.DataParserCheckerRegex + | DP.DataParserCheckerUrl + | DP.DataParserCheckerUuid + | DP.DataParserCheckerRefine + | DP.DataParserCheckerTimeMin + | DP.DataParserCheckerTimeMax +); + +export type CheckerTransformerBuildFunction< + GenericChecker extends DataParserCheckers = DataParserCheckers, +> = ( + checker: GenericChecker, + params: CheckerTransformerParams, +) => CheckerTransformerEither; + +export function createCheckerTransformer< + GenericChecker extends DataParserCheckers, +>( + support: (checker: DataParserCheckers) => checker is GenericChecker, + builder: CheckerTransformerBuildFunction, +) { + return ( + checker: DataParserCheckers, + params: CheckerTransformerParams, + ): CheckerTransformerEither => support(checker) + ? builder( + checker as GenericChecker, + params, + ) + : E.left("checkerNotSupport", checker); +} diff --git a/scripts/toDataParser/checkerTransformer/defaults/array/index.ts b/scripts/toDataParser/checkerTransformer/defaults/array/index.ts new file mode 100644 index 0000000..cc0a179 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/array/index.ts @@ -0,0 +1,2 @@ +export * from "./max"; +export * from "./min"; diff --git a/scripts/toDataParser/checkerTransformer/defaults/array/max.ts b/scripts/toDataParser/checkerTransformer/defaults/array/max.ts new file mode 100644 index 0000000..2a76487 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/array/max.ts @@ -0,0 +1,28 @@ +import { DP } from "@duplojs/utils"; +import { createCheckerTransformer } from "../../create"; +import { factory } from "typescript"; + +export const checkerArrayMaxTransformer = createCheckerTransformer( + DP.checkerArrayMaxKind.has, + ( + checker, + { + success, + getDefinition, + }, + ) => { + const expression = factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("DP"), + factory.createIdentifier("checkerArrayMax"), + ), + undefined, + [ + factory.createNumericLiteral(checker.definition.max), + ...getDefinition(), + ], + ); + + return success(expression); + }, +); diff --git a/scripts/toDataParser/checkerTransformer/defaults/array/min.ts b/scripts/toDataParser/checkerTransformer/defaults/array/min.ts new file mode 100644 index 0000000..43c5384 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/array/min.ts @@ -0,0 +1,28 @@ +import { DP } from "@duplojs/utils"; +import { createCheckerTransformer } from "../../create"; +import { factory } from "typescript"; + +export const checkerArrayMinTransformer = createCheckerTransformer( + DP.checkerArrayMinKind.has, + ( + checker, + { + success, + getDefinition, + }, + ) => { + const expression = factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("DP"), + factory.createIdentifier("checkerArrayMin"), + ), + undefined, + [ + factory.createNumericLiteral(checker.definition.min), + ...getDefinition(), + ], + ); + + return success(expression); + }, +); diff --git a/scripts/toDataParser/checkerTransformer/defaults/bigint/index.ts b/scripts/toDataParser/checkerTransformer/defaults/bigint/index.ts new file mode 100644 index 0000000..cc0a179 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/bigint/index.ts @@ -0,0 +1,2 @@ +export * from "./max"; +export * from "./min"; diff --git a/scripts/toDataParser/checkerTransformer/defaults/bigint/max.ts b/scripts/toDataParser/checkerTransformer/defaults/bigint/max.ts new file mode 100644 index 0000000..0be6bf9 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/bigint/max.ts @@ -0,0 +1,28 @@ +import { DP } from "@duplojs/utils"; +import { createCheckerTransformer } from "../../create"; +import { factory } from "typescript"; + +export const checkerBigIntMaxTransformer = createCheckerTransformer( + DP.checkerBigIntMaxKind.has, + ( + checker, + { + success, + getDefinition, + }, + ) => { + const expression = factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("DP"), + factory.createIdentifier("checkerBigIntMax"), + ), + undefined, + [ + factory.createBigIntLiteral(`${checker.definition.max.toString()}n`), + ...getDefinition(), + ], + ); + + return success(expression); + }, +); diff --git a/scripts/toDataParser/checkerTransformer/defaults/bigint/min.ts b/scripts/toDataParser/checkerTransformer/defaults/bigint/min.ts new file mode 100644 index 0000000..98c8693 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/bigint/min.ts @@ -0,0 +1,28 @@ +import { DP } from "@duplojs/utils"; +import { createCheckerTransformer } from "../../create"; +import { factory } from "typescript"; + +export const checkerBigIntMinTransformer = createCheckerTransformer( + DP.checkerBigIntMinKind.has, + ( + checker, + { + success, + getDefinition, + }, + ) => { + const expression = factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("DP"), + factory.createIdentifier("checkerBigIntMin"), + ), + undefined, + [ + factory.createBigIntLiteral(`${checker.definition.min.toString()}n`), + ...getDefinition(), + ], + ); + + return success(expression); + }, +); diff --git a/scripts/toDataParser/checkerTransformer/defaults/index.ts b/scripts/toDataParser/checkerTransformer/defaults/index.ts new file mode 100644 index 0000000..457426e --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/index.ts @@ -0,0 +1,36 @@ +export * from "./number"; +export * from "./string"; +export * from "./array"; + +import type { createCheckerTransformer } from "../create"; + +import { checkerIntTransformer, checkerNumberMaxTransformer, checkerNumberMinTransformer } from "./number"; +import { checkerEmailTransformer, checkerRegexTransformer, checkerStringMaxTransformer, checkerStringMinTransformer, checkerUrlTransformer, checkerUuidTransformer } from "./string"; +import { checkerArrayMaxTransformer, checkerArrayMinTransformer } from "./array"; +import { checkerBigIntMaxTransformer, checkerBigIntMinTransformer } from "./bigint"; +import { checkerTimeMaxTransformer, checkerTimeMinTransformer } from "./time"; +import { checkerRefineTransformer } from "./refine"; + +export const defaultCheckerTransformers = [ + checkerRefineTransformer, + // number + checkerNumberMaxTransformer, + checkerNumberMinTransformer, + checkerIntTransformer, + // string + checkerStringMaxTransformer, + checkerStringMinTransformer, + checkerEmailTransformer, + checkerRegexTransformer, + checkerUuidTransformer, + checkerUrlTransformer, + // array + checkerArrayMaxTransformer, + checkerArrayMinTransformer, + // bigint + checkerBigIntMaxTransformer, + checkerBigIntMinTransformer, + // time + checkerTimeMaxTransformer, + checkerTimeMinTransformer, +] as const satisfies readonly ReturnType[]; diff --git a/scripts/toDataParser/checkerTransformer/defaults/number/index.ts b/scripts/toDataParser/checkerTransformer/defaults/number/index.ts new file mode 100644 index 0000000..a077ac2 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/number/index.ts @@ -0,0 +1,3 @@ +export * from "./int"; +export * from "./min"; +export * from "./max"; diff --git a/scripts/toDataParser/checkerTransformer/defaults/number/int.ts b/scripts/toDataParser/checkerTransformer/defaults/number/int.ts new file mode 100644 index 0000000..2e875d5 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/number/int.ts @@ -0,0 +1,25 @@ +import { DP } from "@duplojs/utils"; +import { createCheckerTransformer } from "../../create"; +import { factory } from "typescript"; + +export const checkerIntTransformer = createCheckerTransformer( + DP.checkerIntKind.has, + ( + checker, + { + success, + getDefinition, + }, + ) => { + const expression = factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("DP"), + factory.createIdentifier("checkerInt"), + ), + undefined, + getDefinition(), + ); + + return success(expression); + }, +); diff --git a/scripts/toDataParser/checkerTransformer/defaults/number/max.ts b/scripts/toDataParser/checkerTransformer/defaults/number/max.ts new file mode 100644 index 0000000..5c2939b --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/number/max.ts @@ -0,0 +1,39 @@ +import { DP } from "@duplojs/utils"; +import { createCheckerTransformer } from "../../create"; +import { factory, type PropertyAssignment } from "typescript"; + +export const checkerNumberMaxTransformer = createCheckerTransformer( + DP.checkerNumberMaxKind.has, + ( + checker, + { + success, + getDefinition, + }, + ) => { + const checkerDefinition: PropertyAssignment[] = []; + + if (checker.definition.exclusive) { + checkerDefinition.push( + factory.createPropertyAssignment( + factory.createIdentifier("exclusive"), + factory.createTrue(), + ), + ); + } + + const expression = factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("DP"), + factory.createIdentifier("checkerNumberMax"), + ), + undefined, + [ + factory.createNumericLiteral(checker.definition.max), + ...getDefinition(checkerDefinition), + ], + ); + + return success(expression); + }, +); diff --git a/scripts/toDataParser/checkerTransformer/defaults/number/min.ts b/scripts/toDataParser/checkerTransformer/defaults/number/min.ts new file mode 100644 index 0000000..3fef8c7 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/number/min.ts @@ -0,0 +1,39 @@ +import { DP } from "@duplojs/utils"; +import { createCheckerTransformer } from "../../create"; +import { factory, type PropertyAssignment } from "typescript"; + +export const checkerNumberMinTransformer = createCheckerTransformer( + DP.checkerNumberMinKind.has, + ( + checker, + { + success, + getDefinition, + }, + ) => { + const checkerDefinition: PropertyAssignment[] = []; + + if (checker.definition.exclusive) { + checkerDefinition.push( + factory.createPropertyAssignment( + factory.createIdentifier("exclusive"), + factory.createTrue(), + ), + ); + } + + const expression = factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("DP"), + factory.createIdentifier("checkerNumberMin"), + ), + undefined, + [ + factory.createNumericLiteral(checker.definition.min), + ...getDefinition(checkerDefinition), + ], + ); + + return success(expression); + }, +); diff --git a/scripts/toDataParser/checkerTransformer/defaults/refine.ts b/scripts/toDataParser/checkerTransformer/defaults/refine.ts new file mode 100644 index 0000000..e4ceab1 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/refine.ts @@ -0,0 +1,61 @@ +import { DP } from "@duplojs/utils"; +import { createCheckerTransformer } from "../create"; +import { createSourceFile, factory, isArrowFunction, isExpressionStatement, isFunctionExpression, isParenthesizedExpression, ScriptTarget } from "typescript"; + +export const checkerRefineTransformer = createCheckerTransformer( + DP.dataParserCheckerRefineKind.has, + ( + checker, + { + success, + buildError, + getDefinition, + }, + ) => { + const functionSource = checker.definition.theFunction.toString(); + + if (functionSource.includes("[native code]")) { + return buildError(); + } + + const sourceFile = createSourceFile( + "refine-function.ts", + `(${functionSource})`, + ScriptTarget.Latest, + false, + ); + + const statement = sourceFile.statements[0]; + if (!statement || !isExpressionStatement(statement)) { + return buildError(); + } + + const functionExpression = isParenthesizedExpression(statement.expression) + ? statement.expression.expression + : undefined; + + if ( + !functionExpression + || ( + !isFunctionExpression(functionExpression) + && !isArrowFunction(functionExpression) + ) + ) { + return buildError(); + } + + const expression = factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("DP"), + factory.createIdentifier("checkerRefine"), + ), + undefined, + [ + functionExpression, + ...getDefinition(), + ], + ); + + return success(expression); + }, +); diff --git a/scripts/toDataParser/checkerTransformer/defaults/string/email.ts b/scripts/toDataParser/checkerTransformer/defaults/string/email.ts new file mode 100644 index 0000000..9f7bd25 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/string/email.ts @@ -0,0 +1,25 @@ +import { DP } from "@duplojs/utils"; +import { createCheckerTransformer } from "../../create"; +import { factory } from "typescript"; + +export const checkerEmailTransformer = createCheckerTransformer( + DP.checkerEmailKind.has, + ( + checker, + { + success, + getDefinition, + }, + ) => { + const expression = factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("DP"), + factory.createIdentifier("checkerEmail"), + ), + undefined, + getDefinition(), + ); + + return success(expression); + }, +); diff --git a/scripts/toDataParser/checkerTransformer/defaults/string/index.ts b/scripts/toDataParser/checkerTransformer/defaults/string/index.ts new file mode 100644 index 0000000..7713ea4 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/string/index.ts @@ -0,0 +1,6 @@ +export * from "./email"; +export * from "./max"; +export * from "./min"; +export * from "./regex"; +export * from "./url"; +export * from "./uuid"; diff --git a/scripts/toDataParser/checkerTransformer/defaults/string/max.ts b/scripts/toDataParser/checkerTransformer/defaults/string/max.ts new file mode 100644 index 0000000..660d4ae --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/string/max.ts @@ -0,0 +1,28 @@ +import { DP } from "@duplojs/utils"; +import { createCheckerTransformer } from "../../create"; +import { factory } from "typescript"; + +export const checkerStringMaxTransformer = createCheckerTransformer( + DP.checkerStringMaxKind.has, + ( + checker, + { + success, + getDefinition, + }, + ) => { + const expression = factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("DP"), + factory.createIdentifier("checkerStringMax"), + ), + undefined, + [ + factory.createNumericLiteral(checker.definition.max), + ...getDefinition(), + ], + ); + + return success(expression); + }, +); diff --git a/scripts/toDataParser/checkerTransformer/defaults/string/min.ts b/scripts/toDataParser/checkerTransformer/defaults/string/min.ts new file mode 100644 index 0000000..f840880 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/string/min.ts @@ -0,0 +1,28 @@ +import { DP } from "@duplojs/utils"; +import { createCheckerTransformer } from "../../create"; +import { factory } from "typescript"; + +export const checkerStringMinTransformer = createCheckerTransformer( + DP.checkerStringMinKind.has, + ( + checker, + { + success, + getDefinition, + }, + ) => { + const expression = factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("DP"), + factory.createIdentifier("checkerStringMin"), + ), + undefined, + [ + factory.createNumericLiteral(checker.definition.min), + ...getDefinition(), + ], + ); + + return success(expression); + }, +); diff --git a/scripts/toDataParser/checkerTransformer/defaults/string/regex.ts b/scripts/toDataParser/checkerTransformer/defaults/string/regex.ts new file mode 100644 index 0000000..ca0346e --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/string/regex.ts @@ -0,0 +1,32 @@ +import { DP } from "@duplojs/utils"; +import { createCheckerTransformer } from "../../create"; +import { factory } from "typescript"; + +export const checkerRegexTransformer = createCheckerTransformer( + DP.checkerRegexKind.has, + ( + checker, + { + success, + getDefinition, + }, + ) => { + const expression = factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("DP"), + factory.createIdentifier("checkerRegex"), + ), + undefined, + [ + factory.createRegularExpressionLiteral( + `/${checker.definition.regex.source}/${checker.definition.regex.flags}`, + ), + ...getDefinition(), + ], + ); + + return success(expression); + }, +); + +DP.checkerRegex(/^/); diff --git a/scripts/toDataParser/checkerTransformer/defaults/string/url.ts b/scripts/toDataParser/checkerTransformer/defaults/string/url.ts new file mode 100644 index 0000000..f6cfc16 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/string/url.ts @@ -0,0 +1,58 @@ +import { DP } from "@duplojs/utils"; +import { createCheckerTransformer } from "../../create"; +import { factory, type PropertyAssignment } from "typescript"; + +export const checkerUrlTransformer = createCheckerTransformer( + DP.checkerUrlKind.has, + ( + checker, + { + success, + getDefinition, + }, + ) => { + const checkerDefinition: PropertyAssignment[] = []; + + if (checker.definition.hostname) { + checkerDefinition.push( + factory.createPropertyAssignment( + factory.createIdentifier("hostname"), + factory.createRegularExpressionLiteral( + `/${checker.definition.hostname.source}/${checker.definition.hostname.flags}`, + ), + ), + ); + } + + if (checker.definition.normalize) { + checkerDefinition.push( + factory.createPropertyAssignment( + factory.createIdentifier("normalize"), + factory.createTrue(), + ), + ); + } + + if (checker.definition.protocol) { + checkerDefinition.push( + factory.createPropertyAssignment( + factory.createIdentifier("protocol"), + factory.createRegularExpressionLiteral( + `/${checker.definition.protocol.source}/${checker.definition.protocol.flags}`, + ), + ), + ); + } + + const expression = factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("DP"), + factory.createIdentifier("checkerUrl"), + ), + undefined, + getDefinition(checkerDefinition), + ); + + return success(expression); + }, +); diff --git a/scripts/toDataParser/checkerTransformer/defaults/string/uuid.ts b/scripts/toDataParser/checkerTransformer/defaults/string/uuid.ts new file mode 100644 index 0000000..a488c41 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/string/uuid.ts @@ -0,0 +1,25 @@ +import { DP } from "@duplojs/utils"; +import { createCheckerTransformer } from "../../create"; +import { factory } from "typescript"; + +export const checkerUuidTransformer = createCheckerTransformer( + DP.checkerUuidKind.has, + ( + checker, + { + success, + getDefinition, + }, + ) => { + const expression = factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("DP"), + factory.createIdentifier("checkerUuid"), + ), + undefined, + getDefinition(), + ); + + return success(expression); + }, +); diff --git a/scripts/toDataParser/checkerTransformer/defaults/time/index.ts b/scripts/toDataParser/checkerTransformer/defaults/time/index.ts new file mode 100644 index 0000000..cc0a179 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/time/index.ts @@ -0,0 +1,2 @@ +export * from "./max"; +export * from "./min"; diff --git a/scripts/toDataParser/checkerTransformer/defaults/time/max.ts b/scripts/toDataParser/checkerTransformer/defaults/time/max.ts new file mode 100644 index 0000000..e5100cf --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/time/max.ts @@ -0,0 +1,38 @@ +import { DP } from "@duplojs/utils"; +import { createCheckerTransformer } from "../../create"; +import { factory } from "typescript"; + +export const checkerTimeMaxTransformer = createCheckerTransformer( + DP.checkerTimeMaxKind.has, + ( + checker, + { + success, + getDefinition, + }, + ) => { + const expression = factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("DP"), + factory.createIdentifier("checkerTimeMax"), + ), + undefined, + [ + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("DDate"), + factory.createIdentifier("createTime"), + ), + undefined, + [ + factory.createNumericLiteral(checker.definition.max.toNative()), + factory.createStringLiteral("millisecond"), + ], + ), + ...getDefinition(), + ], + ); + + return success(expression); + }, +); diff --git a/scripts/toDataParser/checkerTransformer/defaults/time/min.ts b/scripts/toDataParser/checkerTransformer/defaults/time/min.ts new file mode 100644 index 0000000..6edc1c6 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/defaults/time/min.ts @@ -0,0 +1,38 @@ +import { DP } from "@duplojs/utils"; +import { createCheckerTransformer } from "../../create"; +import { factory } from "typescript"; + +export const checkerTimeMinTransformer = createCheckerTransformer( + DP.checkerTimeMinKind.has, + ( + checker, + { + success, + getDefinition, + }, + ) => { + const expression = factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("DP"), + factory.createIdentifier("checkerTimeMin"), + ), + undefined, + [ + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("DDate"), + factory.createIdentifier("createTime"), + ), + undefined, + [ + factory.createNumericLiteral(checker.definition.min.toNative()), + factory.createStringLiteral("millisecond"), + ], + ), + ...getDefinition(), + ], + ); + + return success(expression); + }, +); diff --git a/scripts/toDataParser/checkerTransformer/index.ts b/scripts/toDataParser/checkerTransformer/index.ts new file mode 100644 index 0000000..a51ba64 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/index.ts @@ -0,0 +1,3 @@ +export * from "./create"; +export * from "./transformer"; +export * from "./defaults"; diff --git a/scripts/toDataParser/checkerTransformer/transformer.ts b/scripts/toDataParser/checkerTransformer/transformer.ts new file mode 100644 index 0000000..8c69945 --- /dev/null +++ b/scripts/toDataParser/checkerTransformer/transformer.ts @@ -0,0 +1,71 @@ +import { A, E, type DP } from "@duplojs/utils"; +import type { CheckerTransformerParams, createCheckerTransformer, CheckerTransformerEither } from "./create"; +import { factory, type PropertyAssignment } from "typescript"; + +export interface CheckerTransformerFunctionParams { + readonly transformers: readonly ReturnType[]; +} + +export function getCheckerDefinition(checker: DP.DataParserChecker, customProperties?: readonly PropertyAssignment[]) { + const propertyAssignments: PropertyAssignment[] = []; + + if (checker.definition.errorMessage) { + propertyAssignments.push( + factory.createPropertyAssignment( + factory.createIdentifier("errorMessage"), + factory.createStringLiteral(checker.definition.errorMessage), + ), + ); + } + + if (customProperties) { + propertyAssignments.push(...customProperties); + } + + return A.minElements(propertyAssignments, 1) + ? [factory.createObjectLiteralExpression(propertyAssignments)] + : []; +} + +export function checkerTransformer( + checker: DP.DataParserChecker, + params: CheckerTransformerFunctionParams, +) { + const functionParams: CheckerTransformerParams = { + success(result) { + return E.right("buildSuccess", result); + }, + buildError() { + return E.left("buildCheckerError", checker); + }, + getDefinition(customProperties) { + return getCheckerDefinition(checker, customProperties); + }, + }; + + return A.reduce( + params.transformers, + A.reduceFrom( + E.left("checkerNotSupport", checker), + ), + ({ + element: functionBuilder, + lastValue, + next, + exit, + }) => { + const result = functionBuilder(checker, functionParams); + + if (E.isLeft(result)) { + if (!E.hasInformation(result, "checkerNotSupport")) { + return exit(result); + } + + return next(lastValue); + } + + return exit(result); + }, + ); +} + diff --git a/tests/toDataParser/checkerTransfomers/__snapshots__/arrayMax.test.ts.snap b/tests/toDataParser/checkerTransfomers/__snapshots__/arrayMax.test.ts.snap new file mode 100644 index 0000000..01e3724 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/__snapshots__/arrayMax.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`checkerArrayMax > basic 1`] = `"DP.checkerArrayMax(5)"`; diff --git a/tests/toDataParser/checkerTransfomers/__snapshots__/arrayMin.test.ts.snap b/tests/toDataParser/checkerTransfomers/__snapshots__/arrayMin.test.ts.snap new file mode 100644 index 0000000..7057cfa --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/__snapshots__/arrayMin.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`checkerArrayMin > basic 1`] = `"DP.checkerArrayMin(1)"`; diff --git a/tests/toDataParser/checkerTransfomers/__snapshots__/bigintMax.test.ts.snap b/tests/toDataParser/checkerTransfomers/__snapshots__/bigintMax.test.ts.snap new file mode 100644 index 0000000..ad9b3c4 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/__snapshots__/bigintMax.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`checkerBigIntMax > basic 1`] = `"DP.checkerBigIntMax(10n)"`; diff --git a/tests/toDataParser/checkerTransfomers/__snapshots__/bigintMin.test.ts.snap b/tests/toDataParser/checkerTransfomers/__snapshots__/bigintMin.test.ts.snap new file mode 100644 index 0000000..ac627fd --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/__snapshots__/bigintMin.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`checkerBigIntMin > basic 1`] = `"DP.checkerBigIntMin(1n)"`; diff --git a/tests/toDataParser/checkerTransfomers/__snapshots__/email.test.ts.snap b/tests/toDataParser/checkerTransfomers/__snapshots__/email.test.ts.snap new file mode 100644 index 0000000..e37e578 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/__snapshots__/email.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`checkerEmail > basic 1`] = `"DP.checkerEmail()"`; diff --git a/tests/toDataParser/checkerTransfomers/__snapshots__/int.test.ts.snap b/tests/toDataParser/checkerTransfomers/__snapshots__/int.test.ts.snap new file mode 100644 index 0000000..8b88003 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/__snapshots__/int.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`checkerInt > basic 1`] = `"DP.checkerInt()"`; diff --git a/tests/toDataParser/checkerTransfomers/__snapshots__/numberMax.test.ts.snap b/tests/toDataParser/checkerTransfomers/__snapshots__/numberMax.test.ts.snap new file mode 100644 index 0000000..60c27e1 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/__snapshots__/numberMax.test.ts.snap @@ -0,0 +1,5 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`checkerNumberMax > exclusive 1`] = `"DP.checkerNumberMax(10, { exclusive: true })"`; + +exports[`checkerNumberMax > non exclusive 1`] = `"DP.checkerNumberMax(10)"`; diff --git a/tests/toDataParser/checkerTransfomers/__snapshots__/numberMin.test.ts.snap b/tests/toDataParser/checkerTransfomers/__snapshots__/numberMin.test.ts.snap new file mode 100644 index 0000000..85eb900 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/__snapshots__/numberMin.test.ts.snap @@ -0,0 +1,5 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`checkerNumberMin > exclusive 1`] = `"DP.checkerNumberMin(1, { exclusive: true })"`; + +exports[`checkerNumberMin > non exclusive 1`] = `"DP.checkerNumberMin(1)"`; diff --git a/tests/toDataParser/checkerTransfomers/__snapshots__/refine.test.ts.snap b/tests/toDataParser/checkerTransfomers/__snapshots__/refine.test.ts.snap new file mode 100644 index 0000000..bba7671 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/__snapshots__/refine.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`checkerRefine > basic 1`] = `"DP.checkerRefine((value) => value.length > 0)"`; diff --git a/tests/toDataParser/checkerTransfomers/__snapshots__/regex.test.ts.snap b/tests/toDataParser/checkerTransfomers/__snapshots__/regex.test.ts.snap new file mode 100644 index 0000000..17f4b89 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/__snapshots__/regex.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`checkerRegex > basic 1`] = `"DP.checkerRegex(/^[a-z]+$/)"`; diff --git a/tests/toDataParser/checkerTransfomers/__snapshots__/stringMax.test.ts.snap b/tests/toDataParser/checkerTransfomers/__snapshots__/stringMax.test.ts.snap new file mode 100644 index 0000000..c85d6d7 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/__snapshots__/stringMax.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`checkerStringMax > basic 1`] = `"DP.checkerStringMax(10)"`; diff --git a/tests/toDataParser/checkerTransfomers/__snapshots__/stringMin.test.ts.snap b/tests/toDataParser/checkerTransfomers/__snapshots__/stringMin.test.ts.snap new file mode 100644 index 0000000..8c255a2 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/__snapshots__/stringMin.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`checkerStringMin > basic 1`] = `"DP.checkerStringMin(2)"`; diff --git a/tests/toDataParser/checkerTransfomers/__snapshots__/timeMax.test.ts.snap b/tests/toDataParser/checkerTransfomers/__snapshots__/timeMax.test.ts.snap new file mode 100644 index 0000000..56342ad --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/__snapshots__/timeMax.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`checkerTimeMax > basic 1`] = `"DP.checkerTimeMax(DDate.createTime(2000, "millisecond"))"`; diff --git a/tests/toDataParser/checkerTransfomers/__snapshots__/timeMin.test.ts.snap b/tests/toDataParser/checkerTransfomers/__snapshots__/timeMin.test.ts.snap new file mode 100644 index 0000000..467aa91 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/__snapshots__/timeMin.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`checkerTimeMin > basic 1`] = `"DP.checkerTimeMin(DDate.createTime(1000, "millisecond"))"`; diff --git a/tests/toDataParser/checkerTransfomers/__snapshots__/url.test.ts.snap b/tests/toDataParser/checkerTransfomers/__snapshots__/url.test.ts.snap new file mode 100644 index 0000000..6044bf2 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/__snapshots__/url.test.ts.snap @@ -0,0 +1,5 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`checkerUrl > with options 1`] = `"DP.checkerUrl({ hostname: /^[a-z.-]+$/, normalize: true, protocol: /^https?$/ })"`; + +exports[`checkerUrl > without options 1`] = `"DP.checkerUrl()"`; diff --git a/tests/toDataParser/checkerTransfomers/__snapshots__/uuid.test.ts.snap b/tests/toDataParser/checkerTransfomers/__snapshots__/uuid.test.ts.snap new file mode 100644 index 0000000..7df9ebf --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/__snapshots__/uuid.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`checkerUuid > basic 1`] = `"DP.checkerUuid()"`; diff --git a/tests/toDataParser/checkerTransfomers/arrayMax.test.ts b/tests/toDataParser/checkerTransfomers/arrayMax.test.ts new file mode 100644 index 0000000..c5eb3aa --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/arrayMax.test.ts @@ -0,0 +1,15 @@ +import { DataParserToDataParser } from "@scripts/index"; +import { asserts, DP, E, unwrap } from "@duplojs/utils"; +import { printExpression } from "./utils"; + +describe("checkerArrayMax", () => { + it("basic", () => { + const result = DataParserToDataParser.checkerTransformer( + DP.checkerArrayMax(5), + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); +}); diff --git a/tests/toDataParser/checkerTransfomers/arrayMin.test.ts b/tests/toDataParser/checkerTransfomers/arrayMin.test.ts new file mode 100644 index 0000000..7a660ce --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/arrayMin.test.ts @@ -0,0 +1,15 @@ +import { DataParserToDataParser } from "@scripts/index"; +import { asserts, DP, E, unwrap } from "@duplojs/utils"; +import { printExpression } from "./utils"; + +describe("checkerArrayMin", () => { + it("basic", () => { + const result = DataParserToDataParser.checkerTransformer( + DP.checkerArrayMin(1), + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); +}); diff --git a/tests/toDataParser/checkerTransfomers/bigintMax.test.ts b/tests/toDataParser/checkerTransfomers/bigintMax.test.ts new file mode 100644 index 0000000..74588a3 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/bigintMax.test.ts @@ -0,0 +1,15 @@ +import { DataParserToDataParser } from "@scripts/index"; +import { asserts, DP, E, unwrap } from "@duplojs/utils"; +import { printExpression } from "./utils"; + +describe("checkerBigIntMax", () => { + it("basic", () => { + const result = DataParserToDataParser.checkerTransformer( + DP.checkerBigIntMax(10n), + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); +}); diff --git a/tests/toDataParser/checkerTransfomers/bigintMin.test.ts b/tests/toDataParser/checkerTransfomers/bigintMin.test.ts new file mode 100644 index 0000000..5b7b4e7 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/bigintMin.test.ts @@ -0,0 +1,15 @@ +import { DataParserToDataParser } from "@scripts/index"; +import { asserts, DP, E, unwrap } from "@duplojs/utils"; +import { printExpression } from "./utils"; + +describe("checkerBigIntMin", () => { + it("basic", () => { + const result = DataParserToDataParser.checkerTransformer( + DP.checkerBigIntMin(1n), + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); +}); diff --git a/tests/toDataParser/checkerTransfomers/email.test.ts b/tests/toDataParser/checkerTransfomers/email.test.ts new file mode 100644 index 0000000..90b48ca --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/email.test.ts @@ -0,0 +1,15 @@ +import { DataParserToDataParser } from "@scripts/index"; +import { asserts, DP, E, unwrap } from "@duplojs/utils"; +import { printExpression } from "./utils"; + +describe("checkerEmail", () => { + it("basic", () => { + const result = DataParserToDataParser.checkerTransformer( + DP.checkerEmail(), + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); +}); diff --git a/tests/toDataParser/checkerTransfomers/int.test.ts b/tests/toDataParser/checkerTransfomers/int.test.ts new file mode 100644 index 0000000..35b6db5 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/int.test.ts @@ -0,0 +1,15 @@ +import { DataParserToDataParser } from "@scripts/index"; +import { asserts, DP, E, unwrap } from "@duplojs/utils"; +import { printExpression } from "./utils"; + +describe("checkerInt", () => { + it("basic", () => { + const result = DataParserToDataParser.checkerTransformer( + DP.checkerInt(), + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); +}); diff --git a/tests/toDataParser/checkerTransfomers/numberMax.test.ts b/tests/toDataParser/checkerTransfomers/numberMax.test.ts new file mode 100644 index 0000000..3c32d65 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/numberMax.test.ts @@ -0,0 +1,25 @@ +import { DataParserToDataParser } from "@scripts/index"; +import { asserts, DP, E, unwrap } from "@duplojs/utils"; +import { printExpression } from "./utils"; + +describe("checkerNumberMax", () => { + it("exclusive", () => { + const result = DataParserToDataParser.checkerTransformer( + DP.checkerNumberMax(10, { exclusive: true }), + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); + + it("non exclusive", () => { + const result = DataParserToDataParser.checkerTransformer( + DP.checkerNumberMax(10), + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); +}); diff --git a/tests/toDataParser/checkerTransfomers/numberMin.test.ts b/tests/toDataParser/checkerTransfomers/numberMin.test.ts new file mode 100644 index 0000000..8e626c4 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/numberMin.test.ts @@ -0,0 +1,25 @@ +import { DataParserToDataParser } from "@scripts/index"; +import { asserts, DP, E, unwrap } from "@duplojs/utils"; +import { printExpression } from "./utils"; + +describe("checkerNumberMin", () => { + it("exclusive", () => { + const result = DataParserToDataParser.checkerTransformer( + DP.checkerNumberMin(1, { exclusive: true }), + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); + + it("non exclusive", () => { + const result = DataParserToDataParser.checkerTransformer( + DP.checkerNumberMin(1), + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); +}); diff --git a/tests/toDataParser/checkerTransfomers/refine.test.ts b/tests/toDataParser/checkerTransfomers/refine.test.ts new file mode 100644 index 0000000..3b4aedc --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/refine.test.ts @@ -0,0 +1,113 @@ +/* eslint-disable @typescript-eslint/consistent-type-imports */ +import { DataParserToDataParser } from "@scripts/index"; +import { asserts, DP, E, unwrap } from "@duplojs/utils"; +import { afterEach, vi } from "vitest"; +import { printExpression } from "./utils"; + +afterEach(() => { + vi.resetModules(); + vi.doUnmock("typescript"); +}); + +describe("checkerRefine", () => { + it("basic", () => { + const checker = DP.checkerRefine((value: number[]) => value.length > 0); + const result = DataParserToDataParser.checkerTransformer( + checker, + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); + + it("native function error", () => { + const checker = DP.checkerRefine(Array.isArray as never); + const result = DataParserToDataParser.checkerTransformer( + checker, + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + expect(result).toEqual(E.left("buildCheckerError", checker)); + }); + + it("invalid source statement error", () => { + const checker = DP.checkerRefine(() => true); + (checker.definition.theFunction as { toString(): string }).toString = () => ";"; + + const result = DataParserToDataParser.checkerTransformer( + checker, + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + expect(result).toEqual(E.left("buildCheckerError", checker)); + }); + + it("non function expression error", () => { + const checker = DP.checkerRefine(() => true); + (checker.definition.theFunction as { toString(): string }).toString = () => "1 + 1"; + + const result = DataParserToDataParser.checkerTransformer( + checker, + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + expect(result).toEqual(E.left("buildCheckerError", checker)); + }); + + it("error when sourceFile has no statement", async() => { + vi.doMock("typescript", async() => { + const actual = await vi.importActual("typescript"); + return { + ...actual, + createSourceFile() { + return { statements: [] }; + }, + }; + }); + + const { checkerRefineTransformer } = await import("@scripts/toDataParser/checkerTransformer/defaults/refine"); + const checker = DP.checkerRefine(() => true); + const result = checkerRefineTransformer(checker, { + success(value) { + return E.right("buildSuccess", value); + }, + buildError() { + return E.left("buildCheckerError", checker); + }, + getDefinition() { + return []; + }, + }); + + expect(result).toEqual(E.left("buildCheckerError", checker)); + }); + + it("error when expression is not parenthesized", async() => { + vi.doMock("typescript", async() => { + const actual = await vi.importActual("typescript"); + return { + ...actual, + isParenthesizedExpression() { + return false; + }, + }; + }); + + const { checkerRefineTransformer } = await import("@scripts/toDataParser/checkerTransformer/defaults/refine"); + const checker = DP.checkerRefine(() => true); + const result = checkerRefineTransformer(checker, { + success(value) { + return E.right("buildSuccess", value); + }, + buildError() { + return E.left("buildCheckerError", checker); + }, + getDefinition() { + return []; + }, + }); + + expect(result).toEqual(E.left("buildCheckerError", checker)); + }); +}); diff --git a/tests/toDataParser/checkerTransfomers/regex.test.ts b/tests/toDataParser/checkerTransfomers/regex.test.ts new file mode 100644 index 0000000..f038a6a --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/regex.test.ts @@ -0,0 +1,15 @@ +import { DataParserToDataParser } from "@scripts/index"; +import { asserts, DP, E, unwrap } from "@duplojs/utils"; +import { printExpression } from "./utils"; + +describe("checkerRegex", () => { + it("basic", () => { + const result = DataParserToDataParser.checkerTransformer( + DP.checkerRegex(/^[a-z]+$/), + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); +}); diff --git a/tests/toDataParser/checkerTransfomers/stringMax.test.ts b/tests/toDataParser/checkerTransfomers/stringMax.test.ts new file mode 100644 index 0000000..4577a2b --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/stringMax.test.ts @@ -0,0 +1,15 @@ +import { DataParserToDataParser } from "@scripts/index"; +import { asserts, DP, E, unwrap } from "@duplojs/utils"; +import { printExpression } from "./utils"; + +describe("checkerStringMax", () => { + it("basic", () => { + const result = DataParserToDataParser.checkerTransformer( + DP.checkerStringMax(10), + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); +}); diff --git a/tests/toDataParser/checkerTransfomers/stringMin.test.ts b/tests/toDataParser/checkerTransfomers/stringMin.test.ts new file mode 100644 index 0000000..984f844 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/stringMin.test.ts @@ -0,0 +1,15 @@ +import { DataParserToDataParser } from "@scripts/index"; +import { asserts, DP, E, unwrap } from "@duplojs/utils"; +import { printExpression } from "./utils"; + +describe("checkerStringMin", () => { + it("basic", () => { + const result = DataParserToDataParser.checkerTransformer( + DP.checkerStringMin(2), + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); +}); diff --git a/tests/toDataParser/checkerTransfomers/timeMax.test.ts b/tests/toDataParser/checkerTransfomers/timeMax.test.ts new file mode 100644 index 0000000..4fa5ac9 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/timeMax.test.ts @@ -0,0 +1,15 @@ +import { DataParserToDataParser } from "@scripts/index"; +import { asserts, DDate, DP, E, unwrap } from "@duplojs/utils"; +import { printExpression } from "./utils"; + +describe("checkerTimeMax", () => { + it("basic", () => { + const result = DataParserToDataParser.checkerTransformer( + DP.checkerTimeMax(DDate.createTime(2000, "millisecond")), + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); +}); diff --git a/tests/toDataParser/checkerTransfomers/timeMin.test.ts b/tests/toDataParser/checkerTransfomers/timeMin.test.ts new file mode 100644 index 0000000..8d62221 --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/timeMin.test.ts @@ -0,0 +1,15 @@ +import { DataParserToDataParser } from "@scripts/index"; +import { asserts, DDate, DP, E, unwrap } from "@duplojs/utils"; +import { printExpression } from "./utils"; + +describe("checkerTimeMin", () => { + it("basic", () => { + const result = DataParserToDataParser.checkerTransformer( + DP.checkerTimeMin(DDate.createTime(1000, "millisecond")), + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); +}); diff --git a/tests/toDataParser/checkerTransfomers/url.test.ts b/tests/toDataParser/checkerTransfomers/url.test.ts new file mode 100644 index 0000000..89a394a --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/url.test.ts @@ -0,0 +1,29 @@ +import { DataParserToDataParser } from "@scripts/index"; +import { asserts, DP, E, unwrap } from "@duplojs/utils"; +import { printExpression } from "./utils"; + +describe("checkerUrl", () => { + it("with options", () => { + const result = DataParserToDataParser.checkerTransformer( + DP.checkerUrl({ + hostname: /^[a-z.-]+$/, + normalize: true, + protocol: /^https?$/, + }), + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); + + it("without options", () => { + const result = DataParserToDataParser.checkerTransformer( + DP.checkerUrl(), + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); +}); diff --git a/tests/toDataParser/checkerTransfomers/utils.ts b/tests/toDataParser/checkerTransfomers/utils.ts new file mode 100644 index 0000000..5209fbb --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/utils.ts @@ -0,0 +1,7 @@ +import { createPrinter, createSourceFile, EmitHint, ScriptKind, ScriptTarget, type CallExpression } from "typescript"; + +export function printExpression(expression: CallExpression) { + const printer = createPrinter(); + const sourceFile = createSourceFile("test.ts", "", ScriptTarget.Latest, false, ScriptKind.TS); + return printer.printNode(EmitHint.Unspecified, expression, sourceFile); +} diff --git a/tests/toDataParser/checkerTransfomers/uuid.test.ts b/tests/toDataParser/checkerTransfomers/uuid.test.ts new file mode 100644 index 0000000..a93ab5d --- /dev/null +++ b/tests/toDataParser/checkerTransfomers/uuid.test.ts @@ -0,0 +1,15 @@ +import { DataParserToDataParser } from "@scripts/index"; +import { asserts, DP, E, unwrap } from "@duplojs/utils"; +import { printExpression } from "./utils"; + +describe("checkerUuid", () => { + it("basic", () => { + const result = DataParserToDataParser.checkerTransformer( + DP.checkerUuid(), + { transformers: DataParserToDataParser.defaultCheckerTransformers }, + ); + + asserts(result, E.isRight); + expect(printExpression(unwrap(result))).toMatchSnapshot(); + }); +}); From 0820db91ab02303fbbaf30ac73931ca9e6b6d80c Mon Sep 17 00:00:00 2001 From: ZeRiix Date: Tue, 19 May 2026 16:46:59 +0200 Subject: [PATCH 02/16] feat(06): add data parser transformer --- .../dataParserTransformer/create.ts | 76 +++++++ .../dataParserTransformer/defaults/array.ts | 43 ++++ .../dataParserTransformer/defaults/bigint.ts | 42 ++++ .../dataParserTransformer/defaults/boolean.ts | 42 ++++ .../dataParserTransformer/defaults/date.ts | 42 ++++ .../dataParserTransformer/defaults/empty.ts | 42 ++++ .../dataParserTransformer/defaults/file.ts | 95 ++++++++ .../dataParserTransformer/defaults/index.ts | 74 ++++++ .../dataParserTransformer/defaults/lazy.ts | 50 +++++ .../dataParserTransformer/defaults/literal.ts | 68 ++++++ .../dataParserTransformer/defaults/nil.ts | 42 ++++ .../defaults/nullable.ts | 43 ++++ .../dataParserTransformer/defaults/number.ts | 42 ++++ .../dataParserTransformer/defaults/object.ts | 66 ++++++ .../defaults/optional.ts | 43 ++++ .../dataParserTransformer/defaults/pipe.ts | 50 +++++ .../dataParserTransformer/defaults/record.ts | 50 +++++ .../dataParserTransformer/defaults/recover.ts | 12 + .../dataParserTransformer/defaults/string.ts | 33 +++ .../defaults/templateLiteral.ts | 88 ++++++++ .../dataParserTransformer/defaults/time.ts | 47 ++++ .../defaults/transform.ts | 77 +++++++ .../dataParserTransformer/defaults/tuple.ts | 74 ++++++ .../dataParserTransformer/defaults/union.ts | 55 +++++ .../dataParserTransformer/defaults/unknown.ts | 33 +++ .../dataParserTransformer/hook.ts | 22 ++ .../dataParserTransformer/importClause.ts | 19 ++ .../dataParserTransformer/index.ts | 4 + .../dataParserTransformer/transformer.ts | 210 ++++++++++++++++++ .../__snapshots__/array.test.ts.snap | 7 + .../__snapshots__/bigint.test.ts.snap | 13 ++ .../__snapshots__/boolean.test.ts.snap | 13 ++ .../__snapshots__/date.test.ts.snap | 13 ++ .../__snapshots__/empty.test.ts.snap | 13 ++ .../__snapshots__/file.test.ts.snap | 27 +++ .../__snapshots__/lazy.test.ts.snap | 7 + .../__snapshots__/literal.test.ts.snap | 7 + .../__snapshots__/nil.test.ts.snap | 13 ++ .../__snapshots__/nullable.test.ts.snap | 7 + .../__snapshots__/number.test.ts.snap | 13 ++ .../__snapshots__/object.test.ts.snap | 7 + .../__snapshots__/optional.test.ts.snap | 7 + .../__snapshots__/pipe.test.ts.snap | 7 + .../__snapshots__/record.test.ts.snap | 7 + .../__snapshots__/recover.test.ts.snap | 7 + .../__snapshots__/string.test.ts.snap | 7 + .../templateLiteral.test.ts.snap | 7 + .../__snapshots__/time.test.ts.snap | 15 ++ .../__snapshots__/transform.test.ts.snap | 7 + .../__snapshots__/tuple.test.ts.snap | 13 ++ .../__snapshots__/union.test.ts.snap | 7 + .../__snapshots__/unknown.test.ts.snap | 7 + .../dataParserTransformer/array.test.ts | 65 ++++++ .../dataParserTransformer/bigint.test.ts | 60 +++++ .../dataParserTransformer/boolean.test.ts | 60 +++++ .../dataParserTransformer/date.test.ts | 60 +++++ .../dataParserTransformer/empty.test.ts | 60 +++++ .../dataParserTransformer/file.test.ts | 81 +++++++ .../dataParserTransformer/lazy.test.ts | 65 ++++++ .../dataParserTransformer/literal.test.ts | 46 ++++ .../dataParserTransformer/nil.test.ts | 58 +++++ .../dataParserTransformer/nullable.test.ts | 65 ++++++ .../dataParserTransformer/number.test.ts | 60 +++++ .../dataParserTransformer/object.test.ts | 74 ++++++ .../dataParserTransformer/optional.test.ts | 65 ++++++ .../dataParserTransformer/pipe.test.ts | 84 +++++++ .../dataParserTransformer/record.test.ts | 88 ++++++++ .../dataParserTransformer/recover.test.ts | 22 ++ .../dataParserTransformer/string.test.ts | 46 ++++ .../templateLiteral.test.ts | 82 +++++++ .../dataParserTransformer/time.test.ts | 62 ++++++ .../dataParserTransformer/transform.test.ts | 171 ++++++++++++++ .../dataParserTransformer/tuple.test.ts | 99 +++++++++ .../dataParserTransformer/union.test.ts | 65 ++++++ .../dataParserTransformer/unknown.test.ts | 46 ++++ 75 files changed, 3399 insertions(+) create mode 100644 scripts/toDataParser/dataParserTransformer/create.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/array.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/bigint.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/boolean.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/date.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/empty.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/file.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/index.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/lazy.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/literal.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/nil.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/nullable.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/number.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/object.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/optional.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/pipe.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/record.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/recover.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/string.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/templateLiteral.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/time.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/transform.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/tuple.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/union.ts create mode 100644 scripts/toDataParser/dataParserTransformer/defaults/unknown.ts create mode 100644 scripts/toDataParser/dataParserTransformer/hook.ts create mode 100644 scripts/toDataParser/dataParserTransformer/importClause.ts create mode 100644 scripts/toDataParser/dataParserTransformer/index.ts create mode 100644 scripts/toDataParser/dataParserTransformer/transformer.ts create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/array.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/bigint.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/boolean.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/date.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/empty.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/file.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/lazy.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/literal.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/nil.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/nullable.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/number.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/object.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/optional.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/pipe.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/record.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/recover.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/string.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/templateLiteral.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/time.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/transform.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/tuple.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/union.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/__snapshots__/unknown.test.ts.snap create mode 100644 tests/toDataParser/dataParserTransformer/array.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/bigint.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/boolean.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/date.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/empty.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/file.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/lazy.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/literal.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/nil.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/nullable.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/number.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/object.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/optional.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/pipe.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/record.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/recover.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/string.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/templateLiteral.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/time.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/transform.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/tuple.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/union.test.ts create mode 100644 tests/toDataParser/dataParserTransformer/unknown.test.ts diff --git a/scripts/toDataParser/dataParserTransformer/create.ts b/scripts/toDataParser/dataParserTransformer/create.ts new file mode 100644 index 0000000..17ad9cd --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/create.ts @@ -0,0 +1,76 @@ +import type { CallExpression, Identifier, ObjectLiteralExpression, PropertyAssignment } from "typescript"; +import { type DP, E } from "@duplojs/utils"; +import type { CheckerTransformerBuildErrorEither, CheckerTransformerCheckerNotSupportedEither } from "../checkerTransformer"; + +export type TransformerSuccessEither = E.Right<"buildSuccess", CallExpression | Identifier>; + +export type DataParserNotSupportedEither = E.Left<"dataParserNotSupport", DP.DataParser>; + +export type DataParserErrorEither = E.Left<"buildDataParserError", DP.DataParser>; + +export type DataParserGetDefinitionErrorEither = E.Left< + "buildDataParserGetDefinitionError", + { + dataParser: DP.DataParser; + error: CheckerTransformerCheckerNotSupportedEither | CheckerTransformerBuildErrorEither; + } +>; + +export interface MapContextValue { + readonly constName: Identifier; + readonly expression: CallExpression | Identifier; +} + +export type MapContext = Map; + +export type MapImportClause = Map; + +export type MaybeTransformerEither = + | TransformerSuccessEither + | DataParserNotSupportedEither + | DataParserErrorEither + | DataParserGetDefinitionErrorEither; + +export interface TransformerParams { + readonly dependencyIdentifier: Identifier; + readonly context: MapContext; + readonly importClause: MapImportClause; + + transformer( + dataParser: DP.DataParser, + ): MaybeTransformerEither; + + success( + result: CallExpression, + ): TransformerSuccessEither; + + buildError(): DataParserErrorEither; + addImportClause(path: string, clause: string): void; + getDefinition( + customProperties?: readonly PropertyAssignment[] + ): readonly [ObjectLiteralExpression] | readonly [] | DataParserGetDefinitionErrorEither; +} + +export type TransformerBuildFunction< + GenericDataParser extends DP.DataParsers = DP.DataParsers, +> = ( + dataParser: GenericDataParser, + params: TransformerParams, +) => MaybeTransformerEither; + +export function createTransformer< + GenericDataParser extends DP.DataParsers, +>( + support: (dataParser: DP.DataParsers) => dataParser is GenericDataParser, + builder: TransformerBuildFunction, +) { + return ( + dataParser: DP.DataParsers, + params: TransformerParams, + ): MaybeTransformerEither => support(dataParser) + ? builder( + dataParser, + params, + ) + : E.left("dataParserNotSupport", dataParser); +} diff --git a/scripts/toDataParser/dataParserTransformer/defaults/array.ts b/scripts/toDataParser/dataParserTransformer/defaults/array.ts new file mode 100644 index 0000000..0fb3aa2 --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/array.ts @@ -0,0 +1,43 @@ +import { DP, E, pipe, unwrap } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { factory } from "typescript"; + +export const arrayTransformer = createTransformer( + DP.arrayKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + transformer, + }, + ) => { + const element = transformer(dataParser.definition.element); + + if (E.isLeft(element)) { + return element; + } + + const definition = getDefinition(); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("array"), + ), + undefined, + [ + unwrap(element), + ...definition, + ], + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/bigint.ts b/scripts/toDataParser/dataParserTransformer/defaults/bigint.ts new file mode 100644 index 0000000..ddccd28 --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/bigint.ts @@ -0,0 +1,42 @@ +import { DP, E, pipe } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { factory } from "typescript"; + +export const bigIntTransformer = createTransformer( + DP.bigIntKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + }, + ) => { + const definition = getDefinition( + dataParser.definition.coerce + ? [ + factory.createPropertyAssignment( + factory.createIdentifier("coerce"), + factory.createTrue(), + ), + ] + : undefined, + ); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("bigint"), + ), + undefined, + definition, + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/boolean.ts b/scripts/toDataParser/dataParserTransformer/defaults/boolean.ts new file mode 100644 index 0000000..cf38b21 --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/boolean.ts @@ -0,0 +1,42 @@ +import { DP, E, pipe } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { factory } from "typescript"; + +export const booleanTransformer = createTransformer( + DP.booleanKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + }, + ) => { + const definition = getDefinition( + dataParser.definition.coerce + ? [ + factory.createPropertyAssignment( + factory.createIdentifier("coerce"), + factory.createTrue(), + ), + ] + : undefined, + ); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("boolean"), + ), + undefined, + definition, + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/date.ts b/scripts/toDataParser/dataParserTransformer/defaults/date.ts new file mode 100644 index 0000000..cc3d154 --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/date.ts @@ -0,0 +1,42 @@ +import { DP, E, pipe } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { factory } from "typescript"; + +export const dateTransformer = createTransformer( + DP.dateKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + }, + ) => { + const definition = getDefinition( + dataParser.definition.coerce + ? [ + factory.createPropertyAssignment( + factory.createIdentifier("coerce"), + factory.createTrue(), + ), + ] + : undefined, + ); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("date"), + ), + undefined, + definition, + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/empty.ts b/scripts/toDataParser/dataParserTransformer/defaults/empty.ts new file mode 100644 index 0000000..357d8ef --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/empty.ts @@ -0,0 +1,42 @@ +import { DP, E, pipe } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { factory } from "typescript"; + +export const emptyTransformer = createTransformer( + DP.emptyKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + }, + ) => { + const definition = getDefinition( + dataParser.definition.coerce + ? [ + factory.createPropertyAssignment( + factory.createIdentifier("coerce"), + factory.createTrue(), + ), + ] + : undefined, + ); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("empty"), + ), + undefined, + definition, + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/file.ts b/scripts/toDataParser/dataParserTransformer/defaults/file.ts new file mode 100644 index 0000000..a3f7ded --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/file.ts @@ -0,0 +1,95 @@ +import { E, justExec, pipe } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { factory, type PropertyAssignment } from "typescript"; +import { SDP } from "@duplojs/server-utils"; + +export const fileTransformer = createTransformer( + SDP.fileKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + addImportClause, + }, + ) => { + const definition = getDefinition(); + + if (E.isLeft(definition)) { + return definition; + } + + const dataParserFileParams: PropertyAssignment[] = []; + + if (dataParser.definition.coerce) { + dataParserFileParams.push( + factory.createPropertyAssignment( + factory.createIdentifier("coerce"), + factory.createTrue(), + ), + ); + } + if (dataParser.definition.checkExist) { + dataParserFileParams.push( + factory.createPropertyAssignment( + factory.createIdentifier("checkExist"), + factory.createTrue(), + ), + ); + } + if (dataParser.definition.maxSize) { + dataParserFileParams.push( + factory.createPropertyAssignment( + factory.createIdentifier("maxSize"), + factory.createNumericLiteral(dataParser.definition.maxSize), + ), + ); + } + if (dataParser.definition.minSize) { + dataParserFileParams.push( + factory.createPropertyAssignment( + factory.createIdentifier("minSize"), + factory.createNumericLiteral(dataParser.definition.minSize), + ), + ); + } + if (dataParser.definition.mimeType) { + dataParserFileParams.push( + factory.createPropertyAssignment( + factory.createIdentifier("mimeType"), + factory.createRegularExpressionLiteral(dataParser.definition.mimeType.toString()), + ), + ); + } + + const namespace = dependencyIdentifier.text === "DP" + ? justExec( + () => { + addImportClause("@duplojs/server-utils/dataParser", "SDP"); + return "SDP"; + }, + ) + : justExec( + () => { + addImportClause("@duplojs/server-utils/dataParserExtended", "SDPE"); + return "SDPE"; + }, + ); + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier(namespace), + factory.createIdentifier("file"), + ), + undefined, + [ + factory.createObjectLiteralExpression(dataParserFileParams), + ...definition, + ], + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/index.ts b/scripts/toDataParser/dataParserTransformer/defaults/index.ts new file mode 100644 index 0000000..2b30fdc --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/index.ts @@ -0,0 +1,74 @@ +export * from "./array"; +export * from "./bigint"; +export * from "./boolean"; +export * from "./date"; +export * from "./empty"; +export * from "./file"; +export * from "./lazy"; +export * from "./literal"; +export * from "./nil"; +export * from "./nullable"; +export * from "./number"; +export * from "./object"; +export * from "./optional"; +export * from "./pipe"; +export * from "./record"; +export * from "./recover"; +export * from "./string"; +export * from "./templateLiteral"; +export * from "./time"; +export * from "./transform"; +export * from "./tuple"; +export * from "./union"; +export * from "./unknown"; + +import type { createTransformer } from "../create"; +import { arrayTransformer } from "./array"; +import { bigIntTransformer } from "./bigint"; +import { booleanTransformer } from "./boolean"; +import { dateTransformer } from "./date"; +import { emptyTransformer } from "./empty"; +import { fileTransformer } from "./file"; +import { lazyTransformer } from "./lazy"; +import { literalTransformer } from "./literal"; +import { nilTransformer } from "./nil"; +import { nullableTransformer } from "./nullable"; +import { numberTransformer } from "./number"; +import { objectTransformer } from "./object"; +import { optionalTransformer } from "./optional"; +import { pipeTransformer } from "./pipe"; +import { recordTransformer } from "./record"; +import { recoverTransformer } from "./recover"; +import { stringTransformer } from "./string"; +import { templateLiteralTransformer } from "./templateLiteral"; +import { timeTransformer } from "./time"; +import { transformTransformer } from "./transform"; +import { tupleTransformer } from "./tuple"; +import { unionTransformer } from "./union"; +import { unknownTransformer } from "./unknown"; + +export const defaultTransformers = [ + arrayTransformer, + bigIntTransformer, + booleanTransformer, + dateTransformer, + emptyTransformer, + fileTransformer, + lazyTransformer, + literalTransformer, + nilTransformer, + nullableTransformer, + numberTransformer, + objectTransformer, + optionalTransformer, + pipeTransformer, + recordTransformer, + recoverTransformer, + stringTransformer, + templateLiteralTransformer, + timeTransformer, + transformTransformer, + tupleTransformer, + unionTransformer, + unknownTransformer, +] as const satisfies readonly ReturnType[]; diff --git a/scripts/toDataParser/dataParserTransformer/defaults/lazy.ts b/scripts/toDataParser/dataParserTransformer/defaults/lazy.ts new file mode 100644 index 0000000..2f85b27 --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/lazy.ts @@ -0,0 +1,50 @@ +import { DP, E, pipe, unwrap } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { factory, SyntaxKind } from "typescript"; + +export const lazyTransformer = createTransformer( + DP.lazyKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + transformer, + }, + ) => { + const getter = transformer(dataParser.definition.getter.value); + + if (E.isLeft(getter)) { + return getter; + } + + const definition = getDefinition(); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("lazy"), + ), + undefined, + [ + factory.createArrowFunction( + undefined, + undefined, + [], + undefined, + factory.createToken(SyntaxKind.EqualsGreaterThanToken), + unwrap(getter), + ), + ...definition, + ], + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/literal.ts b/scripts/toDataParser/dataParserTransformer/defaults/literal.ts new file mode 100644 index 0000000..694a58f --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/literal.ts @@ -0,0 +1,68 @@ +import { A, DP, E, isType, P, pipe, pipeCall } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { factory } from "typescript"; + +export const literalTransformer = createTransformer( + DP.literalKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + }, + ) => { + const definition = getDefinition(); + + if (E.isLeft(definition)) { + return definition; + } + + const values = A.map( + dataParser.definition.value, + (element) => P.match(element) + .when( + isType("string"), + factory.createStringLiteral, + ) + .when( + isType("bigint"), + (value) => factory.createBigIntLiteral(`${value.toString()}n`), + ) + .when( + isType("number"), + pipeCall(factory.createNumericLiteral), + ) + .when( + isType("boolean"), + (value) => value + ? factory.createTrue() + : factory.createFalse(), + ) + .when( + isType("null"), + () => factory.createNull(), + ) + .when( + isType("undefined"), + () => factory.createIdentifier("undefined"), + ) + .exhaustive(), + ); + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("literal"), + ), + undefined, + [ + factory.createArrayLiteralExpression(values), + ...definition, + ], + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/nil.ts b/scripts/toDataParser/dataParserTransformer/defaults/nil.ts new file mode 100644 index 0000000..6a256b8 --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/nil.ts @@ -0,0 +1,42 @@ +import { DP, E, pipe } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { factory } from "typescript"; + +export const nilTransformer = createTransformer( + DP.nilKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + }, + ) => { + const definition = getDefinition( + dataParser.definition.coerce + ? [ + factory.createPropertyAssignment( + factory.createIdentifier("coerce"), + factory.createTrue(), + ), + ] + : undefined, + ); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("nil"), + ), + undefined, + definition, + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/nullable.ts b/scripts/toDataParser/dataParserTransformer/defaults/nullable.ts new file mode 100644 index 0000000..f803578 --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/nullable.ts @@ -0,0 +1,43 @@ +import { DP, E, pipe, unwrap } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { factory } from "typescript"; + +export const nullableTransformer = createTransformer( + DP.nullableKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + transformer, + }, + ) => { + const inner = transformer(dataParser.definition.inner); + + if (E.isLeft(inner)) { + return inner; + } + + const definition = getDefinition(); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("nullable"), + ), + undefined, + [ + unwrap(inner), + ...definition, + ], + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/number.ts b/scripts/toDataParser/dataParserTransformer/defaults/number.ts new file mode 100644 index 0000000..6a9aa1d --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/number.ts @@ -0,0 +1,42 @@ +import { DP, E, pipe } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { factory } from "typescript"; + +export const numberTransformer = createTransformer( + DP.numberKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + }, + ) => { + const definition = getDefinition( + dataParser.definition.coerce + ? [ + factory.createPropertyAssignment( + factory.createIdentifier("coerce"), + factory.createTrue(), + ), + ] + : undefined, + ); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("number"), + ), + undefined, + definition, + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/object.ts b/scripts/toDataParser/dataParserTransformer/defaults/object.ts new file mode 100644 index 0000000..67513f8 --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/object.ts @@ -0,0 +1,66 @@ +import { A, DP, E, O, pipe, when } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { factory, type PropertyAssignment } from "typescript"; + +export const objectTransformer = createTransformer( + DP.objectKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + transformer, + }, + ) => { + const shape = pipe( + dataParser.definition.shape, + O.entries, + A.reduce( + A.reduceFrom([]), + ({ element: [identifier, parser], lastValue, nextPush, exit }) => pipe( + parser, + transformer, + when( + E.isLeft, + exit, + ), + E.whenIsRight( + (result) => nextPush( + lastValue, + factory.createPropertyAssignment( + factory.createIdentifier(identifier), + result, + ), + ), + ), + ), + ), + ); + + if (E.isLeft(shape)) { + return shape; + } + + const definition = getDefinition(); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("object"), + ), + undefined, + [ + factory.createObjectLiteralExpression(shape), + ...definition, + ], + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/optional.ts b/scripts/toDataParser/dataParserTransformer/defaults/optional.ts new file mode 100644 index 0000000..1798e47 --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/optional.ts @@ -0,0 +1,43 @@ +import { DP, E, pipe, unwrap } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { factory } from "typescript"; + +export const optionalTransformer = createTransformer( + DP.optionalKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + transformer, + }, + ) => { + const inner = transformer(dataParser.definition.inner); + + if (E.isLeft(inner)) { + return inner; + } + + const definition = getDefinition(); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("optional"), + ), + undefined, + [ + unwrap(inner), + ...definition, + ], + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/pipe.ts b/scripts/toDataParser/dataParserTransformer/defaults/pipe.ts new file mode 100644 index 0000000..0ca443f --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/pipe.ts @@ -0,0 +1,50 @@ +import { DP, E, pipe, unwrap } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { factory } from "typescript"; + +export const pipeTransformer = createTransformer( + DP.pipeKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + transformer, + }, + ) => { + const input = transformer(dataParser.definition.input); + + if (E.isLeft(input)) { + return input; + } + + const output = transformer(dataParser.definition.output); + + if (E.isLeft(output)) { + return output; + } + + const definition = getDefinition(); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("pipe"), + ), + undefined, + [ + unwrap(input), + unwrap(output), + ...definition, + ], + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/record.ts b/scripts/toDataParser/dataParserTransformer/defaults/record.ts new file mode 100644 index 0000000..31929c1 --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/record.ts @@ -0,0 +1,50 @@ +import { DP, E, pipe, unwrap } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { factory } from "typescript"; + +export const recordTransformer = createTransformer( + DP.recordKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + transformer, + }, + ) => { + const key = transformer(dataParser.definition.key); + + if (E.isLeft(key)) { + return key; + } + + const value = transformer(dataParser.definition.value); + + if (E.isLeft(value)) { + return value; + } + + const definition = getDefinition(); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("record"), + ), + undefined, + [ + unwrap(key), + unwrap(value), + ...definition, + ], + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/recover.ts b/scripts/toDataParser/dataParserTransformer/defaults/recover.ts new file mode 100644 index 0000000..b787a27 --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/recover.ts @@ -0,0 +1,12 @@ +import { DP } from "@duplojs/utils"; +import { createTransformer } from "../create"; + +export const recoverTransformer = createTransformer( + DP.recoverKind.has, + ( + dataParser, + { + transformer, + }, + ) => transformer(dataParser.definition.inner), +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/string.ts b/scripts/toDataParser/dataParserTransformer/defaults/string.ts new file mode 100644 index 0000000..9b17658 --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/string.ts @@ -0,0 +1,33 @@ +import { DP, E, pipe } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { factory } from "typescript"; + +export const stringTransformer = createTransformer( + DP.stringKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + }, + ) => { + const definition = getDefinition(); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("string"), + ), + undefined, + definition, + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/templateLiteral.ts b/scripts/toDataParser/dataParserTransformer/defaults/templateLiteral.ts new file mode 100644 index 0000000..c4a586f --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/templateLiteral.ts @@ -0,0 +1,88 @@ +import { A, DP, E, isType, P, pipe, pipeCall, unwrap } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { type Expression, factory } from "typescript"; + +export const templateLiteralTransformer = createTransformer( + DP.templateLiteralKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + transformer, + }, + ) => { + const parts = A.reduce( + dataParser.definition.template, + A.reduceFrom([]), + ({ element, lastValue, nextPush, exit }) => { + if (DP.dataParserKind.has(element)) { + const transformResult = transformer(element); + + if (E.isLeft(transformResult)) { + return exit(transformResult); + } + + return nextPush(lastValue, unwrap(transformResult)); + } + + const result = P.match(element) + .when( + isType("bigint"), + (value) => factory.createBigIntLiteral(`${value.toString()}n`), + ) + .when( + isType("boolean"), + (value) => value + ? factory.createTrue() + : factory.createFalse(), + ) + .when( + isType("string"), + pipeCall(factory.createStringLiteral), + ) + .when( + isType("number"), + pipeCall(factory.createNumericLiteral), + ) + .when( + isType("null"), + () => factory.createNull(), + ) + .when( + isType("undefined"), + () => factory.createIdentifier("undefined"), + ) + .exhaustive(); + + return nextPush(lastValue, result); + }, + ); + + if (E.isLeft(parts)) { + return parts; + } + + const definition = getDefinition(); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("templateLiteral"), + ), + undefined, + [ + factory.createArrayLiteralExpression(parts), + ...definition, + ], + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/time.ts b/scripts/toDataParser/dataParserTransformer/defaults/time.ts new file mode 100644 index 0000000..957dc1e --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/time.ts @@ -0,0 +1,47 @@ +import { A, DP, E, pipe } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { factory } from "typescript"; + +export const timeTransformer = createTransformer( + DP.timeKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + addImportClause, + }, + ) => { + const definition = getDefinition( + dataParser.definition.coerce + ? [ + factory.createPropertyAssignment( + factory.createIdentifier("coerce"), + factory.createTrue(), + ), + ] + : undefined, + ); + + if (E.isLeft(definition)) { + return definition; + } + + if (A.minElements(dataParser.definition.checkers, 1)) { + addImportClause("@duplojs/utils/date", "DDate"); + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("time"), + ), + undefined, + definition, + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/transform.ts b/scripts/toDataParser/dataParserTransformer/defaults/transform.ts new file mode 100644 index 0000000..0397686 --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/transform.ts @@ -0,0 +1,77 @@ +import { DP, E, pipe, unwrap } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { createSourceFile, factory, isArrowFunction, isExpressionStatement, isFunctionExpression, isParenthesizedExpression, ScriptTarget } from "typescript"; + +export const transformTransformer = createTransformer( + DP.transformKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + transformer, + buildError, + }, + ) => { + const inner = transformer(dataParser.definition.inner); + + if (E.isLeft(inner)) { + return inner; + } + + const theFunction = dataParser.definition.theFunction.toString(); + + if (theFunction.includes("[native code]")) { + return buildError(); + } + + const sourceFile = createSourceFile( + "refine-function.ts", + `(${theFunction})`, + ScriptTarget.Latest, + false, + ); + + const statement = sourceFile.statements[0]; + if (!statement || !isExpressionStatement(statement)) { + return buildError(); + } + + const functionExpression = isParenthesizedExpression(statement.expression) + ? statement.expression.expression + : undefined; + + if ( + !functionExpression + || ( + !isFunctionExpression(functionExpression) + && !isArrowFunction(functionExpression) + ) + ) { + return buildError(); + } + + const definition = getDefinition(); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("transform"), + ), + undefined, + [ + unwrap(inner), + functionExpression, + ...definition, + ], + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/tuple.ts b/scripts/toDataParser/dataParserTransformer/defaults/tuple.ts new file mode 100644 index 0000000..5076d7c --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/tuple.ts @@ -0,0 +1,74 @@ +import { A, DP, E, pipe, unwrap } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { type Expression, factory } from "typescript"; + +export const tupleTransformer = createTransformer( + DP.tupleKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + transformer, + }, + ) => { + const shape = A.reduce( + dataParser.definition.shape, + A.reduceFrom([]), + ({ element, lastValue, nextPush, exit }) => { + const result = transformer(element); + + if (E.isLeft(result)) { + return exit(result); + } + + return nextPush(lastValue, unwrap(result)); + }, + ); + + if (E.isLeft(shape)) { + return shape; + } + + const rest = dataParser.definition.rest + ? pipe( + dataParser.definition.rest, + transformer, + E.whenIsRight( + (expression) => [ + factory.createPropertyAssignment( + factory.createIdentifier("rest"), + expression, + ), + ], + ), + ) + : undefined; + + if (E.isLeft(rest)) { + return rest; + } + + const definition = getDefinition(rest); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("tuple"), + ), + undefined, + [ + factory.createArrayLiteralExpression(shape), + ...definition, + ], + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/union.ts b/scripts/toDataParser/dataParserTransformer/defaults/union.ts new file mode 100644 index 0000000..fa01b1d --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/union.ts @@ -0,0 +1,55 @@ +import { A, DP, E, pipe, unwrap } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { type Expression, factory } from "typescript"; + +export const unionTransformer = createTransformer( + DP.unionKind.has, + ( + dataParser, + { + dependencyIdentifier, + getDefinition, + success, + transformer, + }, + ) => { + const options = A.reduce( + dataParser.definition.options, + A.reduceFrom([]), + ({ element, lastValue, nextPush, exit }) => { + const result = transformer(element); + + if (E.isLeft(result)) { + return exit(result); + } + + return nextPush(lastValue, unwrap(result)); + }, + ); + + if (E.isLeft(options)) { + return options; + } + + const definition = getDefinition(); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("union"), + ), + undefined, + [ + factory.createArrayLiteralExpression(options), + ...definition, + ], + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/unknown.ts b/scripts/toDataParser/dataParserTransformer/defaults/unknown.ts new file mode 100644 index 0000000..ec89969 --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/defaults/unknown.ts @@ -0,0 +1,33 @@ +import { DP, E, pipe } from "@duplojs/utils"; +import { createTransformer } from "../create"; +import { factory } from "typescript"; + +export const unknownTransformer = createTransformer( + DP.unknownKind.has, + ( + dataParser, + { + success, + dependencyIdentifier, + getDefinition, + }, + ) => { + const definition = getDefinition(); + + if (E.isLeft(definition)) { + return definition; + } + + return pipe( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("unknown"), + ), + undefined, + definition, + ), + success, + ); + }, +); diff --git a/scripts/toDataParser/dataParserTransformer/hook.ts b/scripts/toDataParser/dataParserTransformer/hook.ts new file mode 100644 index 0000000..e6abd59 --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/hook.ts @@ -0,0 +1,22 @@ +import type { DP } from "@duplojs/utils"; +import type { MapContext, MapImportClause } from "./create"; + +export type TransformerHookAction = "stop" | "next"; + +export interface TransformerHookOutput { + dataParser: DP.DataParsers; + action: TransformerHookAction; +} + +export interface TransformerHookParams { + dataParser: DP.DataParsers; + context: MapContext; + importDataParser: MapImportClause; + + output( + action: TransformerHookAction, + dataParser: DP.DataParsers + ): TransformerHookOutput; +} + +export type TransformerHook = (params: TransformerHookParams) => TransformerHookOutput; diff --git a/scripts/toDataParser/dataParserTransformer/importClause.ts b/scripts/toDataParser/dataParserTransformer/importClause.ts new file mode 100644 index 0000000..4f4e850 --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/importClause.ts @@ -0,0 +1,19 @@ +import { G } from "@duplojs/utils"; +import type { MapImportClause } from "./create"; +import { factory } from "typescript"; + +export function importClauseTransformer(imports: MapImportClause) { + return G.map( + imports, + ([path, clause]) => factory.createImportDeclaration( + undefined, + factory.createImportClause( + undefined, + undefined, + factory.createNamespaceImport(factory.createIdentifier(clause)), + ), + factory.createStringLiteral(path), + undefined, + ), + ); +} diff --git a/scripts/toDataParser/dataParserTransformer/index.ts b/scripts/toDataParser/dataParserTransformer/index.ts new file mode 100644 index 0000000..23d444f --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/index.ts @@ -0,0 +1,4 @@ +export * from "./create"; +export * from "./transformer"; +export * from "./hook"; +export * from "./defaults"; diff --git a/scripts/toDataParser/dataParserTransformer/transformer.ts b/scripts/toDataParser/dataParserTransformer/transformer.ts new file mode 100644 index 0000000..26f577e --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/transformer.ts @@ -0,0 +1,210 @@ +import { A, E, type DP, pipe, unwrap, when } from "@duplojs/utils"; +import type { MapContext, TransformerParams, createTransformer, MapImportClause, MaybeTransformerEither } from "./create"; +import { factory, type PropertyAssignment, type CallExpression, type Identifier } from "typescript"; +import type { TransformerHook } from "./hook"; +import { type createCheckerTransformer, checkerTransformer } from "../checkerTransformer"; + +export function getDefinitionDataParser( + dataParser: DP.DataParser, + checkerTransformers: readonly ReturnType[], + customProperties?: readonly PropertyAssignment[], +) { + const propertyAssignments: PropertyAssignment[] = []; + + if (dataParser.definition.errorMessage) { + propertyAssignments.push( + factory.createPropertyAssignment( + factory.createIdentifier("errorMessage"), + factory.createStringLiteral(dataParser.definition.errorMessage), + ), + ); + } + if (customProperties) { + propertyAssignments.push(...customProperties); + } + if (A.minElements(dataParser.definition.checkers, 1)) { + const checkers = A.reduce( + dataParser.definition.checkers, + A.reduceFrom([]), + ({ element, lastValue, nextPush, exit }) => pipe( + checkerTransformer(element, { transformers: checkerTransformers }), + E.whenIsRight( + (value) => nextPush(lastValue, value), + ), + when( + E.isLeft, + exit, + ), + ), + ); + + if (E.isLeft(checkers)) { + return E.left("buildDataParserGetDefinitionError", { + dataParser, + error: checkers, + }); + } + + propertyAssignments.push( + factory.createPropertyAssignment( + factory.createIdentifier("checkers"), + factory.createArrayLiteralExpression(checkers), + ), + ); + } + + return A.minElements(propertyAssignments, 1) + ? [factory.createObjectLiteralExpression(propertyAssignments)] + : []; +} + +export interface TransformerFunctionParams { + readonly dataParserTransformers: readonly ReturnType[]; + readonly checkerTransformers: readonly ReturnType[]; + readonly context: MapContext; + readonly buildingConstNames: Map; + readonly dependencyIdentifier: Identifier; + readonly hooks: readonly TransformerHook[]; + readonly recursiveDataParsers: DP.DataParser[]; + readonly importClause: MapImportClause; +} + +export function transformer( + dataParser: DP.DataParser, + params: TransformerFunctionParams, +) { + const currentDataParser = A.reduce( + params.hooks, + A.reduceFrom(dataParser), + ({ element: hook, lastValue, next, exit }) => { + const result = hook({ + dataParser: lastValue, + context: params.context, + importDataParser: params.importClause, + output: (action, dataParser) => ({ + dataParser, + action, + }), + }); + if (result.action === "stop") { + return exit(result.dataParser); + } else { + return next(result.dataParser); + } + }, + ); + + const contextValue = params.context.get(currentDataParser); + + if (contextValue) { + return E.right( + "buildSuccess", + contextValue.constName, + ); + } + + const currentBuildingConstName = params.buildingConstNames.get(currentDataParser); + + if (currentBuildingConstName) { + return E.right( + "buildSuccess", + currentBuildingConstName, + ); + } + + const shouldCreateConstDeclaration = A.includes(params.recursiveDataParsers, currentDataParser) + || !!currentDataParser.definition.constName; + const currentConstName = shouldCreateConstDeclaration + ? factory.createIdentifier( + currentDataParser.definition.constName + ?? `recursiveDataParser${params.context.size + params.buildingConstNames.size}`, + ) + : undefined; + + if (currentConstName) { + params.buildingConstNames.set( + currentDataParser, + currentConstName, + ); + } + + const functionParams: TransformerParams = { + success(result) { + return E.right("buildSuccess", result); + }, + transformer(dataParser) { + return transformer( + dataParser, + params, + ); + }, + context: params.context, + dependencyIdentifier: params.dependencyIdentifier, + buildError() { + return E.left("buildDataParserError", currentDataParser); + }, + importClause: params.importClause, + getDefinition(customProperties) { + return getDefinitionDataParser(currentDataParser, params.checkerTransformers, customProperties); + }, + addImportClause(path, clause) { + params.importClause.set(path, clause); + }, + }; + + const result = currentDataParser.definition.overrideDataParserTransformer + ? currentDataParser.definition.overrideDataParserTransformer( + currentDataParser.addOverrideDataParserTransformer(null), + functionParams, + ) + : A.reduce( + params.dataParserTransformers, + A.reduceFrom( + E.left("dataParserNotSupport", currentDataParser), + ), + ({ + element: functionBuilder, + lastValue, + next, + exit, + }) => { + const result = functionBuilder(currentDataParser, functionParams); + + if (E.isLeft(result)) { + if (!E.hasInformation(result, "dataParserNotSupport")) { + return exit(result); + } + + return next(lastValue); + } + + return exit(result); + }, + ); + + if (E.isLeft(result)) { + if (currentConstName) { + params.buildingConstNames.delete(currentDataParser); + } + + return result; + } + + if (currentConstName) { + params.buildingConstNames.delete(currentDataParser); + params.context.set( + currentDataParser, + { + constName: currentConstName, + expression: unwrap(result), + }, + ); + + return E.right( + "buildSuccess", + currentConstName, + ); + } + + return result; +} diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/array.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/array.test.ts.snap new file mode 100644 index 0000000..87a981e --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/array.test.ts.snap @@ -0,0 +1,7 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`array > renders array parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const arrayParser = DP.array(DP.string());" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/bigint.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/bigint.test.ts.snap new file mode 100644 index 0000000..ddf8d1e --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/bigint.test.ts.snap @@ -0,0 +1,13 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`bigint > renders bigint parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const bigintParser = DP.bigint({ coerce: true });" +`; + +exports[`bigint > renders bigint parser without coerce 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const bigintParserNoCoerce = DP.bigint();" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/boolean.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/boolean.test.ts.snap new file mode 100644 index 0000000..3f7acdb --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/boolean.test.ts.snap @@ -0,0 +1,13 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`boolean > renders boolean parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const booleanParser = DP.boolean({ coerce: true });" +`; + +exports[`boolean > renders boolean parser without coerce 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const booleanParserNoCoerce = DP.boolean();" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/date.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/date.test.ts.snap new file mode 100644 index 0000000..175a736 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/date.test.ts.snap @@ -0,0 +1,13 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`date > renders date parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const dateParser = DP.date({ coerce: true });" +`; + +exports[`date > renders date parser without coerce 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const dateParserNoCoerce = DP.date();" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/empty.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/empty.test.ts.snap new file mode 100644 index 0000000..7168874 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/empty.test.ts.snap @@ -0,0 +1,13 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`empty > renders empty parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const emptyParser = DP.empty({ coerce: true });" +`; + +exports[`empty > renders empty parser without coerce 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const emptyParserNoCoerce = DP.empty();" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/file.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/file.test.ts.snap new file mode 100644 index 0000000..a338d2a --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/file.test.ts.snap @@ -0,0 +1,27 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`file > renders extended file parser namespace 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +import * as DPE from "@duplojs/utils/dataParserExtended"; + +import * as SDPE from "@duplojs/server-utils/dataParserExtended"; + +export const fileParserExtended = SDPE.file({});" +`; + +exports[`file > renders file parser with async constraints 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +import * as SDP from "@duplojs/server-utils/dataParser"; + +export const fileParser = SDP.file({ coerce: true, checkExist: true, maxSize: 10, minSize: 5, mimeType: /image\\/png/ });" +`; + +exports[`file > renders file parser without options 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +import * as SDP from "@duplojs/server-utils/dataParser"; + +export const fileParserNoOptions = SDP.file({});" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/lazy.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/lazy.test.ts.snap new file mode 100644 index 0000000..e43e016 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/lazy.test.ts.snap @@ -0,0 +1,7 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`lazy > renders lazy parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const lazyParser = DP.lazy(() => DP.string());" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/literal.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/literal.test.ts.snap new file mode 100644 index 0000000..c0b1e8e --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/literal.test.ts.snap @@ -0,0 +1,7 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`literal > renders literal parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const literalParser = DP.literal(["foo", 1, 1n, true, false, null, undefined]);" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/nil.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/nil.test.ts.snap new file mode 100644 index 0000000..e198311 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/nil.test.ts.snap @@ -0,0 +1,13 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`nil > renders nil parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const nilParser = DP.nil({ coerce: true });" +`; + +exports[`nil > renders nil parser without coerce 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const nilParserNoCoerce = DP.nil();" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/nullable.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/nullable.test.ts.snap new file mode 100644 index 0000000..6630899 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/nullable.test.ts.snap @@ -0,0 +1,7 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`nullable > renders nullable parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const nullableParser = DP.nullable(DP.string());" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/number.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/number.test.ts.snap new file mode 100644 index 0000000..180c46d --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/number.test.ts.snap @@ -0,0 +1,13 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`number > renders number parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const numberParser = DP.number({ coerce: true });" +`; + +exports[`number > renders number parser without coerce 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const numberParserNoCoerce = DP.number();" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/object.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/object.test.ts.snap new file mode 100644 index 0000000..fb2eeb0 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/object.test.ts.snap @@ -0,0 +1,7 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`object > renders object parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const objectParser = DP.object({ foo: DP.string(), bar: DP.number() });" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/optional.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/optional.test.ts.snap new file mode 100644 index 0000000..85323f9 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/optional.test.ts.snap @@ -0,0 +1,7 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`optional > renders optional parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const optionalParser = DP.optional(DP.string());" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/pipe.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/pipe.test.ts.snap new file mode 100644 index 0000000..0be75c7 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/pipe.test.ts.snap @@ -0,0 +1,7 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`pipe > renders pipe parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const pipeParser = DP.pipe(DP.string(), DP.number());" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/record.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/record.test.ts.snap new file mode 100644 index 0000000..2c478dd --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/record.test.ts.snap @@ -0,0 +1,7 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`record > renders record parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const recordParser = DP.record(DP.string(), DP.number());" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/recover.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/recover.test.ts.snap new file mode 100644 index 0000000..91c49e6 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/recover.test.ts.snap @@ -0,0 +1,7 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`recover > renders inner parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const recoverParser = DP.string();" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/string.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/string.test.ts.snap new file mode 100644 index 0000000..97f8f78 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/string.test.ts.snap @@ -0,0 +1,7 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`string > renders string parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const stringParser = DP.string();" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/templateLiteral.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/templateLiteral.test.ts.snap new file mode 100644 index 0000000..51ad65e --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/templateLiteral.test.ts.snap @@ -0,0 +1,7 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`templateLiteral > renders template literal parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const templateLiteralParser = DP.templateLiteral(["pre-", 1n, "mid-", true, "-false-", false, "-str-", "abc", "-num-", 42, "-null-", null, "-undef-", undefined, "-dp-", DP.string()]);" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/time.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/time.test.ts.snap new file mode 100644 index 0000000..3340abb --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/time.test.ts.snap @@ -0,0 +1,15 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`time > renders time parser with checker imports 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +import * as DDate from "@duplojs/utils/date"; + +export const timeParser = DP.time({ coerce: true, checkers: [DP.checkerTimeMin(DDate.createTime(1, "millisecond"))] });" +`; + +exports[`time > renders time parser without coerce and without checkers 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const timeParserNoCoerce = DP.time();" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/transform.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/transform.test.ts.snap new file mode 100644 index 0000000..baecd5e --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/transform.test.ts.snap @@ -0,0 +1,7 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`transform > renders transform parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const transformParser = DP.transform(DP.string(), (value) => value.trim());" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/tuple.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/tuple.test.ts.snap new file mode 100644 index 0000000..d0bd0b0 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/tuple.test.ts.snap @@ -0,0 +1,13 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`tuple > renders tuple parser with rest 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const tupleParser = DP.tuple([DP.string()], { rest: DP.number() });" +`; + +exports[`tuple > renders tuple parser without rest 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const tupleParserNoRest = DP.tuple([DP.string()]);" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/union.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/union.test.ts.snap new file mode 100644 index 0000000..f8059f8 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/union.test.ts.snap @@ -0,0 +1,7 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`union > renders union parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const unionParser = DP.union([DP.string(), DP.number()]);" +`; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/unknown.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/unknown.test.ts.snap new file mode 100644 index 0000000..871f0ee --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/unknown.test.ts.snap @@ -0,0 +1,7 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`unknown > renders unknown parser 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const unknownParser = DP.unknown();" +`; diff --git a/tests/toDataParser/dataParserTransformer/array.test.ts b/tests/toDataParser/dataParserTransformer/array.test.ts new file mode 100644 index 0000000..42f4682 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/array.test.ts @@ -0,0 +1,65 @@ +import { DP, DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "ArrayParser", + transformers: tsDefaultTransformers, +}; + +describe("array", () => { + it("renders array parser", () => { + expect( + render( + DPE.array(DPE.string()), + { + constName: "arrayParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when inner element cannot be rendered", () => { + expect( + () => render( + DPE.array(DPE.string()), + { + constName: "arrayParserError", + dataParserTransformers: [ + ((dataParser, { buildError }) => DP.stringKind.has(dataParser) + ? buildError() + : E.left("dataParserNotSupport", dataParser)), + ...defaultTransformers, + ], + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.array(DPE.string(), { + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "arrayParserCheckerError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/bigint.test.ts b/tests/toDataParser/dataParserTransformer/bigint.test.ts new file mode 100644 index 0000000..ca7e8fc --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/bigint.test.ts @@ -0,0 +1,60 @@ +import { DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "BigintParser", + transformers: tsDefaultTransformers, +}; + +describe("bigint", () => { + it("renders bigint parser", () => { + expect( + render( + DPE.bigint({ coerce: true }), + { + constName: "bigintParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("renders bigint parser without coerce", () => { + expect( + render( + DPE.bigint(), + { + constName: "bigintParserNoCoerce", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.bigint({ + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "bigintParserError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/boolean.test.ts b/tests/toDataParser/dataParserTransformer/boolean.test.ts new file mode 100644 index 0000000..6897282 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/boolean.test.ts @@ -0,0 +1,60 @@ +import { DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "BooleanParser", + transformers: tsDefaultTransformers, +}; + +describe("boolean", () => { + it("renders boolean parser", () => { + expect( + render( + DPE.boolean({ coerce: true }), + { + constName: "booleanParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("renders boolean parser without coerce", () => { + expect( + render( + DPE.boolean(), + { + constName: "booleanParserNoCoerce", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.boolean({ + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "booleanParserError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/date.test.ts b/tests/toDataParser/dataParserTransformer/date.test.ts new file mode 100644 index 0000000..e22bf7a --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/date.test.ts @@ -0,0 +1,60 @@ +import { DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "DateParser", + transformers: tsDefaultTransformers, +}; + +describe("date", () => { + it("renders date parser", () => { + expect( + render( + DPE.date({ coerce: true }), + { + constName: "dateParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("renders date parser without coerce", () => { + expect( + render( + DPE.date(), + { + constName: "dateParserNoCoerce", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.date({ + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "dateParserError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/empty.test.ts b/tests/toDataParser/dataParserTransformer/empty.test.ts new file mode 100644 index 0000000..eb7e12a --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/empty.test.ts @@ -0,0 +1,60 @@ +import { DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "EmptyParser", + transformers: tsDefaultTransformers, +}; + +describe("empty", () => { + it("renders empty parser", () => { + expect( + render( + DPE.empty({ coerce: true }), + { + constName: "emptyParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("renders empty parser without coerce", () => { + expect( + render( + DPE.empty(), + { + constName: "emptyParserNoCoerce", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.empty({ + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "emptyParserError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/file.test.ts b/tests/toDataParser/dataParserTransformer/file.test.ts new file mode 100644 index 0000000..06f346b --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/file.test.ts @@ -0,0 +1,81 @@ +import { SDP } from "@duplojs/server-utils"; +import { E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "FileParser", + transformers: tsDefaultTransformers, +}; + +describe("file", () => { + it("renders file parser with async constraints", () => { + expect( + render( + SDP.coerce.file({ + checkExist: true, + maxSize: 10, + minSize: 5, + mimeType: /image\/png/, + }), + { + constName: "fileParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("renders file parser without options", () => { + expect( + render( + SDP.file(), + { + constName: "fileParserNoOptions", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("renders extended file parser namespace", () => { + expect( + render( + SDP.file(), + { + constName: "fileParserExtended", + exportMode: "extended", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = SDP.file({}, { + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "fileParserError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/lazy.test.ts b/tests/toDataParser/dataParserTransformer/lazy.test.ts new file mode 100644 index 0000000..b34643f --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/lazy.test.ts @@ -0,0 +1,65 @@ +import { DP, DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "LazyParser", + transformers: tsDefaultTransformers, +}; + +describe("lazy", () => { + it("renders lazy parser", () => { + expect( + render( + DPE.lazy(() => DPE.string()), + { + constName: "lazyParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when lazy inner parser cannot be rendered", () => { + expect( + () => render( + DPE.lazy(() => DPE.string()), + { + constName: "lazyParserError", + dataParserTransformers: [ + ((dataParser, { buildError }) => DP.stringKind.has(dataParser) + ? buildError() + : E.left("dataParserNotSupport", dataParser)), + ...defaultTransformers, + ], + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.lazy(() => DPE.string(), { + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "lazyParserCheckerError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/literal.test.ts b/tests/toDataParser/dataParserTransformer/literal.test.ts new file mode 100644 index 0000000..6eef50b --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/literal.test.ts @@ -0,0 +1,46 @@ +import { DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "LiteralParser", + transformers: tsDefaultTransformers, +}; + +describe("literal", () => { + it("renders literal parser", () => { + expect( + render( + DPE.literal(["foo", 1, 1n, true, false, null, undefined]), + { + constName: "literalParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.literal(["foo"], { + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "literalParserCheckerError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/nil.test.ts b/tests/toDataParser/dataParserTransformer/nil.test.ts new file mode 100644 index 0000000..a6457da --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/nil.test.ts @@ -0,0 +1,58 @@ +import { DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "NilParser", + transformers: tsDefaultTransformers, +}; + +describe("nil", () => { + it("renders nil parser", () => { + expect( + render( + DPE.nil({ coerce: true }), + { + constName: "nilParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("renders nil parser without coerce", () => { + expect( + render( + DPE.nil(), + { + constName: "nilParserNoCoerce", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.nil({ checkers: [{ kind: "forced-error" } as any] }); + + expect( + () => render( + schema, + { + constName: "nilParserError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/nullable.test.ts b/tests/toDataParser/dataParserTransformer/nullable.test.ts new file mode 100644 index 0000000..1f0af35 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/nullable.test.ts @@ -0,0 +1,65 @@ +import { DP, DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "NullableParser", + transformers: tsDefaultTransformers, +}; + +describe("nullable", () => { + it("renders nullable parser", () => { + expect( + render( + DPE.nullable(DPE.string()), + { + constName: "nullableParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when inner parser cannot be rendered", () => { + expect( + () => render( + DPE.nullable(DPE.string()), + { + constName: "nullableParserError", + dataParserTransformers: [ + ((dataParser, { buildError }) => DP.stringKind.has(dataParser) + ? buildError() + : E.left("dataParserNotSupport", dataParser)), + ...defaultTransformers, + ], + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.nullable(DPE.string(), { + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "nullableParserCheckerError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/number.test.ts b/tests/toDataParser/dataParserTransformer/number.test.ts new file mode 100644 index 0000000..ed71e20 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/number.test.ts @@ -0,0 +1,60 @@ +import { DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "NumberParser", + transformers: tsDefaultTransformers, +}; + +describe("number", () => { + it("renders number parser", () => { + expect( + render( + DPE.number({ coerce: true }), + { + constName: "numberParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("renders number parser without coerce", () => { + expect( + render( + DPE.number(), + { + constName: "numberParserNoCoerce", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.number({ + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "numberParserError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/object.test.ts b/tests/toDataParser/dataParserTransformer/object.test.ts new file mode 100644 index 0000000..3c9fe41 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/object.test.ts @@ -0,0 +1,74 @@ +import { DP, DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "ObjectParser", + transformers: tsDefaultTransformers, +}; + +describe("object", () => { + it("renders object parser", () => { + expect( + render( + DPE.object({ + foo: DPE.string(), + bar: DPE.number(), + }), + { + constName: "objectParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when a shape property cannot be rendered", () => { + expect( + () => render( + DPE.object({ + foo: DPE.string(), + bar: DPE.number(), + }), + { + constName: "objectParserError", + dataParserTransformers: [ + ((dataParser, { buildError }) => DP.stringKind.has(dataParser) + ? buildError() + : E.left("dataParserNotSupport", dataParser)), + ...defaultTransformers, + ], + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.object({ + foo: DPE.string(), + bar: DPE.number(), + }, { + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "objectParserCheckerError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/optional.test.ts b/tests/toDataParser/dataParserTransformer/optional.test.ts new file mode 100644 index 0000000..169eb55 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/optional.test.ts @@ -0,0 +1,65 @@ +import { DP, DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "OptionalParser", + transformers: tsDefaultTransformers, +}; + +describe("optional", () => { + it("renders optional parser", () => { + expect( + render( + DPE.optional(DPE.string()), + { + constName: "optionalParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when inner parser cannot be rendered", () => { + expect( + () => render( + DPE.optional(DPE.string()), + { + constName: "optionalParserError", + dataParserTransformers: [ + ((dataParser, { buildError }) => DP.stringKind.has(dataParser) + ? buildError() + : E.left("dataParserNotSupport", dataParser)), + ...defaultTransformers, + ], + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.optional(DPE.string(), { + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "optionalParserCheckerError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/pipe.test.ts b/tests/toDataParser/dataParserTransformer/pipe.test.ts new file mode 100644 index 0000000..0247350 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/pipe.test.ts @@ -0,0 +1,84 @@ +import { DP, DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "PipeParser", + transformers: tsDefaultTransformers, +}; + +describe("pipe", () => { + it("renders pipe parser", () => { + expect( + render( + DPE.pipe(DPE.string(), DPE.number()), + { + constName: "pipeParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when input parser cannot be rendered", () => { + expect( + () => render( + DPE.pipe(DPE.string(), DPE.number()), + { + constName: "pipeParserInputError", + dataParserTransformers: [ + ((dataParser, { buildError }) => DP.stringKind.has(dataParser) + ? buildError() + : E.left("dataParserNotSupport", dataParser)), + ...defaultTransformers, + ], + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails when output parser cannot be rendered", () => { + expect( + () => render( + DPE.pipe(DPE.string(), DPE.number()), + { + constName: "pipeParserOutputError", + dataParserTransformers: [ + ((dataParser, { buildError }) => DP.numberKind.has(dataParser) + ? buildError() + : E.left("dataParserNotSupport", dataParser)), + ...defaultTransformers, + ], + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.pipe(DPE.string(), DPE.number(), { + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "pipeParserCheckerError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/record.test.ts b/tests/toDataParser/dataParserTransformer/record.test.ts new file mode 100644 index 0000000..af10a40 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/record.test.ts @@ -0,0 +1,88 @@ +import { DP, DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "RecordParser", + transformers: tsDefaultTransformers, +}; + +describe("record", () => { + it("renders record parser", () => { + expect( + render( + DPE.record(DPE.string(), DPE.number()), + { + constName: "recordParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when key parser cannot be rendered", () => { + expect( + () => render( + DPE.record(DPE.string(), DPE.number()), + { + constName: "recordParserKeyError", + dataParserTransformers: [ + ((dataParser, { buildError }) => DP.stringKind.has(dataParser) + ? buildError() + : E.left("dataParserNotSupport", dataParser)), + ...defaultTransformers, + ], + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails when value parser cannot be rendered", () => { + expect( + () => render( + DPE.record(DPE.string(), DPE.number()), + { + constName: "recordParserValueError", + dataParserTransformers: [ + ((dataParser, { buildError }) => DP.numberKind.has(dataParser) + ? buildError() + : E.left("dataParserNotSupport", dataParser)), + ...defaultTransformers, + ], + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.record( + DPE.string(), + DPE.number(), + { + checkers: [{ kind: "forced-error" } as any], + }, + ); + + expect( + () => render( + schema, + { + constName: "recordParserCheckerError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/recover.test.ts b/tests/toDataParser/dataParserTransformer/recover.test.ts new file mode 100644 index 0000000..ee32210 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/recover.test.ts @@ -0,0 +1,22 @@ +import { render, defaultTransformers, defaultCheckerTransformers } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; +import { DPE } from "@duplojs/utils"; + +describe("recover", () => { + it("renders inner parser", () => { + expect( + render( + DPE.recover(DPE.string(), "fallback"), + { + constName: "recoverParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript: { + identifier: "RecoverParser", + transformers: tsDefaultTransformers, + }, + }, + ), + ).toMatchSnapshot(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/string.test.ts b/tests/toDataParser/dataParserTransformer/string.test.ts new file mode 100644 index 0000000..34e8340 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/string.test.ts @@ -0,0 +1,46 @@ +import { DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "StringParser", + transformers: tsDefaultTransformers, +}; + +describe("string", () => { + it("renders string parser", () => { + expect( + render( + DPE.string(), + { + constName: "stringParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("renders string parser when definition has a checker error", () => { + const schema = DPE.string({ + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "stringParserError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/templateLiteral.test.ts b/tests/toDataParser/dataParserTransformer/templateLiteral.test.ts new file mode 100644 index 0000000..b09df1b --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/templateLiteral.test.ts @@ -0,0 +1,82 @@ +import { DP, DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "TemplateLiteralParser", + transformers: tsDefaultTransformers, +}; + +describe("templateLiteral", () => { + it("renders template literal parser", () => { + expect( + render( + DPE.templateLiteral([ + "pre-", + 1n, + "mid-", + true, + "-false-", + false, + "-str-", + "abc", + "-num-", + 42, + "-null-", + null, + "-undef-", + undefined, + "-dp-", + DPE.string(), + ]), + { + constName: "templateLiteralParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when nested parser cannot be rendered", () => { + expect( + () => render( + DPE.templateLiteral(["user-", DPE.number(), "-id"]), + { + constName: "templateLiteralParserError", + dataParserTransformers: [ + ((dataParser, { buildError }) => DP.numberKind.has(dataParser) + ? buildError() + : E.left("dataParserNotSupport", dataParser)), + ...defaultTransformers, + ], + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.templateLiteral(["user-", DPE.number(), "-id"], { + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "templateLiteralParserCheckerError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/time.test.ts b/tests/toDataParser/dataParserTransformer/time.test.ts new file mode 100644 index 0000000..854ddf9 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/time.test.ts @@ -0,0 +1,62 @@ +import { DDate, DP, DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "TimeParser", + transformers: tsDefaultTransformers, +}; + +describe("time", () => { + it("renders time parser with checker imports", () => { + expect( + render( + DPE.time({ coerce: true }).addChecker( + DP.checkerTimeMin(DDate.createTime(1, "millisecond")), + ), + { + constName: "timeParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("renders time parser without coerce and without checkers", () => { + expect( + render( + DPE.time(), + { + constName: "timeParserNoCoerce", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.time({ + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "timeParserError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/transform.test.ts b/tests/toDataParser/dataParserTransformer/transform.test.ts new file mode 100644 index 0000000..3edce87 --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/transform.test.ts @@ -0,0 +1,171 @@ +/* eslint-disable @typescript-eslint/consistent-type-imports */ +import { DP, DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; +import { afterEach, vi } from "vitest"; +import * as ts from "typescript"; + +vi.mock("typescript", async() => { + const actual = await vi.importActual("typescript"); + + return { + ...actual, + createSourceFile: vi.fn(actual.createSourceFile), + isExpressionStatement: vi.fn(actual.isExpressionStatement), + isParenthesizedExpression: vi.fn(actual.isParenthesizedExpression), + }; +}); + +const toTypescript = { + identifier: "TransformParser", + transformers: tsDefaultTransformers, +}; + +afterEach(() => { + vi.restoreAllMocks(); +}); + +describe("transform", () => { + it("renders transform parser", () => { + expect( + render( + DPE.transform(DPE.string(), (value) => value.trim()), + { + constName: "transformParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when inner parser cannot be rendered", () => { + expect( + () => render( + DPE.transform(DPE.string(), (value) => value.trim()), + { + constName: "transformParserInnerError", + dataParserTransformers: [ + ((dataParser, { buildError }) => DP.stringKind.has(dataParser) + ? buildError() + : E.left("dataParserNotSupport", dataParser)), + ...defaultTransformers, + ], + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails on native functions", () => { + expect( + () => render( + DPE.transform(DPE.string(), Math.max as any), + { + constName: "transformParserNativeError", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails on malformed functions", () => { + const schema = DPE.transform(DPE.string(), { toString: () => "foo" } as any); + expect( + () => render( + schema, + { + constName: "transformParserMalformedError", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails when the function source cannot be parsed as an expression", () => { + const schema = DPE.transform(DPE.string(), { toString: () => "" } as any); + + expect( + () => render( + schema, + { + constName: "transformParserEmptySourceError", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails when the parsed statement is not an expression statement", () => { + vi.mocked(ts.createSourceFile).mockReturnValue({ + statements: [{ kind: ts.SyntaxKind.VariableStatement }], + } as any); + vi.mocked(ts.isExpressionStatement).mockReturnValue(false); + + expect( + () => render( + DPE.transform(DPE.string(), (value) => value.trim()), + { + constName: "transformParserStatementError", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails when the parsed function is not parenthesized", () => { + vi.mocked(ts.createSourceFile).mockReturnValue({ + statements: [ + { + expression: {}, + }, + ], + } as any); + vi.mocked(ts.isExpressionStatement).mockReturnValue(true); + vi.mocked(ts.isParenthesizedExpression).mockReturnValue(false); + + expect( + () => render( + DPE.transform(DPE.string(), (value) => value.trim()), + { + constName: "transformParserParenthesizedError", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.transform(DPE.string(), (value) => value.trim(), { + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "transformParserCheckerError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/tuple.test.ts b/tests/toDataParser/dataParserTransformer/tuple.test.ts new file mode 100644 index 0000000..600fbfe --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/tuple.test.ts @@ -0,0 +1,99 @@ +import { DP, DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "TupleParser", + transformers: tsDefaultTransformers, +}; + +describe("tuple", () => { + it("renders tuple parser with rest", () => { + expect( + render( + DPE.tuple([DPE.string()], { rest: DPE.number() }), + { + constName: "tupleParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("renders tuple parser without rest", () => { + expect( + render( + DPE.tuple([DPE.string()]), + { + constName: "tupleParserNoRest", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when tuple shape cannot be rendered", () => { + expect( + () => render( + DPE.tuple([DPE.string()], { rest: DPE.number() }), + { + constName: "tupleParserShapeError", + dataParserTransformers: [ + ((dataParser, { buildError }) => DP.stringKind.has(dataParser) + ? buildError() + : E.left("dataParserNotSupport", dataParser)), + ...defaultTransformers, + ], + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails when tuple rest cannot be rendered", () => { + expect( + () => render( + DPE.tuple([DPE.string()], { rest: DPE.number() }), + { + constName: "tupleParserRestError", + dataParserTransformers: [ + ((dataParser, { buildError }) => DP.numberKind.has(dataParser) + ? buildError() + : E.left("dataParserNotSupport", dataParser)), + ...defaultTransformers, + ], + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.tuple([DPE.string()], { + rest: DPE.number(), + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "tupleParserCheckerError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/union.test.ts b/tests/toDataParser/dataParserTransformer/union.test.ts new file mode 100644 index 0000000..d5e4fbb --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/union.test.ts @@ -0,0 +1,65 @@ +import { DP, DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "UnionParser", + transformers: tsDefaultTransformers, +}; + +describe("union", () => { + it("renders union parser", () => { + expect( + render( + DPE.union([DPE.string(), DPE.number()]), + { + constName: "unionParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when option parser cannot be rendered", () => { + expect( + () => render( + DPE.union([DPE.string(), DPE.number()]), + { + constName: "unionParserOptionError", + dataParserTransformers: [ + ((dataParser, { buildError }) => DP.stringKind.has(dataParser) + ? buildError() + : E.left("dataParserNotSupport", dataParser)), + ...defaultTransformers, + ], + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toThrow(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.union([DPE.string(), DPE.number()], { + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "unionParserCheckerError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); diff --git a/tests/toDataParser/dataParserTransformer/unknown.test.ts b/tests/toDataParser/dataParserTransformer/unknown.test.ts new file mode 100644 index 0000000..9b56b3a --- /dev/null +++ b/tests/toDataParser/dataParserTransformer/unknown.test.ts @@ -0,0 +1,46 @@ +import { DPE, E } from "@duplojs/utils"; +import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; + +const toTypescript = { + identifier: "UnknownParser", + transformers: tsDefaultTransformers, +}; + +describe("unknown", () => { + it("renders unknown parser", () => { + expect( + render( + DPE.unknown(), + { + constName: "unknownParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript, + }, + ), + ).toMatchSnapshot(); + }); + + it("fails when definition checker cannot be rendered", () => { + const schema = DPE.unknown({ + checkers: [{ kind: "forced-error" } as any], + }); + + expect( + () => render( + schema, + { + constName: "unknownParserError", + dataParserTransformers: defaultTransformers, + checkerTransformers: [ + ((checker, { buildError }) => (checker as any).kind === "forced-error" + ? buildError() + : E.left("checkerNotSupport", checker)), + ], + toTypescript, + }, + ), + ).toThrow(); + }); +}); From e4f208b724d8914050659e1c59c5b5c56c7e041c Mon Sep 17 00:00:00 2001 From: ZeRiix Date: Tue, 19 May 2026 16:47:24 +0200 Subject: [PATCH 03/16] feat(06): add toDataParser render pipeline --- package.json | 5 + scripts/index.ts | 1 + scripts/toDataParser/index.ts | 5 + scripts/toDataParser/kind.ts | 12 + scripts/toDataParser/render.ts | 226 ++++++++++++++++++ .../__snapshots__/render.test.ts.snap | 80 +++++++ tests/toDataParser/render.test.ts | 187 +++++++++++++++ 7 files changed, 516 insertions(+) create mode 100644 scripts/toDataParser/index.ts create mode 100644 scripts/toDataParser/kind.ts create mode 100644 scripts/toDataParser/render.ts create mode 100644 tests/toDataParser/__snapshots__/render.test.ts.snap create mode 100644 tests/toDataParser/render.test.ts diff --git a/package.json b/package.json index e89e5ba..635b278 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,11 @@ "import": "./dist/toJsonSchema/index.mjs", "require": "./dist/toJsonSchema/index.cjs", "types": "./dist/toJsonSchema/index.d.ts" + }, + "./toDataParser": { + "import": "./dist/toDataParser/index.mjs", + "require": "./dist/toDataParser/index.cjs", + "types": "./dist/toDataParser/index.d.ts" } }, "files": [ diff --git a/scripts/index.ts b/scripts/index.ts index 57f1224..87b45e0 100644 --- a/scripts/index.ts +++ b/scripts/index.ts @@ -1,4 +1,5 @@ export * as DataParserToTypescript from "./toTypescript"; export * as DataParserToJsonSchema from "./toJsonSchema"; +export * as DataParserToDataParser from "./toDataParser"; export * from "./utils"; diff --git a/scripts/toDataParser/index.ts b/scripts/toDataParser/index.ts new file mode 100644 index 0000000..7da6024 --- /dev/null +++ b/scripts/toDataParser/index.ts @@ -0,0 +1,5 @@ +export * from "./kind"; +export * from "./override"; +export * from "./checkerTransformer"; +export * from "./dataParserTransformer"; +export * from "./render"; diff --git a/scripts/toDataParser/kind.ts b/scripts/toDataParser/kind.ts new file mode 100644 index 0000000..0487403 --- /dev/null +++ b/scripts/toDataParser/kind.ts @@ -0,0 +1,12 @@ +import { createKindNamespace } from "@duplojs/utils"; + +declare module "@duplojs/utils" { + interface ReservedKindNamespace { + DuplojsDataParserToolsToDataParser: true; + } +} + +export const createToDataParserKind = createKindNamespace( + // @ts-expect-error reserved kind namespace + "DuplojsDataParserToolsToDataParser", +); diff --git a/scripts/toDataParser/render.ts b/scripts/toDataParser/render.ts new file mode 100644 index 0000000..b93e1a8 --- /dev/null +++ b/scripts/toDataParser/render.ts @@ -0,0 +1,226 @@ +import { A, DP, E, kindHeritage, pipe, S, unwrap } from "@duplojs/utils"; +import { createPrinter, createSourceFile, EmitHint, factory, NodeFlags, ScriptKind, ScriptTarget, SyntaxKind, type TypeAliasDeclaration, type VariableStatement } from "typescript"; +import * as TST from "@scripts/toTypescript"; +import { type createCheckerTransformer } from "./checkerTransformer"; +import { type TransformerHook, type createTransformer, type MapContext, type MapImportClause, transformer, type DataParserNotSupportedEither, type DataParserGetDefinitionErrorEither, type DataParserErrorEither } from "./dataParserTransformer"; +import { getRecursiveDataParser } from "@scripts/utils"; +import { createToDataParserKind } from "./kind"; +import { importClauseTransformer } from "./dataParserTransformer/importClause"; + +export class DataParserToDataParserRenderError extends kindHeritage( + "data-parser-to-data-parser-render-error", + createToDataParserKind("data-parser-to-data-parser-render-error"), + Error, +) { + public constructor( + public dataParser: DP.DataParser, + public error: DataParserNotSupportedEither | DataParserErrorEither | DataParserGetDefinitionErrorEither, + ) { + super({}, ["Error during the render of dataParser in dataParser."]); + } +} + +export class DataParserToDataParserTypeRenderError extends kindHeritage( + "data-parser-to-data-parser-type-render-error", + createToDataParserKind("data-parser-to-data-parser-type-render-error"), + Error, +) { + public constructor( + public dataParser: DP.DataParser, + public error: TST.DataParserNotSupportedEither | TST.DataParserErrorEither, + ) { + super({}, ["Error during the render of recursive dataParser type."]); + } +} + +export interface RenderParams { + readonly constName: string; + readonly dataParserTransformers: readonly ReturnType[]; + readonly checkerTransformers: readonly ReturnType[]; + readonly exportMode?: "normal" | "extended"; + readonly context?: MapContext; + readonly hooks?: readonly TransformerHook[]; + readonly importClause?: MapImportClause; + + readonly toTypescript: { + readonly identifier: string; + readonly transformers: readonly ReturnType[]; + readonly context?: TST.MapContext; + readonly mode?: TST.TransformerMode; + readonly hooks?: readonly TST.TransformerHook[]; + readonly importType?: TST.MapImportType; + }; +} + +export function render(dataParser: DP.DataParser, params: RenderParams) { + const context: MapContext = new Map(params.context); + const importClause: MapImportClause = new Map(params.importClause); + const dependencyIdentifier = factory.createIdentifier(params.exportMode === "extended" ? "DPE" : "DP"); + const recursiveDataParsers = getRecursiveDataParser(dataParser); + const tsContext: TST.MapContext = new Map(params.toTypescript.context); + const importType: TST.MapImportType = new Map(params.toTypescript.importType); + const recursiveTypeAliasDeclarations: TypeAliasDeclaration[] = []; + const recursiveTypeNameByDataParser = new Map(); + + importClause.set("@duplojs/utils/dataParser", "DP"); + + if (params.exportMode === "extended") { + importClause.set("@duplojs/utils/dataParserExtended", "DPE"); + } + + if (A.minElements(recursiveDataParsers, 1)) { + const tsResult = TST.transformer( + dataParser, + { + context: tsContext, + importType, + hooks: params.toTypescript.hooks ?? [], + mode: params.toTypescript.mode ?? "out", + recursiveDataParsers, + transformers: params.toTypescript.transformers, + }, + ); + + if (E.isLeft(tsResult)) { + throw new DataParserToDataParserTypeRenderError( + dataParser, + tsResult, + ); + } + + const typeDeclarations = A.reduce( + recursiveDataParsers, + A.reduceFrom([]), + ({ element: recursiveDataParser, lastValue, nextPush, next }) => { + const declaration = tsContext.get(recursiveDataParser); + + if (!declaration) { + return next(lastValue); + } + + recursiveTypeNameByDataParser.set(recursiveDataParser, declaration.name.text); + + return nextPush(lastValue, declaration); + }, + ); + + recursiveTypeAliasDeclarations.push(...typeDeclarations); + + if (A.includes(recursiveDataParsers, dataParser)) { + if ( + dataParser.definition.identifier + && dataParser.definition.identifier !== params.toTypescript.identifier + ) { + recursiveTypeAliasDeclarations.push( + factory.createTypeAliasDeclaration( + [factory.createToken(SyntaxKind.ExportKeyword)], + factory.createIdentifier(params.toTypescript.identifier), + undefined, + factory.createTypeReferenceNode( + dataParser.definition.identifier, + ), + ), + ); + + recursiveTypeNameByDataParser.set(dataParser, params.toTypescript.identifier); + } else if (dataParser.definition.identifier !== params.toTypescript.identifier) { + recursiveTypeAliasDeclarations.push( + factory.createTypeAliasDeclaration( + [factory.createToken(SyntaxKind.ExportKeyword)], + factory.createIdentifier(params.toTypescript.identifier), + undefined, + unwrap(tsResult), + ), + ); + + recursiveTypeNameByDataParser.set(dataParser, params.toTypescript.identifier); + } + } + } + + const result = transformer( + dataParser, + { + dataParserTransformers: params.dataParserTransformers, + checkerTransformers: params.checkerTransformers, + context, + buildingConstNames: new Map(), + recursiveDataParsers, + importClause, + dependencyIdentifier, + hooks: params.hooks ?? [], + }, + ); + + if (E.isLeft(result)) { + throw new DataParserToDataParserRenderError( + dataParser, + result, + ); + } + + if (dataParser.definition.constName !== params.constName) { + context.set( + DP.empty(), + { + constName: factory.createIdentifier(params.constName), + expression: unwrap(result), + }, + ); + } + + const dataParserConstStatements = A.reduce( + A.from(context), + A.reduceFrom([]), + ({ element: [currentDataParser, contextValue], lastValue, nextPush }) => { + const recursiveTypeName = recursiveTypeNameByDataParser.get(currentDataParser); + + return nextPush( + lastValue, + factory.createVariableStatement( + [factory.createToken(SyntaxKind.ExportKeyword)], + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + contextValue.constName, + undefined, + recursiveTypeName + ? factory.createTypeReferenceNode( + factory.createQualifiedName( + dependencyIdentifier, + factory.createIdentifier("DataParser"), + ), + [factory.createTypeReferenceNode(recursiveTypeName)], + ) + : undefined, + contextValue.expression, + ), + ], + NodeFlags.Const, + ), + ), + ); + }, + ); + + const sourceFile = createSourceFile("print.ts", "", ScriptTarget.Latest, false, ScriptKind.TS); + const printer = createPrinter(); + + return pipe( + [ + ...importClauseTransformer(importClause), + ...TST.importTypesTransformer(importType), + ...recursiveTypeAliasDeclarations, + ...dataParserConstStatements, + ], + A.map( + (value) => printer.printNode( + EmitHint.Unspecified, + value, + sourceFile, + ), + ), + A.join("\n\n"), + S.trim, + ); +} diff --git a/tests/toDataParser/__snapshots__/render.test.ts.snap b/tests/toDataParser/__snapshots__/render.test.ts.snap new file mode 100644 index 0000000..3fb47d3 --- /dev/null +++ b/tests/toDataParser/__snapshots__/render.test.ts.snap @@ -0,0 +1,80 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`render > renders anonymous recursive dataParser with a temporary const 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export type RecursiveType0 = { + next: RecursiveType0; +}; + +export type RecursiveNode = RecursiveType0; + +export const recursiveDataParser0: DP.DataParser = DP.object({ next: DP.lazy(() => recursiveDataParser0) }); + +export const recursiveNodeParser = recursiveDataParser0;" +`; + +exports[`render > renders checked dataParsers in normal and extended modes 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +import * as DDate from "@duplojs/utils/date"; + +export const checkedParser = DP.object({ startAt: DP.time({ checkers: [DP.checkerTimeMin(DDate.createTime(1000, "millisecond")), DP.checkerTimeMax(DDate.createTime(5000, "millisecond"))] }), name: DP.string({ checkers: [DP.checkerStringMin(2)] }), count: DP.number({ checkers: [DP.checkerInt(), DP.checkerNumberMin(1)] }) });" +`; + +exports[`render > renders checked dataParsers in normal and extended modes 2`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +import * as DPE from "@duplojs/utils/dataParserExtended"; + +import * as DDate from "@duplojs/utils/date"; + +export const checkedExtendedParser = DPE.object({ startAt: DPE.time({ checkers: [DP.checkerTimeMin(DDate.createTime(250, "millisecond"))] }), tags: DPE.array(DPE.string({ checkers: [DP.checkerStringMin(1)] }), { checkers: [DP.checkerArrayMin(1)] }) });" +`; + +exports[`render > renders complex nested recursive dataParsers 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export type RecursiveType0 = { + recursiveProp: { + self: RecursiveType0; + array: RecursiveType1; + tuple: RecursiveType2; + union: RecursiveType3; + }; + children: RecursiveType0[]; + tuple: RecursiveType2; + array: RecursiveType1; + union: RecursiveType3; +}; + +export type RecursiveType1 = (string | RecursiveType1 | RecursiveType0)[]; + +export type RecursiveType2 = [ + string, + RecursiveType0, + (RecursiveType2 | RecursiveType3 | string)[] +]; + +export type RecursiveType3 = string | RecursiveType0 | RecursiveType2 | RecursiveType3[]; + +export type ComplexRecursive = RecursiveType0; + +export const recursiveDataParser1: DP.DataParser = DP.array(DP.union([DP.string(), DP.lazy(() => recursiveDataParser1), DP.lazy(() => recursiveDataParser0)])); + +export const recursiveDataParser3: DP.DataParser = DP.union([DP.string(), DP.lazy(() => recursiveDataParser0), DP.lazy(() => recursiveDataParser2), DP.array(DP.lazy(() => recursiveDataParser3))]); + +export const recursiveDataParser2: DP.DataParser = DP.tuple([DP.string(), DP.lazy(() => recursiveDataParser0), DP.array(DP.union([DP.lazy(() => recursiveDataParser2), DP.lazy(() => recursiveDataParser3), DP.string()]))]); + +export const recursiveDataParser0: DP.DataParser = DP.object({ recursiveProp: DP.object({ self: DP.lazy(() => recursiveDataParser0), array: recursiveDataParser1, tuple: recursiveDataParser2, union: recursiveDataParser3 }), children: DP.array(DP.lazy(() => recursiveDataParser0)), tuple: recursiveDataParser2, array: recursiveDataParser1, union: recursiveDataParser3 }); + +export const complexRecursiveParser = recursiveDataParser0;" +`; + +exports[`render > renders named dependencies before their consumers 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const childParser = DP.string(); + +export const parentParser = DP.object({ child: childParser });" +`; diff --git a/tests/toDataParser/render.test.ts b/tests/toDataParser/render.test.ts new file mode 100644 index 0000000..411f49a --- /dev/null +++ b/tests/toDataParser/render.test.ts @@ -0,0 +1,187 @@ +import { DDate, DP, DPE } from "@duplojs/utils"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; +import { defaultCheckerTransformers, defaultTransformers, render } from "@scripts/toDataParser"; + +describe("render", () => { + it("renders anonymous recursive dataParser with a temporary const", () => { + interface RecursiveNode { + next: RecursiveNode; + } + + const schema: DPE.DataParser = DPE.object({ + next: DPE.lazy(() => schema), + }).contract(); + + expect( + render( + schema, + { + constName: "recursiveNodeParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript: { + identifier: "RecursiveNode", + transformers: tsDefaultTransformers, + }, + }, + ), + ).toMatchSnapshot(); + }); + + it("renders named dependencies before their consumers", () => { + const child = DPE.string().addConstName("childParser"); + const schema = DPE.object({ child }).addConstName("parentParser"); + + expect( + render( + schema, + { + constName: "parentParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript: { + identifier: "Parent", + transformers: tsDefaultTransformers, + }, + }, + ), + ).toMatchSnapshot(); + }); + + it("renders complex nested recursive dataParsers", () => { + type RecursiveArray = (RecursiveArray | RecursiveObject | string)[]; + + type RecursiveTuple = [ + string, + RecursiveObject, + (RecursiveTuple | RecursiveUnion | string)[], + ]; + + type RecursiveUnion = + | string + | RecursiveObject + | RecursiveTuple + | RecursiveUnion[]; + + interface RecursiveObject { + recursiveProp: { + self: RecursiveObject; + array: RecursiveArray; + tuple: RecursiveTuple; + union: RecursiveUnion; + }; + children: RecursiveObject[]; + tuple: RecursiveTuple; + array: RecursiveArray; + union: RecursiveUnion; + } + + const schemaArray: DPE.DataParser = DPE.array( + DPE.union([ + DPE.string(), + DPE.lazy(() => schemaArray), + DPE.lazy(() => schema), + ]), + ).contract(); + + const schemaTuple: DPE.DataParser = DPE.tuple([ + DPE.string(), + DPE.lazy(() => schema), + DPE.union([ + DPE.lazy(() => schemaTuple), + DPE.lazy(() => schemaUnion), + DPE.string(), + ]).array(), + ]).contract(); + + const schemaUnion: DPE.DataParser = DPE.union([ + DPE.string(), + DPE.lazy(() => schema), + DPE.lazy(() => schemaTuple), + DPE.array(DPE.lazy(() => schemaUnion)), + ]).contract(); + + const schema: DPE.DataParser = DPE.object({ + recursiveProp: DPE.object({ + self: DPE.lazy(() => schema), + array: schemaArray, + tuple: schemaTuple, + union: schemaUnion, + }), + children: DPE.array(DPE.lazy(() => schema)), + tuple: schemaTuple, + array: schemaArray, + union: schemaUnion, + }).contract(); + + expect( + render( + schema, + { + constName: "complexRecursiveParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript: { + identifier: "ComplexRecursive", + transformers: tsDefaultTransformers, + }, + }, + ), + ).toMatchSnapshot(); + }); + + it("renders checked dataParsers in normal and extended modes", () => { + const checkedSchema = DP.object({ + startAt: DP.time().addChecker( + DP.checkerTimeMin(DDate.createTime(1000, "millisecond")), + DP.checkerTimeMax(DDate.createTime(5000, "millisecond")), + ), + name: DP.string().addChecker(DP.checkerStringMin(2)), + count: DP.number().addChecker( + DP.checkerInt(), + DP.checkerNumberMin(1), + ), + }); + const checkedExtendedSchema = DPE.object({ + startAt: DPE + .time() + .min(DDate.createTime(250, "millisecond")), + tags: DPE + .string() + .min(1) + .array() + .min(1), + }); + + expect( + render( + checkedSchema, + { + constName: "checkedParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript: { + identifier: "Checked", + transformers: tsDefaultTransformers, + }, + }, + ), + ).toMatchSnapshot(); + + expect( + render( + checkedExtendedSchema, + { + constName: "checkedExtendedParser", + exportMode: "extended", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript: { + identifier: "CheckedExtended", + transformers: tsDefaultTransformers, + }, + }, + ), + ).toMatchSnapshot(); + }); +}); From a54ab392c5b59cd8d0bad9a00001d13341c7630c Mon Sep 17 00:00:00 2001 From: ZeRiix Date: Tue, 19 May 2026 16:47:41 +0200 Subject: [PATCH 04/16] feat(06): add const name and override transformer support --- scripts/toDataParser/override.ts | 75 +++++++++++++++++++ tests/toDataParser/override.test.ts | 111 ++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 scripts/toDataParser/override.ts create mode 100644 tests/toDataParser/override.test.ts diff --git a/scripts/toDataParser/override.ts b/scripts/toDataParser/override.ts new file mode 100644 index 0000000..e45f24f --- /dev/null +++ b/scripts/toDataParser/override.ts @@ -0,0 +1,75 @@ +import { dataParserBaseInit } from "@duplojs/utils/dataParser"; +import { type CallExpression } from "typescript"; +import { type TransformerBuildFunction } from "./dataParserTransformer"; + +declare module "@duplojs/utils/dataParser" { + interface DataParserBase { + + /** + * @deprecated this method mutated the dataParser by adding an identifier + */ + setConstName(input: string): this; + addConstName(input: string): this; + + /** + * @deprecated this method mutated the dataParser by adding an override transformer + */ + setOverrideDataParserTransformer( + transformer: CallExpression | TransformerBuildFunction | null, + ): this; + addOverrideDataParserTransformer( + transformer: CallExpression | TransformerBuildFunction | null, + ): this; + } + + interface DataParserDefinition { + constName?: string; + overrideDataParserTransformer?: TransformerBuildFunction; + } +} + +dataParserBaseInit.overrideHandler.setMethod( + "setConstName", + (schema, constName) => { + schema.definition.constName = constName; + + return schema; + }, +); + +dataParserBaseInit.overrideHandler.setMethod( + "addConstName", + (schema, identifier) => { + const newSchema = schema.clone(); + + newSchema.setConstName(identifier); + + return newSchema; + }, +); + +dataParserBaseInit.overrideHandler.setMethod( + "setOverrideDataParserTransformer", + (schema, overrideTransformer) => { + if (overrideTransformer) { + schema.definition.overrideDataParserTransformer = typeof overrideTransformer === "function" + ? overrideTransformer + : (__, { success }) => success(overrideTransformer); + } else { + schema.definition.overrideDataParserTransformer = undefined; + } + + return schema; + }, +); + +dataParserBaseInit.overrideHandler.setMethod( + "addOverrideDataParserTransformer", + (schema, overrideTransformer) => { + const newSchema = schema.clone(); + + newSchema.setOverrideDataParserTransformer(overrideTransformer); + + return newSchema; + }, +); diff --git a/tests/toDataParser/override.test.ts b/tests/toDataParser/override.test.ts new file mode 100644 index 0000000..8a81b2c --- /dev/null +++ b/tests/toDataParser/override.test.ts @@ -0,0 +1,111 @@ +import "@scripts/toDataParser/override"; +import { DP, DPE, justReturn } from "@duplojs/utils"; +import { factory } from "typescript"; +import { defaultCheckerTransformers, defaultTransformers, render } from "@scripts/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; +import { type TransformerBuildFunction } from "@scripts/toDataParser/dataParserTransformer"; + +describe("override", () => { + it("setConstName", () => { + const schema = DP.string(); + + expect(schema.definition.constName).toBe(undefined); + + schema.setConstName("test"); + + expect(schema.definition.constName).toBe("test"); + }); + + it("addConstName", () => { + const schema = DP.string(); + + expect(schema.definition.constName).toBe(undefined); + + const newSchema = schema.addConstName("test"); + + expect(schema.definition.constName).toBe(undefined); + expect(newSchema.definition.constName).toBe("test"); + + const newSchemaWithChecker = newSchema.addChecker(DP.checkerRefine(justReturn(true))); + + schema.setConstName("test1"); + + expect(newSchemaWithChecker.definition.constName).toBe("test"); + }); + + it("setOverrideDataParserTransformer", () => { + const schema = DP.string(); + + expect(schema.definition.overrideDataParserTransformer).toBe(undefined); + + schema.setOverrideDataParserTransformer( + factory.createCallExpression( + factory.createIdentifier("test"), + undefined, + [], + ), + ); + + expect(typeof schema.definition.overrideDataParserTransformer).toBe("function"); + }); + + it("addOverrideDataParserTransformer", () => { + const schema = DP.string(); + const overrideTransformer: TransformerBuildFunction = (__, { success }) => success( + factory.createCallExpression( + factory.createIdentifier("test"), + undefined, + [], + ), + ); + + expect(schema.definition.overrideDataParserTransformer).toBe(undefined); + + const newSchema = schema.addOverrideDataParserTransformer(overrideTransformer); + + expect(schema.definition.overrideDataParserTransformer).toBe(undefined); + expect(newSchema.definition.overrideDataParserTransformer).toBe(overrideTransformer); + + const newSchemaWithChecker = newSchema.addChecker(DP.checkerRefine(justReturn(true))); + + schema.setOverrideDataParserTransformer( + factory.createCallExpression( + factory.createIdentifier("test1"), + undefined, + [], + ), + ); + + expect(newSchemaWithChecker.definition.overrideDataParserTransformer).toBe(overrideTransformer); + }); + + it("uses overrideDataParserTransformer in render", () => { + const schema = DPE.string().addOverrideDataParserTransformer( + (__, { success, dependencyIdentifier }) => success( + factory.createCallExpression( + factory.createPropertyAccessExpression( + dependencyIdentifier, + factory.createIdentifier("number"), + ), + undefined, + [], + ), + ), + ); + + const result = render( + schema, + { + constName: "overrideParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript: { + identifier: "OverrideParser", + transformers: tsDefaultTransformers, + }, + }, + ); + + expect(result).toContain("export const overrideParser = DP.number();"); + }); +}); From 7cfe9aff5bc2c114979d8eabefeb4ca6a72b8707 Mon Sep 17 00:00:00 2001 From: ZeRiix Date: Tue, 19 May 2026 16:47:50 +0200 Subject: [PATCH 05/16] feat(06): add toDataParser integration test --- .../__snapshots__/index.test.ts.snap | 7 +++ integration/toDataParser/index.test.ts | 51 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 integration/toDataParser/__snapshots__/index.test.ts.snap create mode 100644 integration/toDataParser/index.test.ts diff --git a/integration/toDataParser/__snapshots__/index.test.ts.snap b/integration/toDataParser/__snapshots__/index.test.ts.snap new file mode 100644 index 0000000..c47c743 --- /dev/null +++ b/integration/toDataParser/__snapshots__/index.test.ts.snap @@ -0,0 +1,7 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`integration 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const userProfileParser = DP.object({ id: DP.templateLiteral(["user-", DP.number(), "-db1"]), name: DP.string({ checkers: [DP.checkerStringMin(2)] }), email: DP.string({ checkers: [DP.checkerEmail()] }), role: DP.literal(["admin", "editor", "viewer"]), age: DP.optional(DP.number({ coerce: true, checkers: [DP.checkerNumberMin(0)] })), contact: DP.union([DP.object({ phone: DP.string({ checkers: [DP.checkerRegex(/^[+\\d][\\d\\s-]{5,}$/)] }) }), DP.object({ email: DP.string({ checkers: [DP.checkerEmail()] }) })]), address: DP.object({ street: DP.string(), city: DP.string(), zip: DP.string({ checkers: [DP.checkerRegex(/^\\d{5}$/)] }), country: DP.literal(["FR"]) }), roles: DP.array(DP.literal(["admin", "editor", "viewer"]), { checkers: [DP.checkerArrayMin(1)] }), preferences: DP.nullable(DP.object({ theme: DP.literal(["light", "dark"]), newsletter: DP.boolean() })), metadata: DP.record(DP.string(), DP.string()), location: DP.tuple([DP.number(), DP.number()], { rest: DP.number() }), createdAt: DP.date({ coerce: true }), startAt: DP.time() });" +`; diff --git a/integration/toDataParser/index.test.ts b/integration/toDataParser/index.test.ts new file mode 100644 index 0000000..59b6753 --- /dev/null +++ b/integration/toDataParser/index.test.ts @@ -0,0 +1,51 @@ +import { DPE } from "@duplojs/utils"; +import { defaultCheckerTransformers, defaultTransformers, render } from "@duplojs/data-parser-tools/toDataParser"; +import { defaultTransformers as tsDefaultTransformers } from "@duplojs/data-parser-tools/toTypescript"; + +it("integration", () => { + const userSchema = DPE.object({ + id: DPE.templateLiteral(["user-", DPE.number(), "-db1"]), + name: DPE.string().min(2), + email: DPE.email(), + role: DPE.literal(["admin", "editor", "viewer"]), + age: DPE.coerce.number().min(0).optional(), + contact: DPE.union([ + DPE.object({ + phone: DPE.string().regex(/^[+\d][\d\s-]{5,}$/), + }), + DPE.object({ + email: DPE.email(), + }), + ]), + address: DPE.object({ + street: DPE.string(), + city: DPE.string(), + zip: DPE.string().regex(/^\d{5}$/), + country: DPE.literal("FR"), + }), + roles: DPE.literal(["admin", "editor", "viewer"]).array().min(1), + preferences: DPE.object({ + theme: DPE.literal(["light", "dark"]), + newsletter: DPE.boolean(), + }).nullable(), + metadata: DPE.record(DPE.string(), DPE.string()), + location: DPE.tuple([DPE.number(), DPE.number()], { rest: DPE.number() }), + createdAt: DPE.date({ coerce: true }), + startAt: DPE.time(), + }).addConstName("userProfileParser"); + + const result = render( + userSchema, + { + constName: "userProfileParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript: { + identifier: "UserProfile", + transformers: tsDefaultTransformers, + }, + }, + ); + + expect(result).toMatchSnapshot(); +}); From ded5b74793a67a426eabf610a444fb1607382b66 Mon Sep 17 00:00:00 2001 From: ZeRiix Date: Tue, 19 May 2026 16:48:19 +0200 Subject: [PATCH 06/16] feat(06): include toDataParser coverage paths --- vitest.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vitest.config.js b/vitest.config.js index 70d35f4..ba66b0d 100644 --- a/vitest.config.js +++ b/vitest.config.js @@ -15,7 +15,9 @@ export default defineConfig({ reportsDirectory: "coverage", include: [ "scripts/toTypescript/transformer/defaults", - "scripts/toJsonSchema/transformer/defaults" + "scripts/toJsonSchema/transformer/defaults", + "scripts/toDataParser/checkerTransformer/defaults", + "scripts/toDataParser/dataParserTransformer/defaults" ], exclude: [ "**/*.test.ts", From 90284870d15fc55da91869e0bdd6ebbba54df9d3 Mon Sep 17 00:00:00 2001 From: ZeRiix Date: Tue, 19 May 2026 16:48:27 +0200 Subject: [PATCH 07/16] feat(06): cleanup unused imports in existing transformers --- .vscode/settings.json | 5 +++++ scripts/toJsonSchema/transformer/defaults/literal.ts | 2 +- scripts/toJsonSchema/transformer/transformer.ts | 2 +- scripts/toTypescript/render.ts | 2 +- scripts/toTypescript/transformer/index.ts | 1 + 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 679e7f3..4b23af4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -20,4 +20,9 @@ }, "js/ts.tsdk.path": "node_modules/typescript/lib", + "js/ts.format.enabled": false, + "js/ts.tsdk.promptToUseWorkspaceVersion": true, + "cSpell.words": [ + "SDPE" + ], } \ No newline at end of file diff --git a/scripts/toJsonSchema/transformer/defaults/literal.ts b/scripts/toJsonSchema/transformer/defaults/literal.ts index 911ae8b..b56179b 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 SupportedVersions, type SupportedVersionsUrl } from "../create"; +import { createTransformer, type SupportedVersions } from "../create"; type JsonPrimitive = string | number | boolean | null; type JsonType = "string" | "number" | "integer" | "boolean" | "null"; diff --git a/scripts/toJsonSchema/transformer/transformer.ts b/scripts/toJsonSchema/transformer/transformer.ts index edf651d..c6ff83b 100644 --- a/scripts/toJsonSchema/transformer/transformer.ts +++ b/scripts/toJsonSchema/transformer/transformer.ts @@ -1,4 +1,4 @@ -import { A, E, justExec, justReturn, unwrap, whenElse, type DP } from "@duplojs/utils"; +import { A, E, justExec, unwrap, type DP } from "@duplojs/utils"; import { type MapContext, type DataParserNotSupportedEither, diff --git a/scripts/toTypescript/render.ts b/scripts/toTypescript/render.ts index 679bd32..b40d1a2 100644 --- a/scripts/toTypescript/render.ts +++ b/scripts/toTypescript/render.ts @@ -1,4 +1,4 @@ -import { DP, unwrap, E, pipe, G, A, S, kindHeritage } from "@duplojs/utils"; +import { DP, unwrap, E, pipe, A, S, kindHeritage } from "@duplojs/utils"; import { type DataParserErrorEither, type DataParserNotSupportedEither, transformer, type MapContext, type TransformerMode, type TransformerHook, type createTransformer, type MapImportType } from "./transformer"; import { createPrinter, createSourceFile, EmitHint, factory, ScriptKind, ScriptTarget, SyntaxKind } from "typescript"; import { createToTypescriptKind } from "./kind"; diff --git a/scripts/toTypescript/transformer/index.ts b/scripts/toTypescript/transformer/index.ts index c894811..9d575e8 100644 --- a/scripts/toTypescript/transformer/index.ts +++ b/scripts/toTypescript/transformer/index.ts @@ -3,4 +3,5 @@ export * from "./transformer"; export * from "./hook"; export * from "./defaults"; export * from "./includesUndefinedTypeNode"; +export * from "./importTypesTransformer"; export { defaultTransformers } from "./defaults"; From 2584da657528865f86733005b146a4b9bf764071 Mon Sep 17 00:00:00 2001 From: ZeRiix Date: Wed, 20 May 2026 16:49:50 +0200 Subject: [PATCH 08/16] feat(06): add indent dataParser --- eslint.config.js | 4 +- .../toDataParser/__snapshots__/basic.gen.ts | 38 ++++ .../__snapshots__/index.test.ts.snap | 7 - .../__snapshots__/recursive.gen.ts | 43 +++++ .../__snapshots__/withConstName.gen.ts | 10 + integration/toDataParser/index.test.ts | 177 +++++++++++++----- .../dataParserTransformer/create.ts | 6 +- .../dataParserTransformer/defaults/file.ts | 8 +- .../dataParserTransformer/defaults/literal.ts | 6 +- .../dataParserTransformer/defaults/object.ts | 6 +- .../defaults/templateLiteral.ts | 6 +- .../dataParserTransformer/defaults/tuple.ts | 6 +- .../dataParserTransformer/defaults/union.ts | 6 +- .../dataParserTransformer/transformer.ts | 57 ++++-- scripts/toDataParser/override.ts | 8 +- scripts/toDataParser/render.ts | 2 + .../__snapshots__/render.test.ts.snap | 71 ++++++- .../__snapshots__/file.test.ts.snap | 8 +- .../__snapshots__/literal.test.ts.snap | 10 +- .../__snapshots__/object.test.ts.snap | 5 +- .../templateLiteral.test.ts.snap | 19 +- .../__snapshots__/time.test.ts.snap | 5 +- .../__snapshots__/union.test.ts.snap | 5 +- tests/toDataParser/render.test.ts | 31 +++ 24 files changed, 444 insertions(+), 100 deletions(-) create mode 100644 integration/toDataParser/__snapshots__/basic.gen.ts delete mode 100644 integration/toDataParser/__snapshots__/index.test.ts.snap create mode 100644 integration/toDataParser/__snapshots__/recursive.gen.ts create mode 100644 integration/toDataParser/__snapshots__/withConstName.gen.ts diff --git a/eslint.config.js b/eslint.config.js index 49f2e94..9a37b93 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -11,7 +11,7 @@ export default [ }, }, files: ["**/*.test.ts", "**/*.bench.ts", "test/**/*.ts"], - ignores: ["**/*.d.ts"] + ignores: ["**/*.d.ts", "**/*.gen.ts"] }, { ...duplojsEslintOpen, @@ -23,7 +23,7 @@ export default [ }, }, files: ["**/*.ts"], - ignores: ["**/*.test.ts", "**/*.bench.ts", "test/**/*.ts", "**/*.d.ts"], + ignores: ["**/*.test.ts", "**/*.bench.ts", "test/**/*.ts", "**/*.d.ts", "**/*.gen.ts"], }, { ignores: ["coverage", "dist"] diff --git a/integration/toDataParser/__snapshots__/basic.gen.ts b/integration/toDataParser/__snapshots__/basic.gen.ts new file mode 100644 index 0000000..3df86ec --- /dev/null +++ b/integration/toDataParser/__snapshots__/basic.gen.ts @@ -0,0 +1,38 @@ +import * as DP from "@duplojs/utils/dataParser"; + +export const userProfileParser = DP.object({ + id: DP.templateLiteral(["user-", DP.number(), "-db1"]), + name: DP.string({ checkers: [DP.checkerStringMin(2)] }), + email: DP.string({ checkers: [DP.checkerEmail()] }), + role: DP.literal(["admin", "editor", "viewer"]), + age: DP.optional(DP.number({ + coerce: true, + checkers: [ + DP.checkerNumberMin(0), + DP.checkerNumberMax(80) + ] + })), + contact: DP.union([ + DP.object({ + phone: DP.string({ checkers: [DP.checkerRegex(/^[+\d][\d\s-]{5,}$/)] }) + }), + DP.object({ + email: DP.string({ checkers: [DP.checkerEmail()] }) + }) + ]), + address: DP.object({ + street: DP.string(), + city: DP.string(), + zip: DP.string({ checkers: [DP.checkerRegex(/^\d{5}$/)] }), + country: DP.literal(["FR"]) + }), + roles: DP.array(DP.literal(["admin", "editor", "viewer"]), { checkers: [DP.checkerArrayMin(1)] }), + preferences: DP.nullable(DP.object({ + theme: DP.literal(["light", "dark"]), + newsletter: DP.boolean() + })), + metadata: DP.record(DP.string(), DP.string()), + location: DP.tuple([DP.number(), DP.number()], { rest: DP.number() }), + createdAt: DP.date({ coerce: true }), + startAt: DP.time() +}); \ No newline at end of file diff --git a/integration/toDataParser/__snapshots__/index.test.ts.snap b/integration/toDataParser/__snapshots__/index.test.ts.snap deleted file mode 100644 index c47c743..0000000 --- a/integration/toDataParser/__snapshots__/index.test.ts.snap +++ /dev/null @@ -1,7 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`integration 1`] = ` -"import * as DP from "@duplojs/utils/dataParser"; - -export const userProfileParser = DP.object({ id: DP.templateLiteral(["user-", DP.number(), "-db1"]), name: DP.string({ checkers: [DP.checkerStringMin(2)] }), email: DP.string({ checkers: [DP.checkerEmail()] }), role: DP.literal(["admin", "editor", "viewer"]), age: DP.optional(DP.number({ coerce: true, checkers: [DP.checkerNumberMin(0)] })), contact: DP.union([DP.object({ phone: DP.string({ checkers: [DP.checkerRegex(/^[+\\d][\\d\\s-]{5,}$/)] }) }), DP.object({ email: DP.string({ checkers: [DP.checkerEmail()] }) })]), address: DP.object({ street: DP.string(), city: DP.string(), zip: DP.string({ checkers: [DP.checkerRegex(/^\\d{5}$/)] }), country: DP.literal(["FR"]) }), roles: DP.array(DP.literal(["admin", "editor", "viewer"]), { checkers: [DP.checkerArrayMin(1)] }), preferences: DP.nullable(DP.object({ theme: DP.literal(["light", "dark"]), newsletter: DP.boolean() })), metadata: DP.record(DP.string(), DP.string()), location: DP.tuple([DP.number(), DP.number()], { rest: DP.number() }), createdAt: DP.date({ coerce: true }), startAt: DP.time() });" -`; diff --git a/integration/toDataParser/__snapshots__/recursive.gen.ts b/integration/toDataParser/__snapshots__/recursive.gen.ts new file mode 100644 index 0000000..728ed2d --- /dev/null +++ b/integration/toDataParser/__snapshots__/recursive.gen.ts @@ -0,0 +1,43 @@ +import * as DP from "@duplojs/utils/dataParser"; + +export type RecursiveType0 = { + name: string; + children: RecursiveType0[]; + comment: { + id: string; + replies: RecursiveType1[]; + }; + meta: [ + string, + RecursiveType2[] + ]; +}; + +export type RecursiveType1 = { + id: string; + replies: RecursiveType1[]; +}; + +export type RecursiveType2 = [ + string, + RecursiveType2[] +]; + +export type RecursiveNode = RecursiveType0; + +export const recursiveDataParser1: DP.DataParser = DP.object({ + id: DP.string(), + replies: DP.array(DP.lazy(() => recursiveDataParser1)) +}); + +export const recursiveDataParser2: DP.DataParser = DP.tuple([DP.string(), DP.array(DP.lazy(() => recursiveDataParser2))]); + +export const recursiveNodeDataParser: DP.DataParser = DP.object({ + name: DP.string(), + children: DP.array(DP.lazy(() => recursiveNodeDataParser)), + comment: DP.object({ + id: DP.string(), + replies: DP.array(DP.lazy(() => recursiveDataParser1)) + }), + meta: DP.tuple([DP.string(), DP.array(DP.lazy(() => recursiveDataParser2))]) +}); \ No newline at end of file diff --git a/integration/toDataParser/__snapshots__/withConstName.gen.ts b/integration/toDataParser/__snapshots__/withConstName.gen.ts new file mode 100644 index 0000000..f5ec1fb --- /dev/null +++ b/integration/toDataParser/__snapshots__/withConstName.gen.ts @@ -0,0 +1,10 @@ +import * as DP from "@duplojs/utils/dataParser"; + +export const userRoleDataParser = DP.literal(["admin", "editor", "viewer"]); + +export const userDataParser = DP.object({ + id: DP.templateLiteral(["user-", DP.number(), "-db1"]), + name: DP.string({ checkers: [DP.checkerStringMin(2)] }), + email: DP.string({ checkers: [DP.checkerEmail()] }), + role: userRoleDataParser +}); \ No newline at end of file diff --git a/integration/toDataParser/index.test.ts b/integration/toDataParser/index.test.ts index 59b6753..011dcf2 100644 --- a/integration/toDataParser/index.test.ts +++ b/integration/toDataParser/index.test.ts @@ -1,51 +1,140 @@ -import { DPE } from "@duplojs/utils"; +import { asserts, DPE, E, Path, S, unwrap } from "@duplojs/utils"; +import { SF } from "@duplojs/server-utils"; import { defaultCheckerTransformers, defaultTransformers, render } from "@duplojs/data-parser-tools/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@duplojs/data-parser-tools/toTypescript"; -it("integration", () => { - const userSchema = DPE.object({ - id: DPE.templateLiteral(["user-", DPE.number(), "-db1"]), - name: DPE.string().min(2), - email: DPE.email(), - role: DPE.literal(["admin", "editor", "viewer"]), - age: DPE.coerce.number().min(0).optional(), - contact: DPE.union([ - DPE.object({ - phone: DPE.string().regex(/^[+\d][\d\s-]{5,}$/), - }), - DPE.object({ - email: DPE.email(), +async function typedSnapshot(value: string, filePath: string) { + const absoluteFilePath = Path.resolveRelative([import.meta.dirname, filePath]); + + const exist = await SF.exists(absoluteFilePath); + + if (E.isLeft(exist)) { + const writeTextFileResult = await SF.writeTextFile(absoluteFilePath, value); + asserts(writeTextFileResult, E.isRight); + } + + const expected = await E.rightAsyncPipe( + absoluteFilePath, + SF.readTextFile, + S.trim, + ); + + asserts(expected, E.isRight); + + expect(value).toBe(unwrap(expected)); +} + +describe("integration", () => { + it("basic", async() => { + const userSchema = DPE.object({ + id: DPE.templateLiteral(["user-", DPE.number(), "-db1"]), + name: DPE.string().min(2), + email: DPE.email(), + role: DPE.literal(["admin", "editor", "viewer"]), + age: DPE + .coerce + .number() + .min(0) + .max(80) + .optional(), + contact: DPE.union([ + DPE.object({ + phone: DPE.string().regex(/^[+\d][\d\s-]{5,}$/), + }), + DPE.object({ + email: DPE.email(), + }), + ]), + address: DPE.object({ + street: DPE.string(), + city: DPE.string(), + zip: DPE.string().regex(/^\d{5}$/), + country: DPE.literal("FR"), }), - ]), - address: DPE.object({ - street: DPE.string(), - city: DPE.string(), - zip: DPE.string().regex(/^\d{5}$/), - country: DPE.literal("FR"), - }), - roles: DPE.literal(["admin", "editor", "viewer"]).array().min(1), - preferences: DPE.object({ - theme: DPE.literal(["light", "dark"]), - newsletter: DPE.boolean(), - }).nullable(), - metadata: DPE.record(DPE.string(), DPE.string()), - location: DPE.tuple([DPE.number(), DPE.number()], { rest: DPE.number() }), - createdAt: DPE.date({ coerce: true }), - startAt: DPE.time(), - }).addConstName("userProfileParser"); - - const result = render( - userSchema, - { - constName: "userProfileParser", - dataParserTransformers: defaultTransformers, - checkerTransformers: defaultCheckerTransformers, - toTypescript: { - identifier: "UserProfile", - transformers: tsDefaultTransformers, + roles: DPE.literal(["admin", "editor", "viewer"]).array().min(1), + preferences: DPE.object({ + theme: DPE.literal(["light", "dark"]), + newsletter: DPE.boolean(), + }).nullable(), + metadata: DPE.record(DPE.string(), DPE.string()), + location: DPE.tuple([DPE.number(), DPE.number()], { rest: DPE.number() }), + createdAt: DPE.date({ coerce: true }), + startAt: DPE.time(), + }).addConstName("userProfileParser"); + + const result = render( + userSchema, + { + constName: "userProfileParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript: { + identifier: "UserProfile", + transformers: tsDefaultTransformers, + }, }, - }, - ); + ); + + await typedSnapshot(result, "__snapshots__/basic.gen.ts"); + }); + + it("recursive", async() => { + const commentSchema: DPE.DataParser = DPE.object({ + id: DPE.string(), + replies: DPE.lazy(() => commentSchema).array(), + }); + + const metaSchema: DPE.DataParser = DPE.tuple([ + DPE.string(), + DPE.lazy(() => metaSchema).array(), + ]); + + const nodeSchema: DPE.DataParser = DPE.object({ + name: DPE.string(), + children: DPE.lazy(() => nodeSchema).array(), + comment: commentSchema, + meta: metaSchema, + }).addConstName("recursiveNodeDataParser"); + + const result = render( + nodeSchema, + { + constName: "recursiveNodeDataParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript: { + identifier: "RecursiveNode", + transformers: tsDefaultTransformers, + }, + }, + ); + + await typedSnapshot(result, "__snapshots__/recursive.gen.ts"); + }); + + it("divide with constName", async() => { + const roleDataParser = DPE.literal(["admin", "editor", "viewer"]).addConstName("userRoleDataParser"); + + const userDataParser = DPE.object({ + id: DPE.templateLiteral(["user-", DPE.number(), "-db1"]), + name: DPE.string().min(2), + email: DPE.email(), + role: roleDataParser, + }).addConstName("userDataParser"); + + const result = render( + userDataParser, + { + constName: "userDataParser", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript: { + identifier: "UserProfile", + transformers: tsDefaultTransformers, + }, + }, + ); - expect(result).toMatchSnapshot(); + await typedSnapshot(result, "__snapshots__/withConstName.gen.ts"); + }); }); diff --git a/scripts/toDataParser/dataParserTransformer/create.ts b/scripts/toDataParser/dataParserTransformer/create.ts index 17ad9cd..43bdeef 100644 --- a/scripts/toDataParser/dataParserTransformer/create.ts +++ b/scripts/toDataParser/dataParserTransformer/create.ts @@ -35,19 +35,21 @@ export interface TransformerParams { readonly dependencyIdentifier: Identifier; readonly context: MapContext; readonly importClause: MapImportClause; + readonly indent: boolean; transformer( dataParser: DP.DataParser, ): MaybeTransformerEither; success( - result: CallExpression, + result: CallExpression | Identifier, ): TransformerSuccessEither; buildError(): DataParserErrorEither; addImportClause(path: string, clause: string): void; getDefinition( - customProperties?: readonly PropertyAssignment[] + customProperties?: readonly PropertyAssignment[], + indent?: boolean, ): readonly [ObjectLiteralExpression] | readonly [] | DataParserGetDefinitionErrorEither; } diff --git a/scripts/toDataParser/dataParserTransformer/defaults/file.ts b/scripts/toDataParser/dataParserTransformer/defaults/file.ts index a3f7ded..335d32a 100644 --- a/scripts/toDataParser/dataParserTransformer/defaults/file.ts +++ b/scripts/toDataParser/dataParserTransformer/defaults/file.ts @@ -1,4 +1,4 @@ -import { E, justExec, pipe } from "@duplojs/utils"; +import { A, E, justExec, pipe } from "@duplojs/utils"; import { createTransformer } from "../create"; import { factory, type PropertyAssignment } from "typescript"; import { SDP } from "@duplojs/server-utils"; @@ -12,6 +12,7 @@ export const fileTransformer = createTransformer( dependencyIdentifier, getDefinition, addImportClause, + indent, }, ) => { const definition = getDefinition(); @@ -85,7 +86,10 @@ export const fileTransformer = createTransformer( ), undefined, [ - factory.createObjectLiteralExpression(dataParserFileParams), + factory.createObjectLiteralExpression( + dataParserFileParams, + indent && A.minElements(dataParserFileParams, 2), + ), ...definition, ], ), diff --git a/scripts/toDataParser/dataParserTransformer/defaults/literal.ts b/scripts/toDataParser/dataParserTransformer/defaults/literal.ts index 694a58f..07ec58f 100644 --- a/scripts/toDataParser/dataParserTransformer/defaults/literal.ts +++ b/scripts/toDataParser/dataParserTransformer/defaults/literal.ts @@ -10,6 +10,7 @@ export const literalTransformer = createTransformer( success, dependencyIdentifier, getDefinition, + indent, }, ) => { const definition = getDefinition(); @@ -58,7 +59,10 @@ export const literalTransformer = createTransformer( ), undefined, [ - factory.createArrayLiteralExpression(values), + factory.createArrayLiteralExpression( + values, + indent && A.minElements(values, 4), + ), ...definition, ], ), diff --git a/scripts/toDataParser/dataParserTransformer/defaults/object.ts b/scripts/toDataParser/dataParserTransformer/defaults/object.ts index 67513f8..3bf0ce3 100644 --- a/scripts/toDataParser/dataParserTransformer/defaults/object.ts +++ b/scripts/toDataParser/dataParserTransformer/defaults/object.ts @@ -11,6 +11,7 @@ export const objectTransformer = createTransformer( dependencyIdentifier, getDefinition, transformer, + indent, }, ) => { const shape = pipe( @@ -56,7 +57,10 @@ export const objectTransformer = createTransformer( ), undefined, [ - factory.createObjectLiteralExpression(shape), + factory.createObjectLiteralExpression( + shape, + indent, + ), ...definition, ], ), diff --git a/scripts/toDataParser/dataParserTransformer/defaults/templateLiteral.ts b/scripts/toDataParser/dataParserTransformer/defaults/templateLiteral.ts index c4a586f..bbc589c 100644 --- a/scripts/toDataParser/dataParserTransformer/defaults/templateLiteral.ts +++ b/scripts/toDataParser/dataParserTransformer/defaults/templateLiteral.ts @@ -11,6 +11,7 @@ export const templateLiteralTransformer = createTransformer( dependencyIdentifier, getDefinition, transformer, + indent, }, ) => { const parts = A.reduce( @@ -78,7 +79,10 @@ export const templateLiteralTransformer = createTransformer( ), undefined, [ - factory.createArrayLiteralExpression(parts), + factory.createArrayLiteralExpression( + parts, + indent && A.minElements(parts, 4), + ), ...definition, ], ), diff --git a/scripts/toDataParser/dataParserTransformer/defaults/tuple.ts b/scripts/toDataParser/dataParserTransformer/defaults/tuple.ts index 5076d7c..fb8cdc7 100644 --- a/scripts/toDataParser/dataParserTransformer/defaults/tuple.ts +++ b/scripts/toDataParser/dataParserTransformer/defaults/tuple.ts @@ -11,6 +11,7 @@ export const tupleTransformer = createTransformer( dependencyIdentifier, getDefinition, transformer, + indent, }, ) => { const shape = A.reduce( @@ -64,7 +65,10 @@ export const tupleTransformer = createTransformer( ), undefined, [ - factory.createArrayLiteralExpression(shape), + factory.createArrayLiteralExpression( + shape, + indent && A.minElements(shape, 3), + ), ...definition, ], ), diff --git a/scripts/toDataParser/dataParserTransformer/defaults/union.ts b/scripts/toDataParser/dataParserTransformer/defaults/union.ts index fa01b1d..5b8284e 100644 --- a/scripts/toDataParser/dataParserTransformer/defaults/union.ts +++ b/scripts/toDataParser/dataParserTransformer/defaults/union.ts @@ -11,6 +11,7 @@ export const unionTransformer = createTransformer( getDefinition, success, transformer, + indent, }, ) => { const options = A.reduce( @@ -45,7 +46,10 @@ export const unionTransformer = createTransformer( ), undefined, [ - factory.createArrayLiteralExpression(options), + factory.createArrayLiteralExpression( + options, + indent, + ), ...definition, ], ), diff --git a/scripts/toDataParser/dataParserTransformer/transformer.ts b/scripts/toDataParser/dataParserTransformer/transformer.ts index 26f577e..1b00f65 100644 --- a/scripts/toDataParser/dataParserTransformer/transformer.ts +++ b/scripts/toDataParser/dataParserTransformer/transformer.ts @@ -4,30 +4,33 @@ import { factory, type PropertyAssignment, type CallExpression, type Identifier import type { TransformerHook } from "./hook"; import { type createCheckerTransformer, checkerTransformer } from "../checkerTransformer"; -export function getDefinitionDataParser( - dataParser: DP.DataParser, - checkerTransformers: readonly ReturnType[], - customProperties?: readonly PropertyAssignment[], -) { +export interface getDefinitionDataParserParams { + readonly dataParser: DP.DataParser; + readonly checkerTransformers: readonly ReturnType[]; + readonly customProperties: readonly PropertyAssignment[]; + readonly indent: boolean; +} + +export function getDefinitionDataParser(params: getDefinitionDataParserParams) { const propertyAssignments: PropertyAssignment[] = []; - if (dataParser.definition.errorMessage) { + if (params.dataParser.definition.errorMessage) { propertyAssignments.push( factory.createPropertyAssignment( factory.createIdentifier("errorMessage"), - factory.createStringLiteral(dataParser.definition.errorMessage), + factory.createStringLiteral(params.dataParser.definition.errorMessage), ), ); } - if (customProperties) { - propertyAssignments.push(...customProperties); + if (A.minElements(params.customProperties, 1)) { + propertyAssignments.push(...params.customProperties); } - if (A.minElements(dataParser.definition.checkers, 1)) { + if (A.minElements(params.dataParser.definition.checkers, 1)) { const checkers = A.reduce( - dataParser.definition.checkers, + params.dataParser.definition.checkers, A.reduceFrom([]), ({ element, lastValue, nextPush, exit }) => pipe( - checkerTransformer(element, { transformers: checkerTransformers }), + checkerTransformer(element, { transformers: params.checkerTransformers }), E.whenIsRight( (value) => nextPush(lastValue, value), ), @@ -40,7 +43,7 @@ export function getDefinitionDataParser( if (E.isLeft(checkers)) { return E.left("buildDataParserGetDefinitionError", { - dataParser, + dataParser: params.dataParser, error: checkers, }); } @@ -48,13 +51,21 @@ export function getDefinitionDataParser( propertyAssignments.push( factory.createPropertyAssignment( factory.createIdentifier("checkers"), - factory.createArrayLiteralExpression(checkers), + factory.createArrayLiteralExpression( + checkers, + params.indent && A.minElements(checkers, 2), + ), ), ); } return A.minElements(propertyAssignments, 1) - ? [factory.createObjectLiteralExpression(propertyAssignments)] + ? [ + factory.createObjectLiteralExpression( + propertyAssignments, + params.indent && A.minElements(propertyAssignments, 2), + ), + ] : []; } @@ -67,6 +78,7 @@ export interface TransformerFunctionParams { readonly hooks: readonly TransformerHook[]; readonly recursiveDataParsers: DP.DataParser[]; readonly importClause: MapImportClause; + readonly indent: boolean; } export function transformer( @@ -140,12 +152,18 @@ export function transformer( }, context: params.context, dependencyIdentifier: params.dependencyIdentifier, + indent: params.indent, buildError() { return E.left("buildDataParserError", currentDataParser); }, importClause: params.importClause, - getDefinition(customProperties) { - return getDefinitionDataParser(currentDataParser, params.checkerTransformers, customProperties); + getDefinition(customProperties = [], indent = true) { + return getDefinitionDataParser({ + dataParser: currentDataParser, + checkerTransformers: params.checkerTransformers, + customProperties, + indent: indent && params.indent, + }); }, addImportClause(path, clause) { params.importClause.set(path, clause); @@ -206,5 +224,8 @@ export function transformer( ); } - return result; + return E.right( + "buildSuccess", + unwrap(result), + ); } diff --git a/scripts/toDataParser/override.ts b/scripts/toDataParser/override.ts index e45f24f..e37acf7 100644 --- a/scripts/toDataParser/override.ts +++ b/scripts/toDataParser/override.ts @@ -1,6 +1,6 @@ import { dataParserBaseInit } from "@duplojs/utils/dataParser"; -import { type CallExpression } from "typescript"; -import { type TransformerBuildFunction } from "./dataParserTransformer"; +import type { CallExpression, Identifier } from "typescript"; +import type { TransformerBuildFunction } from "./dataParserTransformer"; declare module "@duplojs/utils/dataParser" { interface DataParserBase { @@ -15,10 +15,10 @@ declare module "@duplojs/utils/dataParser" { * @deprecated this method mutated the dataParser by adding an override transformer */ setOverrideDataParserTransformer( - transformer: CallExpression | TransformerBuildFunction | null, + transformer: CallExpression | Identifier | TransformerBuildFunction | null, ): this; addOverrideDataParserTransformer( - transformer: CallExpression | TransformerBuildFunction | null, + transformer: CallExpression | Identifier | TransformerBuildFunction | null, ): this; } diff --git a/scripts/toDataParser/render.ts b/scripts/toDataParser/render.ts index b93e1a8..a198980 100644 --- a/scripts/toDataParser/render.ts +++ b/scripts/toDataParser/render.ts @@ -41,6 +41,7 @@ export interface RenderParams { readonly context?: MapContext; readonly hooks?: readonly TransformerHook[]; readonly importClause?: MapImportClause; + readonly indent?: boolean; readonly toTypescript: { readonly identifier: string; @@ -149,6 +150,7 @@ export function render(dataParser: DP.DataParser, params: RenderParams) { importClause, dependencyIdentifier, hooks: params.hooks ?? [], + indent: params.indent ?? true, }, ); diff --git a/tests/toDataParser/__snapshots__/render.test.ts.snap b/tests/toDataParser/__snapshots__/render.test.ts.snap index 3fb47d3..0f0e1ba 100644 --- a/tests/toDataParser/__snapshots__/render.test.ts.snap +++ b/tests/toDataParser/__snapshots__/render.test.ts.snap @@ -9,7 +9,9 @@ export type RecursiveType0 = { export type RecursiveNode = RecursiveType0; -export const recursiveDataParser0: DP.DataParser = DP.object({ next: DP.lazy(() => recursiveDataParser0) }); +export const recursiveDataParser0: DP.DataParser = DP.object({ + next: DP.lazy(() => recursiveDataParser0) +}); export const recursiveNodeParser = recursiveDataParser0;" `; @@ -19,7 +21,17 @@ exports[`render > renders checked dataParsers in normal and extended modes 1`] = import * as DDate from "@duplojs/utils/date"; -export const checkedParser = DP.object({ startAt: DP.time({ checkers: [DP.checkerTimeMin(DDate.createTime(1000, "millisecond")), DP.checkerTimeMax(DDate.createTime(5000, "millisecond"))] }), name: DP.string({ checkers: [DP.checkerStringMin(2)] }), count: DP.number({ checkers: [DP.checkerInt(), DP.checkerNumberMin(1)] }) });" +export const checkedParser = DP.object({ + startAt: DP.time({ checkers: [ + DP.checkerTimeMin(DDate.createTime(1000, "millisecond")), + DP.checkerTimeMax(DDate.createTime(5000, "millisecond")) + ] }), + name: DP.string({ checkers: [DP.checkerStringMin(2)] }), + count: DP.number({ checkers: [ + DP.checkerInt(), + DP.checkerNumberMin(1) + ] }) +});" `; exports[`render > renders checked dataParsers in normal and extended modes 2`] = ` @@ -29,7 +41,10 @@ import * as DPE from "@duplojs/utils/dataParserExtended"; import * as DDate from "@duplojs/utils/date"; -export const checkedExtendedParser = DPE.object({ startAt: DPE.time({ checkers: [DP.checkerTimeMin(DDate.createTime(250, "millisecond"))] }), tags: DPE.array(DPE.string({ checkers: [DP.checkerStringMin(1)] }), { checkers: [DP.checkerArrayMin(1)] }) });" +export const checkedExtendedParser = DPE.object({ + startAt: DPE.time({ checkers: [DP.checkerTimeMin(DDate.createTime(250, "millisecond"))] }), + tags: DPE.array(DPE.string({ checkers: [DP.checkerStringMin(1)] }), { checkers: [DP.checkerArrayMin(1)] }) +});" `; exports[`render > renders complex nested recursive dataParsers 1`] = ` @@ -60,15 +75,49 @@ export type RecursiveType3 = string | RecursiveType0 | RecursiveType2 | Recursiv export type ComplexRecursive = RecursiveType0; -export const recursiveDataParser1: DP.DataParser = DP.array(DP.union([DP.string(), DP.lazy(() => recursiveDataParser1), DP.lazy(() => recursiveDataParser0)])); +export const recursiveDataParser1: DP.DataParser = DP.array(DP.union([ + DP.string(), + DP.lazy(() => recursiveDataParser1), + DP.lazy(() => recursiveDataParser0) +])); + +export const recursiveDataParser3: DP.DataParser = DP.union([ + DP.string(), + DP.lazy(() => recursiveDataParser0), + DP.lazy(() => recursiveDataParser2), + DP.array(DP.lazy(() => recursiveDataParser3)) +]); + +export const recursiveDataParser2: DP.DataParser = DP.tuple([ + DP.string(), + DP.lazy(() => recursiveDataParser0), + DP.array(DP.union([ + DP.lazy(() => recursiveDataParser2), + DP.lazy(() => recursiveDataParser3), + DP.string() + ])) +]); + +export const recursiveDataParser0: DP.DataParser = DP.object({ + recursiveProp: DP.object({ + self: DP.lazy(() => recursiveDataParser0), + array: recursiveDataParser1, + tuple: recursiveDataParser2, + union: recursiveDataParser3 + }), + children: DP.array(DP.lazy(() => recursiveDataParser0)), + tuple: recursiveDataParser2, + array: recursiveDataParser1, + union: recursiveDataParser3 +}); -export const recursiveDataParser3: DP.DataParser = DP.union([DP.string(), DP.lazy(() => recursiveDataParser0), DP.lazy(() => recursiveDataParser2), DP.array(DP.lazy(() => recursiveDataParser3))]); - -export const recursiveDataParser2: DP.DataParser = DP.tuple([DP.string(), DP.lazy(() => recursiveDataParser0), DP.array(DP.union([DP.lazy(() => recursiveDataParser2), DP.lazy(() => recursiveDataParser3), DP.string()]))]); +export const complexRecursiveParser = recursiveDataParser0;" +`; -export const recursiveDataParser0: DP.DataParser = DP.object({ recursiveProp: DP.object({ self: DP.lazy(() => recursiveDataParser0), array: recursiveDataParser1, tuple: recursiveDataParser2, union: recursiveDataParser3 }), children: DP.array(DP.lazy(() => recursiveDataParser0)), tuple: recursiveDataParser2, array: recursiveDataParser1, union: recursiveDataParser3 }); +exports[`render > renders dataParser in compact mode when indent is false 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; -export const complexRecursiveParser = recursiveDataParser0;" +export const compactParser = DP.object({ name: DP.string({ checkers: [DP.checkerStringMin(2)] }), roles: DP.array(DP.literal(["admin", "editor"]), { checkers: [DP.checkerArrayMin(1)] }), contact: DP.union([DP.object({ email: DP.string({ checkers: [DP.checkerEmail()] }) }), DP.object({ phone: DP.string({ checkers: [DP.checkerRegex(/^[+\\d][\\d\\s-]{5,}$/)] }) })]) });" `; exports[`render > renders named dependencies before their consumers 1`] = ` @@ -76,5 +125,7 @@ exports[`render > renders named dependencies before their consumers 1`] = ` export const childParser = DP.string(); -export const parentParser = DP.object({ child: childParser });" +export const parentParser = DP.object({ + child: childParser +});" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/file.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/file.test.ts.snap index a338d2a..30f6b58 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/file.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/file.test.ts.snap @@ -15,7 +15,13 @@ exports[`file > renders file parser with async constraints 1`] = ` import * as SDP from "@duplojs/server-utils/dataParser"; -export const fileParser = SDP.file({ coerce: true, checkExist: true, maxSize: 10, minSize: 5, mimeType: /image\\/png/ });" +export const fileParser = SDP.file({ + coerce: true, + checkExist: true, + maxSize: 10, + minSize: 5, + mimeType: /image\\/png/ +});" `; exports[`file > renders file parser without options 1`] = ` diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/literal.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/literal.test.ts.snap index c0b1e8e..5fdaf13 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/literal.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/literal.test.ts.snap @@ -3,5 +3,13 @@ exports[`literal > renders literal parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const literalParser = DP.literal(["foo", 1, 1n, true, false, null, undefined]);" +export const literalParser = DP.literal([ + "foo", + 1, + 1n, + true, + false, + null, + undefined +]);" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/object.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/object.test.ts.snap index fb2eeb0..9ea60f4 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/object.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/object.test.ts.snap @@ -3,5 +3,8 @@ exports[`object > renders object parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const objectParser = DP.object({ foo: DP.string(), bar: DP.number() });" +export const objectParser = DP.object({ + foo: DP.string(), + bar: DP.number() +});" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/templateLiteral.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/templateLiteral.test.ts.snap index 51ad65e..ec97465 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/templateLiteral.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/templateLiteral.test.ts.snap @@ -3,5 +3,22 @@ exports[`templateLiteral > renders template literal parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const templateLiteralParser = DP.templateLiteral(["pre-", 1n, "mid-", true, "-false-", false, "-str-", "abc", "-num-", 42, "-null-", null, "-undef-", undefined, "-dp-", DP.string()]);" +export const templateLiteralParser = DP.templateLiteral([ + "pre-", + 1n, + "mid-", + true, + "-false-", + false, + "-str-", + "abc", + "-num-", + 42, + "-null-", + null, + "-undef-", + undefined, + "-dp-", + DP.string() +]);" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/time.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/time.test.ts.snap index 3340abb..5cf4178 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/time.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/time.test.ts.snap @@ -5,7 +5,10 @@ exports[`time > renders time parser with checker imports 1`] = ` import * as DDate from "@duplojs/utils/date"; -export const timeParser = DP.time({ coerce: true, checkers: [DP.checkerTimeMin(DDate.createTime(1, "millisecond"))] });" +export const timeParser = DP.time({ + coerce: true, + checkers: [DP.checkerTimeMin(DDate.createTime(1, "millisecond"))] +});" `; exports[`time > renders time parser without coerce and without checkers 1`] = ` diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/union.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/union.test.ts.snap index f8059f8..801da41 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/union.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/union.test.ts.snap @@ -3,5 +3,8 @@ exports[`union > renders union parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const unionParser = DP.union([DP.string(), DP.number()]);" +export const unionParser = DP.union([ + DP.string(), + DP.number() +]);" `; diff --git a/tests/toDataParser/render.test.ts b/tests/toDataParser/render.test.ts index 411f49a..728dc08 100644 --- a/tests/toDataParser/render.test.ts +++ b/tests/toDataParser/render.test.ts @@ -184,4 +184,35 @@ describe("render", () => { ), ).toMatchSnapshot(); }); + + it("renders dataParser in compact mode when indent is false", () => { + const compactSchema = DPE.object({ + name: DPE.string().min(2), + roles: DPE.literal(["admin", "editor"]).array().min(1), + contact: DPE.union([ + DPE.object({ + email: DPE.email(), + }), + DPE.object({ + phone: DPE.string().regex(/^[+\d][\d\s-]{5,}$/), + }), + ]), + }); + + expect( + render( + compactSchema, + { + constName: "compactParser", + indent: false, + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + toTypescript: { + identifier: "CompactSchema", + transformers: tsDefaultTransformers, + }, + }, + ), + ).toMatchSnapshot(); + }); }); From d2fba9562399f2cf8c779b74fbc2157ecaa8b324 Mon Sep 17 00:00:00 2001 From: mathcovax Date: Fri, 22 May 2026 17:51:25 +0000 Subject: [PATCH 09/16] fix(hf): to data parser --- package-lock.json | 8 +- package.json | 2 +- scripts/toDataParser/buildContext.ts | 104 +++++++++ .../dataParserTransformer/create.ts | 22 +- .../dataParserTransformer/defaults/file.ts | 9 +- .../dataParserTransformer/defaults/literal.ts | 3 +- .../dataParserTransformer/defaults/object.ts | 3 +- .../defaults/templateLiteral.ts | 3 +- .../dataParserTransformer/defaults/time.ts | 4 +- .../dataParserTransformer/defaults/tuple.ts | 3 +- .../dataParserTransformer/defaults/union.ts | 3 +- .../getDefinitionDataParser.ts | 67 ++++++ .../dataParserTransformer/hook.ts | 5 +- .../dataParserTransformer/importClause.ts | 19 -- .../dataParserTransformer/index.ts | 1 + .../dataParserTransformer/transformer.ts | 193 +++++++-------- scripts/toDataParser/override.ts | 16 +- scripts/toDataParser/printer.ts | 56 +++++ scripts/toDataParser/render.ts | 219 +++--------------- scripts/toTypescript/buildContext.ts | 75 ++++++ scripts/toTypescript/index.ts | 2 + scripts/toTypescript/printer.ts | 25 ++ scripts/toTypescript/render.ts | 83 ++----- scripts/toTypescript/transformer/create.ts | 23 +- .../transformer/createImportDeclaration.ts | 61 +++++ scripts/toTypescript/transformer/hook.ts | 9 +- .../transformer/importTypesTransformer.ts | 30 --- scripts/toTypescript/transformer/index.ts | 2 +- .../toTypescript/transformer/transformer.ts | 36 ++- .../dataParserTransformer/array.test.ts | 17 +- .../dataParserTransformer/file.test.ts | 2 +- tests/toDataParser/render.test.ts | 2 +- .../transfomers/templateLiteral.test.ts | 2 + 33 files changed, 635 insertions(+), 474 deletions(-) create mode 100644 scripts/toDataParser/buildContext.ts create mode 100644 scripts/toDataParser/dataParserTransformer/getDefinitionDataParser.ts delete mode 100644 scripts/toDataParser/dataParserTransformer/importClause.ts create mode 100644 scripts/toDataParser/printer.ts create mode 100644 scripts/toTypescript/buildContext.ts create mode 100644 scripts/toTypescript/printer.ts create mode 100644 scripts/toTypescript/transformer/createImportDeclaration.ts delete mode 100644 scripts/toTypescript/transformer/importTypesTransformer.ts diff --git a/package-lock.json b/package-lock.json index 0474a28..2d40939 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,7 +39,7 @@ }, "peerDependencies": { "@duplojs/server-utils": ">=0.3.0 < 1.0.0", - "@duplojs/utils": ">=1.8.1 <2.0.0" + "@duplojs/utils": ">=1.8.4 <2.0.0" } }, "docs": {}, @@ -980,9 +980,9 @@ } }, "node_modules/@duplojs/utils": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@duplojs/utils/-/utils-1.8.1.tgz", - "integrity": "sha512-dVsvAPOTCsayWSr2HDA/2XebK35NVsB8efnd3u5Tw+aqSUB09/S4uaqBNCUkkaVQW/S0OTc5OlHGxnTWsPz00A==", + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/@duplojs/utils/-/utils-1.8.4.tgz", + "integrity": "sha512-56TrQQ5TSok/ScbYZbgwgvj+Jft8aQUE/rLThoUYoqGpu0dE0j06/jBZWqtOOEUjyC/3W1bHH8tmsD3eWKVs2w==", "license": "MIT", "peer": true, "workspaces": [ diff --git a/package.json b/package.json index 635b278..4372c55 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "vitest": "3.2.4" }, "peerDependencies": { - "@duplojs/utils": ">=1.8.1 <2.0.0", + "@duplojs/utils": ">=1.8.4 <2.0.0", "@duplojs/server-utils": ">=0.3.0 < 1.0.0" }, "dependencies": { diff --git a/scripts/toDataParser/buildContext.ts b/scripts/toDataParser/buildContext.ts new file mode 100644 index 0000000..d93f138 --- /dev/null +++ b/scripts/toDataParser/buildContext.ts @@ -0,0 +1,104 @@ +import { DP, E, unwrap } from "@duplojs/utils"; +import { type createTransformer, transformer, type MapContext, type TransformerHook, type DataParserErrorEither, type DataParserNotSupportedEither, type DataParserGetDefinitionErrorEither, type ToTypescriptDataParserErrorEither, type ToTypescriptDataParserNotSupportedEither } from "./dataParserTransformer"; +import type * as TST from "@scripts/toTypescript"; +import { getRecursiveDataParser } from "@scripts/utils"; +import { factory } from "typescript"; +import { type createCheckerTransformer } from "./checkerTransformer"; + +export type ImportMode = "lite" | "extended"; + +export interface BuildedContext { + readonly context: MapContext; + readonly typescriptContext: TST.MapContext; + readonly importContext: TST.MapImportContext; + readonly importMode: ImportMode; +} + +export interface BuildContextParams { + readonly identifier: string; + readonly dataParserTransformers: readonly ReturnType[]; + readonly checkerTransformers: readonly ReturnType[]; + readonly typescriptTransformers: readonly ReturnType[]; + readonly context?: MapContext; + readonly typescriptContext?: TST.MapContext; + readonly importContext?: TST.MapImportContext; + readonly importMode?: ImportMode; + readonly hooks?: readonly TransformerHook[]; + readonly toTypescript?: { + readonly mode?: TST.TransformerMode; + readonly hooks?: readonly TST.TransformerHook[]; + }; +} + +export function buildContext( + schema: DP.DataParser, + params: BuildContextParams, +): ( + | BuildedContext + | DataParserNotSupportedEither + | DataParserErrorEither + | DataParserGetDefinitionErrorEither + | ToTypescriptDataParserNotSupportedEither + | ToTypescriptDataParserErrorEither + ) { + const context: MapContext = params.context ?? new Map(); + const typescriptContext = params.typescriptContext ?? new Map(); + const importContext: TST.MapImportContext = params.importContext ?? new Map(); + const importMode = params.importMode ?? "lite"; + + importContext.set("@duplojs/utils/dataParser", { + type: "clause", + identifier: "DP", + }); + + if (importMode === "extended") { + importContext.set("@duplojs/utils/dataParserExtended", { + type: "clause", + identifier: "DPE", + }); + } + + const result = transformer( + schema, + { + ...params, + context, + typescriptContext, + importContext: importContext, + hooks: params.hooks ?? [], + recursiveDataParsers: getRecursiveDataParser(schema), + dependencyIdentifier: factory.createIdentifier(importMode === "extended" ? "DPE" : "DP"), + }, + ); + + if (E.isLeft(result)) { + return result; + } + + if (!schema.definition.identifier) { + context.set( + DP.empty(), + { + identifier: factory.createIdentifier(params.identifier), + expression: unwrap(result), + typeIdentifier: null, + }, + ); + } else if (schema.definition.identifier !== params.identifier) { + context.set( + DP.empty(), + { + identifier: factory.createIdentifier(params.identifier), + expression: factory.createIdentifier(schema.definition.identifier), + typeIdentifier: null, + }, + ); + } + + return { + context, + importContext: importContext, + typescriptContext, + importMode, + }; +} diff --git a/scripts/toDataParser/dataParserTransformer/create.ts b/scripts/toDataParser/dataParserTransformer/create.ts index 43bdeef..cea6ad5 100644 --- a/scripts/toDataParser/dataParserTransformer/create.ts +++ b/scripts/toDataParser/dataParserTransformer/create.ts @@ -1,5 +1,6 @@ -import type { CallExpression, Identifier, ObjectLiteralExpression, PropertyAssignment } from "typescript"; import { type DP, E } from "@duplojs/utils"; +import type * as TST from "@scripts/toTypescript"; +import type { CallExpression, Identifier, ObjectLiteralExpression, PropertyAssignment } from "typescript"; import type { CheckerTransformerBuildErrorEither, CheckerTransformerCheckerNotSupportedEither } from "../checkerTransformer"; export type TransformerSuccessEither = E.Right<"buildSuccess", CallExpression | Identifier>; @@ -8,6 +9,10 @@ export type DataParserNotSupportedEither = E.Left<"dataParserNotSupport", DP.Dat export type DataParserErrorEither = E.Left<"buildDataParserError", DP.DataParser>; +export type ToTypescriptDataParserNotSupportedEither = E.Left<"toTypescriptDataParserNotSupport", DP.DataParser>; + +export type ToTypescriptDataParserErrorEither = E.Left<"toTypescriptBuildDataParserError", DP.DataParser>; + export type DataParserGetDefinitionErrorEither = E.Left< "buildDataParserGetDefinitionError", { @@ -17,25 +22,25 @@ export type DataParserGetDefinitionErrorEither = E.Left< >; export interface MapContextValue { - readonly constName: Identifier; + readonly identifier: Identifier; readonly expression: CallExpression | Identifier; + readonly typeIdentifier: Identifier | null; } export type MapContext = Map; -export type MapImportClause = Map; - export type MaybeTransformerEither = | TransformerSuccessEither | DataParserNotSupportedEither | DataParserErrorEither - | DataParserGetDefinitionErrorEither; + | DataParserGetDefinitionErrorEither + | ToTypescriptDataParserNotSupportedEither + | ToTypescriptDataParserErrorEither; export interface TransformerParams { readonly dependencyIdentifier: Identifier; readonly context: MapContext; - readonly importClause: MapImportClause; - readonly indent: boolean; + readonly importContext: TST.MapImportContext; transformer( dataParser: DP.DataParser, @@ -46,10 +51,9 @@ export interface TransformerParams { ): TransformerSuccessEither; buildError(): DataParserErrorEither; - addImportClause(path: string, clause: string): void; + addImport(path: string, typeName: string, type?: "default" | "clause"): void; getDefinition( customProperties?: readonly PropertyAssignment[], - indent?: boolean, ): readonly [ObjectLiteralExpression] | readonly [] | DataParserGetDefinitionErrorEither; } diff --git a/scripts/toDataParser/dataParserTransformer/defaults/file.ts b/scripts/toDataParser/dataParserTransformer/defaults/file.ts index 335d32a..fb64385 100644 --- a/scripts/toDataParser/dataParserTransformer/defaults/file.ts +++ b/scripts/toDataParser/dataParserTransformer/defaults/file.ts @@ -11,8 +11,7 @@ export const fileTransformer = createTransformer( success, dependencyIdentifier, getDefinition, - addImportClause, - indent, + addImport, }, ) => { const definition = getDefinition(); @@ -67,13 +66,13 @@ export const fileTransformer = createTransformer( const namespace = dependencyIdentifier.text === "DP" ? justExec( () => { - addImportClause("@duplojs/server-utils/dataParser", "SDP"); + addImport("@duplojs/server-utils/dataParser", "SDP", "clause"); return "SDP"; }, ) : justExec( () => { - addImportClause("@duplojs/server-utils/dataParserExtended", "SDPE"); + addImport("@duplojs/server-utils/dataParserExtended", "SDPE", "clause"); return "SDPE"; }, ); @@ -88,7 +87,7 @@ export const fileTransformer = createTransformer( [ factory.createObjectLiteralExpression( dataParserFileParams, - indent && A.minElements(dataParserFileParams, 2), + A.minElements(dataParserFileParams, 2), ), ...definition, ], diff --git a/scripts/toDataParser/dataParserTransformer/defaults/literal.ts b/scripts/toDataParser/dataParserTransformer/defaults/literal.ts index 07ec58f..8c40e81 100644 --- a/scripts/toDataParser/dataParserTransformer/defaults/literal.ts +++ b/scripts/toDataParser/dataParserTransformer/defaults/literal.ts @@ -10,7 +10,6 @@ export const literalTransformer = createTransformer( success, dependencyIdentifier, getDefinition, - indent, }, ) => { const definition = getDefinition(); @@ -61,7 +60,7 @@ export const literalTransformer = createTransformer( [ factory.createArrayLiteralExpression( values, - indent && A.minElements(values, 4), + A.minElements(values, 4), ), ...definition, ], diff --git a/scripts/toDataParser/dataParserTransformer/defaults/object.ts b/scripts/toDataParser/dataParserTransformer/defaults/object.ts index 3bf0ce3..4642884 100644 --- a/scripts/toDataParser/dataParserTransformer/defaults/object.ts +++ b/scripts/toDataParser/dataParserTransformer/defaults/object.ts @@ -11,7 +11,6 @@ export const objectTransformer = createTransformer( dependencyIdentifier, getDefinition, transformer, - indent, }, ) => { const shape = pipe( @@ -59,7 +58,7 @@ export const objectTransformer = createTransformer( [ factory.createObjectLiteralExpression( shape, - indent, + true, ), ...definition, ], diff --git a/scripts/toDataParser/dataParserTransformer/defaults/templateLiteral.ts b/scripts/toDataParser/dataParserTransformer/defaults/templateLiteral.ts index bbc589c..ce1f62b 100644 --- a/scripts/toDataParser/dataParserTransformer/defaults/templateLiteral.ts +++ b/scripts/toDataParser/dataParserTransformer/defaults/templateLiteral.ts @@ -11,7 +11,6 @@ export const templateLiteralTransformer = createTransformer( dependencyIdentifier, getDefinition, transformer, - indent, }, ) => { const parts = A.reduce( @@ -81,7 +80,7 @@ export const templateLiteralTransformer = createTransformer( [ factory.createArrayLiteralExpression( parts, - indent && A.minElements(parts, 4), + A.minElements(parts, 4), ), ...definition, ], diff --git a/scripts/toDataParser/dataParserTransformer/defaults/time.ts b/scripts/toDataParser/dataParserTransformer/defaults/time.ts index 957dc1e..d76e2bd 100644 --- a/scripts/toDataParser/dataParserTransformer/defaults/time.ts +++ b/scripts/toDataParser/dataParserTransformer/defaults/time.ts @@ -10,7 +10,7 @@ export const timeTransformer = createTransformer( success, dependencyIdentifier, getDefinition, - addImportClause, + addImport, }, ) => { const definition = getDefinition( @@ -29,7 +29,7 @@ export const timeTransformer = createTransformer( } if (A.minElements(dataParser.definition.checkers, 1)) { - addImportClause("@duplojs/utils/date", "DDate"); + addImport("@duplojs/utils/date", "DDate", "clause"); } return pipe( diff --git a/scripts/toDataParser/dataParserTransformer/defaults/tuple.ts b/scripts/toDataParser/dataParserTransformer/defaults/tuple.ts index fb8cdc7..83c6a76 100644 --- a/scripts/toDataParser/dataParserTransformer/defaults/tuple.ts +++ b/scripts/toDataParser/dataParserTransformer/defaults/tuple.ts @@ -11,7 +11,6 @@ export const tupleTransformer = createTransformer( dependencyIdentifier, getDefinition, transformer, - indent, }, ) => { const shape = A.reduce( @@ -67,7 +66,7 @@ export const tupleTransformer = createTransformer( [ factory.createArrayLiteralExpression( shape, - indent && A.minElements(shape, 3), + A.minElements(shape, 3), ), ...definition, ], diff --git a/scripts/toDataParser/dataParserTransformer/defaults/union.ts b/scripts/toDataParser/dataParserTransformer/defaults/union.ts index 5b8284e..a5e8013 100644 --- a/scripts/toDataParser/dataParserTransformer/defaults/union.ts +++ b/scripts/toDataParser/dataParserTransformer/defaults/union.ts @@ -11,7 +11,6 @@ export const unionTransformer = createTransformer( getDefinition, success, transformer, - indent, }, ) => { const options = A.reduce( @@ -48,7 +47,7 @@ export const unionTransformer = createTransformer( [ factory.createArrayLiteralExpression( options, - indent, + true, ), ...definition, ], diff --git a/scripts/toDataParser/dataParserTransformer/getDefinitionDataParser.ts b/scripts/toDataParser/dataParserTransformer/getDefinitionDataParser.ts new file mode 100644 index 0000000..e62a4a5 --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/getDefinitionDataParser.ts @@ -0,0 +1,67 @@ +import { A, type DP, E, pipe, when } from "@duplojs/utils"; +import { checkerTransformer, type createCheckerTransformer } from "../checkerTransformer"; +import { type CallExpression, factory, type PropertyAssignment } from "typescript"; + +export interface getDefinitionDataParserParams { + readonly dataParser: DP.DataParser; + readonly checkerTransformers: readonly ReturnType[]; + readonly customProperties: readonly PropertyAssignment[]; +} + +export function getDefinitionDataParser(params: getDefinitionDataParserParams) { + const propertyAssignments: PropertyAssignment[] = []; + + if (params.dataParser.definition.errorMessage) { + propertyAssignments.push( + factory.createPropertyAssignment( + factory.createIdentifier("errorMessage"), + factory.createStringLiteral(params.dataParser.definition.errorMessage), + ), + ); + } + if (A.minElements(params.customProperties, 1)) { + propertyAssignments.push(...params.customProperties); + } + if (A.minElements(params.dataParser.definition.checkers, 1)) { + const checkers = A.reduce( + params.dataParser.definition.checkers, + A.reduceFrom([]), + ({ element, lastValue, nextPush, exit }) => pipe( + checkerTransformer(element, { transformers: params.checkerTransformers }), + E.whenIsRight( + (value) => nextPush(lastValue, value), + ), + when( + E.isLeft, + exit, + ), + ), + ); + + if (E.isLeft(checkers)) { + return E.left("buildDataParserGetDefinitionError", { + dataParser: params.dataParser, + error: checkers, + }); + } + + propertyAssignments.push( + factory.createPropertyAssignment( + factory.createIdentifier("checkers"), + factory.createArrayLiteralExpression( + checkers, + A.minElements(checkers, 2), + ), + ), + ); + } + + return A.minElements(propertyAssignments, 1) + ? [ + factory.createObjectLiteralExpression( + propertyAssignments, + A.minElements(propertyAssignments, 2), + ), + ] + : []; +} diff --git a/scripts/toDataParser/dataParserTransformer/hook.ts b/scripts/toDataParser/dataParserTransformer/hook.ts index e6abd59..7ff329c 100644 --- a/scripts/toDataParser/dataParserTransformer/hook.ts +++ b/scripts/toDataParser/dataParserTransformer/hook.ts @@ -1,5 +1,6 @@ import type { DP } from "@duplojs/utils"; -import type { MapContext, MapImportClause } from "./create"; +import type * as TST from "@scripts/toTypescript"; +import type { MapContext } from "./create"; export type TransformerHookAction = "stop" | "next"; @@ -11,7 +12,7 @@ export interface TransformerHookOutput { export interface TransformerHookParams { dataParser: DP.DataParsers; context: MapContext; - importDataParser: MapImportClause; + importContext: TST.MapImportContext; output( action: TransformerHookAction, diff --git a/scripts/toDataParser/dataParserTransformer/importClause.ts b/scripts/toDataParser/dataParserTransformer/importClause.ts deleted file mode 100644 index 4f4e850..0000000 --- a/scripts/toDataParser/dataParserTransformer/importClause.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { G } from "@duplojs/utils"; -import type { MapImportClause } from "./create"; -import { factory } from "typescript"; - -export function importClauseTransformer(imports: MapImportClause) { - return G.map( - imports, - ([path, clause]) => factory.createImportDeclaration( - undefined, - factory.createImportClause( - undefined, - undefined, - factory.createNamespaceImport(factory.createIdentifier(clause)), - ), - factory.createStringLiteral(path), - undefined, - ), - ); -} diff --git a/scripts/toDataParser/dataParserTransformer/index.ts b/scripts/toDataParser/dataParserTransformer/index.ts index 23d444f..07a0b4c 100644 --- a/scripts/toDataParser/dataParserTransformer/index.ts +++ b/scripts/toDataParser/dataParserTransformer/index.ts @@ -2,3 +2,4 @@ export * from "./create"; export * from "./transformer"; export * from "./hook"; export * from "./defaults"; +export * from "./getDefinitionDataParser"; diff --git a/scripts/toDataParser/dataParserTransformer/transformer.ts b/scripts/toDataParser/dataParserTransformer/transformer.ts index 1b00f65..b0552e1 100644 --- a/scripts/toDataParser/dataParserTransformer/transformer.ts +++ b/scripts/toDataParser/dataParserTransformer/transformer.ts @@ -1,84 +1,26 @@ -import { A, E, type DP, pipe, unwrap, when } from "@duplojs/utils"; -import type { MapContext, TransformerParams, createTransformer, MapImportClause, MaybeTransformerEither } from "./create"; -import { factory, type PropertyAssignment, type CallExpression, type Identifier } from "typescript"; +import { A, E, type DP, unwrap, S, justExec, pipe, whenNot, isType, equal } from "@duplojs/utils"; +import * as TST from "@scripts/toTypescript"; +import type { MapContext, TransformerParams, createTransformer, MaybeTransformerEither } from "./create"; +import { factory, type Identifier } from "typescript"; import type { TransformerHook } from "./hook"; -import { type createCheckerTransformer, checkerTransformer } from "../checkerTransformer"; - -export interface getDefinitionDataParserParams { - readonly dataParser: DP.DataParser; - readonly checkerTransformers: readonly ReturnType[]; - readonly customProperties: readonly PropertyAssignment[]; - readonly indent: boolean; -} - -export function getDefinitionDataParser(params: getDefinitionDataParserParams) { - const propertyAssignments: PropertyAssignment[] = []; - - if (params.dataParser.definition.errorMessage) { - propertyAssignments.push( - factory.createPropertyAssignment( - factory.createIdentifier("errorMessage"), - factory.createStringLiteral(params.dataParser.definition.errorMessage), - ), - ); - } - if (A.minElements(params.customProperties, 1)) { - propertyAssignments.push(...params.customProperties); - } - if (A.minElements(params.dataParser.definition.checkers, 1)) { - const checkers = A.reduce( - params.dataParser.definition.checkers, - A.reduceFrom([]), - ({ element, lastValue, nextPush, exit }) => pipe( - checkerTransformer(element, { transformers: params.checkerTransformers }), - E.whenIsRight( - (value) => nextPush(lastValue, value), - ), - when( - E.isLeft, - exit, - ), - ), - ); - - if (E.isLeft(checkers)) { - return E.left("buildDataParserGetDefinitionError", { - dataParser: params.dataParser, - error: checkers, - }); - } - - propertyAssignments.push( - factory.createPropertyAssignment( - factory.createIdentifier("checkers"), - factory.createArrayLiteralExpression( - checkers, - params.indent && A.minElements(checkers, 2), - ), - ), - ); - } - - return A.minElements(propertyAssignments, 1) - ? [ - factory.createObjectLiteralExpression( - propertyAssignments, - params.indent && A.minElements(propertyAssignments, 2), - ), - ] - : []; -} +import { type createCheckerTransformer } from "../checkerTransformer"; +import { getDefinitionDataParser } from "./getDefinitionDataParser"; +import { success } from "@duplojs/utils/either"; export interface TransformerFunctionParams { readonly dataParserTransformers: readonly ReturnType[]; readonly checkerTransformers: readonly ReturnType[]; + readonly typescriptTransformers: readonly ReturnType[]; readonly context: MapContext; - readonly buildingConstNames: Map; + readonly typescriptContext: TST.MapContext; + readonly importContext: TST.MapImportContext; readonly dependencyIdentifier: Identifier; readonly hooks: readonly TransformerHook[]; readonly recursiveDataParsers: DP.DataParser[]; - readonly importClause: MapImportClause; - readonly indent: boolean; + readonly toTypescript?: { + readonly mode?: TST.TransformerMode; + readonly hooks?: readonly TST.TransformerHook[]; + }; } export function transformer( @@ -92,7 +34,7 @@ export function transformer( const result = hook({ dataParser: lastValue, context: params.context, - importDataParser: params.importClause, + importContext: params.importContext, output: (action, dataParser) => ({ dataParser, action, @@ -111,32 +53,28 @@ export function transformer( if (contextValue) { return E.right( "buildSuccess", - contextValue.constName, - ); - } - - const currentBuildingConstName = params.buildingConstNames.get(currentDataParser); - - if (currentBuildingConstName) { - return E.right( - "buildSuccess", - currentBuildingConstName, + contextValue.identifier, ); } const shouldCreateConstDeclaration = A.includes(params.recursiveDataParsers, currentDataParser) - || !!currentDataParser.definition.constName; - const currentConstName = shouldCreateConstDeclaration + || !!currentDataParser.definition.identifier; + const currentIdentifier = shouldCreateConstDeclaration ? factory.createIdentifier( - currentDataParser.definition.constName - ?? `recursiveDataParser${params.context.size + params.buildingConstNames.size}`, + currentDataParser.definition.identifier !== undefined + ? `${S.uncapitalize(currentDataParser.definition.identifier)}DataParser` + : `recursiveDataParser${params.context.size + params.context.size}`, ) : undefined; - if (currentConstName) { - params.buildingConstNames.set( + if (currentIdentifier) { + params.context.set( currentDataParser, - currentConstName, + { + identifier: currentIdentifier, + expression: factory.createIdentifier("undefined"), + typeIdentifier: null, + }, ); } @@ -152,21 +90,36 @@ export function transformer( }, context: params.context, dependencyIdentifier: params.dependencyIdentifier, - indent: params.indent, buildError() { return E.left("buildDataParserError", currentDataParser); }, - importClause: params.importClause, - getDefinition(customProperties = [], indent = true) { + importContext: params.importContext, + getDefinition(customProperties = []) { return getDefinitionDataParser({ dataParser: currentDataParser, checkerTransformers: params.checkerTransformers, customProperties, - indent: indent && params.indent, }); }, - addImportClause(path, clause) { - params.importClause.set(path, clause); + addImport(path, typeName, type) { + if (equal(type, ["clause", "default"])) { + params.importContext.set(path, { + type, + identifier: typeName, + }); + } + + const types = pipe( + params.importContext.get(path), + whenNot( + isType("array"), + () => [], + ), + ); + + if (!A.includes(types, typeName)) { + params.importContext.set(path, A.push(types, typeName)); + } }, }; @@ -201,26 +154,58 @@ export function transformer( ); if (E.isLeft(result)) { - if (currentConstName) { - params.buildingConstNames.delete(currentDataParser); - } - return result; } - if (currentConstName) { - params.buildingConstNames.delete(currentDataParser); + if (currentIdentifier) { + const typeIdentifier = justExec(() => { + if (!A.includes(params.recursiveDataParsers, currentDataParser)) { + return undefined; + } + const identifier = `$${currentIdentifier.text}`; + + const result = TST.buildContext( + currentDataParser, + { + identifier, + transformers: params.typescriptTransformers, + context: params.typescriptContext, + importContext: params.importContext, + ...params.toTypescript, + }, + ); + return E.matchInformationOtherwise( + result, + { + buildDataParserError: (dataParser) => E.left( + "toTypescriptBuildDataParserError", + dataParser, + ), + dataParserNotSupport: (dataParser) => E.left( + "toTypescriptDataParserNotSupport", + dataParser, + ), + }, + () => factory.createIdentifier(identifier), + ); + }); + + if (E.isLeft(typeIdentifier)) { + return typeIdentifier; + } + params.context.set( currentDataParser, { - constName: currentConstName, + identifier: currentIdentifier, expression: unwrap(result), + typeIdentifier: typeIdentifier ?? null, }, ); return E.right( "buildSuccess", - currentConstName, + currentIdentifier, ); } diff --git a/scripts/toDataParser/override.ts b/scripts/toDataParser/override.ts index e37acf7..5cb2613 100644 --- a/scripts/toDataParser/override.ts +++ b/scripts/toDataParser/override.ts @@ -8,8 +8,8 @@ declare module "@duplojs/utils/dataParser" { /** * @deprecated this method mutated the dataParser by adding an identifier */ - setConstName(input: string): this; - addConstName(input: string): this; + setIdentifier(input: string): this; + addIdentifier(input: string): this; /** * @deprecated this method mutated the dataParser by adding an override transformer @@ -23,26 +23,26 @@ declare module "@duplojs/utils/dataParser" { } interface DataParserDefinition { - constName?: string; + identifier?: string; overrideDataParserTransformer?: TransformerBuildFunction; } } dataParserBaseInit.overrideHandler.setMethod( - "setConstName", - (schema, constName) => { - schema.definition.constName = constName; + "setIdentifier", + (schema, identifier) => { + schema.definition.identifier = identifier; return schema; }, ); dataParserBaseInit.overrideHandler.setMethod( - "addConstName", + "addIdentifier", (schema, identifier) => { const newSchema = schema.clone(); - newSchema.setConstName(identifier); + newSchema.setIdentifier(identifier); return newSchema; }, diff --git a/scripts/toDataParser/printer.ts b/scripts/toDataParser/printer.ts new file mode 100644 index 0000000..22f492e --- /dev/null +++ b/scripts/toDataParser/printer.ts @@ -0,0 +1,56 @@ +import { createPrinter, createSourceFile, EmitHint, factory, NodeFlags, ScriptKind, ScriptTarget, SyntaxKind, type VariableStatement } from "typescript"; +import { type BuildedContext } from "./buildContext"; +import { A, G, pipe, S } from "@duplojs/utils"; +import * as TST from "@scripts/toTypescript"; + +export function printer(params: BuildedContext) { + const sourceFile = createSourceFile("print.ts", "", ScriptTarget.Latest, false, ScriptKind.TS); + const printer = createPrinter(); + + const dataParserStatements = G.reduce( + params.context.values(), + G.reduceFrom([]), + ({ element: contextValue, lastValue, nextPush }) => nextPush( + lastValue, + factory.createVariableStatement( + [factory.createToken(SyntaxKind.ExportKeyword)], + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + contextValue.identifier, + undefined, + contextValue.typeIdentifier + ? factory.createTypeReferenceNode( + factory.createQualifiedName( + factory.createIdentifier(params.importMode === "extended" ? "DPE" : "DP"), + factory.createIdentifier(params.importMode === "extended" ? "DataParserExtended" : "DataParser"), + ), + [factory.createTypeReferenceNode(contextValue.typeIdentifier)], + ) + : undefined, + contextValue.expression, + ), + ], + NodeFlags.Const, + ), + ), + ), + ); + + return pipe( + [ + ...TST.createImportDeclaration(params.importContext), + ...params.typescriptContext.values(), + ...dataParserStatements, + ], + A.map( + (value) => printer.printNode( + EmitHint.Unspecified, + value, + sourceFile, + ), + ), + A.join("\n\n"), + S.trim, + ); +} diff --git a/scripts/toDataParser/render.ts b/scripts/toDataParser/render.ts index a198980..e7acdf5 100644 --- a/scripts/toDataParser/render.ts +++ b/scripts/toDataParser/render.ts @@ -1,11 +1,9 @@ -import { A, DP, E, kindHeritage, pipe, S, unwrap } from "@duplojs/utils"; -import { createPrinter, createSourceFile, EmitHint, factory, NodeFlags, ScriptKind, ScriptTarget, SyntaxKind, type TypeAliasDeclaration, type VariableStatement } from "typescript"; -import * as TST from "@scripts/toTypescript"; -import { type createCheckerTransformer } from "./checkerTransformer"; -import { type TransformerHook, type createTransformer, type MapContext, type MapImportClause, transformer, type DataParserNotSupportedEither, type DataParserGetDefinitionErrorEither, type DataParserErrorEither } from "./dataParserTransformer"; -import { getRecursiveDataParser } from "@scripts/utils"; +import type * as TST from "@scripts/toTypescript"; +import { type DataParserNotSupportedEither, type DataParserGetDefinitionErrorEither, type DataParserErrorEither, type MapContext, type ToTypescriptDataParserErrorEither, type ToTypescriptDataParserNotSupportedEither } from "./dataParserTransformer"; import { createToDataParserKind } from "./kind"; -import { importClauseTransformer } from "./dataParserTransformer/importClause"; +import { buildContext, type BuildContextParams } from "./buildContext"; +import { type DP, E, kindHeritage } from "@duplojs/utils"; +import { printer } from "./printer"; export class DataParserToDataParserRenderError extends kindHeritage( "data-parser-to-data-parser-render-error", @@ -27,202 +25,47 @@ export class DataParserToDataParserTypeRenderError extends kindHeritage( ) { public constructor( public dataParser: DP.DataParser, - public error: TST.DataParserNotSupportedEither | TST.DataParserErrorEither, + public error: ToTypescriptDataParserNotSupportedEither | ToTypescriptDataParserErrorEither, ) { super({}, ["Error during the render of recursive dataParser type."]); } } -export interface RenderParams { - readonly constName: string; - readonly dataParserTransformers: readonly ReturnType[]; - readonly checkerTransformers: readonly ReturnType[]; - readonly exportMode?: "normal" | "extended"; - readonly context?: MapContext; - readonly hooks?: readonly TransformerHook[]; - readonly importClause?: MapImportClause; - readonly indent?: boolean; - - readonly toTypescript: { - readonly identifier: string; - readonly transformers: readonly ReturnType[]; - readonly context?: TST.MapContext; - readonly mode?: TST.TransformerMode; - readonly hooks?: readonly TST.TransformerHook[]; - readonly importType?: TST.MapImportType; - }; +export interface RenderParams extends BuildContextParams { } export function render(dataParser: DP.DataParser, params: RenderParams) { const context: MapContext = new Map(params.context); - const importClause: MapImportClause = new Map(params.importClause); - const dependencyIdentifier = factory.createIdentifier(params.exportMode === "extended" ? "DPE" : "DP"); - const recursiveDataParsers = getRecursiveDataParser(dataParser); - const tsContext: TST.MapContext = new Map(params.toTypescript.context); - const importType: TST.MapImportType = new Map(params.toTypescript.importType); - const recursiveTypeAliasDeclarations: TypeAliasDeclaration[] = []; - const recursiveTypeNameByDataParser = new Map(); - - importClause.set("@duplojs/utils/dataParser", "DP"); - - if (params.exportMode === "extended") { - importClause.set("@duplojs/utils/dataParserExtended", "DPE"); - } - - if (A.minElements(recursiveDataParsers, 1)) { - const tsResult = TST.transformer( - dataParser, - { - context: tsContext, - importType, - hooks: params.toTypescript.hooks ?? [], - mode: params.toTypescript.mode ?? "out", - recursiveDataParsers, - transformers: params.toTypescript.transformers, - }, - ); - - if (E.isLeft(tsResult)) { - throw new DataParserToDataParserTypeRenderError( - dataParser, - tsResult, - ); - } - - const typeDeclarations = A.reduce( - recursiveDataParsers, - A.reduceFrom([]), - ({ element: recursiveDataParser, lastValue, nextPush, next }) => { - const declaration = tsContext.get(recursiveDataParser); - - if (!declaration) { - return next(lastValue); - } - - recursiveTypeNameByDataParser.set(recursiveDataParser, declaration.name.text); - - return nextPush(lastValue, declaration); - }, - ); - - recursiveTypeAliasDeclarations.push(...typeDeclarations); - - if (A.includes(recursiveDataParsers, dataParser)) { - if ( - dataParser.definition.identifier - && dataParser.definition.identifier !== params.toTypescript.identifier - ) { - recursiveTypeAliasDeclarations.push( - factory.createTypeAliasDeclaration( - [factory.createToken(SyntaxKind.ExportKeyword)], - factory.createIdentifier(params.toTypescript.identifier), - undefined, - factory.createTypeReferenceNode( - dataParser.definition.identifier, - ), - ), - ); - - recursiveTypeNameByDataParser.set(dataParser, params.toTypescript.identifier); - } else if (dataParser.definition.identifier !== params.toTypescript.identifier) { - recursiveTypeAliasDeclarations.push( - factory.createTypeAliasDeclaration( - [factory.createToken(SyntaxKind.ExportKeyword)], - factory.createIdentifier(params.toTypescript.identifier), - undefined, - unwrap(tsResult), - ), - ); - - recursiveTypeNameByDataParser.set(dataParser, params.toTypescript.identifier); - } - } - } - - const result = transformer( - dataParser, - { - dataParserTransformers: params.dataParserTransformers, - checkerTransformers: params.checkerTransformers, - context, - buildingConstNames: new Map(), - recursiveDataParsers, - importClause, - dependencyIdentifier, - hooks: params.hooks ?? [], - indent: params.indent ?? true, - }, - ); - - if (E.isLeft(result)) { + const typescriptContext = new Map(params.typescriptContext); + const importContext: TST.MapImportContext = new Map(params.importContext); + + const result = buildContext(dataParser, { + ...params, + context, + typescriptContext, + importContext, + }); + + if ( + E.hasInformation(result, "buildDataParserError") + || E.hasInformation(result, "dataParserNotSupport") + || E.hasInformation(result, "buildDataParserGetDefinitionError") + ) { throw new DataParserToDataParserRenderError( dataParser, result, ); - } - - if (dataParser.definition.constName !== params.constName) { - context.set( - DP.empty(), - { - constName: factory.createIdentifier(params.constName), - expression: unwrap(result), - }, + } else if ( + E.hasInformation(result, "toTypescriptBuildDataParserError") + || E.hasInformation(result, "toTypescriptDataParserNotSupport") + ) { + throw new DataParserToDataParserTypeRenderError( + dataParser, + result, ); } - const dataParserConstStatements = A.reduce( - A.from(context), - A.reduceFrom([]), - ({ element: [currentDataParser, contextValue], lastValue, nextPush }) => { - const recursiveTypeName = recursiveTypeNameByDataParser.get(currentDataParser); - - return nextPush( - lastValue, - factory.createVariableStatement( - [factory.createToken(SyntaxKind.ExportKeyword)], - factory.createVariableDeclarationList( - [ - factory.createVariableDeclaration( - contextValue.constName, - undefined, - recursiveTypeName - ? factory.createTypeReferenceNode( - factory.createQualifiedName( - dependencyIdentifier, - factory.createIdentifier("DataParser"), - ), - [factory.createTypeReferenceNode(recursiveTypeName)], - ) - : undefined, - contextValue.expression, - ), - ], - NodeFlags.Const, - ), - ), - ); - }, - ); - - const sourceFile = createSourceFile("print.ts", "", ScriptTarget.Latest, false, ScriptKind.TS); - const printer = createPrinter(); - - return pipe( - [ - ...importClauseTransformer(importClause), - ...TST.importTypesTransformer(importType), - ...recursiveTypeAliasDeclarations, - ...dataParserConstStatements, - ], - A.map( - (value) => printer.printNode( - EmitHint.Unspecified, - value, - sourceFile, - ), - ), - A.join("\n\n"), - S.trim, + return printer( + result, ); } diff --git a/scripts/toTypescript/buildContext.ts b/scripts/toTypescript/buildContext.ts new file mode 100644 index 0000000..1d15b5e --- /dev/null +++ b/scripts/toTypescript/buildContext.ts @@ -0,0 +1,75 @@ +import { DP, E, unwrap } from "@duplojs/utils"; +import { type createTransformer, transformer, type MapContext, type MapImportContext, type TransformerHook, type TransformerMode, type DataParserErrorEither, type DataParserNotSupportedEither } from "./transformer"; +import { getRecursiveDataParser } from "@scripts/utils"; +import { factory, SyntaxKind } from "typescript"; + +export interface BuildedContext { + readonly context: MapContext; + readonly importContext: MapImportContext; +} + +export interface BuildContextParams { + readonly identifier: string; + readonly transformers: readonly ReturnType[]; + readonly context?: MapContext; + readonly mode?: TransformerMode; + readonly hooks?: readonly TransformerHook[]; + readonly importContext?: MapImportContext; +} + +export function buildContext( + schema: DP.DataParser, + params: BuildContextParams, +): ( + | BuildedContext + | DataParserNotSupportedEither + | DataParserErrorEither + ) { + const context: MapContext = params.context ?? new Map(); + const importContext: MapImportContext = params.importContext ?? new Map(); + + const result = transformer( + schema, + { + ...params, + context, + importContext, + mode: params.mode ?? "out", + hooks: params.hooks ?? [], + recursiveDataParsers: getRecursiveDataParser(schema), + }, + ); + + if (E.isLeft(result)) { + return result; + } + + if (!schema.definition.identifier) { + context.set( + DP.empty(), + factory.createTypeAliasDeclaration( + [factory.createToken(SyntaxKind.ExportKeyword)], + factory.createIdentifier(params.identifier), + undefined, + unwrap(result), + ), + ); + } else if (schema.definition.identifier !== params.identifier) { + context.set( + DP.empty(), + factory.createTypeAliasDeclaration( + [factory.createToken(SyntaxKind.ExportKeyword)], + factory.createIdentifier(params.identifier), + undefined, + factory.createTypeReferenceNode( + schema.definition.identifier, + ), + ), + ); + } + + return { + context, + importContext, + }; +} diff --git a/scripts/toTypescript/index.ts b/scripts/toTypescript/index.ts index f73f81c..9d369e4 100644 --- a/scripts/toTypescript/index.ts +++ b/scripts/toTypescript/index.ts @@ -2,3 +2,5 @@ export * from "./transformer"; export * from "./override"; export * from "./render"; export * from "./kind"; +export * from "./buildContext"; +export * from "./printer"; diff --git a/scripts/toTypescript/printer.ts b/scripts/toTypescript/printer.ts new file mode 100644 index 0000000..fd1e27c --- /dev/null +++ b/scripts/toTypescript/printer.ts @@ -0,0 +1,25 @@ +import { createPrinter, createSourceFile, EmitHint, ScriptKind, ScriptTarget } from "typescript"; +import { type BuildedContext } from "./buildContext"; +import { A, pipe, S } from "@duplojs/utils"; +import { createImportDeclaration } from "./transformer"; + +export function printer(params: BuildedContext) { + const sourceFile = createSourceFile("print.ts", "", ScriptTarget.Latest, false, ScriptKind.TS); + const printer = createPrinter(); + + return pipe( + [ + ...createImportDeclaration(params.importContext), + ...params.context.values(), + ], + A.map( + (value) => printer.printNode( + EmitHint.Unspecified, + value, + sourceFile, + ), + ), + A.join("\n\n"), + S.trim, + ); +} diff --git a/scripts/toTypescript/render.ts b/scripts/toTypescript/render.ts index b40d1a2..a28bf27 100644 --- a/scripts/toTypescript/render.ts +++ b/scripts/toTypescript/render.ts @@ -1,17 +1,15 @@ -import { DP, unwrap, E, pipe, A, S, kindHeritage } from "@duplojs/utils"; -import { type DataParserErrorEither, type DataParserNotSupportedEither, transformer, type MapContext, type TransformerMode, type TransformerHook, type createTransformer, type MapImportType } from "./transformer"; -import { createPrinter, createSourceFile, EmitHint, factory, ScriptKind, ScriptTarget, SyntaxKind } from "typescript"; +import { type DP, E, kindHeritage } from "@duplojs/utils"; +import { type MapContext, type MapImportContext, type DataParserErrorEither, type DataParserNotSupportedEither } from "./transformer"; import { createToTypescriptKind } from "./kind"; -import { getRecursiveDataParser } from "@scripts/utils"; -import { importTypesTransformer } from "./transformer/importTypesTransformer"; +import { buildContext, type BuildContextParams } from "./buildContext"; +import { printer } from "./printer"; -export interface RenderParams { - readonly identifier: string; - readonly transformers: readonly ReturnType[]; - readonly context?: MapContext; - readonly mode?: TransformerMode; - readonly hooks?: readonly TransformerHook[]; - readonly importType?: MapImportType; +export interface RenderParams extends BuildContextParams { + + /** + * @deprecated use importContext + */ + readonly importType: MapImportContext; } export class DataParserToTypescriptRenderError extends kindHeritage( @@ -29,19 +27,13 @@ export class DataParserToTypescriptRenderError extends kindHeritage( export function render(schema: DP.DataParser, params: RenderParams) { const context: MapContext = new Map(params.context); - const importType: MapImportType = new Map(params.importType); + const importContext: MapImportContext = new Map(params.importContext ?? params.importType); - const result = transformer( - schema, - { - ...params, - context, - mode: params.mode ?? "out", - hooks: params.hooks ?? [], - recursiveDataParsers: getRecursiveDataParser(schema), - importType, - }, - ); + const result = buildContext(schema, { + ...params, + context, + importContext, + }); if (E.isLeft(result)) { throw new DataParserToTypescriptRenderError( @@ -50,46 +42,7 @@ export function render(schema: DP.DataParser, params: RenderParams) { ); } - if (schema.definition.identifier && schema.definition.identifier !== params.identifier) { - context.set( - DP.empty(), - factory.createTypeAliasDeclaration( - [factory.createToken(SyntaxKind.ExportKeyword)], - factory.createIdentifier(params.identifier), - undefined, - factory.createTypeReferenceNode( - schema.definition.identifier, - ), - ), - ); - } else if (schema.definition.identifier !== params.identifier) { - context.set( - DP.empty(), - factory.createTypeAliasDeclaration( - [factory.createToken(SyntaxKind.ExportKeyword)], - factory.createIdentifier(params.identifier), - undefined, - unwrap(result), - ), - ); - } - - const sourceFile = createSourceFile("print.ts", "", ScriptTarget.Latest, false, ScriptKind.TS); - const printer = createPrinter(); - - return pipe( - [ - ...importTypesTransformer(importType), - ...context.values(), - ], - A.map( - (value) => printer.printNode( - EmitHint.Unspecified, - value, - sourceFile, - ), - ), - A.join("\n\n"), - S.trim, + return printer( + result, ); } diff --git a/scripts/toTypescript/transformer/create.ts b/scripts/toTypescript/transformer/create.ts index 0ae8a24..d00405c 100644 --- a/scripts/toTypescript/transformer/create.ts +++ b/scripts/toTypescript/transformer/create.ts @@ -12,7 +12,19 @@ export type DataParserErrorEither< export type MapContext = Map; -export type MapImportType = Map; +export type MapImportContext = Map< + string, + | string[] + | { + type: "default" | "clause"; + identifier: string; + } +>; + +/** + * @deprecated use MapImportContext + */ +export type MapImportType = MapImportContext; export type MaybeTransformerEither = | TransformerSuccessEither @@ -24,7 +36,12 @@ export type TransformerMode = "in" | "out"; export interface TransformerParams { readonly mode: TransformerMode; readonly context: MapContext; - readonly importType: MapImportType; + readonly importContext: MapImportContext; + + /** + * @deprecated use importContext + */ + readonly importType: MapImportContext; transformer( schema: DP.DataParser, @@ -35,7 +52,7 @@ export interface TransformerParams { ): TransformerSuccessEither; buildError(): DataParserErrorEither; - addImport(path: string, typeName: string): void; + addImport(path: string, typeName: string, type?: "default" | "clause"): void; } export type TransformerBuildFunction< diff --git a/scripts/toTypescript/transformer/createImportDeclaration.ts b/scripts/toTypescript/transformer/createImportDeclaration.ts new file mode 100644 index 0000000..7c3751e --- /dev/null +++ b/scripts/toTypescript/transformer/createImportDeclaration.ts @@ -0,0 +1,61 @@ +import { pipe, G, A, P, isType } from "@duplojs/utils"; +import type { MapImportContext } from "./create"; +import { factory, SyntaxKind } from "typescript"; + +export function createImportDeclaration(importContext: MapImportContext) { + return pipe( + importContext, + G.map( + ([path, types]) => P.match(types) + .when( + isType("array"), + (identifiers) => factory.createImportDeclaration( + undefined, + factory.createImportClause( + SyntaxKind.TypeKeyword, + undefined, + factory.createNamedImports( + A.map( + identifiers, + (identifier) => factory.createImportSpecifier( + false, + undefined, + factory.createIdentifier(identifier), + ), + ), + ), + ), + factory.createStringLiteral(path), + undefined, + ), + ) + .with( + { type: "clause" }, + ({ identifier }) => factory.createImportDeclaration( + undefined, + factory.createImportClause( + undefined, + undefined, + factory.createNamespaceImport(factory.createIdentifier(identifier)), + ), + factory.createStringLiteral(path), + undefined, + ), + ) + .with( + { type: "default" }, + ({ identifier }) => factory.createImportDeclaration( + undefined, + factory.createImportClause( + undefined, + factory.createIdentifier(identifier), + undefined, + ), + factory.createStringLiteral(path), + undefined, + ), + ) + .exhaustive(), + ), + ); +} diff --git a/scripts/toTypescript/transformer/hook.ts b/scripts/toTypescript/transformer/hook.ts index 4878942..b4cf774 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, MapImportType } from "./create"; +import type { MapContext, MapImportContext } from "./create"; export type TransformerHookAction = "stop" | "next"; @@ -11,7 +11,12 @@ export interface TransformerHookOutput { export interface TransformerHookParams { schema: DP.DataParsers; context: MapContext; - importType: MapImportType; + importContext: MapImportContext; + + /** + * @deprecated use importContext + */ + importType: MapImportContext; output( action: TransformerHookAction, diff --git a/scripts/toTypescript/transformer/importTypesTransformer.ts b/scripts/toTypescript/transformer/importTypesTransformer.ts deleted file mode 100644 index befe51b..0000000 --- a/scripts/toTypescript/transformer/importTypesTransformer.ts +++ /dev/null @@ -1,30 +0,0 @@ -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/index.ts b/scripts/toTypescript/transformer/index.ts index 9d575e8..0f1a903 100644 --- a/scripts/toTypescript/transformer/index.ts +++ b/scripts/toTypescript/transformer/index.ts @@ -3,5 +3,5 @@ export * from "./transformer"; export * from "./hook"; export * from "./defaults"; export * from "./includesUndefinedTypeNode"; -export * from "./importTypesTransformer"; +export * from "./createImportDeclaration"; export { defaultTransformers } from "./defaults"; diff --git a/scripts/toTypescript/transformer/transformer.ts b/scripts/toTypescript/transformer/transformer.ts index 20f7aff..dd151ca 100644 --- a/scripts/toTypescript/transformer/transformer.ts +++ b/scripts/toTypescript/transformer/transformer.ts @@ -1,5 +1,5 @@ -import { A, type DDataParser, E, unwrap, type DP, justExec } from "@duplojs/utils"; -import type { MapContext, DataParserNotSupportedEither, TransformerParams, createTransformer, TransformerMode, DataParserErrorEither, MapImportType } from "./create"; +import { A, type DDataParser, E, unwrap, type DP, justExec, equal, pipe, isType, whenNot } from "@duplojs/utils"; +import type { MapContext, DataParserNotSupportedEither, TransformerParams, createTransformer, TransformerMode, DataParserErrorEither, MapImportContext } from "./create"; import { factory, SyntaxKind } from "typescript"; import type { TransformerHook } from "./hook"; @@ -9,7 +9,12 @@ export interface TransformerFunctionParams { readonly mode: TransformerMode; readonly hooks: readonly TransformerHook[]; readonly recursiveDataParsers: DDataParser.DataParser[]; - readonly importType: MapImportType; + readonly importContext: MapImportContext; + + /** + * @deprecated use importContext + */ + readonly importType?: MapImportContext; } export function transformer( @@ -23,7 +28,8 @@ export function transformer( const result = hook({ schema: lastValue, context: params.context, - importType: params.importType, + importContext: params.importContext, + importType: params.importContext, output: (action, schema) => ({ schema, action, @@ -88,12 +94,26 @@ export function transformer( buildError() { return E.left("buildDataParserError"); }, - importType: params.importType, - addImport(path, typeName) { - const types = params.importType.get(path) ?? []; + importContext: params.importContext, + importType: params.importContext, + addImport(path, typeName, type) { + if (equal(type, ["clause", "default"])) { + params.importContext.set(path, { + type, + identifier: typeName, + }); + } + + const types = pipe( + params.importContext.get(path), + whenNot( + isType("array"), + () => [], + ), + ); if (!A.includes(types, typeName)) { - params.importType.set(path, A.push(types, typeName)); + params.importContext.set(path, A.push(types, typeName)); } }, }; diff --git a/tests/toDataParser/dataParserTransformer/array.test.ts b/tests/toDataParser/dataParserTransformer/array.test.ts index 42f4682..0f9cb81 100644 --- a/tests/toDataParser/dataParserTransformer/array.test.ts +++ b/tests/toDataParser/dataParserTransformer/array.test.ts @@ -2,21 +2,16 @@ import { DP, DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "ArrayParser", - transformers: tsDefaultTransformers, -}; - describe("array", () => { it("renders array parser", () => { expect( render( DPE.array(DPE.string()), { - constName: "arrayParser", + identifier: "arrayParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -27,7 +22,7 @@ describe("array", () => { () => render( DPE.array(DPE.string()), { - constName: "arrayParserError", + identifier: "arrayParserError", dataParserTransformers: [ ((dataParser, { buildError }) => DP.stringKind.has(dataParser) ? buildError() @@ -35,7 +30,7 @@ describe("array", () => { ...defaultTransformers, ], checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -50,14 +45,14 @@ describe("array", () => { () => render( schema, { - constName: "arrayParserCheckerError", + identifier: "arrayParserCheckerError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/file.test.ts b/tests/toDataParser/dataParserTransformer/file.test.ts index 06f346b..a1b4fb2 100644 --- a/tests/toDataParser/dataParserTransformer/file.test.ts +++ b/tests/toDataParser/dataParserTransformer/file.test.ts @@ -48,7 +48,7 @@ describe("file", () => { SDP.file(), { constName: "fileParserExtended", - exportMode: "extended", + importMode: "extended", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, toTypescript, diff --git a/tests/toDataParser/render.test.ts b/tests/toDataParser/render.test.ts index 728dc08..225b270 100644 --- a/tests/toDataParser/render.test.ts +++ b/tests/toDataParser/render.test.ts @@ -173,7 +173,7 @@ describe("render", () => { checkedExtendedSchema, { constName: "checkedExtendedParser", - exportMode: "extended", + importMode: "extended", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, toTypescript: { diff --git a/tests/toTypescript/transfomers/templateLiteral.test.ts b/tests/toTypescript/transfomers/templateLiteral.test.ts index 25edf7c..13e766e 100644 --- a/tests/toTypescript/transfomers/templateLiteral.test.ts +++ b/tests/toTypescript/transfomers/templateLiteral.test.ts @@ -87,6 +87,7 @@ describe("templateLiteral", () => { buildError: () => E.left("buildDataParserError"), mode: "out", context: new Map(), + importContext: new Map(), importType: new Map(), addImport(path, typeName) { return; @@ -111,6 +112,7 @@ describe("templateLiteral", () => { buildError: () => E.left("buildDataParserError"), mode: "out", context: new Map(), + importContext: new Map(), importType: new Map(), addImport(path, typeName) { return; From 131c74f09cc93523b4175e1281d684f40a94ebd5 Mon Sep 17 00:00:00 2001 From: ZeRiix Date: Sat, 23 May 2026 18:41:44 +0200 Subject: [PATCH 10/16] feat(06): rework imports --- scripts/toDataParser/buildContext.ts | 19 +++-- .../toDataParser/checkerTransformer/create.ts | 9 ++ .../checkerTransformer/defaults/time/max.ts | 5 +- .../checkerTransformer/defaults/time/min.ts | 5 +- .../checkerTransformer/transformer.ts | 6 +- .../dataParserTransformer/create.ts | 7 +- .../dataParserTransformer/defaults/file.ts | 4 +- .../dataParserTransformer/defaults/time.ts | 7 +- .../getDefinitionDataParser.ts | 10 ++- .../dataParserTransformer/hook.ts | 5 ++ .../dataParserTransformer/transformer.ts | 29 ++----- scripts/toDataParser/render.ts | 24 ++++-- scripts/toTypescript/buildContext.ts | 13 ++- scripts/toTypescript/render.ts | 16 ++-- scripts/toTypescript/transformer/addImport.ts | 63 ++++++++++++++ scripts/toTypescript/transformer/create.ts | 12 +-- .../transformer/createImportDeclaration.ts | 85 ++++++++++--------- scripts/toTypescript/transformer/index.ts | 1 + .../toTypescript/transformer/transformer.ts | 26 +----- 19 files changed, 219 insertions(+), 127 deletions(-) create mode 100644 scripts/toTypescript/transformer/addImport.ts diff --git a/scripts/toDataParser/buildContext.ts b/scripts/toDataParser/buildContext.ts index d93f138..a95cb2b 100644 --- a/scripts/toDataParser/buildContext.ts +++ b/scripts/toDataParser/buildContext.ts @@ -1,6 +1,6 @@ import { DP, E, unwrap } from "@duplojs/utils"; import { type createTransformer, transformer, type MapContext, type TransformerHook, type DataParserErrorEither, type DataParserNotSupportedEither, type DataParserGetDefinitionErrorEither, type ToTypescriptDataParserErrorEither, type ToTypescriptDataParserNotSupportedEither } from "./dataParserTransformer"; -import type * as TST from "@scripts/toTypescript"; +import * as TST from "@scripts/toTypescript"; import { getRecursiveDataParser } from "@scripts/utils"; import { factory } from "typescript"; import { type createCheckerTransformer } from "./checkerTransformer"; @@ -22,6 +22,12 @@ export interface BuildContextParams { readonly context?: MapContext; readonly typescriptContext?: TST.MapContext; readonly importContext?: TST.MapImportContext; + + /** + * @deprecated use importContext + */ + readonly importType?: TST.MapImportType; + readonly importMode?: ImportMode; readonly hooks?: readonly TransformerHook[]; readonly toTypescript?: { @@ -43,18 +49,19 @@ export function buildContext( ) { const context: MapContext = params.context ?? new Map(); const typescriptContext = params.typescriptContext ?? new Map(); - const importContext: TST.MapImportContext = params.importContext ?? new Map(); + const importContext: TST.MapImportContext = TST.createImportContext( + params.importContext, + params.importType, + ); const importMode = params.importMode ?? "lite"; importContext.set("@duplojs/utils/dataParser", { - type: "clause", - identifier: "DP", + namespace: ["DP"], }); if (importMode === "extended") { importContext.set("@duplojs/utils/dataParserExtended", { - type: "clause", - identifier: "DPE", + namespace: ["DPE"], }); } diff --git a/scripts/toDataParser/checkerTransformer/create.ts b/scripts/toDataParser/checkerTransformer/create.ts index 1def70c..a792674 100644 --- a/scripts/toDataParser/checkerTransformer/create.ts +++ b/scripts/toDataParser/checkerTransformer/create.ts @@ -1,5 +1,6 @@ import type { CallExpression, ObjectLiteralExpression, PropertyAssignment } from "typescript"; import { type DP, E } from "@duplojs/utils"; +import type * as TST from "@scripts/toTypescript"; export type CheckerTransformerSuccessEither = E.Right<"buildSuccess", CallExpression>; @@ -13,10 +14,18 @@ export type CheckerTransformerEither = | CheckerTransformerBuildErrorEither; export interface CheckerTransformerParams { + readonly importContext: TST.MapImportContext; + + /** + * @deprecated use importContext + */ + readonly importType: TST.MapImportContext; + success( result: CallExpression, ): CheckerTransformerSuccessEither; buildError(): CheckerTransformerBuildErrorEither; + addImport(path: string, typeName: string, type?: "default" | "namespace" | "direct"): void; getDefinition( customProperties?: readonly PropertyAssignment[] ): readonly [ObjectLiteralExpression] | readonly []; diff --git a/scripts/toDataParser/checkerTransformer/defaults/time/max.ts b/scripts/toDataParser/checkerTransformer/defaults/time/max.ts index e5100cf..3f4f862 100644 --- a/scripts/toDataParser/checkerTransformer/defaults/time/max.ts +++ b/scripts/toDataParser/checkerTransformer/defaults/time/max.ts @@ -9,8 +9,11 @@ export const checkerTimeMaxTransformer = createCheckerTransformer( { success, getDefinition, + addImport, }, ) => { + addImport("@duplojs/utils/date", "D", "namespace"); + const expression = factory.createCallExpression( factory.createPropertyAccessExpression( factory.createIdentifier("DP"), @@ -20,7 +23,7 @@ export const checkerTimeMaxTransformer = createCheckerTransformer( [ factory.createCallExpression( factory.createPropertyAccessExpression( - factory.createIdentifier("DDate"), + factory.createIdentifier("D"), factory.createIdentifier("createTime"), ), undefined, diff --git a/scripts/toDataParser/checkerTransformer/defaults/time/min.ts b/scripts/toDataParser/checkerTransformer/defaults/time/min.ts index 6edc1c6..e4cd808 100644 --- a/scripts/toDataParser/checkerTransformer/defaults/time/min.ts +++ b/scripts/toDataParser/checkerTransformer/defaults/time/min.ts @@ -9,8 +9,11 @@ export const checkerTimeMinTransformer = createCheckerTransformer( { success, getDefinition, + addImport, }, ) => { + addImport("@duplojs/utils/date", "D", "namespace"); + const expression = factory.createCallExpression( factory.createPropertyAccessExpression( factory.createIdentifier("DP"), @@ -20,7 +23,7 @@ export const checkerTimeMinTransformer = createCheckerTransformer( [ factory.createCallExpression( factory.createPropertyAccessExpression( - factory.createIdentifier("DDate"), + factory.createIdentifier("D"), factory.createIdentifier("createTime"), ), undefined, diff --git a/scripts/toDataParser/checkerTransformer/transformer.ts b/scripts/toDataParser/checkerTransformer/transformer.ts index 8c69945..a9afadc 100644 --- a/scripts/toDataParser/checkerTransformer/transformer.ts +++ b/scripts/toDataParser/checkerTransformer/transformer.ts @@ -1,9 +1,11 @@ import { A, E, type DP } from "@duplojs/utils"; import type { CheckerTransformerParams, createCheckerTransformer, CheckerTransformerEither } from "./create"; import { factory, type PropertyAssignment } from "typescript"; +import * as TST from "@scripts/toTypescript"; export interface CheckerTransformerFunctionParams { readonly transformers: readonly ReturnType[]; + readonly importContext: TST.MapImportContext; } export function getCheckerDefinition(checker: DP.DataParserChecker, customProperties?: readonly PropertyAssignment[]) { @@ -32,12 +34,15 @@ export function checkerTransformer( params: CheckerTransformerFunctionParams, ) { const functionParams: CheckerTransformerParams = { + importContext: params.importContext, + importType: params.importContext, success(result) { return E.right("buildSuccess", result); }, buildError() { return E.left("buildCheckerError", checker); }, + addImport: TST.createAddImport(params.importContext), getDefinition(customProperties) { return getCheckerDefinition(checker, customProperties); }, @@ -68,4 +73,3 @@ export function checkerTransformer( }, ); } - diff --git a/scripts/toDataParser/dataParserTransformer/create.ts b/scripts/toDataParser/dataParserTransformer/create.ts index cea6ad5..edb5372 100644 --- a/scripts/toDataParser/dataParserTransformer/create.ts +++ b/scripts/toDataParser/dataParserTransformer/create.ts @@ -42,6 +42,11 @@ export interface TransformerParams { readonly context: MapContext; readonly importContext: TST.MapImportContext; + /** + * @deprecated use importContext + */ + readonly importType: TST.MapImportContext; + transformer( dataParser: DP.DataParser, ): MaybeTransformerEither; @@ -51,7 +56,7 @@ export interface TransformerParams { ): TransformerSuccessEither; buildError(): DataParserErrorEither; - addImport(path: string, typeName: string, type?: "default" | "clause"): void; + addImport(path: string, typeName: string, type?: "default" | "namespace" | "direct"): void; getDefinition( customProperties?: readonly PropertyAssignment[], ): readonly [ObjectLiteralExpression] | readonly [] | DataParserGetDefinitionErrorEither; diff --git a/scripts/toDataParser/dataParserTransformer/defaults/file.ts b/scripts/toDataParser/dataParserTransformer/defaults/file.ts index fb64385..b8e7692 100644 --- a/scripts/toDataParser/dataParserTransformer/defaults/file.ts +++ b/scripts/toDataParser/dataParserTransformer/defaults/file.ts @@ -66,13 +66,13 @@ export const fileTransformer = createTransformer( const namespace = dependencyIdentifier.text === "DP" ? justExec( () => { - addImport("@duplojs/server-utils/dataParser", "SDP", "clause"); + addImport("@duplojs/server-utils/dataParser", "SDP", "namespace"); return "SDP"; }, ) : justExec( () => { - addImport("@duplojs/server-utils/dataParserExtended", "SDPE", "clause"); + addImport("@duplojs/server-utils/dataParserExtended", "SDPE", "namespace"); return "SDPE"; }, ); diff --git a/scripts/toDataParser/dataParserTransformer/defaults/time.ts b/scripts/toDataParser/dataParserTransformer/defaults/time.ts index d76e2bd..61e7ff5 100644 --- a/scripts/toDataParser/dataParserTransformer/defaults/time.ts +++ b/scripts/toDataParser/dataParserTransformer/defaults/time.ts @@ -1,4 +1,4 @@ -import { A, DP, E, pipe } from "@duplojs/utils"; +import { DP, E, pipe } from "@duplojs/utils"; import { createTransformer } from "../create"; import { factory } from "typescript"; @@ -10,7 +10,6 @@ export const timeTransformer = createTransformer( success, dependencyIdentifier, getDefinition, - addImport, }, ) => { const definition = getDefinition( @@ -28,10 +27,6 @@ export const timeTransformer = createTransformer( return definition; } - if (A.minElements(dataParser.definition.checkers, 1)) { - addImport("@duplojs/utils/date", "DDate", "clause"); - } - return pipe( factory.createCallExpression( factory.createPropertyAccessExpression( diff --git a/scripts/toDataParser/dataParserTransformer/getDefinitionDataParser.ts b/scripts/toDataParser/dataParserTransformer/getDefinitionDataParser.ts index e62a4a5..11ec1dd 100644 --- a/scripts/toDataParser/dataParserTransformer/getDefinitionDataParser.ts +++ b/scripts/toDataParser/dataParserTransformer/getDefinitionDataParser.ts @@ -1,10 +1,12 @@ import { A, type DP, E, pipe, when } from "@duplojs/utils"; import { checkerTransformer, type createCheckerTransformer } from "../checkerTransformer"; import { type CallExpression, factory, type PropertyAssignment } from "typescript"; +import type * as TST from "@scripts/toTypescript"; export interface getDefinitionDataParserParams { readonly dataParser: DP.DataParser; readonly checkerTransformers: readonly ReturnType[]; + readonly importContext: TST.MapImportContext; readonly customProperties: readonly PropertyAssignment[]; } @@ -27,7 +29,13 @@ export function getDefinitionDataParser(params: getDefinitionDataParserParams) { params.dataParser.definition.checkers, A.reduceFrom([]), ({ element, lastValue, nextPush, exit }) => pipe( - checkerTransformer(element, { transformers: params.checkerTransformers }), + checkerTransformer( + element, + { + transformers: params.checkerTransformers, + importContext: params.importContext, + }, + ), E.whenIsRight( (value) => nextPush(lastValue, value), ), diff --git a/scripts/toDataParser/dataParserTransformer/hook.ts b/scripts/toDataParser/dataParserTransformer/hook.ts index 7ff329c..d279bfe 100644 --- a/scripts/toDataParser/dataParserTransformer/hook.ts +++ b/scripts/toDataParser/dataParserTransformer/hook.ts @@ -14,6 +14,11 @@ export interface TransformerHookParams { context: MapContext; importContext: TST.MapImportContext; + /** + * @deprecated use importContext + */ + importType: TST.MapImportContext; + output( action: TransformerHookAction, dataParser: DP.DataParsers diff --git a/scripts/toDataParser/dataParserTransformer/transformer.ts b/scripts/toDataParser/dataParserTransformer/transformer.ts index b0552e1..f3e60e1 100644 --- a/scripts/toDataParser/dataParserTransformer/transformer.ts +++ b/scripts/toDataParser/dataParserTransformer/transformer.ts @@ -1,11 +1,10 @@ -import { A, E, type DP, unwrap, S, justExec, pipe, whenNot, isType, equal } from "@duplojs/utils"; +import { A, E, type DP, unwrap, S, justExec } from "@duplojs/utils"; import * as TST from "@scripts/toTypescript"; import type { MapContext, TransformerParams, createTransformer, MaybeTransformerEither } from "./create"; import { factory, type Identifier } from "typescript"; import type { TransformerHook } from "./hook"; -import { type createCheckerTransformer } from "../checkerTransformer"; +import type { createCheckerTransformer } from "../checkerTransformer"; import { getDefinitionDataParser } from "./getDefinitionDataParser"; -import { success } from "@duplojs/utils/either"; export interface TransformerFunctionParams { readonly dataParserTransformers: readonly ReturnType[]; @@ -35,6 +34,7 @@ export function transformer( dataParser: lastValue, context: params.context, importContext: params.importContext, + importType: params.importContext, output: (action, dataParser) => ({ dataParser, action, @@ -94,33 +94,16 @@ export function transformer( return E.left("buildDataParserError", currentDataParser); }, importContext: params.importContext, + importType: params.importContext, getDefinition(customProperties = []) { return getDefinitionDataParser({ dataParser: currentDataParser, checkerTransformers: params.checkerTransformers, + importContext: params.importContext, customProperties, }); }, - addImport(path, typeName, type) { - if (equal(type, ["clause", "default"])) { - params.importContext.set(path, { - type, - identifier: typeName, - }); - } - - const types = pipe( - params.importContext.get(path), - whenNot( - isType("array"), - () => [], - ), - ); - - if (!A.includes(types, typeName)) { - params.importContext.set(path, A.push(types, typeName)); - } - }, + addImport: TST.createAddImport(params.importContext), }; const result = currentDataParser.definition.overrideDataParserTransformer diff --git a/scripts/toDataParser/render.ts b/scripts/toDataParser/render.ts index e7acdf5..afa3e10 100644 --- a/scripts/toDataParser/render.ts +++ b/scripts/toDataParser/render.ts @@ -1,12 +1,11 @@ -import type * as TST from "@scripts/toTypescript"; +import * as TST from "@scripts/toTypescript"; import { type DataParserNotSupportedEither, type DataParserGetDefinitionErrorEither, type DataParserErrorEither, type MapContext, type ToTypescriptDataParserErrorEither, type ToTypescriptDataParserNotSupportedEither } from "./dataParserTransformer"; import { createToDataParserKind } from "./kind"; import { buildContext, type BuildContextParams } from "./buildContext"; -import { type DP, E, kindHeritage } from "@duplojs/utils"; +import { type DP, E, kindClass } from "@duplojs/utils"; import { printer } from "./printer"; -export class DataParserToDataParserRenderError extends kindHeritage( - "data-parser-to-data-parser-render-error", +export class DataParserToDataParserRenderError extends kindClass( createToDataParserKind("data-parser-to-data-parser-render-error"), Error, ) { @@ -14,12 +13,11 @@ export class DataParserToDataParserRenderError extends kindHeritage( public dataParser: DP.DataParser, public error: DataParserNotSupportedEither | DataParserErrorEither | DataParserGetDefinitionErrorEither, ) { - super({}, ["Error during the render of dataParser in dataParser."]); + super({}, "Error during the render of dataParser in dataParser."); } } -export class DataParserToDataParserTypeRenderError extends kindHeritage( - "data-parser-to-data-parser-type-render-error", +export class DataParserToDataParserTypeRenderError extends kindClass( createToDataParserKind("data-parser-to-data-parser-type-render-error"), Error, ) { @@ -27,17 +25,25 @@ export class DataParserToDataParserTypeRenderError extends kindHeritage( public dataParser: DP.DataParser, public error: ToTypescriptDataParserNotSupportedEither | ToTypescriptDataParserErrorEither, ) { - super({}, ["Error during the render of recursive dataParser type."]); + super({}, "Error during the render of recursive dataParser type."); } } export interface RenderParams extends BuildContextParams { + + /** + * @deprecated use importContext + */ + readonly importType?: TST.MapImportType; } export function render(dataParser: DP.DataParser, params: RenderParams) { const context: MapContext = new Map(params.context); const typescriptContext = new Map(params.typescriptContext); - const importContext: TST.MapImportContext = new Map(params.importContext); + const importContext: TST.MapImportContext = TST.createImportContext( + params.importContext, + params.importType, + ); const result = buildContext(dataParser, { ...params, diff --git a/scripts/toTypescript/buildContext.ts b/scripts/toTypescript/buildContext.ts index 1d15b5e..bf0ddea 100644 --- a/scripts/toTypescript/buildContext.ts +++ b/scripts/toTypescript/buildContext.ts @@ -1,5 +1,5 @@ import { DP, E, unwrap } from "@duplojs/utils"; -import { type createTransformer, transformer, type MapContext, type MapImportContext, type TransformerHook, type TransformerMode, type DataParserErrorEither, type DataParserNotSupportedEither } from "./transformer"; +import { type createTransformer, transformer, type MapContext, type MapImportContext, type MapImportType, type TransformerHook, type TransformerMode, type DataParserErrorEither, type DataParserNotSupportedEither, createImportContext } from "./transformer"; import { getRecursiveDataParser } from "@scripts/utils"; import { factory, SyntaxKind } from "typescript"; @@ -15,6 +15,11 @@ export interface BuildContextParams { readonly mode?: TransformerMode; readonly hooks?: readonly TransformerHook[]; readonly importContext?: MapImportContext; + + /** + * @deprecated use importContext + */ + readonly importType?: MapImportType; } export function buildContext( @@ -26,7 +31,10 @@ export function buildContext( | DataParserErrorEither ) { const context: MapContext = params.context ?? new Map(); - const importContext: MapImportContext = params.importContext ?? new Map(); + const importContext: MapImportContext = createImportContext( + params.importContext, + params.importType, + ); const result = transformer( schema, @@ -34,6 +42,7 @@ export function buildContext( ...params, context, importContext, + importType: importContext, mode: params.mode ?? "out", hooks: params.hooks ?? [], recursiveDataParsers: getRecursiveDataParser(schema), diff --git a/scripts/toTypescript/render.ts b/scripts/toTypescript/render.ts index a28bf27..efb38e3 100644 --- a/scripts/toTypescript/render.ts +++ b/scripts/toTypescript/render.ts @@ -1,5 +1,5 @@ -import { type DP, E, kindHeritage } from "@duplojs/utils"; -import { type MapContext, type MapImportContext, type DataParserErrorEither, type DataParserNotSupportedEither } from "./transformer"; +import { type DP, E, kindClass } from "@duplojs/utils"; +import { type MapContext, type MapImportContext, type MapImportType, type DataParserErrorEither, type DataParserNotSupportedEither, createImportContext } from "./transformer"; import { createToTypescriptKind } from "./kind"; import { buildContext, type BuildContextParams } from "./buildContext"; import { printer } from "./printer"; @@ -9,11 +9,10 @@ export interface RenderParams extends BuildContextParams { /** * @deprecated use importContext */ - readonly importType: MapImportContext; + readonly importType?: MapImportType; } -export class DataParserToTypescriptRenderError extends kindHeritage( - "data-parser-to-typescript-render-error", +export class DataParserToTypescriptRenderError extends kindClass( createToTypescriptKind("data-parser-to-typescript-render-error"), Error, ) { @@ -21,13 +20,16 @@ export class DataParserToTypescriptRenderError extends kindHeritage( public schema: DP.DataParser, public error: DataParserNotSupportedEither | DataParserErrorEither, ) { - super({}, ["Error during the render of dataParser in typescript type."]); + super({}, "Error during the render of dataParser in typescript type."); } } export function render(schema: DP.DataParser, params: RenderParams) { const context: MapContext = new Map(params.context); - const importContext: MapImportContext = new Map(params.importContext ?? params.importType); + const importContext: MapImportContext = createImportContext( + params.importContext, + params.importType, + ); const result = buildContext(schema, { ...params, diff --git a/scripts/toTypescript/transformer/addImport.ts b/scripts/toTypescript/transformer/addImport.ts new file mode 100644 index 0000000..3835e1b --- /dev/null +++ b/scripts/toTypescript/transformer/addImport.ts @@ -0,0 +1,63 @@ +import { A } from "@duplojs/utils"; +import type { MapImportContext, MapImportType } from "./create"; + +/** + * @deprecated Internal compatibility helper for legacy importType. Use MapImportContext directly. + */ +export function createImportContext( + importContext?: MapImportContext, + importType?: MapImportType, +) { + const newImportContext: MapImportContext = new Map(importContext); + + if (!importType) { + return newImportContext; + } + + for (const [path, identifiers] of importType) { + const currentImports = newImportContext.get(path) ?? {}; + const direct = A.reduce( + identifiers, + A.reduceFrom(currentImports.direct ?? []), + ({ element, lastValue, next }) => next( + A.includes(lastValue, element) + ? lastValue + : A.push(lastValue, element), + ), + ); + + newImportContext.set( + path, + { + ...currentImports, + direct, + }, + ); + } + + return newImportContext; +} + +export function createAddImport(importContext: MapImportContext) { + return ( + path: string, + typeName: string, + type?: "default" | "namespace" | "direct", + ) => { + const importKind = type === undefined + ? "direct" + : type; + const imports = importContext.get(path) ?? {}; + const identifiers = imports[importKind] ?? []; + + if (!A.includes(identifiers, typeName)) { + importContext.set( + path, + { + ...imports, + [importKind]: A.push(identifiers, typeName), + }, + ); + } + }; +} diff --git a/scripts/toTypescript/transformer/create.ts b/scripts/toTypescript/transformer/create.ts index d00405c..277a179 100644 --- a/scripts/toTypescript/transformer/create.ts +++ b/scripts/toTypescript/transformer/create.ts @@ -14,17 +14,17 @@ export type MapContext = Map; export type MapImportContext = Map< string, - | string[] - | { - type: "default" | "clause"; - identifier: string; + { + namespace?: string[]; + default?: string[]; + direct?: string[]; } >; /** * @deprecated use MapImportContext */ -export type MapImportType = MapImportContext; +export type MapImportType = Map; export type MaybeTransformerEither = | TransformerSuccessEither @@ -52,7 +52,7 @@ export interface TransformerParams { ): TransformerSuccessEither; buildError(): DataParserErrorEither; - addImport(path: string, typeName: string, type?: "default" | "clause"): void; + addImport(path: string, typeName: string, type?: "default" | "namespace" | "direct"): void; } export type TransformerBuildFunction< diff --git a/scripts/toTypescript/transformer/createImportDeclaration.ts b/scripts/toTypescript/transformer/createImportDeclaration.ts index 7c3751e..8b7b292 100644 --- a/scripts/toTypescript/transformer/createImportDeclaration.ts +++ b/scripts/toTypescript/transformer/createImportDeclaration.ts @@ -1,37 +1,16 @@ -import { pipe, G, A, P, isType } from "@duplojs/utils"; +import { A } from "@duplojs/utils"; import type { MapImportContext } from "./create"; -import { factory, SyntaxKind } from "typescript"; +import { factory, type ImportDeclaration } from "typescript"; export function createImportDeclaration(importContext: MapImportContext) { - return pipe( - importContext, - G.map( - ([path, types]) => P.match(types) - .when( - isType("array"), - (identifiers) => factory.createImportDeclaration( - undefined, - factory.createImportClause( - SyntaxKind.TypeKeyword, - undefined, - factory.createNamedImports( - A.map( - identifiers, - (identifier) => factory.createImportSpecifier( - false, - undefined, - factory.createIdentifier(identifier), - ), - ), - ), - ), - factory.createStringLiteral(path), - undefined, - ), - ) - .with( - { type: "clause" }, - ({ identifier }) => factory.createImportDeclaration( + return A.reduce( + A.from(importContext), + A.reduceFrom([]), + ({ element: [path, imports], lastValue, next }) => { + const declarations = A.concat( + A.map( + imports.namespace ?? [], + (identifier) => factory.createImportDeclaration( undefined, factory.createImportClause( undefined, @@ -41,10 +20,10 @@ export function createImportDeclaration(importContext: MapImportContext) { factory.createStringLiteral(path), undefined, ), - ) - .with( - { type: "default" }, - ({ identifier }) => factory.createImportDeclaration( + ), + A.map( + imports.default ?? [], + (identifier) => factory.createImportDeclaration( undefined, factory.createImportClause( undefined, @@ -54,8 +33,38 @@ export function createImportDeclaration(importContext: MapImportContext) { factory.createStringLiteral(path), undefined, ), - ) - .exhaustive(), - ), + ), + ); + + return next( + A.concat( + lastValue, + imports.direct?.length + ? A.push( + declarations, + factory.createImportDeclaration( + undefined, + factory.createImportClause( + undefined, + undefined, + factory.createNamedImports( + A.map( + imports.direct, + (identifier) => factory.createImportSpecifier( + false, + undefined, + factory.createIdentifier(identifier), + ), + ), + ), + ), + factory.createStringLiteral(path), + undefined, + ), + ) + : declarations, + ), + ); + }, ); } diff --git a/scripts/toTypescript/transformer/index.ts b/scripts/toTypescript/transformer/index.ts index 0f1a903..b497b52 100644 --- a/scripts/toTypescript/transformer/index.ts +++ b/scripts/toTypescript/transformer/index.ts @@ -4,4 +4,5 @@ export * from "./hook"; export * from "./defaults"; export * from "./includesUndefinedTypeNode"; export * from "./createImportDeclaration"; +export * from "./addImport"; export { defaultTransformers } from "./defaults"; diff --git a/scripts/toTypescript/transformer/transformer.ts b/scripts/toTypescript/transformer/transformer.ts index dd151ca..f8401af 100644 --- a/scripts/toTypescript/transformer/transformer.ts +++ b/scripts/toTypescript/transformer/transformer.ts @@ -1,7 +1,8 @@ -import { A, type DDataParser, E, unwrap, type DP, justExec, equal, pipe, isType, whenNot } from "@duplojs/utils"; +import { A, type DDataParser, E, unwrap, type DP, justExec } from "@duplojs/utils"; import type { MapContext, DataParserNotSupportedEither, TransformerParams, createTransformer, TransformerMode, DataParserErrorEither, MapImportContext } from "./create"; import { factory, SyntaxKind } from "typescript"; import type { TransformerHook } from "./hook"; +import { createAddImport } from "./addImport"; export interface TransformerFunctionParams { readonly transformers: readonly ReturnType[]; @@ -16,7 +17,6 @@ export interface TransformerFunctionParams { */ readonly importType?: MapImportContext; } - export function transformer( schema: DP.DataParser, params: TransformerFunctionParams, @@ -96,26 +96,7 @@ export function transformer( }, importContext: params.importContext, importType: params.importContext, - addImport(path, typeName, type) { - if (equal(type, ["clause", "default"])) { - params.importContext.set(path, { - type, - identifier: typeName, - }); - } - - const types = pipe( - params.importContext.get(path), - whenNot( - isType("array"), - () => [], - ), - ); - - if (!A.includes(types, typeName)) { - params.importContext.set(path, A.push(types, typeName)); - } - }, + addImport: createAddImport(params.importContext), }; const result = currentSchema.definition.overrideTypescriptTransformer @@ -173,4 +154,3 @@ export function transformer( return result; } - From 88221b5edd8e0f08bcb7ee9ffb5eb65cf46b253a Mon Sep 17 00:00:00 2001 From: ZeRiix Date: Sat, 23 May 2026 18:41:48 +0200 Subject: [PATCH 11/16] feat(06): update tests --- .../toDataParser/__snapshots__/basic.gen.ts | 2 +- .../__snapshots__/recursive.gen.ts | 51 ++++----- ...ConstName.gen.ts => withIdentifier.gen.ts} | 2 +- integration/toDataParser/index.test.ts | 43 +++---- .../__snapshots__/index.test.ts.snap | 2 +- .../__snapshots__/render.test.ts.snap | 107 ++++++++++-------- .../__snapshots__/timeMax.test.ts.snap | 2 +- .../__snapshots__/timeMin.test.ts.snap | 2 +- .../checkerTransfomers/arrayMax.test.ts | 5 +- .../checkerTransfomers/arrayMin.test.ts | 5 +- .../checkerTransfomers/bigintMax.test.ts | 5 +- .../checkerTransfomers/bigintMin.test.ts | 5 +- .../checkerTransfomers/email.test.ts | 5 +- .../checkerTransfomers/int.test.ts | 5 +- .../checkerTransfomers/numberMax.test.ts | 10 +- .../checkerTransfomers/numberMin.test.ts | 10 +- .../checkerTransfomers/refine.test.ts | 28 ++++- .../checkerTransfomers/regex.test.ts | 5 +- .../checkerTransfomers/stringMax.test.ts | 5 +- .../checkerTransfomers/stringMin.test.ts | 5 +- .../checkerTransfomers/timeMax.test.ts | 9 +- .../checkerTransfomers/timeMin.test.ts | 9 +- .../checkerTransfomers/url.test.ts | 10 +- .../checkerTransfomers/uuid.test.ts | 5 +- .../__snapshots__/time.test.ts.snap | 4 +- .../dataParserTransformer/bigint.test.ts | 17 +-- .../dataParserTransformer/boolean.test.ts | 17 +-- .../dataParserTransformer/date.test.ts | 17 +-- .../dataParserTransformer/empty.test.ts | 17 +-- .../dataParserTransformer/file.test.ts | 21 ++-- .../dataParserTransformer/lazy.test.ts | 17 +-- .../dataParserTransformer/literal.test.ts | 13 +-- .../dataParserTransformer/nil.test.ts | 17 +-- .../dataParserTransformer/nullable.test.ts | 17 +-- .../dataParserTransformer/number.test.ts | 17 +-- .../dataParserTransformer/object.test.ts | 17 +-- .../dataParserTransformer/optional.test.ts | 17 +-- .../dataParserTransformer/pipe.test.ts | 21 ++-- .../dataParserTransformer/record.test.ts | 21 ++-- .../dataParserTransformer/recover.test.ts | 7 +- .../dataParserTransformer/string.test.ts | 13 +-- .../templateLiteral.test.ts | 17 +-- .../dataParserTransformer/time.test.ts | 17 +-- .../dataParserTransformer/transform.test.ts | 37 +++--- .../dataParserTransformer/tuple.test.ts | 25 ++-- .../dataParserTransformer/union.test.ts | 17 +-- .../dataParserTransformer/unknown.test.ts | 13 +-- tests/toDataParser/override.test.ts | 29 +++-- tests/toDataParser/render.test.ts | 49 +++----- .../__snapshots__/date.test.ts.snap | 10 +- .../__snapshots__/file.test.ts.snap | 6 +- .../__snapshots__/time.test.ts.snap | 10 +- 52 files changed, 397 insertions(+), 440 deletions(-) rename integration/toDataParser/__snapshots__/{withConstName.gen.ts => withIdentifier.gen.ts} (88%) diff --git a/integration/toDataParser/__snapshots__/basic.gen.ts b/integration/toDataParser/__snapshots__/basic.gen.ts index 3df86ec..cbbc136 100644 --- a/integration/toDataParser/__snapshots__/basic.gen.ts +++ b/integration/toDataParser/__snapshots__/basic.gen.ts @@ -1,6 +1,6 @@ import * as DP from "@duplojs/utils/dataParser"; -export const userProfileParser = DP.object({ +export const user = DP.object({ id: DP.templateLiteral(["user-", DP.number(), "-db1"]), name: DP.string({ checkers: [DP.checkerStringMin(2)] }), email: DP.string({ checkers: [DP.checkerEmail()] }), diff --git a/integration/toDataParser/__snapshots__/recursive.gen.ts b/integration/toDataParser/__snapshots__/recursive.gen.ts index 728ed2d..00ca13d 100644 --- a/integration/toDataParser/__snapshots__/recursive.gen.ts +++ b/integration/toDataParser/__snapshots__/recursive.gen.ts @@ -1,43 +1,40 @@ import * as DP from "@duplojs/utils/dataParser"; export type RecursiveType0 = { - name: string; - children: RecursiveType0[]; - comment: { - id: string; - replies: RecursiveType1[]; - }; - meta: [ - string, - RecursiveType2[] - ]; -}; - -export type RecursiveType1 = { id: string; - replies: RecursiveType1[]; + replies: RecursiveType0[]; }; +export type $recursiveDataParser2 = RecursiveType0; + export type RecursiveType2 = [ string, RecursiveType2[] ]; -export type RecursiveNode = RecursiveType0; +export type $recursiveDataParser4 = RecursiveType2; + +export type RecursiveType4 = { + name: string; + children: RecursiveType4[]; + comment: RecursiveType0; + meta: RecursiveType2; +}; + +export type $recursiveDataParser0 = RecursiveType4; + +export const recursiveDataParser0: DP.DataParser<$recursiveDataParser0> = DP.object({ + name: DP.string(), + children: DP.array(DP.lazy(() => recursiveDataParser0)), + comment: DP.lazy(() => recursiveDataParser2), + meta: DP.lazy(() => recursiveDataParser4) +}); -export const recursiveDataParser1: DP.DataParser = DP.object({ +export const recursiveDataParser2: DP.DataParser<$recursiveDataParser2> = DP.object({ id: DP.string(), - replies: DP.array(DP.lazy(() => recursiveDataParser1)) + replies: DP.array(DP.lazy(() => recursiveDataParser2)) }); -export const recursiveDataParser2: DP.DataParser = DP.tuple([DP.string(), DP.array(DP.lazy(() => recursiveDataParser2))]); +export const recursiveDataParser4: DP.DataParser<$recursiveDataParser4> = DP.tuple([DP.string(), DP.array(DP.lazy(() => recursiveDataParser4))]); -export const recursiveNodeDataParser: DP.DataParser = DP.object({ - name: DP.string(), - children: DP.array(DP.lazy(() => recursiveNodeDataParser)), - comment: DP.object({ - id: DP.string(), - replies: DP.array(DP.lazy(() => recursiveDataParser1)) - }), - meta: DP.tuple([DP.string(), DP.array(DP.lazy(() => recursiveDataParser2))]) -}); \ No newline at end of file +export const recursiveNode = recursiveDataParser0; \ No newline at end of file diff --git a/integration/toDataParser/__snapshots__/withConstName.gen.ts b/integration/toDataParser/__snapshots__/withIdentifier.gen.ts similarity index 88% rename from integration/toDataParser/__snapshots__/withConstName.gen.ts rename to integration/toDataParser/__snapshots__/withIdentifier.gen.ts index f5ec1fb..2b43845 100644 --- a/integration/toDataParser/__snapshots__/withConstName.gen.ts +++ b/integration/toDataParser/__snapshots__/withIdentifier.gen.ts @@ -2,7 +2,7 @@ import * as DP from "@duplojs/utils/dataParser"; export const userRoleDataParser = DP.literal(["admin", "editor", "viewer"]); -export const userDataParser = DP.object({ +export const user = DP.object({ id: DP.templateLiteral(["user-", DP.number(), "-db1"]), name: DP.string({ checkers: [DP.checkerStringMin(2)] }), email: DP.string({ checkers: [DP.checkerEmail()] }), diff --git a/integration/toDataParser/index.test.ts b/integration/toDataParser/index.test.ts index 011dcf2..3d93de2 100644 --- a/integration/toDataParser/index.test.ts +++ b/integration/toDataParser/index.test.ts @@ -26,7 +26,7 @@ async function typedSnapshot(value: string, filePath: string) { describe("integration", () => { it("basic", async() => { - const userSchema = DPE.object({ + const userDataParser = DPE.object({ id: DPE.templateLiteral(["user-", DPE.number(), "-db1"]), name: DPE.string().min(2), email: DPE.email(), @@ -60,18 +60,15 @@ describe("integration", () => { location: DPE.tuple([DPE.number(), DPE.number()], { rest: DPE.number() }), createdAt: DPE.date({ coerce: true }), startAt: DPE.time(), - }).addConstName("userProfileParser"); + }); const result = render( - userSchema, + userDataParser, { - constName: "userProfileParser", + identifier: "user", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript: { - identifier: "UserProfile", - transformers: tsDefaultTransformers, - }, + typescriptTransformers: tsDefaultTransformers, }, ); @@ -92,49 +89,43 @@ describe("integration", () => { const nodeSchema: DPE.DataParser = DPE.object({ name: DPE.string(), children: DPE.lazy(() => nodeSchema).array(), - comment: commentSchema, - meta: metaSchema, - }).addConstName("recursiveNodeDataParser"); + comment: DPE.lazy(() => commentSchema), + meta: DPE.lazy(() => metaSchema), + }); const result = render( nodeSchema, { - constName: "recursiveNodeDataParser", + identifier: "recursiveNode", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript: { - identifier: "RecursiveNode", - transformers: tsDefaultTransformers, - }, + typescriptTransformers: tsDefaultTransformers, }, ); await typedSnapshot(result, "__snapshots__/recursive.gen.ts"); }); - it("divide with constName", async() => { - const roleDataParser = DPE.literal(["admin", "editor", "viewer"]).addConstName("userRoleDataParser"); + it("divide with identifier", async() => { + const userRoleDataParser = DPE.literal(["admin", "editor", "viewer"]).addIdentifier("userRole"); const userDataParser = DPE.object({ id: DPE.templateLiteral(["user-", DPE.number(), "-db1"]), name: DPE.string().min(2), email: DPE.email(), - role: roleDataParser, - }).addConstName("userDataParser"); + role: userRoleDataParser, + }); const result = render( userDataParser, { - constName: "userDataParser", + identifier: "user", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript: { - identifier: "UserProfile", - transformers: tsDefaultTransformers, - }, + typescriptTransformers: tsDefaultTransformers, }, ); - await typedSnapshot(result, "__snapshots__/withConstName.gen.ts"); + await typedSnapshot(result, "__snapshots__/withIdentifier.gen.ts"); }); }); diff --git a/integration/toTypescript/__snapshots__/index.test.ts.snap b/integration/toTypescript/__snapshots__/index.test.ts.snap index e038bde..e6c088f 100644 --- a/integration/toTypescript/__snapshots__/index.test.ts.snap +++ b/integration/toTypescript/__snapshots__/index.test.ts.snap @@ -1,7 +1,7 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`integration 1`] = ` -"import type { TheDate, TheTime } from "@duplojs/utils/date"; +"import { TheDate, TheTime } from "@duplojs/utils/date"; export type UserProfile = { id: \`user-\${number}-db1\`; diff --git a/tests/toDataParser/__snapshots__/render.test.ts.snap b/tests/toDataParser/__snapshots__/render.test.ts.snap index 0f0e1ba..61729a8 100644 --- a/tests/toDataParser/__snapshots__/render.test.ts.snap +++ b/tests/toDataParser/__snapshots__/render.test.ts.snap @@ -7,9 +7,9 @@ export type RecursiveType0 = { next: RecursiveType0; }; -export type RecursiveNode = RecursiveType0; +export type $recursiveDataParser0 = RecursiveType0; -export const recursiveDataParser0: DP.DataParser = DP.object({ +export const recursiveDataParser0: DP.DataParser<$recursiveDataParser0> = DP.object({ next: DP.lazy(() => recursiveDataParser0) }); @@ -19,12 +19,12 @@ export const recursiveNodeParser = recursiveDataParser0;" exports[`render > renders checked dataParsers in normal and extended modes 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -import * as DDate from "@duplojs/utils/date"; +import * as D from "@duplojs/utils/date"; export const checkedParser = DP.object({ startAt: DP.time({ checkers: [ - DP.checkerTimeMin(DDate.createTime(1000, "millisecond")), - DP.checkerTimeMax(DDate.createTime(5000, "millisecond")) + DP.checkerTimeMin(D.createTime(1000, "millisecond")), + DP.checkerTimeMax(D.createTime(5000, "millisecond")) ] }), name: DP.string({ checkers: [DP.checkerStringMin(2)] }), count: DP.number({ checkers: [ @@ -39,10 +39,10 @@ exports[`render > renders checked dataParsers in normal and extended modes 2`] = import * as DPE from "@duplojs/utils/dataParserExtended"; -import * as DDate from "@duplojs/utils/date"; +import * as D from "@duplojs/utils/date"; export const checkedExtendedParser = DPE.object({ - startAt: DPE.time({ checkers: [DP.checkerTimeMin(DDate.createTime(250, "millisecond"))] }), + startAt: DPE.time({ checkers: [DP.checkerTimeMin(D.createTime(250, "millisecond"))] }), tags: DPE.array(DPE.string({ checkers: [DP.checkerStringMin(1)] }), { checkers: [DP.checkerArrayMin(1)] }) });" `; @@ -50,82 +50,99 @@ export const checkedExtendedParser = DPE.object({ exports[`render > renders complex nested recursive dataParsers 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export type RecursiveType0 = { +export type RecursiveType0 = (string | RecursiveType0 | RecursiveType1)[]; + +export type RecursiveType1 = { recursiveProp: { - self: RecursiveType0; - array: RecursiveType1; + self: RecursiveType1; + array: RecursiveType0; tuple: RecursiveType2; union: RecursiveType3; }; - children: RecursiveType0[]; + children: RecursiveType1[]; tuple: RecursiveType2; - array: RecursiveType1; + array: RecursiveType0; union: RecursiveType3; }; -export type RecursiveType1 = (string | RecursiveType1 | RecursiveType0)[]; - export type RecursiveType2 = [ string, - RecursiveType0, + RecursiveType1, (RecursiveType2 | RecursiveType3 | string)[] ]; -export type RecursiveType3 = string | RecursiveType0 | RecursiveType2 | RecursiveType3[]; +export type RecursiveType3 = string | RecursiveType1 | RecursiveType2 | RecursiveType3[]; -export type ComplexRecursive = RecursiveType0; +export type $recursiveDataParser2 = RecursiveType0; -export const recursiveDataParser1: DP.DataParser = DP.array(DP.union([ - DP.string(), - DP.lazy(() => recursiveDataParser1), - DP.lazy(() => recursiveDataParser0) -])); +export type $recursiveDataParser6 = RecursiveType3; + +export type $recursiveDataParser4 = RecursiveType2; + +export type $recursiveDataParser0 = RecursiveType1; + +export const recursiveDataParser0: DP.DataParser<$recursiveDataParser0> = DP.object({ + recursiveProp: DP.object({ + self: DP.lazy(() => recursiveDataParser0), + array: recursiveDataParser2, + tuple: recursiveDataParser4, + union: recursiveDataParser6 + }), + children: DP.array(DP.lazy(() => recursiveDataParser0)), + tuple: recursiveDataParser4, + array: recursiveDataParser2, + union: recursiveDataParser6 +}); -export const recursiveDataParser3: DP.DataParser = DP.union([ +export const recursiveDataParser2: DP.DataParser<$recursiveDataParser2> = DP.array(DP.union([ DP.string(), - DP.lazy(() => recursiveDataParser0), DP.lazy(() => recursiveDataParser2), - DP.array(DP.lazy(() => recursiveDataParser3)) -]); + DP.lazy(() => recursiveDataParser0) +])); -export const recursiveDataParser2: DP.DataParser = DP.tuple([ +export const recursiveDataParser4: DP.DataParser<$recursiveDataParser4> = DP.tuple([ DP.string(), DP.lazy(() => recursiveDataParser0), DP.array(DP.union([ - DP.lazy(() => recursiveDataParser2), - DP.lazy(() => recursiveDataParser3), + DP.lazy(() => recursiveDataParser4), + DP.lazy(() => recursiveDataParser6), DP.string() ])) ]); -export const recursiveDataParser0: DP.DataParser = DP.object({ - recursiveProp: DP.object({ - self: DP.lazy(() => recursiveDataParser0), - array: recursiveDataParser1, - tuple: recursiveDataParser2, - union: recursiveDataParser3 - }), - children: DP.array(DP.lazy(() => recursiveDataParser0)), - tuple: recursiveDataParser2, - array: recursiveDataParser1, - union: recursiveDataParser3 -}); +export const recursiveDataParser6: DP.DataParser<$recursiveDataParser6> = DP.union([ + DP.string(), + DP.lazy(() => recursiveDataParser0), + DP.lazy(() => recursiveDataParser4), + DP.array(DP.lazy(() => recursiveDataParser6)) +]); export const complexRecursiveParser = recursiveDataParser0;" `; -exports[`render > renders dataParser in compact mode when indent is false 1`] = ` +exports[`render > renders dataParser with nested checkers 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const compactParser = DP.object({ name: DP.string({ checkers: [DP.checkerStringMin(2)] }), roles: DP.array(DP.literal(["admin", "editor"]), { checkers: [DP.checkerArrayMin(1)] }), contact: DP.union([DP.object({ email: DP.string({ checkers: [DP.checkerEmail()] }) }), DP.object({ phone: DP.string({ checkers: [DP.checkerRegex(/^[+\\d][\\d\\s-]{5,}$/)] }) })]) });" +export const compactParser = DP.object({ + name: DP.string({ checkers: [DP.checkerStringMin(2)] }), + roles: DP.array(DP.literal(["admin", "editor"]), { checkers: [DP.checkerArrayMin(1)] }), + contact: DP.union([ + DP.object({ + email: DP.string({ checkers: [DP.checkerEmail()] }) + }), + DP.object({ + phone: DP.string({ checkers: [DP.checkerRegex(/^[+\\d][\\d\\s-]{5,}$/)] }) + }) + ]) +});" `; exports[`render > renders named dependencies before their consumers 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const childParser = DP.string(); +export const childParserDataParser = DP.string(); export const parentParser = DP.object({ - child: childParser + child: childParserDataParser });" `; diff --git a/tests/toDataParser/checkerTransfomers/__snapshots__/timeMax.test.ts.snap b/tests/toDataParser/checkerTransfomers/__snapshots__/timeMax.test.ts.snap index 56342ad..f8ede2d 100644 --- a/tests/toDataParser/checkerTransfomers/__snapshots__/timeMax.test.ts.snap +++ b/tests/toDataParser/checkerTransfomers/__snapshots__/timeMax.test.ts.snap @@ -1,3 +1,3 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`checkerTimeMax > basic 1`] = `"DP.checkerTimeMax(DDate.createTime(2000, "millisecond"))"`; +exports[`checkerTimeMax > basic 1`] = `"DP.checkerTimeMax(D.createTime(2000, "millisecond"))"`; diff --git a/tests/toDataParser/checkerTransfomers/__snapshots__/timeMin.test.ts.snap b/tests/toDataParser/checkerTransfomers/__snapshots__/timeMin.test.ts.snap index 467aa91..7342f22 100644 --- a/tests/toDataParser/checkerTransfomers/__snapshots__/timeMin.test.ts.snap +++ b/tests/toDataParser/checkerTransfomers/__snapshots__/timeMin.test.ts.snap @@ -1,3 +1,3 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`checkerTimeMin > basic 1`] = `"DP.checkerTimeMin(DDate.createTime(1000, "millisecond"))"`; +exports[`checkerTimeMin > basic 1`] = `"DP.checkerTimeMin(D.createTime(1000, "millisecond"))"`; diff --git a/tests/toDataParser/checkerTransfomers/arrayMax.test.ts b/tests/toDataParser/checkerTransfomers/arrayMax.test.ts index c5eb3aa..c47abd2 100644 --- a/tests/toDataParser/checkerTransfomers/arrayMax.test.ts +++ b/tests/toDataParser/checkerTransfomers/arrayMax.test.ts @@ -6,7 +6,10 @@ describe("checkerArrayMax", () => { it("basic", () => { const result = DataParserToDataParser.checkerTransformer( DP.checkerArrayMax(5), - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); asserts(result, E.isRight); diff --git a/tests/toDataParser/checkerTransfomers/arrayMin.test.ts b/tests/toDataParser/checkerTransfomers/arrayMin.test.ts index 7a660ce..41ad63b 100644 --- a/tests/toDataParser/checkerTransfomers/arrayMin.test.ts +++ b/tests/toDataParser/checkerTransfomers/arrayMin.test.ts @@ -6,7 +6,10 @@ describe("checkerArrayMin", () => { it("basic", () => { const result = DataParserToDataParser.checkerTransformer( DP.checkerArrayMin(1), - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); asserts(result, E.isRight); diff --git a/tests/toDataParser/checkerTransfomers/bigintMax.test.ts b/tests/toDataParser/checkerTransfomers/bigintMax.test.ts index 74588a3..4134783 100644 --- a/tests/toDataParser/checkerTransfomers/bigintMax.test.ts +++ b/tests/toDataParser/checkerTransfomers/bigintMax.test.ts @@ -6,7 +6,10 @@ describe("checkerBigIntMax", () => { it("basic", () => { const result = DataParserToDataParser.checkerTransformer( DP.checkerBigIntMax(10n), - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); asserts(result, E.isRight); diff --git a/tests/toDataParser/checkerTransfomers/bigintMin.test.ts b/tests/toDataParser/checkerTransfomers/bigintMin.test.ts index 5b7b4e7..c7e0e3c 100644 --- a/tests/toDataParser/checkerTransfomers/bigintMin.test.ts +++ b/tests/toDataParser/checkerTransfomers/bigintMin.test.ts @@ -6,7 +6,10 @@ describe("checkerBigIntMin", () => { it("basic", () => { const result = DataParserToDataParser.checkerTransformer( DP.checkerBigIntMin(1n), - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); asserts(result, E.isRight); diff --git a/tests/toDataParser/checkerTransfomers/email.test.ts b/tests/toDataParser/checkerTransfomers/email.test.ts index 90b48ca..d894e5c 100644 --- a/tests/toDataParser/checkerTransfomers/email.test.ts +++ b/tests/toDataParser/checkerTransfomers/email.test.ts @@ -6,7 +6,10 @@ describe("checkerEmail", () => { it("basic", () => { const result = DataParserToDataParser.checkerTransformer( DP.checkerEmail(), - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); asserts(result, E.isRight); diff --git a/tests/toDataParser/checkerTransfomers/int.test.ts b/tests/toDataParser/checkerTransfomers/int.test.ts index 35b6db5..e1c868f 100644 --- a/tests/toDataParser/checkerTransfomers/int.test.ts +++ b/tests/toDataParser/checkerTransfomers/int.test.ts @@ -6,7 +6,10 @@ describe("checkerInt", () => { it("basic", () => { const result = DataParserToDataParser.checkerTransformer( DP.checkerInt(), - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); asserts(result, E.isRight); diff --git a/tests/toDataParser/checkerTransfomers/numberMax.test.ts b/tests/toDataParser/checkerTransfomers/numberMax.test.ts index 3c32d65..c07e13d 100644 --- a/tests/toDataParser/checkerTransfomers/numberMax.test.ts +++ b/tests/toDataParser/checkerTransfomers/numberMax.test.ts @@ -6,7 +6,10 @@ describe("checkerNumberMax", () => { it("exclusive", () => { const result = DataParserToDataParser.checkerTransformer( DP.checkerNumberMax(10, { exclusive: true }), - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); asserts(result, E.isRight); @@ -16,7 +19,10 @@ describe("checkerNumberMax", () => { it("non exclusive", () => { const result = DataParserToDataParser.checkerTransformer( DP.checkerNumberMax(10), - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); asserts(result, E.isRight); diff --git a/tests/toDataParser/checkerTransfomers/numberMin.test.ts b/tests/toDataParser/checkerTransfomers/numberMin.test.ts index 8e626c4..1f24151 100644 --- a/tests/toDataParser/checkerTransfomers/numberMin.test.ts +++ b/tests/toDataParser/checkerTransfomers/numberMin.test.ts @@ -6,7 +6,10 @@ describe("checkerNumberMin", () => { it("exclusive", () => { const result = DataParserToDataParser.checkerTransformer( DP.checkerNumberMin(1, { exclusive: true }), - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); asserts(result, E.isRight); @@ -16,7 +19,10 @@ describe("checkerNumberMin", () => { it("non exclusive", () => { const result = DataParserToDataParser.checkerTransformer( DP.checkerNumberMin(1), - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); asserts(result, E.isRight); diff --git a/tests/toDataParser/checkerTransfomers/refine.test.ts b/tests/toDataParser/checkerTransfomers/refine.test.ts index 3b4aedc..d58cc9e 100644 --- a/tests/toDataParser/checkerTransfomers/refine.test.ts +++ b/tests/toDataParser/checkerTransfomers/refine.test.ts @@ -14,7 +14,10 @@ describe("checkerRefine", () => { const checker = DP.checkerRefine((value: number[]) => value.length > 0); const result = DataParserToDataParser.checkerTransformer( checker, - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); asserts(result, E.isRight); @@ -25,7 +28,10 @@ describe("checkerRefine", () => { const checker = DP.checkerRefine(Array.isArray as never); const result = DataParserToDataParser.checkerTransformer( checker, - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); expect(result).toEqual(E.left("buildCheckerError", checker)); @@ -37,7 +43,10 @@ describe("checkerRefine", () => { const result = DataParserToDataParser.checkerTransformer( checker, - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); expect(result).toEqual(E.left("buildCheckerError", checker)); @@ -49,7 +58,10 @@ describe("checkerRefine", () => { const result = DataParserToDataParser.checkerTransformer( checker, - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); expect(result).toEqual(E.left("buildCheckerError", checker)); @@ -68,13 +80,17 @@ describe("checkerRefine", () => { const { checkerRefineTransformer } = await import("@scripts/toDataParser/checkerTransformer/defaults/refine"); const checker = DP.checkerRefine(() => true); + const importContext = new Map(); const result = checkerRefineTransformer(checker, { + importContext, + importType: importContext, success(value) { return E.right("buildSuccess", value); }, buildError() { return E.left("buildCheckerError", checker); }, + addImport() {}, getDefinition() { return []; }, @@ -96,13 +112,17 @@ describe("checkerRefine", () => { const { checkerRefineTransformer } = await import("@scripts/toDataParser/checkerTransformer/defaults/refine"); const checker = DP.checkerRefine(() => true); + const importContext = new Map(); const result = checkerRefineTransformer(checker, { + importContext, + importType: importContext, success(value) { return E.right("buildSuccess", value); }, buildError() { return E.left("buildCheckerError", checker); }, + addImport() {}, getDefinition() { return []; }, diff --git a/tests/toDataParser/checkerTransfomers/regex.test.ts b/tests/toDataParser/checkerTransfomers/regex.test.ts index f038a6a..e0967bf 100644 --- a/tests/toDataParser/checkerTransfomers/regex.test.ts +++ b/tests/toDataParser/checkerTransfomers/regex.test.ts @@ -6,7 +6,10 @@ describe("checkerRegex", () => { it("basic", () => { const result = DataParserToDataParser.checkerTransformer( DP.checkerRegex(/^[a-z]+$/), - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); asserts(result, E.isRight); diff --git a/tests/toDataParser/checkerTransfomers/stringMax.test.ts b/tests/toDataParser/checkerTransfomers/stringMax.test.ts index 4577a2b..4591143 100644 --- a/tests/toDataParser/checkerTransfomers/stringMax.test.ts +++ b/tests/toDataParser/checkerTransfomers/stringMax.test.ts @@ -6,7 +6,10 @@ describe("checkerStringMax", () => { it("basic", () => { const result = DataParserToDataParser.checkerTransformer( DP.checkerStringMax(10), - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); asserts(result, E.isRight); diff --git a/tests/toDataParser/checkerTransfomers/stringMin.test.ts b/tests/toDataParser/checkerTransfomers/stringMin.test.ts index 984f844..4c5d594 100644 --- a/tests/toDataParser/checkerTransfomers/stringMin.test.ts +++ b/tests/toDataParser/checkerTransfomers/stringMin.test.ts @@ -6,7 +6,10 @@ describe("checkerStringMin", () => { it("basic", () => { const result = DataParserToDataParser.checkerTransformer( DP.checkerStringMin(2), - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); asserts(result, E.isRight); diff --git a/tests/toDataParser/checkerTransfomers/timeMax.test.ts b/tests/toDataParser/checkerTransfomers/timeMax.test.ts index 4fa5ac9..354f49b 100644 --- a/tests/toDataParser/checkerTransfomers/timeMax.test.ts +++ b/tests/toDataParser/checkerTransfomers/timeMax.test.ts @@ -4,12 +4,19 @@ import { printExpression } from "./utils"; describe("checkerTimeMax", () => { it("basic", () => { + const importContext = new Map(); const result = DataParserToDataParser.checkerTransformer( DP.checkerTimeMax(DDate.createTime(2000, "millisecond")), - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext, + }, ); asserts(result, E.isRight); + expect(importContext.get("@duplojs/utils/date")).toStrictEqual({ + namespace: ["D"], + }); expect(printExpression(unwrap(result))).toMatchSnapshot(); }); }); diff --git a/tests/toDataParser/checkerTransfomers/timeMin.test.ts b/tests/toDataParser/checkerTransfomers/timeMin.test.ts index 8d62221..3160b63 100644 --- a/tests/toDataParser/checkerTransfomers/timeMin.test.ts +++ b/tests/toDataParser/checkerTransfomers/timeMin.test.ts @@ -4,12 +4,19 @@ import { printExpression } from "./utils"; describe("checkerTimeMin", () => { it("basic", () => { + const importContext = new Map(); const result = DataParserToDataParser.checkerTransformer( DP.checkerTimeMin(DDate.createTime(1000, "millisecond")), - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext, + }, ); asserts(result, E.isRight); + expect(importContext.get("@duplojs/utils/date")).toStrictEqual({ + namespace: ["D"], + }); expect(printExpression(unwrap(result))).toMatchSnapshot(); }); }); diff --git a/tests/toDataParser/checkerTransfomers/url.test.ts b/tests/toDataParser/checkerTransfomers/url.test.ts index 89a394a..1438098 100644 --- a/tests/toDataParser/checkerTransfomers/url.test.ts +++ b/tests/toDataParser/checkerTransfomers/url.test.ts @@ -10,7 +10,10 @@ describe("checkerUrl", () => { normalize: true, protocol: /^https?$/, }), - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); asserts(result, E.isRight); @@ -20,7 +23,10 @@ describe("checkerUrl", () => { it("without options", () => { const result = DataParserToDataParser.checkerTransformer( DP.checkerUrl(), - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); asserts(result, E.isRight); diff --git a/tests/toDataParser/checkerTransfomers/uuid.test.ts b/tests/toDataParser/checkerTransfomers/uuid.test.ts index a93ab5d..df7674c 100644 --- a/tests/toDataParser/checkerTransfomers/uuid.test.ts +++ b/tests/toDataParser/checkerTransfomers/uuid.test.ts @@ -6,7 +6,10 @@ describe("checkerUuid", () => { it("basic", () => { const result = DataParserToDataParser.checkerTransformer( DP.checkerUuid(), - { transformers: DataParserToDataParser.defaultCheckerTransformers }, + { + transformers: DataParserToDataParser.defaultCheckerTransformers, + importContext: new Map(), + }, ); asserts(result, E.isRight); diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/time.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/time.test.ts.snap index 5cf4178..1d2d762 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/time.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/time.test.ts.snap @@ -3,11 +3,11 @@ exports[`time > renders time parser with checker imports 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -import * as DDate from "@duplojs/utils/date"; +import * as D from "@duplojs/utils/date"; export const timeParser = DP.time({ coerce: true, - checkers: [DP.checkerTimeMin(DDate.createTime(1, "millisecond"))] + checkers: [DP.checkerTimeMin(D.createTime(1, "millisecond"))] });" `; diff --git a/tests/toDataParser/dataParserTransformer/bigint.test.ts b/tests/toDataParser/dataParserTransformer/bigint.test.ts index ca7e8fc..f2e7458 100644 --- a/tests/toDataParser/dataParserTransformer/bigint.test.ts +++ b/tests/toDataParser/dataParserTransformer/bigint.test.ts @@ -2,21 +2,16 @@ import { DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "BigintParser", - transformers: tsDefaultTransformers, -}; - describe("bigint", () => { it("renders bigint parser", () => { expect( render( DPE.bigint({ coerce: true }), { - constName: "bigintParser", + identifier: "bigintParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -27,10 +22,10 @@ describe("bigint", () => { render( DPE.bigint(), { - constName: "bigintParserNoCoerce", + identifier: "bigintParserNoCoerce", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -45,14 +40,14 @@ describe("bigint", () => { () => render( schema, { - constName: "bigintParserError", + identifier: "bigintParserError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/boolean.test.ts b/tests/toDataParser/dataParserTransformer/boolean.test.ts index 6897282..6464665 100644 --- a/tests/toDataParser/dataParserTransformer/boolean.test.ts +++ b/tests/toDataParser/dataParserTransformer/boolean.test.ts @@ -2,21 +2,16 @@ import { DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "BooleanParser", - transformers: tsDefaultTransformers, -}; - describe("boolean", () => { it("renders boolean parser", () => { expect( render( DPE.boolean({ coerce: true }), { - constName: "booleanParser", + identifier: "booleanParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -27,10 +22,10 @@ describe("boolean", () => { render( DPE.boolean(), { - constName: "booleanParserNoCoerce", + identifier: "booleanParserNoCoerce", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -45,14 +40,14 @@ describe("boolean", () => { () => render( schema, { - constName: "booleanParserError", + identifier: "booleanParserError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/date.test.ts b/tests/toDataParser/dataParserTransformer/date.test.ts index e22bf7a..feca440 100644 --- a/tests/toDataParser/dataParserTransformer/date.test.ts +++ b/tests/toDataParser/dataParserTransformer/date.test.ts @@ -2,21 +2,16 @@ import { DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "DateParser", - transformers: tsDefaultTransformers, -}; - describe("date", () => { it("renders date parser", () => { expect( render( DPE.date({ coerce: true }), { - constName: "dateParser", + identifier: "dateParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -27,10 +22,10 @@ describe("date", () => { render( DPE.date(), { - constName: "dateParserNoCoerce", + identifier: "dateParserNoCoerce", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -45,14 +40,14 @@ describe("date", () => { () => render( schema, { - constName: "dateParserError", + identifier: "dateParserError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/empty.test.ts b/tests/toDataParser/dataParserTransformer/empty.test.ts index eb7e12a..655358b 100644 --- a/tests/toDataParser/dataParserTransformer/empty.test.ts +++ b/tests/toDataParser/dataParserTransformer/empty.test.ts @@ -2,21 +2,16 @@ import { DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "EmptyParser", - transformers: tsDefaultTransformers, -}; - describe("empty", () => { it("renders empty parser", () => { expect( render( DPE.empty({ coerce: true }), { - constName: "emptyParser", + identifier: "emptyParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -27,10 +22,10 @@ describe("empty", () => { render( DPE.empty(), { - constName: "emptyParserNoCoerce", + identifier: "emptyParserNoCoerce", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -45,14 +40,14 @@ describe("empty", () => { () => render( schema, { - constName: "emptyParserError", + identifier: "emptyParserError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/file.test.ts b/tests/toDataParser/dataParserTransformer/file.test.ts index a1b4fb2..00e503a 100644 --- a/tests/toDataParser/dataParserTransformer/file.test.ts +++ b/tests/toDataParser/dataParserTransformer/file.test.ts @@ -3,11 +3,6 @@ import { E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "FileParser", - transformers: tsDefaultTransformers, -}; - describe("file", () => { it("renders file parser with async constraints", () => { expect( @@ -19,10 +14,10 @@ describe("file", () => { mimeType: /image\/png/, }), { - constName: "fileParser", + identifier: "fileParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -33,10 +28,10 @@ describe("file", () => { render( SDP.file(), { - constName: "fileParserNoOptions", + identifier: "fileParserNoOptions", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -47,11 +42,11 @@ describe("file", () => { render( SDP.file(), { - constName: "fileParserExtended", + identifier: "fileParserExtended", importMode: "extended", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -66,14 +61,14 @@ describe("file", () => { () => render( schema, { - constName: "fileParserError", + identifier: "fileParserError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/lazy.test.ts b/tests/toDataParser/dataParserTransformer/lazy.test.ts index b34643f..afdba7e 100644 --- a/tests/toDataParser/dataParserTransformer/lazy.test.ts +++ b/tests/toDataParser/dataParserTransformer/lazy.test.ts @@ -2,21 +2,16 @@ import { DP, DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "LazyParser", - transformers: tsDefaultTransformers, -}; - describe("lazy", () => { it("renders lazy parser", () => { expect( render( DPE.lazy(() => DPE.string()), { - constName: "lazyParser", + identifier: "lazyParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -27,7 +22,7 @@ describe("lazy", () => { () => render( DPE.lazy(() => DPE.string()), { - constName: "lazyParserError", + identifier: "lazyParserError", dataParserTransformers: [ ((dataParser, { buildError }) => DP.stringKind.has(dataParser) ? buildError() @@ -35,7 +30,7 @@ describe("lazy", () => { ...defaultTransformers, ], checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -50,14 +45,14 @@ describe("lazy", () => { () => render( schema, { - constName: "lazyParserCheckerError", + identifier: "lazyParserCheckerError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/literal.test.ts b/tests/toDataParser/dataParserTransformer/literal.test.ts index 6eef50b..356e1d2 100644 --- a/tests/toDataParser/dataParserTransformer/literal.test.ts +++ b/tests/toDataParser/dataParserTransformer/literal.test.ts @@ -2,21 +2,16 @@ import { DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "LiteralParser", - transformers: tsDefaultTransformers, -}; - describe("literal", () => { it("renders literal parser", () => { expect( render( DPE.literal(["foo", 1, 1n, true, false, null, undefined]), { - constName: "literalParser", + identifier: "literalParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -31,14 +26,14 @@ describe("literal", () => { () => render( schema, { - constName: "literalParserCheckerError", + identifier: "literalParserCheckerError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/nil.test.ts b/tests/toDataParser/dataParserTransformer/nil.test.ts index a6457da..18cc8e9 100644 --- a/tests/toDataParser/dataParserTransformer/nil.test.ts +++ b/tests/toDataParser/dataParserTransformer/nil.test.ts @@ -2,21 +2,16 @@ import { DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "NilParser", - transformers: tsDefaultTransformers, -}; - describe("nil", () => { it("renders nil parser", () => { expect( render( DPE.nil({ coerce: true }), { - constName: "nilParser", + identifier: "nilParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -27,10 +22,10 @@ describe("nil", () => { render( DPE.nil(), { - constName: "nilParserNoCoerce", + identifier: "nilParserNoCoerce", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -43,14 +38,14 @@ describe("nil", () => { () => render( schema, { - constName: "nilParserError", + identifier: "nilParserError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/nullable.test.ts b/tests/toDataParser/dataParserTransformer/nullable.test.ts index 1f0af35..5ebe221 100644 --- a/tests/toDataParser/dataParserTransformer/nullable.test.ts +++ b/tests/toDataParser/dataParserTransformer/nullable.test.ts @@ -2,21 +2,16 @@ import { DP, DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "NullableParser", - transformers: tsDefaultTransformers, -}; - describe("nullable", () => { it("renders nullable parser", () => { expect( render( DPE.nullable(DPE.string()), { - constName: "nullableParser", + identifier: "nullableParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -27,7 +22,7 @@ describe("nullable", () => { () => render( DPE.nullable(DPE.string()), { - constName: "nullableParserError", + identifier: "nullableParserError", dataParserTransformers: [ ((dataParser, { buildError }) => DP.stringKind.has(dataParser) ? buildError() @@ -35,7 +30,7 @@ describe("nullable", () => { ...defaultTransformers, ], checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -50,14 +45,14 @@ describe("nullable", () => { () => render( schema, { - constName: "nullableParserCheckerError", + identifier: "nullableParserCheckerError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/number.test.ts b/tests/toDataParser/dataParserTransformer/number.test.ts index ed71e20..c6fd1f4 100644 --- a/tests/toDataParser/dataParserTransformer/number.test.ts +++ b/tests/toDataParser/dataParserTransformer/number.test.ts @@ -2,21 +2,16 @@ import { DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "NumberParser", - transformers: tsDefaultTransformers, -}; - describe("number", () => { it("renders number parser", () => { expect( render( DPE.number({ coerce: true }), { - constName: "numberParser", + identifier: "numberParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -27,10 +22,10 @@ describe("number", () => { render( DPE.number(), { - constName: "numberParserNoCoerce", + identifier: "numberParserNoCoerce", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -45,14 +40,14 @@ describe("number", () => { () => render( schema, { - constName: "numberParserError", + identifier: "numberParserError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/object.test.ts b/tests/toDataParser/dataParserTransformer/object.test.ts index 3c9fe41..f39406e 100644 --- a/tests/toDataParser/dataParserTransformer/object.test.ts +++ b/tests/toDataParser/dataParserTransformer/object.test.ts @@ -2,11 +2,6 @@ import { DP, DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "ObjectParser", - transformers: tsDefaultTransformers, -}; - describe("object", () => { it("renders object parser", () => { expect( @@ -16,10 +11,10 @@ describe("object", () => { bar: DPE.number(), }), { - constName: "objectParser", + identifier: "objectParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -33,7 +28,7 @@ describe("object", () => { bar: DPE.number(), }), { - constName: "objectParserError", + identifier: "objectParserError", dataParserTransformers: [ ((dataParser, { buildError }) => DP.stringKind.has(dataParser) ? buildError() @@ -41,7 +36,7 @@ describe("object", () => { ...defaultTransformers, ], checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -59,14 +54,14 @@ describe("object", () => { () => render( schema, { - constName: "objectParserCheckerError", + identifier: "objectParserCheckerError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/optional.test.ts b/tests/toDataParser/dataParserTransformer/optional.test.ts index 169eb55..d37b2a1 100644 --- a/tests/toDataParser/dataParserTransformer/optional.test.ts +++ b/tests/toDataParser/dataParserTransformer/optional.test.ts @@ -2,21 +2,16 @@ import { DP, DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "OptionalParser", - transformers: tsDefaultTransformers, -}; - describe("optional", () => { it("renders optional parser", () => { expect( render( DPE.optional(DPE.string()), { - constName: "optionalParser", + identifier: "optionalParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -27,7 +22,7 @@ describe("optional", () => { () => render( DPE.optional(DPE.string()), { - constName: "optionalParserError", + identifier: "optionalParserError", dataParserTransformers: [ ((dataParser, { buildError }) => DP.stringKind.has(dataParser) ? buildError() @@ -35,7 +30,7 @@ describe("optional", () => { ...defaultTransformers, ], checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -50,14 +45,14 @@ describe("optional", () => { () => render( schema, { - constName: "optionalParserCheckerError", + identifier: "optionalParserCheckerError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/pipe.test.ts b/tests/toDataParser/dataParserTransformer/pipe.test.ts index 0247350..126e885 100644 --- a/tests/toDataParser/dataParserTransformer/pipe.test.ts +++ b/tests/toDataParser/dataParserTransformer/pipe.test.ts @@ -2,21 +2,16 @@ import { DP, DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "PipeParser", - transformers: tsDefaultTransformers, -}; - describe("pipe", () => { it("renders pipe parser", () => { expect( render( DPE.pipe(DPE.string(), DPE.number()), { - constName: "pipeParser", + identifier: "pipeParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -27,7 +22,7 @@ describe("pipe", () => { () => render( DPE.pipe(DPE.string(), DPE.number()), { - constName: "pipeParserInputError", + identifier: "pipeParserInputError", dataParserTransformers: [ ((dataParser, { buildError }) => DP.stringKind.has(dataParser) ? buildError() @@ -35,7 +30,7 @@ describe("pipe", () => { ...defaultTransformers, ], checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -46,7 +41,7 @@ describe("pipe", () => { () => render( DPE.pipe(DPE.string(), DPE.number()), { - constName: "pipeParserOutputError", + identifier: "pipeParserOutputError", dataParserTransformers: [ ((dataParser, { buildError }) => DP.numberKind.has(dataParser) ? buildError() @@ -54,7 +49,7 @@ describe("pipe", () => { ...defaultTransformers, ], checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -69,14 +64,14 @@ describe("pipe", () => { () => render( schema, { - constName: "pipeParserCheckerError", + identifier: "pipeParserCheckerError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/record.test.ts b/tests/toDataParser/dataParserTransformer/record.test.ts index af10a40..2017f01 100644 --- a/tests/toDataParser/dataParserTransformer/record.test.ts +++ b/tests/toDataParser/dataParserTransformer/record.test.ts @@ -2,21 +2,16 @@ import { DP, DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "RecordParser", - transformers: tsDefaultTransformers, -}; - describe("record", () => { it("renders record parser", () => { expect( render( DPE.record(DPE.string(), DPE.number()), { - constName: "recordParser", + identifier: "recordParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -27,7 +22,7 @@ describe("record", () => { () => render( DPE.record(DPE.string(), DPE.number()), { - constName: "recordParserKeyError", + identifier: "recordParserKeyError", dataParserTransformers: [ ((dataParser, { buildError }) => DP.stringKind.has(dataParser) ? buildError() @@ -35,7 +30,7 @@ describe("record", () => { ...defaultTransformers, ], checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -46,7 +41,7 @@ describe("record", () => { () => render( DPE.record(DPE.string(), DPE.number()), { - constName: "recordParserValueError", + identifier: "recordParserValueError", dataParserTransformers: [ ((dataParser, { buildError }) => DP.numberKind.has(dataParser) ? buildError() @@ -54,7 +49,7 @@ describe("record", () => { ...defaultTransformers, ], checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -73,14 +68,14 @@ describe("record", () => { () => render( schema, { - constName: "recordParserCheckerError", + identifier: "recordParserCheckerError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/recover.test.ts b/tests/toDataParser/dataParserTransformer/recover.test.ts index ee32210..5b613f8 100644 --- a/tests/toDataParser/dataParserTransformer/recover.test.ts +++ b/tests/toDataParser/dataParserTransformer/recover.test.ts @@ -8,13 +8,10 @@ describe("recover", () => { render( DPE.recover(DPE.string(), "fallback"), { - constName: "recoverParser", + identifier: "recoverParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript: { - identifier: "RecoverParser", - transformers: tsDefaultTransformers, - }, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); diff --git a/tests/toDataParser/dataParserTransformer/string.test.ts b/tests/toDataParser/dataParserTransformer/string.test.ts index 34e8340..1a608e4 100644 --- a/tests/toDataParser/dataParserTransformer/string.test.ts +++ b/tests/toDataParser/dataParserTransformer/string.test.ts @@ -2,21 +2,16 @@ import { DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "StringParser", - transformers: tsDefaultTransformers, -}; - describe("string", () => { it("renders string parser", () => { expect( render( DPE.string(), { - constName: "stringParser", + identifier: "stringParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -31,14 +26,14 @@ describe("string", () => { () => render( schema, { - constName: "stringParserError", + identifier: "stringParserError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/templateLiteral.test.ts b/tests/toDataParser/dataParserTransformer/templateLiteral.test.ts index b09df1b..f020201 100644 --- a/tests/toDataParser/dataParserTransformer/templateLiteral.test.ts +++ b/tests/toDataParser/dataParserTransformer/templateLiteral.test.ts @@ -2,11 +2,6 @@ import { DP, DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "TemplateLiteralParser", - transformers: tsDefaultTransformers, -}; - describe("templateLiteral", () => { it("renders template literal parser", () => { expect( @@ -30,10 +25,10 @@ describe("templateLiteral", () => { DPE.string(), ]), { - constName: "templateLiteralParser", + identifier: "templateLiteralParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -44,7 +39,7 @@ describe("templateLiteral", () => { () => render( DPE.templateLiteral(["user-", DPE.number(), "-id"]), { - constName: "templateLiteralParserError", + identifier: "templateLiteralParserError", dataParserTransformers: [ ((dataParser, { buildError }) => DP.numberKind.has(dataParser) ? buildError() @@ -52,7 +47,7 @@ describe("templateLiteral", () => { ...defaultTransformers, ], checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -67,14 +62,14 @@ describe("templateLiteral", () => { () => render( schema, { - constName: "templateLiteralParserCheckerError", + identifier: "templateLiteralParserCheckerError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/time.test.ts b/tests/toDataParser/dataParserTransformer/time.test.ts index 854ddf9..58223d8 100644 --- a/tests/toDataParser/dataParserTransformer/time.test.ts +++ b/tests/toDataParser/dataParserTransformer/time.test.ts @@ -2,11 +2,6 @@ import { DDate, DP, DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "TimeParser", - transformers: tsDefaultTransformers, -}; - describe("time", () => { it("renders time parser with checker imports", () => { expect( @@ -15,10 +10,10 @@ describe("time", () => { DP.checkerTimeMin(DDate.createTime(1, "millisecond")), ), { - constName: "timeParser", + identifier: "timeParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -29,10 +24,10 @@ describe("time", () => { render( DPE.time(), { - constName: "timeParserNoCoerce", + identifier: "timeParserNoCoerce", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -47,14 +42,14 @@ describe("time", () => { () => render( schema, { - constName: "timeParserError", + identifier: "timeParserError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/transform.test.ts b/tests/toDataParser/dataParserTransformer/transform.test.ts index 3edce87..71b72f7 100644 --- a/tests/toDataParser/dataParserTransformer/transform.test.ts +++ b/tests/toDataParser/dataParserTransformer/transform.test.ts @@ -16,11 +16,6 @@ vi.mock("typescript", async() => { }; }); -const toTypescript = { - identifier: "TransformParser", - transformers: tsDefaultTransformers, -}; - afterEach(() => { vi.restoreAllMocks(); }); @@ -31,10 +26,10 @@ describe("transform", () => { render( DPE.transform(DPE.string(), (value) => value.trim()), { - constName: "transformParser", + identifier: "transformParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -45,7 +40,7 @@ describe("transform", () => { () => render( DPE.transform(DPE.string(), (value) => value.trim()), { - constName: "transformParserInnerError", + identifier: "transformParserInnerError", dataParserTransformers: [ ((dataParser, { buildError }) => DP.stringKind.has(dataParser) ? buildError() @@ -53,7 +48,7 @@ describe("transform", () => { ...defaultTransformers, ], checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -64,10 +59,10 @@ describe("transform", () => { () => render( DPE.transform(DPE.string(), Math.max as any), { - constName: "transformParserNativeError", + identifier: "transformParserNativeError", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -79,10 +74,10 @@ describe("transform", () => { () => render( schema, { - constName: "transformParserMalformedError", + identifier: "transformParserMalformedError", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -95,10 +90,10 @@ describe("transform", () => { () => render( schema, { - constName: "transformParserEmptySourceError", + identifier: "transformParserEmptySourceError", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -114,10 +109,10 @@ describe("transform", () => { () => render( DPE.transform(DPE.string(), (value) => value.trim()), { - constName: "transformParserStatementError", + identifier: "transformParserStatementError", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -138,10 +133,10 @@ describe("transform", () => { () => render( DPE.transform(DPE.string(), (value) => value.trim()), { - constName: "transformParserParenthesizedError", + identifier: "transformParserParenthesizedError", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -156,14 +151,14 @@ describe("transform", () => { () => render( schema, { - constName: "transformParserCheckerError", + identifier: "transformParserCheckerError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/tuple.test.ts b/tests/toDataParser/dataParserTransformer/tuple.test.ts index 600fbfe..55795ed 100644 --- a/tests/toDataParser/dataParserTransformer/tuple.test.ts +++ b/tests/toDataParser/dataParserTransformer/tuple.test.ts @@ -2,21 +2,16 @@ import { DP, DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "TupleParser", - transformers: tsDefaultTransformers, -}; - describe("tuple", () => { it("renders tuple parser with rest", () => { expect( render( DPE.tuple([DPE.string()], { rest: DPE.number() }), { - constName: "tupleParser", + identifier: "tupleParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -27,10 +22,10 @@ describe("tuple", () => { render( DPE.tuple([DPE.string()]), { - constName: "tupleParserNoRest", + identifier: "tupleParserNoRest", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -41,7 +36,7 @@ describe("tuple", () => { () => render( DPE.tuple([DPE.string()], { rest: DPE.number() }), { - constName: "tupleParserShapeError", + identifier: "tupleParserShapeError", dataParserTransformers: [ ((dataParser, { buildError }) => DP.stringKind.has(dataParser) ? buildError() @@ -49,7 +44,7 @@ describe("tuple", () => { ...defaultTransformers, ], checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -60,7 +55,7 @@ describe("tuple", () => { () => render( DPE.tuple([DPE.string()], { rest: DPE.number() }), { - constName: "tupleParserRestError", + identifier: "tupleParserRestError", dataParserTransformers: [ ((dataParser, { buildError }) => DP.numberKind.has(dataParser) ? buildError() @@ -68,7 +63,7 @@ describe("tuple", () => { ...defaultTransformers, ], checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -84,14 +79,14 @@ describe("tuple", () => { () => render( schema, { - constName: "tupleParserCheckerError", + identifier: "tupleParserCheckerError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/union.test.ts b/tests/toDataParser/dataParserTransformer/union.test.ts index d5e4fbb..b24f08b 100644 --- a/tests/toDataParser/dataParserTransformer/union.test.ts +++ b/tests/toDataParser/dataParserTransformer/union.test.ts @@ -2,21 +2,16 @@ import { DP, DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "UnionParser", - transformers: tsDefaultTransformers, -}; - describe("union", () => { it("renders union parser", () => { expect( render( DPE.union([DPE.string(), DPE.number()]), { - constName: "unionParser", + identifier: "unionParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -27,7 +22,7 @@ describe("union", () => { () => render( DPE.union([DPE.string(), DPE.number()]), { - constName: "unionParserOptionError", + identifier: "unionParserOptionError", dataParserTransformers: [ ((dataParser, { buildError }) => DP.stringKind.has(dataParser) ? buildError() @@ -35,7 +30,7 @@ describe("union", () => { ...defaultTransformers, ], checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); @@ -50,14 +45,14 @@ describe("union", () => { () => render( schema, { - constName: "unionParserCheckerError", + identifier: "unionParserCheckerError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/dataParserTransformer/unknown.test.ts b/tests/toDataParser/dataParserTransformer/unknown.test.ts index 9b56b3a..61ff098 100644 --- a/tests/toDataParser/dataParserTransformer/unknown.test.ts +++ b/tests/toDataParser/dataParserTransformer/unknown.test.ts @@ -2,21 +2,16 @@ import { DPE, E } from "@duplojs/utils"; import { defaultTransformers, defaultCheckerTransformers, render } from "@scripts/toDataParser"; import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; -const toTypescript = { - identifier: "UnknownParser", - transformers: tsDefaultTransformers, -}; - describe("unknown", () => { it("renders unknown parser", () => { expect( render( DPE.unknown(), { - constName: "unknownParser", + identifier: "unknownParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -31,14 +26,14 @@ describe("unknown", () => { () => render( schema, { - constName: "unknownParserError", + identifier: "unknownParserError", dataParserTransformers: defaultTransformers, checkerTransformers: [ ((checker, { buildError }) => (checker as any).kind === "forced-error" ? buildError() : E.left("checkerNotSupport", checker)), ], - toTypescript, + typescriptTransformers: tsDefaultTransformers, }, ), ).toThrow(); diff --git a/tests/toDataParser/override.test.ts b/tests/toDataParser/override.test.ts index 8a81b2c..4300752 100644 --- a/tests/toDataParser/override.test.ts +++ b/tests/toDataParser/override.test.ts @@ -6,31 +6,31 @@ import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescr import { type TransformerBuildFunction } from "@scripts/toDataParser/dataParserTransformer"; describe("override", () => { - it("setConstName", () => { + it("setIdentifier", () => { const schema = DP.string(); - expect(schema.definition.constName).toBe(undefined); + expect(schema.definition.identifier).toBe(undefined); - schema.setConstName("test"); + schema.setIdentifier("test"); - expect(schema.definition.constName).toBe("test"); + expect(schema.definition.identifier).toBe("test"); }); - it("addConstName", () => { + it("addIdentifier", () => { const schema = DP.string(); - expect(schema.definition.constName).toBe(undefined); + expect(schema.definition.identifier).toBe(undefined); - const newSchema = schema.addConstName("test"); + const newSchema = schema.addIdentifier("test"); - expect(schema.definition.constName).toBe(undefined); - expect(newSchema.definition.constName).toBe("test"); + expect(schema.definition.identifier).toBe(undefined); + expect(newSchema.definition.identifier).toBe("test"); const newSchemaWithChecker = newSchema.addChecker(DP.checkerRefine(justReturn(true))); - schema.setConstName("test1"); + schema.setIdentifier("test1"); - expect(newSchemaWithChecker.definition.constName).toBe("test"); + expect(newSchemaWithChecker.definition.identifier).toBe("test"); }); it("setOverrideDataParserTransformer", () => { @@ -96,13 +96,10 @@ describe("override", () => { const result = render( schema, { - constName: "overrideParser", + identifier: "overrideParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript: { - identifier: "OverrideParser", - transformers: tsDefaultTransformers, - }, + typescriptTransformers: tsDefaultTransformers, }, ); diff --git a/tests/toDataParser/render.test.ts b/tests/toDataParser/render.test.ts index 225b270..3efed0d 100644 --- a/tests/toDataParser/render.test.ts +++ b/tests/toDataParser/render.test.ts @@ -16,33 +16,27 @@ describe("render", () => { render( schema, { - constName: "recursiveNodeParser", + identifier: "recursiveNodeParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript: { - identifier: "RecursiveNode", - transformers: tsDefaultTransformers, - }, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); }); it("renders named dependencies before their consumers", () => { - const child = DPE.string().addConstName("childParser"); - const schema = DPE.object({ child }).addConstName("parentParser"); + const child = DPE.string().addIdentifier("childParser"); + const schema = DPE.object({ child }); expect( render( schema, { - constName: "parentParser", + identifier: "parentParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript: { - identifier: "Parent", - transformers: tsDefaultTransformers, - }, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -118,13 +112,10 @@ describe("render", () => { render( schema, { - constName: "complexRecursiveParser", + identifier: "complexRecursiveParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript: { - identifier: "ComplexRecursive", - transformers: tsDefaultTransformers, - }, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -157,13 +148,10 @@ describe("render", () => { render( checkedSchema, { - constName: "checkedParser", + identifier: "checkedParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript: { - identifier: "Checked", - transformers: tsDefaultTransformers, - }, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); @@ -172,20 +160,17 @@ describe("render", () => { render( checkedExtendedSchema, { - constName: "checkedExtendedParser", + identifier: "checkedExtendedParser", importMode: "extended", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript: { - identifier: "CheckedExtended", - transformers: tsDefaultTransformers, - }, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); }); - it("renders dataParser in compact mode when indent is false", () => { + it("renders dataParser with nested checkers", () => { const compactSchema = DPE.object({ name: DPE.string().min(2), roles: DPE.literal(["admin", "editor"]).array().min(1), @@ -203,14 +188,10 @@ describe("render", () => { render( compactSchema, { - constName: "compactParser", - indent: false, + identifier: "compactParser", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, - toTypescript: { - identifier: "CompactSchema", - transformers: tsDefaultTransformers, - }, + typescriptTransformers: tsDefaultTransformers, }, ), ).toMatchSnapshot(); diff --git a/tests/toTypescript/transfomers/__snapshots__/date.test.ts.snap b/tests/toTypescript/transfomers/__snapshots__/date.test.ts.snap index fbdb74f..ea8f90f 100644 --- a/tests/toTypescript/transfomers/__snapshots__/date.test.ts.snap +++ b/tests/toTypescript/transfomers/__snapshots__/date.test.ts.snap @@ -1,31 +1,31 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`date > mode in 1`] = ` -"import type { TheDate, SerializedTheDate } from "@duplojs/utils/date"; +"import { TheDate, SerializedTheDate } from "@duplojs/utils/date"; export type Date = TheDate | Date | SerializedTheDate;" `; exports[`date > mode in 2`] = ` -"import type { TheDate, SerializedTheDate } from "@duplojs/utils/date"; +"import { TheDate, SerializedTheDate } from "@duplojs/utils/date"; export type DateIdentifier = TheDate | Date | SerializedTheDate;" `; exports[`date > mode out 1`] = ` -"import type { TheDate } from "@duplojs/utils/date"; +"import { TheDate } from "@duplojs/utils/date"; export type Date = TheDate;" `; exports[`date > mode out 2`] = ` -"import type { TheDate } from "@duplojs/utils/date"; +"import { TheDate } from "@duplojs/utils/date"; export type DateIdentifier = TheDate;" `; exports[`date > with preset importType 1`] = ` -"import type { TheDate, SerializedTheDate } from "@duplojs/utils/date"; +"import { 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 index 0e0facf..71987ca 100644 --- a/tests/toTypescript/transfomers/__snapshots__/file.test.ts.snap +++ b/tests/toTypescript/transfomers/__snapshots__/file.test.ts.snap @@ -1,19 +1,19 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`file > basic 1`] = ` -"import type { FileInterface } from "@duplojs/server-utils/file"; +"import { FileInterface } from "@duplojs/server-utils/file"; export type File = FileInterface;" `; exports[`file > basic 2`] = ` -"import type { FileInterface } from "@duplojs/server-utils/file"; +"import { FileInterface } from "@duplojs/server-utils/file"; export type FileIdentifier = FileInterface;" `; exports[`file > with preset importType 1`] = ` -"import type { FileInterface } from "@duplojs/server-utils/file"; +"import { 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 316a410..1c823f7 100644 --- a/tests/toTypescript/transfomers/__snapshots__/time.test.ts.snap +++ b/tests/toTypescript/transfomers/__snapshots__/time.test.ts.snap @@ -1,31 +1,31 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`time > mode in 1`] = ` -"import type { TheTime, SerializedTheTime } from "@duplojs/utils/date"; +"import { TheTime, SerializedTheTime } from "@duplojs/utils/date"; export type Time = SerializedTheTime | number | TheTime;" `; exports[`time > mode in 2`] = ` -"import type { TheTime, SerializedTheTime } from "@duplojs/utils/date"; +"import { TheTime, SerializedTheTime } from "@duplojs/utils/date"; export type TimeIdentifier = SerializedTheTime | number | TheTime;" `; exports[`time > mode out 1`] = ` -"import type { TheTime } from "@duplojs/utils/date"; +"import { TheTime } from "@duplojs/utils/date"; export type Time = TheTime;" `; exports[`time > mode out 2`] = ` -"import type { TheTime } from "@duplojs/utils/date"; +"import { TheTime } from "@duplojs/utils/date"; export type TimeIdentifier = TheTime;" `; exports[`time > with preset importType 1`] = ` -"import type { TheTime, SerializedTheTime } from "@duplojs/utils/date"; +"import { TheTime, SerializedTheTime } from "@duplojs/utils/date"; export type Time = SerializedTheTime | number | TheTime;" `; From d692a7b56535b35fb09845eda8b3e046557289c5 Mon Sep 17 00:00:00 2001 From: ZeRiix Date: Sat, 23 May 2026 19:11:26 +0200 Subject: [PATCH 12/16] fix(06): normalize data parser identifiers --- .../toDataParser/__snapshots__/basic.gen.ts | 4 ++-- .../__snapshots__/recursive.gen.ts | 2 +- .../__snapshots__/withIdentifier.gen.ts | 4 ++-- scripts/toDataParser/buildContext.ts | 8 ++++---- .../dataParserTransformer/createIdentifier.ts | 5 +++++ .../dataParserTransformer/index.ts | 1 + .../dataParserTransformer/transformer.ts | 5 +++-- scripts/toTypescript/buildContext.ts | 8 ++++---- .../transformer/createIdentifier.ts | 5 +++++ scripts/toTypescript/transformer/index.ts | 1 + .../toTypescript/transformer/transformer.ts | 5 ++++- .../__snapshots__/render.test.ts.snap | 12 +++++------ .../__snapshots__/array.test.ts.snap | 2 +- .../__snapshots__/bigint.test.ts.snap | 4 ++-- .../__snapshots__/boolean.test.ts.snap | 4 ++-- .../__snapshots__/date.test.ts.snap | 4 ++-- .../__snapshots__/empty.test.ts.snap | 4 ++-- .../__snapshots__/file.test.ts.snap | 6 +++--- .../__snapshots__/lazy.test.ts.snap | 2 +- .../__snapshots__/literal.test.ts.snap | 2 +- .../__snapshots__/nil.test.ts.snap | 4 ++-- .../__snapshots__/nullable.test.ts.snap | 2 +- .../__snapshots__/number.test.ts.snap | 4 ++-- .../__snapshots__/object.test.ts.snap | 2 +- .../__snapshots__/optional.test.ts.snap | 2 +- .../__snapshots__/pipe.test.ts.snap | 2 +- .../__snapshots__/record.test.ts.snap | 2 +- .../__snapshots__/recover.test.ts.snap | 2 +- .../__snapshots__/string.test.ts.snap | 2 +- .../templateLiteral.test.ts.snap | 2 +- .../__snapshots__/time.test.ts.snap | 4 ++-- .../__snapshots__/transform.test.ts.snap | 2 +- .../__snapshots__/tuple.test.ts.snap | 4 ++-- .../__snapshots__/union.test.ts.snap | 2 +- .../__snapshots__/unknown.test.ts.snap | 2 +- tests/toDataParser/override.test.ts | 4 ++-- tests/toDataParser/render.test.ts | 17 ++++++++++++++++ .../__snapshots__/recursive.test.ts.snap | 2 +- tests/toTypescript/render.test.ts | 20 +++++++++++++++++++ 39 files changed, 111 insertions(+), 58 deletions(-) create mode 100644 scripts/toDataParser/dataParserTransformer/createIdentifier.ts create mode 100644 scripts/toTypescript/transformer/createIdentifier.ts create mode 100644 tests/toTypescript/render.test.ts diff --git a/integration/toDataParser/__snapshots__/basic.gen.ts b/integration/toDataParser/__snapshots__/basic.gen.ts index cbbc136..f243c17 100644 --- a/integration/toDataParser/__snapshots__/basic.gen.ts +++ b/integration/toDataParser/__snapshots__/basic.gen.ts @@ -1,6 +1,6 @@ import * as DP from "@duplojs/utils/dataParser"; -export const user = DP.object({ +export const userDataParser = DP.object({ id: DP.templateLiteral(["user-", DP.number(), "-db1"]), name: DP.string({ checkers: [DP.checkerStringMin(2)] }), email: DP.string({ checkers: [DP.checkerEmail()] }), @@ -35,4 +35,4 @@ export const user = DP.object({ location: DP.tuple([DP.number(), DP.number()], { rest: DP.number() }), createdAt: DP.date({ coerce: true }), startAt: DP.time() -}); \ No newline at end of file +}); diff --git a/integration/toDataParser/__snapshots__/recursive.gen.ts b/integration/toDataParser/__snapshots__/recursive.gen.ts index 00ca13d..85e5f88 100644 --- a/integration/toDataParser/__snapshots__/recursive.gen.ts +++ b/integration/toDataParser/__snapshots__/recursive.gen.ts @@ -37,4 +37,4 @@ export const recursiveDataParser2: DP.DataParser<$recursiveDataParser2> = DP.obj export const recursiveDataParser4: DP.DataParser<$recursiveDataParser4> = DP.tuple([DP.string(), DP.array(DP.lazy(() => recursiveDataParser4))]); -export const recursiveNode = recursiveDataParser0; \ No newline at end of file +export const recursiveNodeDataParser = recursiveDataParser0; diff --git a/integration/toDataParser/__snapshots__/withIdentifier.gen.ts b/integration/toDataParser/__snapshots__/withIdentifier.gen.ts index 2b43845..96ae7f1 100644 --- a/integration/toDataParser/__snapshots__/withIdentifier.gen.ts +++ b/integration/toDataParser/__snapshots__/withIdentifier.gen.ts @@ -2,9 +2,9 @@ import * as DP from "@duplojs/utils/dataParser"; export const userRoleDataParser = DP.literal(["admin", "editor", "viewer"]); -export const user = DP.object({ +export const userDataParser = DP.object({ id: DP.templateLiteral(["user-", DP.number(), "-db1"]), name: DP.string({ checkers: [DP.checkerStringMin(2)] }), email: DP.string({ checkers: [DP.checkerEmail()] }), role: userRoleDataParser -}); \ No newline at end of file +}); diff --git a/scripts/toDataParser/buildContext.ts b/scripts/toDataParser/buildContext.ts index a95cb2b..19e1687 100644 --- a/scripts/toDataParser/buildContext.ts +++ b/scripts/toDataParser/buildContext.ts @@ -1,5 +1,5 @@ import { DP, E, unwrap } from "@duplojs/utils"; -import { type createTransformer, transformer, type MapContext, type TransformerHook, type DataParserErrorEither, type DataParserNotSupportedEither, type DataParserGetDefinitionErrorEither, type ToTypescriptDataParserErrorEither, type ToTypescriptDataParserNotSupportedEither } from "./dataParserTransformer"; +import { createIdentifier, type createTransformer, transformer, type MapContext, type TransformerHook, type DataParserErrorEither, type DataParserNotSupportedEither, type DataParserGetDefinitionErrorEither, type ToTypescriptDataParserErrorEither, type ToTypescriptDataParserNotSupportedEither } from "./dataParserTransformer"; import * as TST from "@scripts/toTypescript"; import { getRecursiveDataParser } from "@scripts/utils"; import { factory } from "typescript"; @@ -86,7 +86,7 @@ export function buildContext( context.set( DP.empty(), { - identifier: factory.createIdentifier(params.identifier), + identifier: factory.createIdentifier(createIdentifier(params.identifier)), expression: unwrap(result), typeIdentifier: null, }, @@ -95,8 +95,8 @@ export function buildContext( context.set( DP.empty(), { - identifier: factory.createIdentifier(params.identifier), - expression: factory.createIdentifier(schema.definition.identifier), + identifier: factory.createIdentifier(createIdentifier(params.identifier)), + expression: factory.createIdentifier(createIdentifier(schema.definition.identifier)), typeIdentifier: null, }, ); diff --git a/scripts/toDataParser/dataParserTransformer/createIdentifier.ts b/scripts/toDataParser/dataParserTransformer/createIdentifier.ts new file mode 100644 index 0000000..33a596f --- /dev/null +++ b/scripts/toDataParser/dataParserTransformer/createIdentifier.ts @@ -0,0 +1,5 @@ +import { S } from "@duplojs/utils"; + +export function createIdentifier(identifier: string) { + return `${S.uncapitalize(identifier)}DataParser`; +} diff --git a/scripts/toDataParser/dataParserTransformer/index.ts b/scripts/toDataParser/dataParserTransformer/index.ts index 07a0b4c..92cd93d 100644 --- a/scripts/toDataParser/dataParserTransformer/index.ts +++ b/scripts/toDataParser/dataParserTransformer/index.ts @@ -3,3 +3,4 @@ export * from "./transformer"; export * from "./hook"; export * from "./defaults"; export * from "./getDefinitionDataParser"; +export * from "./createIdentifier"; diff --git a/scripts/toDataParser/dataParserTransformer/transformer.ts b/scripts/toDataParser/dataParserTransformer/transformer.ts index f3e60e1..0c57694 100644 --- a/scripts/toDataParser/dataParserTransformer/transformer.ts +++ b/scripts/toDataParser/dataParserTransformer/transformer.ts @@ -1,10 +1,11 @@ -import { A, E, type DP, unwrap, S, justExec } from "@duplojs/utils"; +import { A, E, type DP, unwrap, justExec } from "@duplojs/utils"; import * as TST from "@scripts/toTypescript"; import type { MapContext, TransformerParams, createTransformer, MaybeTransformerEither } from "./create"; import { factory, type Identifier } from "typescript"; import type { TransformerHook } from "./hook"; import type { createCheckerTransformer } from "../checkerTransformer"; import { getDefinitionDataParser } from "./getDefinitionDataParser"; +import { createIdentifier } from "./createIdentifier"; export interface TransformerFunctionParams { readonly dataParserTransformers: readonly ReturnType[]; @@ -62,7 +63,7 @@ export function transformer( const currentIdentifier = shouldCreateConstDeclaration ? factory.createIdentifier( currentDataParser.definition.identifier !== undefined - ? `${S.uncapitalize(currentDataParser.definition.identifier)}DataParser` + ? createIdentifier(currentDataParser.definition.identifier) : `recursiveDataParser${params.context.size + params.context.size}`, ) : undefined; diff --git a/scripts/toTypescript/buildContext.ts b/scripts/toTypescript/buildContext.ts index bf0ddea..fcb671a 100644 --- a/scripts/toTypescript/buildContext.ts +++ b/scripts/toTypescript/buildContext.ts @@ -1,5 +1,5 @@ import { DP, E, unwrap } from "@duplojs/utils"; -import { type createTransformer, transformer, type MapContext, type MapImportContext, type MapImportType, type TransformerHook, type TransformerMode, type DataParserErrorEither, type DataParserNotSupportedEither, createImportContext } from "./transformer"; +import { createIdentifier, type createTransformer, transformer, type MapContext, type MapImportContext, type MapImportType, type TransformerHook, type TransformerMode, type DataParserErrorEither, type DataParserNotSupportedEither, createImportContext } from "./transformer"; import { getRecursiveDataParser } from "@scripts/utils"; import { factory, SyntaxKind } from "typescript"; @@ -58,7 +58,7 @@ export function buildContext( DP.empty(), factory.createTypeAliasDeclaration( [factory.createToken(SyntaxKind.ExportKeyword)], - factory.createIdentifier(params.identifier), + factory.createIdentifier(createIdentifier(params.identifier)), undefined, unwrap(result), ), @@ -68,10 +68,10 @@ export function buildContext( DP.empty(), factory.createTypeAliasDeclaration( [factory.createToken(SyntaxKind.ExportKeyword)], - factory.createIdentifier(params.identifier), + factory.createIdentifier(createIdentifier(params.identifier)), undefined, factory.createTypeReferenceNode( - schema.definition.identifier, + createIdentifier(schema.definition.identifier), ), ), ); diff --git a/scripts/toTypescript/transformer/createIdentifier.ts b/scripts/toTypescript/transformer/createIdentifier.ts new file mode 100644 index 0000000..15fc8d0 --- /dev/null +++ b/scripts/toTypescript/transformer/createIdentifier.ts @@ -0,0 +1,5 @@ +import { S } from "@duplojs/utils"; + +export function createIdentifier(identifier: string) { + return S.capitalize(identifier); +} diff --git a/scripts/toTypescript/transformer/index.ts b/scripts/toTypescript/transformer/index.ts index b497b52..bd4ab20 100644 --- a/scripts/toTypescript/transformer/index.ts +++ b/scripts/toTypescript/transformer/index.ts @@ -5,4 +5,5 @@ export * from "./defaults"; export * from "./includesUndefinedTypeNode"; export * from "./createImportDeclaration"; export * from "./addImport"; +export * from "./createIdentifier"; export { defaultTransformers } from "./defaults"; diff --git a/scripts/toTypescript/transformer/transformer.ts b/scripts/toTypescript/transformer/transformer.ts index f8401af..6199d0c 100644 --- a/scripts/toTypescript/transformer/transformer.ts +++ b/scripts/toTypescript/transformer/transformer.ts @@ -3,6 +3,7 @@ import type { MapContext, DataParserNotSupportedEither, TransformerParams, creat import { factory, SyntaxKind } from "typescript"; import type { TransformerHook } from "./hook"; import { createAddImport } from "./addImport"; +import { createIdentifier } from "./createIdentifier"; export interface TransformerFunctionParams { readonly transformers: readonly ReturnType[]; @@ -62,7 +63,9 @@ export function transformer( return undefined; } - const identifier = currentSchema.definition.identifier ?? `RecursiveType${params.context.size}`; + const identifier = currentSchema.definition.identifier !== undefined + ? createIdentifier(currentSchema.definition.identifier) + : `RecursiveType${params.context.size}`; params.context.set( currentSchema, diff --git a/tests/toDataParser/__snapshots__/render.test.ts.snap b/tests/toDataParser/__snapshots__/render.test.ts.snap index 61729a8..b081406 100644 --- a/tests/toDataParser/__snapshots__/render.test.ts.snap +++ b/tests/toDataParser/__snapshots__/render.test.ts.snap @@ -13,7 +13,7 @@ export const recursiveDataParser0: DP.DataParser<$recursiveDataParser0> = DP.obj next: DP.lazy(() => recursiveDataParser0) }); -export const recursiveNodeParser = recursiveDataParser0;" +export const recursiveNodeParserDataParser = recursiveDataParser0;" `; exports[`render > renders checked dataParsers in normal and extended modes 1`] = ` @@ -21,7 +21,7 @@ exports[`render > renders checked dataParsers in normal and extended modes 1`] = import * as D from "@duplojs/utils/date"; -export const checkedParser = DP.object({ +export const checkedParserDataParser = DP.object({ startAt: DP.time({ checkers: [ DP.checkerTimeMin(D.createTime(1000, "millisecond")), DP.checkerTimeMax(D.createTime(5000, "millisecond")) @@ -41,7 +41,7 @@ import * as DPE from "@duplojs/utils/dataParserExtended"; import * as D from "@duplojs/utils/date"; -export const checkedExtendedParser = DPE.object({ +export const checkedExtendedParserDataParser = DPE.object({ startAt: DPE.time({ checkers: [DP.checkerTimeMin(D.createTime(250, "millisecond"))] }), tags: DPE.array(DPE.string({ checkers: [DP.checkerStringMin(1)] }), { checkers: [DP.checkerArrayMin(1)] }) });" @@ -117,13 +117,13 @@ export const recursiveDataParser6: DP.DataParser<$recursiveDataParser6> = DP.uni DP.array(DP.lazy(() => recursiveDataParser6)) ]); -export const complexRecursiveParser = recursiveDataParser0;" +export const complexRecursiveParserDataParser = recursiveDataParser0;" `; exports[`render > renders dataParser with nested checkers 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const compactParser = DP.object({ +export const compactParserDataParser = DP.object({ name: DP.string({ checkers: [DP.checkerStringMin(2)] }), roles: DP.array(DP.literal(["admin", "editor"]), { checkers: [DP.checkerArrayMin(1)] }), contact: DP.union([ @@ -142,7 +142,7 @@ exports[`render > renders named dependencies before their consumers 1`] = ` export const childParserDataParser = DP.string(); -export const parentParser = DP.object({ +export const parentParserDataParser = DP.object({ child: childParserDataParser });" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/array.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/array.test.ts.snap index 87a981e..f3bee21 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/array.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/array.test.ts.snap @@ -3,5 +3,5 @@ exports[`array > renders array parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const arrayParser = DP.array(DP.string());" +export const arrayParserDataParser = DP.array(DP.string());" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/bigint.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/bigint.test.ts.snap index ddf8d1e..90c65c2 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/bigint.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/bigint.test.ts.snap @@ -3,11 +3,11 @@ exports[`bigint > renders bigint parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const bigintParser = DP.bigint({ coerce: true });" +export const bigintParserDataParser = DP.bigint({ coerce: true });" `; exports[`bigint > renders bigint parser without coerce 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const bigintParserNoCoerce = DP.bigint();" +export const bigintParserNoCoerceDataParser = DP.bigint();" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/boolean.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/boolean.test.ts.snap index 3f7acdb..cd1f044 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/boolean.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/boolean.test.ts.snap @@ -3,11 +3,11 @@ exports[`boolean > renders boolean parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const booleanParser = DP.boolean({ coerce: true });" +export const booleanParserDataParser = DP.boolean({ coerce: true });" `; exports[`boolean > renders boolean parser without coerce 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const booleanParserNoCoerce = DP.boolean();" +export const booleanParserNoCoerceDataParser = DP.boolean();" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/date.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/date.test.ts.snap index 175a736..a3816c5 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/date.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/date.test.ts.snap @@ -3,11 +3,11 @@ exports[`date > renders date parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const dateParser = DP.date({ coerce: true });" +export const dateParserDataParser = DP.date({ coerce: true });" `; exports[`date > renders date parser without coerce 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const dateParserNoCoerce = DP.date();" +export const dateParserNoCoerceDataParser = DP.date();" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/empty.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/empty.test.ts.snap index 7168874..f75612f 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/empty.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/empty.test.ts.snap @@ -3,11 +3,11 @@ exports[`empty > renders empty parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const emptyParser = DP.empty({ coerce: true });" +export const emptyParserDataParser = DP.empty({ coerce: true });" `; exports[`empty > renders empty parser without coerce 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const emptyParserNoCoerce = DP.empty();" +export const emptyParserNoCoerceDataParser = DP.empty();" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/file.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/file.test.ts.snap index 30f6b58..faaa027 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/file.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/file.test.ts.snap @@ -7,7 +7,7 @@ import * as DPE from "@duplojs/utils/dataParserExtended"; import * as SDPE from "@duplojs/server-utils/dataParserExtended"; -export const fileParserExtended = SDPE.file({});" +export const fileParserExtendedDataParser = SDPE.file({});" `; exports[`file > renders file parser with async constraints 1`] = ` @@ -15,7 +15,7 @@ exports[`file > renders file parser with async constraints 1`] = ` import * as SDP from "@duplojs/server-utils/dataParser"; -export const fileParser = SDP.file({ +export const fileParserDataParser = SDP.file({ coerce: true, checkExist: true, maxSize: 10, @@ -29,5 +29,5 @@ exports[`file > renders file parser without options 1`] = ` import * as SDP from "@duplojs/server-utils/dataParser"; -export const fileParserNoOptions = SDP.file({});" +export const fileParserNoOptionsDataParser = SDP.file({});" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/lazy.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/lazy.test.ts.snap index e43e016..9dee181 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/lazy.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/lazy.test.ts.snap @@ -3,5 +3,5 @@ exports[`lazy > renders lazy parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const lazyParser = DP.lazy(() => DP.string());" +export const lazyParserDataParser = DP.lazy(() => DP.string());" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/literal.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/literal.test.ts.snap index 5fdaf13..fe1bbab 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/literal.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/literal.test.ts.snap @@ -3,7 +3,7 @@ exports[`literal > renders literal parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const literalParser = DP.literal([ +export const literalParserDataParser = DP.literal([ "foo", 1, 1n, diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/nil.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/nil.test.ts.snap index e198311..7a45b75 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/nil.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/nil.test.ts.snap @@ -3,11 +3,11 @@ exports[`nil > renders nil parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const nilParser = DP.nil({ coerce: true });" +export const nilParserDataParser = DP.nil({ coerce: true });" `; exports[`nil > renders nil parser without coerce 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const nilParserNoCoerce = DP.nil();" +export const nilParserNoCoerceDataParser = DP.nil();" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/nullable.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/nullable.test.ts.snap index 6630899..14c7c85 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/nullable.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/nullable.test.ts.snap @@ -3,5 +3,5 @@ exports[`nullable > renders nullable parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const nullableParser = DP.nullable(DP.string());" +export const nullableParserDataParser = DP.nullable(DP.string());" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/number.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/number.test.ts.snap index 180c46d..6a1ab0e 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/number.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/number.test.ts.snap @@ -3,11 +3,11 @@ exports[`number > renders number parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const numberParser = DP.number({ coerce: true });" +export const numberParserDataParser = DP.number({ coerce: true });" `; exports[`number > renders number parser without coerce 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const numberParserNoCoerce = DP.number();" +export const numberParserNoCoerceDataParser = DP.number();" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/object.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/object.test.ts.snap index 9ea60f4..4b6b2f1 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/object.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/object.test.ts.snap @@ -3,7 +3,7 @@ exports[`object > renders object parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const objectParser = DP.object({ +export const objectParserDataParser = DP.object({ foo: DP.string(), bar: DP.number() });" diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/optional.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/optional.test.ts.snap index 85323f9..5d9a245 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/optional.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/optional.test.ts.snap @@ -3,5 +3,5 @@ exports[`optional > renders optional parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const optionalParser = DP.optional(DP.string());" +export const optionalParserDataParser = DP.optional(DP.string());" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/pipe.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/pipe.test.ts.snap index 0be75c7..bdbff94 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/pipe.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/pipe.test.ts.snap @@ -3,5 +3,5 @@ exports[`pipe > renders pipe parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const pipeParser = DP.pipe(DP.string(), DP.number());" +export const pipeParserDataParser = DP.pipe(DP.string(), DP.number());" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/record.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/record.test.ts.snap index 2c478dd..14f0def 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/record.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/record.test.ts.snap @@ -3,5 +3,5 @@ exports[`record > renders record parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const recordParser = DP.record(DP.string(), DP.number());" +export const recordParserDataParser = DP.record(DP.string(), DP.number());" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/recover.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/recover.test.ts.snap index 91c49e6..b6db4cf 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/recover.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/recover.test.ts.snap @@ -3,5 +3,5 @@ exports[`recover > renders inner parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const recoverParser = DP.string();" +export const recoverParserDataParser = DP.string();" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/string.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/string.test.ts.snap index 97f8f78..e0106a5 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/string.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/string.test.ts.snap @@ -3,5 +3,5 @@ exports[`string > renders string parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const stringParser = DP.string();" +export const stringParserDataParser = DP.string();" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/templateLiteral.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/templateLiteral.test.ts.snap index ec97465..37779af 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/templateLiteral.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/templateLiteral.test.ts.snap @@ -3,7 +3,7 @@ exports[`templateLiteral > renders template literal parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const templateLiteralParser = DP.templateLiteral([ +export const templateLiteralParserDataParser = DP.templateLiteral([ "pre-", 1n, "mid-", diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/time.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/time.test.ts.snap index 1d2d762..76650b7 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/time.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/time.test.ts.snap @@ -5,7 +5,7 @@ exports[`time > renders time parser with checker imports 1`] = ` import * as D from "@duplojs/utils/date"; -export const timeParser = DP.time({ +export const timeParserDataParser = DP.time({ coerce: true, checkers: [DP.checkerTimeMin(D.createTime(1, "millisecond"))] });" @@ -14,5 +14,5 @@ export const timeParser = DP.time({ exports[`time > renders time parser without coerce and without checkers 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const timeParserNoCoerce = DP.time();" +export const timeParserNoCoerceDataParser = DP.time();" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/transform.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/transform.test.ts.snap index baecd5e..e15db97 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/transform.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/transform.test.ts.snap @@ -3,5 +3,5 @@ exports[`transform > renders transform parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const transformParser = DP.transform(DP.string(), (value) => value.trim());" +export const transformParserDataParser = DP.transform(DP.string(), (value) => value.trim());" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/tuple.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/tuple.test.ts.snap index d0bd0b0..5dbbd5f 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/tuple.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/tuple.test.ts.snap @@ -3,11 +3,11 @@ exports[`tuple > renders tuple parser with rest 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const tupleParser = DP.tuple([DP.string()], { rest: DP.number() });" +export const tupleParserDataParser = DP.tuple([DP.string()], { rest: DP.number() });" `; exports[`tuple > renders tuple parser without rest 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const tupleParserNoRest = DP.tuple([DP.string()]);" +export const tupleParserNoRestDataParser = DP.tuple([DP.string()]);" `; diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/union.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/union.test.ts.snap index 801da41..ace7d05 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/union.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/union.test.ts.snap @@ -3,7 +3,7 @@ exports[`union > renders union parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const unionParser = DP.union([ +export const unionParserDataParser = DP.union([ DP.string(), DP.number() ]);" diff --git a/tests/toDataParser/dataParserTransformer/__snapshots__/unknown.test.ts.snap b/tests/toDataParser/dataParserTransformer/__snapshots__/unknown.test.ts.snap index 871f0ee..fe8cbe6 100644 --- a/tests/toDataParser/dataParserTransformer/__snapshots__/unknown.test.ts.snap +++ b/tests/toDataParser/dataParserTransformer/__snapshots__/unknown.test.ts.snap @@ -3,5 +3,5 @@ exports[`unknown > renders unknown parser 1`] = ` "import * as DP from "@duplojs/utils/dataParser"; -export const unknownParser = DP.unknown();" +export const unknownParserDataParser = DP.unknown();" `; diff --git a/tests/toDataParser/override.test.ts b/tests/toDataParser/override.test.ts index 4300752..b61f21d 100644 --- a/tests/toDataParser/override.test.ts +++ b/tests/toDataParser/override.test.ts @@ -96,13 +96,13 @@ describe("override", () => { const result = render( schema, { - identifier: "overrideParser", + identifier: "override", dataParserTransformers: defaultTransformers, checkerTransformers: defaultCheckerTransformers, typescriptTransformers: tsDefaultTransformers, }, ); - expect(result).toContain("export const overrideParser = DP.number();"); + expect(result).toContain("export const overrideDataParser = DP.number();"); }); }); diff --git a/tests/toDataParser/render.test.ts b/tests/toDataParser/render.test.ts index 3efed0d..297cc95 100644 --- a/tests/toDataParser/render.test.ts +++ b/tests/toDataParser/render.test.ts @@ -196,4 +196,21 @@ describe("render", () => { ), ).toMatchSnapshot(); }); + + it("normalizes the render identifier into a dataParser const identifier", () => { + const identifier = "UserParser"; + const result = render( + DPE.string(), + { + identifier, + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + typescriptTransformers: tsDefaultTransformers, + }, + ); + const renderedIdentifier = result.match(/export const (?\w+)/)?.groups?.identifier; + + expect(identifier).toBe("UserParser"); + expect(renderedIdentifier).toBe("userParserDataParser"); + }); }); diff --git a/tests/toTypescript/__snapshots__/recursive.test.ts.snap b/tests/toTypescript/__snapshots__/recursive.test.ts.snap index 699f58b..5f3fde3 100644 --- a/tests/toTypescript/__snapshots__/recursive.test.ts.snap +++ b/tests/toTypescript/__snapshots__/recursive.test.ts.snap @@ -1,7 +1,7 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`recursive > when using an schema two time but non recursive 1`] = ` -"export type noneRecursive = { +"export type NoneRecursive = { one: { prop: string; }; diff --git a/tests/toTypescript/render.test.ts b/tests/toTypescript/render.test.ts new file mode 100644 index 0000000..55d3682 --- /dev/null +++ b/tests/toTypescript/render.test.ts @@ -0,0 +1,20 @@ +import { DPE } from "@duplojs/utils"; +import { defaultTransformers, render } from "@scripts/toTypescript"; + +describe("render", () => { + it("normalizes the render identifier into a type identifier", () => { + const identifier = "userType"; + const result = render( + DPE.string(), + { + identifier, + transformers: defaultTransformers, + mode: "out", + }, + ); + const renderedIdentifier = result.match(/export type (?\w+)/)?.groups?.identifier; + + expect(identifier).toBe("userType"); + expect(renderedIdentifier).toBe("UserType"); + }); +}); From 0c304d3376caee832af557899ca30db88c6362a7 Mon Sep 17 00:00:00 2001 From: mathcovax Date: Mon, 25 May 2026 09:39:34 +0000 Subject: [PATCH 13/16] fix(6): remove import type --- scripts/toDataParser/buildContext.ts | 14 ++----- scripts/toDataParser/render.ts | 13 ++----- scripts/toTypescript/buildContext.ts | 12 +----- scripts/toTypescript/render.ts | 13 ++----- scripts/toTypescript/transformer/addImport.ts | 39 +------------------ scripts/toTypescript/transformer/create.ts | 5 --- tests/toTypescript/transfomers/date.test.ts | 10 ++--- tests/toTypescript/transfomers/file.test.ts | 8 ++-- tests/toTypescript/transfomers/time.test.ts | 8 ++-- 9 files changed, 25 insertions(+), 97 deletions(-) diff --git a/scripts/toDataParser/buildContext.ts b/scripts/toDataParser/buildContext.ts index 19e1687..852cb0c 100644 --- a/scripts/toDataParser/buildContext.ts +++ b/scripts/toDataParser/buildContext.ts @@ -1,6 +1,6 @@ import { DP, E, unwrap } from "@duplojs/utils"; import { createIdentifier, type createTransformer, transformer, type MapContext, type TransformerHook, type DataParserErrorEither, type DataParserNotSupportedEither, type DataParserGetDefinitionErrorEither, type ToTypescriptDataParserErrorEither, type ToTypescriptDataParserNotSupportedEither } from "./dataParserTransformer"; -import * as TST from "@scripts/toTypescript"; +import type * as TST from "@scripts/toTypescript"; import { getRecursiveDataParser } from "@scripts/utils"; import { factory } from "typescript"; import { type createCheckerTransformer } from "./checkerTransformer"; @@ -23,11 +23,6 @@ export interface BuildContextParams { readonly typescriptContext?: TST.MapContext; readonly importContext?: TST.MapImportContext; - /** - * @deprecated use importContext - */ - readonly importType?: TST.MapImportType; - readonly importMode?: ImportMode; readonly hooks?: readonly TransformerHook[]; readonly toTypescript?: { @@ -48,11 +43,8 @@ export function buildContext( | ToTypescriptDataParserErrorEither ) { const context: MapContext = params.context ?? new Map(); - const typescriptContext = params.typescriptContext ?? new Map(); - const importContext: TST.MapImportContext = TST.createImportContext( - params.importContext, - params.importType, - ); + const typescriptContext: TST.MapContext = params.typescriptContext ?? new Map(); + const importContext: TST.MapImportContext = params.importContext ?? new Map(); const importMode = params.importMode ?? "lite"; importContext.set("@duplojs/utils/dataParser", { diff --git a/scripts/toDataParser/render.ts b/scripts/toDataParser/render.ts index afa3e10..3b01de9 100644 --- a/scripts/toDataParser/render.ts +++ b/scripts/toDataParser/render.ts @@ -1,4 +1,4 @@ -import * as TST from "@scripts/toTypescript"; +import type * as TST from "@scripts/toTypescript"; import { type DataParserNotSupportedEither, type DataParserGetDefinitionErrorEither, type DataParserErrorEither, type MapContext, type ToTypescriptDataParserErrorEither, type ToTypescriptDataParserNotSupportedEither } from "./dataParserTransformer"; import { createToDataParserKind } from "./kind"; import { buildContext, type BuildContextParams } from "./buildContext"; @@ -31,19 +31,12 @@ export class DataParserToDataParserTypeRenderError extends kindClass( export interface RenderParams extends BuildContextParams { - /** - * @deprecated use importContext - */ - readonly importType?: TST.MapImportType; } export function render(dataParser: DP.DataParser, params: RenderParams) { const context: MapContext = new Map(params.context); - const typescriptContext = new Map(params.typescriptContext); - const importContext: TST.MapImportContext = TST.createImportContext( - params.importContext, - params.importType, - ); + const typescriptContext: TST.MapContext = new Map(params.typescriptContext); + const importContext: TST.MapImportContext = new Map(params.importContext); const result = buildContext(dataParser, { ...params, diff --git a/scripts/toTypescript/buildContext.ts b/scripts/toTypescript/buildContext.ts index fcb671a..279674c 100644 --- a/scripts/toTypescript/buildContext.ts +++ b/scripts/toTypescript/buildContext.ts @@ -1,5 +1,5 @@ import { DP, E, unwrap } from "@duplojs/utils"; -import { createIdentifier, type createTransformer, transformer, type MapContext, type MapImportContext, type MapImportType, type TransformerHook, type TransformerMode, type DataParserErrorEither, type DataParserNotSupportedEither, createImportContext } from "./transformer"; +import { createIdentifier, type createTransformer, transformer, type MapContext, type MapImportContext, type TransformerHook, type TransformerMode, type DataParserErrorEither, type DataParserNotSupportedEither } from "./transformer"; import { getRecursiveDataParser } from "@scripts/utils"; import { factory, SyntaxKind } from "typescript"; @@ -15,11 +15,6 @@ export interface BuildContextParams { readonly mode?: TransformerMode; readonly hooks?: readonly TransformerHook[]; readonly importContext?: MapImportContext; - - /** - * @deprecated use importContext - */ - readonly importType?: MapImportType; } export function buildContext( @@ -31,10 +26,7 @@ export function buildContext( | DataParserErrorEither ) { const context: MapContext = params.context ?? new Map(); - const importContext: MapImportContext = createImportContext( - params.importContext, - params.importType, - ); + const importContext: MapImportContext = params.importContext ?? new Map(); const result = transformer( schema, diff --git a/scripts/toTypescript/render.ts b/scripts/toTypescript/render.ts index efb38e3..8a7ce3e 100644 --- a/scripts/toTypescript/render.ts +++ b/scripts/toTypescript/render.ts @@ -1,15 +1,11 @@ import { type DP, E, kindClass } from "@duplojs/utils"; -import { type MapContext, type MapImportContext, type MapImportType, type DataParserErrorEither, type DataParserNotSupportedEither, createImportContext } from "./transformer"; +import { type DataParserErrorEither, type DataParserNotSupportedEither } from "./transformer"; import { createToTypescriptKind } from "./kind"; import { buildContext, type BuildContextParams } from "./buildContext"; import { printer } from "./printer"; export interface RenderParams extends BuildContextParams { - /** - * @deprecated use importContext - */ - readonly importType?: MapImportType; } export class DataParserToTypescriptRenderError extends kindClass( @@ -25,11 +21,8 @@ export class DataParserToTypescriptRenderError extends kindClass( } export function render(schema: DP.DataParser, params: RenderParams) { - const context: MapContext = new Map(params.context); - const importContext: MapImportContext = createImportContext( - params.importContext, - params.importType, - ); + const context = new Map(params.context); + const importContext = new Map(params.importContext); const result = buildContext(schema, { ...params, diff --git a/scripts/toTypescript/transformer/addImport.ts b/scripts/toTypescript/transformer/addImport.ts index 3835e1b..d3434d8 100644 --- a/scripts/toTypescript/transformer/addImport.ts +++ b/scripts/toTypescript/transformer/addImport.ts @@ -1,42 +1,5 @@ import { A } from "@duplojs/utils"; -import type { MapImportContext, MapImportType } from "./create"; - -/** - * @deprecated Internal compatibility helper for legacy importType. Use MapImportContext directly. - */ -export function createImportContext( - importContext?: MapImportContext, - importType?: MapImportType, -) { - const newImportContext: MapImportContext = new Map(importContext); - - if (!importType) { - return newImportContext; - } - - for (const [path, identifiers] of importType) { - const currentImports = newImportContext.get(path) ?? {}; - const direct = A.reduce( - identifiers, - A.reduceFrom(currentImports.direct ?? []), - ({ element, lastValue, next }) => next( - A.includes(lastValue, element) - ? lastValue - : A.push(lastValue, element), - ), - ); - - newImportContext.set( - path, - { - ...currentImports, - direct, - }, - ); - } - - return newImportContext; -} +import type { MapImportContext } from "./create"; export function createAddImport(importContext: MapImportContext) { return ( diff --git a/scripts/toTypescript/transformer/create.ts b/scripts/toTypescript/transformer/create.ts index 277a179..e5beacd 100644 --- a/scripts/toTypescript/transformer/create.ts +++ b/scripts/toTypescript/transformer/create.ts @@ -21,11 +21,6 @@ export type MapImportContext = Map< } >; -/** - * @deprecated use MapImportContext - */ -export type MapImportType = Map; - export type MaybeTransformerEither = | TransformerSuccessEither | DataParserNotSupportedEither diff --git a/tests/toTypescript/transfomers/date.test.ts b/tests/toTypescript/transfomers/date.test.ts index 966b220..a2649e5 100644 --- a/tests/toTypescript/transfomers/date.test.ts +++ b/tests/toTypescript/transfomers/date.test.ts @@ -1,5 +1,5 @@ import { DPE } from "@duplojs/utils"; -import { defaultTransformers, type MapImportType, render } from "@scripts/toTypescript"; +import { defaultTransformers, type MapImportContext, render } from "@scripts/toTypescript"; describe("date", () => { it("mode out", () => { @@ -54,9 +54,9 @@ describe("date", () => { ).toMatchSnapshot(); }); - it("with preset importType", () => { - const importType: MapImportType = new Map(); - importType.set("@duplojs/utils/date", ["TheDate"]); + it("with preset importContext", () => { + const importContext: MapImportContext = new Map(); + importContext.set("@duplojs/utils/date", { direct: ["TheDate"] }); expect( render( @@ -65,7 +65,7 @@ describe("date", () => { identifier: "Date", transformers: defaultTransformers, mode: "in", - importType, + importContext, }, ), ).toMatchSnapshot(); diff --git a/tests/toTypescript/transfomers/file.test.ts b/tests/toTypescript/transfomers/file.test.ts index 8c056d7..ba72787 100644 --- a/tests/toTypescript/transfomers/file.test.ts +++ b/tests/toTypescript/transfomers/file.test.ts @@ -1,5 +1,5 @@ import { SDP } from "@duplojs/server-utils"; -import { defaultTransformers, type MapImportType, render } from "@scripts/toTypescript"; +import { defaultTransformers, type MapImportContext, render } from "@scripts/toTypescript"; describe("file", () => { it("basic", () => { @@ -29,8 +29,8 @@ describe("file", () => { }); it("with preset importType", () => { - const importType: MapImportType = new Map(); - importType.set("@duplojs/server-utils/file", ["FileInterface"]); + const importContext: MapImportContext = new Map(); + importContext.set("@duplojs/server-utils/file", { direct: ["FileInterface"] }); expect( render( @@ -39,7 +39,7 @@ describe("file", () => { identifier: "File", transformers: defaultTransformers, mode: "in", - importType, + importContext, }, ), ).toMatchSnapshot(); diff --git a/tests/toTypescript/transfomers/time.test.ts b/tests/toTypescript/transfomers/time.test.ts index 7833df5..79101ce 100644 --- a/tests/toTypescript/transfomers/time.test.ts +++ b/tests/toTypescript/transfomers/time.test.ts @@ -1,5 +1,5 @@ import { DPE } from "@duplojs/utils"; -import { defaultTransformers, type MapImportType, render } from "@scripts/toTypescript"; +import { defaultTransformers, type MapImportContext, render } from "@scripts/toTypescript"; describe("time", () => { it("mode out", () => { @@ -55,8 +55,8 @@ describe("time", () => { }); it("with preset importType", () => { - const importType: MapImportType = new Map(); - importType.set("@duplojs/utils/date", ["TheTime"]); + const importContext: MapImportContext = new Map(); + importContext.set("@duplojs/utils/date", { direct: ["TheTime"] }); expect( render( @@ -65,7 +65,7 @@ describe("time", () => { identifier: "Time", transformers: defaultTransformers, mode: "in", - importType, + importContext, }, ), ).toMatchSnapshot(); From fa2800e80f99a1c6b53c1c37683eea8140231bbb Mon Sep 17 00:00:00 2001 From: mathcovax Date: Mon, 25 May 2026 09:49:39 +0000 Subject: [PATCH 14/16] fix(6): remove test import type --- scripts/toDataParser/checkerTransformer/create.ts | 5 ----- scripts/toDataParser/checkerTransformer/transformer.ts | 1 - scripts/toDataParser/dataParserTransformer/create.ts | 5 ----- scripts/toDataParser/dataParserTransformer/hook.ts | 5 ----- scripts/toDataParser/dataParserTransformer/transformer.ts | 2 -- scripts/toTypescript/buildContext.ts | 1 - scripts/toTypescript/transformer/create.ts | 5 ----- scripts/toTypescript/transformer/hook.ts | 5 ----- scripts/toTypescript/transformer/transformer.ts | 7 ------- tests/toDataParser/checkerTransfomers/refine.test.ts | 2 -- .../transfomers/__snapshots__/date.test.ts.snap | 2 +- .../transfomers/__snapshots__/file.test.ts.snap | 2 +- .../transfomers/__snapshots__/time.test.ts.snap | 2 +- tests/toTypescript/transfomers/file.test.ts | 2 +- tests/toTypescript/transfomers/templateLiteral.test.ts | 2 -- tests/toTypescript/transfomers/time.test.ts | 2 +- 16 files changed, 5 insertions(+), 45 deletions(-) diff --git a/scripts/toDataParser/checkerTransformer/create.ts b/scripts/toDataParser/checkerTransformer/create.ts index a792674..c9156d1 100644 --- a/scripts/toDataParser/checkerTransformer/create.ts +++ b/scripts/toDataParser/checkerTransformer/create.ts @@ -16,11 +16,6 @@ export type CheckerTransformerEither = export interface CheckerTransformerParams { readonly importContext: TST.MapImportContext; - /** - * @deprecated use importContext - */ - readonly importType: TST.MapImportContext; - success( result: CallExpression, ): CheckerTransformerSuccessEither; diff --git a/scripts/toDataParser/checkerTransformer/transformer.ts b/scripts/toDataParser/checkerTransformer/transformer.ts index a9afadc..337e361 100644 --- a/scripts/toDataParser/checkerTransformer/transformer.ts +++ b/scripts/toDataParser/checkerTransformer/transformer.ts @@ -35,7 +35,6 @@ export function checkerTransformer( ) { const functionParams: CheckerTransformerParams = { importContext: params.importContext, - importType: params.importContext, success(result) { return E.right("buildSuccess", result); }, diff --git a/scripts/toDataParser/dataParserTransformer/create.ts b/scripts/toDataParser/dataParserTransformer/create.ts index edb5372..f2f8a33 100644 --- a/scripts/toDataParser/dataParserTransformer/create.ts +++ b/scripts/toDataParser/dataParserTransformer/create.ts @@ -42,11 +42,6 @@ export interface TransformerParams { readonly context: MapContext; readonly importContext: TST.MapImportContext; - /** - * @deprecated use importContext - */ - readonly importType: TST.MapImportContext; - transformer( dataParser: DP.DataParser, ): MaybeTransformerEither; diff --git a/scripts/toDataParser/dataParserTransformer/hook.ts b/scripts/toDataParser/dataParserTransformer/hook.ts index d279bfe..7ff329c 100644 --- a/scripts/toDataParser/dataParserTransformer/hook.ts +++ b/scripts/toDataParser/dataParserTransformer/hook.ts @@ -14,11 +14,6 @@ export interface TransformerHookParams { context: MapContext; importContext: TST.MapImportContext; - /** - * @deprecated use importContext - */ - importType: TST.MapImportContext; - output( action: TransformerHookAction, dataParser: DP.DataParsers diff --git a/scripts/toDataParser/dataParserTransformer/transformer.ts b/scripts/toDataParser/dataParserTransformer/transformer.ts index 0c57694..2d19145 100644 --- a/scripts/toDataParser/dataParserTransformer/transformer.ts +++ b/scripts/toDataParser/dataParserTransformer/transformer.ts @@ -35,7 +35,6 @@ export function transformer( dataParser: lastValue, context: params.context, importContext: params.importContext, - importType: params.importContext, output: (action, dataParser) => ({ dataParser, action, @@ -95,7 +94,6 @@ export function transformer( return E.left("buildDataParserError", currentDataParser); }, importContext: params.importContext, - importType: params.importContext, getDefinition(customProperties = []) { return getDefinitionDataParser({ dataParser: currentDataParser, diff --git a/scripts/toTypescript/buildContext.ts b/scripts/toTypescript/buildContext.ts index 279674c..890dc7e 100644 --- a/scripts/toTypescript/buildContext.ts +++ b/scripts/toTypescript/buildContext.ts @@ -34,7 +34,6 @@ export function buildContext( ...params, context, importContext, - importType: importContext, mode: params.mode ?? "out", hooks: params.hooks ?? [], recursiveDataParsers: getRecursiveDataParser(schema), diff --git a/scripts/toTypescript/transformer/create.ts b/scripts/toTypescript/transformer/create.ts index e5beacd..7a1832d 100644 --- a/scripts/toTypescript/transformer/create.ts +++ b/scripts/toTypescript/transformer/create.ts @@ -33,11 +33,6 @@ export interface TransformerParams { readonly context: MapContext; readonly importContext: MapImportContext; - /** - * @deprecated use importContext - */ - readonly importType: MapImportContext; - transformer( schema: DP.DataParser, ): MaybeTransformerEither; diff --git a/scripts/toTypescript/transformer/hook.ts b/scripts/toTypescript/transformer/hook.ts index b4cf774..cbb72b6 100644 --- a/scripts/toTypescript/transformer/hook.ts +++ b/scripts/toTypescript/transformer/hook.ts @@ -13,11 +13,6 @@ export interface TransformerHookParams { context: MapContext; importContext: MapImportContext; - /** - * @deprecated use importContext - */ - importType: MapImportContext; - output( action: TransformerHookAction, schema: DP.DataParsers diff --git a/scripts/toTypescript/transformer/transformer.ts b/scripts/toTypescript/transformer/transformer.ts index 6199d0c..4c09f73 100644 --- a/scripts/toTypescript/transformer/transformer.ts +++ b/scripts/toTypescript/transformer/transformer.ts @@ -12,11 +12,6 @@ export interface TransformerFunctionParams { readonly hooks: readonly TransformerHook[]; readonly recursiveDataParsers: DDataParser.DataParser[]; readonly importContext: MapImportContext; - - /** - * @deprecated use importContext - */ - readonly importType?: MapImportContext; } export function transformer( schema: DP.DataParser, @@ -30,7 +25,6 @@ export function transformer( schema: lastValue, context: params.context, importContext: params.importContext, - importType: params.importContext, output: (action, schema) => ({ schema, action, @@ -98,7 +92,6 @@ export function transformer( return E.left("buildDataParserError"); }, importContext: params.importContext, - importType: params.importContext, addImport: createAddImport(params.importContext), }; diff --git a/tests/toDataParser/checkerTransfomers/refine.test.ts b/tests/toDataParser/checkerTransfomers/refine.test.ts index d58cc9e..9e0650d 100644 --- a/tests/toDataParser/checkerTransfomers/refine.test.ts +++ b/tests/toDataParser/checkerTransfomers/refine.test.ts @@ -83,7 +83,6 @@ describe("checkerRefine", () => { const importContext = new Map(); const result = checkerRefineTransformer(checker, { importContext, - importType: importContext, success(value) { return E.right("buildSuccess", value); }, @@ -115,7 +114,6 @@ describe("checkerRefine", () => { const importContext = new Map(); const result = checkerRefineTransformer(checker, { importContext, - importType: importContext, success(value) { return E.right("buildSuccess", value); }, diff --git a/tests/toTypescript/transfomers/__snapshots__/date.test.ts.snap b/tests/toTypescript/transfomers/__snapshots__/date.test.ts.snap index ea8f90f..773752a 100644 --- a/tests/toTypescript/transfomers/__snapshots__/date.test.ts.snap +++ b/tests/toTypescript/transfomers/__snapshots__/date.test.ts.snap @@ -24,7 +24,7 @@ exports[`date > mode out 2`] = ` export type DateIdentifier = TheDate;" `; -exports[`date > with preset importType 1`] = ` +exports[`date > with preset importContext 1`] = ` "import { 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 index 71987ca..7b773e3 100644 --- a/tests/toTypescript/transfomers/__snapshots__/file.test.ts.snap +++ b/tests/toTypescript/transfomers/__snapshots__/file.test.ts.snap @@ -12,7 +12,7 @@ exports[`file > basic 2`] = ` export type FileIdentifier = FileInterface;" `; -exports[`file > with preset importType 1`] = ` +exports[`file > with preset importContext 1`] = ` "import { 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 1c823f7..bbf1d5a 100644 --- a/tests/toTypescript/transfomers/__snapshots__/time.test.ts.snap +++ b/tests/toTypescript/transfomers/__snapshots__/time.test.ts.snap @@ -24,7 +24,7 @@ exports[`time > mode out 2`] = ` export type TimeIdentifier = TheTime;" `; -exports[`time > with preset importType 1`] = ` +exports[`time > with preset importContext 1`] = ` "import { TheTime, SerializedTheTime } from "@duplojs/utils/date"; export type Time = SerializedTheTime | number | TheTime;" diff --git a/tests/toTypescript/transfomers/file.test.ts b/tests/toTypescript/transfomers/file.test.ts index ba72787..3c096c6 100644 --- a/tests/toTypescript/transfomers/file.test.ts +++ b/tests/toTypescript/transfomers/file.test.ts @@ -28,7 +28,7 @@ describe("file", () => { ).toMatchSnapshot(); }); - it("with preset importType", () => { + it("with preset importContext", () => { const importContext: MapImportContext = new Map(); importContext.set("@duplojs/server-utils/file", { direct: ["FileInterface"] }); diff --git a/tests/toTypescript/transfomers/templateLiteral.test.ts b/tests/toTypescript/transfomers/templateLiteral.test.ts index 13e766e..55c1c8c 100644 --- a/tests/toTypescript/transfomers/templateLiteral.test.ts +++ b/tests/toTypescript/transfomers/templateLiteral.test.ts @@ -88,7 +88,6 @@ describe("templateLiteral", () => { mode: "out", context: new Map(), importContext: new Map(), - importType: new Map(), addImport(path, typeName) { return; }, @@ -113,7 +112,6 @@ describe("templateLiteral", () => { mode: "out", context: new Map(), importContext: 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 79101ce..b6461b7 100644 --- a/tests/toTypescript/transfomers/time.test.ts +++ b/tests/toTypescript/transfomers/time.test.ts @@ -54,7 +54,7 @@ describe("time", () => { ).toMatchSnapshot(); }); - it("with preset importType", () => { + it("with preset importContext", () => { const importContext: MapImportContext = new Map(); importContext.set("@duplojs/utils/date", { direct: ["TheTime"] }); From f5ac82d14a7a2ceff843b363b38624c6c2b96c52 Mon Sep 17 00:00:00 2001 From: ZeRiix Date: Mon, 25 May 2026 11:54:54 +0200 Subject: [PATCH 15/16] fix(06): remove last test import type --- .../transfomers/__snapshots__/file.test.ts.snap | 6 ------ tests/toTypescript/transfomers/file.test.ts | 17 ----------------- 2 files changed, 23 deletions(-) diff --git a/tests/toTypescript/transfomers/__snapshots__/file.test.ts.snap b/tests/toTypescript/transfomers/__snapshots__/file.test.ts.snap index 7b773e3..93a5830 100644 --- a/tests/toTypescript/transfomers/__snapshots__/file.test.ts.snap +++ b/tests/toTypescript/transfomers/__snapshots__/file.test.ts.snap @@ -11,9 +11,3 @@ exports[`file > basic 2`] = ` export type FileIdentifier = FileInterface;" `; - -exports[`file > with preset importContext 1`] = ` -"import { FileInterface } from "@duplojs/server-utils/file"; - -export type File = FileInterface;" -`; diff --git a/tests/toTypescript/transfomers/file.test.ts b/tests/toTypescript/transfomers/file.test.ts index 3c096c6..2275548 100644 --- a/tests/toTypescript/transfomers/file.test.ts +++ b/tests/toTypescript/transfomers/file.test.ts @@ -27,21 +27,4 @@ describe("file", () => { ), ).toMatchSnapshot(); }); - - it("with preset importContext", () => { - const importContext: MapImportContext = new Map(); - importContext.set("@duplojs/server-utils/file", { direct: ["FileInterface"] }); - - expect( - render( - SDP.file(), - { - identifier: "File", - transformers: defaultTransformers, - mode: "in", - importContext, - }, - ), - ).toMatchSnapshot(); - }); }); From 1ee75685e8ed7cf9707710e77a8f1babc3a64e27 Mon Sep 17 00:00:00 2001 From: mathcovax Date: Mon, 25 May 2026 14:15:27 +0000 Subject: [PATCH 16/16] feat(6): add dependencies context --- .../__snapshots__/recursive.gen.ts | 28 ++-- scripts/toDataParser/buildContext.ts | 14 +- .../dataParserTransformer/create.ts | 3 + .../dataParserTransformer/transformer.ts | 73 +++++---- scripts/toDataParser/index.ts | 2 + scripts/toDataParser/render.ts | 4 +- scripts/toTypescript/buildContext.ts | 6 +- scripts/toTypescript/render.ts | 4 +- .../transformer/createImportDeclaration.ts | 48 +++--- tests/_utils/setup.ts | 21 +++ .../dependenciesContext.test.ts.snap | 45 ++++++ .../__snapshots__/render.test.ts.snap | 70 ++++---- .../toDataParser/dependenciesContext.test.ts | 151 ++++++++++++++++++ vitest.config.js | 1 + 14 files changed, 358 insertions(+), 112 deletions(-) create mode 100644 tests/_utils/setup.ts create mode 100644 tests/toDataParser/__snapshots__/dependenciesContext.test.ts.snap create mode 100644 tests/toDataParser/dependenciesContext.test.ts diff --git a/integration/toDataParser/__snapshots__/recursive.gen.ts b/integration/toDataParser/__snapshots__/recursive.gen.ts index 85e5f88..8d072f4 100644 --- a/integration/toDataParser/__snapshots__/recursive.gen.ts +++ b/integration/toDataParser/__snapshots__/recursive.gen.ts @@ -5,14 +5,14 @@ export type RecursiveType0 = { replies: RecursiveType0[]; }; -export type $recursiveDataParser2 = RecursiveType0; +export type $recursive1DataParser = RecursiveType0; export type RecursiveType2 = [ string, RecursiveType2[] ]; -export type $recursiveDataParser4 = RecursiveType2; +export type $recursive2DataParser = RecursiveType2; export type RecursiveType4 = { name: string; @@ -21,20 +21,20 @@ export type RecursiveType4 = { meta: RecursiveType2; }; -export type $recursiveDataParser0 = RecursiveType4; +export type $recursive0DataParser = RecursiveType4; -export const recursiveDataParser0: DP.DataParser<$recursiveDataParser0> = DP.object({ - name: DP.string(), - children: DP.array(DP.lazy(() => recursiveDataParser0)), - comment: DP.lazy(() => recursiveDataParser2), - meta: DP.lazy(() => recursiveDataParser4) -}); - -export const recursiveDataParser2: DP.DataParser<$recursiveDataParser2> = DP.object({ +export const recursive1DataParser: DP.DataParser<$recursive1DataParser> = DP.object({ id: DP.string(), - replies: DP.array(DP.lazy(() => recursiveDataParser2)) + replies: DP.array(DP.lazy(() => recursive1DataParser)) }); -export const recursiveDataParser4: DP.DataParser<$recursiveDataParser4> = DP.tuple([DP.string(), DP.array(DP.lazy(() => recursiveDataParser4))]); +export const recursive2DataParser: DP.DataParser<$recursive2DataParser> = DP.tuple([DP.string(), DP.array(DP.lazy(() => recursive2DataParser))]); + +export const recursive0DataParser: DP.DataParser<$recursive0DataParser> = DP.object({ + name: DP.string(), + children: DP.array(DP.lazy(() => recursive0DataParser)), + comment: DP.lazy(() => recursive1DataParser), + meta: DP.lazy(() => recursive2DataParser) +}); -export const recursiveNodeDataParser = recursiveDataParser0; +export const recursiveNodeDataParser = recursive0DataParser; \ No newline at end of file diff --git a/scripts/toDataParser/buildContext.ts b/scripts/toDataParser/buildContext.ts index 852cb0c..9cca5c8 100644 --- a/scripts/toDataParser/buildContext.ts +++ b/scripts/toDataParser/buildContext.ts @@ -1,5 +1,5 @@ import { DP, E, unwrap } from "@duplojs/utils"; -import { createIdentifier, type createTransformer, transformer, type MapContext, type TransformerHook, type DataParserErrorEither, type DataParserNotSupportedEither, type DataParserGetDefinitionErrorEither, type ToTypescriptDataParserErrorEither, type ToTypescriptDataParserNotSupportedEither } from "./dataParserTransformer"; +import { createIdentifier, type createTransformer, transformer, type MapContext, type TransformerHook, type DataParserErrorEither, type DataParserNotSupportedEither, type DataParserGetDefinitionErrorEither, type ToTypescriptDataParserErrorEither, type ToTypescriptDataParserNotSupportedEither, type DependenciesContext } from "./dataParserTransformer"; import type * as TST from "@scripts/toTypescript"; import { getRecursiveDataParser } from "@scripts/utils"; import { factory } from "typescript"; @@ -35,7 +35,7 @@ export function buildContext( schema: DP.DataParser, params: BuildContextParams, ): ( - | BuildedContext + | E.Success | DataParserNotSupportedEither | DataParserErrorEither | DataParserGetDefinitionErrorEither @@ -45,6 +45,7 @@ export function buildContext( const context: MapContext = params.context ?? new Map(); const typescriptContext: TST.MapContext = params.typescriptContext ?? new Map(); const importContext: TST.MapImportContext = params.importContext ?? new Map(); + const dependenciesContext: DependenciesContext = new Set(); const importMode = params.importMode ?? "lite"; importContext.set("@duplojs/utils/dataParser", { @@ -67,6 +68,7 @@ export function buildContext( hooks: params.hooks ?? [], recursiveDataParsers: getRecursiveDataParser(schema), dependencyIdentifier: factory.createIdentifier(importMode === "extended" ? "DPE" : "DP"), + dependenciesContext, }, ); @@ -81,23 +83,27 @@ export function buildContext( identifier: factory.createIdentifier(createIdentifier(params.identifier)), expression: unwrap(result), typeIdentifier: null, + dependencies: dependenciesContext, }, ); } else if (schema.definition.identifier !== params.identifier) { + dependenciesContext.add(schema); + context.set( DP.empty(), { identifier: factory.createIdentifier(createIdentifier(params.identifier)), expression: factory.createIdentifier(createIdentifier(schema.definition.identifier)), typeIdentifier: null, + dependencies: dependenciesContext, }, ); } - return { + return E.success({ context, importContext: importContext, typescriptContext, importMode, - }; + }); } diff --git a/scripts/toDataParser/dataParserTransformer/create.ts b/scripts/toDataParser/dataParserTransformer/create.ts index f2f8a33..0f385f3 100644 --- a/scripts/toDataParser/dataParserTransformer/create.ts +++ b/scripts/toDataParser/dataParserTransformer/create.ts @@ -21,10 +21,13 @@ export type DataParserGetDefinitionErrorEither = E.Left< } >; +export type DependenciesContext = Set; + export interface MapContextValue { readonly identifier: Identifier; readonly expression: CallExpression | Identifier; readonly typeIdentifier: Identifier | null; + readonly dependencies: DependenciesContext; } export type MapContext = Map; diff --git a/scripts/toDataParser/dataParserTransformer/transformer.ts b/scripts/toDataParser/dataParserTransformer/transformer.ts index 2d19145..4f645a1 100644 --- a/scripts/toDataParser/dataParserTransformer/transformer.ts +++ b/scripts/toDataParser/dataParserTransformer/transformer.ts @@ -1,6 +1,6 @@ import { A, E, type DP, unwrap, justExec } from "@duplojs/utils"; import * as TST from "@scripts/toTypescript"; -import type { MapContext, TransformerParams, createTransformer, MaybeTransformerEither } from "./create"; +import type { MapContext, TransformerParams, createTransformer, MaybeTransformerEither, DependenciesContext, MapContextValue } from "./create"; import { factory, type Identifier } from "typescript"; import type { TransformerHook } from "./hook"; import type { createCheckerTransformer } from "../checkerTransformer"; @@ -14,6 +14,7 @@ export interface TransformerFunctionParams { readonly context: MapContext; readonly typescriptContext: TST.MapContext; readonly importContext: TST.MapImportContext; + readonly dependenciesContext: DependenciesContext; readonly dependencyIdentifier: Identifier; readonly hooks: readonly TransformerHook[]; readonly recursiveDataParsers: DP.DataParser[]; @@ -48,35 +49,47 @@ export function transformer( }, ); - const contextValue = params.context.get(currentDataParser); + if (currentDataParser.definition.identifier) { + params.dependenciesContext.add(currentDataParser); + } + + const identifiedDataParser = params.context.get(currentDataParser); - if (contextValue) { + if (identifiedDataParser) { return E.right( "buildSuccess", - contextValue.identifier, + identifiedDataParser.identifier, ); } - const shouldCreateConstDeclaration = A.includes(params.recursiveDataParsers, currentDataParser) - || !!currentDataParser.definition.identifier; - const currentIdentifier = shouldCreateConstDeclaration - ? factory.createIdentifier( - currentDataParser.definition.identifier !== undefined - ? createIdentifier(currentDataParser.definition.identifier) - : `recursiveDataParser${params.context.size + params.context.size}`, - ) - : undefined; + const newIdentifiedDataParser = justExec(() => { + const currentIdentifier = A.includes(params.recursiveDataParsers, currentDataParser) + || !!currentDataParser.definition.identifier + ? factory.createIdentifier( + currentDataParser.definition.identifier !== undefined + ? createIdentifier(currentDataParser.definition.identifier) + : `recursive${params.context.size}DataParser`, + ) + : undefined; + + if (!currentIdentifier) { + return null; + } + + const contextValue: MapContextValue = { + identifier: currentIdentifier, + expression: factory.createIdentifier("undefined"), + typeIdentifier: null, + dependencies: new Set(), + }; - if (currentIdentifier) { params.context.set( currentDataParser, - { - identifier: currentIdentifier, - expression: factory.createIdentifier("undefined"), - typeIdentifier: null, - }, + contextValue, ); - } + + return contextValue; + }); const functionParams: TransformerParams = { success(result) { @@ -85,7 +98,11 @@ export function transformer( transformer(dataParser) { return transformer( dataParser, - params, + { + ...params, + dependenciesContext: newIdentifiedDataParser?.dependencies + ?? params.dependenciesContext, + }, ); }, context: params.context, @@ -139,12 +156,12 @@ export function transformer( return result; } - if (currentIdentifier) { + if (newIdentifiedDataParser) { const typeIdentifier = justExec(() => { if (!A.includes(params.recursiveDataParsers, currentDataParser)) { - return undefined; + return null; } - const identifier = `$${currentIdentifier.text}`; + const identifier = `$${newIdentifiedDataParser.identifier.text}`; const result = TST.buildContext( currentDataParser, @@ -176,18 +193,20 @@ export function transformer( return typeIdentifier; } + params.context.delete(currentDataParser); + params.context.set( currentDataParser, { - identifier: currentIdentifier, + ...newIdentifiedDataParser, expression: unwrap(result), - typeIdentifier: typeIdentifier ?? null, + typeIdentifier: typeIdentifier, }, ); return E.right( "buildSuccess", - currentIdentifier, + newIdentifiedDataParser.identifier, ); } diff --git a/scripts/toDataParser/index.ts b/scripts/toDataParser/index.ts index 7da6024..c7996cf 100644 --- a/scripts/toDataParser/index.ts +++ b/scripts/toDataParser/index.ts @@ -3,3 +3,5 @@ export * from "./override"; export * from "./checkerTransformer"; export * from "./dataParserTransformer"; export * from "./render"; +export * from "./buildContext"; +export * from "./printer"; diff --git a/scripts/toDataParser/render.ts b/scripts/toDataParser/render.ts index 3b01de9..7fb69bc 100644 --- a/scripts/toDataParser/render.ts +++ b/scripts/toDataParser/render.ts @@ -2,7 +2,7 @@ import type * as TST from "@scripts/toTypescript"; import { type DataParserNotSupportedEither, type DataParserGetDefinitionErrorEither, type DataParserErrorEither, type MapContext, type ToTypescriptDataParserErrorEither, type ToTypescriptDataParserNotSupportedEither } from "./dataParserTransformer"; import { createToDataParserKind } from "./kind"; import { buildContext, type BuildContextParams } from "./buildContext"; -import { type DP, E, kindClass } from "@duplojs/utils"; +import { type DP, E, kindClass, unwrap } from "@duplojs/utils"; import { printer } from "./printer"; export class DataParserToDataParserRenderError extends kindClass( @@ -65,6 +65,6 @@ export function render(dataParser: DP.DataParser, params: RenderParams) { } return printer( - result, + unwrap(result), ); } diff --git a/scripts/toTypescript/buildContext.ts b/scripts/toTypescript/buildContext.ts index 890dc7e..97e17dc 100644 --- a/scripts/toTypescript/buildContext.ts +++ b/scripts/toTypescript/buildContext.ts @@ -21,7 +21,7 @@ export function buildContext( schema: DP.DataParser, params: BuildContextParams, ): ( - | BuildedContext + | E.Success | DataParserNotSupportedEither | DataParserErrorEither ) { @@ -68,8 +68,8 @@ export function buildContext( ); } - return { + return E.success({ context, importContext, - }; + }); } diff --git a/scripts/toTypescript/render.ts b/scripts/toTypescript/render.ts index 8a7ce3e..1482ca5 100644 --- a/scripts/toTypescript/render.ts +++ b/scripts/toTypescript/render.ts @@ -1,4 +1,4 @@ -import { type DP, E, kindClass } from "@duplojs/utils"; +import { type DP, E, kindClass, unwrap } from "@duplojs/utils"; import { type DataParserErrorEither, type DataParserNotSupportedEither } from "./transformer"; import { createToTypescriptKind } from "./kind"; import { buildContext, type BuildContextParams } from "./buildContext"; @@ -38,6 +38,6 @@ export function render(schema: DP.DataParser, params: RenderParams) { } return printer( - result, + unwrap(result), ); } diff --git a/scripts/toTypescript/transformer/createImportDeclaration.ts b/scripts/toTypescript/transformer/createImportDeclaration.ts index 8b7b292..8c1c008 100644 --- a/scripts/toTypescript/transformer/createImportDeclaration.ts +++ b/scripts/toTypescript/transformer/createImportDeclaration.ts @@ -8,6 +8,7 @@ export function createImportDeclaration(importContext: MapImportContext) { A.reduceFrom([]), ({ element: [path, imports], lastValue, next }) => { const declarations = A.concat( + lastValue, A.map( imports.namespace ?? [], (identifier) => factory.createImportDeclaration( @@ -34,36 +35,33 @@ export function createImportDeclaration(importContext: MapImportContext) { undefined, ), ), - ); - - return next( - A.concat( - lastValue, - imports.direct?.length - ? A.push( - declarations, - factory.createImportDeclaration( + imports.direct?.length + ? [ + factory.createImportDeclaration( + undefined, + factory.createImportClause( + undefined, undefined, - factory.createImportClause( - undefined, - undefined, - factory.createNamedImports( - A.map( - imports.direct, - (identifier) => factory.createImportSpecifier( - false, - undefined, - factory.createIdentifier(identifier), - ), + factory.createNamedImports( + A.map( + imports.direct, + (identifier) => factory.createImportSpecifier( + false, + undefined, + factory.createIdentifier(identifier), ), ), ), - factory.createStringLiteral(path), - undefined, ), - ) - : declarations, - ), + factory.createStringLiteral(path), + undefined, + ), + ] + : [], + ); + + return next( + declarations, ); }, ); diff --git a/tests/_utils/setup.ts b/tests/_utils/setup.ts new file mode 100644 index 0000000..e9e4b59 --- /dev/null +++ b/tests/_utils/setup.ts @@ -0,0 +1,21 @@ +import { expect } from "vitest"; + +function areSetsEqual(AA: unknown, BB: unknown): boolean | undefined { + if (!(AA instanceof Set) && !(BB instanceof Set)) { + return undefined; + } + + if (!(AA instanceof Set) || !(BB instanceof Set)) { + return false; + } + + if (AA.size !== BB.size) { + return false; + } + + expect([...AA]).toStrictEqual([...BB]); + + return true; +} + +expect.addEqualityTesters([areSetsEqual]); diff --git a/tests/toDataParser/__snapshots__/dependenciesContext.test.ts.snap b/tests/toDataParser/__snapshots__/dependenciesContext.test.ts.snap new file mode 100644 index 0000000..468c664 --- /dev/null +++ b/tests/toDataParser/__snapshots__/dependenciesContext.test.ts.snap @@ -0,0 +1,45 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`dependencies context > dataParser with no identifier 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const test1DataParser = DP.object({ + name: DP.string(), + age: DP.number() +});" +`; + +exports[`dependencies context > dataParser with sub dataParser with identifier 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const userNameDataParser = DP.string(); + +export const userAgeDataParser = DP.number(); + +export const otherTestDataParser = DP.object({ + name: userNameDataParser, + age: userAgeDataParser +}); + +export const test4DataParser = otherTestDataParser;" +`; + +exports[`dependencies context > dataParser with top level identifier 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const test3DataParser = DP.object({ + name: DP.string(), + age: DP.number() +});" +`; + +exports[`dependencies context > dataParser with top level identifier but it doesn't match with builder identifier 1`] = ` +"import * as DP from "@duplojs/utils/dataParser"; + +export const otherTestDataParser = DP.object({ + name: DP.string(), + age: DP.number() +}); + +export const test2DataParser = otherTestDataParser;" +`; diff --git a/tests/toDataParser/__snapshots__/render.test.ts.snap b/tests/toDataParser/__snapshots__/render.test.ts.snap index b081406..77b386b 100644 --- a/tests/toDataParser/__snapshots__/render.test.ts.snap +++ b/tests/toDataParser/__snapshots__/render.test.ts.snap @@ -7,13 +7,13 @@ export type RecursiveType0 = { next: RecursiveType0; }; -export type $recursiveDataParser0 = RecursiveType0; +export type $recursive0DataParser = RecursiveType0; -export const recursiveDataParser0: DP.DataParser<$recursiveDataParser0> = DP.object({ - next: DP.lazy(() => recursiveDataParser0) +export const recursive0DataParser: DP.DataParser<$recursive0DataParser> = DP.object({ + next: DP.lazy(() => recursive0DataParser) }); -export const recursiveNodeParserDataParser = recursiveDataParser0;" +export const recursiveNodeParserDataParser = recursive0DataParser;" `; exports[`render > renders checked dataParsers in normal and extended modes 1`] = ` @@ -73,51 +73,51 @@ export type RecursiveType2 = [ export type RecursiveType3 = string | RecursiveType1 | RecursiveType2 | RecursiveType3[]; -export type $recursiveDataParser2 = RecursiveType0; +export type $recursive1DataParser = RecursiveType0; -export type $recursiveDataParser6 = RecursiveType3; +export type $recursive3DataParser = RecursiveType3; -export type $recursiveDataParser4 = RecursiveType2; +export type $recursive2DataParser = RecursiveType2; -export type $recursiveDataParser0 = RecursiveType1; +export type $recursive0DataParser = RecursiveType1; -export const recursiveDataParser0: DP.DataParser<$recursiveDataParser0> = DP.object({ - recursiveProp: DP.object({ - self: DP.lazy(() => recursiveDataParser0), - array: recursiveDataParser2, - tuple: recursiveDataParser4, - union: recursiveDataParser6 - }), - children: DP.array(DP.lazy(() => recursiveDataParser0)), - tuple: recursiveDataParser4, - array: recursiveDataParser2, - union: recursiveDataParser6 -}); - -export const recursiveDataParser2: DP.DataParser<$recursiveDataParser2> = DP.array(DP.union([ +export const recursive1DataParser: DP.DataParser<$recursive1DataParser> = DP.array(DP.union([ DP.string(), - DP.lazy(() => recursiveDataParser2), - DP.lazy(() => recursiveDataParser0) + DP.lazy(() => recursive1DataParser), + DP.lazy(() => recursive0DataParser) ])); -export const recursiveDataParser4: DP.DataParser<$recursiveDataParser4> = DP.tuple([ +export const recursive3DataParser: DP.DataParser<$recursive3DataParser> = DP.union([ + DP.string(), + DP.lazy(() => recursive0DataParser), + DP.lazy(() => recursive2DataParser), + DP.array(DP.lazy(() => recursive3DataParser)) +]); + +export const recursive2DataParser: DP.DataParser<$recursive2DataParser> = DP.tuple([ DP.string(), - DP.lazy(() => recursiveDataParser0), + DP.lazy(() => recursive0DataParser), DP.array(DP.union([ - DP.lazy(() => recursiveDataParser4), - DP.lazy(() => recursiveDataParser6), + DP.lazy(() => recursive2DataParser), + DP.lazy(() => recursive3DataParser), DP.string() ])) ]); -export const recursiveDataParser6: DP.DataParser<$recursiveDataParser6> = DP.union([ - DP.string(), - DP.lazy(() => recursiveDataParser0), - DP.lazy(() => recursiveDataParser4), - DP.array(DP.lazy(() => recursiveDataParser6)) -]); +export const recursive0DataParser: DP.DataParser<$recursive0DataParser> = DP.object({ + recursiveProp: DP.object({ + self: DP.lazy(() => recursive0DataParser), + array: recursive1DataParser, + tuple: recursive2DataParser, + union: recursive3DataParser + }), + children: DP.array(DP.lazy(() => recursive0DataParser)), + tuple: recursive2DataParser, + array: recursive1DataParser, + union: recursive3DataParser +}); -export const complexRecursiveParserDataParser = recursiveDataParser0;" +export const complexRecursiveParserDataParser = recursive0DataParser;" `; exports[`render > renders dataParser with nested checkers 1`] = ` diff --git a/tests/toDataParser/dependenciesContext.test.ts b/tests/toDataParser/dependenciesContext.test.ts new file mode 100644 index 0000000..79454aa --- /dev/null +++ b/tests/toDataParser/dependenciesContext.test.ts @@ -0,0 +1,151 @@ +import { DP, E } from "@duplojs/utils"; +import { defaultTransformers as tsDefaultTransformers } from "@scripts/toTypescript"; +import { defaultCheckerTransformers, defaultTransformers, buildContext, printer } from "@scripts/toDataParser"; + +describe("dependencies context", () => { + it("dataParser with no identifier", () => { + const dataParser = DP.object({ + name: DP.string(), + age: DP.number(), + }); + + const result = E.unwrapRightOrThrow( + buildContext( + dataParser, + { + identifier: "test1", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + typescriptTransformers: tsDefaultTransformers, + }, + ), + ); + + expect([...result.context.entries()]).toStrictEqual([ + [ + expect.objectContaining(DP.emptyKind.setTo({})), + expect.objectContaining({ + dependencies: new Set(), + }), + ], + ]); + + expect(printer(result)).toMatchSnapshot(); + }); + + it("dataParser with top level identifier but it doesn't match with builder identifier", () => { + const dataParser = DP.object({ + name: DP.string(), + age: DP.number(), + }).addIdentifier("otherTest"); + + const result = E.unwrapRightOrThrow( + buildContext( + dataParser, + { + identifier: "test2", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + typescriptTransformers: tsDefaultTransformers, + }, + ), + ); + + expect([...result.context.entries()]).toStrictEqual([ + [ + dataParser, + expect.objectContaining({ + dependencies: new Set(), + }), + ], + [ + expect.objectContaining(DP.emptyKind.setTo({})), + expect.objectContaining({ + dependencies: new Set([dataParser]), + }), + ], + ]); + + expect(printer(result)).toMatchSnapshot(); + }); + + it("dataParser with top level identifier", () => { + const dataParser = DP.object({ + name: DP.string(), + age: DP.number(), + }).addIdentifier("test3"); + + const result = E.unwrapRightOrThrow( + buildContext( + dataParser, + { + identifier: "test3", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + typescriptTransformers: tsDefaultTransformers, + }, + ), + ); + + expect([...result.context.entries()]).toStrictEqual([ + [ + dataParser, + expect.objectContaining({ + dependencies: new Set([]), + }), + ], + ]); + + expect(printer(result)).toMatchSnapshot(); + }); + + it("dataParser with sub dataParser with identifier", () => { + const userNameDataParser = DP.string().addIdentifier("UserName"); + const userAgeDataParser = DP.number().addIdentifier("UserAge"); + const dataParser = DP.object({ + name: userNameDataParser, + age: userAgeDataParser, + }).addIdentifier("otherTest"); + + const result = E.unwrapRightOrThrow( + buildContext( + dataParser, + { + identifier: "test4", + dataParserTransformers: defaultTransformers, + checkerTransformers: defaultCheckerTransformers, + typescriptTransformers: tsDefaultTransformers, + }, + ), + ); + + expect([...result.context.entries()]).toStrictEqual([ + [ + userNameDataParser, + expect.objectContaining({ + dependencies: new Set([]), + }), + ], + [ + userAgeDataParser, + expect.objectContaining({ + dependencies: new Set([]), + }), + ], + [ + dataParser, + expect.objectContaining({ + dependencies: new Set([userNameDataParser, userAgeDataParser]), + }), + ], + [ + expect.objectContaining(DP.emptyKind.setTo({})), + expect.objectContaining({ + dependencies: new Set([dataParser]), + }), + ], + ]); + + expect(printer(result)).toMatchSnapshot(); + }); +}); diff --git a/vitest.config.js b/vitest.config.js index ba66b0d..3f14171 100644 --- a/vitest.config.js +++ b/vitest.config.js @@ -5,6 +5,7 @@ export default defineConfig({ test: { watch: false, globals: true, + setupFiles: "tests/_utils/setup.ts", include: [ "tests/**/*.test.ts", "integration/**/*.test.ts",