ts-proto 1.96.0 → 1.96.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [1.96.1](https://github.com/stephenh/ts-proto/compare/v1.96.0...v1.96.1) (2021-12-28)
2
+
3
+
4
+ ### Performance Improvements
5
+
6
+ * optimize object creation in `decode`, `fromJSON` and `fromPartial` ([#457](https://github.com/stephenh/ts-proto/issues/457)) ([70832d3](https://github.com/stephenh/ts-proto/commit/70832d33bae82ecb3c5f87845d14e992a13437e4))
7
+
1
8
  # [1.96.0](https://github.com/stephenh/ts-proto/compare/v1.95.1...v1.96.0) (2021-12-24)
2
9
 
3
10
 
package/build/main.js CHANGED
@@ -70,7 +70,7 @@ function generateFile(ctx, fileDesc) {
70
70
  // then add the encoder/decoder/base instance
71
71
  visit_1.visit(fileDesc, sourceInfo, (fullName, message, sInfo, fullProtoTypeName) => {
72
72
  const fullTypeName = utils_1.maybePrefixPackage(fileDesc, fullProtoTypeName);
73
- chunks.push(generateBaseInstance(ctx, fullName, message, fullTypeName));
73
+ chunks.push(generateBaseInstanceFactory(ctx, fullName, message, fullTypeName));
74
74
  const staticMembers = [];
75
75
  if (options.outputTypeRegistry) {
76
76
  staticMembers.push(ts_poet_1.code `$type: '${fullTypeName}' as const`);
@@ -460,20 +460,39 @@ function generateOneofProperty(ctx, messageDesc, oneofIndex, sourceInfo) {
460
460
  return prop;
461
461
  */
462
462
  }
463
- // Create a 'base' instance with default values for decode to use as a prototype
464
- function generateBaseInstance(ctx, fullName, messageDesc, fullTypeName) {
465
- const fields = messageDesc.field
466
- .filter((field) => !types_1.isWithinOneOf(field))
467
- .map((field) => [field, types_1.defaultValue(ctx, field)])
468
- .filter(([field, val]) => val !== 'undefined' && !types_1.isBytes(field))
469
- .map(([field, val]) => {
463
+ // Create a function that constructs 'base' instance with default values for decode to use as a prototype
464
+ function generateBaseInstanceFactory(ctx, fullName, messageDesc, fullTypeName) {
465
+ const fields = [];
466
+ // When oneof=unions, we generate a single property with an ADT per `oneof` clause.
467
+ const processedOneofs = new Set();
468
+ for (const field of messageDesc.field) {
469
+ if (types_1.isWithinOneOfThatShouldBeUnion(ctx.options, field)) {
470
+ const { oneofIndex } = field;
471
+ if (!processedOneofs.has(oneofIndex)) {
472
+ processedOneofs.add(oneofIndex);
473
+ const name = case_1.maybeSnakeToCamel(messageDesc.oneofDecl[oneofIndex].name, ctx.options);
474
+ fields.push(ts_poet_1.code `${name}: undefined`);
475
+ }
476
+ continue;
477
+ }
470
478
  const name = case_1.maybeSnakeToCamel(field.name, ctx.options);
471
- return ts_poet_1.code `${name}: ${val}`;
472
- });
479
+ const val = types_1.isWithinOneOf(field)
480
+ ? 'undefined'
481
+ : types_1.isMapType(ctx, messageDesc, field)
482
+ ? '{}'
483
+ : types_1.isRepeated(field)
484
+ ? '[]'
485
+ : types_1.defaultValue(ctx, field);
486
+ fields.push(ts_poet_1.code `${name}: ${val}`);
487
+ }
473
488
  if (ctx.options.outputTypeRegistry) {
474
489
  fields.unshift(ts_poet_1.code `$type: '${fullTypeName}'`);
475
490
  }
476
- return ts_poet_1.code `const base${fullName}: object = { ${ts_poet_1.joinCode(fields, { on: ',' })} };`;
491
+ return ts_poet_1.code `
492
+ function createBase${fullName}(): ${fullName} {
493
+ return { ${ts_poet_1.joinCode(fields, { on: ',' })} };
494
+ }
495
+ `;
477
496
  }
478
497
  /** Creates a function to decode a message by loop overing the tags. */
479
498
  function generateDecode(ctx, fullName, messageDesc) {
@@ -487,22 +506,8 @@ function generateDecode(ctx, fullName, messageDesc) {
487
506
  ): ${fullName} {
488
507
  const reader = input instanceof ${Reader} ? input : new ${Reader}(input);
489
508
  let end = length === undefined ? reader.len : reader.pos + length;
490
- const message = { ...base${fullName} } as ${fullName};
509
+ const message = createBase${fullName}();
491
510
  `);
492
- // initialize all lists
493
- messageDesc.field.filter(types_1.isRepeated).forEach((field) => {
494
- const name = case_1.maybeSnakeToCamel(field.name, options);
495
- const value = types_1.isMapType(ctx, messageDesc, field) ? '{}' : '[]';
496
- chunks.push(ts_poet_1.code `message.${name} = ${value};`);
497
- });
498
- // initialize all buffers
499
- messageDesc.field
500
- .filter((field) => !types_1.isRepeated(field) && !types_1.isWithinOneOf(field) && types_1.isBytes(field))
501
- .forEach((field) => {
502
- const value = options.env === options_1.EnvOption.NODE ? 'Buffer.alloc(0)' : 'new Uint8Array()';
503
- const name = case_1.maybeSnakeToCamel(field.name, options);
504
- chunks.push(ts_poet_1.code `message.${name} = ${value};`);
505
- });
506
511
  // start the tag loop
507
512
  chunks.push(ts_poet_1.code `
508
513
  while (reader.pos < end) {
@@ -567,28 +572,29 @@ function generateDecode(ctx, fullName, messageDesc) {
567
572
  }
568
573
  // and then use the snippet to handle repeated fields if necessary
569
574
  if (types_1.isRepeated(field)) {
575
+ const maybeNonNullAssertion = ctx.options.useOptionals === 'all' ? '!' : '';
570
576
  if (types_1.isMapType(ctx, messageDesc, field)) {
571
577
  // We need a unique const within the `cast` statement
572
578
  const varName = `entry${field.number}`;
573
579
  chunks.push(ts_poet_1.code `
574
580
  const ${varName} = ${readSnippet};
575
581
  if (${varName}.value !== undefined) {
576
- message.${fieldName}[${varName}.key] = ${varName}.value;
582
+ message.${fieldName}${maybeNonNullAssertion}[${varName}.key] = ${varName}.value;
577
583
  }
578
584
  `);
579
585
  }
580
586
  else if (types_1.packedType(field.type) === undefined) {
581
- chunks.push(ts_poet_1.code `message.${fieldName}.push(${readSnippet});`);
587
+ chunks.push(ts_poet_1.code `message.${fieldName}${maybeNonNullAssertion}.push(${readSnippet});`);
582
588
  }
583
589
  else {
584
590
  chunks.push(ts_poet_1.code `
585
591
  if ((tag & 7) === 2) {
586
592
  const end2 = reader.uint32() + reader.pos;
587
593
  while (reader.pos < end2) {
588
- message.${fieldName}.push(${readSnippet});
594
+ message.${fieldName}${maybeNonNullAssertion}.push(${readSnippet});
589
595
  }
590
596
  } else {
591
- message.${fieldName}.push(${readSnippet});
597
+ message.${fieldName}${maybeNonNullAssertion}.push(${readSnippet});
592
598
  }
593
599
  `);
594
600
  }
@@ -799,7 +805,7 @@ function generateFromJson(ctx, fullName, messageDesc) {
799
805
  // create the basic function declaration
800
806
  chunks.push(ts_poet_1.code `
801
807
  fromJSON(${messageDesc.field.length > 0 ? 'object' : '_'}: any): ${fullName} {
802
- const message = { ...base${fullName} } as ${fullName};
808
+ const message = createBase${fullName}();
803
809
  `);
804
810
  // add a check for each incoming field
805
811
  messageDesc.field.forEach((field) => {
@@ -1100,7 +1106,7 @@ function generateFromPartial(ctx, fullName, messageDesc) {
1100
1106
  const paramName = messageDesc.field.length > 0 ? 'object' : '_';
1101
1107
  chunks.push(ts_poet_1.code `
1102
1108
  fromPartial<I extends ${utils.Exact}<${utils.DeepPartial}<${fullName}>, I>>(${paramName}: I): ${fullName} {
1103
- const message = { ...base${fullName} } as ${fullName};
1109
+ const message = createBase${fullName}();
1104
1110
  `);
1105
1111
  // add a check for each incoming field
1106
1112
  messageDesc.field.forEach((field) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-proto",
3
- "version": "1.96.0",
3
+ "version": "1.96.1",
4
4
  "description": "",
5
5
  "main": "build/plugin.js",
6
6
  "repository": "github:stephenh/ts-proto",