typia 3.6.4 → 3.6.6

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 (72) hide show
  1. package/lib/functional/$is_uuid.js +1 -1
  2. package/lib/functional/$is_uuid.js.map +1 -1
  3. package/lib/module.d.ts +1 -1
  4. package/lib/programmers/internal/application_number.js +1 -1
  5. package/package.json +1 -1
  6. package/src/executable/setup/ArgumentParser.ts +91 -91
  7. package/src/executable/setup/FileRetriever.ts +33 -33
  8. package/src/executable/setup/PackageManager.ts +92 -92
  9. package/src/executable/setup/PluginConfigurator.ts +99 -99
  10. package/src/factories/internal/metadata/emplace_metadata_object.ts +142 -142
  11. package/src/functional/$is_uuid.ts +2 -1
  12. package/src/module.ts +1946 -1946
  13. package/src/programmers/AssertCloneProgrammer.ts +70 -70
  14. package/src/programmers/AssertParseProgrammer.ts +65 -65
  15. package/src/programmers/AssertProgrammer.ts +232 -232
  16. package/src/programmers/AssertPruneProgrammer.ts +67 -67
  17. package/src/programmers/AssertStringifyProgrammer.ts +71 -71
  18. package/src/programmers/CheckerProgrammer.ts +893 -893
  19. package/src/programmers/CloneProgrammer.ts +386 -386
  20. package/src/programmers/FeatureProgrammer.ts +505 -505
  21. package/src/programmers/IsCloneProgrammer.ts +80 -80
  22. package/src/programmers/IsParseProgrammer.ts +74 -74
  23. package/src/programmers/IsPruneProgrammer.ts +75 -75
  24. package/src/programmers/IsStringifyProgrammer.ts +81 -81
  25. package/src/programmers/PruneProgrammer.ts +341 -341
  26. package/src/programmers/RandomProgrammer.ts +391 -391
  27. package/src/programmers/StringifyProgrammer.ts +795 -795
  28. package/src/programmers/ValidateCloneProgrammer.ts +90 -90
  29. package/src/programmers/ValidateParseProgrammer.ts +69 -69
  30. package/src/programmers/ValidateProgrammer.ts +266 -266
  31. package/src/programmers/ValidatePruneProgrammer.ts +83 -83
  32. package/src/programmers/ValidateStringifyProgrammer.ts +89 -89
  33. package/src/programmers/internal/application_number.ts +1 -1
  34. package/src/transformers/features/miscellaneous/AssertCloneTransformer.ts +9 -9
  35. package/src/transformers/features/miscellaneous/AssertPruneTransformer.ts +9 -9
  36. package/src/transformers/features/miscellaneous/CloneTransformer.ts +9 -9
  37. package/src/transformers/features/miscellaneous/CreateAssertCloneTransformer.ts +9 -9
  38. package/src/transformers/features/miscellaneous/CreateAssertPruneTransformer.ts +9 -9
  39. package/src/transformers/features/miscellaneous/CreateCloneTransformer.ts +9 -9
  40. package/src/transformers/features/miscellaneous/CreateIsCloneTransformer.ts +9 -9
  41. package/src/transformers/features/miscellaneous/CreateIsPruneTransformer.ts +9 -9
  42. package/src/transformers/features/miscellaneous/CreatePruneTransformer.ts +9 -9
  43. package/src/transformers/features/miscellaneous/CreateRandomGenerator.ts +42 -42
  44. package/src/transformers/features/miscellaneous/CreateValidateCloneTransformer.ts +9 -9
  45. package/src/transformers/features/miscellaneous/CreateValidatePruneTransformer.ts +9 -9
  46. package/src/transformers/features/miscellaneous/IsCloneTransformer.ts +9 -9
  47. package/src/transformers/features/miscellaneous/IsPruneTransformer.ts +9 -9
  48. package/src/transformers/features/miscellaneous/PruneTransformer.ts +9 -9
  49. package/src/transformers/features/miscellaneous/RandomTransformer.ts +48 -48
  50. package/src/transformers/features/miscellaneous/ValidateCloneTransformer.ts +9 -9
  51. package/src/transformers/features/miscellaneous/ValidatePruneTransformer.ts +9 -9
  52. package/src/transformers/features/parsers/AssertParseTransformer.ts +9 -9
  53. package/src/transformers/features/parsers/CreateAssertParseTransformer.ts +9 -9
  54. package/src/transformers/features/parsers/CreateIsParseTransformer.ts +9 -9
  55. package/src/transformers/features/parsers/CreateValidateParseTransformer.ts +9 -9
  56. package/src/transformers/features/parsers/IsParseTransformer.ts +9 -9
  57. package/src/transformers/features/parsers/ValidateParseTransformer.ts +9 -9
  58. package/src/transformers/features/stringifiers/AssertStringifyTransformer.ts +10 -10
  59. package/src/transformers/features/stringifiers/CreateAssertStringifyTransformer.ts +9 -9
  60. package/src/transformers/features/stringifiers/CreateIsStringifyTransformer.ts +9 -9
  61. package/src/transformers/features/stringifiers/CreateStringifyTransformer.ts +9 -9
  62. package/src/transformers/features/stringifiers/CreateValidateStringifyProgrammer.ts +11 -11
  63. package/src/transformers/features/stringifiers/IsStringifyTransformer.ts +9 -9
  64. package/src/transformers/features/stringifiers/StringifyTransformer.ts +9 -9
  65. package/src/transformers/features/stringifiers/ValidateStringifyTransformer.ts +10 -10
  66. package/src/transformers/features/validators/AssertTransformer.ts +11 -11
  67. package/src/transformers/features/validators/CreateAssertTransformer.ts +12 -12
  68. package/src/transformers/features/validators/CreateIsTransformer.ts +10 -10
  69. package/src/transformers/features/validators/CreateValidateTransformer.ts +12 -12
  70. package/src/transformers/features/validators/IsTransformer.ts +10 -10
  71. package/src/transformers/features/validators/ValidateTransformer.ts +11 -11
  72. package/src/transformers/internal/GenericTransformer.ts +99 -99
