typia 6.7.0 → 6.7.1

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 (85) hide show
  1. package/lib/programmers/AssertProgrammer.d.ts +0 -1
  2. package/lib/programmers/AssertProgrammer.js.map +1 -1
  3. package/lib/programmers/CheckerProgrammer.d.ts +1 -1
  4. package/lib/programmers/FeatureProgrammer.d.ts +1 -1
  5. package/lib/programmers/IsProgrammer.d.ts +1 -1
  6. package/lib/programmers/RandomProgrammer.d.ts +10 -1
  7. package/lib/programmers/RandomProgrammer.js +62 -37
  8. package/lib/programmers/RandomProgrammer.js.map +1 -1
  9. package/lib/programmers/ValidateProgrammer.d.ts +1 -1
  10. package/lib/programmers/json/JsonIsParseProgrammer.d.ts +1 -1
  11. package/lib/programmers/json/JsonIsStringifyProgrammer.d.ts +1 -1
  12. package/lib/programmers/json/JsonStringifyProgrammer.d.ts +1 -1
  13. package/lib/programmers/json/JsonStringifyProgrammer.js +1 -3
  14. package/lib/programmers/json/JsonStringifyProgrammer.js.map +1 -1
  15. package/lib/programmers/json/JsonValidateParseProgrammer.d.ts +1 -1
  16. package/lib/programmers/json/JsonValidateStringifyProgrammer.d.ts +1 -1
  17. package/lib/programmers/misc/MiscCloneProgrammer.d.ts +1 -1
  18. package/lib/programmers/misc/MiscCloneProgrammer.js +33 -14
  19. package/lib/programmers/misc/MiscCloneProgrammer.js.map +1 -1
  20. package/lib/programmers/misc/MiscIsCloneProgrammer.d.ts +1 -1
  21. package/lib/programmers/misc/MiscIsPruneProgrammer.d.ts +1 -1
  22. package/lib/programmers/misc/MiscPruneProgrammer.d.ts +1 -1
  23. package/lib/programmers/misc/MiscValidateCloneProgrammer.d.ts +1 -1
  24. package/lib/programmers/misc/MiscValidatePruneProgrammer.d.ts +1 -1
  25. package/lib/programmers/notations/NotationGeneralProgrammer.d.ts +1 -1
  26. package/lib/programmers/notations/NotationGeneralProgrammer.js +30 -11
  27. package/lib/programmers/notations/NotationGeneralProgrammer.js.map +1 -1
  28. package/lib/programmers/notations/NotationValidateGeneralProgrammer.d.ts +1 -1
  29. package/package.json +1 -1
  30. package/src/programmers/AssertProgrammer.ts +397 -398
  31. package/src/programmers/CheckerProgrammer.ts +1138 -1138
  32. package/src/programmers/FeatureProgrammer.ts +549 -549
  33. package/src/programmers/IsProgrammer.ts +1 -1
  34. package/src/programmers/RandomProgrammer.ts +112 -77
  35. package/src/programmers/ValidateProgrammer.ts +382 -382
  36. package/src/programmers/functional/FunctionalAssertFunctionProgrammer.ts +141 -141
  37. package/src/programmers/functional/FunctionalAssertParametersProgrammer.ts +108 -108
  38. package/src/programmers/functional/FunctionalAssertReturnProgrammer.ts +98 -98
  39. package/src/programmers/functional/FunctionalIsFunctionProgrammer.ts +72 -72
  40. package/src/programmers/functional/FunctionalIsParametersProgrammer.ts +101 -101
  41. package/src/programmers/functional/FunctionalIsReturnProgrammer.ts +106 -106
  42. package/src/programmers/functional/FunctionalValidateFunctionProgrammer.ts +123 -123
  43. package/src/programmers/functional/FunctionalValidateParametersProgrammer.ts +267 -267
  44. package/src/programmers/functional/FunctionalValidateReturnProgrammer.ts +126 -126
  45. package/src/programmers/helpers/FunctionImporter.ts +97 -97
  46. package/src/programmers/http/HttpAssertFormDataProgrammer.ts +91 -91
  47. package/src/programmers/http/HttpAssertHeadersProgrammer.ts +91 -91
  48. package/src/programmers/http/HttpAssertQueryProgrammer.ts +93 -93
  49. package/src/programmers/http/HttpFormDataProgrammer.ts +278 -278
  50. package/src/programmers/http/HttpHeadersProgrammer.ts +347 -347
  51. package/src/programmers/http/HttpIsFormDataProgrammer.ts +102 -102
  52. package/src/programmers/http/HttpIsHeadersProgrammer.ts +102 -102
  53. package/src/programmers/http/HttpIsQueryProgrammer.ts +104 -104
  54. package/src/programmers/http/HttpQueryProgrammer.ts +298 -298
  55. package/src/programmers/http/HttpValidateFormDataProgrammer.ts +85 -85
  56. package/src/programmers/http/HttpValidateHeadersProgrammer.ts +85 -85
  57. package/src/programmers/http/HttpValidateQueryProgrammer.ts +87 -87
  58. package/src/programmers/json/JsonAssertParseProgrammer.ts +96 -96
  59. package/src/programmers/json/JsonAssertStringifyProgrammer.ts +104 -104
  60. package/src/programmers/json/JsonIsParseProgrammer.ts +110 -110
  61. package/src/programmers/json/JsonIsStringifyProgrammer.ts +102 -102
  62. package/src/programmers/json/JsonStringifyProgrammer.ts +909 -910
  63. package/src/programmers/json/JsonValidateParseProgrammer.ts +87 -87
  64. package/src/programmers/json/JsonValidateStringifyProgrammer.ts +111 -111
  65. package/src/programmers/misc/MiscAssertCloneProgrammer.ts +87 -87
  66. package/src/programmers/misc/MiscAssertPruneProgrammer.ts +87 -87
  67. package/src/programmers/misc/MiscCloneProgrammer.ts +781 -759
  68. package/src/programmers/misc/MiscIsCloneProgrammer.ts +93 -93
  69. package/src/programmers/misc/MiscIsPruneProgrammer.ts +94 -94
  70. package/src/programmers/misc/MiscPruneProgrammer.ts +560 -560
  71. package/src/programmers/misc/MiscValidateCloneProgrammer.ts +104 -104
  72. package/src/programmers/misc/MiscValidatePruneProgrammer.ts +98 -98
  73. package/src/programmers/notations/NotationAssertGeneralProgrammer.ts +91 -91
  74. package/src/programmers/notations/NotationGeneralProgrammer.ts +709 -685
  75. package/src/programmers/notations/NotationIsGeneralProgrammer.ts +97 -97
  76. package/src/programmers/notations/NotationValidateGeneralProgrammer.ts +107 -107
  77. package/src/programmers/protobuf/ProtobufAssertDecodeProgrammer.ts +91 -91
  78. package/src/programmers/protobuf/ProtobufAssertEncodeProgrammer.ts +95 -95
  79. package/src/programmers/protobuf/ProtobufDecodeProgrammer.ts +646 -646
  80. package/src/programmers/protobuf/ProtobufEncodeProgrammer.ts +852 -852
  81. package/src/programmers/protobuf/ProtobufIsDecodeProgrammer.ts +104 -104
  82. package/src/programmers/protobuf/ProtobufIsEncodeProgrammer.ts +93 -93
  83. package/src/programmers/protobuf/ProtobufValidateDecodeProgrammer.ts +85 -85
  84. package/src/programmers/protobuf/ProtobufValidateEncodeProgrammer.ts +109 -109
  85. package/src/transformers/internal/GenericTransformer.ts +104 -104
