typia 6.7.1 → 6.7.2-dev.20240805-2

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.
@@ -1,951 +1,951 @@
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 { TemplateFactory } from "../factories/TemplateFactory";
9
- import { TypeFactory } from "../factories/TypeFactory";
10
-
11
- import { Metadata } from "../schemas/metadata/Metadata";
12
- import { MetadataArray } from "../schemas/metadata/MetadataArray";
13
- import { MetadataArrayType } from "../schemas/metadata/MetadataArrayType";
14
- import { MetadataAtomic } from "../schemas/metadata/MetadataAtomic";
15
- import { MetadataObject } from "../schemas/metadata/MetadataObject";
16
- import { MetadataTemplate } from "../schemas/metadata/MetadataTemplate";
17
- import { MetadataTuple } from "../schemas/metadata/MetadataTuple";
18
- import { MetadataTupleType } from "../schemas/metadata/MetadataTupleType";
19
-
20
- import { IProject } from "../transformers/IProject";
21
- import { TransformerError } from "../transformers/TransformerError";
22
-
23
- import { Escaper } from "../utils/Escaper";
24
-
25
- import { Format } from "../tags";
26
- import { FeatureProgrammer } from "./FeatureProgrammer";
27
- import { FunctionImporter } from "./helpers/FunctionImporter";
28
- import { RandomJoiner } from "./helpers/RandomJoiner";
29
- import { RandomRanger } from "./helpers/RandomRanger";
30
- import { random_custom } from "./internal/random_custom";
31
-
32
- export namespace RandomProgrammer {
33
- export const decompose = (props: {
34
- project: IProject;
35
- importer: FunctionImporter;
36
- type: ts.Type;
37
- name: string | undefined;
38
- init: ts.Expression | undefined;
39
- }): FeatureProgrammer.IDecomposed => {
40
- const collection: MetadataCollection = new MetadataCollection();
41
- const result = MetadataFactory.analyze(
42
- props.project.checker,
43
- props.project.context,
44
- )({
45
- escape: false,
46
- constant: true,
47
- absorb: true,
48
- validate: (meta) => {
49
- const output: string[] = [];
50
- if (meta.natives.some((n) => n === "WeakSet"))
51
- output.push(`WeakSet is not supported.`);
52
- else if (meta.natives.some((n) => n === "WeakMap"))
53
- output.push(`WeakMap is not supported.`);
54
- return output;
55
- },
56
- })(collection)(props.type);
57
- if (result.success === false)
58
- throw TransformerError.from(`typia.${props.importer.method}`)(
59
- result.errors,
60
- );
61
-
62
- // GENERATE FUNCTION
63
- const functions: Record<string, ts.VariableStatement> = Object.fromEntries([
64
- ...write_object_functions(props.importer)(collection).map((v, i) => [
65
- Prefix.object(i),
66
- v,
67
- ]),
68
- ...write_array_functions(props.importer)(collection).map((v, i) => [
69
- Prefix.array(i),
70
- v,
71
- ]),
72
- ...write_tuple_functions(props.importer)(collection).map((v, i) => [
73
- Prefix.tuple(i),
74
- v,
75
- ]),
76
- ]);
77
- const arrow: ts.ArrowFunction = ts.factory.createArrowFunction(
78
- undefined,
79
- undefined,
80
- [
81
- IdentifierFactory.parameter(
82
- "generator",
83
- ts.factory.createTypeReferenceNode("Partial<typia.IRandomGenerator>"),
84
- props.init ?? ts.factory.createToken(ts.SyntaxKind.QuestionToken),
85
- ),
86
- ],
87
- ts.factory.createImportTypeNode(
88
- ts.factory.createLiteralTypeNode(
89
- ts.factory.createStringLiteral("typia"),
90
- ),
91
- undefined,
92
- ts.factory.createIdentifier("Resolved"),
93
- [
94
- ts.factory.createTypeReferenceNode(
95
- props.name ??
96
- TypeFactory.getFullName(props.project.checker)(props.type),
97
- ),
98
- ],
99
- false,
100
- ),
101
- undefined,
102
- ts.factory.createBlock(
103
- [
104
- ts.factory.createExpressionStatement(
105
- ts.factory.createBinaryExpression(
106
- ts.factory.createIdentifier("_generator"),
107
- ts.SyntaxKind.EqualsToken,
108
- ts.factory.createIdentifier("generator"),
109
- ),
110
- ),
111
- ts.factory.createReturnStatement(
112
- decode(props.importer)({
113
- function: false,
114
- recursive: false,
115
- })(result.data),
116
- ),
117
- ],
118
- true,
119
- ),
120
- );
121
- return {
122
- functions,
123
- statements: [StatementFactory.mut("_generator")],
124
- arrow,
125
- };
126
- };
127
-
128
- export const write =
129
- (project: IProject) =>
130
- (modulo: ts.LeftHandSideExpression) =>
131
- (init?: ts.Expression) =>
132
- (type: ts.Type, name?: string) => {
133
- const importer: FunctionImporter = new FunctionImporter(modulo.getText());
134
- const result: FeatureProgrammer.IDecomposed = decompose({
135
- project,
136
- importer,
137
- type,
138
- name,
139
- init,
140
- });
141
- return FeatureProgrammer.writeDecomposed({
142
- modulo,
143
- importer,
144
- result,
145
- });
146
- };
147
-
148
- const write_object_functions =
149
- (importer: FunctionImporter) =>
150
- (collection: MetadataCollection): ts.VariableStatement[] =>
151
- collection.objects().map((obj, i) =>
152
- StatementFactory.constant(
153
- Prefix.object(i),
154
- ts.factory.createArrowFunction(
155
- undefined,
156
- undefined,
157
- [
158
- IdentifierFactory.parameter(
159
- "_recursive",
160
- TypeFactory.keyword("boolean"),
161
- ts.factory.createIdentifier(String(obj.recursive)),
162
- ),
163
- IdentifierFactory.parameter(
164
- "_depth",
165
- TypeFactory.keyword("number"),
166
- ExpressionFactory.number(0),
167
- ),
168
- ],
169
- TypeFactory.keyword("any"),
170
- undefined,
171
- RandomJoiner.object(COALESCE(importer))(
172
- decode(importer)({
173
- recursive: obj.recursive,
174
- function: true,
175
- }),
176
- )(obj),
177
- ),
178
- ),
179
- );
180
-
181
- const write_array_functions =
182
- (importer: FunctionImporter) =>
183
- (collection: MetadataCollection): ts.VariableStatement[] =>
184
- collection
185
- .arrays()
186
- .filter((a) => a.recursive)
187
- .map((array, i) =>
188
- StatementFactory.constant(
189
- Prefix.array(i),
190
- ts.factory.createArrowFunction(
191
- undefined,
192
- undefined,
193
- [
194
- IdentifierFactory.parameter(
195
- "length",
196
- TypeFactory.keyword("number"),
197
- ),
198
- IdentifierFactory.parameter(
199
- "unique",
200
- TypeFactory.keyword("boolean"),
201
- ),
202
- IdentifierFactory.parameter(
203
- "_recursive",
204
- TypeFactory.keyword("boolean"),
205
- ts.factory.createTrue(),
206
- ),
207
- IdentifierFactory.parameter(
208
- "_depth",
209
- TypeFactory.keyword("number"),
210
- ExpressionFactory.number(0),
211
- ),
212
- ],
213
- TypeFactory.keyword("any"),
214
- undefined,
215
- RandomJoiner.array(COALESCE(importer))(
216
- decode(importer)({
217
- recursive: true,
218
- function: true,
219
- }),
220
- )({
221
- recursive: true,
222
- function: true,
223
- })(
224
- ts.factory.createIdentifier("length"),
225
- ts.factory.createIdentifier("unique"),
226
- )(array.value),
227
- ),
228
- ),
229
- );
230
-
231
- const write_tuple_functions =
232
- (importer: FunctionImporter) =>
233
- (collection: MetadataCollection): ts.VariableStatement[] =>
234
- collection
235
- .tuples()
236
- .filter((a) => a.recursive)
237
- .map((tuple, i) =>
238
- StatementFactory.constant(
239
- Prefix.tuple(i),
240
- ts.factory.createArrowFunction(
241
- undefined,
242
- undefined,
243
- [
244
- IdentifierFactory.parameter(
245
- "_recursive",
246
- TypeFactory.keyword("boolean"),
247
- ts.factory.createTrue(),
248
- ),
249
- IdentifierFactory.parameter(
250
- "_depth",
251
- TypeFactory.keyword("number"),
252
- ExpressionFactory.number(0),
253
- ),
254
- ],
255
- TypeFactory.keyword("any"),
256
- undefined,
257
- RandomJoiner.tuple(
258
- decode(importer)({
259
- function: true,
260
- recursive: true,
261
- }),
262
- )(tuple.elements),
263
- ),
264
- ),
265
- );
266
-
267
- /* -----------------------------------------------------------
268
- DECODERS
269
- ----------------------------------------------------------- */
270
- const decode =
271
- (importer: FunctionImporter) =>
272
- (explore: IExplore) =>
273
- (meta: Metadata): ts.Expression => {
274
- const expressions: ts.Expression[] = [];
275
- if (meta.any)
276
- expressions.push(ts.factory.createStringLiteral("any type used..."));
277
-
278
- // NULL COALESCING
279
- if (meta.isRequired() === false || meta.functional === true)
280
- expressions.push(ts.factory.createIdentifier("undefined"));
281
- if (meta.nullable === true) expressions.push(ts.factory.createNull());
282
-
283
- // CONSTANT TYPES
284
- for (const constant of meta.constants)
285
- for (const { value } of constant.values)
286
- expressions.push(decode_atomic(value));
287
-
288
- // ATOMIC VARIABLES
289
- for (const template of meta.templates)
290
- expressions.push(decode_template(importer)(explore)(template));
291
- for (const atomic of meta.atomics)
292
- if (atomic.type === "boolean")
293
- expressions.push(decode_boolean(importer));
294
- else if (atomic.type === "number")
295
- expressions.push(...decode_number(importer)(atomic));
296
- else if (atomic.type === "string")
297
- expressions.push(...decode_string(importer)(atomic));
298
- else if (atomic.type === "bigint")
299
- expressions.push(...decode_bigint(importer)(atomic));
300
-
301
- // INSTANCE TYPES
302
- if (meta.escaped)
303
- expressions.push(decode(importer)(explore)(meta.escaped.returns));
304
- for (const array of meta.arrays)
305
- expressions.push(...decode_array(importer)(explore)(array));
306
- for (const tuple of meta.tuples)
307
- expressions.push(decode_tuple(importer)(explore)(tuple));
308
- for (const o of meta.objects)
309
- expressions.push(decode_object(importer)(explore)(o));
310
- for (const native of meta.natives)
311
- expressions.push(decode_native(importer)(native));
312
- for (const set of meta.sets)
313
- expressions.push(decode_set(importer)(explore)(set));
314
- for (const map of meta.maps)
315
- expressions.push(decode_map(importer)(explore)(map));
316
-
317
- // PICK UP A TYPE
318
- if (expressions.length === 1) return expressions[0]!;
319
- return ts.factory.createCallExpression(
320
- ts.factory.createCallExpression(importer.use("pick"), undefined, [
321
- ts.factory.createArrayLiteralExpression(
322
- expressions.map((expr) =>
323
- ts.factory.createArrowFunction(
324
- undefined,
325
- undefined,
326
- [],
327
- undefined,
328
- undefined,
329
- expr,
330
- ),
331
- ),
332
- true,
333
- ),
334
- ]),
335
- undefined,
336
- undefined,
337
- );
338
- };
339
-
340
- const decode_boolean = (importer: FunctionImporter) =>
341
- ts.factory.createCallExpression(
342
- COALESCE(importer)("boolean"),
343
- undefined,
344
- undefined,
345
- );
346
-
347
- const decode_atomic = (value: Atomic) =>
348
- typeof value === "boolean"
349
- ? ts.factory.createIdentifier(value.toString())
350
- : typeof value === "number"
351
- ? ExpressionFactory.number(value)
352
- : typeof value === "string"
353
- ? ts.factory.createStringLiteral(value)
354
- : ExpressionFactory.bigint(Number(value));
355
-
356
- const decode_template =
357
- (importer: FunctionImporter) =>
358
- (explore: IExplore) =>
359
- (template: MetadataTemplate) =>
360
- TemplateFactory.generate(
361
- template.row.map((meta) => decode(importer)(explore)(meta)),
362
- );
363
-
364
- const decode_number =
365
- (importer: FunctionImporter) =>
366
- (atomic: MetadataAtomic): ts.Expression[] =>
367
- (atomic.tags.length ? atomic.tags : [[]]).map((tags) => {
368
- const type = tags.find(
369
- (t) =>
370
- t.kind === "type" && (t.value === "int32" || t.value === "int64"),
371
- )
372
- ? "int"
373
- : tags.find(
374
- (t) =>
375
- t.kind === "type" &&
376
- (t.value === "uint32" || t.value === "uint64"),
377
- )
378
- ? "uint"
379
- : "double";
380
- const multiply = tags.find((t) => t.kind === "multipleOf");
381
- return random_custom(COALESCE(importer))("number")(tags)(
382
- RandomRanger.number({
383
- type,
384
- transform: (value) => ExpressionFactory.number(value),
385
- setter: (args) =>
386
- ts.factory.createCallExpression(
387
- type !== "double" || multiply !== undefined
388
- ? COALESCE(importer)("integer")
389
- : COALESCE(importer)("number"),
390
- undefined,
391
- args.map((val) => ExpressionFactory.number(val)),
392
- ),
393
- })({
394
- minimum: 0,
395
- maximum: 100,
396
- gap: 10,
397
- })(tags),
398
- );
399
- });
400
-
401
- const decode_bigint =
402
- (importer: FunctionImporter) =>
403
- (atomic: MetadataAtomic): ts.Expression[] =>
404
- (atomic.tags.length ? atomic.tags : [[]]).map((tags) =>
405
- random_custom(COALESCE(importer))("bigint")(tags)(
406
- RandomRanger.number({
407
- type: tags.find(
408
- (t) =>
409
- t.kind === "type" &&
410
- (t.value === "uint" || t.value === "uint64"),
411
- )
412
- ? "uint"
413
- : "int",
414
- transform: (value) => ExpressionFactory.bigint(value),
415
- setter: (args) =>
416
- ts.factory.createCallExpression(
417
- COALESCE(importer)("bigint"),
418
- undefined,
419
- args.map((value) => ExpressionFactory.bigint(value)),
420
- ),
421
- })({
422
- minimum: 0,
423
- maximum: 100,
424
- gap: 10,
425
- })(tags),
426
- ),
427
- );
428
-
429
- const decode_string =
430
- (importer: FunctionImporter) =>
431
- (atomic: MetadataAtomic): ts.Expression[] =>
432
- (atomic.tags.length ? atomic.tags : [[]]).map((tags) =>
433
- random_custom(COALESCE(importer))("string")(tags)(
434
- (() => {
435
- for (const t of tags)
436
- if (t.kind === "format")
437
- return ts.factory.createCallExpression(
438
- COALESCE(importer)(emendFormat(t.value)),
439
- undefined,
440
- undefined,
441
- );
442
- else if (t.kind === "pattern")
443
- return ts.factory.createCallExpression(
444
- COALESCE(importer)("pattern"),
445
- undefined,
446
- [ts.factory.createIdentifier(`/${t.value}/`)],
447
- );
448
-
449
- const tail = RandomRanger.length(COALESCE(importer))({
450
- minimum: 5,
451
- maximum: 25,
452
- gap: 5,
453
- })({
454
- minimum: "minLength",
455
- maximum: "maxLength",
456
- })(tags);
457
- return ts.factory.createCallExpression(
458
- COALESCE(importer)("string"),
459
- undefined,
460
- tail ? [tail] : undefined,
461
- );
462
- })(),
463
- ),
464
- );
465
-
466
- const decode_array =
467
- (importer: FunctionImporter) =>
468
- (explore: IExplore) =>
469
- (array: MetadataArray): ts.Expression[] => {
470
- const fixed: Array<
471
- [ts.Expression | undefined, ts.Expression | undefined]
472
- > = (array.tags.length ? array.tags : [[]]).map((tags) => [
473
- RandomRanger.length(COALESCE(importer))({
474
- minimum: 0,
475
- maximum: 3,
476
- gap: 3,
477
- })({
478
- minimum: "minItems",
479
- maximum: "maxItems",
480
- })(tags),
481
- (() => {
482
- const uniqueItems = tags.find((t) => t.kind === "uniqueItems");
483
- return uniqueItems === undefined
484
- ? undefined
485
- : uniqueItems.value === false
486
- ? ts.factory.createFalse()
487
- : ts.factory.createTrue();
488
- })(),
489
- ]);
490
- if (array.type.recursive)
491
- return fixed.map(([len, unique]) =>
492
- ts.factory.createCallExpression(
493
- ts.factory.createIdentifier(
494
- importer.useLocal(Prefix.array(array.type.index!)),
495
- ),
496
- undefined,
497
- [
498
- len ?? COALESCE(importer)("length"),
499
- unique ?? ts.factory.createFalse(),
500
- ts.factory.createTrue(),
501
- explore.recursive
502
- ? ts.factory.createAdd(
503
- ExpressionFactory.number(1),
504
- ts.factory.createIdentifier("_depth"),
505
- )
506
- : ExpressionFactory.number(0),
507
- ],
508
- ),
509
- );
510
- return fixed.map(([len, unique]) => {
511
- const expr: ts.Expression = RandomJoiner.array(COALESCE(importer))(
512
- decode(importer)(explore),
513
- )(explore)(
514
- len,
515
- unique,
516
- )(array.type.value);
517
- return explore.recursive
518
- ? ts.factory.createConditionalExpression(
519
- ts.factory.createLogicalAnd(
520
- ts.factory.createIdentifier("_recursive"),
521
- ts.factory.createLessThan(
522
- ExpressionFactory.number(5),
523
- ts.factory.createIdentifier("_depth"),
524
- ),
525
- ),
526
- undefined,
527
- ts.factory.createIdentifier("[]"),
528
- undefined,
529
- expr,
530
- )
531
- : expr;
532
- });
533
- };
534
-
535
- const decode_tuple =
536
- (importer: FunctionImporter) =>
537
- (explore: IExplore) =>
538
- (tuple: MetadataTuple): ts.Expression =>
539
- tuple.type.recursive
540
- ? ts.factory.createCallExpression(
541
- ts.factory.createIdentifier(
542
- importer.useLocal(Prefix.tuple(tuple.type.index!)),
543
- ),
544
- undefined,
545
- [
546
- ts.factory.createTrue(),
547
- explore.recursive
548
- ? ts.factory.createAdd(
549
- ExpressionFactory.number(1),
550
- ts.factory.createIdentifier("_depth"),
551
- )
552
- : ExpressionFactory.number(0),
553
- ],
554
- )
555
- : RandomJoiner.tuple(decode(importer)(explore))(tuple.type.elements);
556
-
557
- const decode_object =
558
- (importer: FunctionImporter) =>
559
- (explore: IExplore) =>
560
- (object: MetadataObject) =>
561
- ts.factory.createCallExpression(
562
- ts.factory.createIdentifier(
563
- importer.useLocal(Prefix.object(object.index)),
564
- ),
565
- undefined,
566
- explore.function
567
- ? [
568
- explore.recursive
569
- ? ts.factory.createTrue()
570
- : ts.factory.createIdentifier("_recursive"),
571
- ts.factory.createConditionalExpression(
572
- ts.factory.createIdentifier("_recursive"),
573
- undefined,
574
- ts.factory.createAdd(
575
- ExpressionFactory.number(1),
576
- ts.factory.createIdentifier("_depth"),
577
- ),
578
- undefined,
579
- ts.factory.createIdentifier("_depth"),
580
- ),
581
- ]
582
- : undefined,
583
- );
584
-
585
- /* -----------------------------------------------------------
586
- NATIVE CLASSES
587
- ----------------------------------------------------------- */
588
- const decode_set =
589
- (importer: FunctionImporter) => (explore: IExplore) => (meta: Metadata) =>
590
- ts.factory.createNewExpression(
591
- ts.factory.createIdentifier("Set"),
592
- undefined,
593
- [
594
- decode_array(importer)(explore)(
595
- MetadataArray.create({
596
- tags: [],
597
- type: MetadataArrayType.create({
598
- value: meta,
599
- recursive: false,
600
- index: null,
601
- nullables: [],
602
- name: `Set<${meta.getName()}>`,
603
- }),
604
- }),
605
- )[0]!,
606
- ],
607
- );
608
-
609
- const decode_map =
610
- (importer: FunctionImporter) =>
611
- (explore: IExplore) =>
612
- (map: Metadata.Entry) =>
613
- ts.factory.createNewExpression(
614
- ts.factory.createIdentifier("Map"),
615
- undefined,
616
- [
617
- decode_array(importer)(explore)(
618
- MetadataArray.create({
619
- tags: [],
620
- type: MetadataArrayType.create({
621
- name: `Map<${map.key.getName()}, ${map.value.getName()}>`,
622
- index: null,
623
- recursive: false,
624
- nullables: [],
625
- value: Metadata.create({
626
- ...Metadata.initialize(),
627
- tuples: [
628
- (() => {
629
- const type = MetadataTupleType.create({
630
- name: `[${map.key.getName()}, ${map.value.getName()}]`,
631
- index: null,
632
- recursive: false,
633
- nullables: [],
634
- elements: [map.key, map.value],
635
- });
636
- type.of_map = true;
637
- return MetadataTuple.create({
638
- type,
639
- tags: [],
640
- });
641
- })(),
642
- ],
643
- }),
644
- }),
645
- }),
646
- )[0]!,
647
- ],
648
- );
649
-
650
- const decode_native =
651
- (importer: FunctionImporter) =>
652
- (type: string): ts.Expression => {
653
- if (type === "Boolean") return decode_boolean(importer);
654
- else if (type === "Number")
655
- return decode_number(importer)(
656
- MetadataAtomic.create({
657
- type: "number",
658
- tags: [],
659
- }),
660
- )[0]!;
661
- else if (type === "String")
662
- return decode_string(importer)(
663
- MetadataAtomic.create({
664
- type: "string",
665
- tags: [],
666
- }),
667
- )[0]!;
668
- else if (type === "Date") return decode_native_date(importer);
669
- else if (
670
- type === "Uint8Array" ||
671
- type === "Uint8ClampedArray" ||
672
- type === "Uint16Array" ||
673
- type === "Uint32Array" ||
674
- type === "BigUint64Array" ||
675
- type === "Int8Array" ||
676
- type === "Int16Array" ||
677
- type === "Int32Array" ||
678
- type === "BigInt64Array" ||
679
- type === "Float32Array" ||
680
- type === "Float64Array"
681
- )
682
- return decode_native_byte_array(importer)(type);
683
- else if (type === "ArrayBuffer" || type === "SharedArrayBuffer")
684
- return decode_native_array_buffer(importer)(type);
685
- else if (type === "DataView") return decode_native_data_view(importer);
686
- else if (type === "Blob") return decode_native_blob(importer);
687
- else if (type === "File") return decode_native_file(importer);
688
- else if (type === "RegExp") return decode_regexp();
689
- else
690
- return ts.factory.createNewExpression(
691
- ts.factory.createIdentifier(type),
692
- undefined,
693
- [],
694
- );
695
- };
696
-
697
- const decode_native_date = (importer: FunctionImporter) =>
698
- ts.factory.createNewExpression(
699
- ts.factory.createIdentifier("Date"),
700
- undefined,
701
- [
702
- ts.factory.createCallExpression(
703
- COALESCE(importer)("datetime"),
704
- undefined,
705
- [],
706
- ),
707
- ],
708
- );
709
-
710
- const decode_native_byte_array =
711
- (importer: FunctionImporter) =>
712
- (
713
- type:
714
- | "Uint8Array"
715
- | "Uint8ClampedArray"
716
- | "Uint16Array"
717
- | "Uint32Array"
718
- | "BigUint64Array"
719
- | "Int8Array"
720
- | "Int16Array"
721
- | "Int32Array"
722
- | "BigInt64Array"
723
- | "Float32Array"
724
- | "Float64Array",
725
- ): ts.Expression => {
726
- new BigInt64Array();
727
- const [minimum, maximum]: [number, number] = (() => {
728
- if (type === "Uint8Array" || type === "Uint8ClampedArray")
729
- return [0, 255];
730
- else if (type === "Uint16Array") return [0, 65535];
731
- else if (type === "Uint32Array") return [0, 4294967295];
732
- else if (type === "BigUint64Array") return [0, 18446744073709551615];
733
- else if (type === "Int8Array") return [-128, 127];
734
- else if (type === "Int16Array") return [-32768, 32767];
735
- else if (type === "Int32Array") return [-2147483648, 2147483647];
736
- else if (type === "BigInt64Array")
737
- return [-9223372036854775808, 9223372036854775807];
738
- else if (type === "Float32Array")
739
- return [-1.175494351e38, 3.4028235e38];
740
- return [Number.MIN_VALUE, Number.MAX_VALUE];
741
- })();
742
- const literal =
743
- type === "BigInt64Array" || type === "BigUint64Array"
744
- ? ExpressionFactory.bigint
745
- : ExpressionFactory.number;
746
- return ts.factory.createNewExpression(
747
- ts.factory.createIdentifier(type),
748
- [],
749
- [
750
- ts.factory.createCallExpression(
751
- COALESCE(importer)("array"),
752
- undefined,
753
- [
754
- ts.factory.createArrowFunction(
755
- undefined,
756
- undefined,
757
- [],
758
- TypeFactory.keyword("any"),
759
- undefined,
760
- ts.factory.createCallExpression(
761
- COALESCE(importer)(
762
- type === "Float32Array" || type === "Float64Array"
763
- ? "number"
764
- : type === "BigInt64Array" || type === "BigUint64Array"
765
- ? "bigint"
766
- : "integer",
767
- ),
768
- undefined,
769
- [literal(minimum), literal(maximum)],
770
- ),
771
- ),
772
- ],
773
- ),
774
- ],
775
- );
776
- };
777
-
778
- const decode_native_blob = (importer: FunctionImporter) =>
779
- ts.factory.createNewExpression(
780
- ts.factory.createIdentifier("Blob"),
781
- undefined,
782
- [
783
- ts.factory.createArrayLiteralExpression(
784
- [decode_native_byte_array(importer)("Uint8Array")],
785
- true,
786
- ),
787
- ],
788
- );
789
-
790
- const decode_native_file = (importer: FunctionImporter) =>
791
- ts.factory.createNewExpression(
792
- ts.factory.createIdentifier("File"),
793
- undefined,
794
- [
795
- ts.factory.createArrayLiteralExpression(
796
- [decode_native_byte_array(importer)("Uint8Array")],
797
- true,
798
- ),
799
- ts.factory.createTemplateExpression(ts.factory.createTemplateHead(""), [
800
- ts.factory.createTemplateSpan(
801
- ts.factory.createCallExpression(
802
- COALESCE(importer)("string"),
803
- undefined,
804
- [ts.factory.createNumericLiteral(8)],
805
- ),
806
- ts.factory.createTemplateMiddle("."),
807
- ),
808
- ts.factory.createTemplateSpan(
809
- ts.factory.createCallExpression(
810
- COALESCE(importer)("string"),
811
- undefined,
812
- [ts.factory.createNumericLiteral(3)],
813
- ),
814
- ts.factory.createTemplateTail(""),
815
- ),
816
- ]),
817
- ],
818
- );
819
-
820
- const decode_native_array_buffer =
821
- (importer: FunctionImporter) =>
822
- (type: "ArrayBuffer" | "SharedArrayBuffer"): ts.Expression =>
823
- type === "ArrayBuffer"
824
- ? IdentifierFactory.access(
825
- decode_native_byte_array(importer)("Uint8Array"),
826
- )("buffer")
827
- : ExpressionFactory.selfCall(
828
- ts.factory.createBlock(
829
- [
830
- StatementFactory.constant(
831
- "length",
832
- ts.factory.createCallExpression(
833
- COALESCE(importer)("integer"),
834
- undefined,
835
- [],
836
- ),
837
- ),
838
- StatementFactory.constant(
839
- "buffer",
840
- ts.factory.createNewExpression(
841
- ts.factory.createIdentifier("SharedArrayBuffer"),
842
- [],
843
- [ts.factory.createIdentifier("length")],
844
- ),
845
- ),
846
- StatementFactory.constant(
847
- "bytes",
848
- ts.factory.createNewExpression(
849
- ts.factory.createIdentifier("Uint8Array"),
850
- [],
851
- [ts.factory.createIdentifier("buffer")],
852
- ),
853
- ),
854
- ts.factory.createExpressionStatement(
855
- ts.factory.createCallExpression(
856
- IdentifierFactory.access(
857
- ts.factory.createIdentifier("bytes"),
858
- )("set"),
859
- undefined,
860
- [
861
- ts.factory.createCallExpression(
862
- COALESCE(importer)("array"),
863
- undefined,
864
- [
865
- ts.factory.createArrowFunction(
866
- undefined,
867
- undefined,
868
- [],
869
- TypeFactory.keyword("any"),
870
- undefined,
871
- ts.factory.createCallExpression(
872
- COALESCE(importer)("integer"),
873
- undefined,
874
- [
875
- ExpressionFactory.number(0),
876
- ExpressionFactory.number(255),
877
- ],
878
- ),
879
- ),
880
- ts.factory.createIdentifier("length"),
881
- ],
882
- ),
883
- ExpressionFactory.number(0),
884
- ],
885
- ),
886
- ),
887
- ts.factory.createReturnStatement(
888
- ts.factory.createIdentifier("buffer"),
889
- ),
890
- ],
891
- true,
892
- ),
893
- );
894
-
895
- const decode_native_data_view = (importer: FunctionImporter) =>
896
- ts.factory.createNewExpression(
897
- ts.factory.createIdentifier("DataView"),
898
- [],
899
- [
900
- IdentifierFactory.access(
901
- decode_native_byte_array(importer)("Uint8Array"),
902
- )("buffer"),
903
- ],
904
- );
905
-
906
- const decode_regexp = () =>
907
- ts.factory.createNewExpression(
908
- ts.factory.createIdentifier("RegExp"),
909
- [],
910
- [ts.factory.createIdentifier("/(?:)/")],
911
- );
912
- }
913
-
914
- type Atomic = boolean | number | string | bigint;
915
- interface IExplore {
916
- function: boolean;
917
- recursive: boolean;
918
- }
919
-
920
- const Prefix = {
921
- object: (i: number) => `$ro${i}`,
922
- array: (i: number) => `$ra${i}`,
923
- tuple: (i: number) => `$rt${i}`,
924
- };
925
-
926
- const COALESCE = (importer: FunctionImporter) => (name: string) =>
927
- ExpressionFactory.coalesce(
928
- Escaper.variable(name)
929
- ? ts.factory.createPropertyAccessChain(
930
- ts.factory.createIdentifier("_generator"),
931
- ts.factory.createToken(ts.SyntaxKind.QuestionDotToken),
932
- ts.factory.createIdentifier(name),
933
- )
934
- : ts.factory.createElementAccessChain(
935
- ts.factory.createIdentifier("_generator"),
936
- ts.factory.createToken(ts.SyntaxKind.QuestionDotToken),
937
- ts.factory.createStringLiteral(name),
938
- ),
939
- )(IdentifierFactory.access(importer.use("generator"))(name));
940
-
941
- const emendFormat = (key: keyof Format.Validator) =>
942
- key === "date-time"
943
- ? "datetime"
944
- : key
945
- .split("-")
946
- .map((str, i) =>
947
- i === 0 || str.length === 0
948
- ? str
949
- : str[0]!.toUpperCase() + str.substring(1),
950
- )
951
- .join("");
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 { TemplateFactory } from "../factories/TemplateFactory";
9
+ import { TypeFactory } from "../factories/TypeFactory";
10
+
11
+ import { Metadata } from "../schemas/metadata/Metadata";
12
+ import { MetadataArray } from "../schemas/metadata/MetadataArray";
13
+ import { MetadataArrayType } from "../schemas/metadata/MetadataArrayType";
14
+ import { MetadataAtomic } from "../schemas/metadata/MetadataAtomic";
15
+ import { MetadataObject } from "../schemas/metadata/MetadataObject";
16
+ import { MetadataTemplate } from "../schemas/metadata/MetadataTemplate";
17
+ import { MetadataTuple } from "../schemas/metadata/MetadataTuple";
18
+ import { MetadataTupleType } from "../schemas/metadata/MetadataTupleType";
19
+
20
+ import { IProject } from "../transformers/IProject";
21
+ import { TransformerError } from "../transformers/TransformerError";
22
+
23
+ import { Escaper } from "../utils/Escaper";
24
+
25
+ import { Format } from "../tags";
26
+ import { FeatureProgrammer } from "./FeatureProgrammer";
27
+ import { FunctionImporter } from "./helpers/FunctionImporter";
28
+ import { RandomJoiner } from "./helpers/RandomJoiner";
29
+ import { RandomRanger } from "./helpers/RandomRanger";
30
+ import { random_custom } from "./internal/random_custom";
31
+
32
+ export namespace RandomProgrammer {
33
+ export const decompose = (props: {
34
+ project: IProject;
35
+ importer: FunctionImporter;
36
+ type: ts.Type;
37
+ name: string | undefined;
38
+ init: ts.Expression | undefined;
39
+ }): FeatureProgrammer.IDecomposed => {
40
+ const collection: MetadataCollection = new MetadataCollection();
41
+ const result = MetadataFactory.analyze(
42
+ props.project.checker,
43
+ props.project.context,
44
+ )({
45
+ escape: false,
46
+ constant: true,
47
+ absorb: true,
48
+ validate: (meta) => {
49
+ const output: string[] = [];
50
+ if (meta.natives.some((n) => n === "WeakSet"))
51
+ output.push(`WeakSet is not supported.`);
52
+ else if (meta.natives.some((n) => n === "WeakMap"))
53
+ output.push(`WeakMap is not supported.`);
54
+ return output;
55
+ },
56
+ })(collection)(props.type);
57
+ if (result.success === false)
58
+ throw TransformerError.from(`typia.${props.importer.method}`)(
59
+ result.errors,
60
+ );
61
+
62
+ // GENERATE FUNCTION
63
+ const functions: Record<string, ts.VariableStatement> = Object.fromEntries([
64
+ ...write_object_functions(props.importer)(collection).map((v, i) => [
65
+ Prefix.object(i),
66
+ v,
67
+ ]),
68
+ ...write_array_functions(props.importer)(collection).map((v, i) => [
69
+ Prefix.array(i),
70
+ v,
71
+ ]),
72
+ ...write_tuple_functions(props.importer)(collection).map((v, i) => [
73
+ Prefix.tuple(i),
74
+ v,
75
+ ]),
76
+ ]);
77
+ const arrow: ts.ArrowFunction = ts.factory.createArrowFunction(
78
+ undefined,
79
+ undefined,
80
+ [
81
+ IdentifierFactory.parameter(
82
+ "generator",
83
+ ts.factory.createTypeReferenceNode("Partial<typia.IRandomGenerator>"),
84
+ props.init ?? ts.factory.createToken(ts.SyntaxKind.QuestionToken),
85
+ ),
86
+ ],
87
+ ts.factory.createImportTypeNode(
88
+ ts.factory.createLiteralTypeNode(
89
+ ts.factory.createStringLiteral("typia"),
90
+ ),
91
+ undefined,
92
+ ts.factory.createIdentifier("Resolved"),
93
+ [
94
+ ts.factory.createTypeReferenceNode(
95
+ props.name ??
96
+ TypeFactory.getFullName(props.project.checker)(props.type),
97
+ ),
98
+ ],
99
+ false,
100
+ ),
101
+ undefined,
102
+ ts.factory.createBlock(
103
+ [
104
+ ts.factory.createExpressionStatement(
105
+ ts.factory.createBinaryExpression(
106
+ ts.factory.createIdentifier("_generator"),
107
+ ts.SyntaxKind.EqualsToken,
108
+ ts.factory.createIdentifier("generator"),
109
+ ),
110
+ ),
111
+ ts.factory.createReturnStatement(
112
+ decode(props.importer)({
113
+ function: false,
114
+ recursive: false,
115
+ })(result.data),
116
+ ),
117
+ ],
118
+ true,
119
+ ),
120
+ );
121
+ return {
122
+ functions,
123
+ statements: [StatementFactory.mut("_generator")],
124
+ arrow,
125
+ };
126
+ };
127
+
128
+ export const write =
129
+ (project: IProject) =>
130
+ (modulo: ts.LeftHandSideExpression) =>
131
+ (init?: ts.Expression) =>
132
+ (type: ts.Type, name?: string) => {
133
+ const importer: FunctionImporter = new FunctionImporter(modulo.getText());
134
+ const result: FeatureProgrammer.IDecomposed = decompose({
135
+ project,
136
+ importer,
137
+ type,
138
+ name,
139
+ init,
140
+ });
141
+ return FeatureProgrammer.writeDecomposed({
142
+ modulo,
143
+ importer,
144
+ result,
145
+ });
146
+ };
147
+
148
+ const write_object_functions =
149
+ (importer: FunctionImporter) =>
150
+ (collection: MetadataCollection): ts.VariableStatement[] =>
151
+ collection.objects().map((obj, i) =>
152
+ StatementFactory.constant(
153
+ Prefix.object(i),
154
+ ts.factory.createArrowFunction(
155
+ undefined,
156
+ undefined,
157
+ [
158
+ IdentifierFactory.parameter(
159
+ "_recursive",
160
+ TypeFactory.keyword("boolean"),
161
+ ts.factory.createIdentifier(String(obj.recursive)),
162
+ ),
163
+ IdentifierFactory.parameter(
164
+ "_depth",
165
+ TypeFactory.keyword("number"),
166
+ ExpressionFactory.number(0),
167
+ ),
168
+ ],
169
+ TypeFactory.keyword("any"),
170
+ undefined,
171
+ RandomJoiner.object(COALESCE(importer))(
172
+ decode(importer)({
173
+ recursive: obj.recursive,
174
+ function: true,
175
+ }),
176
+ )(obj),
177
+ ),
178
+ ),
179
+ );
180
+
181
+ const write_array_functions =
182
+ (importer: FunctionImporter) =>
183
+ (collection: MetadataCollection): ts.VariableStatement[] =>
184
+ collection
185
+ .arrays()
186
+ .filter((a) => a.recursive)
187
+ .map((array, i) =>
188
+ StatementFactory.constant(
189
+ Prefix.array(i),
190
+ ts.factory.createArrowFunction(
191
+ undefined,
192
+ undefined,
193
+ [
194
+ IdentifierFactory.parameter(
195
+ "length",
196
+ TypeFactory.keyword("number"),
197
+ ),
198
+ IdentifierFactory.parameter(
199
+ "unique",
200
+ TypeFactory.keyword("boolean"),
201
+ ),
202
+ IdentifierFactory.parameter(
203
+ "_recursive",
204
+ TypeFactory.keyword("boolean"),
205
+ ts.factory.createTrue(),
206
+ ),
207
+ IdentifierFactory.parameter(
208
+ "_depth",
209
+ TypeFactory.keyword("number"),
210
+ ExpressionFactory.number(0),
211
+ ),
212
+ ],
213
+ TypeFactory.keyword("any"),
214
+ undefined,
215
+ RandomJoiner.array(COALESCE(importer))(
216
+ decode(importer)({
217
+ recursive: true,
218
+ function: true,
219
+ }),
220
+ )({
221
+ recursive: true,
222
+ function: true,
223
+ })(
224
+ ts.factory.createIdentifier("length"),
225
+ ts.factory.createIdentifier("unique"),
226
+ )(array.value),
227
+ ),
228
+ ),
229
+ );
230
+
231
+ const write_tuple_functions =
232
+ (importer: FunctionImporter) =>
233
+ (collection: MetadataCollection): ts.VariableStatement[] =>
234
+ collection
235
+ .tuples()
236
+ .filter((a) => a.recursive)
237
+ .map((tuple, i) =>
238
+ StatementFactory.constant(
239
+ Prefix.tuple(i),
240
+ ts.factory.createArrowFunction(
241
+ undefined,
242
+ undefined,
243
+ [
244
+ IdentifierFactory.parameter(
245
+ "_recursive",
246
+ TypeFactory.keyword("boolean"),
247
+ ts.factory.createTrue(),
248
+ ),
249
+ IdentifierFactory.parameter(
250
+ "_depth",
251
+ TypeFactory.keyword("number"),
252
+ ExpressionFactory.number(0),
253
+ ),
254
+ ],
255
+ TypeFactory.keyword("any"),
256
+ undefined,
257
+ RandomJoiner.tuple(
258
+ decode(importer)({
259
+ function: true,
260
+ recursive: true,
261
+ }),
262
+ )(tuple.elements),
263
+ ),
264
+ ),
265
+ );
266
+
267
+ /* -----------------------------------------------------------
268
+ DECODERS
269
+ ----------------------------------------------------------- */
270
+ const decode =
271
+ (importer: FunctionImporter) =>
272
+ (explore: IExplore) =>
273
+ (meta: Metadata): ts.Expression => {
274
+ const expressions: ts.Expression[] = [];
275
+ if (meta.any)
276
+ expressions.push(ts.factory.createStringLiteral("any type used..."));
277
+
278
+ // NULL COALESCING
279
+ if (meta.isRequired() === false || meta.functional === true)
280
+ expressions.push(ts.factory.createIdentifier("undefined"));
281
+ if (meta.nullable === true) expressions.push(ts.factory.createNull());
282
+
283
+ // CONSTANT TYPES
284
+ for (const constant of meta.constants)
285
+ for (const { value } of constant.values)
286
+ expressions.push(decode_atomic(value));
287
+
288
+ // ATOMIC VARIABLES
289
+ for (const template of meta.templates)
290
+ expressions.push(decode_template(importer)(explore)(template));
291
+ for (const atomic of meta.atomics)
292
+ if (atomic.type === "boolean")
293
+ expressions.push(decode_boolean(importer));
294
+ else if (atomic.type === "number")
295
+ expressions.push(...decode_number(importer)(atomic));
296
+ else if (atomic.type === "string")
297
+ expressions.push(...decode_string(importer)(atomic));
298
+ else if (atomic.type === "bigint")
299
+ expressions.push(...decode_bigint(importer)(atomic));
300
+
301
+ // INSTANCE TYPES
302
+ if (meta.escaped)
303
+ expressions.push(decode(importer)(explore)(meta.escaped.returns));
304
+ for (const array of meta.arrays)
305
+ expressions.push(...decode_array(importer)(explore)(array));
306
+ for (const tuple of meta.tuples)
307
+ expressions.push(decode_tuple(importer)(explore)(tuple));
308
+ for (const o of meta.objects)
309
+ expressions.push(decode_object(importer)(explore)(o));
310
+ for (const native of meta.natives)
311
+ expressions.push(decode_native(importer)(native));
312
+ for (const set of meta.sets)
313
+ expressions.push(decode_set(importer)(explore)(set));
314
+ for (const map of meta.maps)
315
+ expressions.push(decode_map(importer)(explore)(map));
316
+
317
+ // PICK UP A TYPE
318
+ if (expressions.length === 1) return expressions[0]!;
319
+ return ts.factory.createCallExpression(
320
+ ts.factory.createCallExpression(importer.use("pick"), undefined, [
321
+ ts.factory.createArrayLiteralExpression(
322
+ expressions.map((expr) =>
323
+ ts.factory.createArrowFunction(
324
+ undefined,
325
+ undefined,
326
+ [],
327
+ undefined,
328
+ undefined,
329
+ expr,
330
+ ),
331
+ ),
332
+ true,
333
+ ),
334
+ ]),
335
+ undefined,
336
+ undefined,
337
+ );
338
+ };
339
+
340
+ const decode_boolean = (importer: FunctionImporter) =>
341
+ ts.factory.createCallExpression(
342
+ COALESCE(importer)("boolean"),
343
+ undefined,
344
+ undefined,
345
+ );
346
+
347
+ const decode_atomic = (value: Atomic) =>
348
+ typeof value === "boolean"
349
+ ? ts.factory.createIdentifier(value.toString())
350
+ : typeof value === "number"
351
+ ? ExpressionFactory.number(value)
352
+ : typeof value === "string"
353
+ ? ts.factory.createStringLiteral(value)
354
+ : ExpressionFactory.bigint(Number(value));
355
+
356
+ const decode_template =
357
+ (importer: FunctionImporter) =>
358
+ (explore: IExplore) =>
359
+ (template: MetadataTemplate) =>
360
+ TemplateFactory.generate(
361
+ template.row.map((meta) => decode(importer)(explore)(meta)),
362
+ );
363
+
364
+ const decode_number =
365
+ (importer: FunctionImporter) =>
366
+ (atomic: MetadataAtomic): ts.Expression[] =>
367
+ (atomic.tags.length ? atomic.tags : [[]]).map((tags) => {
368
+ const type = tags.find(
369
+ (t) =>
370
+ t.kind === "type" && (t.value === "int32" || t.value === "int64"),
371
+ )
372
+ ? "int"
373
+ : tags.find(
374
+ (t) =>
375
+ t.kind === "type" &&
376
+ (t.value === "uint32" || t.value === "uint64"),
377
+ )
378
+ ? "uint"
379
+ : "double";
380
+ const multiply = tags.find((t) => t.kind === "multipleOf");
381
+ return random_custom(COALESCE(importer))("number")(tags)(
382
+ RandomRanger.number({
383
+ type,
384
+ transform: (value) => ExpressionFactory.number(value),
385
+ setter: (args) =>
386
+ ts.factory.createCallExpression(
387
+ type !== "double" || multiply !== undefined
388
+ ? COALESCE(importer)("integer")
389
+ : COALESCE(importer)("number"),
390
+ undefined,
391
+ args.map((val) => ExpressionFactory.number(val)),
392
+ ),
393
+ })({
394
+ minimum: 0,
395
+ maximum: 100,
396
+ gap: 10,
397
+ })(tags),
398
+ );
399
+ });
400
+
401
+ const decode_bigint =
402
+ (importer: FunctionImporter) =>
403
+ (atomic: MetadataAtomic): ts.Expression[] =>
404
+ (atomic.tags.length ? atomic.tags : [[]]).map((tags) =>
405
+ random_custom(COALESCE(importer))("bigint")(tags)(
406
+ RandomRanger.number({
407
+ type: tags.find(
408
+ (t) =>
409
+ t.kind === "type" &&
410
+ (t.value === "uint" || t.value === "uint64"),
411
+ )
412
+ ? "uint"
413
+ : "int",
414
+ transform: (value) => ExpressionFactory.bigint(value),
415
+ setter: (args) =>
416
+ ts.factory.createCallExpression(
417
+ COALESCE(importer)("bigint"),
418
+ undefined,
419
+ args.map((value) => ExpressionFactory.bigint(value)),
420
+ ),
421
+ })({
422
+ minimum: 0,
423
+ maximum: 100,
424
+ gap: 10,
425
+ })(tags),
426
+ ),
427
+ );
428
+
429
+ const decode_string =
430
+ (importer: FunctionImporter) =>
431
+ (atomic: MetadataAtomic): ts.Expression[] =>
432
+ (atomic.tags.length ? atomic.tags : [[]]).map((tags) =>
433
+ random_custom(COALESCE(importer))("string")(tags)(
434
+ (() => {
435
+ for (const t of tags)
436
+ if (t.kind === "format")
437
+ return ts.factory.createCallExpression(
438
+ COALESCE(importer)(emendFormat(t.value)),
439
+ undefined,
440
+ undefined,
441
+ );
442
+ else if (t.kind === "pattern")
443
+ return ts.factory.createCallExpression(
444
+ COALESCE(importer)("pattern"),
445
+ undefined,
446
+ [ts.factory.createIdentifier(`/${t.value}/`)],
447
+ );
448
+
449
+ const tail = RandomRanger.length(COALESCE(importer))({
450
+ minimum: 5,
451
+ maximum: 25,
452
+ gap: 5,
453
+ })({
454
+ minimum: "minLength",
455
+ maximum: "maxLength",
456
+ })(tags);
457
+ return ts.factory.createCallExpression(
458
+ COALESCE(importer)("string"),
459
+ undefined,
460
+ tail ? [tail] : undefined,
461
+ );
462
+ })(),
463
+ ),
464
+ );
465
+
466
+ const decode_array =
467
+ (importer: FunctionImporter) =>
468
+ (explore: IExplore) =>
469
+ (array: MetadataArray): ts.Expression[] => {
470
+ const fixed: Array<
471
+ [ts.Expression | undefined, ts.Expression | undefined]
472
+ > = (array.tags.length ? array.tags : [[]]).map((tags) => [
473
+ RandomRanger.length(COALESCE(importer))({
474
+ minimum: 0,
475
+ maximum: 3,
476
+ gap: 3,
477
+ })({
478
+ minimum: "minItems",
479
+ maximum: "maxItems",
480
+ })(tags),
481
+ (() => {
482
+ const uniqueItems = tags.find((t) => t.kind === "uniqueItems");
483
+ return uniqueItems === undefined
484
+ ? undefined
485
+ : uniqueItems.value === false
486
+ ? ts.factory.createFalse()
487
+ : ts.factory.createTrue();
488
+ })(),
489
+ ]);
490
+ if (array.type.recursive)
491
+ return fixed.map(([len, unique]) =>
492
+ ts.factory.createCallExpression(
493
+ ts.factory.createIdentifier(
494
+ importer.useLocal(Prefix.array(array.type.index!)),
495
+ ),
496
+ undefined,
497
+ [
498
+ len ?? COALESCE(importer)("length"),
499
+ unique ?? ts.factory.createFalse(),
500
+ ts.factory.createTrue(),
501
+ explore.recursive
502
+ ? ts.factory.createAdd(
503
+ ExpressionFactory.number(1),
504
+ ts.factory.createIdentifier("_depth"),
505
+ )
506
+ : ExpressionFactory.number(0),
507
+ ],
508
+ ),
509
+ );
510
+ return fixed.map(([len, unique]) => {
511
+ const expr: ts.Expression = RandomJoiner.array(COALESCE(importer))(
512
+ decode(importer)(explore),
513
+ )(explore)(
514
+ len,
515
+ unique,
516
+ )(array.type.value);
517
+ return explore.recursive
518
+ ? ts.factory.createConditionalExpression(
519
+ ts.factory.createLogicalAnd(
520
+ ts.factory.createIdentifier("_recursive"),
521
+ ts.factory.createLessThan(
522
+ ExpressionFactory.number(5),
523
+ ts.factory.createIdentifier("_depth"),
524
+ ),
525
+ ),
526
+ undefined,
527
+ ts.factory.createIdentifier("[]"),
528
+ undefined,
529
+ expr,
530
+ )
531
+ : expr;
532
+ });
533
+ };
534
+
535
+ const decode_tuple =
536
+ (importer: FunctionImporter) =>
537
+ (explore: IExplore) =>
538
+ (tuple: MetadataTuple): ts.Expression =>
539
+ tuple.type.recursive
540
+ ? ts.factory.createCallExpression(
541
+ ts.factory.createIdentifier(
542
+ importer.useLocal(Prefix.tuple(tuple.type.index!)),
543
+ ),
544
+ undefined,
545
+ [
546
+ ts.factory.createTrue(),
547
+ explore.recursive
548
+ ? ts.factory.createAdd(
549
+ ExpressionFactory.number(1),
550
+ ts.factory.createIdentifier("_depth"),
551
+ )
552
+ : ExpressionFactory.number(0),
553
+ ],
554
+ )
555
+ : RandomJoiner.tuple(decode(importer)(explore))(tuple.type.elements);
556
+
557
+ const decode_object =
558
+ (importer: FunctionImporter) =>
559
+ (explore: IExplore) =>
560
+ (object: MetadataObject) =>
561
+ ts.factory.createCallExpression(
562
+ ts.factory.createIdentifier(
563
+ importer.useLocal(Prefix.object(object.index)),
564
+ ),
565
+ undefined,
566
+ explore.function
567
+ ? [
568
+ explore.recursive
569
+ ? ts.factory.createTrue()
570
+ : ts.factory.createIdentifier("_recursive"),
571
+ ts.factory.createConditionalExpression(
572
+ ts.factory.createIdentifier("_recursive"),
573
+ undefined,
574
+ ts.factory.createAdd(
575
+ ExpressionFactory.number(1),
576
+ ts.factory.createIdentifier("_depth"),
577
+ ),
578
+ undefined,
579
+ ts.factory.createIdentifier("_depth"),
580
+ ),
581
+ ]
582
+ : undefined,
583
+ );
584
+
585
+ /* -----------------------------------------------------------
586
+ NATIVE CLASSES
587
+ ----------------------------------------------------------- */
588
+ const decode_set =
589
+ (importer: FunctionImporter) => (explore: IExplore) => (meta: Metadata) =>
590
+ ts.factory.createNewExpression(
591
+ ts.factory.createIdentifier("Set"),
592
+ undefined,
593
+ [
594
+ decode_array(importer)(explore)(
595
+ MetadataArray.create({
596
+ tags: [],
597
+ type: MetadataArrayType.create({
598
+ value: meta,
599
+ recursive: false,
600
+ index: null,
601
+ nullables: [],
602
+ name: `Set<${meta.getName()}>`,
603
+ }),
604
+ }),
605
+ )[0]!,
606
+ ],
607
+ );
608
+
609
+ const decode_map =
610
+ (importer: FunctionImporter) =>
611
+ (explore: IExplore) =>
612
+ (map: Metadata.Entry) =>
613
+ ts.factory.createNewExpression(
614
+ ts.factory.createIdentifier("Map"),
615
+ undefined,
616
+ [
617
+ decode_array(importer)(explore)(
618
+ MetadataArray.create({
619
+ tags: [],
620
+ type: MetadataArrayType.create({
621
+ name: `Map<${map.key.getName()}, ${map.value.getName()}>`,
622
+ index: null,
623
+ recursive: false,
624
+ nullables: [],
625
+ value: Metadata.create({
626
+ ...Metadata.initialize(),
627
+ tuples: [
628
+ (() => {
629
+ const type = MetadataTupleType.create({
630
+ name: `[${map.key.getName()}, ${map.value.getName()}]`,
631
+ index: null,
632
+ recursive: false,
633
+ nullables: [],
634
+ elements: [map.key, map.value],
635
+ });
636
+ type.of_map = true;
637
+ return MetadataTuple.create({
638
+ type,
639
+ tags: [],
640
+ });
641
+ })(),
642
+ ],
643
+ }),
644
+ }),
645
+ }),
646
+ )[0]!,
647
+ ],
648
+ );
649
+
650
+ const decode_native =
651
+ (importer: FunctionImporter) =>
652
+ (type: string): ts.Expression => {
653
+ if (type === "Boolean") return decode_boolean(importer);
654
+ else if (type === "Number")
655
+ return decode_number(importer)(
656
+ MetadataAtomic.create({
657
+ type: "number",
658
+ tags: [],
659
+ }),
660
+ )[0]!;
661
+ else if (type === "String")
662
+ return decode_string(importer)(
663
+ MetadataAtomic.create({
664
+ type: "string",
665
+ tags: [],
666
+ }),
667
+ )[0]!;
668
+ else if (type === "Date") return decode_native_date(importer);
669
+ else if (
670
+ type === "Uint8Array" ||
671
+ type === "Uint8ClampedArray" ||
672
+ type === "Uint16Array" ||
673
+ type === "Uint32Array" ||
674
+ type === "BigUint64Array" ||
675
+ type === "Int8Array" ||
676
+ type === "Int16Array" ||
677
+ type === "Int32Array" ||
678
+ type === "BigInt64Array" ||
679
+ type === "Float32Array" ||
680
+ type === "Float64Array"
681
+ )
682
+ return decode_native_byte_array(importer)(type);
683
+ else if (type === "ArrayBuffer" || type === "SharedArrayBuffer")
684
+ return decode_native_array_buffer(importer)(type);
685
+ else if (type === "DataView") return decode_native_data_view(importer);
686
+ else if (type === "Blob") return decode_native_blob(importer);
687
+ else if (type === "File") return decode_native_file(importer);
688
+ else if (type === "RegExp") return decode_regexp();
689
+ else
690
+ return ts.factory.createNewExpression(
691
+ ts.factory.createIdentifier(type),
692
+ undefined,
693
+ [],
694
+ );
695
+ };
696
+
697
+ const decode_native_date = (importer: FunctionImporter) =>
698
+ ts.factory.createNewExpression(
699
+ ts.factory.createIdentifier("Date"),
700
+ undefined,
701
+ [
702
+ ts.factory.createCallExpression(
703
+ COALESCE(importer)("datetime"),
704
+ undefined,
705
+ [],
706
+ ),
707
+ ],
708
+ );
709
+
710
+ const decode_native_byte_array =
711
+ (importer: FunctionImporter) =>
712
+ (
713
+ type:
714
+ | "Uint8Array"
715
+ | "Uint8ClampedArray"
716
+ | "Uint16Array"
717
+ | "Uint32Array"
718
+ | "BigUint64Array"
719
+ | "Int8Array"
720
+ | "Int16Array"
721
+ | "Int32Array"
722
+ | "BigInt64Array"
723
+ | "Float32Array"
724
+ | "Float64Array",
725
+ ): ts.Expression => {
726
+ new BigInt64Array();
727
+ const [minimum, maximum]: [number, number] = (() => {
728
+ if (type === "Uint8Array" || type === "Uint8ClampedArray")
729
+ return [0, 255];
730
+ else if (type === "Uint16Array") return [0, 65535];
731
+ else if (type === "Uint32Array") return [0, 4294967295];
732
+ else if (type === "BigUint64Array") return [0, 18446744073709551615];
733
+ else if (type === "Int8Array") return [-128, 127];
734
+ else if (type === "Int16Array") return [-32768, 32767];
735
+ else if (type === "Int32Array") return [-2147483648, 2147483647];
736
+ else if (type === "BigInt64Array")
737
+ return [-9223372036854775808, 9223372036854775807];
738
+ else if (type === "Float32Array")
739
+ return [-1.175494351e38, 3.4028235e38];
740
+ return [Number.MIN_VALUE, Number.MAX_VALUE];
741
+ })();
742
+ const literal =
743
+ type === "BigInt64Array" || type === "BigUint64Array"
744
+ ? ExpressionFactory.bigint
745
+ : ExpressionFactory.number;
746
+ return ts.factory.createNewExpression(
747
+ ts.factory.createIdentifier(type),
748
+ [],
749
+ [
750
+ ts.factory.createCallExpression(
751
+ COALESCE(importer)("array"),
752
+ undefined,
753
+ [
754
+ ts.factory.createArrowFunction(
755
+ undefined,
756
+ undefined,
757
+ [],
758
+ TypeFactory.keyword("any"),
759
+ undefined,
760
+ ts.factory.createCallExpression(
761
+ COALESCE(importer)(
762
+ type === "Float32Array" || type === "Float64Array"
763
+ ? "number"
764
+ : type === "BigInt64Array" || type === "BigUint64Array"
765
+ ? "bigint"
766
+ : "integer",
767
+ ),
768
+ undefined,
769
+ [literal(minimum), literal(maximum)],
770
+ ),
771
+ ),
772
+ ],
773
+ ),
774
+ ],
775
+ );
776
+ };
777
+
778
+ const decode_native_blob = (importer: FunctionImporter) =>
779
+ ts.factory.createNewExpression(
780
+ ts.factory.createIdentifier("Blob"),
781
+ undefined,
782
+ [
783
+ ts.factory.createArrayLiteralExpression(
784
+ [decode_native_byte_array(importer)("Uint8Array")],
785
+ true,
786
+ ),
787
+ ],
788
+ );
789
+
790
+ const decode_native_file = (importer: FunctionImporter) =>
791
+ ts.factory.createNewExpression(
792
+ ts.factory.createIdentifier("File"),
793
+ undefined,
794
+ [
795
+ ts.factory.createArrayLiteralExpression(
796
+ [decode_native_byte_array(importer)("Uint8Array")],
797
+ true,
798
+ ),
799
+ ts.factory.createTemplateExpression(ts.factory.createTemplateHead(""), [
800
+ ts.factory.createTemplateSpan(
801
+ ts.factory.createCallExpression(
802
+ COALESCE(importer)("string"),
803
+ undefined,
804
+ [ts.factory.createNumericLiteral(8)],
805
+ ),
806
+ ts.factory.createTemplateMiddle("."),
807
+ ),
808
+ ts.factory.createTemplateSpan(
809
+ ts.factory.createCallExpression(
810
+ COALESCE(importer)("string"),
811
+ undefined,
812
+ [ts.factory.createNumericLiteral(3)],
813
+ ),
814
+ ts.factory.createTemplateTail(""),
815
+ ),
816
+ ]),
817
+ ],
818
+ );
819
+
820
+ const decode_native_array_buffer =
821
+ (importer: FunctionImporter) =>
822
+ (type: "ArrayBuffer" | "SharedArrayBuffer"): ts.Expression =>
823
+ type === "ArrayBuffer"
824
+ ? IdentifierFactory.access(
825
+ decode_native_byte_array(importer)("Uint8Array"),
826
+ )("buffer")
827
+ : ExpressionFactory.selfCall(
828
+ ts.factory.createBlock(
829
+ [
830
+ StatementFactory.constant(
831
+ "length",
832
+ ts.factory.createCallExpression(
833
+ COALESCE(importer)("integer"),
834
+ undefined,
835
+ [],
836
+ ),
837
+ ),
838
+ StatementFactory.constant(
839
+ "buffer",
840
+ ts.factory.createNewExpression(
841
+ ts.factory.createIdentifier("SharedArrayBuffer"),
842
+ [],
843
+ [ts.factory.createIdentifier("length")],
844
+ ),
845
+ ),
846
+ StatementFactory.constant(
847
+ "bytes",
848
+ ts.factory.createNewExpression(
849
+ ts.factory.createIdentifier("Uint8Array"),
850
+ [],
851
+ [ts.factory.createIdentifier("buffer")],
852
+ ),
853
+ ),
854
+ ts.factory.createExpressionStatement(
855
+ ts.factory.createCallExpression(
856
+ IdentifierFactory.access(
857
+ ts.factory.createIdentifier("bytes"),
858
+ )("set"),
859
+ undefined,
860
+ [
861
+ ts.factory.createCallExpression(
862
+ COALESCE(importer)("array"),
863
+ undefined,
864
+ [
865
+ ts.factory.createArrowFunction(
866
+ undefined,
867
+ undefined,
868
+ [],
869
+ TypeFactory.keyword("any"),
870
+ undefined,
871
+ ts.factory.createCallExpression(
872
+ COALESCE(importer)("integer"),
873
+ undefined,
874
+ [
875
+ ExpressionFactory.number(0),
876
+ ExpressionFactory.number(255),
877
+ ],
878
+ ),
879
+ ),
880
+ ts.factory.createIdentifier("length"),
881
+ ],
882
+ ),
883
+ ExpressionFactory.number(0),
884
+ ],
885
+ ),
886
+ ),
887
+ ts.factory.createReturnStatement(
888
+ ts.factory.createIdentifier("buffer"),
889
+ ),
890
+ ],
891
+ true,
892
+ ),
893
+ );
894
+
895
+ const decode_native_data_view = (importer: FunctionImporter) =>
896
+ ts.factory.createNewExpression(
897
+ ts.factory.createIdentifier("DataView"),
898
+ [],
899
+ [
900
+ IdentifierFactory.access(
901
+ decode_native_byte_array(importer)("Uint8Array"),
902
+ )("buffer"),
903
+ ],
904
+ );
905
+
906
+ const decode_regexp = () =>
907
+ ts.factory.createNewExpression(
908
+ ts.factory.createIdentifier("RegExp"),
909
+ [],
910
+ [ts.factory.createIdentifier("/(?:)/")],
911
+ );
912
+ }
913
+
914
+ type Atomic = boolean | number | string | bigint;
915
+ interface IExplore {
916
+ function: boolean;
917
+ recursive: boolean;
918
+ }
919
+
920
+ const Prefix = {
921
+ object: (i: number) => `$ro${i}`,
922
+ array: (i: number) => `$ra${i}`,
923
+ tuple: (i: number) => `$rt${i}`,
924
+ };
925
+
926
+ const COALESCE = (importer: FunctionImporter) => (name: string) =>
927
+ ExpressionFactory.coalesce(
928
+ Escaper.variable(name)
929
+ ? ts.factory.createPropertyAccessChain(
930
+ ts.factory.createIdentifier("_generator"),
931
+ ts.factory.createToken(ts.SyntaxKind.QuestionDotToken),
932
+ ts.factory.createIdentifier(name),
933
+ )
934
+ : ts.factory.createElementAccessChain(
935
+ ts.factory.createIdentifier("_generator"),
936
+ ts.factory.createToken(ts.SyntaxKind.QuestionDotToken),
937
+ ts.factory.createStringLiteral(name),
938
+ ),
939
+ )(IdentifierFactory.access(importer.use("generator"))(name));
940
+
941
+ const emendFormat = (key: keyof Format.Validator) =>
942
+ key === "date-time"
943
+ ? "datetime"
944
+ : key
945
+ .split("-")
946
+ .map((str, i) =>
947
+ i === 0 || str.length === 0
948
+ ? str
949
+ : str[0]!.toUpperCase() + str.substring(1),
950
+ )
951
+ .join("");