From 0e4605cd9fc0b1ee8f8bce13bf70054100d70b4a Mon Sep 17 00:00:00 2001 From: Jeongho Nam Date: Thu, 8 Aug 2024 03:30:58 +0900 Subject: [PATCH] Experiment of samchon/nestia#980: `ts.Type` de/serialization. Succeeded to serialized and deserialize `ts.Type` class instnace from the JSON value level. Also, to accomplish the experiment, refactored `typia` code never to utlize the `ts.Type` methods. --- benchmark/package.json | 2 +- errors/package.json | 2 +- package.json | 2 +- packages/typescript-json/package.json | 4 +- src/factories/TypeFactory.ts | 80 ++++++++++++++++++- .../metadata/emplace_metadata_array_type.ts | 2 +- .../metadata/emplace_metadata_object.ts | 9 ++- .../internal/metadata/iterate_metadata.ts | 4 +- .../metadata/iterate_metadata_array.ts | 3 +- .../metadata/iterate_metadata_atomic.ts | 2 +- .../metadata/iterate_metadata_coalesce.ts | 2 +- .../metadata/iterate_metadata_constant.ts | 5 +- .../metadata/iterate_metadata_intersection.ts | 5 +- .../internal/metadata/iterate_metadata_map.ts | 2 +- .../metadata/iterate_metadata_native.ts | 5 +- .../metadata/iterate_metadata_object.ts | 5 +- .../internal/metadata/iterate_metadata_set.ts | 2 +- .../metadata/iterate_metadata_template.ts | 2 +- .../metadata/iterate_metadata_union.ts | 4 +- .../features/CreateRandomTransformer.ts | 4 +- .../features/RandomTransformer.ts | 4 +- .../json/JsonApplicationTransformer.ts | 10 ++- .../features/misc/MiscLiteralsTransformer.ts | 4 +- .../protobuf/ProtobufMessageTransformer.ts | 4 +- .../reflect/ReflectMetadataTransformer.ts | 4 +- .../internal/GenericTransformer.ts | 6 +- src/utils/TypePredicator.ts | 32 ++++++++ test-esm/package.json | 2 +- test/package.json | 2 +- 29 files changed, 170 insertions(+), 44 deletions(-) create mode 100644 src/utils/TypePredicator.ts diff --git a/benchmark/package.json b/benchmark/package.json index 856aaf6dd7..a16e2a131b 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -72,6 +72,6 @@ "suppress-warnings": "^1.0.2", "tstl": "^3.0.0", "uuid": "^9.0.1", - "typia": "../typia-6.7.2.tgz" + "typia": "../typia-6.7.3-dev.20240808.tgz" } } \ No newline at end of file diff --git a/errors/package.json b/errors/package.json index efc25a8d15..3b0ea81697 100644 --- a/errors/package.json +++ b/errors/package.json @@ -32,6 +32,6 @@ "typescript": "^5.3.2" }, "dependencies": { - "typia": "../typia-6.7.2.tgz" + "typia": "../typia-6.7.3-dev.20240808.tgz" } } \ No newline at end of file diff --git a/package.json b/package.json index a6a2cb2bca..3f648b18e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "typia", - "version": "6.7.2", + "version": "6.7.3-dev.20240808", "description": "Superfast runtime validators with only one line", "main": "lib/index.js", "typings": "lib/index.d.ts", diff --git a/packages/typescript-json/package.json b/packages/typescript-json/package.json index f7bdc28d33..124b4c00fa 100644 --- a/packages/typescript-json/package.json +++ b/packages/typescript-json/package.json @@ -1,6 +1,6 @@ { "name": "typescript-json", - "version": "6.7.2", + "version": "6.7.3-dev.20240808", "description": "Superfast runtime validators with only one line", "main": "lib/index.js", "typings": "lib/index.d.ts", @@ -63,7 +63,7 @@ }, "homepage": "https://typia.io", "dependencies": { - "typia": "6.7.2" + "typia": "6.7.3-dev.20240808" }, "peerDependencies": { "typescript": ">=4.8.0 <5.6.0" diff --git a/src/factories/TypeFactory.ts b/src/factories/TypeFactory.ts index e0ba1c1791..4ea6c42fcb 100644 --- a/src/factories/TypeFactory.ts +++ b/src/factories/TypeFactory.ts @@ -1,5 +1,9 @@ import ts from "typescript"; +import { TypePredicator } from "../utils/TypePredicator"; + +import { Resolved } from "../Resolved"; + export namespace TypeFactory { export const isFunction = (type: ts.Type): boolean => getFunction(type) !== null; @@ -22,7 +26,10 @@ export namespace TypeFactory { (type: ts.Type) => (name: string): ts.Type | null => { // FIND TO-JSON METHOD - const symbol: ts.Symbol | undefined = type.getProperty(name); + const symbol: ts.Symbol | undefined = checker.getPropertyOfType( + type, + name, + ); if (!symbol) return null; else if (!symbol.valueDeclaration) return null; @@ -44,12 +51,17 @@ export namespace TypeFactory { (checker: ts.TypeChecker) => (type: ts.Type, symbol?: ts.Symbol): string => { // PRIMITIVE - symbol ??= type.aliasSymbol ?? type.getSymbol(); + symbol ??= type.aliasSymbol ?? type.symbol; if (symbol === undefined) return checker.typeToString(type); // UNION OR INTERSECT - if (type.aliasSymbol === undefined && type.isUnionOrIntersection()) { - const joiner: string = type.isIntersection() ? " & " : " | "; + if ( + type.aliasSymbol === undefined && + TypePredicator.isUnionOrIntersection(type) + ) { + const joiner: string = TypePredicator.isIntersection(type) + ? " & " + : " | "; return type.types .map((child) => getFullName(checker)(child)) .join(joiner); @@ -115,4 +127,64 @@ export namespace TypeFactory { : ts.SyntaxKind.StringKeyword, ); }; + + export const clone = (type: ts.Type): Resolved => + cloneType(type, 0, new Set()); } + +const cloneType = (x: any, depth: number, visited: Set): any => { + if (x === undefined || depth > 4) return undefined; + else if (typeof x === "object") + if (x === null) return null; + else if (Array.isArray(x)) + return x.map((y) => cloneType(y, depth + 1, visited)); + else { + visited.add(x); + const entries = (() => { + try { + return Object.entries(x); + } catch { + return undefined; + } + })(); + if (entries === undefined) return undefined; + return Object.fromEntries( + entries + .filter( + ([k, y]) => + k !== "parent" && + typeof y !== "function" && + !(typeof y === "object" && y !== null && visited.has(y) === true), + ) + .map(([k, y]) => { + // if (typeof y === "object" && y !== null) console.log(k, get_uid(y)); + return [k, cloneType(y, depth + 1, visited)]; + }), + ); + } + return x; +}; + +// function get_uid(obj: object | null | undefined): number { +// // NO UID EXISTS, THEN ISSUE ONE. +// if (obj instanceof Object) { +// if (obj.hasOwnProperty("__get_m_iUID") === false) { +// const uid: number = ++__s_iUID; +// Object.defineProperty(obj, "__get_m_iUID", { +// value: function (): number { +// return uid; +// }, +// }); +// } + +// // RETURNS +// return (obj as IObject).__get_m_iUID(); +// } else if (obj === undefined) return -1; +// // is null +// else return 0; +// } + +// interface IObject { +// readonly __get_m_iUID: () => number; +// } +// let __s_iUID: number = 0; diff --git a/src/factories/internal/metadata/emplace_metadata_array_type.ts b/src/factories/internal/metadata/emplace_metadata_array_type.ts index 6c05332099..d67a48547e 100644 --- a/src/factories/internal/metadata/emplace_metadata_array_type.ts +++ b/src/factories/internal/metadata/emplace_metadata_array_type.ts @@ -31,7 +31,7 @@ export const emplace_metadata_array_type = // CONSTRUCT VALUE TYPE const value: Metadata = explore_metadata(checker)(options)(collection)( errors, - )(arrayType.getNumberIndexType()!, { + )(checker.getIndexTypeOfType(arrayType, ts.IndexKind.Number)!, { ...explore, escaped: false, aliased: false, diff --git a/src/factories/internal/metadata/emplace_metadata_object.ts b/src/factories/internal/metadata/emplace_metadata_object.ts index 887a32ce43..ed7bc98eb1 100644 --- a/src/factories/internal/metadata/emplace_metadata_object.ts +++ b/src/factories/internal/metadata/emplace_metadata_object.ts @@ -7,6 +7,7 @@ import { MetadataProperty } from "../../../schemas/metadata/MetadataProperty"; import { Writable } from "../../../typings/Writable"; import { ArrayUtil } from "../../../utils/ArrayUtil"; +import { TypePredicator } from "../../../utils/TypePredicator"; import { CommentFactory } from "../../CommentFactory"; import { MetadataCollection } from "../../MetadataCollection"; @@ -28,7 +29,7 @@ export const emplace_metadata_object = if (newbie === false) return obj; // PREPARE ASSETS - const isClass: boolean = parent.isClass(); + const isClass: boolean = TypePredicator.isClass(parent); const pred: (node: ts.Declaration) => boolean = isClass ? (node) => { const kind: ts.SyntaxKind | undefined = node @@ -71,7 +72,9 @@ export const emplace_metadata_object = //---- // REGULAR PROPERTIES //---- - for (const prop of parent.getApparentProperties()) { + for (const prop of checker.getPropertiesOfType( + checker.getApparentType(parent), + )) { // CHECK INTERNAL TAG if ( (prop.getJsDocTags(checker) ?? []).find( @@ -170,7 +173,7 @@ const isProperty = (node: ts.Declaration) => ts.isTypeLiteralNode(node); const iterate_optional_coalesce = (meta: Metadata, type: ts.Type): void => { - if (type.isUnionOrIntersection()) + if (TypePredicator.isUnionOrIntersection(type)) type.types.forEach((child) => iterate_optional_coalesce(meta, child)); else iterate_metadata_coalesce(meta, type); }; diff --git a/src/factories/internal/metadata/iterate_metadata.ts b/src/factories/internal/metadata/iterate_metadata.ts index 9db91096fb..ea6ac54a22 100644 --- a/src/factories/internal/metadata/iterate_metadata.ts +++ b/src/factories/internal/metadata/iterate_metadata.ts @@ -2,6 +2,8 @@ import ts from "typescript"; import { Metadata } from "../../../schemas/metadata/Metadata"; +import { TypePredicator } from "../../../utils/TypePredicator"; + import { MetadataCollection } from "../../MetadataCollection"; import { MetadataFactory } from "../../MetadataFactory"; import { TypeFactory } from "../../TypeFactory"; @@ -26,7 +28,7 @@ export const iterate_metadata = (collection: MetadataCollection) => (errors: MetadataFactory.IError[]) => (meta: Metadata, type: ts.Type, explore: MetadataFactory.IExplore): void => { - if (type.isTypeParameter() === true) { + if (TypePredicator.isTypeParameter(type) === true) { errors.push({ name: TypeFactory.getFullName(checker)(type), explore: { ...explore }, diff --git a/src/factories/internal/metadata/iterate_metadata_array.ts b/src/factories/internal/metadata/iterate_metadata_array.ts index 6720079354..5e61ceadca 100644 --- a/src/factories/internal/metadata/iterate_metadata_array.ts +++ b/src/factories/internal/metadata/iterate_metadata_array.ts @@ -5,6 +5,7 @@ import { MetadataArray } from "../../../schemas/metadata/MetadataArray"; import { MetadataArrayType } from "../../../schemas/metadata/MetadataArrayType"; import { ArrayUtil } from "../../../utils/ArrayUtil"; +import { TypePredicator } from "../../../utils/TypePredicator"; import { MetadataCollection } from "../../MetadataCollection"; import { MetadataFactory } from "../../MetadataFactory"; @@ -49,7 +50,7 @@ const find_array_extended = memory.set(type, null); const res: ts.Type | null = (() => { - if (type.isClassOrInterface() === false) return null; + if (TypePredicator.isInterfaceOrClass(type) === false) return null; for (const t of type.resolvedBaseTypes ?? []) if (checker.isArrayType(t)) return t; else { diff --git a/src/factories/internal/metadata/iterate_metadata_atomic.ts b/src/factories/internal/metadata/iterate_metadata_atomic.ts index 39aea69859..31ec6eb901 100644 --- a/src/factories/internal/metadata/iterate_metadata_atomic.ts +++ b/src/factories/internal/metadata/iterate_metadata_atomic.ts @@ -7,7 +7,7 @@ import { ArrayUtil } from "../../../utils/ArrayUtil"; const same = (type: ts.Type | null) => { if (type === null) return () => false; - return (flag: ts.TypeFlags) => (type.getFlags() & flag) !== 0; + return (flag: ts.TypeFlags) => (type.flags & flag) !== 0; }; export const iterate_metadata_atomic = ( diff --git a/src/factories/internal/metadata/iterate_metadata_coalesce.ts b/src/factories/internal/metadata/iterate_metadata_coalesce.ts index 41b7826e52..61dd71cded 100644 --- a/src/factories/internal/metadata/iterate_metadata_coalesce.ts +++ b/src/factories/internal/metadata/iterate_metadata_coalesce.ts @@ -10,7 +10,7 @@ export const iterate_metadata_coalesce = ( meta: Metadata, type: ts.Type, ): boolean => { - const filter = (flag: ts.TypeFlags) => (type.getFlags() & flag) !== 0; + const filter = (flag: ts.TypeFlags) => (type.flags & flag) !== 0; if (filter(ts.TypeFlags.Unknown) || filter(ts.TypeFlags.Any)) { Writable(meta).any = true; return true; diff --git a/src/factories/internal/metadata/iterate_metadata_constant.ts b/src/factories/internal/metadata/iterate_metadata_constant.ts index cfb3a1cb76..4c9a33c697 100644 --- a/src/factories/internal/metadata/iterate_metadata_constant.ts +++ b/src/factories/internal/metadata/iterate_metadata_constant.ts @@ -5,6 +5,7 @@ import { MetadataConstant } from "../../../schemas/metadata/MetadataConstant"; import { MetadataConstantValue } from "../../../schemas/metadata/MetadataConstantValue"; import { ArrayUtil } from "../../../utils/ArrayUtil"; +import { TypePredicator } from "../../../utils/TypePredicator"; import { CommentFactory } from "../../CommentFactory"; import { MetadataFactory } from "../../MetadataFactory"; @@ -15,7 +16,7 @@ export const iterate_metadata_constant = (meta: Metadata, type: ts.Type): boolean => { if (!options.constant) return false; - const filter = (flag: ts.TypeFlags) => (type.getFlags() & flag) !== 0; + const filter = (flag: ts.TypeFlags) => (type.flags & flag) !== 0; const comment = () => { if (!filter(ts.TypeFlags.EnumLiteral)) return {}; return { @@ -25,7 +26,7 @@ export const iterate_metadata_constant = : undefined, }; }; - if (type.isLiteral()) { + if (TypePredicator.isLiteral(type)) { const value: string | number | bigint = typeof type.value === "object" ? BigInt(`${type.value.negative ? "-" : ""}${type.value.base10Value}`) diff --git a/src/factories/internal/metadata/iterate_metadata_intersection.ts b/src/factories/internal/metadata/iterate_metadata_intersection.ts index 19df54b1f5..2f876bc5f3 100644 --- a/src/factories/internal/metadata/iterate_metadata_intersection.ts +++ b/src/factories/internal/metadata/iterate_metadata_intersection.ts @@ -8,6 +8,7 @@ import { MetadataConstantValue } from "../../../schemas/metadata/MetadataConstan import { MetadataTemplate } from "../../../schemas/metadata/MetadataTemplate"; import { ArrayUtil } from "../../../utils/ArrayUtil"; +import { TypePredicator } from "../../../utils/TypePredicator"; import { MetadataCollection } from "../../MetadataCollection"; import { MetadataFactory } from "../../MetadataFactory"; @@ -26,12 +27,12 @@ export const iterate_metadata_intersection = type: ts.Type, explore: MetadataFactory.IExplore, ): boolean => { - if (!type.isIntersection()) return false; + if (TypePredicator.isIntersection(type) === false) return false; if ( // ONLY OBJECT TYPED INTERSECTION type.types.every( (child) => - (child.getFlags() & ts.TypeFlags.Object) !== 0 && + (child.flags & ts.TypeFlags.Object) !== 0 && !checker.isArrayType(child) && !checker.isTupleType(child), ) diff --git a/src/factories/internal/metadata/iterate_metadata_map.ts b/src/factories/internal/metadata/iterate_metadata_map.ts index c73d276a93..2448104c20 100644 --- a/src/factories/internal/metadata/iterate_metadata_map.ts +++ b/src/factories/internal/metadata/iterate_metadata_map.ts @@ -21,7 +21,7 @@ export const iterate_metadata_map = ): boolean => { type = checker.getApparentType(type); - const name = TypeFactory.getFullName(checker)(type, type.getSymbol()); + const name = TypeFactory.getFullName(checker)(type, type.symbol); const generic = type.aliasSymbol ? type.aliasTypeArguments : checker.getTypeArguments(type as ts.TypeReference); diff --git a/src/factories/internal/metadata/iterate_metadata_native.ts b/src/factories/internal/metadata/iterate_metadata_native.ts index e792b8f811..2a70ab1fda 100644 --- a/src/factories/internal/metadata/iterate_metadata_native.ts +++ b/src/factories/internal/metadata/iterate_metadata_native.ts @@ -10,10 +10,7 @@ export const iterate_metadata_native = (checker: ts.TypeChecker) => (meta: Metadata, type: ts.Type): boolean => { const validator = validate(checker)(type); - const name: string = TypeFactory.getFullName(checker)( - type, - type.getSymbol(), - ); + const name: string = TypeFactory.getFullName(checker)(type, type.symbol); const simple = SIMPLES.get(name); if (simple && validator(simple)) { diff --git a/src/factories/internal/metadata/iterate_metadata_object.ts b/src/factories/internal/metadata/iterate_metadata_object.ts index 19235e2e19..bc6ddad484 100644 --- a/src/factories/internal/metadata/iterate_metadata_object.ts +++ b/src/factories/internal/metadata/iterate_metadata_object.ts @@ -4,6 +4,7 @@ import { Metadata } from "../../../schemas/metadata/Metadata"; import { MetadataObject } from "../../../schemas/metadata/MetadataObject"; import { ArrayUtil } from "../../../utils/ArrayUtil"; +import { TypePredicator } from "../../../utils/TypePredicator"; import { MetadataCollection } from "../../MetadataCollection"; import { MetadataFactory } from "../../MetadataFactory"; @@ -16,10 +17,10 @@ export const iterate_metadata_object = (errors: MetadataFactory.IError[]) => (meta: Metadata, type: ts.Type, ensure: boolean = false): boolean => { if (ensure === false) { - const filter = (flag: ts.TypeFlags) => (type.getFlags() & flag) !== 0; + const filter = (flag: ts.TypeFlags) => (type.flags & flag) !== 0; if ( !filter(ts.TypeFlags.Object) && - !type.isIntersection() && + !TypePredicator.isIntersection(type) && (type as any).intrinsicName !== "object" ) return false; diff --git a/src/factories/internal/metadata/iterate_metadata_set.ts b/src/factories/internal/metadata/iterate_metadata_set.ts index 19f3de0a37..6365076123 100644 --- a/src/factories/internal/metadata/iterate_metadata_set.ts +++ b/src/factories/internal/metadata/iterate_metadata_set.ts @@ -21,7 +21,7 @@ export const iterate_metadata_set = ): boolean => { type = checker.getApparentType(type); - const name = TypeFactory.getFullName(checker)(type, type.getSymbol()); + const name = TypeFactory.getFullName(checker)(type, type.symbol); const generic = type.aliasSymbol ? type.aliasTypeArguments : checker.getTypeArguments(type as ts.TypeReference); diff --git a/src/factories/internal/metadata/iterate_metadata_template.ts b/src/factories/internal/metadata/iterate_metadata_template.ts index da682dc959..9189fd0cbc 100644 --- a/src/factories/internal/metadata/iterate_metadata_template.ts +++ b/src/factories/internal/metadata/iterate_metadata_template.ts @@ -18,7 +18,7 @@ export const iterate_metadata_template = type: ts.Type, explore: MetadataFactory.IExplore, ): boolean => { - const filter = (flag: ts.TypeFlags) => (type.getFlags() & flag) !== 0; + const filter = (flag: ts.TypeFlags) => (type.flags & flag) !== 0; if (!filter(ts.TypeFlags.TemplateLiteral)) return false; const template: ts.TemplateLiteralType = type as ts.TemplateLiteralType; diff --git a/src/factories/internal/metadata/iterate_metadata_union.ts b/src/factories/internal/metadata/iterate_metadata_union.ts index 11e45e234b..44b3d5d683 100644 --- a/src/factories/internal/metadata/iterate_metadata_union.ts +++ b/src/factories/internal/metadata/iterate_metadata_union.ts @@ -2,6 +2,8 @@ import ts from "typescript"; import { Metadata } from "../../../schemas/metadata/Metadata"; +import { TypePredicator } from "../../../utils/TypePredicator"; + import { MetadataCollection } from "../../MetadataCollection"; import { MetadataFactory } from "../../MetadataFactory"; import { iterate_metadata } from "./iterate_metadata"; @@ -16,7 +18,7 @@ export const iterate_metadata_union = type: ts.Type, explore: MetadataFactory.IExplore, ): boolean => { - if (!type.isUnion()) return false; + if (TypePredicator.isUnion(type) === false) return false; type.types.forEach((t) => iterate_metadata(checker)(options)(collection)(errors)(meta, t, { ...explore, diff --git a/src/transformers/features/CreateRandomTransformer.ts b/src/transformers/features/CreateRandomTransformer.ts index f0bc8a34d7..ef0abb3a1e 100644 --- a/src/transformers/features/CreateRandomTransformer.ts +++ b/src/transformers/features/CreateRandomTransformer.ts @@ -2,6 +2,8 @@ import ts from "typescript"; import { RandomProgrammer } from "../../programmers/RandomProgrammer"; +import { TypePredicator } from "../../utils/TypePredicator"; + import { IProject } from "../IProject"; import { TransformerError } from "../TransformerError"; @@ -21,7 +23,7 @@ export namespace CreateRandomTransformer { const node: ts.TypeNode = expression.typeArguments[0]; const type: ts.Type = project.checker.getTypeFromTypeNode(node); - if (type.isTypeParameter()) + if (TypePredicator.isTypeParameter(type)) throw new TransformerError({ code: "typia.createRandom", message: "non-specified generic argument.", diff --git a/src/transformers/features/RandomTransformer.ts b/src/transformers/features/RandomTransformer.ts index b656dd4a7c..64739f69a6 100644 --- a/src/transformers/features/RandomTransformer.ts +++ b/src/transformers/features/RandomTransformer.ts @@ -2,6 +2,8 @@ import ts from "typescript"; import { RandomProgrammer } from "../../programmers/RandomProgrammer"; +import { TypePredicator } from "../../utils/TypePredicator"; + import { IProject } from "../IProject"; import { TransformerError } from "../TransformerError"; @@ -21,7 +23,7 @@ export namespace RandomTransformer { const node: ts.TypeNode = expression.typeArguments[0]; const type: ts.Type = project.checker.getTypeFromTypeNode(node); - if (type.isTypeParameter()) + if (TypePredicator.isTypeParameter(type)) throw new TransformerError({ code: `typia.${modulo.getText()}`, message: "non-specified generic argument.", diff --git a/src/transformers/features/json/JsonApplicationTransformer.ts b/src/transformers/features/json/JsonApplicationTransformer.ts index f059dd8a2f..3e332aa2b5 100644 --- a/src/transformers/features/json/JsonApplicationTransformer.ts +++ b/src/transformers/features/json/JsonApplicationTransformer.ts @@ -11,6 +11,8 @@ import { JsonApplicationProgrammer } from "../../../programmers/json/JsonApplica import { ValidationPipe } from "../../../typings/ValidationPipe"; +import { TypePredicator } from "../../../utils/TypePredicator"; + import { IProject } from "../../IProject"; import { TransformerError } from "../../TransformerError"; @@ -37,7 +39,7 @@ export namespace JsonApplicationTransformer { const types: ts.Type[] = top.elements.map((child) => project.checker.getTypeFromTypeNode(child as ts.TypeNode), ); - if (types.some((t) => t.isTypeParameter())) + if (types.some(TypePredicator.isTypeParameter)) throw new TransformerError({ code: "typia.json.application", message: "non-specified generic argument(s).", @@ -102,8 +104,8 @@ export namespace JsonApplicationTransformer { // CHECK LITERAL TYPE const type: ts.Type = props.checker.getTypeFromTypeNode(node); if ( - !type.isLiteral() && - (type.getFlags() & ts.TypeFlags.BooleanLiteral) === 0 + !TypePredicator.isLiteral(type) && + (type.flags & ts.TypeFlags.BooleanLiteral) === 0 ) throw new TransformerError({ code: "typia.json.application", @@ -111,7 +113,7 @@ export namespace JsonApplicationTransformer { }); // GET VALUE AND VALIDATE IT - const value = type.isLiteral() + const value = TypePredicator.isLiteral(type) ? type.value : props.checker.typeToString(type); if (typeof value !== "string" || props.is(value) === false) diff --git a/src/transformers/features/misc/MiscLiteralsTransformer.ts b/src/transformers/features/misc/MiscLiteralsTransformer.ts index 468374e92a..991426e596 100644 --- a/src/transformers/features/misc/MiscLiteralsTransformer.ts +++ b/src/transformers/features/misc/MiscLiteralsTransformer.ts @@ -2,6 +2,8 @@ import ts from "typescript"; import { MiscLiteralsProgrammer } from "../../../programmers/misc/MiscLiteralsProgrammer"; +import { TypePredicator } from "../../../utils/TypePredicator"; + import { IProject } from "../../IProject"; import { TransformerError } from "../../TransformerError"; @@ -20,7 +22,7 @@ export namespace MiscLiteralsTransformer { const node: ts.TypeNode = expression.typeArguments[0]; const type: ts.Type = project.checker.getTypeFromTypeNode(node); - if (type.isTypeParameter()) + if (TypePredicator.isTypeParameter(type)) throw new TransformerError({ code: "typia.misc.literals", message: "non-specified generic argument.", diff --git a/src/transformers/features/protobuf/ProtobufMessageTransformer.ts b/src/transformers/features/protobuf/ProtobufMessageTransformer.ts index 12480dbc47..8325d087c6 100644 --- a/src/transformers/features/protobuf/ProtobufMessageTransformer.ts +++ b/src/transformers/features/protobuf/ProtobufMessageTransformer.ts @@ -2,6 +2,8 @@ import ts from "typescript"; import { ProtobufMessageProgrammer } from "../../../programmers/protobuf/ProtobufMessageProgrammer"; +import { TypePredicator } from "../../../utils/TypePredicator"; + import { IProject } from "../../IProject"; import { TransformerError } from "../../TransformerError"; @@ -21,7 +23,7 @@ export namespace ProtobufMessageTransformer { const type: ts.Type = project.checker.getTypeFromTypeNode( expression.typeArguments[0], ); - if (type.isTypeParameter()) + if (TypePredicator.isTypeParameter(type)) throw new TransformerError({ code: "tyipa.protobuf.message", message: "non-specified generic argument.", diff --git a/src/transformers/features/reflect/ReflectMetadataTransformer.ts b/src/transformers/features/reflect/ReflectMetadataTransformer.ts index 15da6d9fae..7a9c29c665 100644 --- a/src/transformers/features/reflect/ReflectMetadataTransformer.ts +++ b/src/transformers/features/reflect/ReflectMetadataTransformer.ts @@ -7,6 +7,8 @@ import { MetadataFactory } from "../../../factories/MetadataFactory"; import { IMetadataApplication } from "../../../schemas/metadata/IMetadataApplication"; import { Metadata } from "../../../schemas/metadata/Metadata"; +import { TypePredicator } from "../../../utils/TypePredicator"; + import { IProject } from "../../IProject"; import { TransformerError } from "../../TransformerError"; @@ -30,7 +32,7 @@ export namespace ReflectMetadataTransformer { const types: ts.Type[] = top.elements.map((child) => project.checker.getTypeFromTypeNode(child as ts.TypeNode), ); - if (types.some((t) => t.isTypeParameter())) + if (types.some(TypePredicator.isTypeParameter)) throw new TransformerError({ code: "typia.reflect.metadata", message: "non-specified generic argument(s).", diff --git a/src/transformers/internal/GenericTransformer.ts b/src/transformers/internal/GenericTransformer.ts index a5c8294085..7be2e06a76 100644 --- a/src/transformers/internal/GenericTransformer.ts +++ b/src/transformers/internal/GenericTransformer.ts @@ -1,5 +1,7 @@ import ts from "typescript"; +import { TypePredicator } from "../../utils/TypePredicator"; + import { IProject } from "../IProject"; import { TransformerError } from "../TransformerError"; @@ -36,7 +38,7 @@ export namespace GenericTransformer { expression.arguments[0]!, false, ]; - if (type.isTypeParameter()) + if (TypePredicator.isTypeParameter(type)) throw new TransformerError({ code: `typia.${method}`, message: `non-specified generic argument.`, @@ -82,7 +84,7 @@ export namespace GenericTransformer { const node: ts.TypeNode = expression.typeArguments[0]; const type: ts.Type = project.checker.getTypeFromTypeNode(node); - if (type.isTypeParameter()) + if (TypePredicator.isTypeParameter(type)) throw new TransformerError({ code: `typia.${method}`, message: `non-specified generic argument.`, diff --git a/src/utils/TypePredicator.ts b/src/utils/TypePredicator.ts new file mode 100644 index 0000000000..bbb9ccd5f8 --- /dev/null +++ b/src/utils/TypePredicator.ts @@ -0,0 +1,32 @@ +import ts from "typescript"; + +export namespace TypePredicator { + export const isLiteral = (type: ts.Type): type is ts.LiteralType => + !!( + type.flags & + (ts.TypeFlags.EnumLiteral | + ts.TypeFlags.StringLiteral | + ts.TypeFlags.NumberLiteral | + ts.TypeFlags.BigIntLiteral) + ); + + export const isTypeParameter = (type: ts.Type): type is ts.TypeParameter => + !!(type.flags & ts.TypeFlags.TypeParameter); + + export const isIntersection = (type: ts.Type): type is ts.IntersectionType => + !!(type.flags & ts.TypeFlags.Intersection); + + export const isUnion = (type: ts.Type): type is ts.UnionType => + !!(type.flags & ts.TypeFlags.Union); + + export const isUnionOrIntersection = ( + type: ts.Type, + ): type is ts.UnionOrIntersectionType => + !!(type.flags & ts.TypeFlags.UnionOrIntersection); + + export const isClass = (type: ts.Type): type is ts.InterfaceType => + !!(ts.getObjectFlags(type) & ts.ObjectFlags.Class); + + export const isInterfaceOrClass = (type: ts.Type): type is ts.InterfaceType => + !!(ts.getObjectFlags(type) & ts.ObjectFlags.ClassOrInterface); +} diff --git a/test-esm/package.json b/test-esm/package.json index a171f3908d..e082b38f50 100644 --- a/test-esm/package.json +++ b/test-esm/package.json @@ -36,6 +36,6 @@ "typescript": "^5.4.5" }, "dependencies": { - "typia": "../typia-6.7.2.tgz" + "typia": "../typia-6.7.3-dev.20240808.tgz" } } \ No newline at end of file diff --git a/test/package.json b/test/package.json index 1fddbb94e9..52deaeabef 100644 --- a/test/package.json +++ b/test/package.json @@ -52,6 +52,6 @@ "suppress-warnings": "^1.0.2", "tstl": "^3.0.0", "uuid": "^9.0.1", - "typia": "../typia-6.7.2.tgz" + "typia": "../typia-6.7.3-dev.20240808.tgz" } } \ No newline at end of file