typia 7.0.0-dev.20240921 → 7.0.0-dev.20240922

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