@@ -1,893 +1,893 @@
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 { TypeFactory } from "../factories/TypeFactory";
8
- import { ValueFactory } from "../factories/ValueFactory";
9
-
10
- import { IMetadataTag } from "../metadata/IMetadataTag";
11
- import { Metadata } from "../metadata/Metadata";
12
- import { MetadataObject } from "../metadata/MetadataObject";
13
-
14
- import { IProject } from "../transformers/IProject";
15
-
16
- import { FeatureProgrammer } from "./FeatureProgrammer";
17
- import { AtomicPredicator } from "./helpers/AtomicPredicator";
18
- import { FunctionImporter } from "./helpers/FunctionImporeter";
19
- import { IExpressionEntry } from "./helpers/IExpressionEntry";
20
- import { OptionPredicator } from "./helpers/OptionPredicator";
21
- import { UnionExplorer } from "./helpers/UnionExplorer";
22
- import { check_array } from "./internal/check_array";
23
- import { check_array_length } from "./internal/check_array_length";
24
- import { check_bigint } from "./internal/check_bigint";
25
- import { check_native } from "./internal/check_native";
26
- import { check_number } from "./internal/check_number";
27
- import { check_string } from "./internal/check_string";
28
- import { check_template } from "./internal/check_template";
29
- import { check_union_tuple } from "./internal/check_union_tuple";
30
- import { decode_union_object } from "./internal/decode_union_object";
31
-
32
- export namespace CheckerProgrammer {
33
- export interface IConfig {
34
- functors: string;
35
- unioners: string;
36
- path: boolean;
37
- trace: boolean;
38
- equals: boolean;
39
- numeric: boolean;
40
- combiner: IConfig.Combiner;
41
- decoder?: FeatureProgrammer.Decoder<Metadata, ts.Expression>;
42
- joiner: IConfig.IJoiner;
43
- success: ts.Expression;
44
- }
45
- export namespace IConfig {
46
- export interface Combiner {
47
- (explorer: IExplore): {
48
- (logic: "and" | "or"): {
49
- (
50
- input: ts.Expression,
51
- binaries: IBinary[],
52
- expected: string,
53
- ): ts.Expression;
54
- };
55
- };
56
- }
57
- export interface IJoiner {
58
- object(
59
- input: ts.Expression,
60
- entries: IExpressionEntry[],
61
- ): ts.Expression;
62
- array(input: ts.Expression, arrow: ts.ArrowFunction): ts.Expression;
63
- tuple?(exprs: ts.Expression[]): ts.Expression;
64
-
65
- failure(
66
- value: ts.Expression,
67
- expected: string,
68
- explore?: FeatureProgrammer.IExplore,
69
- ): ts.Expression;
70
- is?(expression: ts.Expression): ts.Expression;
71
- required?(exp: ts.Expression): ts.Expression;
72
- full?: (
73
- condition: ts.Expression,
74
- ) => (
75
- input: ts.Expression,
76
- expected: string,
77
- explore: IExplore,
78
- ) => ts.Expression;
79
- }
80
- }
81
- export import IExplore = FeatureProgrammer.IExplore;
82
-
83
- export interface IBinary {
84
- expression: ts.Expression;
85
- combined: boolean;
86
- }
87
-
88
- /* -----------------------------------------------------------
89
- GENERATORS
90
- ----------------------------------------------------------- */
91
- export function generate(
92
- project: IProject,
93
- config: IConfig,
94
- importer: FunctionImporter,
95
- addition?: () => ts.Statement[],
96
- ) {
97
- return FeatureProgrammer.generate(
98
- project,
99
- CONFIG(project, config, importer),
100
- importer,
101
- () => (addition ? (addition ? addition() : []) : undefined),
102
- );
103
- }
104
-
105
- export const generate_functors = (
106
- project: IProject,
107
- config: IConfig,
108
- importer: FunctionImporter,
109
- ) =>
110
- FeatureProgrammer.generate_functors(CONFIG(project, config, importer))(
111
- importer,
112
- );
113
-
114
- export const generate_unioners = (
115
- project: IProject,
116
- config: IConfig,
117
- importer: FunctionImporter,
118
- ) =>
119
- FeatureProgrammer.generate_unioners(
120
- CONFIG(project, { ...config, numeric: false }, importer),
121
- )(importer);
122
-
123
- function CONFIG(
124
- project: IProject,
125
- config: IConfig,
126
- importer: FunctionImporter,
127
- ): FeatureProgrammer.IConfig {
128
- const output: FeatureProgrammer.IConfig = {
129
- types: {
130
- input: () => TypeFactory.keyword("any"),
131
- output: (type, name) =>
132
- ts.factory.createTypePredicateNode(
133
- undefined,
134
- "input",
135
- ts.factory.createTypeReferenceNode(
136
- name ??
137
- TypeFactory.getFullName(project.checker, type),
138
- ),
139
- ),
140
- },
141
- trace: config.trace,
142
- path: config.path,
143
- functors: config.functors,
144
- unioners: config.unioners,
145
- initializer: ({ checker }, type) => {
146
- const collection: MetadataCollection = new MetadataCollection();
147
- const meta: Metadata = MetadataFactory.generate(
148
- checker,
149
- collection,
150
- type,
151
- {
152
- resolve: false,
153
- constant: true,
154
- },
155
- );
156
- return [collection, meta];
157
- },
158
- decoder: config.decoder || decode(project, config, importer),
159
- objector: {
160
- checker: config.decoder || decode(project, config, importer),
161
- decoder: decode_object(config)(importer),
162
- joiner: config.joiner.object,
163
- unionizer: config.equals
164
- ? decode_union_object(decode_object(config)(importer))(
165
- (input, obj, explore) =>
166
- decode_object(config)(importer)(input, obj, {
167
- ...explore,
168
- tracable: true,
169
- }),
170
- )(config.joiner.is || ((expr) => expr))(
171
- (value, expected) =>
172
- ts.factory.createReturnStatement(
173
- config.joiner.failure(value, expected),
174
- ),
175
- )
176
- : (input, targets, explore) =>
177
- config.combiner(explore)("or")(
178
- input,
179
- targets.map((obj) => ({
180
- expression: decode_object(config)(importer)(
181
- input,
182
- obj,
183
- explore,
184
- ),
185
- combined: true,
186
- })),
187
- `(${targets.map((t) => t.name).join(" | ")})`,
188
- ),
189
- failure: (value, expected) =>
190
- ts.factory.createReturnStatement(
191
- config.joiner.failure(value, expected),
192
- ),
193
- is: config.joiner.is,
194
- required: config.joiner.required,
195
- full: config.joiner.full,
196
- type: TypeFactory.keyword("boolean"),
197
- },
198
- };
199
- if (config.numeric === true)
200
- output.generator = {
201
- unioners: FeatureProgrammer.generate_unioners(
202
- CONFIG(project, { ...config, numeric: false }, importer),
203
- )(importer),
204
- };
205
- return output;
206
- }
207
-
208
- /* -----------------------------------------------------------
209
- DECODERS
210
- ----------------------------------------------------------- */
211
- export function decode(
212
- project: IProject,
213
- config: IConfig,
214
- importer: FunctionImporter,
215
- ): (
216
- input: ts.Expression,
217
- meta: Metadata,
218
- explore: IExplore,
219
- tags: IMetadataTag[],
220
- ) => ts.Expression;
221
-
222
- /**
223
- * @internal
224
- */
225
- export function decode(
226
- project: IProject,
227
- config: IConfig,
228
- importer: FunctionImporter,
229
- checkTupleLength: boolean,
230
- ): (
231
- input: ts.Expression,
232
- meta: Metadata,
233
- explore: IExplore,
234
- tags: IMetadataTag[],
235
- ) => ts.Expression;
236
-
237
- /**
238
- * @internal
239
- */
240
- export function decode(
241
- project: IProject,
242
- config: IConfig,
243
- importer: FunctionImporter,
244
- ) {
245
- return function (
246
- input: ts.Expression,
247
- meta: Metadata,
248
- explore: IExplore,
249
- tags: IMetadataTag[],
250
- ): ts.Expression {
251
- if (meta.any) return config.success;
252
-
253
- const top: IBinary[] = [];
254
- const binaries: IBinary[] = [];
255
- const add = create_add(binaries)(input);
256
- const getConstantValue = (
257
- value: number | string | bigint | boolean,
258
- ) =>
259
- typeof value === "string"
260
- ? ts.factory.createStringLiteral(value)
261
- : ts.factory.createIdentifier(value.toString());
262
-
263
- //----
264
- // CHECK OPTIONAL
265
- //----
266
- // @todo -> should be elaborated
267
- const checkOptional: boolean = meta.empty() || meta.isUnionBucket();
268
-
269
- // NULLABLE
270
- if (
271
- checkOptional ||
272
- meta.nullable
273
- // || (meta.objects.length && meta.size() !== meta.objects.length)
274
- )
275
- (meta.nullable ? add : create_add(top)(input))(
276
- meta.nullable,
277
- ValueFactory.NULL(),
278
- );
279
-
280
- // UNDEFINDABLE
281
- if (checkOptional || !meta.required)
282
- (meta.required ? create_add(top)(input) : add)(
283
- !meta.required,
284
- ValueFactory.UNDEFINED(),
285
- );
286
-
287
- // FUNCTIONAL
288
- if (meta.functional === true)
289
- if (
290
- OptionPredicator.functional(project.options) ||
291
- meta.size() !== 1
292
- )
293
- add(
294
- true,
295
- ts.factory.createStringLiteral("function"),
296
- ValueFactory.TYPEOF(input),
297
- );
298
- else
299
- binaries.push({
300
- combined: false,
301
- expression: config.success,
302
- });
303
-
304
- //----
305
- // VALUES
306
- //----
307
- // CONSTANT VALUES
308
- for (const constant of meta.constants)
309
- if (AtomicPredicator.constant(meta)(constant.type))
310
- for (const val of constant.values)
311
- add(true, getConstantValue(val));
312
-
313
- // ATOMIC VALUES
314
- for (const type of meta.atomics)
315
- if (AtomicPredicator.atomic(meta)(type) === false) continue;
316
- else if (type === "number")
317
- binaries.push({
318
- expression: check_number(project, config.numeric)(
319
- input,
320
- tags,
321
- ),
322
- combined: false,
323
- });
324
- else if (type === "bigint")
325
- binaries.push({
326
- expression: check_bigint(input, tags),
327
- combined: false,
328
- });
329
- else if (type === "string")
330
- binaries.push({
331
- expression: check_string(importer)(input, tags),
332
- combined: false,
333
- });
334
- else
335
- add(
336
- true,
337
- ts.factory.createStringLiteral(type),
338
- ValueFactory.TYPEOF(input),
339
- );
340
-
341
- // TEMPLATE LITERAL VALUES
342
- if (meta.templates.length)
343
- if (AtomicPredicator.template(meta))
344
- binaries.push({
345
- expression: check_template(importer)(
346
- input,
347
- meta.templates,
348
- tags,
349
- ),
350
- combined: false,
351
- });
352
-
353
- // NATIVE CLASSES
354
- for (const native of meta.natives)
355
- binaries.push({
356
- expression: check_native(native)(input),
357
- combined: false,
358
- });
359
-
360
- //----
361
- // INSTANCES
362
- //----
363
- interface IInstance {
364
- pre: ts.Expression;
365
- body: ts.Expression | null;
366
- expected: string;
367
- }
368
- const instances: IInstance[] = [];
369
- const prepare =
370
- (pre: ts.Expression, expected: string) =>
371
- (body: ts.Expression | null) =>
372
- instances.push({
373
- pre,
374
- expected,
375
- body,
376
- });
377
-
378
- // SETS
379
- if (meta.sets.length) {
380
- const install = prepare(
381
- check_native("Set")(input),
382
- meta.sets
383
- .map((elem) => `Set<${elem.getName()}>`)
384
- .join(" | "),
385
- );
386
- if (meta.sets.some((elem) => elem.any)) install(null);
387
- else
388
- install(
389
- explore_sets(project, config, importer)(
390
- input,
391
- meta.sets,
392
- {
393
- ...explore,
394
- from: "array",
395
- },
396
- [],
397
- ),
398
- );
399
- }
400
-
401
- // MAPS
402
- if (meta.maps.length) {
403
- const install = prepare(
404
- check_native("Map")(input),
405
- meta.maps
406
- .map(({ key, value }) => `Map<${key}, ${value}>`)
407
- .join(" | "),
408
- );
409
- if (meta.maps.some((elem) => elem.key.any && elem.value.any))
410
- install(null);
411
- else
412
- install(
413
- explore_maps(project, config, importer)(
414
- input,
415
- meta.maps.map((m) => [m.key, m.value]),
416
- {
417
- ...explore,
418
- from: "array",
419
- },
420
- [],
421
- ),
422
- );
423
- }
424
-
425
- // ARRAYS AND TUPLES
426
- if (meta.tuples.length + meta.arrays.length > 0) {
427
- const install = prepare(
428
- check_array(input, meta.tuples.length === 0 ? tags : []),
429
- [...meta.tuples, ...meta.arrays]
430
- .map((elem) =>
431
- Array.isArray(elem)
432
- ? `[${elem
433
- .map((elem) => elem.getName())
434
- .join(", ")}]`
435
- : `Array<${elem.getName()}>`,
436
- )
437
- .join(" | "),
438
- );
439
- if (meta.arrays.length === 0)
440
- install(
441
- explore_tuples(project, config, importer)(
442
- input,
443
- meta.tuples,
444
- {
445
- ...explore,
446
- from: "array",
447
- },
448
- tags,
449
- ),
450
- );
451
- else if (meta.arrays.some((elem) => elem.any)) install(null);
452
- else if (meta.tuples.length === 0)
453
- // ARRAY ONLY
454
- install(
455
- explore_arrays(project, config, importer)(
456
- input,
457
- meta.arrays,
458
- {
459
- ...explore,
460
- from: "array",
461
- },
462
- tags,
463
- ),
464
- );
465
- else
466
- install(
467
- explore_arrays_and_tuples(project, config, importer)(
468
- input,
469
- [...meta.tuples, ...meta.arrays],
470
- explore,
471
- tags,
472
- ),
473
- );
474
- }
475
-
476
- // OBJECT
477
- if (meta.objects.length > 0)
478
- prepare(
479
- ExpressionFactory.isObject(input, {
480
- checkNull: true,
481
- checkArray: meta.objects.some((obj) =>
482
- obj.properties.every(
483
- (prop) =>
484
- !prop.key.isSoleLiteral() ||
485
- !prop.value.required,
486
- ),
487
- ),
488
- }),
489
- meta.objects
490
- .map((obj) => `Resolve<${obj.name}>`)
491
- .join(" | "),
492
- )(
493
- explore_objects(config)(importer)(input, meta, {
494
- ...explore,
495
- from: "object",
496
- }),
497
- );
498
-
499
- if (instances.length) {
500
- const transformer =
501
- (
502
- merger: (
503
- x: ts.Expression,
504
- y: ts.Expression,
505
- ) => ts.Expression,
506
- ) =>
507
- (ins: IInstance) =>
508
- ins.body
509
- ? {
510
- expression: merger(ins.pre, ins.body),
511
- combined: true,
512
- }
513
- : {
514
- expression: ins.pre,
515
- combined: false,
516
- };
517
- if (instances.length === 1)
518
- binaries.push(
519
- transformer((pre, body) =>
520
- config.combiner(explore)("and")(
521
- input,
522
- [pre, body].map((expression) => ({
523
- expression,
524
- combined: expression !== pre,
525
- })),
526
- meta.getName(),
527
- ),
528
- )(instances[0]!),
529
- );
530
- else
531
- binaries.push({
532
- expression: config.combiner(explore)("or")(
533
- input,
534
- instances.map(
535
- transformer(ts.factory.createLogicalAnd),
536
- ),
537
- meta.getName(),
538
- ),
539
- combined: true,
540
- });
541
- }
542
-
543
- //----
544
- // COMBINE CONDITIONS
545
- //----
546
- return top.length && binaries.length
547
- ? config.combiner(explore)("and")(
548
- input,
549
- [
550
- ...top,
551
- {
552
- expression: config.combiner(explore)("or")(
553
- input,
554
- binaries,
555
- meta.getName(),
556
- ),
557
- combined: true,
558
- },
559
- ],
560
- meta.getName(),
561
- )
562
- : binaries.length
563
- ? config.combiner(explore)("or")(
564
- input,
565
- binaries,
566
- meta.getName(),
567
- )
568
- : config.success;
569
- };
570
- }
571
-
572
- export function decode_tuple(
573
- project: IProject,
574
- config: IConfig,
575
- importer: FunctionImporter,
576
- checkLength: boolean,
577
- ) {
578
- return function (
579
- input: ts.Expression,
580
- tuple: Array<Metadata>,
581
- explore: IExplore,
582
- tagList: IMetadataTag[],
583
- ): ts.Expression {
584
- const binaries: ts.Expression[] = tuple
585
- .filter((meta) => meta.rest === null)
586
- .map((meta, index) =>
587
- decode(project, config, importer)(
588
- ts.factory.createElementAccessExpression(input, index),
589
- meta,
590
- {
591
- ...explore,
592
- from: "array",
593
- postfix: explore.postfix.length
594
- ? `${explore.postfix.slice(0, -1)}[${index}]"`
595
- : `[${index}]`,
596
- },
597
- tagList,
598
- ),
599
- );
600
- const rest: ts.Expression | null =
601
- tuple.length && tuple[tuple.length - 1]!.rest !== null
602
- ? decode(project, config, importer, false)(
603
- ts.factory.createCallExpression(
604
- IdentifierFactory.join(input, "slice"),
605
- undefined,
606
- [
607
- ts.factory.createNumericLiteral(
608
- tuple.length - 1,
609
- ),
610
- ],
611
- ),
612
- (() => {
613
- const wrapper: Metadata = Metadata.initialize();
614
- wrapper.arrays.push(
615
- tuple[tuple.length - 1]!.rest!,
616
- );
617
- return wrapper;
618
- })(),
619
- {
620
- ...explore,
621
- start: tuple.length - 1,
622
- },
623
- tagList,
624
- )
625
- : null;
626
-
627
- return config.combiner(explore)("and")(
628
- input,
629
- [
630
- ...(checkLength && rest === null
631
- ? [
632
- {
633
- combined: false,
634
- expression: ts.factory.createStrictEquality(
635
- ts.factory.createPropertyAccessExpression(
636
- input,
637
- "length",
638
- ),
639
- ts.factory.createNumericLiteral(
640
- tuple.length,
641
- ),
642
- ),
643
- },
644
- ]
645
- : []),
646
- ...(config.joiner.tuple
647
- ? [
648
- {
649
- expression: config.joiner.tuple(binaries),
650
- combined: true,
651
- },
652
- ]
653
- : binaries.map((expression) => ({
654
- expression,
655
- combined: true,
656
- }))),
657
- ...(rest !== null
658
- ? [
659
- {
660
- expression: rest,
661
- combined: true,
662
- },
663
- ]
664
- : []),
665
- ],
666
- `[${tuple.map((t) => t.getName()).join(", ")}]`,
667
- );
668
- };
669
- }
670
-
671
- function decode_array(
672
- project: IProject,
673
- config: IConfig,
674
- importer: FunctionImporter,
675
- checkTupleLength: boolean,
676
- ) {
677
- return FeatureProgrammer.decode_array(
678
- {
679
- trace: config.trace,
680
- path: config.path,
681
- decoder: decode(project, config, importer, checkTupleLength),
682
- },
683
- importer,
684
- config.joiner.array,
685
- );
686
- }
687
-
688
- export const decode_object =
689
- (config: IConfig) => (importer: FunctionImporter) => {
690
- const func = FeatureProgrammer.decode_object(config)(importer);
691
- return function (
692
- input: ts.Expression,
693
- obj: MetadataObject,
694
- explore: IExplore,
695
- ) {
696
- obj.validated = true;
697
- return func(input, obj, explore);
698
- };
699
- };
700
-
701
- const explore_sets = (
702
- project: IProject,
703
- config: IConfig,
704
- importer: FunctionImporter,
705
- ) =>
706
- UnionExplorer.set({
707
- checker: decode(project, config, importer),
708
- decoder: decode_array(project, config, importer, true),
709
- empty: config.success,
710
- success: config.success,
711
- failure: (input, expected, explore) =>
712
- ts.factory.createReturnStatement(
713
- config.joiner.failure(input, expected, explore),
714
- ),
715
- });
716
-
717
- const explore_maps = (
718
- project: IProject,
719
- config: IConfig,
720
- importer: FunctionImporter,
721
- ) =>
722
- UnionExplorer.map({
723
- checker: (input, entry, explore) => {
724
- const func = decode(project, config, importer);
725
- return ts.factory.createLogicalAnd(
726
- func(
727
- ts.factory.createElementAccessExpression(input, 0),
728
- entry[0],
729
- { ...explore, postfix: `${explore.postfix}[0]` },
730
- [],
731
- ),
732
- func(
733
- ts.factory.createElementAccessExpression(input, 1),
734
- entry[1],
735
- { ...explore, postfix: `${explore.postfix}[1]` },
736
- [],
737
- ),
738
- );
739
- },
740
- decoder: (input, target, explore) =>
741
- decode_array(project, config, importer, false)(
742
- input,
743
- Metadata.create({
744
- any: false,
745
- nullable: false,
746
- required: true,
747
- functional: false,
748
- resolved: null,
749
- constants: [],
750
- atomics: [],
751
- templates: [],
752
- rest: null,
753
- arrays: [],
754
- tuples: [target],
755
- objects: [],
756
- natives: [],
757
- sets: [],
758
- maps: [],
759
- }),
760
- explore,
761
- [],
762
- ),
763
- empty: config.success,
764
- success: config.success,
765
- failure: (input, expected, explore) =>
766
- ts.factory.createReturnStatement(
767
- config.joiner.failure(input, expected, explore),
768
- ),
769
- });
770
-
771
- const explore_tuples = (
772
- project: IProject,
773
- config: IConfig,
774
- importer: FunctionImporter,
775
- ) =>
776
- UnionExplorer.tuple({
777
- checker: check_union_tuple(project, config, importer),
778
- decoder: decode_tuple(project, config, importer, true),
779
- empty: config.success,
780
- success: config.success,
781
- failure: (input, expected, explore) =>
782
- ts.factory.createReturnStatement(
783
- config.joiner.failure(input, expected, explore),
784
- ),
785
- });
786
-
787
- const explore_arrays = (
788
- project: IProject,
789
- config: IConfig,
790
- importer: FunctionImporter,
791
- ) =>
792
- UnionExplorer.array({
793
- checker: decode(project, config, importer),
794
- decoder: decode_array(project, config, importer, true),
795
- empty: config.success,
796
- success: config.success,
797
- failure: (input, expected, explore) =>
798
- ts.factory.createReturnStatement(
799
- config.joiner.failure(input, expected, explore),
800
- ),
801
- });
802
-
803
- const explore_arrays_and_tuples = (
804
- project: IProject,
805
- config: IConfig,
806
- importer: FunctionImporter,
807
- ) =>
808
- UnionExplorer.array_or_tuple({
809
- checker: (front, target, explore, tags, array) => {
810
- if (Array.isArray(target))
811
- return check_union_tuple(project, config, importer)(
812
- front,
813
- target,
814
- explore,
815
- tags,
816
- array,
817
- );
818
- const condition = decode(project, config, importer)(
819
- front,
820
- target,
821
- explore,
822
- tags,
823
- );
824
- const length = check_array_length(array, tags);
825
- return length !== null
826
- ? ts.factory.createBitwiseAnd(condition, length)
827
- : condition;
828
- },
829
- decoder: (input, target, explore, tags) =>
830
- Array.isArray(target)
831
- ? decode_tuple(project, config, importer, true)(
832
- input,
833
- target,
834
- explore,
835
- tags,
836
- )
837
- : decode_array(project, config, importer, true)(
838
- input,
839
- target,
840
- explore,
841
- tags,
842
- ),
843
- empty: config.success,
844
- success: config.success,
845
- failure: (input, expected, explore) =>
846
- ts.factory.createReturnStatement(
847
- config.joiner.failure(input, expected, explore),
848
- ),
849
- });
850
-
851
- const explore_objects =
852
- (config: IConfig) => (importer: FunctionImporter) => {
853
- const objector = decode_object(config)(importer);
854
-
855
- return (
856
- input: ts.Expression,
857
- meta: Metadata,
858
- explore: IExplore,
859
- ) => {
860
- if (meta.objects.length === 1)
861
- return objector(input, meta.objects[0]!, explore);
862
-
863
- return ts.factory.createCallExpression(
864
- ts.factory.createIdentifier(
865
- importer.useLocal(
866
- `${config.unioners}${meta.union_index!}`,
867
- ),
868
- ),
869
- undefined,
870
- FeatureProgrammer.get_object_arguments(config)(explore)(
871
- input,
872
- ),
873
- );
874
- };
875
- };
876
- }
877
-
878
- const create_add =
879
- (binaries: CheckerProgrammer.IBinary[]) =>
880
- (defaultInput: ts.Expression) =>
881
- (
882
- exact: boolean,
883
- left: ts.Expression,
884
- right: ts.Expression = defaultInput,
885
- ) => {
886
- const factory = exact
887
- ? ts.factory.createStrictEquality
888
- : ts.factory.createStrictInequality;
889
- binaries.push({
890
- expression: factory(left, right),
891
- combined: false,
892
- });
893
- };
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 { TypeFactory } from "../factories/TypeFactory";
8
+ import { ValueFactory } from "../factories/ValueFactory";
9
+
10
+ import { IMetadataTag } from "../metadata/IMetadataTag";
11
+ import { Metadata } from "../metadata/Metadata";
12
+ import { MetadataObject } from "../metadata/MetadataObject";
13
+
14
+ import { IProject } from "../transformers/IProject";
15
+
16
+ import { FeatureProgrammer } from "./FeatureProgrammer";
17
+ import { AtomicPredicator } from "./helpers/AtomicPredicator";
18
+ import { FunctionImporter } from "./helpers/FunctionImporeter";
19
+ import { IExpressionEntry } from "./helpers/IExpressionEntry";
20
+ import { OptionPredicator } from "./helpers/OptionPredicator";
21
+ import { UnionExplorer } from "./helpers/UnionExplorer";
22
+ import { check_array } from "./internal/check_array";
23
+ import { check_array_length } from "./internal/check_array_length";
24
+ import { check_bigint } from "./internal/check_bigint";
25
+ import { check_native } from "./internal/check_native";
26
+ import { check_number } from "./internal/check_number";
27
+ import { check_string } from "./internal/check_string";
28
+ import { check_template } from "./internal/check_template";
29
+ import { check_union_tuple } from "./internal/check_union_tuple";
30
+ import { decode_union_object } from "./internal/decode_union_object";
31
+
32
+ export namespace CheckerProgrammer {
33
+ export interface IConfig {
34
+ functors: string;
35
+ unioners: string;
36
+ path: boolean;
37
+ trace: boolean;
38
+ equals: boolean;
39
+ numeric: boolean;
40
+ combiner: IConfig.Combiner;
41
+ decoder?: FeatureProgrammer.Decoder<Metadata, ts.Expression>;
42
+ joiner: IConfig.IJoiner;
43
+ success: ts.Expression;
44
+ }
45
+ export namespace IConfig {
46
+ export interface Combiner {
47
+ (explorer: IExplore): {
48
+ (logic: "and" | "or"): {
49
+ (
50
+ input: ts.Expression,
51
+ binaries: IBinary[],
52
+ expected: string,
53
+ ): ts.Expression;
54
+ };
55
+ };
56
+ }
57
+ export interface IJoiner {
58
+ object(
59
+ input: ts.Expression,
60
+ entries: IExpressionEntry[],
61
+ ): ts.Expression;
62
+ array(input: ts.Expression, arrow: ts.ArrowFunction): ts.Expression;
63
+ tuple?(exprs: ts.Expression[]): ts.Expression;
64
+
65
+ failure(
66
+ value: ts.Expression,
67
+ expected: string,
68
+ explore?: FeatureProgrammer.IExplore,
69
+ ): ts.Expression;
70
+ is?(expression: ts.Expression): ts.Expression;
71
+ required?(exp: ts.Expression): ts.Expression;
72
+ full?: (
73
+ condition: ts.Expression,
74
+ ) => (
75
+ input: ts.Expression,
76
+ expected: string,
77
+ explore: IExplore,
78
+ ) => ts.Expression;
79
+ }
80
+ }
81
+ export import IExplore = FeatureProgrammer.IExplore;
82
+
83
+ export interface IBinary {
84
+ expression: ts.Expression;
85
+ combined: boolean;
86
+ }
87
+
88
+ /* -----------------------------------------------------------
89
+ GENERATORS
90
+ ----------------------------------------------------------- */
91
+ export function generate(
92
+ project: IProject,
93
+ config: IConfig,
94
+ importer: FunctionImporter,
95
+ addition?: () => ts.Statement[],
96
+ ) {
97
+ return FeatureProgrammer.generate(
98
+ project,
99
+ CONFIG(project, config, importer),
100
+ importer,
101
+ () => (addition ? (addition ? addition() : []) : undefined),
102
+ );
103
+ }
104
+
105
+ export const generate_functors = (
106
+ project: IProject,
107
+ config: IConfig,
108
+ importer: FunctionImporter,
109
+ ) =>
110
+ FeatureProgrammer.generate_functors(CONFIG(project, config, importer))(
111
+ importer,
112
+ );
113
+
114
+ export const generate_unioners = (
115
+ project: IProject,
116
+ config: IConfig,
117
+ importer: FunctionImporter,
118
+ ) =>
119
+ FeatureProgrammer.generate_unioners(
120
+ CONFIG(project, { ...config, numeric: false }, importer),
121
+ )(importer);
122
+
123
+ function CONFIG(
124
+ project: IProject,
125
+ config: IConfig,
126
+ importer: FunctionImporter,
127
+ ): FeatureProgrammer.IConfig {
128
+ const output: FeatureProgrammer.IConfig = {
129
+ types: {
130
+ input: () => TypeFactory.keyword("any"),
131
+ output: (type, name) =>
132
+ ts.factory.createTypePredicateNode(
133
+ undefined,
134
+ "input",
135
+ ts.factory.createTypeReferenceNode(
136
+ name ??
137
+ TypeFactory.getFullName(project.checker, type),
138
+ ),
139
+ ),
140
+ },
141
+ trace: config.trace,
142
+ path: config.path,
143
+ functors: config.functors,
144
+ unioners: config.unioners,
145
+ initializer: ({ checker }, type) => {
146
+ const collection: MetadataCollection = new MetadataCollection();
147
+ const meta: Metadata = MetadataFactory.generate(
148
+ checker,
149
+ collection,
150
+ type,
151
+ {
152
+ resolve: false,
153
+ constant: true,
154
+ },
155
+ );
156
+ return [collection, meta];
157
+ },
158
+ decoder: config.decoder || decode(project, config, importer),
159
+ objector: {
160
+ checker: config.decoder || decode(project, config, importer),
161
+ decoder: decode_object(config)(importer),
162
+ joiner: config.joiner.object,
163
+ unionizer: config.equals
164
+ ? decode_union_object(decode_object(config)(importer))(
165
+ (input, obj, explore) =>
166
+ decode_object(config)(importer)(input, obj, {
167
+ ...explore,
168
+ tracable: true,
169
+ }),
170
+ )(config.joiner.is || ((expr) => expr))(
171
+ (value, expected) =>
172
+ ts.factory.createReturnStatement(
173
+ config.joiner.failure(value, expected),
174
+ ),
175
+ )
176
+ : (input, targets, explore) =>
177
+ config.combiner(explore)("or")(
178
+ input,
179
+ targets.map((obj) => ({
180
+ expression: decode_object(config)(importer)(
181
+ input,
182
+ obj,
183
+ explore,
184
+ ),
185
+ combined: true,
186
+ })),
187
+ `(${targets.map((t) => t.name).join(" | ")})`,
188
+ ),
189
+ failure: (value, expected) =>
190
+ ts.factory.createReturnStatement(
191
+ config.joiner.failure(value, expected),
192
+ ),
193
+ is: config.joiner.is,
194
+ required: config.joiner.required,
195
+ full: config.joiner.full,
196
+ type: TypeFactory.keyword("boolean"),
197
+ },
198
+ };
199
+ if (config.numeric === true)
200
+ output.generator = {
201
+ unioners: FeatureProgrammer.generate_unioners(
202
+ CONFIG(project, { ...config, numeric: false }, importer),
203
+ )(importer),
204
+ };
205
+ return output;
206
+ }
207
+
208
+ /* -----------------------------------------------------------
209
+ DECODERS
210
+ ----------------------------------------------------------- */
211
+ export function decode(
212
+ project: IProject,
213
+ config: IConfig,
214
+ importer: FunctionImporter,
215
+ ): (
216
+ input: ts.Expression,
217
+ meta: Metadata,
218
+ explore: IExplore,
219
+ tags: IMetadataTag[],
220
+ ) => ts.Expression;
221
+
222
+ /**
223
+ * @internal
224
+ */
225
+ export function decode(
226
+ project: IProject,
227
+ config: IConfig,
228
+ importer: FunctionImporter,
229
+ checkTupleLength: boolean,
230
+ ): (
231
+ input: ts.Expression,
232
+ meta: Metadata,
233
+ explore: IExplore,
234
+ tags: IMetadataTag[],
235
+ ) => ts.Expression;
236
+
237
+ /**
238
+ * @internal
239
+ */
240
+ export function decode(
241
+ project: IProject,
242
+ config: IConfig,
243
+ importer: FunctionImporter,
244
+ ) {
245
+ return function (
246
+ input: ts.Expression,
247
+ meta: Metadata,
248
+ explore: IExplore,
249
+ tags: IMetadataTag[],
250
+ ): ts.Expression {
251
+ if (meta.any) return config.success;
252
+
253
+ const top: IBinary[] = [];
254
+ const binaries: IBinary[] = [];
255
+ const add = create_add(binaries)(input);
256
+ const getConstantValue = (
257
+ value: number | string | bigint | boolean,
258
+ ) =>
259
+ typeof value === "string"
260
+ ? ts.factory.createStringLiteral(value)
261
+ : ts.factory.createIdentifier(value.toString());
262
+
263
+ //----
264
+ // CHECK OPTIONAL
265
+ //----
266
+ // @todo -> should be elaborated
267
+ const checkOptional: boolean = meta.empty() || meta.isUnionBucket();
268
+
269
+ // NULLABLE
270
+ if (
271
+ checkOptional ||
272
+ meta.nullable
273
+ // || (meta.objects.length && meta.size() !== meta.objects.length)
274
+ )
275
+ (meta.nullable ? add : create_add(top)(input))(
276
+ meta.nullable,
277
+ ValueFactory.NULL(),
278
+ );
279
+
280
+ // UNDEFINDABLE
281
+ if (checkOptional || !meta.required)
282
+ (meta.required ? create_add(top)(input) : add)(
283
+ !meta.required,
284
+ ValueFactory.UNDEFINED(),
285
+ );
286
+
287
+ // FUNCTIONAL
288
+ if (meta.functional === true)
289
+ if (
290
+ OptionPredicator.functional(project.options) ||
291
+ meta.size() !== 1
292
+ )
293
+ add(
294
+ true,
295
+ ts.factory.createStringLiteral("function"),
296
+ ValueFactory.TYPEOF(input),
297
+ );
298
+ else
299
+ binaries.push({
300
+ combined: false,
301
+ expression: config.success,
302
+ });
303
+
304
+ //----
305
+ // VALUES
306
+ //----
307
+ // CONSTANT VALUES
308
+ for (const constant of meta.constants)
309
+ if (AtomicPredicator.constant(meta)(constant.type))
310
+ for (const val of constant.values)
311
+ add(true, getConstantValue(val));
312
+
313
+ // ATOMIC VALUES
314
+ for (const type of meta.atomics)
315
+ if (AtomicPredicator.atomic(meta)(type) === false) continue;
316
+ else if (type === "number")
317
+ binaries.push({
318
+ expression: check_number(project, config.numeric)(
319
+ input,
320
+ tags,
321
+ ),
322
+ combined: false,
323
+ });
324
+ else if (type === "bigint")
325
+ binaries.push({
326
+ expression: check_bigint(input, tags),
327
+ combined: false,
328
+ });
329
+ else if (type === "string")
330
+ binaries.push({
331
+ expression: check_string(importer)(input, tags),
332
+ combined: false,
333
+ });
334
+ else
335
+ add(
336
+ true,
337
+ ts.factory.createStringLiteral(type),
338
+ ValueFactory.TYPEOF(input),
339
+ );
340
+
341
+ // TEMPLATE LITERAL VALUES
342
+ if (meta.templates.length)
343
+ if (AtomicPredicator.template(meta))
344
+ binaries.push({
345
+ expression: check_template(importer)(
346
+ input,
347
+ meta.templates,
348
+ tags,
349
+ ),
350
+ combined: false,
351
+ });
352
+
353
+ // NATIVE CLASSES
354
+ for (const native of meta.natives)
355
+ binaries.push({
356
+ expression: check_native(native)(input),
357
+ combined: false,
358
+ });
359
+
360
+ //----
361
+ // INSTANCES
362
+ //----
363
+ interface IInstance {
364
+ pre: ts.Expression;
365
+ body: ts.Expression | null;
366
+ expected: string;
367
+ }
368
+ const instances: IInstance[] = [];
369
+ const prepare =
370
+ (pre: ts.Expression, expected: string) =>
371
+ (body: ts.Expression | null) =>
372
+ instances.push({
373
+ pre,
374
+ expected,
375
+ body,
376
+ });
377
+
378
+ // SETS
379
+ if (meta.sets.length) {
380
+ const install = prepare(
381
+ check_native("Set")(input),
382
+ meta.sets
383
+ .map((elem) => `Set<${elem.getName()}>`)
384
+ .join(" | "),
385
+ );
386
+ if (meta.sets.some((elem) => elem.any)) install(null);
387
+ else
388
+ install(
389
+ explore_sets(project, config, importer)(
390
+ input,
391
+ meta.sets,
392
+ {
393
+ ...explore,
394
+ from: "array",
395
+ },
396
+ [],
397
+ ),
398
+ );
399
+ }
400
+
401
+ // MAPS
402
+ if (meta.maps.length) {
403
+ const install = prepare(
404
+ check_native("Map")(input),
405
+ meta.maps
406
+ .map(({ key, value }) => `Map<${key}, ${value}>`)
407
+ .join(" | "),
408
+ );
409
+ if (meta.maps.some((elem) => elem.key.any && elem.value.any))
410
+ install(null);
411
+ else
412
+ install(
413
+ explore_maps(project, config, importer)(
414
+ input,
415
+ meta.maps.map((m) => [m.key, m.value]),
416
+ {
417
+ ...explore,
418
+ from: "array",
419
+ },
420
+ [],
421
+ ),
422
+ );
423
+ }
424
+
425
+ // ARRAYS AND TUPLES
426
+ if (meta.tuples.length + meta.arrays.length > 0) {
427
+ const install = prepare(
428
+ check_array(input, meta.tuples.length === 0 ? tags : []),
429
+ [...meta.tuples, ...meta.arrays]
430
+ .map((elem) =>
431
+ Array.isArray(elem)
432
+ ? `[${elem
433
+ .map((elem) => elem.getName())
434
+ .join(", ")}]`
435
+ : `Array<${elem.getName()}>`,
436
+ )
437
+ .join(" | "),
438
+ );
439
+ if (meta.arrays.length === 0)
440
+ install(
441
+ explore_tuples(project, config, importer)(
442
+ input,
443
+ meta.tuples,
444
+ {
445
+ ...explore,
446
+ from: "array",
447
+ },
448
+ tags,
449
+ ),
450
+ );
451
+ else if (meta.arrays.some((elem) => elem.any)) install(null);
452
+ else if (meta.tuples.length === 0)
453
+ // ARRAY ONLY
454
+ install(
455
+ explore_arrays(project, config, importer)(
456
+ input,
457
+ meta.arrays,
458
+ {
459
+ ...explore,
460
+ from: "array",
461
+ },
462
+ tags,
463
+ ),
464
+ );
465
+ else
466
+ install(
467
+ explore_arrays_and_tuples(project, config, importer)(
468
+ input,
469
+ [...meta.tuples, ...meta.arrays],
470
+ explore,
471
+ tags,
472
+ ),
473
+ );
474
+ }
475
+
476
+ // OBJECT
477
+ if (meta.objects.length > 0)
478
+ prepare(
479
+ ExpressionFactory.isObject(input, {
480
+ checkNull: true,
481
+ checkArray: meta.objects.some((obj) =>
482
+ obj.properties.every(
483
+ (prop) =>
484
+ !prop.key.isSoleLiteral() ||
485
+ !prop.value.required,
486
+ ),
487
+ ),
488
+ }),
489
+ meta.objects
490
+ .map((obj) => `Resolve<${obj.name}>`)
491
+ .join(" | "),
492
+ )(
493
+ explore_objects(config)(importer)(input, meta, {
494
+ ...explore,
495
+ from: "object",
496
+ }),
497
+ );
498
+
499
+ if (instances.length) {
500
+ const transformer =
501
+ (
502
+ merger: (
503
+ x: ts.Expression,
504
+ y: ts.Expression,
505
+ ) => ts.Expression,
506
+ ) =>
507
+ (ins: IInstance) =>
508
+ ins.body
509
+ ? {
510
+ expression: merger(ins.pre, ins.body),
511
+ combined: true,
512
+ }
513
+ : {
514
+ expression: ins.pre,
515
+ combined: false,
516
+ };
517
+ if (instances.length === 1)
518
+ binaries.push(
519
+ transformer((pre, body) =>
520
+ config.combiner(explore)("and")(
521
+ input,
522
+ [pre, body].map((expression) => ({
523
+ expression,
524
+ combined: expression !== pre,
525
+ })),
526
+ meta.getName(),
527
+ ),
528
+ )(instances[0]!),
529
+ );
530
+ else
531
+ binaries.push({
532
+ expression: config.combiner(explore)("or")(
533
+ input,
534
+ instances.map(
535
+ transformer(ts.factory.createLogicalAnd),
536
+ ),
537
+ meta.getName(),
538
+ ),
539
+ combined: true,
540
+ });
541
+ }
542
+
543
+ //----
544
+ // COMBINE CONDITIONS
545
+ //----
546
+ return top.length && binaries.length
547
+ ? config.combiner(explore)("and")(
548
+ input,
549
+ [
550
+ ...top,
551
+ {
552
+ expression: config.combiner(explore)("or")(
553
+ input,
554
+ binaries,
555
+ meta.getName(),
556
+ ),
557
+ combined: true,
558
+ },
559
+ ],
560
+ meta.getName(),
561
+ )
562
+ : binaries.length
563
+ ? config.combiner(explore)("or")(
564
+ input,
565
+ binaries,
566
+ meta.getName(),
567
+ )
568
+ : config.success;
569
+ };
570
+ }
571
+
572
+ export function decode_tuple(
573
+ project: IProject,
574
+ config: IConfig,
575
+ importer: FunctionImporter,
576
+ checkLength: boolean,
577
+ ) {
578
+ return function (
579
+ input: ts.Expression,
580
+ tuple: Array<Metadata>,
581
+ explore: IExplore,
582
+ tagList: IMetadataTag[],
583
+ ): ts.Expression {
584
+ const binaries: ts.Expression[] = tuple
585
+ .filter((meta) => meta.rest === null)
586
+ .map((meta, index) =>
587
+ decode(project, config, importer)(
588
+ ts.factory.createElementAccessExpression(input, index),
589
+ meta,
590
+ {
591
+ ...explore,
592
+ from: "array",
593
+ postfix: explore.postfix.length
594
+ ? `${explore.postfix.slice(0, -1)}[${index}]"`
595
+ : `[${index}]`,
596
+ },
597
+ tagList,
598
+ ),
599
+ );
600
+ const rest: ts.Expression | null =
601
+ tuple.length && tuple[tuple.length - 1]!.rest !== null
602
+ ? decode(project, config, importer, false)(
603
+ ts.factory.createCallExpression(
604
+ IdentifierFactory.join(input, "slice"),
605
+ undefined,
606
+ [
607
+ ts.factory.createNumericLiteral(
608
+ tuple.length - 1,
609
+ ),
610
+ ],
611
+ ),
612
+ (() => {
613
+ const wrapper: Metadata = Metadata.initialize();
614
+ wrapper.arrays.push(
615
+ tuple[tuple.length - 1]!.rest!,
616
+ );
617
+ return wrapper;
618
+ })(),
619
+ {
620
+ ...explore,
621
+ start: tuple.length - 1,
622
+ },
623
+ tagList,
624
+ )
625
+ : null;
626
+
627
+ return config.combiner(explore)("and")(
628
+ input,
629
+ [
630
+ ...(checkLength && rest === null
631
+ ? [
632
+ {
633
+ combined: false,
634
+ expression: ts.factory.createStrictEquality(
635
+ ts.factory.createPropertyAccessExpression(
636
+ input,
637
+ "length",
638
+ ),
639
+ ts.factory.createNumericLiteral(
640
+ tuple.length,
641
+ ),
642
+ ),
643
+ },
644
+ ]
645
+ : []),
646
+ ...(config.joiner.tuple
647
+ ? [
648
+ {
649
+ expression: config.joiner.tuple(binaries),
650
+ combined: true,
651
+ },
652
+ ]
653
+ : binaries.map((expression) => ({
654
+ expression,
655
+ combined: true,
656
+ }))),
657
+ ...(rest !== null
658
+ ? [
659
+ {
660
+ expression: rest,
661
+ combined: true,
662
+ },
663
+ ]
664
+ : []),
665
+ ],
666
+ `[${tuple.map((t) => t.getName()).join(", ")}]`,
667
+ );
668
+ };
669
+ }
670
+
671
+ function decode_array(
672
+ project: IProject,
673
+ config: IConfig,
674
+ importer: FunctionImporter,
675
+ checkTupleLength: boolean,
676
+ ) {
677
+ return FeatureProgrammer.decode_array(
678
+ {
679
+ trace: config.trace,
680
+ path: config.path,
681
+ decoder: decode(project, config, importer, checkTupleLength),
682
+ },
683
+ importer,
684
+ config.joiner.array,
685
+ );
686
+ }
687
+
688
+ export const decode_object =
689
+ (config: IConfig) => (importer: FunctionImporter) => {
690
+ const func = FeatureProgrammer.decode_object(config)(importer);
691
+ return function (
692
+ input: ts.Expression,
693
+ obj: MetadataObject,
694
+ explore: IExplore,
695
+ ) {
696
+ obj.validated = true;
697
+ return func(input, obj, explore);
698
+ };
699
+ };
700
+
701
+ const explore_sets = (
702
+ project: IProject,
703
+ config: IConfig,
704
+ importer: FunctionImporter,
705
+ ) =>
706
+ UnionExplorer.set({
707
+ checker: decode(project, config, importer),
708
+ decoder: decode_array(project, config, importer, true),
709
+ empty: config.success,
710
+ success: config.success,
711
+ failure: (input, expected, explore) =>
712
+ ts.factory.createReturnStatement(
713
+ config.joiner.failure(input, expected, explore),
714
+ ),
715
+ });
716
+
717
+ const explore_maps = (
718
+ project: IProject,
719
+ config: IConfig,
720
+ importer: FunctionImporter,
721
+ ) =>
722
+ UnionExplorer.map({
723
+ checker: (input, entry, explore) => {
724
+ const func = decode(project, config, importer);
725
+ return ts.factory.createLogicalAnd(
726
+ func(
727
+ ts.factory.createElementAccessExpression(input, 0),
728
+ entry[0],
729
+ { ...explore, postfix: `${explore.postfix}[0]` },
730
+ [],
731
+ ),
732
+ func(
733
+ ts.factory.createElementAccessExpression(input, 1),
734
+ entry[1],
735
+ { ...explore, postfix: `${explore.postfix}[1]` },
736
+ [],
737
+ ),
738
+ );
739
+ },
740
+ decoder: (input, target, explore) =>
741
+ decode_array(project, config, importer, false)(
742
+ input,
743
+ Metadata.create({
744
+ any: false,
745
+ nullable: false,
746
+ required: true,
747
+ functional: false,
748
+ resolved: null,
749
+ constants: [],
750
+ atomics: [],
751
+ templates: [],
752
+ rest: null,
753
+ arrays: [],
754
+ tuples: [target],
755
+ objects: [],
756
+ natives: [],
757
+ sets: [],
758
+ maps: [],
759
+ }),
760
+ explore,
761
+ [],
762
+ ),
763
+ empty: config.success,
764
+ success: config.success,
765
+ failure: (input, expected, explore) =>
766
+ ts.factory.createReturnStatement(
767
+ config.joiner.failure(input, expected, explore),
768
+ ),
769
+ });
770
+
771
+ const explore_tuples = (
772
+ project: IProject,
773
+ config: IConfig,
774
+ importer: FunctionImporter,
775
+ ) =>
776
+ UnionExplorer.tuple({
777
+ checker: check_union_tuple(project, config, importer),
778
+ decoder: decode_tuple(project, config, importer, true),
779
+ empty: config.success,
780
+ success: config.success,
781
+ failure: (input, expected, explore) =>
782
+ ts.factory.createReturnStatement(
783
+ config.joiner.failure(input, expected, explore),
784
+ ),
785
+ });
786
+
787
+ const explore_arrays = (
788
+ project: IProject,
789
+ config: IConfig,
790
+ importer: FunctionImporter,
791
+ ) =>
792
+ UnionExplorer.array({
793
+ checker: decode(project, config, importer),
794
+ decoder: decode_array(project, config, importer, true),
795
+ empty: config.success,
796
+ success: config.success,
797
+ failure: (input, expected, explore) =>
798
+ ts.factory.createReturnStatement(
799
+ config.joiner.failure(input, expected, explore),
800
+ ),
801
+ });
802
+
803
+ const explore_arrays_and_tuples = (
804
+ project: IProject,
805
+ config: IConfig,
806
+ importer: FunctionImporter,
807
+ ) =>
808
+ UnionExplorer.array_or_tuple({
809
+ checker: (front, target, explore, tags, array) => {
810
+ if (Array.isArray(target))
811
+ return check_union_tuple(project, config, importer)(
812
+ front,
813
+ target,
814
+ explore,
815
+ tags,
816
+ array,
817
+ );
818
+ const condition = decode(project, config, importer)(
819
+ front,
820
+ target,
821
+ explore,
822
+ tags,
823
+ );
824
+ const length = check_array_length(array, tags);
825
+ return length !== null
826
+ ? ts.factory.createBitwiseAnd(condition, length)
827
+ : condition;
828
+ },
829
+ decoder: (input, target, explore, tags) =>
830
+ Array.isArray(target)
831
+ ? decode_tuple(project, config, importer, true)(
832
+ input,
833
+ target,
834
+ explore,
835
+ tags,
836
+ )
837
+ : decode_array(project, config, importer, true)(
838
+ input,
839
+ target,
840
+ explore,
841
+ tags,
842
+ ),
843
+ empty: config.success,
844
+ success: config.success,
845
+ failure: (input, expected, explore) =>
846
+ ts.factory.createReturnStatement(
847
+ config.joiner.failure(input, expected, explore),
848
+ ),
849
+ });
850
+
851
+ const explore_objects =
852
+ (config: IConfig) => (importer: FunctionImporter) => {
853
+ const objector = decode_object(config)(importer);
854
+
855
+ return (
856
+ input: ts.Expression,
857
+ meta: Metadata,
858
+ explore: IExplore,
859
+ ) => {
860
+ if (meta.objects.length === 1)
861
+ return objector(input, meta.objects[0]!, explore);
862
+
863
+ return ts.factory.createCallExpression(
864
+ ts.factory.createIdentifier(
865
+ importer.useLocal(
866
+ `${config.unioners}${meta.union_index!}`,
867
+ ),
868
+ ),
869
+ undefined,
870
+ FeatureProgrammer.get_object_arguments(config)(explore)(
871
+ input,
872
+ ),
873
+ );
874
+ };
875
+ };
876
+ }
877
+
878
+ const create_add =
879
+ (binaries: CheckerProgrammer.IBinary[]) =>
880
+ (defaultInput: ts.Expression) =>
881
+ (
882
+ exact: boolean,
883
+ left: ts.Expression,
884
+ right: ts.Expression = defaultInput,
885
+ ) => {
886
+ const factory = exact
887
+ ? ts.factory.createStrictEquality
888
+ : ts.factory.createStrictInequality;
889
+ binaries.push({
890
+ expression: factory(left, right),
891
+ combined: false,
892
+ });
893
+ };