typia 5.2.5 → 5.2.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 (64) hide show
  1. package/lib/factories/ExpressionFactory.d.ts +1 -0
  2. package/lib/factories/ExpressionFactory.js +5 -0
  3. package/lib/factories/ExpressionFactory.js.map +1 -1
  4. package/lib/programmers/CheckerProgrammer.js +4 -4
  5. package/lib/programmers/CheckerProgrammer.js.map +1 -1
  6. package/lib/programmers/RandomProgrammer.js +16 -18
  7. package/lib/programmers/RandomProgrammer.js.map +1 -1
  8. package/lib/programmers/ValidateProgrammer.js +2 -1
  9. package/lib/programmers/ValidateProgrammer.js.map +1 -1
  10. package/lib/programmers/helpers/RandomJoiner.js +4 -6
  11. package/lib/programmers/helpers/RandomJoiner.js.map +1 -1
  12. package/lib/programmers/helpers/RandomRanger.js +3 -2
  13. package/lib/programmers/helpers/RandomRanger.js.map +1 -1
  14. package/lib/programmers/http/HttpHeadersProgrammer.js +1 -1
  15. package/lib/programmers/http/HttpHeadersProgrammer.js.map +1 -1
  16. package/lib/programmers/internal/check_dynamic_properties.js +4 -3
  17. package/lib/programmers/internal/check_dynamic_properties.js.map +1 -1
  18. package/lib/programmers/internal/check_union_array_like.js +3 -2
  19. package/lib/programmers/internal/check_union_array_like.js.map +1 -1
  20. package/lib/programmers/json/JsonStringifyProgrammer.js +1 -3
  21. package/lib/programmers/json/JsonStringifyProgrammer.js.map +1 -1
  22. package/lib/programmers/misc/MiscCloneProgrammer.js +1 -3
  23. package/lib/programmers/misc/MiscCloneProgrammer.js.map +1 -1
  24. package/lib/programmers/misc/MiscLiteralsProgrammer.js +1 -1
  25. package/lib/programmers/misc/MiscLiteralsProgrammer.js.map +1 -1
  26. package/lib/programmers/misc/MiscPruneProgrammer.js +1 -3
  27. package/lib/programmers/misc/MiscPruneProgrammer.js.map +1 -1
  28. package/lib/programmers/notations/NotationGeneralProgrammer.js +1 -3
  29. package/lib/programmers/notations/NotationGeneralProgrammer.js.map +1 -1
  30. package/lib/programmers/protobuf/ProtobufDecodeProgrammer.js +6 -6
  31. package/lib/programmers/protobuf/ProtobufDecodeProgrammer.js.map +1 -1
  32. package/lib/programmers/protobuf/ProtobufEncodeProgrammer.js +2 -2
  33. package/lib/programmers/protobuf/ProtobufEncodeProgrammer.js.map +1 -1
  34. package/package.json +1 -1
  35. package/src/Primitive.ts +135 -135
  36. package/src/executable/TypiaSetupWizard.ts +142 -142
  37. package/src/executable/setup/CommandExecutor.ts +8 -8
  38. package/src/factories/ExpressionFactory.ts +8 -0
  39. package/src/factories/JsonMetadataFactory.ts +50 -50
  40. package/src/factories/MetadataCollection.ts +282 -282
  41. package/src/factories/internal/metadata/emplace_metadata_object.ts +178 -178
  42. package/src/functional/$stoll.ts +8 -8
  43. package/src/functional/Namespace.ts +168 -168
  44. package/src/programmers/AssertProgrammer.ts +322 -322
  45. package/src/programmers/CheckerProgrammer.ts +4 -4
  46. package/src/programmers/IsProgrammer.ts +258 -258
  47. package/src/programmers/RandomProgrammer.ts +16 -17
  48. package/src/programmers/ValidateProgrammer.ts +350 -349
  49. package/src/programmers/helpers/AtomicPredicator.ts +31 -31
  50. package/src/programmers/helpers/RandomJoiner.ts +4 -6
  51. package/src/programmers/helpers/RandomRanger.ts +4 -2
  52. package/src/programmers/http/HttpHeadersProgrammer.ts +1 -1
  53. package/src/programmers/internal/check_dynamic_key.ts +178 -178
  54. package/src/programmers/internal/check_dynamic_properties.ts +202 -201
  55. package/src/programmers/internal/check_object.ts +62 -62
  56. package/src/programmers/internal/check_union_array_like.ts +4 -3
  57. package/src/programmers/json/JsonStringifyProgrammer.ts +960 -964
  58. package/src/programmers/misc/MiscCloneProgrammer.ts +786 -790
  59. package/src/programmers/misc/MiscLiteralsProgrammer.ts +1 -1
  60. package/src/programmers/misc/MiscPruneProgrammer.ts +548 -552
  61. package/src/programmers/notations/NotationGeneralProgrammer.ts +716 -720
  62. package/src/programmers/protobuf/ProtobufDecodeProgrammer.ts +7 -9
  63. package/src/programmers/protobuf/ProtobufEncodeProgrammer.ts +882 -882
  64. package/src/transform.ts +35 -35
