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,639 +1,655 @@
1
- import ts from "typescript";
2
-
3
- import { ExpressionFactory } from "../../factories/ExpressionFactory";
4
- import { IdentifierFactory } from "../../factories/IdentifierFactory";
5
- import { MetadataCollection } from "../../factories/MetadataCollection";
6
- import { MetadataFactory } from "../../factories/MetadataFactory";
7
- import { 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 { FunctionImporter } from "../helpers/FunctionImporeter";
21
- import { ProtobufUtil } from "../helpers/ProtobufUtil";
22
-
23
- export namespace ProtobufDecodeProgrammer {
24
- export const write =
25
- (project: IProject) =>
26
- (modulo: ts.LeftHandSideExpression) =>
27
- (type: ts.Type, name?: string): ts.ArrowFunction => {
28
- const importer: FunctionImporter = new FunctionImporter(
29
- modulo.getText(),
30
- );
31
- const collection: MetadataCollection = new MetadataCollection();
32
- const meta: Metadata = ProtobufFactory.metadata(modulo.getText())(
33
- project.checker,
34
- )(collection)(type);
35
-
36
- const functors = collection
37
- .objects()
38
- .filter((obj) => ProtobufUtil.isStaticObject(obj))
39
- .map((obj) =>
40
- StatementFactory.constant(
41
- `${PREFIX}o${obj.index}`,
42
- write_object_function(project)(importer)(obj),
43
- ),
44
- );
45
- const reader = StatementFactory.constant(
46
- "reader",
47
- ts.factory.createNewExpression(
48
- importer.use("Reader"),
49
- undefined,
50
- [ts.factory.createIdentifier("input")],
51
- ),
52
- );
53
-
54
- return ts.factory.createArrowFunction(
55
- undefined,
56
- undefined,
57
- [
58
- IdentifierFactory.parameter(
59
- "input",
60
- ts.factory.createTypeReferenceNode("Uint8Array"),
61
- ),
62
- ],
63
- ts.factory.createTypeReferenceNode(
64
- `typia.Resolved<${
65
- name ?? TypeFactory.getFullName(project.checker)(type)
66
- }>`,
67
- ),
68
- undefined,
69
- ts.factory.createBlock(
70
- [
71
- ...importer.declare(modulo),
72
- ...functors,
73
- reader,
74
- ts.factory.createReturnStatement(
75
- decode_regular_object(true)(meta.objects[0]!),
76
- ),
77
- ],
78
- true,
79
- ),
80
- );
81
- };
82
-
83
- const write_object_function =
84
- (project: IProject) =>
85
- (importer: FunctionImporter) =>
86
- (obj: MetadataObject): ts.ArrowFunction =>
87
- ts.factory.createArrowFunction(
88
- undefined,
89
- undefined,
90
- [
91
- IdentifierFactory.parameter("reader"),
92
- IdentifierFactory.parameter(
93
- "length",
94
- TypeFactory.keyword("number"),
95
- ts.factory.createNumericLiteral(-1),
96
- ),
97
- ],
98
- TypeFactory.keyword("any"),
99
- undefined,
100
- ts.factory.createBlock(
101
- [
102
- ts.factory.createExpressionStatement(
103
- ts.factory.createBinaryExpression(
104
- ts.factory.createIdentifier("length"),
105
- ts.factory.createToken(
106
- ts.SyntaxKind.EqualsToken,
107
- ),
108
- ts.factory.createConditionalExpression(
109
- ts.factory.createLessThan(
110
- ts.factory.createIdentifier("length"),
111
- ts.factory.createNumericLiteral(0),
112
- ),
113
- undefined,
114
- ts.factory.createCallExpression(
115
- IdentifierFactory.access(READER())(
116
- "size",
117
- ),
118
- undefined,
119
- undefined,
120
- ),
121
- undefined,
122
- ts.factory.createAdd(
123
- ts.factory.createCallExpression(
124
- IdentifierFactory.access(READER())(
125
- "index",
126
- ),
127
- undefined,
128
- undefined,
129
- ),
130
- ts.factory.createIdentifier("length"),
131
- ),
132
- ),
133
- ),
134
- ),
135
- ...write_object_function_body(project)(importer)({
136
- condition: ts.factory.createLessThan(
137
- ts.factory.createCallExpression(
138
- IdentifierFactory.access(READER())("index"),
139
- undefined,
140
- undefined,
141
- ),
142
- ts.factory.createIdentifier("length"),
143
- ),
144
- tag: "tag",
145
- output: "output",
146
- })(obj.properties),
147
- ts.factory.createReturnStatement(
148
- ts.factory.createIdentifier("output"),
149
- ),
150
- ],
151
- true,
152
- ),
153
- );
154
-
155
- const write_object_function_body =
156
- (project: IProject) =>
157
- (importer: FunctionImporter) =>
158
- (props: { condition: ts.Expression; tag: string; output: string }) =>
159
- (properties: MetadataProperty[]): ts.Statement[] => {
160
- let i: number = 1;
161
- const clauses: ts.CaseClause[] = properties
162
- .map((p) => {
163
- const clause = decode_property(project)(importer)(i)(
164
- IdentifierFactory.access(
165
- ts.factory.createIdentifier(props.output),
166
- )(p.key.getSoleLiteral()!),
167
- p.value,
168
- );
169
- i += ProtobufUtil.size(p.value);
170
- return clause;
171
- })
172
- .flat();
173
- return [
174
- StatementFactory.constant(
175
- props.output,
176
- ts.factory.createObjectLiteralExpression(
177
- properties.map((p) =>
178
- ts.factory.createPropertyAssignment(
179
- IdentifierFactory.identifier(
180
- p.key.getSoleLiteral()!,
181
- ),
182
- write_property_default_value(p.value),
183
- ),
184
- ),
185
- true,
186
- ),
187
- ),
188
- ts.factory.createWhileStatement(
189
- props.condition,
190
- ts.factory.createBlock([
191
- StatementFactory.constant(
192
- props.tag,
193
- ts.factory.createCallExpression(
194
- IdentifierFactory.access(READER())("uint32"),
195
- undefined,
196
- undefined,
197
- ),
198
- ),
199
- ts.factory.createSwitchStatement(
200
- ts.factory.createUnsignedRightShift(
201
- ts.factory.createIdentifier(props.tag),
202
- ts.factory.createNumericLiteral(3),
203
- ),
204
- ts.factory.createCaseBlock([
205
- ...clauses,
206
- ts.factory.createDefaultClause([
207
- ts.factory.createExpressionStatement(
208
- ts.factory.createCallExpression(
209
- IdentifierFactory.access(READER())(
210
- "skipType",
211
- ),
212
- undefined,
213
- [
214
- ts.factory.createBitwiseAnd(
215
- ts.factory.createIdentifier(
216
- props.tag,
217
- ),
218
- ts.factory.createNumericLiteral(
219
- 7,
220
- ),
221
- ),
222
- ],
223
- ),
224
- ),
225
- ts.factory.createBreakStatement(),
226
- ]),
227
- ]),
228
- ),
229
- ]),
230
- ),
231
- ];
232
- };
233
-
234
- const write_property_default_value = (value: Metadata) =>
235
- ts.factory.createAsExpression(
236
- value.nullable
237
- ? ts.factory.createNull()
238
- : value.isRequired() === false
239
- ? ts.factory.createIdentifier("undefined")
240
- : value.arrays.length
241
- ? ts.factory.createArrayLiteralExpression()
242
- : value.maps.length
243
- ? ts.factory.createNewExpression(
244
- ts.factory.createIdentifier("Map"),
245
- undefined,
246
- [],
247
- )
248
- : value.natives.length
249
- ? ts.factory.createNewExpression(
250
- ts.factory.createIdentifier("Uint8Array"),
251
- undefined,
252
- [],
253
- )
254
- : value.atomics.some((a) => a.type === "string") ||
255
- value.constants.some(
256
- (c) =>
257
- c.type === "string" && c.values.some((v) => v === ""),
258
- ) ||
259
- value.templates.some(
260
- (tpl) =>
261
- tpl.length === 1 && tpl[0]!.getName() === "string",
262
- )
263
- ? ts.factory.createStringLiteral("")
264
- : value.objects.length &&
265
- value.objects.some((obj) => !ProtobufUtil.isStaticObject(obj))
266
- ? ts.factory.createObjectLiteralExpression()
267
- : ts.factory.createIdentifier("undefined"),
268
- TypeFactory.keyword("any"),
269
- );
270
-
271
- /* -----------------------------------------------------------
272
- DECODERS
273
- ----------------------------------------------------------- */
274
- const decode_property =
275
- (project: IProject) =>
276
- (importer: FunctionImporter) =>
277
- (index: number) =>
278
- (
279
- accessor: ts.ElementAccessExpression | ts.PropertyAccessExpression,
280
- meta: Metadata,
281
- ): ts.CaseClause[] => {
282
- const clauses: ts.CaseClause[] = [];
283
- const emplace =
284
- (name: string) => (v: ts.Expression | ts.Statement[]) =>
285
- clauses.push(
286
- ts.factory.createCaseClause(
287
- ts.factory.createNumericLiteral(index++),
288
- Array.isArray(v)
289
- ? [
290
- ts.factory.createExpressionStatement(
291
- ts.factory.createIdentifier(
292
- `// type: ${name}`,
293
- ),
294
- ),
295
- ...v,
296
- ts.factory.createBreakStatement(),
297
- ]
298
- : [
299
- ts.factory.createExpressionStatement(
300
- ts.factory.createIdentifier(
301
- `// ${name}`,
302
- ),
303
- ),
304
- ts.factory.createExpressionStatement(
305
- ts.factory.createBinaryExpression(
306
- accessor,
307
- ts.factory.createToken(
308
- ts.SyntaxKind.EqualsToken,
309
- ),
310
- v,
311
- ),
312
- ),
313
- ts.factory.createBreakStatement(),
314
- ],
315
- ),
316
- );
317
-
318
- const required: boolean = meta.isRequired() && !meta.nullable;
319
- for (const atomic of ProtobufUtil.getAtomics(meta))
320
- emplace(atomic)(decode_atomic(meta)(atomic));
321
- if (meta.natives.length) emplace("bytes")(decode_bytes("bytes"));
322
- for (const array of meta.arrays)
323
- emplace(`Array<${array.type.value.getName()}>`)(
324
- decode_array(accessor, array, required),
325
- );
326
- for (const map of meta.maps)
327
- emplace(`Map<string, ${map.value.getName()}>`)(
328
- decode_map(project)(importer)(accessor, map, required),
329
- );
330
- for (const obj of meta.objects)
331
- emplace(obj.name)(
332
- ProtobufUtil.isStaticObject(obj)
333
- ? decode_regular_object(false)(obj)
334
- : decode_dynamic_object(project)(importer)(
335
- accessor,
336
- obj,
337
- required,
338
- ),
339
- );
340
- return clauses;
341
- };
342
-
343
- const decode_atomic =
344
- (meta: Metadata) =>
345
- (atomic: ProtobufAtomic): ts.Expression => {
346
- if (atomic === "string") return decode_bytes("string");
347
-
348
- const call: ts.CallExpression = ts.factory.createCallExpression(
349
- IdentifierFactory.access(ts.factory.createIdentifier("reader"))(
350
- atomic,
351
- ),
352
- undefined,
353
- undefined,
354
- );
355
- if (atomic !== "int64" && atomic !== "uint64") return call;
356
-
357
- const isNumber: boolean = ProtobufUtil.getNumbers(meta).some(
358
- (n) => n === atomic,
359
- );
360
- return isNumber
361
- ? ts.factory.createCallExpression(
362
- ts.factory.createIdentifier("Number"),
363
- undefined,
364
- [call],
365
- )
366
- : call;
367
- };
368
-
369
- const decode_bytes = (method: "bytes" | "string"): ts.Expression =>
370
- ts.factory.createCallExpression(
371
- IdentifierFactory.access(ts.factory.createIdentifier("reader"))(
372
- method,
373
- ),
374
- undefined,
375
- undefined,
376
- );
377
-
378
- const decode_array = (
379
- accessor: ts.ElementAccessExpression | ts.PropertyAccessExpression,
380
- array: MetadataArray,
381
- required: boolean,
382
- ): ts.Statement[] => {
383
- const statements: Array<ts.Expression | ts.Statement> = [];
384
- if (required === false)
385
- statements.push(
386
- ts.factory.createBinaryExpression(
387
- accessor,
388
- ts.factory.createToken(
389
- ts.SyntaxKind.QuestionQuestionEqualsToken,
390
- ),
391
- ts.factory.createAsExpression(
392
- ts.factory.createArrayLiteralExpression(),
393
- ts.factory.createTypeReferenceNode("any[]"),
394
- ),
395
- ),
396
- );
397
- const atomics = ProtobufUtil.getAtomics(array.type.value);
398
- const decoder = atomics.length
399
- ? () => decode_atomic(array.type.value)(atomics[0]!)
400
- : array.type.value.natives.length
401
- ? () => decode_bytes("bytes")
402
- : array.type.value.objects.length
403
- ? () => decode_regular_object(false)(array.type.value.objects[0]!)
404
- : null;
405
- if (decoder === null) throw new Error("Never reach here.");
406
- else if (atomics.length && atomics[0] !== "string") {
407
- statements.push(
408
- ts.factory.createIfStatement(
409
- ts.factory.createStrictEquality(
410
- ts.factory.createNumericLiteral(2),
411
- ts.factory.createBitwiseAnd(
412
- ts.factory.createIdentifier("tag"),
413
- ts.factory.createNumericLiteral(7),
414
- ),
415
- ),
416
- ts.factory.createBlock(
417
- [
418
- StatementFactory.constant(
419
- "piece",
420
- ts.factory.createAdd(
421
- ts.factory.createCallExpression(
422
- IdentifierFactory.access(READER())(
423
- "uint32",
424
- ),
425
- undefined,
426
- undefined,
427
- ),
428
- ts.factory.createCallExpression(
429
- IdentifierFactory.access(READER())(
430
- "index",
431
- ),
432
- undefined,
433
- undefined,
434
- ),
435
- ),
436
- ),
437
- ts.factory.createWhileStatement(
438
- ts.factory.createLessThan(
439
- ts.factory.createCallExpression(
440
- IdentifierFactory.access(READER())(
441
- "index",
442
- ),
443
- undefined,
444
- undefined,
445
- ),
446
- ts.factory.createIdentifier("piece"),
447
- ),
448
- ts.factory.createExpressionStatement(
449
- ts.factory.createCallExpression(
450
- IdentifierFactory.access(accessor)(
451
- "push",
452
- ),
453
- undefined,
454
- [decoder()],
455
- ),
456
- ),
457
- ),
458
- ],
459
- true,
460
- ),
461
- ts.factory.createExpressionStatement(
462
- ts.factory.createCallExpression(
463
- IdentifierFactory.access(accessor)("push"),
464
- undefined,
465
- [decoder()],
466
- ),
467
- ),
468
- ),
469
- );
470
- } else
471
- statements.push(
472
- ts.factory.createCallExpression(
473
- IdentifierFactory.access(accessor)("push"),
474
- undefined,
475
- [decoder()],
476
- ),
477
- );
478
- return statements.map((stmt) =>
479
- ts.isExpression(stmt)
480
- ? ts.factory.createExpressionStatement(stmt)
481
- : stmt,
482
- );
483
- };
484
-
485
- const decode_regular_object =
486
- (top: boolean) =>
487
- (obj: MetadataObject): ts.Expression =>
488
- ts.factory.createCallExpression(
489
- ts.factory.createIdentifier(`${PREFIX}o${obj.index}`),
490
- undefined,
491
- [
492
- ts.factory.createIdentifier("reader"),
493
- ...(top
494
- ? []
495
- : [
496
- ts.factory.createCallExpression(
497
- IdentifierFactory.access(READER())("uint32"),
498
- undefined,
499
- undefined,
500
- ),
501
- ]),
502
- ],
503
- );
504
-
505
- const decode_dynamic_object =
506
- (project: IProject) =>
507
- (importer: FunctionImporter) =>
508
- (
509
- accessor: ts.ElementAccessExpression | ts.PropertyAccessExpression,
510
- obj: MetadataObject,
511
- required: boolean,
512
- ): ts.Statement[] => {
513
- const top = obj.properties[0]!;
514
- return decode_entry(project)(importer)({
515
- initializer: () =>
516
- ts.factory.createBinaryExpression(
517
- accessor,
518
- ts.factory.createToken(
519
- ts.SyntaxKind.QuestionQuestionEqualsToken,
520
- ),
521
- ts.factory.createObjectLiteralExpression(),
522
- ),
523
- setter: () =>
524
- ts.factory.createBinaryExpression(
525
- ts.factory.createElementAccessExpression(
526
- accessor,
527
- ts.factory.createIdentifier("entry.key"),
528
- ),
529
- ts.factory.createToken(ts.SyntaxKind.EqualsToken),
530
- ts.factory.createIdentifier("entry.value"),
531
- ),
532
- })(top, required);
533
- };
534
-
535
- const decode_map =
536
- (project: IProject) =>
537
- (importer: FunctionImporter) =>
538
- (
539
- accessor: ts.ElementAccessExpression | ts.PropertyAccessExpression,
540
- map: Metadata.Entry,
541
- required: boolean,
542
- ): ts.Statement[] =>
543
- decode_entry(project)(importer)({
544
- initializer: () =>
545
- ts.factory.createBinaryExpression(
546
- accessor,
547
- ts.factory.createToken(
548
- ts.SyntaxKind.QuestionQuestionEqualsToken,
549
- ),
550
- ts.factory.createNewExpression(
551
- ts.factory.createIdentifier("Map"),
552
- [
553
- TypeFactory.keyword("any"),
554
- TypeFactory.keyword("any"),
555
- ],
556
- [],
557
- ),
558
- ),
559
- setter: () =>
560
- ts.factory.createCallExpression(
561
- IdentifierFactory.access(accessor)("set"),
562
- undefined,
563
- [
564
- ts.factory.createIdentifier("entry.key"),
565
- ts.factory.createIdentifier("entry.value"),
566
- ],
567
- ),
568
- })(map, required);
569
-
570
- const decode_entry =
571
- (project: IProject) =>
572
- (importer: FunctionImporter) =>
573
- (props: {
574
- initializer: () => ts.Expression;
575
- setter: () => ts.Expression;
576
- }) =>
577
- (map: Metadata.Entry, required: boolean): ts.Statement[] => {
578
- const statements: ts.Statement[] = [
579
- ...(required
580
- ? []
581
- : [
582
- ts.factory.createExpressionStatement(
583
- props.initializer(),
584
- ),
585
- ]),
586
- StatementFactory.constant(
587
- "piece",
588
- ts.factory.createAdd(
589
- ts.factory.createCallExpression(
590
- IdentifierFactory.access(READER())("uint32"),
591
- undefined,
592
- undefined,
593
- ),
594
- ts.factory.createCallExpression(
595
- IdentifierFactory.access(READER())("index"),
596
- undefined,
597
- undefined,
598
- ),
599
- ),
600
- ),
601
- ...write_object_function_body(project)(importer)({
602
- condition: ts.factory.createLessThan(
603
- ts.factory.createCallExpression(
604
- IdentifierFactory.access(READER())("index"),
605
- undefined,
606
- undefined,
607
- ),
608
- ts.factory.createIdentifier("piece"),
609
- ),
610
- tag: "kind",
611
- output: "entry",
612
- })([
613
- MetadataProperty.create({
614
- key: MetadataFactory.soleLiteral("key"),
615
- value: map.key,
616
- description: null,
617
- jsDocTags: [],
618
- }),
619
- MetadataProperty.create({
620
- key: MetadataFactory.soleLiteral("value"),
621
- value: map.value,
622
- description: null,
623
- jsDocTags: [],
624
- }),
625
- ]),
626
- ts.factory.createExpressionStatement(props.setter()),
627
- ];
628
- return [
629
- ts.factory.createExpressionStatement(
630
- ExpressionFactory.selfCall(
631
- ts.factory.createBlock(statements, true),
632
- ),
633
- ),
634
- ];
635
- };
636
- }
637
-
638
- const PREFIX = "$pd";
639
- const READER = () => ts.factory.createIdentifier("reader");
1
+ import ts from "typescript";
2
+
3
+ import { ExpressionFactory } from "../../factories/ExpressionFactory";
4
+ import { IdentifierFactory } from "../../factories/IdentifierFactory";
5
+ import { MetadataCollection } from "../../factories/MetadataCollection";
6
+ import { MetadataFactory } from "../../factories/MetadataFactory";
7
+ import { 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 { FunctionImporter } from "../helpers/FunctionImporeter";
22
+ import { ProtobufUtil } from "../helpers/ProtobufUtil";
23
+
24
+ export namespace ProtobufDecodeProgrammer {
25
+ export const write =
26
+ (project: IProject) =>
27
+ (modulo: ts.LeftHandSideExpression) =>
28
+ (type: ts.Type, name?: string): ts.ArrowFunction => {
29
+ const importer: FunctionImporter = new FunctionImporter(
30
+ modulo.getText(),
31
+ );
32
+ const collection: MetadataCollection = new MetadataCollection();
33
+ const meta: Metadata = ProtobufFactory.metadata(modulo.getText())(
34
+ project.checker,
35
+ )(collection)(type);
36
+
37
+ const functors = collection
38
+ .objects()
39
+ .filter((obj) => ProtobufUtil.isStaticObject(obj))
40
+ .map((obj) =>
41
+ StatementFactory.constant(
42
+ `${PREFIX}o${obj.index}`,
43
+ write_object_function(project)(importer)(obj),
44
+ ),
45
+ );
46
+ const reader = StatementFactory.constant(
47
+ "reader",
48
+ ts.factory.createNewExpression(
49
+ importer.use("Reader"),
50
+ undefined,
51
+ [ts.factory.createIdentifier("input")],
52
+ ),
53
+ );
54
+
55
+ return ts.factory.createArrowFunction(
56
+ undefined,
57
+ undefined,
58
+ [
59
+ IdentifierFactory.parameter(
60
+ "input",
61
+ ts.factory.createTypeReferenceNode("Uint8Array"),
62
+ ),
63
+ ],
64
+ ts.factory.createTypeReferenceNode(
65
+ `typia.Resolved<${
66
+ name ?? TypeFactory.getFullName(project.checker)(type)
67
+ }>`,
68
+ ),
69
+ undefined,
70
+ ts.factory.createBlock(
71
+ [
72
+ ...importer.declare(modulo),
73
+ ...functors,
74
+ reader,
75
+ ts.factory.createReturnStatement(
76
+ decode_regular_object(true)(meta.objects[0]!),
77
+ ),
78
+ ],
79
+ true,
80
+ ),
81
+ );
82
+ };
83
+
84
+ const write_object_function =
85
+ (project: IProject) =>
86
+ (importer: FunctionImporter) =>
87
+ (obj: MetadataObject): ts.ArrowFunction =>
88
+ ts.factory.createArrowFunction(
89
+ undefined,
90
+ undefined,
91
+ [
92
+ IdentifierFactory.parameter("reader"),
93
+ IdentifierFactory.parameter(
94
+ "length",
95
+ TypeFactory.keyword("number"),
96
+ ts.factory.createNumericLiteral(-1),
97
+ ),
98
+ ],
99
+ TypeFactory.keyword("any"),
100
+ undefined,
101
+ ts.factory.createBlock(
102
+ [
103
+ ts.factory.createExpressionStatement(
104
+ ts.factory.createBinaryExpression(
105
+ ts.factory.createIdentifier("length"),
106
+ ts.factory.createToken(
107
+ ts.SyntaxKind.EqualsToken,
108
+ ),
109
+ ts.factory.createConditionalExpression(
110
+ ts.factory.createLessThan(
111
+ ts.factory.createIdentifier("length"),
112
+ ts.factory.createNumericLiteral(0),
113
+ ),
114
+ undefined,
115
+ ts.factory.createCallExpression(
116
+ IdentifierFactory.access(READER())(
117
+ "size",
118
+ ),
119
+ undefined,
120
+ undefined,
121
+ ),
122
+ undefined,
123
+ ts.factory.createAdd(
124
+ ts.factory.createCallExpression(
125
+ IdentifierFactory.access(READER())(
126
+ "index",
127
+ ),
128
+ undefined,
129
+ undefined,
130
+ ),
131
+ ts.factory.createIdentifier("length"),
132
+ ),
133
+ ),
134
+ ),
135
+ ),
136
+ ...write_object_function_body(project)(importer)({
137
+ condition: ts.factory.createLessThan(
138
+ ts.factory.createCallExpression(
139
+ IdentifierFactory.access(READER())("index"),
140
+ undefined,
141
+ undefined,
142
+ ),
143
+ ts.factory.createIdentifier("length"),
144
+ ),
145
+ tag: "tag",
146
+ output: "output",
147
+ })(obj.properties),
148
+ ts.factory.createReturnStatement(
149
+ ts.factory.createIdentifier("output"),
150
+ ),
151
+ ],
152
+ true,
153
+ ),
154
+ );
155
+
156
+ const write_object_function_body =
157
+ (project: IProject) =>
158
+ (importer: FunctionImporter) =>
159
+ (props: { condition: ts.Expression; tag: string; output: string }) =>
160
+ (properties: MetadataProperty[]): ts.Statement[] => {
161
+ let i: number = 1;
162
+ const clauses: ts.CaseClause[] = properties
163
+ .map((p) => {
164
+ const clause = decode_property(project)(importer)(i)(
165
+ IdentifierFactory.access(
166
+ ts.factory.createIdentifier(props.output),
167
+ )(p.key.getSoleLiteral()!),
168
+ p.value,
169
+ );
170
+ i += ProtobufUtil.size(p.value);
171
+ return clause;
172
+ })
173
+ .flat();
174
+ return [
175
+ StatementFactory.constant(
176
+ props.output,
177
+ ts.factory.createObjectLiteralExpression(
178
+ properties.map((p) =>
179
+ ts.factory.createPropertyAssignment(
180
+ IdentifierFactory.identifier(
181
+ p.key.getSoleLiteral()!,
182
+ ),
183
+ write_property_default_value(p.value),
184
+ ),
185
+ ),
186
+ true,
187
+ ),
188
+ ),
189
+ ts.factory.createWhileStatement(
190
+ props.condition,
191
+ ts.factory.createBlock([
192
+ StatementFactory.constant(
193
+ props.tag,
194
+ ts.factory.createCallExpression(
195
+ IdentifierFactory.access(READER())("uint32"),
196
+ undefined,
197
+ undefined,
198
+ ),
199
+ ),
200
+ ts.factory.createSwitchStatement(
201
+ ts.factory.createUnsignedRightShift(
202
+ ts.factory.createIdentifier(props.tag),
203
+ ts.factory.createNumericLiteral(3),
204
+ ),
205
+ ts.factory.createCaseBlock([
206
+ ...clauses,
207
+ ts.factory.createDefaultClause([
208
+ ts.factory.createExpressionStatement(
209
+ ts.factory.createCallExpression(
210
+ IdentifierFactory.access(READER())(
211
+ "skipType",
212
+ ),
213
+ undefined,
214
+ [
215
+ ts.factory.createBitwiseAnd(
216
+ ts.factory.createIdentifier(
217
+ props.tag,
218
+ ),
219
+ ts.factory.createNumericLiteral(
220
+ 7,
221
+ ),
222
+ ),
223
+ ],
224
+ ),
225
+ ),
226
+ ts.factory.createBreakStatement(),
227
+ ]),
228
+ ]),
229
+ ),
230
+ ]),
231
+ ),
232
+ ];
233
+ };
234
+
235
+ const write_property_default_value = (value: Metadata) =>
236
+ ts.factory.createAsExpression(
237
+ value.nullable
238
+ ? ts.factory.createNull()
239
+ : value.isRequired() === false
240
+ ? ts.factory.createIdentifier("undefined")
241
+ : value.arrays.length
242
+ ? ts.factory.createArrayLiteralExpression()
243
+ : value.maps.length
244
+ ? ts.factory.createNewExpression(
245
+ ts.factory.createIdentifier("Map"),
246
+ undefined,
247
+ [],
248
+ )
249
+ : value.natives.length
250
+ ? ts.factory.createNewExpression(
251
+ ts.factory.createIdentifier("Uint8Array"),
252
+ undefined,
253
+ [],
254
+ )
255
+ : value.atomics.some((a) => a.type === "string") ||
256
+ value.constants.some(
257
+ (c) =>
258
+ c.type === "string" && c.values.some((v) => v === ""),
259
+ ) ||
260
+ value.templates.some(
261
+ (tpl) =>
262
+ tpl.length === 1 && tpl[0]!.getName() === "string",
263
+ )
264
+ ? ts.factory.createStringLiteral("")
265
+ : value.objects.length &&
266
+ value.objects.some((obj) => !ProtobufUtil.isStaticObject(obj))
267
+ ? ts.factory.createObjectLiteralExpression()
268
+ : ts.factory.createIdentifier("undefined"),
269
+ TypeFactory.keyword("any"),
270
+ );
271
+
272
+ /* -----------------------------------------------------------
273
+ DECODERS
274
+ ----------------------------------------------------------- */
275
+ const decode_property =
276
+ (project: IProject) =>
277
+ (importer: FunctionImporter) =>
278
+ (index: number) =>
279
+ (
280
+ accessor: ts.ElementAccessExpression | ts.PropertyAccessExpression,
281
+ meta: Metadata,
282
+ ): ts.CaseClause[] => {
283
+ const clauses: ts.CaseClause[] = [];
284
+ const emplace =
285
+ (name: string) => (v: ts.Expression | ts.Statement[]) =>
286
+ clauses.push(
287
+ ts.factory.createCaseClause(
288
+ ts.factory.createNumericLiteral(index++),
289
+ Array.isArray(v)
290
+ ? [
291
+ ts.factory.createExpressionStatement(
292
+ ts.factory.createIdentifier(
293
+ `// type: ${name}`,
294
+ ),
295
+ ),
296
+ ...v,
297
+ ts.factory.createBreakStatement(),
298
+ ]
299
+ : [
300
+ ts.factory.createExpressionStatement(
301
+ ts.factory.createIdentifier(
302
+ `// ${name}`,
303
+ ),
304
+ ),
305
+ ts.factory.createExpressionStatement(
306
+ ts.factory.createBinaryExpression(
307
+ accessor,
308
+ ts.factory.createToken(
309
+ ts.SyntaxKind.EqualsToken,
310
+ ),
311
+ v,
312
+ ),
313
+ ),
314
+ ts.factory.createBreakStatement(),
315
+ ],
316
+ ),
317
+ );
318
+
319
+ const required: boolean = meta.isRequired() && !meta.nullable;
320
+ for (const atomic of ProtobufUtil.getAtomics(meta))
321
+ emplace(atomic)(decode_atomic(meta)(atomic));
322
+ if (meta.natives.length) emplace("bytes")(decode_bytes("bytes"));
323
+ for (const array of meta.arrays)
324
+ emplace(`Array<${array.type.value.getName()}>`)(
325
+ decode_array(accessor, array, required),
326
+ );
327
+ for (const map of meta.maps)
328
+ emplace(`Map<string, ${map.value.getName()}>`)(
329
+ decode_map(project)(importer)(accessor, map, required),
330
+ );
331
+ for (const obj of meta.objects)
332
+ emplace(obj.name)(
333
+ ProtobufUtil.isStaticObject(obj)
334
+ ? decode_regular_object(false)(obj)
335
+ : decode_dynamic_object(project)(importer)(
336
+ accessor,
337
+ obj,
338
+ required,
339
+ ),
340
+ );
341
+ return clauses;
342
+ };
343
+
344
+ const decode_atomic =
345
+ (meta: Metadata) =>
346
+ (atomic: ProtobufAtomic): ts.Expression => {
347
+ if (atomic === "string") return decode_bytes("string");
348
+
349
+ const call: ts.CallExpression = ts.factory.createCallExpression(
350
+ IdentifierFactory.access(ts.factory.createIdentifier("reader"))(
351
+ atomic,
352
+ ),
353
+ undefined,
354
+ undefined,
355
+ );
356
+ if (atomic !== "int64" && atomic !== "uint64") return call;
357
+
358
+ const isNumber: boolean = ProtobufUtil.getNumbers(meta).some(
359
+ (n) => n === atomic,
360
+ );
361
+ return isNumber
362
+ ? ts.factory.createCallExpression(
363
+ ts.factory.createIdentifier("Number"),
364
+ undefined,
365
+ [call],
366
+ )
367
+ : call;
368
+ };
369
+
370
+ const decode_bytes = (method: "bytes" | "string"): ts.Expression =>
371
+ ts.factory.createCallExpression(
372
+ IdentifierFactory.access(ts.factory.createIdentifier("reader"))(
373
+ method,
374
+ ),
375
+ undefined,
376
+ undefined,
377
+ );
378
+
379
+ const decode_array = (
380
+ accessor: ts.ElementAccessExpression | ts.PropertyAccessExpression,
381
+ array: MetadataArray,
382
+ required: boolean,
383
+ ): ts.Statement[] => {
384
+ const statements: Array<ts.Expression | ts.Statement> = [];
385
+ if (required === false)
386
+ statements.push(
387
+ ts.factory.createBinaryExpression(
388
+ accessor,
389
+ ts.factory.createToken(
390
+ ts.SyntaxKind.QuestionQuestionEqualsToken,
391
+ ),
392
+ ts.factory.createAsExpression(
393
+ ts.factory.createArrayLiteralExpression(),
394
+ ts.factory.createTypeReferenceNode("any[]"),
395
+ ),
396
+ ),
397
+ );
398
+ const atomics = ProtobufUtil.getAtomics(array.type.value);
399
+ const decoder = atomics.length
400
+ ? () => decode_atomic(array.type.value)(atomics[0]!)
401
+ : array.type.value.natives.length
402
+ ? () => decode_bytes("bytes")
403
+ : array.type.value.objects.length
404
+ ? () => decode_regular_object(false)(array.type.value.objects[0]!)
405
+ : null;
406
+ if (decoder === null) throw new Error("Never reach here.");
407
+ else if (atomics.length && atomics[0] !== "string") {
408
+ statements.push(
409
+ ts.factory.createIfStatement(
410
+ ts.factory.createStrictEquality(
411
+ ts.factory.createNumericLiteral(2),
412
+ ts.factory.createBitwiseAnd(
413
+ ts.factory.createIdentifier("tag"),
414
+ ts.factory.createNumericLiteral(7),
415
+ ),
416
+ ),
417
+ ts.factory.createBlock(
418
+ [
419
+ StatementFactory.constant(
420
+ "piece",
421
+ ts.factory.createAdd(
422
+ ts.factory.createCallExpression(
423
+ IdentifierFactory.access(READER())(
424
+ "uint32",
425
+ ),
426
+ undefined,
427
+ undefined,
428
+ ),
429
+ ts.factory.createCallExpression(
430
+ IdentifierFactory.access(READER())(
431
+ "index",
432
+ ),
433
+ undefined,
434
+ undefined,
435
+ ),
436
+ ),
437
+ ),
438
+ ts.factory.createWhileStatement(
439
+ ts.factory.createLessThan(
440
+ ts.factory.createCallExpression(
441
+ IdentifierFactory.access(READER())(
442
+ "index",
443
+ ),
444
+ undefined,
445
+ undefined,
446
+ ),
447
+ ts.factory.createIdentifier("piece"),
448
+ ),
449
+ ts.factory.createExpressionStatement(
450
+ ts.factory.createCallExpression(
451
+ IdentifierFactory.access(accessor)(
452
+ "push",
453
+ ),
454
+ undefined,
455
+ [decoder()],
456
+ ),
457
+ ),
458
+ ),
459
+ ],
460
+ true,
461
+ ),
462
+ ts.factory.createExpressionStatement(
463
+ ts.factory.createCallExpression(
464
+ IdentifierFactory.access(accessor)("push"),
465
+ undefined,
466
+ [decoder()],
467
+ ),
468
+ ),
469
+ ),
470
+ );
471
+ } else
472
+ statements.push(
473
+ ts.factory.createCallExpression(
474
+ IdentifierFactory.access(accessor)("push"),
475
+ undefined,
476
+ [decoder()],
477
+ ),
478
+ );
479
+ return statements.map((stmt) =>
480
+ ts.isExpression(stmt)
481
+ ? ts.factory.createExpressionStatement(stmt)
482
+ : stmt,
483
+ );
484
+ };
485
+
486
+ const decode_regular_object =
487
+ (top: boolean) =>
488
+ (obj: MetadataObject): ts.Expression =>
489
+ ts.factory.createCallExpression(
490
+ ts.factory.createIdentifier(`${PREFIX}o${obj.index}`),
491
+ undefined,
492
+ [
493
+ ts.factory.createIdentifier("reader"),
494
+ ...(top
495
+ ? []
496
+ : [
497
+ ts.factory.createCallExpression(
498
+ IdentifierFactory.access(READER())("uint32"),
499
+ undefined,
500
+ undefined,
501
+ ),
502
+ ]),
503
+ ],
504
+ );
505
+
506
+ const decode_dynamic_object =
507
+ (project: IProject) =>
508
+ (importer: FunctionImporter) =>
509
+ (
510
+ accessor: ts.ElementAccessExpression | ts.PropertyAccessExpression,
511
+ obj: MetadataObject,
512
+ required: boolean,
513
+ ): ts.Statement[] => {
514
+ const top = obj.properties[0]!;
515
+ return decode_entry(project)(importer)({
516
+ initializer: () =>
517
+ ts.factory.createBinaryExpression(
518
+ accessor,
519
+ ts.factory.createToken(
520
+ ts.SyntaxKind.QuestionQuestionEqualsToken,
521
+ ),
522
+ ts.factory.createObjectLiteralExpression(),
523
+ ),
524
+ setter: () =>
525
+ ts.factory.createBinaryExpression(
526
+ ts.factory.createElementAccessExpression(
527
+ accessor,
528
+ ts.factory.createIdentifier("entry.key"),
529
+ ),
530
+ ts.factory.createToken(ts.SyntaxKind.EqualsToken),
531
+ ts.factory.createIdentifier("entry.value"),
532
+ ),
533
+ })(
534
+ MetadataProperty.create({
535
+ ...top,
536
+ key: (() => {
537
+ const key: Metadata = Metadata.initialize();
538
+ key.atomics.push(
539
+ MetadataAtomic.create({
540
+ type: "string",
541
+ tags: [],
542
+ }),
543
+ );
544
+ return key;
545
+ })(),
546
+ }),
547
+ required,
548
+ );
549
+ };
550
+
551
+ const decode_map =
552
+ (project: IProject) =>
553
+ (importer: FunctionImporter) =>
554
+ (
555
+ accessor: ts.ElementAccessExpression | ts.PropertyAccessExpression,
556
+ map: Metadata.Entry,
557
+ required: boolean,
558
+ ): ts.Statement[] =>
559
+ decode_entry(project)(importer)({
560
+ initializer: () =>
561
+ ts.factory.createBinaryExpression(
562
+ accessor,
563
+ ts.factory.createToken(
564
+ ts.SyntaxKind.QuestionQuestionEqualsToken,
565
+ ),
566
+ ts.factory.createNewExpression(
567
+ ts.factory.createIdentifier("Map"),
568
+ [
569
+ TypeFactory.keyword("any"),
570
+ TypeFactory.keyword("any"),
571
+ ],
572
+ [],
573
+ ),
574
+ ),
575
+ setter: () =>
576
+ ts.factory.createCallExpression(
577
+ IdentifierFactory.access(accessor)("set"),
578
+ undefined,
579
+ [
580
+ ts.factory.createIdentifier("entry.key"),
581
+ ts.factory.createIdentifier("entry.value"),
582
+ ],
583
+ ),
584
+ })(map, required);
585
+
586
+ const decode_entry =
587
+ (project: IProject) =>
588
+ (importer: FunctionImporter) =>
589
+ (props: {
590
+ initializer: () => ts.Expression;
591
+ setter: () => ts.Expression;
592
+ }) =>
593
+ (map: Metadata.Entry, required: boolean): ts.Statement[] => {
594
+ const statements: ts.Statement[] = [
595
+ ...(required
596
+ ? []
597
+ : [
598
+ ts.factory.createExpressionStatement(
599
+ props.initializer(),
600
+ ),
601
+ ]),
602
+ StatementFactory.constant(
603
+ "piece",
604
+ ts.factory.createAdd(
605
+ ts.factory.createCallExpression(
606
+ IdentifierFactory.access(READER())("uint32"),
607
+ undefined,
608
+ undefined,
609
+ ),
610
+ ts.factory.createCallExpression(
611
+ IdentifierFactory.access(READER())("index"),
612
+ undefined,
613
+ undefined,
614
+ ),
615
+ ),
616
+ ),
617
+ ...write_object_function_body(project)(importer)({
618
+ condition: ts.factory.createLessThan(
619
+ ts.factory.createCallExpression(
620
+ IdentifierFactory.access(READER())("index"),
621
+ undefined,
622
+ undefined,
623
+ ),
624
+ ts.factory.createIdentifier("piece"),
625
+ ),
626
+ tag: "kind",
627
+ output: "entry",
628
+ })([
629
+ MetadataProperty.create({
630
+ key: MetadataFactory.soleLiteral("key"),
631
+ value: map.key,
632
+ description: null,
633
+ jsDocTags: [],
634
+ }),
635
+ MetadataProperty.create({
636
+ key: MetadataFactory.soleLiteral("value"),
637
+ value: map.value,
638
+ description: null,
639
+ jsDocTags: [],
640
+ }),
641
+ ]),
642
+ ts.factory.createExpressionStatement(props.setter()),
643
+ ];
644
+ return [
645
+ ts.factory.createExpressionStatement(
646
+ ExpressionFactory.selfCall(
647
+ ts.factory.createBlock(statements, true),
648
+ ),
649
+ ),
650
+ ];
651
+ };
652
+ }
653
+
654
+ const PREFIX = "$pd";
655
+ const READER = () => ts.factory.createIdentifier("reader");