ts-proto 2.13.3 → 2.15.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/README.markdown +11 -1
- package/build/src/generate-nestjs.d.ts +1 -1
- package/build/src/generate-nestjs.js +6 -3
- package/build/src/generate-type-registry.js +3 -1
- package/build/src/main.d.ts +4 -1
- package/build/src/main.js +121 -3
- package/build/src/options.d.ts +7 -0
- package/build/src/options.js +13 -1
- package/build/src/schema.js +48 -27
- package/package.json +1 -1
package/README.markdown
CHANGED
|
@@ -465,11 +465,17 @@ With `--ts_proto_opt=protoJsonFormat=false`, strict proto3 compliance is disable
|
|
|
465
465
|
|
|
466
466
|
(Requires `nestJs=true`.)
|
|
467
467
|
|
|
468
|
+
- With `--ts_proto_opt=useNestjsFqnServiceName=true`, the generated `@FooServiceControllerMethods()` decorator will pass the fully qualified service name (i.e. `package.FooService` instead of `FooService`) to the `@GrpcMethod`/`@GrpcStreamMethod` decorators of `@nestjs/microservices`.
|
|
469
|
+
|
|
470
|
+
NestJS falls back to resolving a handler by the `package.Service` segment of the gRPC method path, so the handlers are found regardless of which `package` the gRPC server was configured with, and services with the same name in different packages no longer collide. The `FOO_SERVICE_NAME` const is not affected, since `client.getService()` expects the package-relative name.
|
|
471
|
+
|
|
472
|
+
(Requires `nestJs=true`.)
|
|
473
|
+
|
|
468
474
|
- With `--ts_proto_opt=nestJs=true`, the defaults will change to generate [NestJS protobuf](https://docs.nestjs.com/microservices/grpc) friendly types & service interfaces that can be used in both the client-side and server-side of NestJS protobuf implementations. See the [nestjs readme](NESTJS.markdown) for more information and implementation examples.
|
|
469
475
|
|
|
470
476
|
Specifically `outputEncodeMethods`, `outputJsonMethods`, and `outputClientImpl` will all be false, `lowerCaseServiceMethods` will be true and `outputServices` will be ignored.
|
|
471
477
|
|
|
472
|
-
Note that `addGrpcMetadata`, `addNestjsRestParameter` and `
|
|
478
|
+
Note that `addGrpcMetadata`, `addNestjsRestParameter`, `returnObservable` and `useNestjsFqnServiceName` will still be false.
|
|
473
479
|
|
|
474
480
|
- With `--ts_proto_opt=useDate=false`, fields of type `google.protobuf.Timestamp` will not be mapped to type `Date` in the generated types. See [Timestamp](#timestamp) for more details.
|
|
475
481
|
|
|
@@ -662,6 +668,10 @@ This option allows the library to act in a compatible way with the [Wire impleme
|
|
|
662
668
|
|
|
663
669
|
- With `--ts_proto_opt=useDuration=string`, the generated code will use the `string` type for `google.protobuf.Duration` instead of `{seconds: number, nano: number}`.
|
|
664
670
|
|
|
671
|
+
- With `--ts_proto_opt=anyType=@type` (the default), `google.protobuf.Any` uses its canonical JSON form in `toJSON`/`fromJSON`: the JSON of the packed message with an added `"@type"` key, or `{"@type": ..., "value": ...}` when the packed message is a well-known type with its own JSON form, such as `google.protobuf.Duration`. The packed message type is looked up by name in the type registry, so this needs `outputTypeRegistry=true` (and the default `outputEncodeMethods=true`), and the type must be registered; otherwise `toJSON`/`fromJSON` throw. Without the type registry, `Any` keeps the `{"typeUrl": ..., "value": ...}` form, with `value` base64 encoded.
|
|
672
|
+
|
|
673
|
+
`--ts_proto_opt=anyType=typeUrl` keeps the `{"typeUrl": ..., "value": ...}` form even with the type registry. It is deprecated and may be removed in a future release.
|
|
674
|
+
|
|
665
675
|
### NestJS Support
|
|
666
676
|
|
|
667
677
|
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).
|
|
@@ -4,4 +4,4 @@ import SourceInfo from "./sourceInfo";
|
|
|
4
4
|
import { Context } from "./context";
|
|
5
5
|
export declare function generateNestjsServiceController(ctx: Context, fileDesc: FileDescriptorProto, sourceInfo: SourceInfo, serviceDesc: ServiceDescriptorProto): Code;
|
|
6
6
|
export declare function generateNestjsServiceClient(ctx: Context, fileDesc: FileDescriptorProto, sourceInfo: SourceInfo, serviceDesc: ServiceDescriptorProto): Code;
|
|
7
|
-
export declare function generateNestjsGrpcServiceMethodsDecorator(ctx: Context, serviceDesc: ServiceDescriptorProto): Code;
|
|
7
|
+
export declare function generateNestjsGrpcServiceMethodsDecorator(ctx: Context, fileDesc: FileDescriptorProto, serviceDesc: ServiceDescriptorProto): Code;
|
|
@@ -118,10 +118,13 @@ function generateNestjsServiceClient(ctx, fileDesc, sourceInfo, serviceDesc) {
|
|
|
118
118
|
chunks.push((0, ts_poet_1.code) `}`);
|
|
119
119
|
return (0, ts_poet_1.joinCode)(chunks, { on: "\n\n" });
|
|
120
120
|
}
|
|
121
|
-
function generateNestjsGrpcServiceMethodsDecorator(ctx, serviceDesc) {
|
|
121
|
+
function generateNestjsGrpcServiceMethodsDecorator(ctx, fileDesc, serviceDesc) {
|
|
122
122
|
const { options } = ctx;
|
|
123
123
|
const GrpcMethod = (0, ts_poet_1.imp)("GrpcMethod@@nestjs/microservices");
|
|
124
124
|
const GrpcStreamMethod = (0, ts_poet_1.imp)("GrpcStreamMethod@@nestjs/microservices");
|
|
125
|
+
const serviceName = options.useNestjsFqnServiceName
|
|
126
|
+
? (0, utils_1.maybePrefixPackage)(fileDesc, serviceDesc.name)
|
|
127
|
+
: serviceDesc.name;
|
|
125
128
|
const grpcMethods = serviceDesc.method
|
|
126
129
|
.filter((m) => !m.clientStreaming)
|
|
127
130
|
.map((m) => {
|
|
@@ -142,13 +145,13 @@ function generateNestjsGrpcServiceMethodsDecorator(ctx, serviceDesc) {
|
|
|
142
145
|
const grpcMethods: string[] = [${grpcMethods.join(", ")}];
|
|
143
146
|
for (const method of grpcMethods) {
|
|
144
147
|
const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method);
|
|
145
|
-
${GrpcMethod}('${
|
|
148
|
+
${GrpcMethod}('${serviceName}', method)(constructor.prototype[method], method, descriptor);
|
|
146
149
|
Object.defineProperty(constructor.prototype, method, descriptor);
|
|
147
150
|
}
|
|
148
151
|
const grpcStreamMethods: string[] = [${grpcStreamMethods.join(", ")}];
|
|
149
152
|
for (const method of grpcStreamMethods) {
|
|
150
153
|
const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method);
|
|
151
|
-
${GrpcStreamMethod}('${
|
|
154
|
+
${GrpcStreamMethod}('${serviceName}', method)(constructor.prototype[method], method, descriptor);
|
|
152
155
|
Object.defineProperty(constructor.prototype, method, descriptor);
|
|
153
156
|
}
|
|
154
157
|
};
|
|
@@ -7,8 +7,10 @@ function generateTypeRegistry(ctx) {
|
|
|
7
7
|
const chunks = [];
|
|
8
8
|
chunks.push(generateMessageType(ctx));
|
|
9
9
|
if ((0, options_1.addTypeToMessages)(ctx.options)) {
|
|
10
|
+
// With outputTypeAnnotations=optional, messages declare `$type?`, so the registry has to accept them.
|
|
11
|
+
const optional = ctx.options.outputTypeAnnotations === "optional" ? "?" : "";
|
|
10
12
|
chunks.push((0, ts_poet_1.code) `
|
|
11
|
-
export type UnknownMessage = {$type: string};
|
|
13
|
+
export type UnknownMessage = {$type${optional}: string};
|
|
12
14
|
`);
|
|
13
15
|
}
|
|
14
16
|
else {
|
package/build/src/main.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { FileDescriptorProto } from "ts-proto-descriptors";
|
|
|
4
4
|
import { Context } from "./context";
|
|
5
5
|
import { Options } from "./options";
|
|
6
6
|
export declare function generateFile(ctx: Context, fileDesc: FileDescriptorProto): [string, Code];
|
|
7
|
-
export type Utils = ReturnType<typeof makeDeepPartial> & ReturnType<typeof makeObjectIdMethods> & ReturnType<typeof makeTimestampMethods> & ReturnType<typeof makeByteUtils> & ReturnType<typeof makeLongUtils> & ReturnType<typeof makeComparisonUtils> & ReturnType<typeof makeNiceGrpcServerStreamingMethodResult> & ReturnType<typeof makeGrpcWebErrorClass> & ReturnType<typeof makeExtensionClass> & ReturnType<typeof makeAssertionUtils> & ReturnType<typeof makeMessageFns>;
|
|
7
|
+
export type Utils = ReturnType<typeof makeDeepPartial> & ReturnType<typeof makeObjectIdMethods> & ReturnType<typeof makeTimestampMethods> & ReturnType<typeof makeByteUtils> & ReturnType<typeof makeLongUtils> & ReturnType<typeof makeComparisonUtils> & ReturnType<typeof makeNiceGrpcServerStreamingMethodResult> & ReturnType<typeof makeGrpcWebErrorClass> & ReturnType<typeof makeExtensionClass> & ReturnType<typeof makeAssertionUtils> & ReturnType<typeof makeMessageFns> & ReturnType<typeof makeAnyJsonUtils>;
|
|
8
8
|
/** These are runtime utility methods used by the generated code. */
|
|
9
9
|
export declare function makeUtils(options: Options): Utils;
|
|
10
10
|
declare function makeLongUtils(options: Options, bytes: ReturnType<typeof makeByteUtils>): {
|
|
@@ -43,6 +43,9 @@ declare function makeTimestampMethods(options: Options, longs: ReturnType<typeof
|
|
|
43
43
|
timestampFractionRegex: ConditionalOutput;
|
|
44
44
|
fromJsonTimestamp: ConditionalOutput;
|
|
45
45
|
};
|
|
46
|
+
declare function makeAnyJsonUtils(): {
|
|
47
|
+
anyJsonValueTypes: ConditionalOutput;
|
|
48
|
+
};
|
|
46
49
|
declare function makeComparisonUtils(): {
|
|
47
50
|
isObject: ConditionalOutput;
|
|
48
51
|
isSet: ConditionalOutput;
|
package/build/src/main.js
CHANGED
|
@@ -233,7 +233,7 @@ function generateFile(ctx, fileDesc) {
|
|
|
233
233
|
// and the service controller interface
|
|
234
234
|
chunks.push((0, generate_nestjs_1.generateNestjsServiceController)(ctx, fileDesc, sInfo, serviceDesc));
|
|
235
235
|
// generate nestjs grpc service controller decorator
|
|
236
|
-
chunks.push((0, generate_nestjs_1.generateNestjsGrpcServiceMethodsDecorator)(ctx, serviceDesc));
|
|
236
|
+
chunks.push((0, generate_nestjs_1.generateNestjsGrpcServiceMethodsDecorator)(ctx, fileDesc, serviceDesc));
|
|
237
237
|
let serviceConstName = `${(0, case_1.camelToSnake)(serviceDesc.name)}_NAME`;
|
|
238
238
|
if (!serviceDesc.name.toLowerCase().endsWith("service")) {
|
|
239
239
|
serviceConstName = `${(0, case_1.camelToSnake)(serviceDesc.name)}_SERVICE_NAME`;
|
|
@@ -340,6 +340,7 @@ function makeUtils(options) {
|
|
|
340
340
|
...extension,
|
|
341
341
|
...makeAssertionUtils(bytes),
|
|
342
342
|
...makeMessageFns(options, deepPartial, extension),
|
|
343
|
+
...makeAnyJsonUtils(),
|
|
343
344
|
};
|
|
344
345
|
}
|
|
345
346
|
function makeProtobufTimestampWrapper() {
|
|
@@ -830,6 +831,31 @@ function makeTimestampMethods(options, longs, bytes) {
|
|
|
830
831
|
`);
|
|
831
832
|
return { toTimestamp, fromTimestamp, timestampFractionRegex, fromJsonTimestamp };
|
|
832
833
|
}
|
|
834
|
+
function makeAnyJsonUtils() {
|
|
835
|
+
// Well-known types whose JSON is not an object of their fields. Packed in an Any, that
|
|
836
|
+
// JSON goes under "value" rather than next to "@type".
|
|
837
|
+
const anyJsonValueTypes = (0, ts_poet_1.conditionalOutput)("anyJsonValueTypes", (0, ts_poet_1.code) `
|
|
838
|
+
const anyJsonValueTypes: readonly string[] = [
|
|
839
|
+
"google.protobuf.Any",
|
|
840
|
+
"google.protobuf.BoolValue",
|
|
841
|
+
"google.protobuf.BytesValue",
|
|
842
|
+
"google.protobuf.DoubleValue",
|
|
843
|
+
"google.protobuf.Duration",
|
|
844
|
+
"google.protobuf.FieldMask",
|
|
845
|
+
"google.protobuf.FloatValue",
|
|
846
|
+
"google.protobuf.Int32Value",
|
|
847
|
+
"google.protobuf.Int64Value",
|
|
848
|
+
"google.protobuf.ListValue",
|
|
849
|
+
"google.protobuf.StringValue",
|
|
850
|
+
"google.protobuf.Struct",
|
|
851
|
+
"google.protobuf.Timestamp",
|
|
852
|
+
"google.protobuf.UInt32Value",
|
|
853
|
+
"google.protobuf.UInt64Value",
|
|
854
|
+
"google.protobuf.Value",
|
|
855
|
+
];
|
|
856
|
+
`);
|
|
857
|
+
return { anyJsonValueTypes };
|
|
858
|
+
}
|
|
833
859
|
function makeComparisonUtils() {
|
|
834
860
|
const isObject = (0, ts_poet_1.conditionalOutput)("isObject", (0, ts_poet_1.code) `
|
|
835
861
|
function isObject(value: any): boolean {
|
|
@@ -1462,7 +1488,12 @@ function generateEncode(ctx, fullName, messageDesc) {
|
|
|
1462
1488
|
`);
|
|
1463
1489
|
}
|
|
1464
1490
|
else {
|
|
1465
|
-
|
|
1491
|
+
// A packed field with no elements must not be written, not even its tag and length.
|
|
1492
|
+
chunks.push((0, ts_poet_1.code) `
|
|
1493
|
+
if (${messageProperty}.length !== 0) {
|
|
1494
|
+
${listWriteSnippet}
|
|
1495
|
+
}
|
|
1496
|
+
`);
|
|
1466
1497
|
}
|
|
1467
1498
|
}
|
|
1468
1499
|
else {
|
|
@@ -1518,7 +1549,12 @@ function generateEncode(ctx, fullName, messageDesc) {
|
|
|
1518
1549
|
`);
|
|
1519
1550
|
}
|
|
1520
1551
|
else {
|
|
1521
|
-
|
|
1552
|
+
// A packed field with no elements must not be written, not even its tag and length.
|
|
1553
|
+
chunks.push((0, ts_poet_1.code) `
|
|
1554
|
+
if (${messageProperty}.length !== 0) {
|
|
1555
|
+
${listWriteSnippet}
|
|
1556
|
+
}
|
|
1557
|
+
`);
|
|
1522
1558
|
}
|
|
1523
1559
|
}
|
|
1524
1560
|
}
|
|
@@ -1829,6 +1865,9 @@ function generateExtension(ctx, message, extension) {
|
|
|
1829
1865
|
function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
|
|
1830
1866
|
const { options, utils, currentFile } = ctx;
|
|
1831
1867
|
const chunks = [];
|
|
1868
|
+
if (fullTypeName === "google.protobuf.Any" && useCanonicalAnyJson(options)) {
|
|
1869
|
+
return generateCanonicalAnyFromJson(ctx, fullName, messageDesc);
|
|
1870
|
+
}
|
|
1832
1871
|
// Handle Duration string format as a special case
|
|
1833
1872
|
if (fullTypeName === "google.protobuf.Duration" && ctx.options.useDuration === options_1.DurationOption.STRING) {
|
|
1834
1873
|
let parseSeconds;
|
|
@@ -2232,9 +2271,83 @@ function generateCanonicalToJson(fullName, fullProtobufTypeName, { useOptionals,
|
|
|
2232
2271
|
}
|
|
2233
2272
|
return undefined;
|
|
2234
2273
|
}
|
|
2274
|
+
/** Whether `google.protobuf.Any` gets its canonical `@type` JSON form, see the `anyType` option. */
|
|
2275
|
+
function useCanonicalAnyJson(options) {
|
|
2276
|
+
// Converting the packed message needs the type registry and its encode/decode methods. Without
|
|
2277
|
+
// them, Any keeps the `{ typeUrl, value }` form even though `@type` is the default.
|
|
2278
|
+
return (options.anyType === options_1.AnyTypeOption.AT_TYPE && options.outputTypeRegistry && options.outputEncodeMethods === true);
|
|
2279
|
+
}
|
|
2280
|
+
/** The `type_url` and `value` fields of `google.protobuf.Any`. */
|
|
2281
|
+
function anyFields(messageDesc) {
|
|
2282
|
+
const typeUrl = messageDesc.field.find((field) => field.number === 1);
|
|
2283
|
+
const value = messageDesc.field.find((field) => field.number === 2);
|
|
2284
|
+
return [typeUrl, value];
|
|
2285
|
+
}
|
|
2286
|
+
/**
|
|
2287
|
+
* The canonical JSON of an `Any` is the JSON of the packed message with an added
|
|
2288
|
+
* `"@type"`, or `{"@type", "value"}` for well-known types with their own JSON form.
|
|
2289
|
+
*/
|
|
2290
|
+
function generateCanonicalAnyToJson(ctx, fullName, messageDesc) {
|
|
2291
|
+
const { options, utils } = ctx;
|
|
2292
|
+
const messageTypeRegistry = (0, utils_1.impFile)(options, "messageTypeRegistry@./typeRegistry");
|
|
2293
|
+
const [typeUrlField, valueField] = anyFields(messageDesc);
|
|
2294
|
+
const typeUrl = (0, utils_1.getPropertyAccessor)("message", (0, utils_1.getFieldName)(typeUrlField, options));
|
|
2295
|
+
const value = (0, utils_1.getPropertyAccessor)("message", (0, utils_1.getFieldName)(valueField, options));
|
|
2296
|
+
return (0, ts_poet_1.code) `
|
|
2297
|
+
toJSON(message: ${fullName}): unknown {
|
|
2298
|
+
const typeUrl = ${typeUrl} ?? "";
|
|
2299
|
+
if (typeUrl === "") {
|
|
2300
|
+
return {};
|
|
2301
|
+
}
|
|
2302
|
+
const typeName = typeUrl.slice(typeUrl.lastIndexOf("/") + 1);
|
|
2303
|
+
const type = ${messageTypeRegistry}.get(typeName);
|
|
2304
|
+
if (type === undefined) {
|
|
2305
|
+
throw new ${utils.globalThis}.Error(\`Cannot convert google.protobuf.Any to JSON: unknown type \${typeName}\`);
|
|
2306
|
+
}
|
|
2307
|
+
const json = type.toJSON(type.decode(${value} ?? new Uint8Array(0)));
|
|
2308
|
+
return ${utils.anyJsonValueTypes}.includes(typeName)
|
|
2309
|
+
? { "@type": typeUrl, value: json }
|
|
2310
|
+
: { "@type": typeUrl, ...(json as object) };
|
|
2311
|
+
}
|
|
2312
|
+
`;
|
|
2313
|
+
}
|
|
2314
|
+
/** The inverse of {@link generateCanonicalAnyToJson}. */
|
|
2315
|
+
function generateCanonicalAnyFromJson(ctx, fullName, messageDesc) {
|
|
2316
|
+
const { options, utils } = ctx;
|
|
2317
|
+
const messageTypeRegistry = (0, utils_1.impFile)(options, "messageTypeRegistry@./typeRegistry");
|
|
2318
|
+
const [typeUrlField, valueField] = anyFields(messageDesc);
|
|
2319
|
+
const typeUrlKey = (0, utils_1.safeAccessor)((0, utils_1.getFieldName)(typeUrlField, options));
|
|
2320
|
+
const valueKey = (0, utils_1.safeAccessor)((0, utils_1.getFieldName)(valueField, options));
|
|
2321
|
+
const typeField = (0, options_1.addTypeToMessages)(options) ? (0, ts_poet_1.code) `$type: ${fullName}.$type,` : "";
|
|
2322
|
+
const bytes = options.env === options_1.EnvOption.NODE ? (0, ts_poet_1.code) `Buffer.from(bytes)` : (0, ts_poet_1.code) `bytes`;
|
|
2323
|
+
return (0, ts_poet_1.code) `
|
|
2324
|
+
fromJSON(object: any): ${fullName} {
|
|
2325
|
+
const typeUrl = ${utils.isSet}(object?.["@type"]) ? ${utils.globalThis}.String(object["@type"]) : "";
|
|
2326
|
+
if (typeUrl === "") {
|
|
2327
|
+
return { ${typeField} ${typeUrlKey}: ${(0, types_1.defaultValue)(ctx, typeUrlField)}, ${valueKey}: ${(0, types_1.defaultValue)(ctx, valueField)} };
|
|
2328
|
+
}
|
|
2329
|
+
const typeName = typeUrl.slice(typeUrl.lastIndexOf("/") + 1);
|
|
2330
|
+
const type = ${messageTypeRegistry}.get(typeName);
|
|
2331
|
+
if (type === undefined) {
|
|
2332
|
+
throw new ${utils.globalThis}.Error(\`Cannot convert JSON to google.protobuf.Any: unknown type \${typeName}\`);
|
|
2333
|
+
}
|
|
2334
|
+
let json = object.value;
|
|
2335
|
+
if (!${utils.anyJsonValueTypes}.includes(typeName)) {
|
|
2336
|
+
json = { ...object };
|
|
2337
|
+
delete json["@type"];
|
|
2338
|
+
}
|
|
2339
|
+
const bytes = type.encode(type.fromJSON(json)).finish();
|
|
2340
|
+
return { ${typeField} ${typeUrlKey}: typeUrl, ${valueKey}: ${bytes} };
|
|
2341
|
+
}
|
|
2342
|
+
`;
|
|
2343
|
+
}
|
|
2235
2344
|
function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
|
|
2236
2345
|
const { options, utils, typeMap } = ctx;
|
|
2237
2346
|
const chunks = [];
|
|
2347
|
+
if (fullProtobufTypeName === "google.protobuf.Any" && useCanonicalAnyJson(options)) {
|
|
2348
|
+
chunks.push(generateCanonicalAnyToJson(ctx, fullName, messageDesc));
|
|
2349
|
+
return (0, ts_poet_1.joinCode)(chunks, { on: "\n" });
|
|
2350
|
+
}
|
|
2238
2351
|
const canonicalToJson = generateCanonicalToJson(fullName, fullProtobufTypeName, options);
|
|
2239
2352
|
if (canonicalToJson) {
|
|
2240
2353
|
chunks.push(canonicalToJson);
|
|
@@ -2623,6 +2736,11 @@ function generateFromPartial(ctx, fullName, messageDesc) {
|
|
|
2623
2736
|
`);
|
|
2624
2737
|
currentSwitchTarget = oneofNameWithObject;
|
|
2625
2738
|
}
|
|
2739
|
+
else if ((0, types_1.isAnyValueType)(field)) {
|
|
2740
|
+
// null is a valid google.protobuf.Value (NullValue), so only an absent value gets the fallback.
|
|
2741
|
+
const fallback = (0, types_1.isWithinOneOf)(field) || noDefaultValue ? "undefined" : (0, types_1.defaultValue)(ctx, field);
|
|
2742
|
+
chunks.push((0, ts_poet_1.code) `${messageProperty} = ${objectProperty} === undefined ? ${fallback} : ${objectProperty};`);
|
|
2743
|
+
}
|
|
2626
2744
|
else if (readSnippet(`x`).toCodeString([]) == "x") {
|
|
2627
2745
|
// An optimized case of the else below that works when `readSnippet` returns the plain input
|
|
2628
2746
|
const fallback = (0, types_1.isWithinOneOf)(field) || noDefaultValue ? "undefined" : (0, types_1.defaultValue)(ctx, field);
|
package/build/src/options.d.ts
CHANGED
|
@@ -20,6 +20,11 @@ export declare enum DurationOption {
|
|
|
20
20
|
DURATION = "duration",
|
|
21
21
|
STRING = "string"
|
|
22
22
|
}
|
|
23
|
+
export declare enum AnyTypeOption {
|
|
24
|
+
/** @deprecated Kept for existing users of the `{ typeUrl, value }` JSON form; may be removed in the future. */
|
|
25
|
+
TYPE_URL = "typeUrl",
|
|
26
|
+
AT_TYPE = "@type"
|
|
27
|
+
}
|
|
23
28
|
export declare enum EnvOption {
|
|
24
29
|
NODE = "node",
|
|
25
30
|
BROWSER = "browser",
|
|
@@ -75,6 +80,7 @@ export type Options = {
|
|
|
75
80
|
addGrpcMetadata: boolean;
|
|
76
81
|
metadataType: string | undefined;
|
|
77
82
|
addNestjsRestParameter: boolean;
|
|
83
|
+
useNestjsFqnServiceName: boolean;
|
|
78
84
|
returnObservable: boolean;
|
|
79
85
|
lowerCaseServiceMethods: boolean;
|
|
80
86
|
nestJs: boolean;
|
|
@@ -116,6 +122,7 @@ export type Options = {
|
|
|
116
122
|
typePrefix: string;
|
|
117
123
|
typeSuffix: string;
|
|
118
124
|
useDuration: DurationOption;
|
|
125
|
+
anyType: AnyTypeOption;
|
|
119
126
|
};
|
|
120
127
|
export declare function defaultOptions(): Options;
|
|
121
128
|
export declare function optionsFromParameter(parameter: string | undefined): Options;
|
package/build/src/options.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.OutputSchemaOption = exports.ServiceOption = exports.OneofOption = exports.EnvOption = exports.DurationOption = exports.JsonTimestampOption = exports.DateOption = exports.LongOption = void 0;
|
|
3
|
+
exports.OutputSchemaOption = exports.ServiceOption = exports.OneofOption = exports.EnvOption = exports.AnyTypeOption = exports.DurationOption = exports.JsonTimestampOption = exports.DateOption = exports.LongOption = void 0;
|
|
4
4
|
exports.defaultOptions = defaultOptions;
|
|
5
5
|
exports.optionsFromParameter = optionsFromParameter;
|
|
6
6
|
exports.getTsPoetOpts = getTsPoetOpts;
|
|
@@ -30,6 +30,12 @@ var DurationOption;
|
|
|
30
30
|
DurationOption["DURATION"] = "duration";
|
|
31
31
|
DurationOption["STRING"] = "string";
|
|
32
32
|
})(DurationOption || (exports.DurationOption = DurationOption = {}));
|
|
33
|
+
var AnyTypeOption;
|
|
34
|
+
(function (AnyTypeOption) {
|
|
35
|
+
/** @deprecated Kept for existing users of the `{ typeUrl, value }` JSON form; may be removed in the future. */
|
|
36
|
+
AnyTypeOption["TYPE_URL"] = "typeUrl";
|
|
37
|
+
AnyTypeOption["AT_TYPE"] = "@type";
|
|
38
|
+
})(AnyTypeOption || (exports.AnyTypeOption = AnyTypeOption = {}));
|
|
33
39
|
var EnvOption;
|
|
34
40
|
(function (EnvOption) {
|
|
35
41
|
EnvOption["NODE"] = "node";
|
|
@@ -92,6 +98,7 @@ function defaultOptions() {
|
|
|
92
98
|
addGrpcMetadata: false,
|
|
93
99
|
metadataType: undefined,
|
|
94
100
|
addNestjsRestParameter: false,
|
|
101
|
+
useNestjsFqnServiceName: false,
|
|
95
102
|
nestJs: false,
|
|
96
103
|
env: EnvOption.BOTH,
|
|
97
104
|
unrecognizedEnum: true,
|
|
@@ -129,6 +136,7 @@ function defaultOptions() {
|
|
|
129
136
|
typePrefix: "",
|
|
130
137
|
typeSuffix: "",
|
|
131
138
|
useDuration: DurationOption.DURATION,
|
|
139
|
+
anyType: AnyTypeOption.AT_TYPE,
|
|
132
140
|
};
|
|
133
141
|
}
|
|
134
142
|
const nestJsOptions = {
|
|
@@ -231,6 +239,10 @@ function optionsFromParameter(parameter) {
|
|
|
231
239
|
if (options.nestJs) {
|
|
232
240
|
options.initializeFieldsAsUndefined = false;
|
|
233
241
|
}
|
|
242
|
+
else {
|
|
243
|
+
// useNestjsFqnServiceName requires nestJs=true
|
|
244
|
+
options.useNestjsFqnServiceName = false;
|
|
245
|
+
}
|
|
234
246
|
if (options.outputIndex) {
|
|
235
247
|
options.exportCommonSymbols = false;
|
|
236
248
|
}
|
package/build/src/schema.js
CHANGED
|
@@ -23,11 +23,17 @@ function generateSchema(ctx, fileDesc, sourceInfo) {
|
|
|
23
23
|
const outputFileDescriptor = !outputSchemaOptions.includes(options_1.OutputSchemaOption.NO_FILE_DESCRIPTOR);
|
|
24
24
|
const outputAsConst = outputSchemaOptions.includes(options_1.OutputSchemaOption.CONST);
|
|
25
25
|
chunks.push((0, ts_poet_1.code) `
|
|
26
|
+
type ProtoMetaEnumOptions = {
|
|
27
|
+
options?: { [key: string]: any };
|
|
28
|
+
values?: { [key: string]: { [key: string]: any } };
|
|
29
|
+
};
|
|
30
|
+
|
|
26
31
|
type ProtoMetaMessageOptions = {
|
|
27
32
|
options?: { [key: string]: any };
|
|
28
33
|
fields?: { [key: string]: { [key: string]: any } };
|
|
29
34
|
oneof?: { [key: string]: { [key: string]: any } };
|
|
30
35
|
nested?: { [key: string]: ProtoMetaMessageOptions };
|
|
36
|
+
enums?: { [key: string]: ProtoMetaEnumOptions };
|
|
31
37
|
};
|
|
32
38
|
|
|
33
39
|
export interface ProtoMetadata {
|
|
@@ -45,10 +51,7 @@ function generateSchema(ctx, fileDesc, sourceInfo) {
|
|
|
45
51
|
[key: string]: ProtoMetaMessageOptions;
|
|
46
52
|
};
|
|
47
53
|
enums?: {
|
|
48
|
-
[key: string]:
|
|
49
|
-
options?: { [key: string]: any };
|
|
50
|
-
values?: { [key: string]: { [key: string]: any } };
|
|
51
|
-
};
|
|
54
|
+
[key: string]: ProtoMetaEnumOptions;
|
|
52
55
|
};
|
|
53
56
|
};
|
|
54
57
|
}
|
|
@@ -119,28 +122,9 @@ function generateSchema(ctx, fileDesc, sourceInfo) {
|
|
|
119
122
|
});
|
|
120
123
|
const enumsOptions = [];
|
|
121
124
|
(fileDesc.enumType || []).forEach((Enum) => {
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const valueOptions = encodedOptionsToOptions(ctx, ".google.protobuf.EnumValueOptions", value.options._unknownFields);
|
|
126
|
-
delete value.options._unknownFields;
|
|
127
|
-
if (valueOptions) {
|
|
128
|
-
valuesOptions.push((0, ts_poet_1.code) `'${value.name}': ${valueOptions}`);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
let enumOptions;
|
|
133
|
-
if (Enum.options) {
|
|
134
|
-
enumOptions = encodedOptionsToOptions(ctx, ".google.protobuf.EnumOptions", Enum.options._unknownFields);
|
|
135
|
-
delete Enum.options._unknownFields;
|
|
136
|
-
}
|
|
137
|
-
if (valuesOptions.length > 0 || enumOptions) {
|
|
138
|
-
enumsOptions.push((0, ts_poet_1.code) `
|
|
139
|
-
'${Enum.name}': {
|
|
140
|
-
${enumOptions ? (0, ts_poet_1.code) `options: ${enumOptions},` : ""}
|
|
141
|
-
values: {${(0, ts_poet_1.joinCode)(valuesOptions, { on: "," })}}
|
|
142
|
-
}
|
|
143
|
-
`);
|
|
125
|
+
const resolvedEnum = resolveEnumOptions(ctx, Enum);
|
|
126
|
+
if (resolvedEnum) {
|
|
127
|
+
enumsOptions.push(resolvedEnum);
|
|
144
128
|
}
|
|
145
129
|
});
|
|
146
130
|
chunks.push((0, ts_poet_1.code) `
|
|
@@ -247,18 +231,55 @@ function resolveMessageOptions(ctx, message) {
|
|
|
247
231
|
}
|
|
248
232
|
});
|
|
249
233
|
}
|
|
234
|
+
const enumsOptions = [];
|
|
235
|
+
(message.enumType || []).forEach((Enum) => {
|
|
236
|
+
const resolvedEnum = resolveEnumOptions(ctx, Enum);
|
|
237
|
+
if (resolvedEnum) {
|
|
238
|
+
enumsOptions.push(resolvedEnum);
|
|
239
|
+
}
|
|
240
|
+
});
|
|
250
241
|
let messageOptions;
|
|
251
242
|
if (message.options) {
|
|
252
243
|
messageOptions = encodedOptionsToOptions(ctx, ".google.protobuf.MessageOptions", message.options._unknownFields);
|
|
253
244
|
delete message.options._unknownFields;
|
|
254
245
|
}
|
|
255
|
-
if (fieldsOptions.length > 0 ||
|
|
246
|
+
if (fieldsOptions.length > 0 ||
|
|
247
|
+
oneOfsOptions.length > 0 ||
|
|
248
|
+
nestedOptions.length > 0 ||
|
|
249
|
+
enumsOptions.length > 0 ||
|
|
250
|
+
messageOptions) {
|
|
256
251
|
return (0, ts_poet_1.code) `
|
|
257
252
|
'${message.name}': {
|
|
258
253
|
${messageOptions ? (0, ts_poet_1.code) `options: ${messageOptions},` : ""}
|
|
259
254
|
${fieldsOptions.length > 0 ? (0, ts_poet_1.code) `fields: {${(0, ts_poet_1.joinCode)(fieldsOptions, { on: "," })}},` : ""}
|
|
260
255
|
${oneOfsOptions.length > 0 ? (0, ts_poet_1.code) `oneof: {${(0, ts_poet_1.joinCode)(oneOfsOptions, { on: "," })}},` : ""}
|
|
261
256
|
${nestedOptions.length > 0 ? (0, ts_poet_1.code) `nested: {${(0, ts_poet_1.joinCode)(nestedOptions, { on: "," })}},` : ""}
|
|
257
|
+
${enumsOptions.length > 0 ? (0, ts_poet_1.code) `enums: {${(0, ts_poet_1.joinCode)(enumsOptions, { on: "," })}},` : ""}
|
|
258
|
+
}
|
|
259
|
+
`;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function resolveEnumOptions(ctx, Enum) {
|
|
263
|
+
const valuesOptions = [];
|
|
264
|
+
Enum.value.forEach((value) => {
|
|
265
|
+
if (value.options) {
|
|
266
|
+
const valueOptions = encodedOptionsToOptions(ctx, ".google.protobuf.EnumValueOptions", value.options._unknownFields);
|
|
267
|
+
delete value.options._unknownFields;
|
|
268
|
+
if (valueOptions) {
|
|
269
|
+
valuesOptions.push((0, ts_poet_1.code) `'${value.name}': ${valueOptions}`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
let enumOptions;
|
|
274
|
+
if (Enum.options) {
|
|
275
|
+
enumOptions = encodedOptionsToOptions(ctx, ".google.protobuf.EnumOptions", Enum.options._unknownFields);
|
|
276
|
+
delete Enum.options._unknownFields;
|
|
277
|
+
}
|
|
278
|
+
if (valuesOptions.length > 0 || enumOptions) {
|
|
279
|
+
return (0, ts_poet_1.code) `
|
|
280
|
+
'${Enum.name}': {
|
|
281
|
+
${enumOptions ? (0, ts_poet_1.code) `options: ${enumOptions},` : ""}
|
|
282
|
+
values: {${(0, ts_poet_1.joinCode)(valuesOptions, { on: "," })}}
|
|
262
283
|
}
|
|
263
284
|
`;
|
|
264
285
|
}
|