typia 6.7.0 → 6.7.1

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