typia 9.7.2 → 10.0.0-dev.20251107

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +153 -153
  3. package/lib/factories/ProtobufFactory.js +1 -1
  4. package/lib/factories/ProtobufFactory.mjs +1 -1
  5. package/lib/programmers/internal/json_schema_station.d.mts +2 -2
  6. package/lib/programmers/internal/json_schema_station.d.ts +2 -2
  7. package/lib/programmers/llm/LlmApplicationProgrammer.js +5 -1
  8. package/lib/programmers/llm/LlmApplicationProgrammer.js.map +1 -1
  9. package/lib/programmers/llm/LlmApplicationProgrammer.mjs +5 -1
  10. package/lib/programmers/llm/LlmSchemaProgrammer.js +1 -4
  11. package/lib/programmers/llm/LlmSchemaProgrammer.js.map +1 -1
  12. package/lib/programmers/llm/LlmSchemaProgrammer.mjs +1 -35
  13. package/package.json +121 -121
  14. package/src/AssertionGuard.ts +41 -41
  15. package/src/CamelCase.ts +75 -75
  16. package/src/IRandomGenerator.ts +337 -337
  17. package/src/IReadableURLSearchParams.ts +9 -9
  18. package/src/PascalCase.ts +71 -71
  19. package/src/Primitive.ts +90 -90
  20. package/src/Resolved.ts +72 -72
  21. package/src/SnakeCase.ts +127 -127
  22. package/src/TypeGuardError.ts +216 -216
  23. package/src/factories/MetadataCollection.ts +270 -270
  24. package/src/factories/MetadataCommentTagFactory.ts +632 -632
  25. package/src/factories/MetadataFactory.ts +402 -402
  26. package/src/factories/ProtobufFactory.ts +873 -873
  27. package/src/functional.ts +705 -705
  28. package/src/http.ts +972 -972
  29. package/src/internal/_ProtobufReader.ts +188 -188
  30. package/src/internal/_ProtobufSizer.ts +137 -137
  31. package/src/internal/_ProtobufWriter.ts +135 -135
  32. package/src/internal/_jsonStringifyString.ts +42 -42
  33. package/src/json.ts +643 -643
  34. package/src/llm.ts +615 -615
  35. package/src/misc.ts +594 -594
  36. package/src/module.ts +889 -889
  37. package/src/notations.ts +751 -751
  38. package/src/programmers/FeatureProgrammer.ts +605 -605
  39. package/src/programmers/ImportProgrammer.ts +179 -179
  40. package/src/programmers/RandomProgrammer.ts +1195 -1195
  41. package/src/programmers/helpers/ProtobufWire.ts +34 -34
  42. package/src/programmers/internal/check_array_length.ts +43 -43
  43. package/src/programmers/internal/check_bigint.ts +46 -46
  44. package/src/programmers/internal/check_dynamic_key.ts +197 -197
  45. package/src/programmers/internal/check_dynamic_properties.ts +231 -231
  46. package/src/programmers/internal/check_everything.ts +21 -21
  47. package/src/programmers/internal/check_native.ts +23 -23
  48. package/src/programmers/internal/check_number.ts +108 -108
  49. package/src/programmers/internal/check_object.ts +72 -72
  50. package/src/programmers/internal/check_string.ts +46 -46
  51. package/src/programmers/internal/check_template.ts +46 -46
  52. package/src/programmers/internal/check_union_array_like.ts +331 -331
  53. package/src/programmers/internal/decode_union_object.ts +110 -110
  54. package/src/programmers/internal/feature_object_entries.ts +59 -59
  55. package/src/programmers/internal/json_schema_escaped.ts +78 -78
  56. package/src/programmers/internal/json_schema_object.ts +150 -150
  57. package/src/programmers/internal/json_schema_station.ts +2 -2
  58. package/src/programmers/internal/metadata_to_pattern.ts +40 -40
  59. package/src/programmers/internal/postfix_of_tuple.ts +3 -3
  60. package/src/programmers/internal/prune_object_properties.ts +69 -69
  61. package/src/programmers/internal/stringify_dynamic_properties.ts +158 -158
  62. package/src/programmers/internal/stringify_native.ts +5 -5
  63. package/src/programmers/internal/stringify_regular_properties.ts +77 -77
  64. package/src/programmers/internal/template_to_pattern.ts +21 -21
  65. package/src/programmers/internal/wrap_metadata_rest_tuple.ts +21 -21
  66. package/src/programmers/json/JsonStringifyProgrammer.ts +1124 -1124
  67. package/src/programmers/llm/LlmApplicationProgrammer.ts +10 -1
  68. package/src/programmers/llm/LlmSchemaProgrammer.ts +2 -7
  69. package/src/protobuf.ts +820 -820
  70. package/src/reflect.ts +46 -46
  71. package/src/schemas/json/IJsonApplication.ts +77 -77
  72. package/src/schemas/json/IJsonSchemaCollection.ts +212 -212
  73. package/src/schemas/json/IJsonSchemaUnit.ts +263 -263
  74. package/src/schemas/metadata/IMetadataTypeTag.ts +14 -14
  75. package/src/schemas/metadata/Metadata.ts +669 -669
  76. package/src/schemas/metadata/MetadataAliasType.ts +57 -57
  77. package/src/schemas/metadata/MetadataApplication.ts +40 -40
  78. package/src/schemas/metadata/MetadataArray.ts +47 -47
  79. package/src/schemas/metadata/MetadataArrayType.ts +51 -51
  80. package/src/schemas/metadata/MetadataAtomic.ts +85 -85
  81. package/src/schemas/metadata/MetadataEscaped.ts +45 -45
  82. package/src/schemas/metadata/MetadataFunction.ts +45 -45
  83. package/src/schemas/metadata/MetadataObject.ts +46 -46
  84. package/src/schemas/metadata/MetadataObjectType.ts +137 -137
  85. package/src/schemas/metadata/MetadataParameter.ts +52 -52
  86. package/src/schemas/metadata/MetadataProperty.ts +53 -53
  87. package/src/schemas/metadata/MetadataTemplate.ts +78 -78
  88. package/src/schemas/metadata/MetadataTuple.ts +28 -28
  89. package/src/schemas/metadata/MetadataTupleType.ts +61 -61
  90. package/src/tags/Constant.ts +47 -47
  91. package/src/tags/ContentMediaType.ts +27 -27
  92. package/src/tags/Default.ts +52 -52
  93. package/src/tags/Example.ts +56 -56
  94. package/src/tags/Examples.ts +56 -56
  95. package/src/tags/ExclusiveMaximum.ts +44 -44
  96. package/src/tags/ExclusiveMinimum.ts +44 -44
  97. package/src/tags/Format.ts +78 -78
  98. package/src/tags/JsonSchemaPlugin.ts +36 -36
  99. package/src/tags/MaxItems.ts +31 -31
  100. package/src/tags/MaxLength.ts +25 -25
  101. package/src/tags/Maximum.ts +39 -39
  102. package/src/tags/MinItems.ts +31 -31
  103. package/src/tags/MinLength.ts +25 -25
  104. package/src/tags/Minimum.ts +39 -39
  105. package/src/tags/MultipleOf.ts +42 -42
  106. package/src/tags/Pattern.ts +49 -49
  107. package/src/tags/Sequence.ts +37 -37
  108. package/src/tags/TagBase.ts +102 -102
  109. package/src/tags/Type.ts +64 -64
  110. package/src/tags/UniqueItems.ts +34 -34
  111. package/src/tags/internal/FormatCheatSheet.ts +71 -71
  112. package/src/transformers/ITransformOptions.ts +70 -70
  113. package/src/transformers/ImportTransformer.ts +253 -253
  114. package/src/transformers/NoTransformConfigurationError.ts +16 -16
  115. package/src/transformers/features/llm/LlmApplicationTransformer.ts +224 -224
  116. package/src/typings/Equal.ts +18 -18