@@ -1,1138 +1,1138 @@
1
- import ts from "typescript";
2
-
3
- import { ExpressionFactory } from "../factories/ExpressionFactory";
4
- import { IdentifierFactory } from "../factories/IdentifierFactory";
5
- import { MetadataCollection } from "../factories/MetadataCollection";
6
- import { MetadataFactory } from "../factories/MetadataFactory";
7
- import { StatementFactory } from "../factories/StatementFactory";
8
- import { TypeFactory } from "../factories/TypeFactory";
9
- import { ValueFactory } from "../factories/ValueFactory";
10
-
11
- import { Metadata } from "../schemas/metadata/Metadata";
12
- import { MetadataArray } from "../schemas/metadata/MetadataArray";
13
- import { MetadataConstant } from "../schemas/metadata/MetadataConstant";
14
- import { MetadataObject } from "../schemas/metadata/MetadataObject";
15
- import { MetadataTuple } from "../schemas/metadata/MetadataTuple";
16
- import { MetadataTupleType } from "../schemas/metadata/MetadataTupleType";
17
-
18
- import { IProject } from "../transformers/IProject";
19
- import { TransformerError } from "../transformers/TransformerError";
20
-
21
- import { FeatureProgrammer } from "./FeatureProgrammer";
22
- import { IsProgrammer } from "./IsProgrammer";
23
- import { AtomicPredicator } from "./helpers/AtomicPredicator";
24
- import { FunctionImporter } from "./helpers/FunctionImporter";
25
- import { ICheckEntry } from "./helpers/ICheckEntry";
26
- import { IExpressionEntry } from "./helpers/IExpressionEntry";
27
- import { OptionPredicator } from "./helpers/OptionPredicator";
28
- import { UnionExplorer } from "./helpers/UnionExplorer";
29
- import { check_array_length } from "./internal/check_array_length";
30
- import { check_bigint } from "./internal/check_bigint";
31
- import { check_native } from "./internal/check_native";
32
- import { check_number } from "./internal/check_number";
33
- import { check_string } from "./internal/check_string";
34
- import { check_template } from "./internal/check_template";
35
- import { decode_union_object } from "./internal/decode_union_object";
36
- import { postfix_of_tuple } from "./internal/postfix_of_tuple";
37
- import { wrap_metadata_rest_tuple } from "./internal/wrap_metadata_rest_tuple";
38
-
39
- export namespace CheckerProgrammer {
40
- export interface IConfig {
41
- prefix: string;
42
- path: boolean;
43
- trace: boolean;
44
- equals: boolean;
45
- numeric: boolean;
46
- addition?: () => ts.Statement[];
47
- decoder?: () => FeatureProgrammer.Decoder<Metadata, ts.Expression>;
48
- combiner: IConfig.Combiner;
49
- atomist: (
50
- explore: IExplore,
51
- ) => (check: ICheckEntry) => (input: ts.Expression) => ts.Expression;
52
- joiner: IConfig.IJoiner;
53
- success: ts.Expression;
54
- }
55
- export namespace IConfig {
56
- export interface Combiner {
57
- (explorer: IExplore): {
58
- (logic: "and" | "or"): {
59
- (
60
- input: ts.Expression,
61
- binaries: IBinary[],
62
- expected: string,
63
- ): ts.Expression;
64
- };
65
- };
66
- }
67
- export interface IJoiner {
68
- object(input: ts.Expression, entries: IExpressionEntry[]): ts.Expression;
69
- array(input: ts.Expression, arrow: ts.ArrowFunction): ts.Expression;
70
- tuple?: undefined | ((exprs: ts.Expression[]) => ts.Expression);
71
-
72
- failure(
73
- value: ts.Expression,
74
- expected: string,
75
- explore?: undefined | FeatureProgrammer.IExplore,
76
- ): ts.Expression;
77
- is?(expression: ts.Expression): ts.Expression;
78
- required?(exp: ts.Expression): ts.Expression;
79
- full?:
80
- | undefined
81
- | ((
82
- condition: ts.Expression,
83
- ) => (
84
- input: ts.Expression,
85
- expected: string,
86
- explore: IExplore,
87
- ) => ts.Expression);
88
- }
89
- }
90
- export type IExplore = FeatureProgrammer.IExplore;
91
-
92
- export interface IBinary {
93
- expression: ts.Expression;
94
- combined: boolean;
95
- }
96
-
97
- /* -----------------------------------------------------------
98
- WRITERS
99
- ----------------------------------------------------------- */
100
- export const compose = (props: {
101
- project: IProject;
102
- config: IConfig;
103
- importer: FunctionImporter;
104
- type: ts.Type;
105
- name?: string;
106
- }) =>
107
- FeatureProgrammer.compose({
108
- ...props,
109
- config: configure(props.project)(props.config)(props.importer),
110
- });
111
-
112
- export const write =
113
- (project: IProject) => (config: IConfig) => (importer: FunctionImporter) =>
114
- FeatureProgrammer.write(project)(configure(project)(config)(importer))(
115
- importer,
116
- );
117
-
118
- export const write_object_functions =
119
- (project: IProject) => (config: IConfig) => (importer: FunctionImporter) =>
120
- FeatureProgrammer.write_object_functions(
121
- configure(project)(config)(importer),
122
- )(importer);
123
-
124
- export const write_union_functions =
125
- (project: IProject) => (config: IConfig) => (importer: FunctionImporter) =>
126
- FeatureProgrammer.write_union_functions(
127
- configure(project)({ ...config, numeric: false })(importer),
128
- );
129
-
130
- export const write_array_functions =
131
- (project: IProject) =>
132
- (config: IConfig) =>
133
- (importer: FunctionImporter) =>
134
- (collection: MetadataCollection): ts.VariableStatement[] =>
135
- collection
136
- .arrays()
137
- .filter((a) => a.recursive)
138
- .map((type, i) =>
139
- StatementFactory.constant(
140
- `${config.prefix}a${i}`,
141
- ts.factory.createArrowFunction(
142
- undefined,
143
- undefined,
144
- FeatureProgrammer.parameterDeclarations(config)(
145
- TypeFactory.keyword("any"),
146
- )(ts.factory.createIdentifier("input")),
147
- TypeFactory.keyword("any"),
148
- undefined,
149
- decode_array_inline(project)(config)(importer)(
150
- ts.factory.createIdentifier("input"),
151
- MetadataArray.create({
152
- type,
153
- tags: [],
154
- }),
155
- {
156
- tracable: config.trace,
157
- source: "function",
158
- from: "array",
159
- postfix: "",
160
- },
161
- ),
162
- ),
163
- ),
164
- );
165
-
166
- export const write_tuple_functions =
167
- (project: IProject) =>
168
- (config: IConfig) =>
169
- (importer: FunctionImporter) =>
170
- (collection: MetadataCollection): ts.VariableStatement[] =>
171
- collection
172
- .tuples()
173
- .filter((t) => t.recursive)
174
- .map((tuple, i) =>
175
- StatementFactory.constant(
176
- `${config.prefix}t${i}`,
177
- ts.factory.createArrowFunction(
178
- undefined,
179
- undefined,
180
- FeatureProgrammer.parameterDeclarations(config)(
181
- TypeFactory.keyword("any"),
182
- )(ts.factory.createIdentifier("input")),
183
- TypeFactory.keyword("any"),
184
- undefined,
185
- decode_tuple_inline(project)(config)(importer)(
186
- ts.factory.createIdentifier("input"),
187
- tuple,
188
- {
189
- tracable: config.trace,
190
- source: "function",
191
- from: "array",
192
- postfix: "",
193
- },
194
- ),
195
- ),
196
- ),
197
- );
198
-
199
- const configure =
200
- (project: IProject) =>
201
- (config: IConfig) =>
202
- (importer: FunctionImporter): FeatureProgrammer.IConfig => ({
203
- types: {
204
- input: () => TypeFactory.keyword("any"),
205
- output: (type, name) =>
206
- ts.factory.createTypePredicateNode(
207
- undefined,
208
- "input",
209
- ts.factory.createTypeReferenceNode(
210
- name ?? TypeFactory.getFullName(project.checker)(type),
211
- ),
212
- ),
213
- },
214
- trace: config.trace,
215
- path: config.path,
216
- prefix: config.prefix,
217
- initializer: (project) => (importer) => (type) => {
218
- const collection: MetadataCollection = new MetadataCollection();
219
- const result = MetadataFactory.analyze(
220
- project.checker,
221
- project.context,
222
- )({
223
- escape: false,
224
- constant: true,
225
- absorb: true,
226
- })(collection)(type);
227
- if (result.success === false)
228
- throw TransformerError.from(`typia.${importer.method}`)(
229
- result.errors,
230
- );
231
- return [collection, result.data];
232
- },
233
- addition: config.addition,
234
- decoder: () => config.decoder?.() ?? decode(project)(config)(importer),
235
- objector: {
236
- checker: () => config.decoder?.() ?? decode(project)(config)(importer),
237
- decoder: () => decode_object(config)(importer),
238
- joiner: config.joiner.object,
239
- unionizer: config.equals
240
- ? decode_union_object(decode_object(config)(importer))(
241
- (input, obj, explore) =>
242
- decode_object(config)(importer)(input, obj, {
243
- ...explore,
244
- tracable: true,
245
- }),
246
- )(config.joiner.is ?? ((expr) => expr))((value, expected) =>
247
- ts.factory.createReturnStatement(
248
- config.joiner.failure(value, expected),
249
- ),
250
- )
251
- : (input, targets, explore) =>
252
- config.combiner(explore)("or")(
253
- input,
254
- targets.map((obj) => ({
255
- expression: decode_object(config)(importer)(
256
- input,
257
- obj,
258
- explore,
259
- ),
260
- combined: true,
261
- })),
262
- `(${targets.map((t) => t.name).join(" | ")})`,
263
- ),
264
- failure: (value, expected) =>
265
- ts.factory.createReturnStatement(
266
- config.joiner.failure(value, expected),
267
- ),
268
- is: config.joiner.is,
269
- required: config.joiner.required,
270
- full: config.joiner.full,
271
- type: TypeFactory.keyword("boolean"),
272
- },
273
- generator: {
274
- unions: config.numeric
275
- ? () =>
276
- FeatureProgrammer.write_union_functions(
277
- configure(project)({ ...config, numeric: false })(importer),
278
- )
279
- : undefined,
280
- arrays: () => write_array_functions(project)(config)(importer),
281
- tuples: () => write_tuple_functions(project)(config)(importer),
282
- },
283
- });
284
-
285
- /* -----------------------------------------------------------
286
- DECODERS
287
- ----------------------------------------------------------- */
288
- /**
289
- * @internal
290
- */
291
- export const decode =
292
- (project: IProject) =>
293
- (config: IConfig) =>
294
- (importer: FunctionImporter) =>
295
- (
296
- input: ts.Expression,
297
- meta: Metadata,
298
- explore: IExplore,
299
- ): ts.Expression => {
300
- if (meta.any) return config.success;
301
-
302
- const top: IBinary[] = [];
303
- const binaries: IBinary[] = [];
304
- const add = create_add(binaries)(input);
305
- const getConstantValue = (value: number | string | bigint | boolean) => {
306
- if (typeof value === "string")
307
- return ts.factory.createStringLiteral(value);
308
- else if (typeof value === "bigint")
309
- return ExpressionFactory.bigint(value);
310
- return ts.factory.createIdentifier(value.toString());
311
- };
312
-
313
- //----
314
- // CHECK OPTIONAL
315
- //----
316
- // @todo -> should be elaborated
317
- const checkOptional: boolean = meta.empty() || meta.isUnionBucket();
318
-
319
- // NULLABLE
320
- if (checkOptional || meta.nullable)
321
- (meta.nullable ? add : create_add(top)(input))(
322
- meta.nullable,
323
- ValueFactory.NULL(),
324
- );
325
-
326
- // UNDEFINDABLE
327
- if (checkOptional || !meta.isRequired())
328
- (meta.isRequired() ? create_add(top)(input) : add)(
329
- !meta.isRequired(),
330
- ValueFactory.UNDEFINED(),
331
- );
332
-
333
- // FUNCTIONAL
334
- if (meta.functional === true)
335
- if (OptionPredicator.functional(project.options) || meta.size() !== 1)
336
- add(
337
- true,
338
- ts.factory.createStringLiteral("function"),
339
- ValueFactory.TYPEOF(input),
340
- );
341
- else
342
- binaries.push({
343
- combined: false,
344
- expression: config.success,
345
- });
346
-
347
- //----
348
- // VALUES
349
- //----
350
- // CONSTANT VALUES
351
- const constants: MetadataConstant[] = meta.constants.filter((c) =>
352
- AtomicPredicator.constant(meta)(c.type),
353
- );
354
- const constantLength: number = constants
355
- .map((c) => c.values.length)
356
- .reduce((a, b) => a + b, 0);
357
- if (constantLength >= 10) {
358
- const values: Array<boolean | number | string | bigint> = constants
359
- .map((c) => c.values.map((v) => v.value))
360
- .flat();
361
- add(
362
- true,
363
- ts.factory.createTrue(),
364
- ts.factory.createCallExpression(
365
- IdentifierFactory.access(
366
- importer.emplaceVariable(
367
- `${config.prefix}v${importer.increment()}`,
368
- ts.factory.createNewExpression(
369
- ts.factory.createIdentifier("Set"),
370
- undefined,
371
- [
372
- ts.factory.createArrayLiteralExpression(
373
- values.map((v) =>
374
- typeof v === "boolean"
375
- ? v === true
376
- ? ts.factory.createTrue()
377
- : ts.factory.createFalse()
378
- : typeof v === "bigint"
379
- ? ExpressionFactory.bigint(v)
380
- : typeof v === "number"
381
- ? ExpressionFactory.number(v)
382
- : ts.factory.createStringLiteral(v.toString()),
383
- ),
384
- ),
385
- ],
386
- ),
387
- ),
388
- )("has"),
389
- undefined,
390
- [input],
391
- ),
392
- );
393
- } else
394
- for (const c of constants)
395
- if (AtomicPredicator.constant(meta)(c.type))
396
- for (const v of c.values) add(true, getConstantValue(v.value));
397
-
398
- // ATOMIC VALUES
399
- for (const atom of meta.atomics)
400
- if (AtomicPredicator.atomic(meta)(atom.type) === false) continue;
401
- else if (atom.type === "number")
402
- binaries.push({
403
- expression: config.atomist(explore)(
404
- check_number(project, config.numeric)(atom)(input),
405
- )(input),
406
- combined: false,
407
- });
408
- else if (atom.type === "bigint")
409
- binaries.push({
410
- expression: config.atomist(explore)(
411
- check_bigint(project)(atom)(input),
412
- )(input),
413
- combined: false,
414
- });
415
- else if (atom.type === "string")
416
- binaries.push({
417
- expression: config.atomist(explore)(
418
- check_string(project)(atom)(input),
419
- )(input),
420
- combined: false,
421
- });
422
- else
423
- add(
424
- true,
425
- ts.factory.createStringLiteral(atom.type),
426
- ValueFactory.TYPEOF(input),
427
- );
428
-
429
- // TEMPLATE LITERAL VALUES
430
- if (meta.templates.length)
431
- if (AtomicPredicator.template(meta))
432
- binaries.push({
433
- expression: config.atomist(explore)(
434
- check_template(meta.templates)(input),
435
- )(input),
436
- combined: false,
437
- });
438
-
439
- // NATIVE CLASSES
440
- for (const native of meta.natives)
441
- binaries.push({
442
- expression: check_native(native)(input),
443
- combined: false,
444
- });
445
-
446
- //----
447
- // INSTANCES
448
- //----
449
- interface IInstance {
450
- pre: ts.Expression;
451
- body: ts.Expression | null;
452
- expected: string;
453
- }
454
- const instances: IInstance[] = [];
455
- const prepare =
456
- (pre: ts.Expression, expected: string) =>
457
- (body: ts.Expression | null) =>
458
- instances.push({
459
- pre,
460
- expected,
461
- body,
462
- });
463
-
464
- // SETS
465
- if (meta.sets.length) {
466
- const install = prepare(
467
- check_native("Set")(input),
468
- meta.sets.map((elem) => `Set<${elem.getName()}>`).join(" | "),
469
- );
470
- if (meta.sets.some((elem) => elem.any)) install(null);
471
- else
472
- install(
473
- explore_sets(project)(config)(importer)(input, meta.sets, {
474
- ...explore,
475
- from: "array",
476
- }),
477
- );
478
- }
479
-
480
- // MAPS
481
- if (meta.maps.length) {
482
- const install = prepare(
483
- check_native("Map")(input),
484
- meta.maps
485
- .map(({ key, value }) => `Map<${key}, ${value}>`)
486
- .join(" | "),
487
- );
488
- if (meta.maps.some((elem) => elem.key.any && elem.value.any))
489
- install(null);
490
- else
491
- install(
492
- explore_maps(project)(config)(importer)(input, meta.maps, {
493
- ...explore,
494
- from: "array",
495
- }),
496
- );
497
- }
498
-
499
- // ARRAYS AND TUPLES
500
- if (meta.tuples.length + meta.arrays.length > 0) {
501
- const install = prepare(
502
- config.atomist(explore)({
503
- expected: [
504
- ...meta.tuples.map((t) => t.type.name),
505
- ...meta.arrays.map((a) => a.getName()),
506
- ].join(" | "),
507
- expression: ExpressionFactory.isArray(input),
508
- conditions: [],
509
- })(input),
510
- [...meta.tuples, ...meta.arrays]
511
- .map((elem) => elem.type.name)
512
- .join(" | "),
513
- );
514
- if (meta.arrays.length === 0)
515
- if (meta.tuples.length === 1)
516
- install(
517
- decode_tuple(project)(config)(importer)(input, meta.tuples[0]!, {
518
- ...explore,
519
- from: "array",
520
- }),
521
- );
522
- // TUPLE ONLY
523
- else
524
- install(
525
- explore_tuples(project)(config)(importer)(input, meta.tuples, {
526
- ...explore,
527
- from: "array",
528
- }),
529
- );
530
- else if (meta.arrays.some((elem) => elem.type.value.any)) install(null);
531
- else if (meta.tuples.length === 0)
532
- if (meta.arrays.length === 1)
533
- // ARRAY ONLY
534
- install(
535
- decode_array(project)(config)(importer)(input, meta.arrays[0]!, {
536
- ...explore,
537
- from: "array",
538
- }),
539
- );
540
- else
541
- install(
542
- explore_arrays(project)(config)(importer)(input, meta.arrays, {
543
- ...explore,
544
- from: "array",
545
- }),
546
- );
547
- else
548
- install(
549
- explore_arrays_and_tuples(project)(config)(importer)(
550
- input,
551
- [...meta.tuples, ...meta.arrays],
552
- explore,
553
- ),
554
- );
555
- }
556
-
557
- // OBJECT
558
- if (meta.objects.length > 0)
559
- prepare(
560
- ExpressionFactory.isObject({
561
- checkNull: true,
562
- checkArray: meta.objects.some((obj) =>
563
- obj.properties.every(
564
- (prop) => !prop.key.isSoleLiteral() || !prop.value.isRequired(),
565
- ),
566
- ),
567
- })(input),
568
- meta.objects.map((obj) => obj.name).join(" | "),
569
- )(
570
- explore_objects(config)(importer)(input, meta, {
571
- ...explore,
572
- from: "object",
573
- }),
574
- );
575
-
576
- if (instances.length) {
577
- const transformer =
578
- (merger: (x: ts.Expression, y: ts.Expression) => ts.Expression) =>
579
- (ins: IInstance) =>
580
- ins.body
581
- ? {
582
- expression: merger(ins.pre, ins.body),
583
- combined: true,
584
- }
585
- : {
586
- expression: ins.pre,
587
- combined: false,
588
- };
589
- if (instances.length === 1)
590
- binaries.push(
591
- transformer((pre, body) =>
592
- config.combiner(explore)("and")(
593
- input,
594
- [pre, body].map((expression) => ({
595
- expression,
596
- combined: expression !== pre,
597
- })),
598
- meta.getName(),
599
- ),
600
- )(instances[0]!),
601
- );
602
- else
603
- binaries.push({
604
- expression: config.combiner(explore)("or")(
605
- input,
606
- instances.map(transformer(ts.factory.createLogicalAnd)),
607
- meta.getName(),
608
- ),
609
- combined: true,
610
- });
611
- }
612
-
613
- // ESCAPED CASE
614
- if (meta.escaped !== null)
615
- binaries.push({
616
- combined: false,
617
- expression:
618
- meta.escaped.original.size() === 1 &&
619
- meta.escaped.original.natives.length === 1
620
- ? check_native(meta.escaped.original.natives[0]!)(input)
621
- : ts.factory.createLogicalAnd(
622
- decode(project)(config)(importer)(
623
- input,
624
- meta.escaped.original,
625
- explore,
626
- ),
627
- ts.factory.createLogicalAnd(
628
- IsProgrammer.decode_to_json(false)(input),
629
- decode_escaped(project)(config)(importer)(
630
- input,
631
- meta.escaped.returns,
632
- explore,
633
- ),
634
- ),
635
- ),
636
- });
637
-
638
- //----
639
- // COMBINE CONDITIONS
640
- //----
641
- return top.length && binaries.length
642
- ? config.combiner(explore)("and")(
643
- input,
644
- [
645
- ...top,
646
- {
647
- expression: config.combiner(explore)("or")(
648
- input,
649
- binaries,
650
- meta.getName(),
651
- ),
652
- combined: true,
653
- },
654
- ],
655
- meta.getName(),
656
- )
657
- : binaries.length
658
- ? config.combiner(explore)("or")(input, binaries, meta.getName())
659
- : config.success;
660
- };
661
-
662
- export const decode_object =
663
- (config: IConfig) => (importer: FunctionImporter) => {
664
- const func = FeatureProgrammer.decode_object(config)(importer);
665
- return (input: ts.Expression, obj: MetadataObject, explore: IExplore) => {
666
- obj.validated = true;
667
- return func(input, obj, explore);
668
- };
669
- };
670
-
671
- const decode_array =
672
- (project: IProject) =>
673
- (config: IConfig) =>
674
- (importer: FunctionImporter) =>
675
- (input: ts.Expression, array: MetadataArray, explore: IExplore) => {
676
- if (array.type.recursive === false)
677
- return decode_array_inline(project)(config)(importer)(
678
- input,
679
- array,
680
- explore,
681
- );
682
-
683
- explore = {
684
- ...explore,
685
- source: "function",
686
- from: "array",
687
- };
688
- return ts.factory.createLogicalOr(
689
- ts.factory.createCallExpression(
690
- ts.factory.createIdentifier(
691
- importer.useLocal(`${config.prefix}a${array.type.index}`),
692
- ),
693
- undefined,
694
- FeatureProgrammer.argumentsArray(config)({
695
- ...explore,
696
- source: "function",
697
- from: "array",
698
- })(input),
699
- ),
700
- config.joiner.failure(input, array.type.name, explore),
701
- );
702
- };
703
-
704
- const decode_array_inline =
705
- (project: IProject) =>
706
- (config: IConfig) =>
707
- (importer: FunctionImporter) =>
708
- (
709
- input: ts.Expression,
710
- array: MetadataArray,
711
- explore: IExplore,
712
- ): ts.Expression => {
713
- const length = check_array_length(project)(array)(input);
714
- const main = FeatureProgrammer.decode_array({
715
- prefix: config.prefix,
716
- trace: config.trace,
717
- path: config.path,
718
- decoder: () => decode(project)(config)(importer),
719
- })(importer)(config.joiner.array)(input, array, explore);
720
- return length.expression === null && length.conditions.length === 0
721
- ? main
722
- : ts.factory.createLogicalAnd(
723
- config.atomist(explore)(length)(input),
724
- main,
725
- );
726
- };
727
-
728
- const decode_tuple =
729
- (project: IProject) =>
730
- (config: IConfig) =>
731
- (importer: FunctionImporter) =>
732
- (
733
- input: ts.Expression,
734
- tuple: MetadataTuple,
735
- explore: IExplore,
736
- ): ts.Expression => {
737
- if (tuple.type.recursive === false)
738
- return decode_tuple_inline(project)(config)(importer)(
739
- input,
740
- tuple.type,
741
- explore,
742
- );
743
- explore = {
744
- ...explore,
745
- source: "function",
746
- from: "array",
747
- };
748
- return ts.factory.createLogicalOr(
749
- ts.factory.createCallExpression(
750
- ts.factory.createIdentifier(
751
- importer.useLocal(`${config.prefix}t${tuple.type.index}`),
752
- ),
753
- undefined,
754
- FeatureProgrammer.argumentsArray(config)({
755
- ...explore,
756
- source: "function",
757
- })(input),
758
- ),
759
- config.joiner.failure(input, tuple.type.name, explore),
760
- );
761
- };
762
-
763
- const decode_tuple_inline =
764
- (project: IProject) =>
765
- (config: IConfig) =>
766
- (importer: FunctionImporter) =>
767
- (
768
- input: ts.Expression,
769
- tuple: MetadataTupleType,
770
- explore: IExplore,
771
- ): ts.Expression => {
772
- const binaries: ts.Expression[] = tuple.elements
773
- .filter((meta) => meta.rest === null)
774
- .map((meta, index) =>
775
- decode(project)(config)(importer)(
776
- ts.factory.createElementAccessExpression(input, index),
777
- meta,
778
- {
779
- ...explore,
780
- from: "array",
781
- postfix: explore.postfix.length
782
- ? `${postfix_of_tuple(explore.postfix)}[${index}]"`
783
- : `"[${index}]"`,
784
- },
785
- ),
786
- );
787
- const rest: ts.Expression | null =
788
- tuple.elements.length && tuple.elements.at(-1)!.rest !== null
789
- ? decode(project)(config)(importer)(
790
- ts.factory.createCallExpression(
791
- IdentifierFactory.access(input)("slice"),
792
- undefined,
793
- [ExpressionFactory.number(tuple.elements.length - 1)],
794
- ),
795
- wrap_metadata_rest_tuple(tuple.elements.at(-1)!.rest!),
796
- {
797
- ...explore,
798
- start: tuple.elements.length - 1,
799
- },
800
- )
801
- : null;
802
-
803
- const arrayLength = ts.factory.createPropertyAccessExpression(
804
- input,
805
- "length",
806
- );
807
- return config.combiner(explore)("and")(
808
- input,
809
- [
810
- ...(rest === null
811
- ? tuple.elements.every((t) => t.optional === false)
812
- ? [
813
- {
814
- combined: false,
815
- expression: ts.factory.createStrictEquality(
816
- arrayLength,
817
- ExpressionFactory.number(tuple.elements.length),
818
- ),
819
- },
820
- ]
821
- : [
822
- {
823
- combined: false,
824
- expression: ts.factory.createLogicalAnd(
825
- ts.factory.createLessThanEquals(
826
- ExpressionFactory.number(
827
- tuple.elements.filter((t) => t.optional === false)
828
- .length,
829
- ),
830
- arrayLength,
831
- ),
832
- ts.factory.createGreaterThanEquals(
833
- ExpressionFactory.number(tuple.elements.length),
834
- arrayLength,
835
- ),
836
- ),
837
- },
838
- ]
839
- : []),
840
- ...(config.joiner.tuple
841
- ? [
842
- {
843
- expression: config.joiner.tuple(binaries),
844
- combined: true,
845
- },
846
- ]
847
- : binaries.map((expression) => ({
848
- expression,
849
- combined: true,
850
- }))),
851
- ...(rest !== null
852
- ? [
853
- {
854
- expression: rest,
855
- combined: true,
856
- },
857
- ]
858
- : []),
859
- ],
860
- `[${tuple.elements.map((t) => t.getName()).join(", ")}]`,
861
- );
862
- };
863
-
864
- const decode_escaped =
865
- (project: IProject) =>
866
- (config: IConfig) =>
867
- (importer: FunctionImporter) =>
868
- (input: ts.Expression, meta: Metadata, explore: IExplore): ts.Expression =>
869
- ts.factory.createCallExpression(
870
- ts.factory.createParenthesizedExpression(
871
- ts.factory.createArrowFunction(
872
- undefined,
873
- undefined,
874
- [IdentifierFactory.parameter("input", TypeFactory.keyword("any"))],
875
- undefined,
876
- undefined,
877
- decode(project)(config)(importer)(
878
- ts.factory.createIdentifier("input"),
879
- meta,
880
- explore,
881
- ),
882
- ),
883
- ),
884
- undefined,
885
- [
886
- ts.factory.createCallExpression(
887
- IdentifierFactory.access(input)("toJSON"),
888
- undefined,
889
- [],
890
- ),
891
- ],
892
- );
893
-
894
- /* -----------------------------------------------------------
895
- UNION TYPE EXPLORERS
896
- ----------------------------------------------------------- */
897
- const explore_sets =
898
- (project: IProject) =>
899
- (config: IConfig) =>
900
- (importer: FunctionImporter) =>
901
- (
902
- input: ts.Expression,
903
- sets: Metadata[],
904
- explore: IExplore,
905
- ): ts.Expression =>
906
- ts.factory.createCallExpression(
907
- UnionExplorer.set({
908
- checker: decode(project)(config)(importer),
909
- decoder: decode_array(project)(config)(importer),
910
- empty: config.success,
911
- success: config.success,
912
- failure: (input, expected, explore) =>
913
- ts.factory.createReturnStatement(
914
- config.joiner.failure(input, expected, explore),
915
- ),
916
- })([])(input, sets, explore),
917
- undefined,
918
- undefined,
919
- );
920
-
921
- const explore_maps =
922
- (project: IProject) =>
923
- (config: IConfig) =>
924
- (importer: FunctionImporter) =>
925
- (
926
- input: ts.Expression,
927
- maps: Metadata.Entry[],
928
- explore: IExplore,
929
- ): ts.Expression =>
930
- ts.factory.createCallExpression(
931
- UnionExplorer.map({
932
- checker: (input, entry, explore) => {
933
- const func = decode(project)(config)(importer);
934
- return ts.factory.createLogicalAnd(
935
- func(
936
- ts.factory.createElementAccessExpression(input, 0),
937
- entry[0],
938
- {
939
- ...explore,
940
- postfix: `${explore.postfix}[0]`,
941
- },
942
- ),
943
- func(
944
- ts.factory.createElementAccessExpression(input, 1),
945
- entry[1],
946
- {
947
- ...explore,
948
- postfix: `${explore.postfix}[1]`,
949
- },
950
- ),
951
- );
952
- },
953
- decoder: decode_array(project)(config)(importer),
954
- empty: config.success,
955
- success: config.success,
956
- failure: (input, expected, explore) =>
957
- ts.factory.createReturnStatement(
958
- config.joiner.failure(input, expected, explore),
959
- ),
960
- })([])(input, maps, explore),
961
- undefined,
962
- undefined,
963
- );
964
-
965
- const explore_tuples =
966
- (project: IProject) =>
967
- (config: IConfig) =>
968
- (importer: FunctionImporter) =>
969
- (
970
- input: ts.Expression,
971
- tuples: MetadataTuple[],
972
- explore: IExplore,
973
- ): ts.Expression =>
974
- explore_array_like_union_types(config)(importer)(
975
- UnionExplorer.tuple({
976
- checker: decode_tuple(project)(config)(importer),
977
- decoder: decode_tuple(project)(config)(importer),
978
- empty: config.success,
979
- success: config.success,
980
- failure: (input, expected, explore) =>
981
- ts.factory.createReturnStatement(
982
- config.joiner.failure(input, expected, explore),
983
- ),
984
- }),
985
- )(input, tuples, explore);
986
-
987
- const explore_arrays =
988
- (project: IProject) =>
989
- (config: IConfig) =>
990
- (importer: FunctionImporter) =>
991
- (
992
- input: ts.Expression,
993
- arrays: MetadataArray[],
994
- explore: IExplore,
995
- ): ts.Expression =>
996
- explore_array_like_union_types(config)(importer)(
997
- UnionExplorer.array({
998
- checker: decode(project)(config)(importer),
999
- decoder: decode_array(project)(config)(importer),
1000
- empty: config.success,
1001
- success: config.success,
1002
- failure: (input, expected, explore) =>
1003
- ts.factory.createReturnStatement(
1004
- config.joiner.failure(input, expected, explore),
1005
- ),
1006
- }),
1007
- )(input, arrays, explore);
1008
-
1009
- const explore_arrays_and_tuples =
1010
- (project: IProject) =>
1011
- (config: IConfig) =>
1012
- (importer: FunctionImporter) =>
1013
- (
1014
- input: ts.Expression,
1015
- elements: Array<MetadataArray | MetadataTuple>,
1016
- explore: IExplore,
1017
- ): ts.Expression =>
1018
- explore_array_like_union_types(config)(importer)(
1019
- UnionExplorer.array_or_tuple({
1020
- checker: (front, target, explore, array) =>
1021
- target instanceof MetadataTuple
1022
- ? decode_tuple(project)(config)(importer)(front, target, explore)
1023
- : config.atomist(explore)({
1024
- expected: elements
1025
- .map((elem) =>
1026
- elem instanceof MetadataArray
1027
- ? elem.getName()
1028
- : elem.type.name,
1029
- )
1030
- .join(" | "),
1031
- expression: decode(project)(config)(importer)(
1032
- front,
1033
- target,
1034
- explore,
1035
- ),
1036
- conditions: [],
1037
- })(array),
1038
- decoder: (input, target, explore) =>
1039
- target instanceof MetadataTuple
1040
- ? decode_tuple(project)(config)(importer)(input, target, explore)
1041
- : decode_array(project)(config)(importer)(input, target, explore),
1042
- empty: config.success,
1043
- success: config.success,
1044
- failure: (input, expected, explore) =>
1045
- ts.factory.createReturnStatement(
1046
- config.joiner.failure(input, expected, explore),
1047
- ),
1048
- }),
1049
- )(input, elements, explore);
1050
-
1051
- const explore_array_like_union_types =
1052
- (config: IConfig) =>
1053
- (importer: FunctionImporter) =>
1054
- <T extends MetadataArray | MetadataTuple>(
1055
- factory: (
1056
- parameters: ts.ParameterDeclaration[],
1057
- ) => (
1058
- input: ts.Expression,
1059
- elements: T[],
1060
- explore: IExplore,
1061
- ) => ts.ArrowFunction,
1062
- ) =>
1063
- (input: ts.Expression, elements: T[], explore: IExplore): ts.Expression => {
1064
- const arrow =
1065
- (parameters: ts.ParameterDeclaration[]) =>
1066
- (explore: IExplore) =>
1067
- (input: ts.Expression): ts.ArrowFunction =>
1068
- factory(parameters)(input, elements, explore);
1069
- if (elements.every((e) => e.type.recursive === false))
1070
- ts.factory.createCallExpression(
1071
- arrow([])(explore)(input),
1072
- undefined,
1073
- [],
1074
- );
1075
- explore = {
1076
- ...explore,
1077
- source: "function",
1078
- from: "array",
1079
- };
1080
- return ts.factory.createLogicalOr(
1081
- ts.factory.createCallExpression(
1082
- ts.factory.createIdentifier(
1083
- importer.emplaceUnion(
1084
- config.prefix,
1085
- elements.map((e) => e.type.name).join(" | "),
1086
- () =>
1087
- arrow(
1088
- FeatureProgrammer.parameterDeclarations(config)(
1089
- TypeFactory.keyword("any"),
1090
- )(ts.factory.createIdentifier("input")),
1091
- )({
1092
- ...explore,
1093
- postfix: "",
1094
- })(ts.factory.createIdentifier("input")),
1095
- ),
1096
- ),
1097
- undefined,
1098
- FeatureProgrammer.argumentsArray(config)(explore)(input),
1099
- ),
1100
- config.joiner.failure(
1101
- input,
1102
- elements.map((e) => e.type.name).join(" | "),
1103
- explore,
1104
- ),
1105
- );
1106
- };
1107
-
1108
- const explore_objects =
1109
- (config: IConfig) =>
1110
- (importer: FunctionImporter) =>
1111
- (input: ts.Expression, meta: Metadata, explore: IExplore) =>
1112
- meta.objects.length === 1
1113
- ? decode_object(config)(importer)(input, meta.objects[0]!, explore)
1114
- : ts.factory.createCallExpression(
1115
- ts.factory.createIdentifier(
1116
- importer.useLocal(`${config.prefix}u${meta.union_index!}`),
1117
- ),
1118
- undefined,
1119
- FeatureProgrammer.argumentsArray(config)(explore)(input),
1120
- );
1121
- }
1122
-
1123
- const create_add =
1124
- (binaries: CheckerProgrammer.IBinary[]) =>
1125
- (defaultInput: ts.Expression) =>
1126
- (
1127
- exact: boolean,
1128
- left: ts.Expression,
1129
- right: ts.Expression = defaultInput,
1130
- ) => {
1131
- const factory = exact
1132
- ? ts.factory.createStrictEquality
1133
- : ts.factory.createStrictInequality;
1134
- binaries.push({
1135
- expression: factory(left, right),
1136
- combined: false,
1137
- });
1138
- };
1
+ import ts from "typescript";
2
+
3
+ import { ExpressionFactory } from "../factories/ExpressionFactory";
4
+ import { IdentifierFactory } from "../factories/IdentifierFactory";
5
+ import { MetadataCollection } from "../factories/MetadataCollection";
6
+ import { MetadataFactory } from "../factories/MetadataFactory";
7
+ import { StatementFactory } from "../factories/StatementFactory";
8
+ import { TypeFactory } from "../factories/TypeFactory";
9
+ import { ValueFactory } from "../factories/ValueFactory";
10
+
11
+ import { Metadata } from "../schemas/metadata/Metadata";
12
+ import { MetadataArray } from "../schemas/metadata/MetadataArray";
13
+ import { MetadataConstant } from "../schemas/metadata/MetadataConstant";
14
+ import { MetadataObject } from "../schemas/metadata/MetadataObject";
15
+ import { MetadataTuple } from "../schemas/metadata/MetadataTuple";
16
+ import { MetadataTupleType } from "../schemas/metadata/MetadataTupleType";
17
+
18
+ import { IProject } from "../transformers/IProject";
19
+ import { TransformerError } from "../transformers/TransformerError";
20
+
21
+ import { FeatureProgrammer } from "./FeatureProgrammer";
22
+ import { IsProgrammer } from "./IsProgrammer";
23
+ import { AtomicPredicator } from "./helpers/AtomicPredicator";
24
+ import { FunctionImporter } from "./helpers/FunctionImporter";
25
+ import { ICheckEntry } from "./helpers/ICheckEntry";
26
+ import { IExpressionEntry } from "./helpers/IExpressionEntry";
27
+ import { OptionPredicator } from "./helpers/OptionPredicator";
28
+ import { UnionExplorer } from "./helpers/UnionExplorer";
29
+ import { check_array_length } from "./internal/check_array_length";
30
+ import { check_bigint } from "./internal/check_bigint";
31
+ import { check_native } from "./internal/check_native";
32
+ import { check_number } from "./internal/check_number";
33
+ import { check_string } from "./internal/check_string";
34
+ import { check_template } from "./internal/check_template";
35
+ import { decode_union_object } from "./internal/decode_union_object";
36
+ import { postfix_of_tuple } from "./internal/postfix_of_tuple";
37
+ import { wrap_metadata_rest_tuple } from "./internal/wrap_metadata_rest_tuple";
38
+
39
+ export namespace CheckerProgrammer {
40
+ export interface IConfig {
41
+ prefix: string;
42
+ path: boolean;
43
+ trace: boolean;
44
+ equals: boolean;
45
+ numeric: boolean;
46
+ addition?: () => ts.Statement[];
47
+ decoder?: () => FeatureProgrammer.Decoder<Metadata, ts.Expression>;
48
+ combiner: IConfig.Combiner;
49
+ atomist: (
50
+ explore: IExplore,
51
+ ) => (check: ICheckEntry) => (input: ts.Expression) => ts.Expression;
52
+ joiner: IConfig.IJoiner;
53
+ success: ts.Expression;
54
+ }
55
+ export namespace IConfig {
56
+ export interface Combiner {
57
+ (explorer: IExplore): {
58
+ (logic: "and" | "or"): {
59
+ (
60
+ input: ts.Expression,
61
+ binaries: IBinary[],
62
+ expected: string,
63
+ ): ts.Expression;
64
+ };
65
+ };
66
+ }
67
+ export interface IJoiner {
68
+ object(input: ts.Expression, entries: IExpressionEntry[]): ts.Expression;
69
+ array(input: ts.Expression, arrow: ts.ArrowFunction): ts.Expression;
70
+ tuple?: undefined | ((exprs: ts.Expression[]) => ts.Expression);
71
+
72
+ failure(
73
+ value: ts.Expression,
74
+ expected: string,
75
+ explore?: undefined | FeatureProgrammer.IExplore,
76
+ ): ts.Expression;
77
+ is?(expression: ts.Expression): ts.Expression;
78
+ required?(exp: ts.Expression): ts.Expression;
79
+ full?:
80
+ | undefined
81
+ | ((
82
+ condition: ts.Expression,
83
+ ) => (
84
+ input: ts.Expression,
85
+ expected: string,
86
+ explore: IExplore,
87
+ ) => ts.Expression);
88
+ }
89
+ }
90
+ export type IExplore = FeatureProgrammer.IExplore;
91
+
92
+ export interface IBinary {
93
+ expression: ts.Expression;
94
+ combined: boolean;
95
+ }
96
+
97
+ /* -----------------------------------------------------------
98
+ WRITERS
99
+ ----------------------------------------------------------- */
100
+ export const compose = (props: {
101
+ project: IProject;
102
+ config: IConfig;
103
+ importer: FunctionImporter;
104
+ type: ts.Type;
105
+ name: string | undefined;
106
+ }) =>
107
+ FeatureProgrammer.compose({
108
+ ...props,
109
+ config: configure(props.project)(props.config)(props.importer),
110
+ });
111
+
112
+ export const write =
113
+ (project: IProject) => (config: IConfig) => (importer: FunctionImporter) =>
114
+ FeatureProgrammer.write(project)(configure(project)(config)(importer))(
115
+ importer,
116
+ );
117
+
118
+ export const write_object_functions =
119
+ (project: IProject) => (config: IConfig) => (importer: FunctionImporter) =>
120
+ FeatureProgrammer.write_object_functions(
121
+ configure(project)(config)(importer),
122
+ )(importer);
123
+
124
+ export const write_union_functions =
125
+ (project: IProject) => (config: IConfig) => (importer: FunctionImporter) =>
126
+ FeatureProgrammer.write_union_functions(
127
+ configure(project)({ ...config, numeric: false })(importer),
128
+ );
129
+
130
+ export const write_array_functions =
131
+ (project: IProject) =>
132
+ (config: IConfig) =>
133
+ (importer: FunctionImporter) =>
134
+ (collection: MetadataCollection): ts.VariableStatement[] =>
135
+ collection
136
+ .arrays()
137
+ .filter((a) => a.recursive)
138
+ .map((type, i) =>
139
+ StatementFactory.constant(
140
+ `${config.prefix}a${i}`,
141
+ ts.factory.createArrowFunction(
142
+ undefined,
143
+ undefined,
144
+ FeatureProgrammer.parameterDeclarations(config)(
145
+ TypeFactory.keyword("any"),
146
+ )(ts.factory.createIdentifier("input")),
147
+ TypeFactory.keyword("any"),
148
+ undefined,
149
+ decode_array_inline(project)(config)(importer)(
150
+ ts.factory.createIdentifier("input"),
151
+ MetadataArray.create({
152
+ type,
153
+ tags: [],
154
+ }),
155
+ {
156
+ tracable: config.trace,
157
+ source: "function",
158
+ from: "array",
159
+ postfix: "",
160
+ },
161
+ ),
162
+ ),
163
+ ),
164
+ );
165
+
166
+ export const write_tuple_functions =
167
+ (project: IProject) =>
168
+ (config: IConfig) =>
169
+ (importer: FunctionImporter) =>
170
+ (collection: MetadataCollection): ts.VariableStatement[] =>
171
+ collection
172
+ .tuples()
173
+ .filter((t) => t.recursive)
174
+ .map((tuple, i) =>
175
+ StatementFactory.constant(
176
+ `${config.prefix}t${i}`,
177
+ ts.factory.createArrowFunction(
178
+ undefined,
179
+ undefined,
180
+ FeatureProgrammer.parameterDeclarations(config)(
181
+ TypeFactory.keyword("any"),
182
+ )(ts.factory.createIdentifier("input")),
183
+ TypeFactory.keyword("any"),
184
+ undefined,
185
+ decode_tuple_inline(project)(config)(importer)(
186
+ ts.factory.createIdentifier("input"),
187
+ tuple,
188
+ {
189
+ tracable: config.trace,
190
+ source: "function",
191
+ from: "array",
192
+ postfix: "",
193
+ },
194
+ ),
195
+ ),
196
+ ),
197
+ );
198
+
199
+ const configure =
200
+ (project: IProject) =>
201
+ (config: IConfig) =>
202
+ (importer: FunctionImporter): FeatureProgrammer.IConfig => ({
203
+ types: {
204
+ input: () => TypeFactory.keyword("any"),
205
+ output: (type, name) =>
206
+ ts.factory.createTypePredicateNode(
207
+ undefined,
208
+ "input",
209
+ ts.factory.createTypeReferenceNode(
210
+ name ?? TypeFactory.getFullName(project.checker)(type),
211
+ ),
212
+ ),
213
+ },
214
+ trace: config.trace,
215
+ path: config.path,
216
+ prefix: config.prefix,
217
+ initializer: (project) => (importer) => (type) => {
218
+ const collection: MetadataCollection = new MetadataCollection();
219
+ const result = MetadataFactory.analyze(
220
+ project.checker,
221
+ project.context,
222
+ )({
223
+ escape: false,
224
+ constant: true,
225
+ absorb: true,
226
+ })(collection)(type);
227
+ if (result.success === false)
228
+ throw TransformerError.from(`typia.${importer.method}`)(
229
+ result.errors,
230
+ );
231
+ return [collection, result.data];
232
+ },
233
+ addition: config.addition,
234
+ decoder: () => config.decoder?.() ?? decode(project)(config)(importer),
235
+ objector: {
236
+ checker: () => config.decoder?.() ?? decode(project)(config)(importer),
237
+ decoder: () => decode_object(config)(importer),
238
+ joiner: config.joiner.object,
239
+ unionizer: config.equals
240
+ ? decode_union_object(decode_object(config)(importer))(
241
+ (input, obj, explore) =>
242
+ decode_object(config)(importer)(input, obj, {
243
+ ...explore,
244
+ tracable: true,
245
+ }),
246
+ )(config.joiner.is ?? ((expr) => expr))((value, expected) =>
247
+ ts.factory.createReturnStatement(
248
+ config.joiner.failure(value, expected),
249
+ ),
250
+ )
251
+ : (input, targets, explore) =>
252
+ config.combiner(explore)("or")(
253
+ input,
254
+ targets.map((obj) => ({
255
+ expression: decode_object(config)(importer)(
256
+ input,
257
+ obj,
258
+ explore,
259
+ ),
260
+ combined: true,
261
+ })),
262
+ `(${targets.map((t) => t.name).join(" | ")})`,
263
+ ),
264
+ failure: (value, expected) =>
265
+ ts.factory.createReturnStatement(
266
+ config.joiner.failure(value, expected),
267
+ ),
268
+ is: config.joiner.is,
269
+ required: config.joiner.required,
270
+ full: config.joiner.full,
271
+ type: TypeFactory.keyword("boolean"),
272
+ },
273
+ generator: {
274
+ unions: config.numeric
275
+ ? () =>
276
+ FeatureProgrammer.write_union_functions(
277
+ configure(project)({ ...config, numeric: false })(importer),
278
+ )
279
+ : undefined,
280
+ arrays: () => write_array_functions(project)(config)(importer),
281
+ tuples: () => write_tuple_functions(project)(config)(importer),
282
+ },
283
+ });
284
+
285
+ /* -----------------------------------------------------------
286
+ DECODERS
287
+ ----------------------------------------------------------- */
288
+ /**
289
+ * @internal
290
+ */
291
+ export const decode =
292
+ (project: IProject) =>
293
+ (config: IConfig) =>
294
+ (importer: FunctionImporter) =>
295
+ (
296
+ input: ts.Expression,
297
+ meta: Metadata,
298
+ explore: IExplore,
299
+ ): ts.Expression => {
300
+ if (meta.any) return config.success;
301
+
302
+ const top: IBinary[] = [];
303
+ const binaries: IBinary[] = [];
304
+ const add = create_add(binaries)(input);
305
+ const getConstantValue = (value: number | string | bigint | boolean) => {
306
+ if (typeof value === "string")
307
+ return ts.factory.createStringLiteral(value);
308
+ else if (typeof value === "bigint")
309
+ return ExpressionFactory.bigint(value);
310
+ return ts.factory.createIdentifier(value.toString());
311
+ };
312
+
313
+ //----
314
+ // CHECK OPTIONAL
315
+ //----
316
+ // @todo -> should be elaborated
317
+ const checkOptional: boolean = meta.empty() || meta.isUnionBucket();
318
+
319
+ // NULLABLE
320
+ if (checkOptional || meta.nullable)
321
+ (meta.nullable ? add : create_add(top)(input))(
322
+ meta.nullable,
323
+ ValueFactory.NULL(),
324
+ );
325
+
326
+ // UNDEFINDABLE
327
+ if (checkOptional || !meta.isRequired())
328
+ (meta.isRequired() ? create_add(top)(input) : add)(
329
+ !meta.isRequired(),
330
+ ValueFactory.UNDEFINED(),
331
+ );
332
+
333
+ // FUNCTIONAL
334
+ if (meta.functional === true)
335
+ if (OptionPredicator.functional(project.options) || meta.size() !== 1)
336
+ add(
337
+ true,
338
+ ts.factory.createStringLiteral("function"),
339
+ ValueFactory.TYPEOF(input),
340
+ );
341
+ else
342
+ binaries.push({
343
+ combined: false,
344
+ expression: config.success,
345
+ });
346
+
347
+ //----
348
+ // VALUES
349
+ //----
350
+ // CONSTANT VALUES
351
+ const constants: MetadataConstant[] = meta.constants.filter((c) =>
352
+ AtomicPredicator.constant(meta)(c.type),
353
+ );
354
+ const constantLength: number = constants
355
+ .map((c) => c.values.length)
356
+ .reduce((a, b) => a + b, 0);
357
+ if (constantLength >= 10) {
358
+ const values: Array<boolean | number | string | bigint> = constants
359
+ .map((c) => c.values.map((v) => v.value))
360
+ .flat();
361
+ add(
362
+ true,
363
+ ts.factory.createTrue(),
364
+ ts.factory.createCallExpression(
365
+ IdentifierFactory.access(
366
+ importer.emplaceVariable(
367
+ `${config.prefix}v${importer.increment()}`,
368
+ ts.factory.createNewExpression(
369
+ ts.factory.createIdentifier("Set"),
370
+ undefined,
371
+ [
372
+ ts.factory.createArrayLiteralExpression(
373
+ values.map((v) =>
374
+ typeof v === "boolean"
375
+ ? v === true
376
+ ? ts.factory.createTrue()
377
+ : ts.factory.createFalse()
378
+ : typeof v === "bigint"
379
+ ? ExpressionFactory.bigint(v)
380
+ : typeof v === "number"
381
+ ? ExpressionFactory.number(v)
382
+ : ts.factory.createStringLiteral(v.toString()),
383
+ ),
384
+ ),
385
+ ],
386
+ ),
387
+ ),
388
+ )("has"),
389
+ undefined,
390
+ [input],
391
+ ),
392
+ );
393
+ } else
394
+ for (const c of constants)
395
+ if (AtomicPredicator.constant(meta)(c.type))
396
+ for (const v of c.values) add(true, getConstantValue(v.value));
397
+
398
+ // ATOMIC VALUES
399
+ for (const atom of meta.atomics)
400
+ if (AtomicPredicator.atomic(meta)(atom.type) === false) continue;
401
+ else if (atom.type === "number")
402
+ binaries.push({
403
+ expression: config.atomist(explore)(
404
+ check_number(project, config.numeric)(atom)(input),
405
+ )(input),
406
+ combined: false,
407
+ });
408
+ else if (atom.type === "bigint")
409
+ binaries.push({
410
+ expression: config.atomist(explore)(
411
+ check_bigint(project)(atom)(input),
412
+ )(input),
413
+ combined: false,
414
+ });
415
+ else if (atom.type === "string")
416
+ binaries.push({
417
+ expression: config.atomist(explore)(
418
+ check_string(project)(atom)(input),
419
+ )(input),
420
+ combined: false,
421
+ });
422
+ else
423
+ add(
424
+ true,
425
+ ts.factory.createStringLiteral(atom.type),
426
+ ValueFactory.TYPEOF(input),
427
+ );
428
+
429
+ // TEMPLATE LITERAL VALUES
430
+ if (meta.templates.length)
431
+ if (AtomicPredicator.template(meta))
432
+ binaries.push({
433
+ expression: config.atomist(explore)(
434
+ check_template(meta.templates)(input),
435
+ )(input),
436
+ combined: false,
437
+ });
438
+
439
+ // NATIVE CLASSES
440
+ for (const native of meta.natives)
441
+ binaries.push({
442
+ expression: check_native(native)(input),
443
+ combined: false,
444
+ });
445
+
446
+ //----
447
+ // INSTANCES
448
+ //----
449
+ interface IInstance {
450
+ pre: ts.Expression;
451
+ body: ts.Expression | null;
452
+ expected: string;
453
+ }
454
+ const instances: IInstance[] = [];
455
+ const prepare =
456
+ (pre: ts.Expression, expected: string) =>
457
+ (body: ts.Expression | null) =>
458
+ instances.push({
459
+ pre,
460
+ expected,
461
+ body,
462
+ });
463
+
464
+ // SETS
465
+ if (meta.sets.length) {
466
+ const install = prepare(
467
+ check_native("Set")(input),
468
+ meta.sets.map((elem) => `Set<${elem.getName()}>`).join(" | "),
469
+ );
470
+ if (meta.sets.some((elem) => elem.any)) install(null);
471
+ else
472
+ install(
473
+ explore_sets(project)(config)(importer)(input, meta.sets, {
474
+ ...explore,
475
+ from: "array",
476
+ }),
477
+ );
478
+ }
479
+
480
+ // MAPS
481
+ if (meta.maps.length) {
482
+ const install = prepare(
483
+ check_native("Map")(input),
484
+ meta.maps
485
+ .map(({ key, value }) => `Map<${key}, ${value}>`)
486
+ .join(" | "),
487
+ );
488
+ if (meta.maps.some((elem) => elem.key.any && elem.value.any))
489
+ install(null);
490
+ else
491
+ install(
492
+ explore_maps(project)(config)(importer)(input, meta.maps, {
493
+ ...explore,
494
+ from: "array",
495
+ }),
496
+ );
497
+ }
498
+
499
+ // ARRAYS AND TUPLES
500
+ if (meta.tuples.length + meta.arrays.length > 0) {
501
+ const install = prepare(
502
+ config.atomist(explore)({
503
+ expected: [
504
+ ...meta.tuples.map((t) => t.type.name),
505
+ ...meta.arrays.map((a) => a.getName()),
506
+ ].join(" | "),
507
+ expression: ExpressionFactory.isArray(input),
508
+ conditions: [],
509
+ })(input),
510
+ [...meta.tuples, ...meta.arrays]
511
+ .map((elem) => elem.type.name)
512
+ .join(" | "),
513
+ );
514
+ if (meta.arrays.length === 0)
515
+ if (meta.tuples.length === 1)
516
+ install(
517
+ decode_tuple(project)(config)(importer)(input, meta.tuples[0]!, {
518
+ ...explore,
519
+ from: "array",
520
+ }),
521
+ );
522
+ // TUPLE ONLY
523
+ else
524
+ install(
525
+ explore_tuples(project)(config)(importer)(input, meta.tuples, {
526
+ ...explore,
527
+ from: "array",
528
+ }),
529
+ );
530
+ else if (meta.arrays.some((elem) => elem.type.value.any)) install(null);
531
+ else if (meta.tuples.length === 0)
532
+ if (meta.arrays.length === 1)
533
+ // ARRAY ONLY
534
+ install(
535
+ decode_array(project)(config)(importer)(input, meta.arrays[0]!, {
536
+ ...explore,
537
+ from: "array",
538
+ }),
539
+ );
540
+ else
541
+ install(
542
+ explore_arrays(project)(config)(importer)(input, meta.arrays, {
543
+ ...explore,
544
+ from: "array",
545
+ }),
546
+ );
547
+ else
548
+ install(
549
+ explore_arrays_and_tuples(project)(config)(importer)(
550
+ input,
551
+ [...meta.tuples, ...meta.arrays],
552
+ explore,
553
+ ),
554
+ );
555
+ }
556
+
557
+ // OBJECT
558
+ if (meta.objects.length > 0)
559
+ prepare(
560
+ ExpressionFactory.isObject({
561
+ checkNull: true,
562
+ checkArray: meta.objects.some((obj) =>
563
+ obj.properties.every(
564
+ (prop) => !prop.key.isSoleLiteral() || !prop.value.isRequired(),
565
+ ),
566
+ ),
567
+ })(input),
568
+ meta.objects.map((obj) => obj.name).join(" | "),
569
+ )(
570
+ explore_objects(config)(importer)(input, meta, {
571
+ ...explore,
572
+ from: "object",
573
+ }),
574
+ );
575
+
576
+ if (instances.length) {
577
+ const transformer =
578
+ (merger: (x: ts.Expression, y: ts.Expression) => ts.Expression) =>
579
+ (ins: IInstance) =>
580
+ ins.body
581
+ ? {
582
+ expression: merger(ins.pre, ins.body),
583
+ combined: true,
584
+ }
585
+ : {
586
+ expression: ins.pre,
587
+ combined: false,
588
+ };
589
+ if (instances.length === 1)
590
+ binaries.push(
591
+ transformer((pre, body) =>
592
+ config.combiner(explore)("and")(
593
+ input,
594
+ [pre, body].map((expression) => ({
595
+ expression,
596
+ combined: expression !== pre,
597
+ })),
598
+ meta.getName(),
599
+ ),
600
+ )(instances[0]!),
601
+ );
602
+ else
603
+ binaries.push({
604
+ expression: config.combiner(explore)("or")(
605
+ input,
606
+ instances.map(transformer(ts.factory.createLogicalAnd)),
607
+ meta.getName(),
608
+ ),
609
+ combined: true,
610
+ });
611
+ }
612
+
613
+ // ESCAPED CASE
614
+ if (meta.escaped !== null)
615
+ binaries.push({
616
+ combined: false,
617
+ expression:
618
+ meta.escaped.original.size() === 1 &&
619
+ meta.escaped.original.natives.length === 1
620
+ ? check_native(meta.escaped.original.natives[0]!)(input)
621
+ : ts.factory.createLogicalAnd(
622
+ decode(project)(config)(importer)(
623
+ input,
624
+ meta.escaped.original,
625
+ explore,
626
+ ),
627
+ ts.factory.createLogicalAnd(
628
+ IsProgrammer.decode_to_json(false)(input),
629
+ decode_escaped(project)(config)(importer)(
630
+ input,
631
+ meta.escaped.returns,
632
+ explore,
633
+ ),
634
+ ),
635
+ ),
636
+ });
637
+
638
+ //----
639
+ // COMBINE CONDITIONS
640
+ //----
641
+ return top.length && binaries.length
642
+ ? config.combiner(explore)("and")(
643
+ input,
644
+ [
645
+ ...top,
646
+ {
647
+ expression: config.combiner(explore)("or")(
648
+ input,
649
+ binaries,
650
+ meta.getName(),
651
+ ),
652
+ combined: true,
653
+ },
654
+ ],
655
+ meta.getName(),
656
+ )
657
+ : binaries.length
658
+ ? config.combiner(explore)("or")(input, binaries, meta.getName())
659
+ : config.success;
660
+ };
661
+
662
+ export const decode_object =
663
+ (config: IConfig) => (importer: FunctionImporter) => {
664
+ const func = FeatureProgrammer.decode_object(config)(importer);
665
+ return (input: ts.Expression, obj: MetadataObject, explore: IExplore) => {
666
+ obj.validated = true;
667
+ return func(input, obj, explore);
668
+ };
669
+ };
670
+
671
+ const decode_array =
672
+ (project: IProject) =>
673
+ (config: IConfig) =>
674
+ (importer: FunctionImporter) =>
675
+ (input: ts.Expression, array: MetadataArray, explore: IExplore) => {
676
+ if (array.type.recursive === false)
677
+ return decode_array_inline(project)(config)(importer)(
678
+ input,
679
+ array,
680
+ explore,
681
+ );
682
+
683
+ explore = {
684
+ ...explore,
685
+ source: "function",
686
+ from: "array",
687
+ };
688
+ return ts.factory.createLogicalOr(
689
+ ts.factory.createCallExpression(
690
+ ts.factory.createIdentifier(
691
+ importer.useLocal(`${config.prefix}a${array.type.index}`),
692
+ ),
693
+ undefined,
694
+ FeatureProgrammer.argumentsArray(config)({
695
+ ...explore,
696
+ source: "function",
697
+ from: "array",
698
+ })(input),
699
+ ),
700
+ config.joiner.failure(input, array.type.name, explore),
701
+ );
702
+ };
703
+
704
+ const decode_array_inline =
705
+ (project: IProject) =>
706
+ (config: IConfig) =>
707
+ (importer: FunctionImporter) =>
708
+ (
709
+ input: ts.Expression,
710
+ array: MetadataArray,
711
+ explore: IExplore,
712
+ ): ts.Expression => {
713
+ const length = check_array_length(project)(array)(input);
714
+ const main = FeatureProgrammer.decode_array({
715
+ prefix: config.prefix,
716
+ trace: config.trace,
717
+ path: config.path,
718
+ decoder: () => decode(project)(config)(importer),
719
+ })(importer)(config.joiner.array)(input, array, explore);
720
+ return length.expression === null && length.conditions.length === 0
721
+ ? main
722
+ : ts.factory.createLogicalAnd(
723
+ config.atomist(explore)(length)(input),
724
+ main,
725
+ );
726
+ };
727
+
728
+ const decode_tuple =
729
+ (project: IProject) =>
730
+ (config: IConfig) =>
731
+ (importer: FunctionImporter) =>
732
+ (
733
+ input: ts.Expression,
734
+ tuple: MetadataTuple,
735
+ explore: IExplore,
736
+ ): ts.Expression => {
737
+ if (tuple.type.recursive === false)
738
+ return decode_tuple_inline(project)(config)(importer)(
739
+ input,
740
+ tuple.type,
741
+ explore,
742
+ );
743
+ explore = {
744
+ ...explore,
745
+ source: "function",
746
+ from: "array",
747
+ };
748
+ return ts.factory.createLogicalOr(
749
+ ts.factory.createCallExpression(
750
+ ts.factory.createIdentifier(
751
+ importer.useLocal(`${config.prefix}t${tuple.type.index}`),
752
+ ),
753
+ undefined,
754
+ FeatureProgrammer.argumentsArray(config)({
755
+ ...explore,
756
+ source: "function",
757
+ })(input),
758
+ ),
759
+ config.joiner.failure(input, tuple.type.name, explore),
760
+ );
761
+ };
762
+
763
+ const decode_tuple_inline =
764
+ (project: IProject) =>
765
+ (config: IConfig) =>
766
+ (importer: FunctionImporter) =>
767
+ (
768
+ input: ts.Expression,
769
+ tuple: MetadataTupleType,
770
+ explore: IExplore,
771
+ ): ts.Expression => {
772
+ const binaries: ts.Expression[] = tuple.elements
773
+ .filter((meta) => meta.rest === null)
774
+ .map((meta, index) =>
775
+ decode(project)(config)(importer)(
776
+ ts.factory.createElementAccessExpression(input, index),
777
+ meta,
778
+ {
779
+ ...explore,
780
+ from: "array",
781
+ postfix: explore.postfix.length
782
+ ? `${postfix_of_tuple(explore.postfix)}[${index}]"`
783
+ : `"[${index}]"`,
784
+ },
785
+ ),
786
+ );
787
+ const rest: ts.Expression | null =
788
+ tuple.elements.length && tuple.elements.at(-1)!.rest !== null
789
+ ? decode(project)(config)(importer)(
790
+ ts.factory.createCallExpression(
791
+ IdentifierFactory.access(input)("slice"),
792
+ undefined,
793
+ [ExpressionFactory.number(tuple.elements.length - 1)],
794
+ ),
795
+ wrap_metadata_rest_tuple(tuple.elements.at(-1)!.rest!),
796
+ {
797
+ ...explore,
798
+ start: tuple.elements.length - 1,
799
+ },
800
+ )
801
+ : null;
802
+
803
+ const arrayLength = ts.factory.createPropertyAccessExpression(
804
+ input,
805
+ "length",
806
+ );
807
+ return config.combiner(explore)("and")(
808
+ input,
809
+ [
810
+ ...(rest === null
811
+ ? tuple.elements.every((t) => t.optional === false)
812
+ ? [
813
+ {
814
+ combined: false,
815
+ expression: ts.factory.createStrictEquality(
816
+ arrayLength,
817
+ ExpressionFactory.number(tuple.elements.length),
818
+ ),
819
+ },
820
+ ]
821
+ : [
822
+ {
823
+ combined: false,
824
+ expression: ts.factory.createLogicalAnd(
825
+ ts.factory.createLessThanEquals(
826
+ ExpressionFactory.number(
827
+ tuple.elements.filter((t) => t.optional === false)
828
+ .length,
829
+ ),
830
+ arrayLength,
831
+ ),
832
+ ts.factory.createGreaterThanEquals(
833
+ ExpressionFactory.number(tuple.elements.length),
834
+ arrayLength,
835
+ ),
836
+ ),
837
+ },
838
+ ]
839
+ : []),
840
+ ...(config.joiner.tuple
841
+ ? [
842
+ {
843
+ expression: config.joiner.tuple(binaries),
844
+ combined: true,
845
+ },
846
+ ]
847
+ : binaries.map((expression) => ({
848
+ expression,
849
+ combined: true,
850
+ }))),
851
+ ...(rest !== null
852
+ ? [
853
+ {
854
+ expression: rest,
855
+ combined: true,
856
+ },
857
+ ]
858
+ : []),
859
+ ],
860
+ `[${tuple.elements.map((t) => t.getName()).join(", ")}]`,
861
+ );
862
+ };
863
+
864
+ const decode_escaped =
865
+ (project: IProject) =>
866
+ (config: IConfig) =>
867
+ (importer: FunctionImporter) =>
868
+ (input: ts.Expression, meta: Metadata, explore: IExplore): ts.Expression =>
869
+ ts.factory.createCallExpression(
870
+ ts.factory.createParenthesizedExpression(
871
+ ts.factory.createArrowFunction(
872
+ undefined,
873
+ undefined,
874
+ [IdentifierFactory.parameter("input", TypeFactory.keyword("any"))],
875
+ undefined,
876
+ undefined,
877
+ decode(project)(config)(importer)(
878
+ ts.factory.createIdentifier("input"),
879
+ meta,
880
+ explore,
881
+ ),
882
+ ),
883
+ ),
884
+ undefined,
885
+ [
886
+ ts.factory.createCallExpression(
887
+ IdentifierFactory.access(input)("toJSON"),
888
+ undefined,
889
+ [],
890
+ ),
891
+ ],
892
+ );
893
+
894
+ /* -----------------------------------------------------------
895
+ UNION TYPE EXPLORERS
896
+ ----------------------------------------------------------- */
897
+ const explore_sets =
898
+ (project: IProject) =>
899
+ (config: IConfig) =>
900
+ (importer: FunctionImporter) =>
901
+ (
902
+ input: ts.Expression,
903
+ sets: Metadata[],
904
+ explore: IExplore,
905
+ ): ts.Expression =>
906
+ ts.factory.createCallExpression(
907
+ UnionExplorer.set({
908
+ checker: decode(project)(config)(importer),
909
+ decoder: decode_array(project)(config)(importer),
910
+ empty: config.success,
911
+ success: config.success,
912
+ failure: (input, expected, explore) =>
913
+ ts.factory.createReturnStatement(
914
+ config.joiner.failure(input, expected, explore),
915
+ ),
916
+ })([])(input, sets, explore),
917
+ undefined,
918
+ undefined,
919
+ );
920
+
921
+ const explore_maps =
922
+ (project: IProject) =>
923
+ (config: IConfig) =>
924
+ (importer: FunctionImporter) =>
925
+ (
926
+ input: ts.Expression,
927
+ maps: Metadata.Entry[],
928
+ explore: IExplore,
929
+ ): ts.Expression =>
930
+ ts.factory.createCallExpression(
931
+ UnionExplorer.map({
932
+ checker: (input, entry, explore) => {
933
+ const func = decode(project)(config)(importer);
934
+ return ts.factory.createLogicalAnd(
935
+ func(
936
+ ts.factory.createElementAccessExpression(input, 0),
937
+ entry[0],
938
+ {
939
+ ...explore,
940
+ postfix: `${explore.postfix}[0]`,
941
+ },
942
+ ),
943
+ func(
944
+ ts.factory.createElementAccessExpression(input, 1),
945
+ entry[1],
946
+ {
947
+ ...explore,
948
+ postfix: `${explore.postfix}[1]`,
949
+ },
950
+ ),
951
+ );
952
+ },
953
+ decoder: decode_array(project)(config)(importer),
954
+ empty: config.success,
955
+ success: config.success,
956
+ failure: (input, expected, explore) =>
957
+ ts.factory.createReturnStatement(
958
+ config.joiner.failure(input, expected, explore),
959
+ ),
960
+ })([])(input, maps, explore),
961
+ undefined,
962
+ undefined,
963
+ );
964
+
965
+ const explore_tuples =
966
+ (project: IProject) =>
967
+ (config: IConfig) =>
968
+ (importer: FunctionImporter) =>
969
+ (
970
+ input: ts.Expression,
971
+ tuples: MetadataTuple[],
972
+ explore: IExplore,
973
+ ): ts.Expression =>
974
+ explore_array_like_union_types(config)(importer)(
975
+ UnionExplorer.tuple({
976
+ checker: decode_tuple(project)(config)(importer),
977
+ decoder: decode_tuple(project)(config)(importer),
978
+ empty: config.success,
979
+ success: config.success,
980
+ failure: (input, expected, explore) =>
981
+ ts.factory.createReturnStatement(
982
+ config.joiner.failure(input, expected, explore),
983
+ ),
984
+ }),
985
+ )(input, tuples, explore);
986
+
987
+ const explore_arrays =
988
+ (project: IProject) =>
989
+ (config: IConfig) =>
990
+ (importer: FunctionImporter) =>
991
+ (
992
+ input: ts.Expression,
993
+ arrays: MetadataArray[],
994
+ explore: IExplore,
995
+ ): ts.Expression =>
996
+ explore_array_like_union_types(config)(importer)(
997
+ UnionExplorer.array({
998
+ checker: decode(project)(config)(importer),
999
+ decoder: decode_array(project)(config)(importer),
1000
+ empty: config.success,
1001
+ success: config.success,
1002
+ failure: (input, expected, explore) =>
1003
+ ts.factory.createReturnStatement(
1004
+ config.joiner.failure(input, expected, explore),
1005
+ ),
1006
+ }),
1007
+ )(input, arrays, explore);
1008
+
1009
+ const explore_arrays_and_tuples =
1010
+ (project: IProject) =>
1011
+ (config: IConfig) =>
1012
+ (importer: FunctionImporter) =>
1013
+ (
1014
+ input: ts.Expression,
1015
+ elements: Array<MetadataArray | MetadataTuple>,
1016
+ explore: IExplore,
1017
+ ): ts.Expression =>
1018
+ explore_array_like_union_types(config)(importer)(
1019
+ UnionExplorer.array_or_tuple({
1020
+ checker: (front, target, explore, array) =>
1021
+ target instanceof MetadataTuple
1022
+ ? decode_tuple(project)(config)(importer)(front, target, explore)
1023
+ : config.atomist(explore)({
1024
+ expected: elements
1025
+ .map((elem) =>
1026
+ elem instanceof MetadataArray
1027
+ ? elem.getName()
1028
+ : elem.type.name,
1029
+ )
1030
+ .join(" | "),
1031
+ expression: decode(project)(config)(importer)(
1032
+ front,
1033
+ target,
1034
+ explore,
1035
+ ),
1036
+ conditions: [],
1037
+ })(array),
1038
+ decoder: (input, target, explore) =>
1039
+ target instanceof MetadataTuple
1040
+ ? decode_tuple(project)(config)(importer)(input, target, explore)
1041
+ : decode_array(project)(config)(importer)(input, target, explore),
1042
+ empty: config.success,
1043
+ success: config.success,
1044
+ failure: (input, expected, explore) =>
1045
+ ts.factory.createReturnStatement(
1046
+ config.joiner.failure(input, expected, explore),
1047
+ ),
1048
+ }),
1049
+ )(input, elements, explore);
1050
+
1051
+ const explore_array_like_union_types =
1052
+ (config: IConfig) =>
1053
+ (importer: FunctionImporter) =>
1054
+ <T extends MetadataArray | MetadataTuple>(
1055
+ factory: (
1056
+ parameters: ts.ParameterDeclaration[],
1057
+ ) => (
1058
+ input: ts.Expression,
1059
+ elements: T[],
1060
+ explore: IExplore,
1061
+ ) => ts.ArrowFunction,
1062
+ ) =>
1063
+ (input: ts.Expression, elements: T[], explore: IExplore): ts.Expression => {
1064
+ const arrow =
1065
+ (parameters: ts.ParameterDeclaration[]) =>
1066
+ (explore: IExplore) =>
1067
+ (input: ts.Expression): ts.ArrowFunction =>
1068
+ factory(parameters)(input, elements, explore);
1069
+ if (elements.every((e) => e.type.recursive === false))
1070
+ ts.factory.createCallExpression(
1071
+ arrow([])(explore)(input),
1072
+ undefined,
1073
+ [],
1074
+ );
1075
+ explore = {
1076
+ ...explore,
1077
+ source: "function",
1078
+ from: "array",
1079
+ };
1080
+ return ts.factory.createLogicalOr(
1081
+ ts.factory.createCallExpression(
1082
+ ts.factory.createIdentifier(
1083
+ importer.emplaceUnion(
1084
+ config.prefix,
1085
+ elements.map((e) => e.type.name).join(" | "),
1086
+ () =>
1087
+ arrow(
1088
+ FeatureProgrammer.parameterDeclarations(config)(
1089
+ TypeFactory.keyword("any"),
1090
+ )(ts.factory.createIdentifier("input")),
1091
+ )({
1092
+ ...explore,
1093
+ postfix: "",
1094
+ })(ts.factory.createIdentifier("input")),
1095
+ ),
1096
+ ),
1097
+ undefined,
1098
+ FeatureProgrammer.argumentsArray(config)(explore)(input),
1099
+ ),
1100
+ config.joiner.failure(
1101
+ input,
1102
+ elements.map((e) => e.type.name).join(" | "),
1103
+ explore,
1104
+ ),
1105
+ );
1106
+ };
1107
+
1108
+ const explore_objects =
1109
+ (config: IConfig) =>
1110
+ (importer: FunctionImporter) =>
1111
+ (input: ts.Expression, meta: Metadata, explore: IExplore) =>
1112
+ meta.objects.length === 1
1113
+ ? decode_object(config)(importer)(input, meta.objects[0]!, explore)
1114
+ : ts.factory.createCallExpression(
1115
+ ts.factory.createIdentifier(
1116
+ importer.useLocal(`${config.prefix}u${meta.union_index!}`),
1117
+ ),
1118
+ undefined,
1119
+ FeatureProgrammer.argumentsArray(config)(explore)(input),
1120
+ );
1121
+ }
1122
+
1123
+ const create_add =
1124
+ (binaries: CheckerProgrammer.IBinary[]) =>
1125
+ (defaultInput: ts.Expression) =>
1126
+ (
1127
+ exact: boolean,
1128
+ left: ts.Expression,
1129
+ right: ts.Expression = defaultInput,
1130
+ ) => {
1131
+ const factory = exact
1132
+ ? ts.factory.createStrictEquality
1133
+ : ts.factory.createStrictInequality;
1134
+ binaries.push({
1135
+ expression: factory(left, right),
1136
+ combined: false,
1137
+ });
1138
+ };