@@ -1,882 +1,882 @@
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 { NumericRangeFactory } from "../../factories/NumericRangeFactory";
7
- import { ProtobufFactory } from "../../factories/ProtobufFactory";
8
- import { StatementFactory } from "../../factories/StatementFactory";
9
- import { TypeFactory } from "../../factories/TypeFactory";
10
-
11
- import { Metadata } from "../../schemas/metadata/Metadata";
12
- import { MetadataArray } from "../../schemas/metadata/MetadataArray";
13
- import { MetadataAtomic } from "../../schemas/metadata/MetadataAtomic";
14
- import { MetadataObject } from "../../schemas/metadata/MetadataObject";
15
- import { MetadataProperty } from "../../schemas/metadata/MetadataProperty";
16
-
17
- import { IProject } from "../../transformers/IProject";
18
-
19
- import { ProtobufAtomic } from "../../typings/ProtobufAtomic";
20
-
21
- import { FeatureProgrammer } from "../FeatureProgrammer";
22
- import { IsProgrammer } from "../IsProgrammer";
23
- import { FunctionImporter } from "../helpers/FunctionImporeter";
24
- import { ProtobufUtil } from "../helpers/ProtobufUtil";
25
- import { ProtobufWire } from "../helpers/ProtobufWire";
26
- import { UnionPredicator } from "../helpers/UnionPredicator";
27
- import { decode_union_object } from "../internal/decode_union_object";
28
-
29
- export namespace ProtobufEncodeProgrammer {
30
- export const write =
31
- (project: IProject) =>
32
- (modulo: ts.LeftHandSideExpression) =>
33
- (type: ts.Type, name?: string): ts.ArrowFunction => {
34
- const importer = new FunctionImporter(modulo.getText());
35
- const collection = new MetadataCollection();
36
- const meta: Metadata = ProtobufFactory.metadata(modulo.getText())(
37
- project.checker,
38
- )(collection)(type);
39
-
40
- const callEncoder =
41
- (writer: string) => (factory: ts.NewExpression) =>
42
- StatementFactory.constant(
43
- writer,
44
- ts.factory.createCallExpression(
45
- ts.factory.createIdentifier("encoder"),
46
- undefined,
47
- [factory],
48
- ),
49
- );
50
-
51
- const block: ts.Statement[] = [
52
- StatementFactory.constant(
53
- "encoder",
54
- write_encoder(project)(importer)(collection)(meta),
55
- ),
56
- callEncoder("sizer")(
57
- ts.factory.createNewExpression(
58
- importer.use("Sizer"),
59
- undefined,
60
- [],
61
- ),
62
- ),
63
- callEncoder("writer")(
64
- ts.factory.createNewExpression(
65
- importer.use("Writer"),
66
- undefined,
67
- [ts.factory.createIdentifier("sizer")],
68
- ),
69
- ),
70
- ts.factory.createReturnStatement(
71
- ts.factory.createCallExpression(
72
- IdentifierFactory.access(WRITER())("buffer"),
73
- undefined,
74
- undefined,
75
- ),
76
- ),
77
- ];
78
-
79
- return ts.factory.createArrowFunction(
80
- undefined,
81
- undefined,
82
- [
83
- IdentifierFactory.parameter(
84
- "input",
85
- ts.factory.createTypeReferenceNode(
86
- name ??
87
- TypeFactory.getFullName(project.checker)(type),
88
- ),
89
- ),
90
- ],
91
- ts.factory.createTypeReferenceNode("Uint8Array"),
92
- undefined,
93
- ts.factory.createBlock(
94
- [...importer.declare(modulo, false), ...block],
95
- true,
96
- ),
97
- );
98
- };
99
-
100
- const write_encoder =
101
- (project: IProject) =>
102
- (importer: FunctionImporter) =>
103
- (collection: MetadataCollection) =>
104
- (meta: Metadata): ts.ArrowFunction => {
105
- const functors = collection
106
- .objects()
107
- .filter((obj) => ProtobufUtil.isStaticObject(obj))
108
- .map((obj) =>
109
- StatementFactory.constant(
110
- `${PREFIX}o${obj.index}`,
111
- write_object_function(project)(importer)(
112
- ts.factory.createIdentifier("input"),
113
- obj,
114
- {
115
- source: "function",
116
- from: "object",
117
- tracable: false,
118
- postfix: "",
119
- },
120
- ),
121
- ),
122
- );
123
- const main = decode(project)(importer)(null)(
124
- ts.factory.createIdentifier("input"),
125
- meta,
126
- {
127
- source: "top",
128
- from: "top",
129
- tracable: false,
130
- postfix: "",
131
- },
132
- );
133
- return ts.factory.createArrowFunction(
134
- undefined,
135
- undefined,
136
- [IdentifierFactory.parameter("writer")],
137
- TypeFactory.keyword("any"),
138
- undefined,
139
- ts.factory.createBlock(
140
- [
141
- ...importer.declareUnions(),
142
- ...functors,
143
- ...IsProgrammer.write_function_statements(project)(
144
- importer,
145
- )(collection),
146
- ...main.statements,
147
- ts.factory.createReturnStatement(
148
- ts.factory.createIdentifier("writer"),
149
- ),
150
- ],
151
- true,
152
- ),
153
- );
154
- };
155
-
156
- const write_object_function =
157
- (project: IProject) =>
158
- (importer: FunctionImporter) =>
159
- (
160
- input: ts.Expression,
161
- obj: MetadataObject,
162
- explore: FeatureProgrammer.IExplore,
163
- ): ts.ArrowFunction => {
164
- let index: number = 1;
165
- const body: ts.Statement[] = obj.properties
166
- .map((p) => {
167
- const block = decode(project)(importer)(index)(
168
- IdentifierFactory.access(input)(
169
- p.key.getSoleLiteral()!,
170
- ),
171
- p.value,
172
- explore,
173
- );
174
- index += ProtobufUtil.size(p.value);
175
- return [
176
- ts.factory.createExpressionStatement(
177
- ts.factory.createIdentifier(
178
- `// property "${p.key.getSoleLiteral()!}"`,
179
- ),
180
- ),
181
- ...block.statements,
182
- ];
183
- })
184
- .flat();
185
-
186
- return ts.factory.createArrowFunction(
187
- undefined,
188
- undefined,
189
- [IdentifierFactory.parameter("input")],
190
- TypeFactory.keyword("any"),
191
- undefined,
192
- ts.factory.createBlock(body, true),
193
- );
194
- };
195
-
196
- /* -----------------------------------------------------------
197
- DECODERS
198
- ----------------------------------------------------------- */
199
- const decode =
200
- (project: IProject) =>
201
- (importer: FunctionImporter) =>
202
- (index: number | null) =>
203
- (
204
- input: ts.Expression,
205
- meta: Metadata,
206
- explore: FeatureProgrammer.IExplore,
207
- ): ts.Block => {
208
- const wrapper: (block: ts.Block) => ts.Block =
209
- meta.isRequired() && meta.nullable === false
210
- ? (block) => block
211
- : meta.isRequired() === false && meta.nullable === true
212
- ? (block) =>
213
- ts.factory.createBlock(
214
- [
215
- ts.factory.createIfStatement(
216
- ts.factory.createLogicalAnd(
217
- ts.factory.createStrictInequality(
218
- ts.factory.createIdentifier(
219
- "undefined",
220
- ),
221
- input,
222
- ),
223
- ts.factory.createStrictInequality(
224
- ts.factory.createNull(),
225
- input,
226
- ),
227
- ),
228
- block,
229
- ),
230
- ],
231
- true,
232
- )
233
- : meta.isRequired() === false
234
- ? (block) =>
235
- ts.factory.createBlock(
236
- [
237
- ts.factory.createIfStatement(
238
- ts.factory.createStrictInequality(
239
- ts.factory.createIdentifier(
240
- "undefined",
241
- ),
242
- input,
243
- ),
244
- block,
245
- ),
246
- ],
247
- true,
248
- )
249
- : (block) =>
250
- ts.factory.createBlock(
251
- [
252
- ts.factory.createIfStatement(
253
- ts.factory.createStrictInequality(
254
- ts.factory.createNull(),
255
- input,
256
- ),
257
- block,
258
- ),
259
- ],
260
- true,
261
- );
262
-
263
- // STARTS FROM ATOMIC TYPES
264
- const unions: IUnion[] = [];
265
- const numbers = ProtobufUtil.getNumbers(meta);
266
- const bigints = ProtobufUtil.getBigints(meta);
267
-
268
- for (const atom of ProtobufUtil.getAtomics(meta))
269
- if (atom === "bool")
270
- unions.push({
271
- type: "bool",
272
- is: () =>
273
- ts.factory.createStrictEquality(
274
- ts.factory.createStringLiteral("boolean"),
275
- ts.factory.createTypeOfExpression(input),
276
- ),
277
- value: (index) => decode_bool(index)(input),
278
- });
279
- else if (
280
- atom === "int32" ||
281
- atom === "uint32" ||
282
- atom === "float" ||
283
- atom === "double"
284
- )
285
- unions.push(decode_number(project)(numbers)(atom)(input));
286
- else if (atom === "int64" || atom === "uint64")
287
- if (numbers.some((n) => n === atom))
288
- unions.push(
289
- decode_number(project)(numbers)(atom)(input),
290
- );
291
- else
292
- unions.push(
293
- decode_bigint(project)(bigints)(atom)(input),
294
- );
295
- else if (atom === "string")
296
- unions.push({
297
- type: "string",
298
- is: () =>
299
- ts.factory.createStrictEquality(
300
- ts.factory.createStringLiteral("string"),
301
- ts.factory.createTypeOfExpression(input),
302
- ),
303
- value: (index) => decode_bytes("string")(index!)(input),
304
- });
305
-
306
- // CONSIDER BYTES
307
- if (meta.natives.length)
308
- unions.push({
309
- type: "bytes",
310
- is: () =>
311
- ExpressionFactory.isInstanceOf("Uint8Array")(input),
312
- value: (index) => decode_bytes("bytes")(index!)(input),
313
- });
314
-
315
- // CONSIDER ARRAYS
316
- if (meta.arrays.length)
317
- unions.push({
318
- type: "array",
319
- is: () => ExpressionFactory.isArray(input),
320
- value: (index) =>
321
- decode_array(project)(importer)(index!)(
322
- input,
323
- meta.arrays[0]!,
324
- {
325
- ...explore,
326
- from: "array",
327
- },
328
- ),
329
- });
330
-
331
- // CONSIDER MAPS
332
- if (meta.maps.length)
333
- unions.push({
334
- type: "map",
335
- is: () => ExpressionFactory.isInstanceOf("Map")(input),
336
- value: (index) =>
337
- decode_map(project)(importer)(index!)(
338
- input,
339
- meta.maps[0]!,
340
- {
341
- ...explore,
342
- from: "array",
343
- },
344
- ),
345
- });
346
-
347
- // CONSIDER OBJECTS
348
- if (meta.objects.length)
349
- unions.push({
350
- type: "object",
351
- is: () =>
352
- ExpressionFactory.isObject({
353
- checkNull: true,
354
- checkArray: false,
355
- })(input),
356
- value: (index) =>
357
- explore_objects(project)(importer)(0)(index)(
358
- input,
359
- meta.objects,
360
- {
361
- ...explore,
362
- from: "object",
363
- },
364
- ),
365
- });
366
-
367
- // RETURNS
368
- if (unions.length === 1) return wrapper(unions[0]!.value(index));
369
- else
370
- return wrapper(
371
- iterate(importer)(index)(unions)(meta.getName())(input),
372
- );
373
- };
374
-
375
- const iterate =
376
- (importer: FunctionImporter) =>
377
- (index: number | null) =>
378
- (unions: IUnion[]) =>
379
- (expected: string) =>
380
- (input: ts.Expression) =>
381
- ts.factory.createBlock(
382
- [
383
- unions
384
- .map((u, i) =>
385
- ts.factory.createIfStatement(
386
- u.is(),
387
- u.value(index ? index + i : null),
388
- i === unions.length - 1
389
- ? create_throw_error(importer)(expected)(
390
- input,
391
- )
392
- : undefined,
393
- ),
394
- )
395
- .reverse()
396
- .reduce((a, b) =>
397
- ts.factory.createIfStatement(
398
- b.expression,
399
- b.thenStatement,
400
- a,
401
- ),
402
- ),
403
- ],
404
- true,
405
- );
406
-
407
- const decode_map =
408
- (project: IProject) =>
409
- (importer: FunctionImporter) =>
410
- (index: number) =>
411
- (
412
- input: ts.Expression,
413
- map: Metadata.Entry,
414
- explore: FeatureProgrammer.IExplore,
415
- ): ts.Block => {
416
- const each: ts.Statement[] = [
417
- ts.factory.createExpressionStatement(
418
- decode_tag(ProtobufWire.LEN)(index),
419
- ),
420
- ts.factory.createExpressionStatement(
421
- ts.factory.createCallExpression(
422
- IdentifierFactory.access(WRITER())("fork"),
423
- undefined,
424
- undefined,
425
- ),
426
- ),
427
- ...decode(project)(importer)(1)(
428
- ts.factory.createIdentifier("key"),
429
- map.key,
430
- explore,
431
- ).statements,
432
- ...decode(project)(importer)(2)(
433
- ts.factory.createIdentifier("value"),
434
- map.value,
435
- explore,
436
- ).statements,
437
- ts.factory.createExpressionStatement(
438
- ts.factory.createCallExpression(
439
- IdentifierFactory.access(WRITER())("ldelim"),
440
- undefined,
441
- undefined,
442
- ),
443
- ),
444
- ];
445
- return ts.factory.createBlock(
446
- [
447
- ts.factory.createForOfStatement(
448
- undefined,
449
- StatementFactory.entry("key")("value"),
450
- input,
451
- ts.factory.createBlock(each),
452
- ),
453
- ],
454
- true,
455
- );
456
- };
457
-
458
- const decode_object =
459
- (project: IProject) =>
460
- (importer: FunctionImporter) =>
461
- (index: number | null) =>
462
- (
463
- input: ts.Expression,
464
- object: MetadataObject,
465
- explore: FeatureProgrammer.IExplore,
466
- ): ts.Block => {
467
- const top: MetadataProperty = object.properties[0]!;
468
- if (top.key.isSoleLiteral() === false)
469
- return decode_map(project)(importer)(index!)(
470
- ts.factory.createCallExpression(
471
- ts.factory.createIdentifier("Object.entries"),
472
- [],
473
- [input],
474
- ),
475
- MetadataProperty.create({
476
- ...top,
477
- key: (() => {
478
- const key: Metadata = Metadata.initialize();
479
- key.atomics.push(
480
- MetadataAtomic.create({
481
- type: "string",
482
- tags: [],
483
- }),
484
- );
485
- return key;
486
- })(),
487
- }),
488
- explore,
489
- );
490
- return ts.factory.createBlock(
491
- [
492
- ts.factory.createIdentifier(
493
- `//${index !== null ? ` ${index} -> ` : ""}${
494
- object.name
495
- }`,
496
- ),
497
- ...(index !== null
498
- ? [
499
- decode_tag(ProtobufWire.LEN)(index),
500
- ts.factory.createCallExpression(
501
- IdentifierFactory.access(WRITER())("fork"),
502
- undefined,
503
- undefined,
504
- ),
505
- ]
506
- : []),
507
- ts.factory.createCallExpression(
508
- ts.factory.createIdentifier(
509
- importer.useLocal(`${PREFIX}o${object.index}`),
510
- ),
511
- [],
512
- [input],
513
- ),
514
- ...(index !== null
515
- ? [
516
- ts.factory.createCallExpression(
517
- IdentifierFactory.access(WRITER())("ldelim"),
518
- undefined,
519
- undefined,
520
- ),
521
- ]
522
- : []),
523
- ].map((expr) => ts.factory.createExpressionStatement(expr)),
524
- true,
525
- );
526
- };
527
-
528
- const decode_array =
529
- (project: IProject) =>
530
- (importer: FunctionImporter) =>
531
- (index: number) =>
532
- (
533
- input: ts.Expression,
534
- array: MetadataArray,
535
- explore: FeatureProgrammer.IExplore,
536
- ): ts.Block => {
537
- const wire = get_standalone_wire(array.type.value);
538
- const forLoop = (index: number | null) =>
539
- ts.factory.createForOfStatement(
540
- undefined,
541
- ts.factory.createVariableDeclarationList(
542
- [ts.factory.createVariableDeclaration("elem")],
543
- ts.NodeFlags.Const,
544
- ),
545
- input,
546
- decode(project)(importer)(index)(
547
- ts.factory.createIdentifier("elem"),
548
- array.type.value,
549
- explore,
550
- ),
551
- );
552
- const length = (block: ts.Block) =>
553
- ts.factory.createBlock(
554
- [
555
- ts.factory.createIfStatement(
556
- ts.factory.createStrictInequality(
557
- ts.factory.createNumericLiteral(0),
558
- IdentifierFactory.access(input)("length"),
559
- ),
560
- block,
561
- ),
562
- ],
563
- true,
564
- );
565
-
566
- if (wire === ProtobufWire.LEN)
567
- return length(ts.factory.createBlock([forLoop(index)], true));
568
- return length(
569
- ts.factory.createBlock(
570
- [
571
- ts.factory.createExpressionStatement(
572
- decode_tag(ProtobufWire.LEN)(index),
573
- ),
574
- ts.factory.createExpressionStatement(
575
- ts.factory.createCallExpression(
576
- IdentifierFactory.access(WRITER())("fork"),
577
- undefined,
578
- undefined,
579
- ),
580
- ),
581
- forLoop(null),
582
- ts.factory.createExpressionStatement(
583
- ts.factory.createCallExpression(
584
- IdentifierFactory.access(WRITER())("ldelim"),
585
- undefined,
586
- undefined,
587
- ),
588
- ),
589
- ],
590
- true,
591
- ),
592
- );
593
- };
594
-
595
- const decode_bool = (index: number | null) => (input: ts.Expression) =>
596
- ts.factory.createBlock(
597
- [
598
- ...(index !== null
599
- ? [decode_tag(ProtobufWire.VARIANT)(index)]
600
- : []),
601
- ts.factory.createCallExpression(
602
- IdentifierFactory.access(WRITER())("bool"),
603
- undefined,
604
- [input],
605
- ),
606
- ].map((exp) => ts.factory.createExpressionStatement(exp)),
607
- true,
608
- );
609
-
610
- const decode_number =
611
- (project: IProject) =>
612
- (candidates: ProtobufAtomic.Numeric[]) =>
613
- (type: ProtobufAtomic.Numeric) =>
614
- (input: ts.Expression): IUnion => ({
615
- type,
616
- is: () =>
617
- candidates.length === 1
618
- ? ts.factory.createStrictEquality(
619
- ts.factory.createStringLiteral("number"),
620
- ts.factory.createTypeOfExpression(input),
621
- )
622
- : ts.factory.createLogicalAnd(
623
- ts.factory.createStrictEquality(
624
- ts.factory.createStringLiteral("number"),
625
- ts.factory.createTypeOfExpression(input),
626
- ),
627
- NumericRangeFactory.number(project.context)(type)(
628
- input,
629
- ),
630
- ),
631
- value: (index) =>
632
- ts.factory.createBlock(
633
- [
634
- ...(index !== null
635
- ? [decode_tag(get_numeric_wire(type))(index)]
636
- : []),
637
- ts.factory.createCallExpression(
638
- IdentifierFactory.access(WRITER())(type),
639
- undefined,
640
- [input],
641
- ),
642
- ].map((exp) => ts.factory.createExpressionStatement(exp)),
643
- true,
644
- ),
645
- });
646
-
647
- const decode_bigint =
648
- (project: IProject) =>
649
- (candidates: ProtobufAtomic.BigNumeric[]) =>
650
- (type: ProtobufAtomic.BigNumeric) =>
651
- (input: ts.Expression): IUnion => ({
652
- type,
653
- is: () =>
654
- candidates.length === 1
655
- ? ts.factory.createStrictEquality(
656
- ts.factory.createStringLiteral("bigint"),
657
- ts.factory.createTypeOfExpression(input),
658
- )
659
- : ts.factory.createLogicalAnd(
660
- ts.factory.createStrictEquality(
661
- ts.factory.createStringLiteral("bigint"),
662
- ts.factory.createTypeOfExpression(input),
663
- ),
664
- NumericRangeFactory.bigint(project.context)(type)(
665
- input,
666
- ),
667
- ),
668
- value: (index) =>
669
- ts.factory.createBlock(
670
- [
671
- ...(index !== null
672
- ? [decode_tag(ProtobufWire.VARIANT)(index)]
673
- : []),
674
- ts.factory.createCallExpression(
675
- IdentifierFactory.access(WRITER())(type),
676
- undefined,
677
- [input],
678
- ),
679
- ].map((exp) => ts.factory.createExpressionStatement(exp)),
680
- true,
681
- ),
682
- });
683
-
684
- const decode_bytes =
685
- (method: "bytes" | "string") =>
686
- (index: number) =>
687
- (input: ts.Expression): ts.Block =>
688
- ts.factory.createBlock(
689
- [
690
- decode_tag(ProtobufWire.LEN)(index),
691
- ts.factory.createCallExpression(
692
- IdentifierFactory.access(WRITER())(method),
693
- undefined,
694
- [input],
695
- ),
696
- ].map((expr) => ts.factory.createExpressionStatement(expr)),
697
- true,
698
- );
699
-
700
- const decode_tag =
701
- (wire: ProtobufWire) =>
702
- (index: number): ts.CallExpression =>
703
- ts.factory.createCallExpression(
704
- IdentifierFactory.access(WRITER())("uint32"),
705
- undefined,
706
- [ts.factory.createNumericLiteral((index << 3) | wire)],
707
- );
708
-
709
- const get_standalone_wire = (meta: Metadata): ProtobufWire => {
710
- if (
711
- meta.arrays.length ||
712
- meta.objects.length ||
713
- meta.maps.length ||
714
- meta.natives.length
715
- )
716
- return ProtobufWire.LEN;
717
-
718
- const v = ProtobufUtil.getAtomics(meta)[0]!;
719
- if (v === "string") return ProtobufWire.LEN;
720
- else if (
721
- v === "bool" ||
722
- v === "int32" ||
723
- v === "uint32" ||
724
- v === "int64" ||
725
- v === "uint64"
726
- )
727
- return ProtobufWire.VARIANT;
728
- else if (v === "float") return ProtobufWire.I32;
729
- return ProtobufWire.I64;
730
- };
731
-
732
- const get_numeric_wire = (type: ProtobufAtomic.Numeric) =>
733
- type === "double"
734
- ? ProtobufWire.I64
735
- : type === "float"
736
- ? ProtobufWire.I32
737
- : ProtobufWire.VARIANT;
738
-
739
- /* -----------------------------------------------------------
740
- EXPLORERS
741
- ----------------------------------------------------------- */
742
- const explore_objects =
743
- (project: IProject) =>
744
- (importer: FunctionImporter) =>
745
- (level: number) =>
746
- (index: number | null) =>
747
- (
748
- input: ts.Expression,
749
- targets: MetadataObject[],
750
- explore: FeatureProgrammer.IExplore,
751
- indexes?: Map<MetadataObject, number>,
752
- ): ts.Block => {
753
- if (targets.length === 1)
754
- return decode_object(project)(importer)(
755
- indexes ? indexes.get(targets[0]!)! : index,
756
- )(input, targets[0]!, explore);
757
-
758
- const expected: string = `(${targets
759
- .map((t) => t.name)
760
- .join(" | ")})`;
761
-
762
- // POSSIBLE TO SPECIALIZE?
763
- const specList = UnionPredicator.object(targets);
764
- indexes ??= new Map(targets.map((t, i) => [t, index! + i]));
765
-
766
- if (specList.length === 0) {
767
- const condition: ts.Expression = decode_union_object(
768
- IsProgrammer.decode_object(project)(importer),
769
- )((i, o, e) =>
770
- ExpressionFactory.selfCall(
771
- decode_object(project)(importer)(indexes!.get(o)!)(
772
- i,
773
- o,
774
- e,
775
- ),
776
- ),
777
- )((expr) => expr)((value, expected) =>
778
- create_throw_error(importer)(expected)(value),
779
- )(input, targets, explore);
780
- return StatementFactory.block(condition);
781
- }
782
- const remained: MetadataObject[] = targets.filter(
783
- (t) => specList.find((s) => s.object === t) === undefined,
784
- );
785
-
786
- // DO SPECIALIZE
787
- const condition: ts.IfStatement = specList
788
- .filter((spec) => spec.property.key.getSoleLiteral() !== null)
789
- .map((spec, i, array) => {
790
- const key: string = spec.property.key.getSoleLiteral()!;
791
- const accessor: ts.Expression =
792
- IdentifierFactory.access(input)(key);
793
- const pred: ts.Expression = spec.neighbour
794
- ? IsProgrammer.decode(project)(importer)(
795
- accessor,
796
- spec.property.value,
797
- {
798
- ...explore,
799
- tracable: false,
800
- postfix: IdentifierFactory.postfix(key),
801
- },
802
- )
803
- : ExpressionFactory.isRequired(accessor);
804
- return ts.factory.createIfStatement(
805
- pred,
806
- ts.factory.createReturnStatement(
807
- ExpressionFactory.selfCall(
808
- decode_object(project)(importer)(
809
- indexes!.get(spec.object)!,
810
- )(input, spec.object, explore),
811
- ),
812
- ),
813
- i === array.length - 1
814
- ? remained.length
815
- ? ts.factory.createReturnStatement(
816
- ExpressionFactory.selfCall(
817
- explore_objects(project)(importer)(
818
- level + 1,
819
- )(index)(
820
- input,
821
- remained,
822
- explore,
823
- indexes!,
824
- ),
825
- ),
826
- )
827
- : create_throw_error(importer)(expected)(input)
828
- : undefined,
829
- );
830
- })
831
- .reverse()
832
- .reduce((a, b) =>
833
- ts.factory.createIfStatement(
834
- b.expression,
835
- b.thenStatement,
836
- a,
837
- ),
838
- );
839
-
840
- // RETURNS WITH CONDITIONS
841
- return ts.factory.createBlock([condition], true);
842
- };
843
-
844
- /* -----------------------------------------------------------
845
- CONFIGURATIONS
846
- ----------------------------------------------------------- */
847
- const PREFIX = "$pe";
848
-
849
- const create_throw_error =
850
- (importer: FunctionImporter) =>
851
- (expected: string) =>
852
- (value: ts.Expression) =>
853
- ts.factory.createExpressionStatement(
854
- ts.factory.createCallExpression(
855
- importer.use("throws"),
856
- [],
857
- [
858
- ts.factory.createObjectLiteralExpression(
859
- [
860
- ts.factory.createPropertyAssignment(
861
- "expected",
862
- ts.factory.createStringLiteral(expected),
863
- ),
864
- ts.factory.createPropertyAssignment(
865
- "value",
866
- value,
867
- ),
868
- ],
869
- true,
870
- ),
871
- ],
872
- ),
873
- );
874
- }
875
-
876
- const WRITER = () => ts.factory.createIdentifier("writer");
877
-
878
- interface IUnion {
879
- type: string;
880
- is: () => ts.Expression;
881
- value: (index: number | null) => ts.Block;
882
- }
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 { NumericRangeFactory } from "../../factories/NumericRangeFactory";
7
+ import { ProtobufFactory } from "../../factories/ProtobufFactory";
8
+ import { StatementFactory } from "../../factories/StatementFactory";
9
+ import { TypeFactory } from "../../factories/TypeFactory";
10
+
11
+ import { Metadata } from "../../schemas/metadata/Metadata";
12
+ import { MetadataArray } from "../../schemas/metadata/MetadataArray";
13
+ import { MetadataAtomic } from "../../schemas/metadata/MetadataAtomic";
14
+ import { MetadataObject } from "../../schemas/metadata/MetadataObject";
15
+ import { MetadataProperty } from "../../schemas/metadata/MetadataProperty";
16
+
17
+ import { IProject } from "../../transformers/IProject";
18
+
19
+ import { ProtobufAtomic } from "../../typings/ProtobufAtomic";
20
+
21
+ import { FeatureProgrammer } from "../FeatureProgrammer";
22
+ import { IsProgrammer } from "../IsProgrammer";
23
+ import { FunctionImporter } from "../helpers/FunctionImporeter";
24
+ import { ProtobufUtil } from "../helpers/ProtobufUtil";
25
+ import { ProtobufWire } from "../helpers/ProtobufWire";
26
+ import { UnionPredicator } from "../helpers/UnionPredicator";
27
+ import { decode_union_object } from "../internal/decode_union_object";
28
+
29
+ export namespace ProtobufEncodeProgrammer {
30
+ export const write =
31
+ (project: IProject) =>
32
+ (modulo: ts.LeftHandSideExpression) =>
33
+ (type: ts.Type, name?: string): ts.ArrowFunction => {
34
+ const importer = new FunctionImporter(modulo.getText());
35
+ const collection = new MetadataCollection();
36
+ const meta: Metadata = ProtobufFactory.metadata(modulo.getText())(
37
+ project.checker,
38
+ )(collection)(type);
39
+
40
+ const callEncoder =
41
+ (writer: string) => (factory: ts.NewExpression) =>
42
+ StatementFactory.constant(
43
+ writer,
44
+ ts.factory.createCallExpression(
45
+ ts.factory.createIdentifier("encoder"),
46
+ undefined,
47
+ [factory],
48
+ ),
49
+ );
50
+
51
+ const block: ts.Statement[] = [
52
+ StatementFactory.constant(
53
+ "encoder",
54
+ write_encoder(project)(importer)(collection)(meta),
55
+ ),
56
+ callEncoder("sizer")(
57
+ ts.factory.createNewExpression(
58
+ importer.use("Sizer"),
59
+ undefined,
60
+ [],
61
+ ),
62
+ ),
63
+ callEncoder("writer")(
64
+ ts.factory.createNewExpression(
65
+ importer.use("Writer"),
66
+ undefined,
67
+ [ts.factory.createIdentifier("sizer")],
68
+ ),
69
+ ),
70
+ ts.factory.createReturnStatement(
71
+ ts.factory.createCallExpression(
72
+ IdentifierFactory.access(WRITER())("buffer"),
73
+ undefined,
74
+ undefined,
75
+ ),
76
+ ),
77
+ ];
78
+
79
+ return ts.factory.createArrowFunction(
80
+ undefined,
81
+ undefined,
82
+ [
83
+ IdentifierFactory.parameter(
84
+ "input",
85
+ ts.factory.createTypeReferenceNode(
86
+ name ??
87
+ TypeFactory.getFullName(project.checker)(type),
88
+ ),
89
+ ),
90
+ ],
91
+ ts.factory.createTypeReferenceNode("Uint8Array"),
92
+ undefined,
93
+ ts.factory.createBlock(
94
+ [...importer.declare(modulo, false), ...block],
95
+ true,
96
+ ),
97
+ );
98
+ };
99
+
100
+ const write_encoder =
101
+ (project: IProject) =>
102
+ (importer: FunctionImporter) =>
103
+ (collection: MetadataCollection) =>
104
+ (meta: Metadata): ts.ArrowFunction => {
105
+ const functors = collection
106
+ .objects()
107
+ .filter((obj) => ProtobufUtil.isStaticObject(obj))
108
+ .map((obj) =>
109
+ StatementFactory.constant(
110
+ `${PREFIX}o${obj.index}`,
111
+ write_object_function(project)(importer)(
112
+ ts.factory.createIdentifier("input"),
113
+ obj,
114
+ {
115
+ source: "function",
116
+ from: "object",
117
+ tracable: false,
118
+ postfix: "",
119
+ },
120
+ ),
121
+ ),
122
+ );
123
+ const main = decode(project)(importer)(null)(
124
+ ts.factory.createIdentifier("input"),
125
+ meta,
126
+ {
127
+ source: "top",
128
+ from: "top",
129
+ tracable: false,
130
+ postfix: "",
131
+ },
132
+ );
133
+ return ts.factory.createArrowFunction(
134
+ undefined,
135
+ undefined,
136
+ [IdentifierFactory.parameter("writer")],
137
+ TypeFactory.keyword("any"),
138
+ undefined,
139
+ ts.factory.createBlock(
140
+ [
141
+ ...importer.declareUnions(),
142
+ ...functors,
143
+ ...IsProgrammer.write_function_statements(project)(
144
+ importer,
145
+ )(collection),
146
+ ...main.statements,
147
+ ts.factory.createReturnStatement(
148
+ ts.factory.createIdentifier("writer"),
149
+ ),
150
+ ],
151
+ true,
152
+ ),
153
+ );
154
+ };
155
+
156
+ const write_object_function =
157
+ (project: IProject) =>
158
+ (importer: FunctionImporter) =>
159
+ (
160
+ input: ts.Expression,
161
+ obj: MetadataObject,
162
+ explore: FeatureProgrammer.IExplore,
163
+ ): ts.ArrowFunction => {
164
+ let index: number = 1;
165
+ const body: ts.Statement[] = obj.properties
166
+ .map((p) => {
167
+ const block = decode(project)(importer)(index)(
168
+ IdentifierFactory.access(input)(
169
+ p.key.getSoleLiteral()!,
170
+ ),
171
+ p.value,
172
+ explore,
173
+ );
174
+ index += ProtobufUtil.size(p.value);
175
+ return [
176
+ ts.factory.createExpressionStatement(
177
+ ts.factory.createIdentifier(
178
+ `// property "${p.key.getSoleLiteral()!}"`,
179
+ ),
180
+ ),
181
+ ...block.statements,
182
+ ];
183
+ })
184
+ .flat();
185
+
186
+ return ts.factory.createArrowFunction(
187
+ undefined,
188
+ undefined,
189
+ [IdentifierFactory.parameter("input")],
190
+ TypeFactory.keyword("any"),
191
+ undefined,
192
+ ts.factory.createBlock(body, true),
193
+ );
194
+ };
195
+
196
+ /* -----------------------------------------------------------
197
+ DECODERS
198
+ ----------------------------------------------------------- */
199
+ const decode =
200
+ (project: IProject) =>
201
+ (importer: FunctionImporter) =>
202
+ (index: number | null) =>
203
+ (
204
+ input: ts.Expression,
205
+ meta: Metadata,
206
+ explore: FeatureProgrammer.IExplore,
207
+ ): ts.Block => {
208
+ const wrapper: (block: ts.Block) => ts.Block =
209
+ meta.isRequired() && meta.nullable === false
210
+ ? (block) => block
211
+ : meta.isRequired() === false && meta.nullable === true
212
+ ? (block) =>
213
+ ts.factory.createBlock(
214
+ [
215
+ ts.factory.createIfStatement(
216
+ ts.factory.createLogicalAnd(
217
+ ts.factory.createStrictInequality(
218
+ ts.factory.createIdentifier(
219
+ "undefined",
220
+ ),
221
+ input,
222
+ ),
223
+ ts.factory.createStrictInequality(
224
+ ts.factory.createNull(),
225
+ input,
226
+ ),
227
+ ),
228
+ block,
229
+ ),
230
+ ],
231
+ true,
232
+ )
233
+ : meta.isRequired() === false
234
+ ? (block) =>
235
+ ts.factory.createBlock(
236
+ [
237
+ ts.factory.createIfStatement(
238
+ ts.factory.createStrictInequality(
239
+ ts.factory.createIdentifier(
240
+ "undefined",
241
+ ),
242
+ input,
243
+ ),
244
+ block,
245
+ ),
246
+ ],
247
+ true,
248
+ )
249
+ : (block) =>
250
+ ts.factory.createBlock(
251
+ [
252
+ ts.factory.createIfStatement(
253
+ ts.factory.createStrictInequality(
254
+ ts.factory.createNull(),
255
+ input,
256
+ ),
257
+ block,
258
+ ),
259
+ ],
260
+ true,
261
+ );
262
+
263
+ // STARTS FROM ATOMIC TYPES
264
+ const unions: IUnion[] = [];
265
+ const numbers = ProtobufUtil.getNumbers(meta);
266
+ const bigints = ProtobufUtil.getBigints(meta);
267
+
268
+ for (const atom of ProtobufUtil.getAtomics(meta))
269
+ if (atom === "bool")
270
+ unions.push({
271
+ type: "bool",
272
+ is: () =>
273
+ ts.factory.createStrictEquality(
274
+ ts.factory.createStringLiteral("boolean"),
275
+ ts.factory.createTypeOfExpression(input),
276
+ ),
277
+ value: (index) => decode_bool(index)(input),
278
+ });
279
+ else if (
280
+ atom === "int32" ||
281
+ atom === "uint32" ||
282
+ atom === "float" ||
283
+ atom === "double"
284
+ )
285
+ unions.push(decode_number(project)(numbers)(atom)(input));
286
+ else if (atom === "int64" || atom === "uint64")
287
+ if (numbers.some((n) => n === atom))
288
+ unions.push(
289
+ decode_number(project)(numbers)(atom)(input),
290
+ );
291
+ else
292
+ unions.push(
293
+ decode_bigint(project)(bigints)(atom)(input),
294
+ );
295
+ else if (atom === "string")
296
+ unions.push({
297
+ type: "string",
298
+ is: () =>
299
+ ts.factory.createStrictEquality(
300
+ ts.factory.createStringLiteral("string"),
301
+ ts.factory.createTypeOfExpression(input),
302
+ ),
303
+ value: (index) => decode_bytes("string")(index!)(input),
304
+ });
305
+
306
+ // CONSIDER BYTES
307
+ if (meta.natives.length)
308
+ unions.push({
309
+ type: "bytes",
310
+ is: () =>
311
+ ExpressionFactory.isInstanceOf("Uint8Array")(input),
312
+ value: (index) => decode_bytes("bytes")(index!)(input),
313
+ });
314
+
315
+ // CONSIDER ARRAYS
316
+ if (meta.arrays.length)
317
+ unions.push({
318
+ type: "array",
319
+ is: () => ExpressionFactory.isArray(input),
320
+ value: (index) =>
321
+ decode_array(project)(importer)(index!)(
322
+ input,
323
+ meta.arrays[0]!,
324
+ {
325
+ ...explore,
326
+ from: "array",
327
+ },
328
+ ),
329
+ });
330
+
331
+ // CONSIDER MAPS
332
+ if (meta.maps.length)
333
+ unions.push({
334
+ type: "map",
335
+ is: () => ExpressionFactory.isInstanceOf("Map")(input),
336
+ value: (index) =>
337
+ decode_map(project)(importer)(index!)(
338
+ input,
339
+ meta.maps[0]!,
340
+ {
341
+ ...explore,
342
+ from: "array",
343
+ },
344
+ ),
345
+ });
346
+
347
+ // CONSIDER OBJECTS
348
+ if (meta.objects.length)
349
+ unions.push({
350
+ type: "object",
351
+ is: () =>
352
+ ExpressionFactory.isObject({
353
+ checkNull: true,
354
+ checkArray: false,
355
+ })(input),
356
+ value: (index) =>
357
+ explore_objects(project)(importer)(0)(index)(
358
+ input,
359
+ meta.objects,
360
+ {
361
+ ...explore,
362
+ from: "object",
363
+ },
364
+ ),
365
+ });
366
+
367
+ // RETURNS
368
+ if (unions.length === 1) return wrapper(unions[0]!.value(index));
369
+ else
370
+ return wrapper(
371
+ iterate(importer)(index)(unions)(meta.getName())(input),
372
+ );
373
+ };
374
+
375
+ const iterate =
376
+ (importer: FunctionImporter) =>
377
+ (index: number | null) =>
378
+ (unions: IUnion[]) =>
379
+ (expected: string) =>
380
+ (input: ts.Expression) =>
381
+ ts.factory.createBlock(
382
+ [
383
+ unions
384
+ .map((u, i) =>
385
+ ts.factory.createIfStatement(
386
+ u.is(),
387
+ u.value(index ? index + i : null),
388
+ i === unions.length - 1
389
+ ? create_throw_error(importer)(expected)(
390
+ input,
391
+ )
392
+ : undefined,
393
+ ),
394
+ )
395
+ .reverse()
396
+ .reduce((a, b) =>
397
+ ts.factory.createIfStatement(
398
+ b.expression,
399
+ b.thenStatement,
400
+ a,
401
+ ),
402
+ ),
403
+ ],
404
+ true,
405
+ );
406
+
407
+ const decode_map =
408
+ (project: IProject) =>
409
+ (importer: FunctionImporter) =>
410
+ (index: number) =>
411
+ (
412
+ input: ts.Expression,
413
+ map: Metadata.Entry,
414
+ explore: FeatureProgrammer.IExplore,
415
+ ): ts.Block => {
416
+ const each: ts.Statement[] = [
417
+ ts.factory.createExpressionStatement(
418
+ decode_tag(ProtobufWire.LEN)(index),
419
+ ),
420
+ ts.factory.createExpressionStatement(
421
+ ts.factory.createCallExpression(
422
+ IdentifierFactory.access(WRITER())("fork"),
423
+ undefined,
424
+ undefined,
425
+ ),
426
+ ),
427
+ ...decode(project)(importer)(1)(
428
+ ts.factory.createIdentifier("key"),
429
+ map.key,
430
+ explore,
431
+ ).statements,
432
+ ...decode(project)(importer)(2)(
433
+ ts.factory.createIdentifier("value"),
434
+ map.value,
435
+ explore,
436
+ ).statements,
437
+ ts.factory.createExpressionStatement(
438
+ ts.factory.createCallExpression(
439
+ IdentifierFactory.access(WRITER())("ldelim"),
440
+ undefined,
441
+ undefined,
442
+ ),
443
+ ),
444
+ ];
445
+ return ts.factory.createBlock(
446
+ [
447
+ ts.factory.createForOfStatement(
448
+ undefined,
449
+ StatementFactory.entry("key")("value"),
450
+ input,
451
+ ts.factory.createBlock(each),
452
+ ),
453
+ ],
454
+ true,
455
+ );
456
+ };
457
+
458
+ const decode_object =
459
+ (project: IProject) =>
460
+ (importer: FunctionImporter) =>
461
+ (index: number | null) =>
462
+ (
463
+ input: ts.Expression,
464
+ object: MetadataObject,
465
+ explore: FeatureProgrammer.IExplore,
466
+ ): ts.Block => {
467
+ const top: MetadataProperty = object.properties[0]!;
468
+ if (top.key.isSoleLiteral() === false)
469
+ return decode_map(project)(importer)(index!)(
470
+ ts.factory.createCallExpression(
471
+ ts.factory.createIdentifier("Object.entries"),
472
+ [],
473
+ [input],
474
+ ),
475
+ MetadataProperty.create({
476
+ ...top,
477
+ key: (() => {
478
+ const key: Metadata = Metadata.initialize();
479
+ key.atomics.push(
480
+ MetadataAtomic.create({
481
+ type: "string",
482
+ tags: [],
483
+ }),
484
+ );
485
+ return key;
486
+ })(),
487
+ }),
488
+ explore,
489
+ );
490
+ return ts.factory.createBlock(
491
+ [
492
+ ts.factory.createIdentifier(
493
+ `//${index !== null ? ` ${index} -> ` : ""}${
494
+ object.name
495
+ }`,
496
+ ),
497
+ ...(index !== null
498
+ ? [
499
+ decode_tag(ProtobufWire.LEN)(index),
500
+ ts.factory.createCallExpression(
501
+ IdentifierFactory.access(WRITER())("fork"),
502
+ undefined,
503
+ undefined,
504
+ ),
505
+ ]
506
+ : []),
507
+ ts.factory.createCallExpression(
508
+ ts.factory.createIdentifier(
509
+ importer.useLocal(`${PREFIX}o${object.index}`),
510
+ ),
511
+ [],
512
+ [input],
513
+ ),
514
+ ...(index !== null
515
+ ? [
516
+ ts.factory.createCallExpression(
517
+ IdentifierFactory.access(WRITER())("ldelim"),
518
+ undefined,
519
+ undefined,
520
+ ),
521
+ ]
522
+ : []),
523
+ ].map((expr) => ts.factory.createExpressionStatement(expr)),
524
+ true,
525
+ );
526
+ };
527
+
528
+ const decode_array =
529
+ (project: IProject) =>
530
+ (importer: FunctionImporter) =>
531
+ (index: number) =>
532
+ (
533
+ input: ts.Expression,
534
+ array: MetadataArray,
535
+ explore: FeatureProgrammer.IExplore,
536
+ ): ts.Block => {
537
+ const wire = get_standalone_wire(array.type.value);
538
+ const forLoop = (index: number | null) =>
539
+ ts.factory.createForOfStatement(
540
+ undefined,
541
+ ts.factory.createVariableDeclarationList(
542
+ [ts.factory.createVariableDeclaration("elem")],
543
+ ts.NodeFlags.Const,
544
+ ),
545
+ input,
546
+ decode(project)(importer)(index)(
547
+ ts.factory.createIdentifier("elem"),
548
+ array.type.value,
549
+ explore,
550
+ ),
551
+ );
552
+ const length = (block: ts.Block) =>
553
+ ts.factory.createBlock(
554
+ [
555
+ ts.factory.createIfStatement(
556
+ ts.factory.createStrictInequality(
557
+ ExpressionFactory.number(0),
558
+ IdentifierFactory.access(input)("length"),
559
+ ),
560
+ block,
561
+ ),
562
+ ],
563
+ true,
564
+ );
565
+
566
+ if (wire === ProtobufWire.LEN)
567
+ return length(ts.factory.createBlock([forLoop(index)], true));
568
+ return length(
569
+ ts.factory.createBlock(
570
+ [
571
+ ts.factory.createExpressionStatement(
572
+ decode_tag(ProtobufWire.LEN)(index),
573
+ ),
574
+ ts.factory.createExpressionStatement(
575
+ ts.factory.createCallExpression(
576
+ IdentifierFactory.access(WRITER())("fork"),
577
+ undefined,
578
+ undefined,
579
+ ),
580
+ ),
581
+ forLoop(null),
582
+ ts.factory.createExpressionStatement(
583
+ ts.factory.createCallExpression(
584
+ IdentifierFactory.access(WRITER())("ldelim"),
585
+ undefined,
586
+ undefined,
587
+ ),
588
+ ),
589
+ ],
590
+ true,
591
+ ),
592
+ );
593
+ };
594
+
595
+ const decode_bool = (index: number | null) => (input: ts.Expression) =>
596
+ ts.factory.createBlock(
597
+ [
598
+ ...(index !== null
599
+ ? [decode_tag(ProtobufWire.VARIANT)(index)]
600
+ : []),
601
+ ts.factory.createCallExpression(
602
+ IdentifierFactory.access(WRITER())("bool"),
603
+ undefined,
604
+ [input],
605
+ ),
606
+ ].map((exp) => ts.factory.createExpressionStatement(exp)),
607
+ true,
608
+ );
609
+
610
+ const decode_number =
611
+ (project: IProject) =>
612
+ (candidates: ProtobufAtomic.Numeric[]) =>
613
+ (type: ProtobufAtomic.Numeric) =>
614
+ (input: ts.Expression): IUnion => ({
615
+ type,
616
+ is: () =>
617
+ candidates.length === 1
618
+ ? ts.factory.createStrictEquality(
619
+ ts.factory.createStringLiteral("number"),
620
+ ts.factory.createTypeOfExpression(input),
621
+ )
622
+ : ts.factory.createLogicalAnd(
623
+ ts.factory.createStrictEquality(
624
+ ts.factory.createStringLiteral("number"),
625
+ ts.factory.createTypeOfExpression(input),
626
+ ),
627
+ NumericRangeFactory.number(project.context)(type)(
628
+ input,
629
+ ),
630
+ ),
631
+ value: (index) =>
632
+ ts.factory.createBlock(
633
+ [
634
+ ...(index !== null
635
+ ? [decode_tag(get_numeric_wire(type))(index)]
636
+ : []),
637
+ ts.factory.createCallExpression(
638
+ IdentifierFactory.access(WRITER())(type),
639
+ undefined,
640
+ [input],
641
+ ),
642
+ ].map((exp) => ts.factory.createExpressionStatement(exp)),
643
+ true,
644
+ ),
645
+ });
646
+
647
+ const decode_bigint =
648
+ (project: IProject) =>
649
+ (candidates: ProtobufAtomic.BigNumeric[]) =>
650
+ (type: ProtobufAtomic.BigNumeric) =>
651
+ (input: ts.Expression): IUnion => ({
652
+ type,
653
+ is: () =>
654
+ candidates.length === 1
655
+ ? ts.factory.createStrictEquality(
656
+ ts.factory.createStringLiteral("bigint"),
657
+ ts.factory.createTypeOfExpression(input),
658
+ )
659
+ : ts.factory.createLogicalAnd(
660
+ ts.factory.createStrictEquality(
661
+ ts.factory.createStringLiteral("bigint"),
662
+ ts.factory.createTypeOfExpression(input),
663
+ ),
664
+ NumericRangeFactory.bigint(project.context)(type)(
665
+ input,
666
+ ),
667
+ ),
668
+ value: (index) =>
669
+ ts.factory.createBlock(
670
+ [
671
+ ...(index !== null
672
+ ? [decode_tag(ProtobufWire.VARIANT)(index)]
673
+ : []),
674
+ ts.factory.createCallExpression(
675
+ IdentifierFactory.access(WRITER())(type),
676
+ undefined,
677
+ [input],
678
+ ),
679
+ ].map((exp) => ts.factory.createExpressionStatement(exp)),
680
+ true,
681
+ ),
682
+ });
683
+
684
+ const decode_bytes =
685
+ (method: "bytes" | "string") =>
686
+ (index: number) =>
687
+ (input: ts.Expression): ts.Block =>
688
+ ts.factory.createBlock(
689
+ [
690
+ decode_tag(ProtobufWire.LEN)(index),
691
+ ts.factory.createCallExpression(
692
+ IdentifierFactory.access(WRITER())(method),
693
+ undefined,
694
+ [input],
695
+ ),
696
+ ].map((expr) => ts.factory.createExpressionStatement(expr)),
697
+ true,
698
+ );
699
+
700
+ const decode_tag =
701
+ (wire: ProtobufWire) =>
702
+ (index: number): ts.CallExpression =>
703
+ ts.factory.createCallExpression(
704
+ IdentifierFactory.access(WRITER())("uint32"),
705
+ undefined,
706
+ [ExpressionFactory.number((index << 3) | wire)],
707
+ );
708
+
709
+ const get_standalone_wire = (meta: Metadata): ProtobufWire => {
710
+ if (
711
+ meta.arrays.length ||
712
+ meta.objects.length ||
713
+ meta.maps.length ||
714
+ meta.natives.length
715
+ )
716
+ return ProtobufWire.LEN;
717
+
718
+ const v = ProtobufUtil.getAtomics(meta)[0]!;
719
+ if (v === "string") return ProtobufWire.LEN;
720
+ else if (
721
+ v === "bool" ||
722
+ v === "int32" ||
723
+ v === "uint32" ||
724
+ v === "int64" ||
725
+ v === "uint64"
726
+ )
727
+ return ProtobufWire.VARIANT;
728
+ else if (v === "float") return ProtobufWire.I32;
729
+ return ProtobufWire.I64;
730
+ };
731
+
732
+ const get_numeric_wire = (type: ProtobufAtomic.Numeric) =>
733
+ type === "double"
734
+ ? ProtobufWire.I64
735
+ : type === "float"
736
+ ? ProtobufWire.I32
737
+ : ProtobufWire.VARIANT;
738
+
739
+ /* -----------------------------------------------------------
740
+ EXPLORERS
741
+ ----------------------------------------------------------- */
742
+ const explore_objects =
743
+ (project: IProject) =>
744
+ (importer: FunctionImporter) =>
745
+ (level: number) =>
746
+ (index: number | null) =>
747
+ (
748
+ input: ts.Expression,
749
+ targets: MetadataObject[],
750
+ explore: FeatureProgrammer.IExplore,
751
+ indexes?: Map<MetadataObject, number>,
752
+ ): ts.Block => {
753
+ if (targets.length === 1)
754
+ return decode_object(project)(importer)(
755
+ indexes ? indexes.get(targets[0]!)! : index,
756
+ )(input, targets[0]!, explore);
757
+
758
+ const expected: string = `(${targets
759
+ .map((t) => t.name)
760
+ .join(" | ")})`;
761
+
762
+ // POSSIBLE TO SPECIALIZE?
763
+ const specList = UnionPredicator.object(targets);
764
+ indexes ??= new Map(targets.map((t, i) => [t, index! + i]));
765
+
766
+ if (specList.length === 0) {
767
+ const condition: ts.Expression = decode_union_object(
768
+ IsProgrammer.decode_object(project)(importer),
769
+ )((i, o, e) =>
770
+ ExpressionFactory.selfCall(
771
+ decode_object(project)(importer)(indexes!.get(o)!)(
772
+ i,
773
+ o,
774
+ e,
775
+ ),
776
+ ),
777
+ )((expr) => expr)((value, expected) =>
778
+ create_throw_error(importer)(expected)(value),
779
+ )(input, targets, explore);
780
+ return StatementFactory.block(condition);
781
+ }
782
+ const remained: MetadataObject[] = targets.filter(
783
+ (t) => specList.find((s) => s.object === t) === undefined,
784
+ );
785
+
786
+ // DO SPECIALIZE
787
+ const condition: ts.IfStatement = specList
788
+ .filter((spec) => spec.property.key.getSoleLiteral() !== null)
789
+ .map((spec, i, array) => {
790
+ const key: string = spec.property.key.getSoleLiteral()!;
791
+ const accessor: ts.Expression =
792
+ IdentifierFactory.access(input)(key);
793
+ const pred: ts.Expression = spec.neighbour
794
+ ? IsProgrammer.decode(project)(importer)(
795
+ accessor,
796
+ spec.property.value,
797
+ {
798
+ ...explore,
799
+ tracable: false,
800
+ postfix: IdentifierFactory.postfix(key),
801
+ },
802
+ )
803
+ : ExpressionFactory.isRequired(accessor);
804
+ return ts.factory.createIfStatement(
805
+ pred,
806
+ ts.factory.createReturnStatement(
807
+ ExpressionFactory.selfCall(
808
+ decode_object(project)(importer)(
809
+ indexes!.get(spec.object)!,
810
+ )(input, spec.object, explore),
811
+ ),
812
+ ),
813
+ i === array.length - 1
814
+ ? remained.length
815
+ ? ts.factory.createReturnStatement(
816
+ ExpressionFactory.selfCall(
817
+ explore_objects(project)(importer)(
818
+ level + 1,
819
+ )(index)(
820
+ input,
821
+ remained,
822
+ explore,
823
+ indexes!,
824
+ ),
825
+ ),
826
+ )
827
+ : create_throw_error(importer)(expected)(input)
828
+ : undefined,
829
+ );
830
+ })
831
+ .reverse()
832
+ .reduce((a, b) =>
833
+ ts.factory.createIfStatement(
834
+ b.expression,
835
+ b.thenStatement,
836
+ a,
837
+ ),
838
+ );
839
+
840
+ // RETURNS WITH CONDITIONS
841
+ return ts.factory.createBlock([condition], true);
842
+ };
843
+
844
+ /* -----------------------------------------------------------
845
+ CONFIGURATIONS
846
+ ----------------------------------------------------------- */
847
+ const PREFIX = "$pe";
848
+
849
+ const create_throw_error =
850
+ (importer: FunctionImporter) =>
851
+ (expected: string) =>
852
+ (value: ts.Expression) =>
853
+ ts.factory.createExpressionStatement(
854
+ ts.factory.createCallExpression(
855
+ importer.use("throws"),
856
+ [],
857
+ [
858
+ ts.factory.createObjectLiteralExpression(
859
+ [
860
+ ts.factory.createPropertyAssignment(
861
+ "expected",
862
+ ts.factory.createStringLiteral(expected),
863
+ ),
864
+ ts.factory.createPropertyAssignment(
865
+ "value",
866
+ value,
867
+ ),
868
+ ],
869
+ true,
870
+ ),
871
+ ],
872
+ ),
873
+ );
874
+ }
875
+
876
+ const WRITER = () => ts.factory.createIdentifier("writer");
877
+
878
+ interface IUnion {
879
+ type: string;
880
+ is: () => ts.Expression;
881
+ value: (index: number | null) => ts.Block;
882
+ }