@@ -1,605 +1,605 @@
1
- import ts from "typescript";
2
-
3
- import { IdentifierFactory } from "../factories/IdentifierFactory";
4
- import { MetadataCollection } from "../factories/MetadataCollection";
5
- import { StatementFactory } from "../factories/StatementFactory";
6
- import { TypeFactory } from "../factories/TypeFactory";
7
- import { ValueFactory } from "../factories/ValueFactory";
8
-
9
- import { Metadata } from "../schemas/metadata/Metadata";
10
- import { MetadataArray } from "../schemas/metadata/MetadataArray";
11
- import { MetadataObjectType } from "../schemas/metadata/MetadataObjectType";
12
-
13
- import { ITypiaContext } from "../transformers/ITypiaContext";
14
-
15
- import { CheckerProgrammer } from "./CheckerProgrammer";
16
- import { FunctionProgrammer } from "./helpers/FunctionProgrammer";
17
- import { IExpressionEntry } from "./helpers/IExpressionEntry";
18
- import { UnionExplorer } from "./helpers/UnionExplorer";
19
- import { feature_object_entries } from "./internal/feature_object_entries";
20
-
21
- export namespace FeatureProgrammer {
22
- /* -----------------------------------------------------------
23
- PARAMETERS
24
- ----------------------------------------------------------- */
25
- export interface IConfig<Output extends ts.ConciseBody = ts.ConciseBody> {
26
- types: IConfig.ITypes;
27
-
28
- /** Prefix name of internal functions for specific types. */
29
- prefix: string;
30
-
31
- /** Whether to archive access path or not. */
32
- path: boolean;
33
-
34
- /** Whether to trace exception or not. */
35
- trace: boolean;
36
-
37
- addition?: undefined | ((collection: MetadataCollection) => ts.Statement[]);
38
-
39
- /** Initializer of metadata. */
40
- initializer: (props: {
41
- context: ITypiaContext;
42
- functor: FunctionProgrammer;
43
- type: ts.Type;
44
- }) => {
45
- collection: MetadataCollection;
46
- metadata: Metadata;
47
- };
48
-
49
- /** Decoder, station of every types. */
50
- decoder: (props: {
51
- metadata: Metadata;
52
- input: ts.Expression;
53
- explore: IExplore;
54
- }) => Output;
55
-
56
- /** Object configurator. */
57
- objector: IConfig.IObjector<Output>;
58
-
59
- /** Generator of functions for object types. */
60
- generator: IConfig.IGenerator;
61
- }
62
- export namespace IConfig {
63
- export interface ITypes {
64
- input: (type: ts.Type, name?: undefined | string) => ts.TypeNode;
65
- output: (type: ts.Type, name?: undefined | string) => ts.TypeNode;
66
- }
67
-
68
- export interface IObjector<Output extends ts.ConciseBody = ts.ConciseBody> {
69
- /** Type checker when union object type comes. */
70
- checker: (props: {
71
- metadata: Metadata;
72
- input: ts.Expression;
73
- explore: IExplore;
74
- }) => ts.Expression;
75
-
76
- /** Decoder, function call expression generator of specific typed objects. */
77
- decoder: (props: {
78
- input: ts.Expression;
79
- object: MetadataObjectType;
80
- explore: IExplore;
81
- }) => ts.Expression;
82
-
83
- /** Joiner of expressions from properties. */
84
- joiner(props: {
85
- entries: IExpressionEntry<Output>[];
86
- input?: ts.Expression;
87
- object?: MetadataObjectType;
88
- }): ts.ConciseBody;
89
-
90
- /**
91
- * Union type specificator.
92
- *
93
- * Expression of an algorithm specifying object type and calling the
94
- * `decoder` function of the specified object type.
95
- */
96
- unionizer: (props: {
97
- objects: MetadataObjectType[];
98
- input: ts.Expression;
99
- explore: IExplore;
100
- }) => ts.Expression;
101
-
102
- /**
103
- * Handler of union type specification failure.
104
- *
105
- * @param props Properties of failure
106
- * @returns Statement of failure
107
- */
108
- failure(props: {
109
- input: ts.Expression;
110
- expected: string;
111
- explore?: undefined | IExplore;
112
- }): ts.Statement;
113
-
114
- /**
115
- * Transformer of type checking expression by discrimination.
116
- *
117
- * When an object type has been specified by a discrimination without full
118
- * iteration, the `unionizer` will decode the object instance after the
119
- * last type checking.
120
- *
121
- * In such circumtance, you can transform the last type checking function.
122
- *
123
- * @deprecated
124
- * @param exp Current expression about type checking
125
- * @returns Transformed expression
126
- */
127
- is?: undefined | ((exp: ts.Expression) => ts.Expression);
128
-
129
- /**
130
- * Transformer of non-undefined type checking by discrimination.
131
- *
132
- * When specifying an union type of objects, `typia` tries to find
133
- * discrimination way just by checking only one property type. If
134
- * succeeded to find the discrimination way, `typia` will check the target
135
- * property type and in the checking, non-undefined type checking would be
136
- * done.
137
- *
138
- * In such process, you can transform the non-undefined type checking.
139
- *
140
- * @deprecated
141
- * @param exp
142
- * @returns Transformed expression
143
- */
144
- required?: undefined | ((exp: ts.Expression) => ts.Expression);
145
-
146
- /**
147
- * Condition wrapper when unable to specify any object type.
148
- *
149
- * When failed to specify an object type through discrimination, full
150
- * iteration type checking would be happened. In such circumstance, you
151
- * can wrap the condition with additional function.
152
- *
153
- * @param props Properties of condition
154
- * @returns The wrapper expression
155
- */
156
- full?:
157
- | undefined
158
- | ((props: {
159
- condition: ts.Expression;
160
- input: ts.Expression;
161
- expected: string;
162
- explore: IExplore;
163
- }) => ts.Expression);
164
-
165
- /** Return type. */
166
- type?: undefined | ts.TypeNode;
167
- }
168
- export interface IGenerator {
169
- objects?:
170
- | undefined
171
- | ((collection: MetadataCollection) => ts.VariableStatement[]);
172
- unions?:
173
- | undefined
174
- | ((collection: MetadataCollection) => ts.VariableStatement[]);
175
- arrays: (collection: MetadataCollection) => ts.VariableStatement[];
176
- tuples: (collection: MetadataCollection) => ts.VariableStatement[];
177
- }
178
- }
179
-
180
- export interface IExplore {
181
- tracable: boolean;
182
- source: "top" | "function";
183
- from: "top" | "array" | "object";
184
- postfix: string;
185
- start?: undefined | number;
186
- }
187
-
188
- export type Decoder<
189
- T,
190
- Output extends ts.ConciseBody = ts.ConciseBody,
191
- > = (props: {
192
- input: ts.Expression;
193
- definition: T;
194
- explore: IExplore;
195
- }) => Output;
196
-
197
- /* -----------------------------------------------------------
198
- GENERATORS
199
- ----------------------------------------------------------- */
200
- export interface IComposed {
201
- body: ts.ConciseBody;
202
- parameters: ts.ParameterDeclaration[];
203
- functions: Record<string, ts.VariableStatement>;
204
- statements: ts.Statement[];
205
- response: ts.TypeNode;
206
- }
207
- export interface IDecomposed {
208
- functions: Record<string, ts.VariableStatement>;
209
- statements: ts.Statement[];
210
- arrow: ts.ArrowFunction;
211
- }
212
-
213
- export const compose = (props: {
214
- context: ITypiaContext;
215
- config: IConfig;
216
- functor: FunctionProgrammer;
217
- type: ts.Type;
218
- name: string | undefined;
219
- }): IComposed => {
220
- const { collection, metadata } = props.config.initializer(props);
221
- return {
222
- body: props.config.decoder({
223
- input: ValueFactory.INPUT(),
224
- metadata,
225
- explore: {
226
- tracable: props.config.path || props.config.trace,
227
- source: "top",
228
- from: "top",
229
- postfix: '""',
230
- },
231
- }),
232
- statements: props.config.addition
233
- ? props.config.addition(collection)
234
- : [],
235
- functions: {
236
- ...Object.fromEntries(
237
- (
238
- props.config.generator.objects?.(collection) ??
239
- write_object_functions({
240
- ...props,
241
- collection,
242
- })
243
- ).map((v, i) => [`${props.config.prefix}o${i}`, v]),
244
- ),
245
- ...Object.fromEntries(
246
- (
247
- props.config.generator.unions?.(collection) ??
248
- write_union_functions({
249
- config: props.config,
250
- collection,
251
- })
252
- ).map((v, i) => [`${props.config.prefix}u${i}`, v]),
253
- ),
254
- ...Object.fromEntries(
255
- props.config.generator
256
- .arrays(collection)
257
- .map((v, i) => [`${props.config.prefix}a${i}`, v]),
258
- ),
259
- ...Object.fromEntries(
260
- props.config.generator
261
- .tuples(collection)
262
- .map((v, i) => [`${props.config.prefix}t${i}`, v]),
263
- ),
264
- },
265
- parameters: parameterDeclarations({
266
- config: props.config,
267
- type: props.config.types.input(props.type, props.name),
268
- input: ValueFactory.INPUT(),
269
- }),
270
- response: props.config.types.output(props.type, props.name),
271
- };
272
- };
273
-
274
- export const writeDecomposed = (props: {
275
- modulo: ts.LeftHandSideExpression;
276
- functor: FunctionProgrammer;
277
- result: IDecomposed;
278
- returnWrapper?: (arrow: ts.ArrowFunction) => ts.Expression;
279
- }): ts.CallExpression =>
280
- ts.factory.createCallExpression(
281
- ts.factory.createArrowFunction(
282
- undefined,
283
- undefined,
284
- [],
285
- undefined,
286
- undefined,
287
- ts.factory.createBlock([
288
- ...props.functor.declare(),
289
- ...Object.entries(props.result.functions)
290
- .filter(([k]) => props.functor.hasLocal(k))
291
- .map(([_k, v]) => v),
292
- ...props.result.statements,
293
- ts.factory.createReturnStatement(
294
- props.returnWrapper
295
- ? props.returnWrapper(props.result.arrow)
296
- : props.result.arrow,
297
- ),
298
- ]),
299
- ),
300
- undefined,
301
- undefined,
302
- );
303
-
304
- export const write = (props: {
305
- context: ITypiaContext;
306
- config: IConfig;
307
- functor: FunctionProgrammer;
308
- type: ts.Type;
309
- name?: string | undefined;
310
- }): ts.ArrowFunction => {
311
- // ITERATE OVER ALL METADATA
312
- const { collection, metadata } = props.config.initializer(props);
313
- const output: ts.ConciseBody = props.config.decoder({
314
- metadata,
315
- input: ValueFactory.INPUT(),
316
- explore: {
317
- tracable: props.config.path || props.config.trace,
318
- source: "top",
319
- from: "top",
320
- postfix: '""',
321
- },
322
- });
323
-
324
- // RETURNS THE OPTIMAL ARROW FUNCTION
325
- const functions = {
326
- objects:
327
- props.config.generator.objects?.(collection) ??
328
- write_object_functions({
329
- config: props.config,
330
- context: props.context,
331
- collection,
332
- }),
333
- unions:
334
- props.config.generator.unions?.(collection) ??
335
- write_union_functions({
336
- config: props.config,
337
- collection,
338
- }),
339
- arrays: props.config.generator.arrays(collection),
340
- tuples: props.config.generator.tuples(collection),
341
- };
342
- const added: ts.Statement[] = (props.config.addition ?? (() => []))(
343
- collection,
344
- );
345
-
346
- return ts.factory.createArrowFunction(
347
- undefined,
348
- undefined,
349
- parameterDeclarations({
350
- config: props.config,
351
- type: props.config.types.input(props.type, props.name),
352
- input: ValueFactory.INPUT(),
353
- }),
354
- props.config.types.output(props.type, props.name),
355
- undefined,
356
- ts.factory.createBlock(
357
- [
358
- ...added,
359
- ...functions.objects.filter((_, i) =>
360
- props.functor.hasLocal(`${props.config.prefix}o${i}`),
361
- ),
362
- ...functions.unions.filter((_, i) =>
363
- props.functor.hasLocal(`${props.config.prefix}u${i}`),
364
- ),
365
- ...functions.arrays.filter((_, i) =>
366
- props.functor.hasLocal(`${props.config.prefix}a${i}`),
367
- ),
368
- ...functions.tuples.filter((_, i) =>
369
- props.functor.hasLocal(`${props.config.prefix}t${i}`),
370
- ),
371
- ...(ts.isBlock(output)
372
- ? output.statements
373
- : [ts.factory.createReturnStatement(output)]),
374
- ],
375
- true,
376
- ),
377
- );
378
- };
379
-
380
- export const write_object_functions = (props: {
381
- config: IConfig;
382
- context: ITypiaContext;
383
- collection: MetadataCollection;
384
- }) =>
385
- props.collection.objects().map((object) =>
386
- StatementFactory.constant({
387
- name: `${props.config.prefix}o${object.index}`,
388
- value: ts.factory.createArrowFunction(
389
- undefined,
390
- undefined,
391
- parameterDeclarations({
392
- config: props.config,
393
- type: TypeFactory.keyword("any"),
394
- input: ValueFactory.INPUT(),
395
- }),
396
- props.config.objector.type ?? TypeFactory.keyword("any"),
397
- undefined,
398
- props.config.objector.joiner({
399
- input: ts.factory.createIdentifier("input"),
400
- entries: feature_object_entries({
401
- config: props.config,
402
- context: props.context,
403
- input: ts.factory.createIdentifier("input"),
404
- object,
405
- }),
406
- object,
407
- }),
408
- ),
409
- }),
410
- );
411
-
412
- export const write_union_functions = (props: {
413
- config: IConfig;
414
- collection: MetadataCollection;
415
- }) =>
416
- props.collection.unions().map((union, i) =>
417
- StatementFactory.constant({
418
- name: `${props.config.prefix}u${i}`,
419
- value: write_union({
420
- config: props.config,
421
- objects: union,
422
- }),
423
- }),
424
- );
425
-
426
- const write_union = (props: {
427
- config: IConfig;
428
- objects: MetadataObjectType[];
429
- }) =>
430
- ts.factory.createArrowFunction(
431
- undefined,
432
- undefined,
433
- parameterDeclarations({
434
- config: props.config,
435
- type: TypeFactory.keyword("any"),
436
- input: ValueFactory.INPUT(),
437
- }),
438
- TypeFactory.keyword("any"),
439
- undefined,
440
- UnionExplorer.object({
441
- config: props.config,
442
- objects: props.objects,
443
- input: ValueFactory.INPUT(),
444
- explore: {
445
- tracable: props.config.path || props.config.trace,
446
- source: "function",
447
- from: "object",
448
- postfix: "",
449
- },
450
- }),
451
- );
452
-
453
- /* -----------------------------------------------------------
454
- DECODERS
455
- ----------------------------------------------------------- */
456
- export const decode_array = (props: {
457
- config: Pick<IConfig, "trace" | "path" | "decoder" | "prefix">;
458
- functor: FunctionProgrammer;
459
- combiner: (next: {
460
- input: ts.Expression;
461
- arrow: ts.ArrowFunction;
462
- }) => ts.Expression;
463
- array: MetadataArray;
464
- input: ts.Expression;
465
- explore: IExplore;
466
- }) => {
467
- const rand: string = props.functor.increment().toString();
468
- const tail =
469
- props.config.path || props.config.trace
470
- ? [
471
- IdentifierFactory.parameter(
472
- "_index" + rand,
473
- TypeFactory.keyword("number"),
474
- ),
475
- ]
476
- : [];
477
- const arrow: ts.ArrowFunction = ts.factory.createArrowFunction(
478
- undefined,
479
- undefined,
480
- [
481
- IdentifierFactory.parameter("elem", TypeFactory.keyword("any")),
482
- ...tail,
483
- ],
484
- undefined,
485
- undefined,
486
- props.config.decoder({
487
- input: ValueFactory.INPUT("elem"),
488
- metadata: props.array.type.value,
489
- explore: {
490
- tracable: props.explore.tracable,
491
- source: props.explore.source,
492
- from: "array",
493
- postfix: index({
494
- start: props.explore.start ?? null,
495
- postfix: props.explore.postfix,
496
- rand,
497
- }),
498
- },
499
- }),
500
- );
501
- return props.combiner({
502
- input: props.input,
503
- arrow,
504
- });
505
- };
506
-
507
- export const decode_object = (props: {
508
- config: Pick<IConfig, "trace" | "path" | "prefix">;
509
- functor: FunctionProgrammer;
510
- object: MetadataObjectType;
511
- input: ts.Expression;
512
- explore: IExplore;
513
- }) =>
514
- ts.factory.createCallExpression(
515
- ts.factory.createIdentifier(
516
- props.functor.useLocal(`${props.config.prefix}o${props.object.index}`),
517
- ),
518
- undefined,
519
- argumentsArray(props),
520
- );
521
-
522
- /* -----------------------------------------------------------
523
- UTILITIES FOR INTERNAL FUNCTIONS
524
- ----------------------------------------------------------- */
525
- export const index = (props: {
526
- start: number | null;
527
- postfix: string;
528
- rand: string;
529
- }) => {
530
- const tail: string =
531
- props.start !== null
532
- ? `"[" + (${props.start} + _index${props.rand}) + "]"`
533
- : `"[" + _index${props.rand} + "]"`;
534
- if (props.postfix === "") return tail;
535
- else if (props.postfix[props.postfix.length - 1] === `"`)
536
- return (
537
- props.postfix.substring(0, props.postfix.length - 1) + tail.substring(1)
538
- );
539
- return props.postfix + ` + ${tail}`;
540
- };
541
-
542
- export const argumentsArray = (props: {
543
- config: Pick<IConfig, "path" | "trace">;
544
- input: ts.Expression;
545
- explore: FeatureProgrammer.IExplore;
546
- }) => {
547
- const tail: ts.Expression[] =
548
- props.config.path === false && props.config.trace === false
549
- ? []
550
- : props.config.path === true && props.config.trace === true
551
- ? [
552
- ts.factory.createIdentifier(
553
- props.explore.postfix
554
- ? `_path + ${props.explore.postfix}`
555
- : "_path",
556
- ),
557
- props.explore.source === "function"
558
- ? ts.factory.createIdentifier(
559
- `${props.explore.tracable} && _exceptionable`,
560
- )
561
- : props.explore.tracable
562
- ? ts.factory.createTrue()
563
- : ts.factory.createFalse(),
564
- ]
565
- : props.config.path === true
566
- ? [
567
- ts.factory.createIdentifier(
568
- props.explore.postfix
569
- ? `_path + ${props.explore.postfix}`
570
- : "_path",
571
- ),
572
- ]
573
- : [
574
- props.explore.source === "function"
575
- ? ts.factory.createIdentifier(
576
- `${props.explore.tracable} && _exceptionable`,
577
- )
578
- : props.explore.tracable
579
- ? ts.factory.createTrue()
580
- : ts.factory.createFalse(),
581
- ];
582
- return [props.input, ...tail];
583
- };
584
-
585
- export const parameterDeclarations = (props: {
586
- config: Pick<CheckerProgrammer.IConfig, "path" | "trace">;
587
- type: ts.TypeNode;
588
- input: ts.Identifier;
589
- }) => {
590
- const tail: ts.ParameterDeclaration[] = [];
591
- if (props.config.path)
592
- tail.push(
593
- IdentifierFactory.parameter("_path", TypeFactory.keyword("string")),
594
- );
595
- if (props.config.trace)
596
- tail.push(
597
- IdentifierFactory.parameter(
598
- "_exceptionable",
599
- TypeFactory.keyword("boolean"),
600
- ts.factory.createTrue(),
601
- ),
602
- );
603
- return [IdentifierFactory.parameter(props.input, props.type), ...tail];
604
- };
605
- }
1
+ import ts from "typescript";
2
+
3
+ import { IdentifierFactory } from "../factories/IdentifierFactory";
4
+ import { MetadataCollection } from "../factories/MetadataCollection";
5
+ import { StatementFactory } from "../factories/StatementFactory";
6
+ import { TypeFactory } from "../factories/TypeFactory";
7
+ import { ValueFactory } from "../factories/ValueFactory";
8
+
9
+ import { Metadata } from "../schemas/metadata/Metadata";
10
+ import { MetadataArray } from "../schemas/metadata/MetadataArray";
11
+ import { MetadataObjectType } from "../schemas/metadata/MetadataObjectType";
12
+
13
+ import { ITypiaContext } from "../transformers/ITypiaContext";
14
+
15
+ import { CheckerProgrammer } from "./CheckerProgrammer";
16
+ import { FunctionProgrammer } from "./helpers/FunctionProgrammer";
17
+ import { IExpressionEntry } from "./helpers/IExpressionEntry";
18
+ import { UnionExplorer } from "./helpers/UnionExplorer";
19
+ import { feature_object_entries } from "./internal/feature_object_entries";
20
+
21
+ export namespace FeatureProgrammer {
22
+ /* -----------------------------------------------------------
23
+ PARAMETERS
24
+ ----------------------------------------------------------- */
25
+ export interface IConfig<Output extends ts.ConciseBody = ts.ConciseBody> {
26
+ types: IConfig.ITypes;
27
+
28
+ /** Prefix name of internal functions for specific types. */
29
+ prefix: string;
30
+
31
+ /** Whether to archive access path or not. */
32
+ path: boolean;
33
+
34
+ /** Whether to trace exception or not. */
35
+ trace: boolean;
36
+
37
+ addition?: undefined | ((collection: MetadataCollection) => ts.Statement[]);
38
+
39
+ /** Initializer of metadata. */
40
+ initializer: (props: {
41
+ context: ITypiaContext;
42
+ functor: FunctionProgrammer;
43
+ type: ts.Type;
44
+ }) => {
45
+ collection: MetadataCollection;
46
+ metadata: Metadata;
47
+ };
48
+
49
+ /** Decoder, station of every types. */
50
+ decoder: (props: {
51
+ metadata: Metadata;
52
+ input: ts.Expression;
53
+ explore: IExplore;
54
+ }) => Output;
55
+
56
+ /** Object configurator. */
57
+ objector: IConfig.IObjector<Output>;
58
+
59
+ /** Generator of functions for object types. */
60
+ generator: IConfig.IGenerator;
61
+ }
62
+ export namespace IConfig {
63
+ export interface ITypes {
64
+ input: (type: ts.Type, name?: undefined | string) => ts.TypeNode;
65
+ output: (type: ts.Type, name?: undefined | string) => ts.TypeNode;
66
+ }
67
+
68
+ export interface IObjector<Output extends ts.ConciseBody = ts.ConciseBody> {
69
+ /** Type checker when union object type comes. */
70
+ checker: (props: {
71
+ metadata: Metadata;
72
+ input: ts.Expression;
73
+ explore: IExplore;
74
+ }) => ts.Expression;
75
+
76
+ /** Decoder, function call expression generator of specific typed objects. */
77
+ decoder: (props: {
78
+ input: ts.Expression;
79
+ object: MetadataObjectType;
80
+ explore: IExplore;
81
+ }) => ts.Expression;
82
+
83
+ /** Joiner of expressions from properties. */
84
+ joiner(props: {
85
+ entries: IExpressionEntry<Output>[];
86
+ input?: ts.Expression;
87
+ object?: MetadataObjectType;
88
+ }): ts.ConciseBody;
89
+
90
+ /**
91
+ * Union type specificator.
92
+ *
93
+ * Expression of an algorithm specifying object type and calling the
94
+ * `decoder` function of the specified object type.
95
+ */
96
+ unionizer: (props: {
97
+ objects: MetadataObjectType[];
98
+ input: ts.Expression;
99
+ explore: IExplore;
100
+ }) => ts.Expression;
101
+
102
+ /**
103
+ * Handler of union type specification failure.
104
+ *
105
+ * @param props Properties of failure
106
+ * @returns Statement of failure
107
+ */
108
+ failure(props: {
109
+ input: ts.Expression;
110
+ expected: string;
111
+ explore?: undefined | IExplore;
112
+ }): ts.Statement;
113
+
114
+ /**
115
+ * Transformer of type checking expression by discrimination.
116
+ *
117
+ * When an object type has been specified by a discrimination without full
118
+ * iteration, the `unionizer` will decode the object instance after the
119
+ * last type checking.
120
+ *
121
+ * In such circumtance, you can transform the last type checking function.
122
+ *
123
+ * @deprecated
124
+ * @param exp Current expression about type checking
125
+ * @returns Transformed expression
126
+ */
127
+ is?: undefined | ((exp: ts.Expression) => ts.Expression);
128
+
129
+ /**
130
+ * Transformer of non-undefined type checking by discrimination.
131
+ *
132
+ * When specifying an union type of objects, `typia` tries to find
133
+ * discrimination way just by checking only one property type. If
134
+ * succeeded to find the discrimination way, `typia` will check the target
135
+ * property type and in the checking, non-undefined type checking would be
136
+ * done.
137
+ *
138
+ * In such process, you can transform the non-undefined type checking.
139
+ *
140
+ * @deprecated
141
+ * @param exp
142
+ * @returns Transformed expression
143
+ */
144
+ required?: undefined | ((exp: ts.Expression) => ts.Expression);
145
+
146
+ /**
147
+ * Condition wrapper when unable to specify any object type.
148
+ *
149
+ * When failed to specify an object type through discrimination, full
150
+ * iteration type checking would be happened. In such circumstance, you
151
+ * can wrap the condition with additional function.
152
+ *
153
+ * @param props Properties of condition
154
+ * @returns The wrapper expression
155
+ */
156
+ full?:
157
+ | undefined
158
+ | ((props: {
159
+ condition: ts.Expression;
160
+ input: ts.Expression;
161
+ expected: string;
162
+ explore: IExplore;
163
+ }) => ts.Expression);
164
+
165
+ /** Return type. */
166
+ type?: undefined | ts.TypeNode;
167
+ }
168
+ export interface IGenerator {
169
+ objects?:
170
+ | undefined
171
+ | ((collection: MetadataCollection) => ts.VariableStatement[]);
172
+ unions?:
173
+ | undefined
174
+ | ((collection: MetadataCollection) => ts.VariableStatement[]);
175
+ arrays: (collection: MetadataCollection) => ts.VariableStatement[];
176
+ tuples: (collection: MetadataCollection) => ts.VariableStatement[];
177
+ }
178
+ }
179
+
180
+ export interface IExplore {
181
+ tracable: boolean;
182
+ source: "top" | "function";
183
+ from: "top" | "array" | "object";
184
+ postfix: string;
185
+ start?: undefined | number;
186
+ }
187
+
188
+ export type Decoder<
189
+ T,
190
+ Output extends ts.ConciseBody = ts.ConciseBody,
191
+ > = (props: {
192
+ input: ts.Expression;
193
+ definition: T;
194
+ explore: IExplore;
195
+ }) => Output;
196
+
197
+ /* -----------------------------------------------------------
198
+ GENERATORS
199
+ ----------------------------------------------------------- */
200
+ export interface IComposed {
201
+ body: ts.ConciseBody;
202
+ parameters: ts.ParameterDeclaration[];
203
+ functions: Record<string, ts.VariableStatement>;
204
+ statements: ts.Statement[];
205
+ response: ts.TypeNode;
206
+ }
207
+ export interface IDecomposed {
208
+ functions: Record<string, ts.VariableStatement>;
209
+ statements: ts.Statement[];
210
+ arrow: ts.ArrowFunction;
211
+ }
212
+
213
+ export const compose = (props: {
214
+ context: ITypiaContext;
215
+ config: IConfig;
216
+ functor: FunctionProgrammer;
217
+ type: ts.Type;
218
+ name: string | undefined;
219
+ }): IComposed => {
220
+ const { collection, metadata } = props.config.initializer(props);
221
+ return {
222
+ body: props.config.decoder({
223
+ input: ValueFactory.INPUT(),
224
+ metadata,
225
+ explore: {
226
+ tracable: props.config.path || props.config.trace,
227
+ source: "top",
228
+ from: "top",
229
+ postfix: '""',
230
+ },
231
+ }),
232
+ statements: props.config.addition
233
+ ? props.config.addition(collection)
234
+ : [],
235
+ functions: {
236
+ ...Object.fromEntries(
237
+ (
238
+ props.config.generator.objects?.(collection) ??
239
+ write_object_functions({
240
+ ...props,
241
+ collection,
242
+ })
243
+ ).map((v, i) => [`${props.config.prefix}o${i}`, v]),
244
+ ),
245
+ ...Object.fromEntries(
246
+ (
247
+ props.config.generator.unions?.(collection) ??
248
+ write_union_functions({
249
+ config: props.config,
250
+ collection,
251
+ })
252
+ ).map((v, i) => [`${props.config.prefix}u${i}`, v]),
253
+ ),
254
+ ...Object.fromEntries(
255
+ props.config.generator
256
+ .arrays(collection)
257
+ .map((v, i) => [`${props.config.prefix}a${i}`, v]),
258
+ ),
259
+ ...Object.fromEntries(
260
+ props.config.generator
261
+ .tuples(collection)
262
+ .map((v, i) => [`${props.config.prefix}t${i}`, v]),
263
+ ),
264
+ },
265
+ parameters: parameterDeclarations({
266
+ config: props.config,
267
+ type: props.config.types.input(props.type, props.name),
268
+ input: ValueFactory.INPUT(),
269
+ }),
270
+ response: props.config.types.output(props.type, props.name),
271
+ };
272
+ };
273
+
274
+ export const writeDecomposed = (props: {
275
+ modulo: ts.LeftHandSideExpression;
276
+ functor: FunctionProgrammer;
277
+ result: IDecomposed;
278
+ returnWrapper?: (arrow: ts.ArrowFunction) => ts.Expression;
279
+ }): ts.CallExpression =>
280
+ ts.factory.createCallExpression(
281
+ ts.factory.createArrowFunction(
282
+ undefined,
283
+ undefined,
284
+ [],
285
+ undefined,
286
+ undefined,
287
+ ts.factory.createBlock([
288
+ ...props.functor.declare(),
289
+ ...Object.entries(props.result.functions)
290
+ .filter(([k]) => props.functor.hasLocal(k))
291
+ .map(([_k, v]) => v),
292
+ ...props.result.statements,
293
+ ts.factory.createReturnStatement(
294
+ props.returnWrapper
295
+ ? props.returnWrapper(props.result.arrow)
296
+ : props.result.arrow,
297
+ ),
298
+ ]),
299
+ ),
300
+ undefined,
301
+ undefined,
302
+ );
303
+
304
+ export const write = (props: {
305
+ context: ITypiaContext;
306
+ config: IConfig;
307
+ functor: FunctionProgrammer;
308
+ type: ts.Type;
309
+ name?: string | undefined;
310
+ }): ts.ArrowFunction => {
311
+ // ITERATE OVER ALL METADATA
312
+ const { collection, metadata } = props.config.initializer(props);
313
+ const output: ts.ConciseBody = props.config.decoder({
314
+ metadata,
315
+ input: ValueFactory.INPUT(),
316
+ explore: {
317
+ tracable: props.config.path || props.config.trace,
318
+ source: "top",
319
+ from: "top",
320
+ postfix: '""',
321
+ },
322
+ });
323
+
324
+ // RETURNS THE OPTIMAL ARROW FUNCTION
325
+ const functions = {
326
+ objects:
327
+ props.config.generator.objects?.(collection) ??
328
+ write_object_functions({
329
+ config: props.config,
330
+ context: props.context,
331
+ collection,
332
+ }),
333
+ unions:
334
+ props.config.generator.unions?.(collection) ??
335
+ write_union_functions({
336
+ config: props.config,
337
+ collection,
338
+ }),
339
+ arrays: props.config.generator.arrays(collection),
340
+ tuples: props.config.generator.tuples(collection),
341
+ };
342
+ const added: ts.Statement[] = (props.config.addition ?? (() => []))(
343
+ collection,
344
+ );
345
+
346
+ return ts.factory.createArrowFunction(
347
+ undefined,
348
+ undefined,
349
+ parameterDeclarations({
350
+ config: props.config,
351
+ type: props.config.types.input(props.type, props.name),
352
+ input: ValueFactory.INPUT(),
353
+ }),
354
+ props.config.types.output(props.type, props.name),
355
+ undefined,
356
+ ts.factory.createBlock(
357
+ [
358
+ ...added,
359
+ ...functions.objects.filter((_, i) =>
360
+ props.functor.hasLocal(`${props.config.prefix}o${i}`),
361
+ ),
362
+ ...functions.unions.filter((_, i) =>
363
+ props.functor.hasLocal(`${props.config.prefix}u${i}`),
364
+ ),
365
+ ...functions.arrays.filter((_, i) =>
366
+ props.functor.hasLocal(`${props.config.prefix}a${i}`),
367
+ ),
368
+ ...functions.tuples.filter((_, i) =>
369
+ props.functor.hasLocal(`${props.config.prefix}t${i}`),
370
+ ),
371
+ ...(ts.isBlock(output)
372
+ ? output.statements
373
+ : [ts.factory.createReturnStatement(output)]),
374
+ ],
375
+ true,
376
+ ),
377
+ );
378
+ };
379
+
380
+ export const write_object_functions = (props: {
381
+ config: IConfig;
382
+ context: ITypiaContext;
383
+ collection: MetadataCollection;
384
+ }) =>
385
+ props.collection.objects().map((object) =>
386
+ StatementFactory.constant({
387
+ name: `${props.config.prefix}o${object.index}`,
388
+ value: ts.factory.createArrowFunction(
389
+ undefined,
390
+ undefined,
391
+ parameterDeclarations({
392
+ config: props.config,
393
+ type: TypeFactory.keyword("any"),
394
+ input: ValueFactory.INPUT(),
395
+ }),
396
+ props.config.objector.type ?? TypeFactory.keyword("any"),
397
+ undefined,
398
+ props.config.objector.joiner({
399
+ input: ts.factory.createIdentifier("input"),
400
+ entries: feature_object_entries({
401
+ config: props.config,
402
+ context: props.context,
403
+ input: ts.factory.createIdentifier("input"),
404
+ object,
405
+ }),
406
+ object,
407
+ }),
408
+ ),
409
+ }),
410
+ );
411
+
412
+ export const write_union_functions = (props: {
413
+ config: IConfig;
414
+ collection: MetadataCollection;
415
+ }) =>
416
+ props.collection.unions().map((union, i) =>
417
+ StatementFactory.constant({
418
+ name: `${props.config.prefix}u${i}`,
419
+ value: write_union({
420
+ config: props.config,
421
+ objects: union,
422
+ }),
423
+ }),
424
+ );
425
+
426
+ const write_union = (props: {
427
+ config: IConfig;
428
+ objects: MetadataObjectType[];
429
+ }) =>
430
+ ts.factory.createArrowFunction(
431
+ undefined,
432
+ undefined,
433
+ parameterDeclarations({
434
+ config: props.config,
435
+ type: TypeFactory.keyword("any"),
436
+ input: ValueFactory.INPUT(),
437
+ }),
438
+ TypeFactory.keyword("any"),
439
+ undefined,
440
+ UnionExplorer.object({
441
+ config: props.config,
442
+ objects: props.objects,
443
+ input: ValueFactory.INPUT(),
444
+ explore: {
445
+ tracable: props.config.path || props.config.trace,
446
+ source: "function",
447
+ from: "object",
448
+ postfix: "",
449
+ },
450
+ }),
451
+ );
452
+
453
+ /* -----------------------------------------------------------
454
+ DECODERS
455
+ ----------------------------------------------------------- */
456
+ export const decode_array = (props: {
457
+ config: Pick<IConfig, "trace" | "path" | "decoder" | "prefix">;
458
+ functor: FunctionProgrammer;
459
+ combiner: (next: {
460
+ input: ts.Expression;
461
+ arrow: ts.ArrowFunction;
462
+ }) => ts.Expression;
463
+ array: MetadataArray;
464
+ input: ts.Expression;
465
+ explore: IExplore;
466
+ }) => {
467
+ const rand: string = props.functor.increment().toString();
468
+ const tail =
469
+ props.config.path || props.config.trace
470
+ ? [
471
+ IdentifierFactory.parameter(
472
+ "_index" + rand,
473
+ TypeFactory.keyword("number"),
474
+ ),
475
+ ]
476
+ : [];
477
+ const arrow: ts.ArrowFunction = ts.factory.createArrowFunction(
478
+ undefined,
479
+ undefined,
480
+ [
481
+ IdentifierFactory.parameter("elem", TypeFactory.keyword("any")),
482
+ ...tail,
483
+ ],
484
+ undefined,
485
+ undefined,
486
+ props.config.decoder({
487
+ input: ValueFactory.INPUT("elem"),
488
+ metadata: props.array.type.value,
489
+ explore: {
490
+ tracable: props.explore.tracable,
491
+ source: props.explore.source,
492
+ from: "array",
493
+ postfix: index({
494
+ start: props.explore.start ?? null,
495
+ postfix: props.explore.postfix,
496
+ rand,
497
+ }),
498
+ },
499
+ }),
500
+ );
501
+ return props.combiner({
502
+ input: props.input,
503
+ arrow,
504
+ });
505
+ };
506
+
507
+ export const decode_object = (props: {
508
+ config: Pick<IConfig, "trace" | "path" | "prefix">;
509
+ functor: FunctionProgrammer;
510
+ object: MetadataObjectType;
511
+ input: ts.Expression;
512
+ explore: IExplore;
513
+ }) =>
514
+ ts.factory.createCallExpression(
515
+ ts.factory.createIdentifier(
516
+ props.functor.useLocal(`${props.config.prefix}o${props.object.index}`),
517
+ ),
518
+ undefined,
519
+ argumentsArray(props),
520
+ );
521
+
522
+ /* -----------------------------------------------------------
523
+ UTILITIES FOR INTERNAL FUNCTIONS
524
+ ----------------------------------------------------------- */
525
+ export const index = (props: {
526
+ start: number | null;
527
+ postfix: string;
528
+ rand: string;
529
+ }) => {
530
+ const tail: string =
531
+ props.start !== null
532
+ ? `"[" + (${props.start} + _index${props.rand}) + "]"`
533
+ : `"[" + _index${props.rand} + "]"`;
534
+ if (props.postfix === "") return tail;
535
+ else if (props.postfix[props.postfix.length - 1] === `"`)
536
+ return (
537
+ props.postfix.substring(0, props.postfix.length - 1) + tail.substring(1)
538
+ );
539
+ return props.postfix + ` + ${tail}`;
540
+ };
541
+
542
+ export const argumentsArray = (props: {
543
+ config: Pick<IConfig, "path" | "trace">;
544
+ input: ts.Expression;
545
+ explore: FeatureProgrammer.IExplore;
546
+ }) => {
547
+ const tail: ts.Expression[] =
548
+ props.config.path === false && props.config.trace === false
549
+ ? []
550
+ : props.config.path === true && props.config.trace === true
551
+ ? [
552
+ ts.factory.createIdentifier(
553
+ props.explore.postfix
554
+ ? `_path + ${props.explore.postfix}`
555
+ : "_path",
556
+ ),
557
+ props.explore.source === "function"
558
+ ? ts.factory.createIdentifier(
559
+ `${props.explore.tracable} && _exceptionable`,
560
+ )
561
+ : props.explore.tracable
562
+ ? ts.factory.createTrue()
563
+ : ts.factory.createFalse(),
564
+ ]
565
+ : props.config.path === true
566
+ ? [
567
+ ts.factory.createIdentifier(
568
+ props.explore.postfix
569
+ ? `_path + ${props.explore.postfix}`
570
+ : "_path",
571
+ ),
572
+ ]
573
+ : [
574
+ props.explore.source === "function"
575
+ ? ts.factory.createIdentifier(
576
+ `${props.explore.tracable} && _exceptionable`,
577
+ )
578
+ : props.explore.tracable
579
+ ? ts.factory.createTrue()
580
+ : ts.factory.createFalse(),
581
+ ];
582
+ return [props.input, ...tail];
583
+ };
584
+
585
+ export const parameterDeclarations = (props: {
586
+ config: Pick<CheckerProgrammer.IConfig, "path" | "trace">;
587
+ type: ts.TypeNode;
588
+ input: ts.Identifier;
589
+ }) => {
590
+ const tail: ts.ParameterDeclaration[] = [];
591
+ if (props.config.path)
592
+ tail.push(
593
+ IdentifierFactory.parameter("_path", TypeFactory.keyword("string")),
594
+ );
595
+ if (props.config.trace)
596
+ tail.push(
597
+ IdentifierFactory.parameter(
598
+ "_exceptionable",
599
+ TypeFactory.keyword("boolean"),
600
+ ts.factory.createTrue(),
601
+ ),
602
+ );
603
+ return [IdentifierFactory.parameter(props.input, props.type), ...tail];
604
+ };
605
+ }