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