ts-proto 1.128.0 → 1.130.0
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 +14 -0
- package/README.markdown +6 -0
- package/build/main.js +95 -42
- package/build/options.js +2 -0
- package/build/types.js +13 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [1.130.0](https://github.com/stephenh/ts-proto/compare/v1.129.0...v1.130.0) (2022-10-22)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* support `useReadonlyTypes` option ([#691](https://github.com/stephenh/ts-proto/issues/691)) ([4b87334](https://github.com/stephenh/ts-proto/commit/4b8733452fb59cea3b9fb4721159b97e6df59854))
|
|
7
|
+
|
|
8
|
+
# [1.129.0](https://github.com/stephenh/ts-proto/compare/v1.128.0...v1.129.0) (2022-10-16)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* support `useMapType` option ([#686](https://github.com/stephenh/ts-proto/issues/686)) ([f2e80ab](https://github.com/stephenh/ts-proto/commit/f2e80ab3ecc3a438ecbd88b2170b8119ebadfcd3))
|
|
14
|
+
|
|
1
15
|
# [1.128.0](https://github.com/stephenh/ts-proto/compare/v1.127.0...v1.128.0) (2022-10-13)
|
|
2
16
|
|
|
3
17
|
|
package/README.markdown
CHANGED
|
@@ -458,6 +458,12 @@ Generated code will be placed in the Gradle build directory.
|
|
|
458
458
|
- **Note**: Uses are accummulated, so multiple values are expected in the form of `--ts_proto_opt=M... --ts_proto_opt=M...` (one `ts_proto_opt` per mapping).
|
|
459
459
|
- **Note**: Proto files that match mapped imports **will not be generated**.
|
|
460
460
|
|
|
461
|
+
- With `--ts_proto_opt=useMapType=true`, the generated code for protobuf `map<key_type, value_type>` will become `Map<key_type, value_type>` that uses JavaScript Map type.
|
|
462
|
+
|
|
463
|
+
The default behavior is `useMapType=false`, which makes it generate the code for protobuf `map<key_type, value_type` with the key-value pair like `{[key: key_type]: value_type}`.
|
|
464
|
+
|
|
465
|
+
- With `--ts_proto_opt=useReadonlyTypes=true`, the generated types will be declared as immutable using typescript's `readonly` modifer.
|
|
466
|
+
|
|
461
467
|
### NestJS Support
|
|
462
468
|
|
|
463
469
|
We have a great way of working together with [nestjs](https://docs.nestjs.com/microservices/grpc). `ts-proto` generates `interfaces` and `decorators` for you controller, client. For more information see the [nestjs readme](NESTJS.markdown).
|
package/build/main.js
CHANGED
|
@@ -530,7 +530,7 @@ function generateInterfaceDeclaration(ctx, fullName, messageDesc, sourceInfo, fu
|
|
|
530
530
|
const name = (0, case_1.maybeSnakeToCamel)(fieldDesc.name, options);
|
|
531
531
|
const type = (0, types_1.toTypeName)(ctx, messageDesc, fieldDesc);
|
|
532
532
|
const q = (0, types_1.isOptionalProperty)(fieldDesc, messageDesc.options, options) ? "?" : "";
|
|
533
|
-
chunks.push((0, ts_poet_1.code) `${name}${q}: ${type}, `);
|
|
533
|
+
chunks.push((0, ts_poet_1.code) `${ctx.options.useReadonlyTypes ? "readonly " : ""}${name}${q}: ${type}, `);
|
|
534
534
|
});
|
|
535
535
|
chunks.push((0, ts_poet_1.code) `}`);
|
|
536
536
|
return (0, ts_poet_1.joinCode)(chunks, { on: "\n" });
|
|
@@ -589,7 +589,9 @@ function generateBaseInstanceFactory(ctx, fullName, messageDesc, fullTypeName) {
|
|
|
589
589
|
const val = (0, types_1.isWithinOneOf)(field)
|
|
590
590
|
? "undefined"
|
|
591
591
|
: (0, types_1.isMapType)(ctx, messageDesc, field)
|
|
592
|
-
?
|
|
592
|
+
? ctx.options.useMapType
|
|
593
|
+
? "new Map()"
|
|
594
|
+
: "{}"
|
|
593
595
|
: (0, types_1.isRepeated)(field)
|
|
594
596
|
? "[]"
|
|
595
597
|
: (0, types_1.defaultValue)(ctx, field);
|
|
@@ -621,8 +623,8 @@ function generateDecode(ctx, fullName, messageDesc) {
|
|
|
621
623
|
): ${fullName} {
|
|
622
624
|
const reader = input instanceof ${Reader} ? input : new ${Reader}(input);
|
|
623
625
|
let end = length === undefined ? reader.len : reader.pos + length;
|
|
624
|
-
const message = ${createBase};
|
|
625
626
|
`);
|
|
627
|
+
chunks.push((0, ts_poet_1.code) `const message = ${createBase}${options.useReadonlyTypes ? " as any" : ""};`);
|
|
626
628
|
if (options.unknownFields) {
|
|
627
629
|
chunks.push((0, ts_poet_1.code) `(message as any)._unknownFields = {}`);
|
|
628
630
|
}
|
|
@@ -698,10 +700,13 @@ function generateDecode(ctx, fullName, messageDesc) {
|
|
|
698
700
|
if ((0, types_1.isMapType)(ctx, messageDesc, field)) {
|
|
699
701
|
// We need a unique const within the `cast` statement
|
|
700
702
|
const varName = `entry${field.number}`;
|
|
703
|
+
const valueSetterSnippet = ctx.options.useMapType
|
|
704
|
+
? `message.${fieldName}${maybeNonNullAssertion}.set(${varName}.key, ${varName}.value)`
|
|
705
|
+
: `message.${fieldName}${maybeNonNullAssertion}[${varName}.key] = ${varName}.value`;
|
|
701
706
|
chunks.push((0, ts_poet_1.code) `
|
|
702
707
|
const ${varName} = ${readSnippet};
|
|
703
708
|
if (${varName}.value !== undefined) {
|
|
704
|
-
|
|
709
|
+
${valueSetterSnippet};
|
|
705
710
|
}
|
|
706
711
|
`);
|
|
707
712
|
}
|
|
@@ -822,11 +827,20 @@ function generateEncode(ctx, fullName, messageDesc) {
|
|
|
822
827
|
`
|
|
823
828
|
: writeSnippet(`{ ${maybeTypeField} key: key as any, value }`);
|
|
824
829
|
const optionalAlternative = isOptional ? " || {}" : "";
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
${
|
|
828
|
-
|
|
829
|
-
|
|
830
|
+
if (ctx.options.useMapType) {
|
|
831
|
+
chunks.push((0, ts_poet_1.code) `
|
|
832
|
+
message.${fieldName}${optionalAlternative}.forEach((value, key) => {
|
|
833
|
+
${entryWriteSnippet}
|
|
834
|
+
});
|
|
835
|
+
`);
|
|
836
|
+
}
|
|
837
|
+
else {
|
|
838
|
+
chunks.push((0, ts_poet_1.code) `
|
|
839
|
+
Object.entries(message.${fieldName}${optionalAlternative}).forEach(([key, value]) => {
|
|
840
|
+
${entryWriteSnippet}
|
|
841
|
+
});
|
|
842
|
+
`);
|
|
843
|
+
}
|
|
830
844
|
}
|
|
831
845
|
else if ((0, types_1.packedType)(field.type) === undefined) {
|
|
832
846
|
const listWriteSnippet = (0, ts_poet_1.code) `
|
|
@@ -1099,14 +1113,26 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
|
|
|
1099
1113
|
if ((0, types_1.isMapType)(ctx, messageDesc, field)) {
|
|
1100
1114
|
const fieldType = (0, types_1.toTypeName)(ctx, messageDesc, field);
|
|
1101
1115
|
const i = maybeCastToNumber(ctx, messageDesc, field, "key");
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1116
|
+
if (ctx.options.useMapType) {
|
|
1117
|
+
chunks.push((0, ts_poet_1.code) `
|
|
1118
|
+
${fieldName}: ${ctx.utils.isObject}(${jsonProperty})
|
|
1119
|
+
? Object.entries(${jsonProperty}).reduce<${fieldType}>((acc, [key, value]) => {
|
|
1120
|
+
acc.set(${i}, ${readSnippet("value")});
|
|
1121
|
+
return acc;
|
|
1122
|
+
}, new Map())
|
|
1123
|
+
: new Map(),
|
|
1124
|
+
`);
|
|
1125
|
+
}
|
|
1126
|
+
else {
|
|
1127
|
+
chunks.push((0, ts_poet_1.code) `
|
|
1128
|
+
${fieldName}: ${ctx.utils.isObject}(${jsonProperty})
|
|
1129
|
+
? Object.entries(${jsonProperty}).reduce<${fieldType}>((acc, [key, value]) => {
|
|
1130
|
+
acc[${i}] = ${readSnippet("value")};
|
|
1131
|
+
return acc;
|
|
1132
|
+
}, {})
|
|
1133
|
+
: {},
|
|
1134
|
+
`);
|
|
1135
|
+
}
|
|
1110
1136
|
}
|
|
1111
1137
|
else {
|
|
1112
1138
|
const readValueSnippet = readSnippet("e");
|
|
@@ -1286,14 +1312,26 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
|
|
|
1286
1312
|
};
|
|
1287
1313
|
if ((0, types_1.isMapType)(ctx, messageDesc, field)) {
|
|
1288
1314
|
// Maps might need their values transformed, i.e. bytes --> base64
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1315
|
+
if (ctx.options.useMapType) {
|
|
1316
|
+
chunks.push((0, ts_poet_1.code) `
|
|
1317
|
+
${jsonProperty} = {};
|
|
1318
|
+
if (message.${fieldName}) {
|
|
1319
|
+
message.${fieldName}.forEach((v, k) => {
|
|
1320
|
+
${jsonProperty}[k] = ${readSnippet("v")};
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
`);
|
|
1324
|
+
}
|
|
1325
|
+
else {
|
|
1326
|
+
chunks.push((0, ts_poet_1.code) `
|
|
1327
|
+
${jsonProperty} = {};
|
|
1328
|
+
if (message.${fieldName}) {
|
|
1329
|
+
Object.entries(message.${fieldName}).forEach(([k, v]) => {
|
|
1330
|
+
${jsonProperty}[k] = ${readSnippet("v")};
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
`);
|
|
1334
|
+
}
|
|
1297
1335
|
}
|
|
1298
1336
|
else if ((0, types_1.isRepeated)(field)) {
|
|
1299
1337
|
// Arrays might need their elements transformed
|
|
@@ -1339,7 +1377,7 @@ function generateFromPartial(ctx, fullName, messageDesc) {
|
|
|
1339
1377
|
if (options.usePrototypeForDefaults) {
|
|
1340
1378
|
createBase = (0, ts_poet_1.code) `Object.create(${createBase}) as ${fullName}`;
|
|
1341
1379
|
}
|
|
1342
|
-
chunks.push((0, ts_poet_1.code) `const message = ${createBase};`);
|
|
1380
|
+
chunks.push((0, ts_poet_1.code) `const message = ${createBase}${options.useReadonlyTypes ? " as any" : ""};`);
|
|
1343
1381
|
// add a check for each incoming field
|
|
1344
1382
|
messageDesc.field.forEach((field) => {
|
|
1345
1383
|
const fieldName = (0, case_1.maybeSnakeToCamel)(field.name, options);
|
|
@@ -1408,14 +1446,29 @@ function generateFromPartial(ctx, fullName, messageDesc) {
|
|
|
1408
1446
|
if ((0, types_1.isMapType)(ctx, messageDesc, field)) {
|
|
1409
1447
|
const fieldType = (0, types_1.toTypeName)(ctx, messageDesc, field);
|
|
1410
1448
|
const i = maybeCastToNumber(ctx, messageDesc, field, "key");
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1449
|
+
if (ctx.options.useMapType) {
|
|
1450
|
+
chunks.push((0, ts_poet_1.code) `
|
|
1451
|
+
message.${fieldName} = (() => {
|
|
1452
|
+
const m = new Map();
|
|
1453
|
+
(object.${fieldName} as ${fieldType} ?? new Map()).forEach((value, key) => {
|
|
1454
|
+
if (value !== undefined) {
|
|
1455
|
+
m.set(${i}, ${readSnippet("value")});
|
|
1456
|
+
}
|
|
1457
|
+
});
|
|
1458
|
+
return m;
|
|
1459
|
+
})();
|
|
1460
|
+
`);
|
|
1461
|
+
}
|
|
1462
|
+
else {
|
|
1463
|
+
chunks.push((0, ts_poet_1.code) `
|
|
1464
|
+
message.${fieldName} = Object.entries(object.${fieldName} ?? {}).reduce<${fieldType}>((acc, [key, value]) => {
|
|
1465
|
+
if (value !== undefined) {
|
|
1466
|
+
acc[${i}] = ${readSnippet("value")};
|
|
1467
|
+
}
|
|
1468
|
+
return acc;
|
|
1469
|
+
}, {});
|
|
1470
|
+
`);
|
|
1471
|
+
}
|
|
1419
1472
|
}
|
|
1420
1473
|
else {
|
|
1421
1474
|
chunks.push((0, ts_poet_1.code) `
|
|
@@ -1471,7 +1524,7 @@ function generateWrap(ctx, fullProtoTypeName, fieldNames) {
|
|
|
1471
1524
|
if ((0, types_1.isAnyValueTypeName)(fullProtoTypeName)) {
|
|
1472
1525
|
if (ctx.options.oneof === options_1.OneofOption.UNIONS) {
|
|
1473
1526
|
chunks.push((0, ts_poet_1.code) `wrap(value: any): Value {
|
|
1474
|
-
const result = createBaseValue();
|
|
1527
|
+
const result = createBaseValue()${ctx.options.useReadonlyTypes ? " as any" : ""};
|
|
1475
1528
|
|
|
1476
1529
|
if (value === null) {
|
|
1477
1530
|
result.kind = {$case: '${fieldNames.nullValue}', ${fieldNames.nullValue}: NullValue.NULL_VALUE};
|
|
@@ -1494,7 +1547,7 @@ function generateWrap(ctx, fullProtoTypeName, fieldNames) {
|
|
|
1494
1547
|
}
|
|
1495
1548
|
else {
|
|
1496
1549
|
chunks.push((0, ts_poet_1.code) `wrap(value: any): Value {
|
|
1497
|
-
const result = createBaseValue();
|
|
1550
|
+
const result = createBaseValue()${ctx.options.useReadonlyTypes ? " as any" : ""};
|
|
1498
1551
|
|
|
1499
1552
|
if (value === null) {
|
|
1500
1553
|
result.${fieldNames.nullValue} = NullValue.NULL_VALUE;
|
|
@@ -1517,8 +1570,8 @@ function generateWrap(ctx, fullProtoTypeName, fieldNames) {
|
|
|
1517
1570
|
}
|
|
1518
1571
|
}
|
|
1519
1572
|
if ((0, types_1.isListValueTypeName)(fullProtoTypeName)) {
|
|
1520
|
-
chunks.push((0, ts_poet_1.code) `wrap(value: Array<any> | undefined): ListValue {
|
|
1521
|
-
const result = createBaseListValue();
|
|
1573
|
+
chunks.push((0, ts_poet_1.code) `wrap(value: ${ctx.options.useReadonlyTypes ? "ReadonlyArray<any>" : "Array<any>"} | undefined): ListValue {
|
|
1574
|
+
const result = createBaseListValue()${ctx.options.useReadonlyTypes ? " as any" : ""};
|
|
1522
1575
|
|
|
1523
1576
|
result.values = value ?? [];
|
|
1524
1577
|
|
|
@@ -1526,8 +1579,8 @@ function generateWrap(ctx, fullProtoTypeName, fieldNames) {
|
|
|
1526
1579
|
}`);
|
|
1527
1580
|
}
|
|
1528
1581
|
if ((0, types_1.isFieldMaskTypeName)(fullProtoTypeName)) {
|
|
1529
|
-
chunks.push((0, ts_poet_1.code) `wrap(paths: string[]): FieldMask {
|
|
1530
|
-
const result = createBaseFieldMask();
|
|
1582
|
+
chunks.push((0, ts_poet_1.code) `wrap(paths: ${ctx.options.useReadonlyTypes ? "readonly " : ""} string[]): FieldMask {
|
|
1583
|
+
const result = createBaseFieldMask()${ctx.options.useReadonlyTypes ? " as any" : ""};
|
|
1531
1584
|
|
|
1532
1585
|
result.paths = paths;
|
|
1533
1586
|
|
|
@@ -1587,12 +1640,12 @@ function generateUnwrap(ctx, fullProtoTypeName, fieldNames) {
|
|
|
1587
1640
|
}
|
|
1588
1641
|
}
|
|
1589
1642
|
if ((0, types_1.isListValueTypeName)(fullProtoTypeName)) {
|
|
1590
|
-
chunks.push((0, ts_poet_1.code) `unwrap(message: ListValue): Array<any> {
|
|
1643
|
+
chunks.push((0, ts_poet_1.code) `unwrap(message: ${ctx.options.useReadonlyTypes ? "any" : "ListValue"}): Array<any> {
|
|
1591
1644
|
return message.values;
|
|
1592
1645
|
}`);
|
|
1593
1646
|
}
|
|
1594
1647
|
if ((0, types_1.isFieldMaskTypeName)(fullProtoTypeName)) {
|
|
1595
|
-
chunks.push((0, ts_poet_1.code) `unwrap(message: FieldMask): string[] {
|
|
1648
|
+
chunks.push((0, ts_poet_1.code) `unwrap(message: ${ctx.options.useReadonlyTypes ? "any" : "FieldMask"}): string[] {
|
|
1596
1649
|
return message.paths;
|
|
1597
1650
|
}`);
|
|
1598
1651
|
}
|
package/build/options.js
CHANGED
package/build/types.js
CHANGED
|
@@ -457,13 +457,17 @@ function valueTypeName(ctx, typeName) {
|
|
|
457
457
|
? (0, ts_poet_1.code) `string`
|
|
458
458
|
: (0, ts_poet_1.code) `Uint8Array`;
|
|
459
459
|
case ".google.protobuf.ListValue":
|
|
460
|
-
return (0, ts_poet_1.code) `Array<any>`;
|
|
460
|
+
return ctx.options.useReadonlyTypes ? (0, ts_poet_1.code) `ReadonlyArray<any>` : (0, ts_poet_1.code) `Array<any>`;
|
|
461
461
|
case ".google.protobuf.Value":
|
|
462
462
|
return (0, ts_poet_1.code) `any`;
|
|
463
463
|
case ".google.protobuf.Struct":
|
|
464
|
-
return (0, ts_poet_1.code) `{[key: string]: any}`;
|
|
464
|
+
return ctx.options.useReadonlyTypes ? (0, ts_poet_1.code) `{readonly [key: string]: any}` : (0, ts_poet_1.code) `{[key: string]: any}`;
|
|
465
465
|
case ".google.protobuf.FieldMask":
|
|
466
|
-
return ctx.options.useJsonWireFormat
|
|
466
|
+
return ctx.options.useJsonWireFormat
|
|
467
|
+
? (0, ts_poet_1.code) `string`
|
|
468
|
+
: ctx.options.useReadonlyTypes
|
|
469
|
+
? (0, ts_poet_1.code) `readonly string[]`
|
|
470
|
+
: (0, ts_poet_1.code) `string[]`;
|
|
467
471
|
case ".google.protobuf.Duration":
|
|
468
472
|
return ctx.options.useJsonWireFormat ? (0, ts_poet_1.code) `string` : undefined;
|
|
469
473
|
case ".google.protobuf.Timestamp":
|
|
@@ -557,8 +561,14 @@ function toTypeName(ctx, messageDesc, field) {
|
|
|
557
561
|
const mapType = detectMapType(ctx, messageDesc, field);
|
|
558
562
|
if (mapType) {
|
|
559
563
|
const { keyType, valueType } = mapType;
|
|
564
|
+
if (ctx.options.useMapType) {
|
|
565
|
+
return (0, ts_poet_1.code) `Map<${keyType}, ${valueType}>`;
|
|
566
|
+
}
|
|
560
567
|
return (0, ts_poet_1.code) `{ [key: ${keyType} ]: ${valueType} }`;
|
|
561
568
|
}
|
|
569
|
+
if (ctx.options.useReadonlyTypes) {
|
|
570
|
+
return (0, ts_poet_1.code) `readonly ${type}[]`;
|
|
571
|
+
}
|
|
562
572
|
return (0, ts_poet_1.code) `${type}[]`;
|
|
563
573
|
}
|
|
564
574
|
if (isValueType(ctx, field)) {
|