ts-proto 2.18.6 → 2.20.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 CHANGED
@@ -443,6 +443,12 @@ With `--ts_proto_opt=protoJsonFormat=false`, strict proto3 compliance is disable
443
443
 
444
444
  - With `--ts_proto_opt=outputPartialMethods=false`, the `Message.fromPartial` and `Message.create` methods for accepting partially-formed objects/object literals will not be output.
445
445
 
446
+ - With `--ts_proto_opt=outputStandaloneFunctions=true`, the message methods are output as standalone functions instead of members of a `Message` const, e.g. `Message.encode` becomes `messageEncode` and `Foo_Bar.fromJSON` becomes `foo_BarFromJSON`, following the enum functions.
447
+
448
+ This is useful if you want bundlers to tree-shake the functions you don't use.
449
+
450
+ This can't be combined with `outputTypeRegistry=true`, `outputTypeAnnotations=static-only`, `outputServices=generic-definitions`, `nestJs=true` or `useMongoObjectId=true`. `outputSchema` leaves messages out of its `references`, and files mapped with `M` options need to be generated with this option as well.
451
+
446
452
  - With `--ts_proto_opt=stringEnums=true`, the generated enum types will be string-based instead of int-based.
447
453
 
448
454
  This is useful if you want "only types" and are using a gRPC REST Gateway configured to serialize enums as strings.
@@ -479,6 +485,12 @@ With `--ts_proto_opt=protoJsonFormat=false`, strict proto3 compliance is disable
479
485
 
480
486
  Note that `addGrpcMetadata`, `addNestjsRestParameter`, `returnObservable` and `useNestjsFqnServiceName` will still be false.
481
487
 
488
+ - With `--ts_proto_opt=nestJs=client` or `--ts_proto_opt=nestJs=server`, only the client-side or server-side NestJS service output will be generated, with the same changed defaults as `nestJs=true`.
489
+
490
+ With `nestJs=client`, only the `FooServiceClient` interface is generated, i.e. there is no `FooServiceController` interface or `@FooServiceControllerMethods()` decorator, so the output doesn't import `@nestjs/microservices`. With `nestJs=server`, only the controller interface and decorator are generated. The message types and the `FOO_PACKAGE_NAME`/`FOO_SERVICE_NAME` consts are generated in both cases.
491
+
492
+ `nestJs=client,nestJs=server` is the same as `nestJs=true`.
493
+
482
494
  - 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.
483
495
 
484
496
  - With `--ts_proto_opt=useMongoObjectId=true`, fields of a type called ObjectId where the message is constructed to have on field called value that is a string will be mapped to type `mongodb.ObjectId` in the generated types. This will require your project to install the mongodb npm package. See [ObjectId](#objectid) for more details.
@@ -5,14 +5,13 @@ exports.generateDecoder = generateDecoder;
5
5
  const ts_poet_1 = require("ts-poet");
6
6
  const types_1 = require("./types");
7
7
  const options_1 = require("./options");
8
- const utils_1 = require("./utils");
9
8
  function generateEncoder(ctx, typeName) {
10
9
  const name = (0, types_1.wrapperTypeName)(typeName);
10
+ const encode = (0, types_1.getMessageMethod)(ctx, typeName, "encode");
11
11
  if (!name) {
12
- return (0, ts_poet_1.code) `${(0, types_1.messageToTypeName)(ctx, typeName, { keepValueType: true })}.encode(value).finish()`;
12
+ return (0, ts_poet_1.code) `${encode}(value).finish()`;
13
13
  }
14
14
  if (name == "Timestamp") {
15
- const TimestampValue = (0, utils_1.impProto)(ctx.options, "google/protobuf/timestamp", (0, utils_1.wrapTypeName)(ctx.options, name));
16
15
  let value = (0, ts_poet_1.code) `value`;
17
16
  if (ctx.options.useDate === options_1.DateOption.DATE ||
18
17
  ctx.options.useDate === options_1.DateOption.STRING ||
@@ -20,48 +19,43 @@ function generateEncoder(ctx, typeName) {
20
19
  ctx.options.useDate === options_1.DateOption.TEMPORAL) {
21
20
  value = (0, ts_poet_1.code) `${ctx.utils.toTimestamp}(${value})`;
22
21
  }
23
- return (0, ts_poet_1.code) `${TimestampValue}.encode(${value}).finish()`;
22
+ return (0, ts_poet_1.code) `${encode}(${value}).finish()`;
24
23
  }
25
24
  if (name == "Struct" || name == "Value") {
26
- const StructType = (0, utils_1.impProto)(ctx.options, "google/protobuf/struct", (0, utils_1.wrapTypeName)(ctx.options, name));
27
- return (0, ts_poet_1.code) `${StructType}.encode(${StructType}.wrap(value)).finish()`;
25
+ return (0, ts_poet_1.code) `${encode}(${(0, types_1.getMessageMethod)(ctx, typeName, "wrap")}(value)).finish()`;
28
26
  }
29
27
  if (name == "ListValue") {
30
- const ListValueType = (0, utils_1.impProto)(ctx.options, "google/protobuf/struct", (0, utils_1.wrapTypeName)(ctx.options, name));
31
- return (0, ts_poet_1.code) `${ListValueType}.encode({values: value ?? []}).finish()`;
28
+ return (0, ts_poet_1.code) `${encode}({values: value ?? []}).finish()`;
32
29
  }
33
- const TypeValue = (0, utils_1.impProto)(ctx.options, "google/protobuf/wrappers", (0, utils_1.wrapTypeName)(ctx.options, name));
34
30
  switch (name) {
35
31
  case "StringValue":
36
- return (0, ts_poet_1.code) `${TypeValue}.encode({value: value ?? ""}).finish()`;
32
+ return (0, ts_poet_1.code) `${encode}({value: value ?? ""}).finish()`;
37
33
  case "Int32Value":
38
34
  case "UInt32Value":
39
35
  case "DoubleValue":
40
36
  case "FloatValue":
41
- return (0, ts_poet_1.code) `${TypeValue}.encode({value: value ?? 0}).finish()`;
37
+ return (0, ts_poet_1.code) `${encode}({value: value ?? 0}).finish()`;
42
38
  case "Int64Value":
43
39
  case "UInt64Value":
44
40
  if (ctx.options.forceLong === options_1.LongOption.LONG) {
45
- return (0, ts_poet_1.code) `${TypeValue}.encode({value: value ? value.toNumber(): 0}).finish()`;
41
+ return (0, ts_poet_1.code) `${encode}({value: value ? value.toNumber(): 0}).finish()`;
46
42
  }
47
- return (0, ts_poet_1.code) `${TypeValue}.encode({value: value ?? 0 }).finish()`;
43
+ return (0, ts_poet_1.code) `${encode}({value: value ?? 0 }).finish()`;
48
44
  case "BoolValue":
49
- return (0, ts_poet_1.code) `${TypeValue}.encode({value: value ?? false}).finish()`;
45
+ return (0, ts_poet_1.code) `${encode}({value: value ?? false}).finish()`;
50
46
  case "BytesValue":
51
- return (0, ts_poet_1.code) `${TypeValue}.encode({value: value ?? new Uint8Array(0)}).finish()`;
47
+ return (0, ts_poet_1.code) `${encode}({value: value ?? new Uint8Array(0)}).finish()`;
52
48
  }
53
49
  throw new Error(`unknown wrapper type: ${name}`);
54
50
  }
55
51
  function generateDecoder(ctx, typeName) {
56
52
  const { options } = ctx;
57
53
  let name = (0, types_1.wrapperTypeName)(typeName);
54
+ const decoder = (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, typeName, "decode")}(value)`;
58
55
  if (!name) {
59
- return (0, ts_poet_1.code) `${(0, types_1.messageToTypeName)(ctx, typeName, { keepValueType: true })}.decode(value)`;
56
+ return decoder;
60
57
  }
61
- let TypeValue;
62
58
  if (name == "Timestamp") {
63
- TypeValue = (0, utils_1.impProto)(ctx.options, "google/protobuf/timestamp", (0, utils_1.wrapTypeName)(ctx.options, name));
64
- const decoder = (0, ts_poet_1.code) `${TypeValue}.decode(value)`;
65
59
  if (ctx.options.useDate === options_1.DateOption.DATE ||
66
60
  ctx.options.useDate === options_1.DateOption.STRING ||
67
61
  ctx.options.useDate === options_1.DateOption.STRING_NANO ||
@@ -71,9 +65,7 @@ function generateDecoder(ctx, typeName) {
71
65
  return decoder;
72
66
  }
73
67
  if (name == "Struct" || name == "ListValue" || name == "Value") {
74
- TypeValue = (0, utils_1.impProto)(ctx.options, "google/protobuf/struct", (0, utils_1.wrapTypeName)(ctx.options, name));
75
- return (0, ts_poet_1.code) `${TypeValue}.unwrap(${TypeValue}.decode(value))`;
68
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, typeName, "unwrap")}(${decoder})`;
76
69
  }
77
- TypeValue = (0, utils_1.impProto)(ctx.options, "google/protobuf/wrappers", (0, utils_1.wrapTypeName)(ctx.options, name));
78
- return (0, ts_poet_1.code) `${TypeValue}.decode(value).value`;
70
+ return (0, ts_poet_1.code) `${decoder}.value`;
79
71
  }
@@ -1,6 +1,6 @@
1
1
  import { Code } from "ts-poet";
2
- import { Utils } from "./main";
2
+ import { Context } from "./context";
3
3
  /** Creates a function to transform a message Source to a Uint8Array Source. */
4
- export declare function generateEncodeTransform(utils: Utils, fullName: string): Code;
4
+ export declare function generateEncodeTransform(ctx: Context, fullName: string): Code;
5
5
  /** Creates a function to transform a Uint8Array Source to a message Source. */
6
- export declare function generateDecodeTransform(utils: Utils, fullName: string): Code;
6
+ export declare function generateDecodeTransform(ctx: Context, fullName: string): Code;
@@ -3,41 +3,42 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateEncodeTransform = generateEncodeTransform;
4
4
  exports.generateDecodeTransform = generateDecodeTransform;
5
5
  const ts_poet_1 = require("ts-poet");
6
+ const utils_1 = require("./utils");
6
7
  /** Creates a function to transform a message Source to a Uint8Array Source. */
7
- function generateEncodeTransform(utils, fullName) {
8
+ function generateEncodeTransform(ctx, fullName) {
8
9
  return (0, ts_poet_1.code) `
9
10
  // encodeTransform encodes a source of message objects.
10
11
  // Transform<${fullName}, Uint8Array>
11
- async *encodeTransform(
12
+ ${(0, utils_1.messageMethodHead)(ctx.options, fullName, "encodeTransform", true)}(
12
13
  source: AsyncIterable<${fullName} | ${fullName}[]> | Iterable<${fullName} | ${fullName}[]>
13
14
  ): AsyncIterable<Uint8Array> {
14
15
  for await (const pkt of source) {
15
- if (${utils.globalThis}.Array.isArray(pkt)) {
16
+ if (${ctx.utils.globalThis}.Array.isArray(pkt)) {
16
17
  for (const p of (pkt as any)) {
17
- yield* [${fullName}.encode(p).finish()]
18
+ yield* [${(0, utils_1.localMessageMethod)(ctx.options, fullName, "encode")}(p).finish()]
18
19
  }
19
20
  } else {
20
- yield* [${fullName}.encode(pkt as any).finish()]
21
+ yield* [${(0, utils_1.localMessageMethod)(ctx.options, fullName, "encode")}(pkt as any).finish()]
21
22
  }
22
23
  }
23
24
  }
24
25
  `;
25
26
  }
26
27
  /** Creates a function to transform a Uint8Array Source to a message Source. */
27
- function generateDecodeTransform(utils, fullName) {
28
+ function generateDecodeTransform(ctx, fullName) {
28
29
  return (0, ts_poet_1.code) `
29
30
  // decodeTransform decodes a source of encoded messages.
30
31
  // Transform<Uint8Array, ${fullName}>
31
- async *decodeTransform(
32
+ ${(0, utils_1.messageMethodHead)(ctx.options, fullName, "decodeTransform", true)}(
32
33
  source: AsyncIterable<Uint8Array | Uint8Array[]> | Iterable<Uint8Array | Uint8Array[]>
33
34
  ): AsyncIterable<${fullName}> {
34
35
  for await (const pkt of source) {
35
- if (${utils.globalThis}.Array.isArray(pkt)) {
36
+ if (${ctx.utils.globalThis}.Array.isArray(pkt)) {
36
37
  for (const p of (pkt as any)) {
37
- yield* [${fullName}.decode(p)]
38
+ yield* [${(0, utils_1.localMessageMethod)(ctx.options, fullName, "decode")}(p)]
38
39
  }
39
40
  } else {
40
- yield* [${fullName}.decode(pkt as any)]
41
+ yield* [${(0, utils_1.localMessageMethod)(ctx.options, fullName, "decode")}(pkt as any)]
41
42
  }
42
43
  }
43
44
  }
@@ -43,7 +43,6 @@ function generateRpcMethod(ctx, serviceDesc, methodDesc) {
43
43
  (0, utils_1.assertInstanceOf)(methodDesc, utils_1.FormattedMethodDescriptor);
44
44
  const { options } = ctx;
45
45
  const { useAbortSignal } = options;
46
- const requestMessage = (0, types_1.requestType)(ctx, methodDesc, false);
47
46
  const inputType = (0, types_1.requestType)(ctx, methodDesc, true);
48
47
  const returns = (0, types_1.responsePromiseOrObservable)(ctx, methodDesc);
49
48
  if (methodDesc.clientStreaming) {
@@ -66,7 +65,7 @@ function generateRpcMethod(ctx, serviceDesc, methodDesc) {
66
65
  ): ${returns} {
67
66
  return this.rpc.${method}(
68
67
  ${methodDescName(serviceDesc, methodDesc)},
69
- ${requestMessage}.fromPartial(request),
68
+ ${(0, types_1.getMessageMethod)(ctx, methodDesc.inputType, "fromPartial")}(request),
70
69
  metadata,
71
70
  ${useAbortSignal ? "abortSignal," : ""}
72
71
  );
@@ -89,8 +88,6 @@ function generateGrpcServiceDesc(fileDesc, serviceDesc) {
89
88
  * implementation.
90
89
  */
91
90
  function generateGrpcMethodDesc(ctx, serviceDesc, methodDesc) {
92
- const inputType = (0, types_1.requestType)(ctx, methodDesc);
93
- const outputType = (0, types_1.responseType)(ctx, methodDesc);
94
91
  // grpc-web expects this to be a class, but the ts-proto messages are just interfaces.
95
92
  //
96
93
  // That said, grpc-web's runtime doesn't really use this (at least so far for what ts-proto
@@ -104,7 +101,7 @@ function generateGrpcMethodDesc(ctx, serviceDesc, methodDesc) {
104
101
  // This makes our data look enough like an object/class that grpc-web works just fine.
105
102
  const requestFn = (0, ts_poet_1.code) `{
106
103
  serializeBinary() {
107
- return ${inputType}.encode(this).finish();
104
+ return ${(0, types_1.getMessageMethod)(ctx, methodDesc.inputType, "encode")}(this).finish();
108
105
  },
109
106
  }`;
110
107
  // grpc-web also expects this to be a class, but with a static `deserializeBinary` method to
@@ -113,7 +110,7 @@ function generateGrpcMethodDesc(ctx, serviceDesc, methodDesc) {
113
110
  // we want/what grpc-web's runtime needs.
114
111
  const responseFn = (0, ts_poet_1.code) `{
115
112
  deserializeBinary(data: Uint8Array) {
116
- const value = ${outputType}.decode(data);
113
+ const value = ${(0, types_1.getMessageMethod)(ctx, methodDesc.outputType, "decode")}(data);
117
114
  return {
118
115
  ...value,
119
116
  toObject() { return value; },
@@ -78,9 +78,7 @@ function generateRegularRpcMethod(ctx, methodDesc) {
78
78
  (0, utils_1.assertInstanceOf)(methodDesc, utils_1.FormattedMethodDescriptor);
79
79
  const { options } = ctx;
80
80
  const BinaryReader = (0, ts_poet_1.imp)("BinaryReader@@bufbuild/protobuf/wire");
81
- const rawInputType = (0, types_1.rawRequestType)(ctx, methodDesc, { keepValueType: true });
82
81
  const inputType = (0, types_1.requestType)(ctx, methodDesc);
83
- const rawOutputType = (0, types_1.responseType)(ctx, methodDesc, { keepValueType: true });
84
82
  const metadataType = options.metadataType ? (0, ts_poet_1.imp)(options.metadataType) : (0, ts_poet_1.imp)("t:Metadata@@grpc/grpc-js");
85
83
  const params = [
86
84
  ...(options.context ? [(0, ts_poet_1.code) `ctx: Context`] : []),
@@ -100,7 +98,7 @@ function generateRegularRpcMethod(ctx, methodDesc) {
100
98
  return Promise.reject(error);
101
99
  `;
102
100
  }
103
- let encode = (0, ts_poet_1.code) `${rawInputType}.encode(request).finish()`;
101
+ let encode = (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, methodDesc.inputType, "encode")}(request).finish()`;
104
102
  let beforeRequest;
105
103
  if (options.rpcBeforeRequest && !methodDesc.clientStreaming) {
106
104
  beforeRequest = generateBeforeRequest(methodDesc.name);
@@ -108,10 +106,10 @@ function generateRegularRpcMethod(ctx, methodDesc) {
108
106
  else if (methodDesc.clientStreaming && options.rpcBeforeRequest) {
109
107
  encode = (0, ts_poet_1.code) `{const encodedRequest = ${encode}; ${generateBeforeRequest(methodDesc.name, "encodedRequest")}; return encodedRequest}`;
110
108
  }
111
- let decode = (0, ts_poet_1.code) `${rawOutputType}.decode(new ${BinaryReader}(data))`;
109
+ let decode = (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, methodDesc.outputType, "decode")}(new ${BinaryReader}(data))`;
112
110
  if (options.rpcAfterResponse) {
113
111
  decode = (0, ts_poet_1.code) `
114
- const response = ${rawOutputType}.decode(new ${BinaryReader}(data));
112
+ const response = ${decode};
115
113
  if (this.rpc.afterResponse) {
116
114
  this.rpc.afterResponse(this.service, "${methodDesc.name}", response);
117
115
  }
@@ -123,7 +121,7 @@ function generateRegularRpcMethod(ctx, methodDesc) {
123
121
  // }
124
122
  if (methodDesc.clientStreaming) {
125
123
  if (options.useAsyncIterable) {
126
- encode = (0, ts_poet_1.code) `${rawInputType}.encodeTransform(request)`;
124
+ encode = (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, methodDesc.inputType, "encodeTransform")}(request)`;
127
125
  }
128
126
  else {
129
127
  encode = (0, ts_poet_1.code) `request.pipe(${(0, ts_poet_1.imp)("map@rxjs/operators")}(request => ${encode}))`;
@@ -175,11 +173,10 @@ function generateBeforeRequest(methodName, requestVariableName = "request") {
175
173
  }
176
174
  function createDefaultServiceReturn(ctx, methodDesc, decode, errorHandler) {
177
175
  const { options } = ctx;
178
- const rawOutputType = (0, types_1.responseType)(ctx, methodDesc, { keepValueType: true });
179
176
  const returnStatement = (0, utils_1.arrowFunction)("data", decode, !options.rpcAfterResponse);
180
177
  if (options.returnObservable || methodDesc.serverStreaming) {
181
178
  if (options.useAsyncIterable) {
182
- return (0, ts_poet_1.code) `${rawOutputType}.decodeTransform(result)`;
179
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, methodDesc.outputType, "decodeTransform")}(result)`;
183
180
  }
184
181
  else {
185
182
  if (errorHandler) {
@@ -302,9 +299,9 @@ function generateCachingRpcMethod(ctx, fileDesc, serviceDesc, methodDesc) {
302
299
  const lambda = (0, ts_poet_1.code) `
303
300
  (requests) => {
304
301
  const responses = requests.map(async request => {
305
- const data = ${inputType}.encode(request).finish()
302
+ const data = ${(0, types_1.getMessageMethod)(ctx, methodDesc.inputType, "encode")}(request).finish()
306
303
  const response = await this.rpc.request(ctx, "${(0, utils_1.maybePrefixPackage)(fileDesc, serviceDesc.name)}", "${methodDesc.name}", data);
307
- return ${outputType}.decode(new ${BinaryReader}(response));
304
+ return ${(0, types_1.getMessageMethod)(ctx, methodDesc.outputType, "decode")}(new ${BinaryReader}(response));
308
305
  });
309
306
  return Promise.all(responses);
310
307
  }
@@ -164,7 +164,7 @@ function generateWrapShallow(ctx, fullProtoTypeName, fieldNames) {
164
164
  }
165
165
  if (ctx.options.useOptionals !== "all")
166
166
  defaultFields = "";
167
- chunks.push((0, ts_poet_1.code) `wrap(object: {[key: string]: any} | undefined): ${(0, utils_1.wrapTypeName)(ctx.options, "Struct")} {
167
+ chunks.push((0, ts_poet_1.code) `${methodHead(ctx, "Struct", "wrap")}(object: {[key: string]: any} | undefined): ${(0, utils_1.wrapTypeName)(ctx.options, "Struct")} {
168
168
  const struct = createBase${(0, utils_1.wrapTypeName)(ctx.options, "Struct")}();
169
169
  ${defaultFields}
170
170
  if (object !== undefined) {
@@ -177,7 +177,7 @@ function generateWrapShallow(ctx, fullProtoTypeName, fieldNames) {
177
177
  }
178
178
  if ((0, types_1.isAnyValueTypeName)(fullProtoTypeName)) {
179
179
  if (ctx.options.oneof === options_1.OneofOption.UNIONS) {
180
- chunks.push((0, ts_poet_1.code) `wrap(value: any): ${(0, utils_1.wrapTypeName)(ctx.options, "Value")} {
180
+ chunks.push((0, ts_poet_1.code) `${methodHead(ctx, "Value", "wrap")}(value: any): ${(0, utils_1.wrapTypeName)(ctx.options, "Value")} {
181
181
  const result = createBase${(0, utils_1.wrapTypeName)(ctx.options, "Value")}()${maybeAsAny(ctx.options)};
182
182
  if (value === null) {
183
183
  result.kind = {$case: '${fieldNames.nullValue}', ${fieldNames.nullValue}: ${(0, utils_1.wrapTypeName)(ctx.options, "NullValue", "enum")}.NULL_VALUE};
@@ -198,7 +198,7 @@ function generateWrapShallow(ctx, fullProtoTypeName, fieldNames) {
198
198
  }`);
199
199
  }
200
200
  else if (ctx.options.oneof === options_1.OneofOption.UNIONS_VALUE) {
201
- chunks.push((0, ts_poet_1.code) `wrap(value: any): ${(0, utils_1.wrapTypeName)(ctx.options, "Value")} {
201
+ chunks.push((0, ts_poet_1.code) `${methodHead(ctx, "Value", "wrap")}(value: any): ${(0, utils_1.wrapTypeName)(ctx.options, "Value")} {
202
202
  const result = createBase${(0, utils_1.wrapTypeName)(ctx.options, "Value")}()${maybeAsAny(ctx.options)};
203
203
  if (value === null) {
204
204
  result.kind = {$case: '${fieldNames.nullValue}', value: ${(0, utils_1.wrapTypeName)(ctx.options, "NullValue", "enum")}.NULL_VALUE};
@@ -219,7 +219,7 @@ function generateWrapShallow(ctx, fullProtoTypeName, fieldNames) {
219
219
  }`);
220
220
  }
221
221
  else {
222
- chunks.push((0, ts_poet_1.code) `wrap(value: any): ${(0, utils_1.wrapTypeName)(ctx.options, "Value")} {
222
+ chunks.push((0, ts_poet_1.code) `${methodHead(ctx, "Value", "wrap")}(value: any): ${(0, utils_1.wrapTypeName)(ctx.options, "Value")} {
223
223
  const result = createBase${(0, utils_1.wrapTypeName)(ctx.options, "Value")}()${maybeAsAny(ctx.options)};
224
224
  if (value === null) {
225
225
  result.${fieldNames.nullValue} = ${(0, utils_1.wrapTypeName)(ctx.options, "NullValue", "enum")}.NULL_VALUE;
@@ -242,14 +242,14 @@ function generateWrapShallow(ctx, fullProtoTypeName, fieldNames) {
242
242
  }
243
243
  if ((0, types_1.isListValueTypeName)(fullProtoTypeName)) {
244
244
  const maybeReadyOnly = ctx.options.useReadonlyTypes ? "Readonly" : "";
245
- chunks.push((0, ts_poet_1.code) `wrap(array: ${maybeReadyOnly}Array<any> | undefined): ${(0, utils_1.wrapTypeName)(ctx.options, "ListValue")} {
245
+ chunks.push((0, ts_poet_1.code) `${methodHead(ctx, "ListValue", "wrap")}(array: ${maybeReadyOnly}Array<any> | undefined): ${(0, utils_1.wrapTypeName)(ctx.options, "ListValue")} {
246
246
  const result = createBase${(0, utils_1.wrapTypeName)(ctx.options, "ListValue")}()${maybeAsAny(ctx.options)};
247
247
  result.values = array ?? [];
248
248
  return result;
249
249
  }`);
250
250
  }
251
251
  if ((0, types_1.isFieldMaskTypeName)(fullProtoTypeName)) {
252
- chunks.push((0, ts_poet_1.code) `wrap(paths: ${maybeReadonly(ctx.options)} string[]): ${(0, utils_1.wrapTypeName)(ctx.options, "FieldMask")} {
252
+ chunks.push((0, ts_poet_1.code) `${methodHead(ctx, "FieldMask", "wrap")}(paths: ${maybeReadonly(ctx.options)} string[]): ${(0, utils_1.wrapTypeName)(ctx.options, "FieldMask")} {
253
253
  const result = createBase${(0, utils_1.wrapTypeName)(ctx.options, "FieldMask")}()${maybeAsAny(ctx.options)};
254
254
  result.paths = paths;
255
255
  return result;
@@ -266,7 +266,7 @@ function generateUnwrapShallow(ctx, fullProtoTypeName, fieldNames) {
266
266
  const chunks = [];
267
267
  if ((0, types_1.isStructTypeName)(fullProtoTypeName)) {
268
268
  if (ctx.options.useMapType) {
269
- chunks.push((0, ts_poet_1.code) `unwrap(message: ${(0, utils_1.wrapTypeName)(ctx.options, "Struct")}): {[key: string]: any} {
269
+ chunks.push((0, ts_poet_1.code) `${methodHead(ctx, "Struct", "unwrap")}(message: ${(0, utils_1.wrapTypeName)(ctx.options, "Struct")}): {[key: string]: any} {
270
270
  const object: { [key: string]: any } = {};
271
271
  if (message.fields) {
272
272
  for (const key of message.fields.keys()) {
@@ -277,7 +277,7 @@ function generateUnwrapShallow(ctx, fullProtoTypeName, fieldNames) {
277
277
  }`);
278
278
  }
279
279
  else {
280
- chunks.push((0, ts_poet_1.code) `unwrap(message: ${(0, utils_1.wrapTypeName)(ctx.options, "Struct")}): {[key: string]: any} {
280
+ chunks.push((0, ts_poet_1.code) `${methodHead(ctx, "Struct", "unwrap")}(message: ${(0, utils_1.wrapTypeName)(ctx.options, "Struct")}): {[key: string]: any} {
281
281
  const object: { [key: string]: any } = {};
282
282
  if (message.fields) {
283
283
  for (const key of ${ctx.utils.globalThis}.Object.keys(message.fields)) {
@@ -290,7 +290,7 @@ function generateUnwrapShallow(ctx, fullProtoTypeName, fieldNames) {
290
290
  }
291
291
  if ((0, types_1.isAnyValueTypeName)(fullProtoTypeName)) {
292
292
  if (ctx.options.oneof === options_1.OneofOption.UNIONS) {
293
- chunks.push((0, ts_poet_1.code) `unwrap(message: ${(0, utils_1.wrapTypeName)(ctx.options, "Value")}): string | number | boolean | Object | null | Array<any> | undefined {
293
+ chunks.push((0, ts_poet_1.code) `${methodHead(ctx, "Value", "unwrap")}(message: ${(0, utils_1.wrapTypeName)(ctx.options, "Value")}): string | number | boolean | Object | null | Array<any> | undefined {
294
294
  if (message.kind?.$case === '${fieldNames.nullValue}') {
295
295
  return null;
296
296
  } else if (message.kind?.$case === '${fieldNames.numberValue}') {
@@ -309,12 +309,12 @@ function generateUnwrapShallow(ctx, fullProtoTypeName, fieldNames) {
309
309
  }`);
310
310
  }
311
311
  else if (ctx.options.oneof === options_1.OneofOption.UNIONS_VALUE) {
312
- chunks.push((0, ts_poet_1.code) `unwrap(message: ${(0, utils_1.wrapTypeName)(ctx.options, "Value")}): string | number | boolean | Object | null | Array<any> | undefined {
312
+ chunks.push((0, ts_poet_1.code) `${methodHead(ctx, "Value", "unwrap")}(message: ${(0, utils_1.wrapTypeName)(ctx.options, "Value")}): string | number | boolean | Object | null | Array<any> | undefined {
313
313
  return (message.kind?.$case === '${fieldNames.nullValue}') ? null : message.kind?.value;
314
314
  }`);
315
315
  }
316
316
  else {
317
- chunks.push((0, ts_poet_1.code) `unwrap(message: any): string | number | boolean | Object | null | Array<any> | undefined {
317
+ chunks.push((0, ts_poet_1.code) `${methodHead(ctx, "Value", "unwrap")}(message: any): string | number | boolean | Object | null | Array<any> | undefined {
318
318
  if (message.${fieldNames.stringValue} !== undefined) {
319
319
  return message.${fieldNames.stringValue};
320
320
  } else if (message?.${fieldNames.numberValue} !== undefined) {
@@ -333,7 +333,7 @@ function generateUnwrapShallow(ctx, fullProtoTypeName, fieldNames) {
333
333
  }
334
334
  }
335
335
  if ((0, types_1.isListValueTypeName)(fullProtoTypeName)) {
336
- chunks.push((0, ts_poet_1.code) `unwrap(message: ${ctx.options.useReadonlyTypes ? "any" : (0, utils_1.wrapTypeName)(ctx.options, "ListValue")}): Array<any> {
336
+ chunks.push((0, ts_poet_1.code) `${methodHead(ctx, "ListValue", "unwrap")}(message: ${ctx.options.useReadonlyTypes ? "any" : (0, utils_1.wrapTypeName)(ctx.options, "ListValue")}): Array<any> {
337
337
  if (message?.hasOwnProperty('values') && ${ctx.utils.globalThis}.Array.isArray(message.values)) {
338
338
  return message.values;
339
339
  } else {
@@ -349,10 +349,13 @@ function generateUnwrapShallow(ctx, fullProtoTypeName, fieldNames) {
349
349
  function generateFieldMaskUnwrap(ctx) {
350
350
  const returnType = ctx.options.useOptionals === "all" ? "string[] | undefined" : "string[]";
351
351
  const pathModifier = ctx.options.useOptionals === "all" ? "?" : "";
352
- return (0, ts_poet_1.code) `unwrap(message: ${ctx.options.useReadonlyTypes ? "any" : (0, utils_1.wrapTypeName)(ctx.options, "FieldMask")}): ${returnType} {
352
+ return (0, ts_poet_1.code) `${methodHead(ctx, "FieldMask", "unwrap")}(message: ${ctx.options.useReadonlyTypes ? "any" : (0, utils_1.wrapTypeName)(ctx.options, "FieldMask")}): ${returnType} {
353
353
  return message${pathModifier}.paths;
354
354
  }`;
355
355
  }
356
+ function methodHead(ctx, name, method) {
357
+ return (0, utils_1.messageMethodHead)(ctx.options, (0, utils_1.wrapTypeName)(ctx.options, name), method);
358
+ }
356
359
  function maybeReadonly(options) {
357
360
  return options.useReadonlyTypes ? "readonly " : "";
358
361
  }
package/build/src/main.js CHANGED
@@ -69,7 +69,7 @@ function generateFile(ctx, fileDesc) {
69
69
  chunks.push((0, enums_1.generateEnum)(ctx, fullName, enumDesc, sInfo));
70
70
  });
71
71
  // If nestJs=true export [package]_PACKAGE_NAME and [service]_SERVICE_NAME const
72
- if (options.nestJs) {
72
+ if (options.nestJs.length > 0) {
73
73
  if (options.exportCommonSymbols) {
74
74
  const prefix = (0, case_1.camelToSnake)(fileDesc.package.replace(/\./g, "_"));
75
75
  chunks.push((0, ts_poet_1.code) `export const ${prefix}_PACKAGE_NAME = '${fileDesc.package}';`);
@@ -85,7 +85,7 @@ function generateFile(ctx, fileDesc) {
85
85
  options.outputJsonMethods ||
86
86
  options.outputTypeAnnotations ||
87
87
  options.outputTypeRegistry ||
88
- options.nestJs) {
88
+ options.nestJs.length > 0) {
89
89
  // then add the encoder/decoder/base instance
90
90
  (0, visit_1.visit)(fileDesc, sourceInfo, (fullName, message, _sInfo, fullProtoTypeName) => {
91
91
  const fullTypeName = (0, utils_1.maybePrefixPackage)(fileDesc, fullProtoTypeName);
@@ -98,18 +98,23 @@ function generateFile(ctx, fileDesc) {
98
98
  (options.outputDecodeIncludeTypes === "" ||
99
99
  new RegExp(options.outputDecodeIncludeTypes).test(fullTypeName))) ||
100
100
  options.outputPartialMethods ||
101
- (outputWrapAndUnwrap && !(options.nestJs && (0, types_1.isAnyValueTypeName)(fullTypeName)))) {
101
+ (outputWrapAndUnwrap && !(options.nestJs.length > 0 && (0, types_1.isAnyValueTypeName)(fullTypeName)))) {
102
102
  chunks.push(generateBaseInstanceFactory(ctx, fullName, message, fullTypeName));
103
103
  }
104
104
  const staticMembers = [];
105
105
  const hasTypeMember = options.outputTypeAnnotations || options.outputTypeRegistry;
106
- if (hasTypeMember) {
106
+ if (hasTypeMember && !options.outputStandaloneFunctions) {
107
107
  staticMembers.push((0, ts_poet_1.code) `$type: '${fullTypeName}' as const`);
108
108
  }
109
109
  if (options.outputExtensions) {
110
110
  for (const extension of message.extension) {
111
111
  const { name, type, extensionInfo } = generateExtension(ctx, message, extension);
112
- staticMembers.push((0, ts_poet_1.code) `${name}: <${ctx.utils.Extension}<${type}>> ${extensionInfo}`);
112
+ if (options.outputStandaloneFunctions) {
113
+ staticMembers.push((0, ts_poet_1.code) `export const ${(0, ts_poet_1.def)((0, utils_1.messageFunctionName)(fullName, name))}: ${ctx.utils.Extension}<${type}> = ${extensionInfo};`);
114
+ }
115
+ else {
116
+ staticMembers.push((0, ts_poet_1.code) `${name}: <${ctx.utils.Extension}<${type}>> ${extensionInfo}`);
117
+ }
113
118
  }
114
119
  }
115
120
  if (options.outputEncodeMethods) {
@@ -124,7 +129,7 @@ function generateFile(ctx, fileDesc) {
124
129
  }
125
130
  }
126
131
  else if (options.outputEncodeMethods === true) {
127
- staticMembers.push(generateEmptyEncode(fullName));
132
+ staticMembers.push(generateEmptyEncode(ctx, fullName));
128
133
  }
129
134
  }
130
135
  if (options.outputEncodeMethods === true || options.outputEncodeMethods === "decode-only") {
@@ -136,13 +141,13 @@ function generateFile(ctx, fileDesc) {
136
141
  }
137
142
  }
138
143
  else if (options.outputEncodeMethods === true) {
139
- staticMembers.push(generateEmptyDecode(fullName));
144
+ staticMembers.push(generateEmptyDecode(ctx, fullName));
140
145
  }
141
146
  }
142
147
  }
143
148
  if (options.useAsyncIterable) {
144
- staticMembers.push((0, generate_async_iterable_1.generateEncodeTransform)(ctx.utils, fullName));
145
- staticMembers.push((0, generate_async_iterable_1.generateDecodeTransform)(ctx.utils, fullName));
149
+ staticMembers.push((0, generate_async_iterable_1.generateEncodeTransform)(ctx, fullName));
150
+ staticMembers.push((0, generate_async_iterable_1.generateDecodeTransform)(ctx, fullName));
146
151
  }
147
152
  if (options.outputJsonMethods) {
148
153
  if (options.outputJsonMethods === true || options.outputJsonMethods === "from-only") {
@@ -163,7 +168,7 @@ function generateFile(ctx, fileDesc) {
163
168
  structValue: (0, utils_1.getFieldName)({ name: "struct_value", jsonName: (0, case_1.snakeToCamel)("struct_value") }, ctx.options),
164
169
  listValue: (0, utils_1.getFieldName)({ name: "list_value", jsonName: (0, case_1.snakeToCamel)("list_value") }, ctx.options),
165
170
  };
166
- if (options.nestJs) {
171
+ if (options.nestJs.length > 0) {
167
172
  staticMembers.push(...(0, generate_struct_wrappers_1.generateWrapDeep)(ctx, fullTypeName, structFieldNames));
168
173
  staticMembers.push(...(0, generate_struct_wrappers_1.generateUnwrapDeep)(ctx, fullTypeName, structFieldNames));
169
174
  }
@@ -171,7 +176,10 @@ function generateFile(ctx, fileDesc) {
171
176
  staticMembers.push(...(0, generate_struct_wrappers_1.generateWrapShallow)(ctx, fullTypeName, structFieldNames));
172
177
  staticMembers.push(...(0, generate_struct_wrappers_1.generateUnwrapShallow)(ctx, fullTypeName, structFieldNames));
173
178
  }
174
- if (staticMembers.length > 0) {
179
+ if (options.outputStandaloneFunctions) {
180
+ chunks.push(...staticMembers);
181
+ }
182
+ else if (staticMembers.length > 0) {
175
183
  const messageFnsTypeParameters = [fullName, hasTypeMember && `'${fullTypeName}'`]
176
184
  .filter((p) => !!p)
177
185
  .join(", ");
@@ -224,7 +232,7 @@ function generateFile(ctx, fileDesc) {
224
232
  chunks.push((0, ts_poet_1.code) `export const ${name}: ${ctx.utils.Extension}<${type}> = ${extensionInfo};`);
225
233
  }
226
234
  }
227
- if (options.nestJs) {
235
+ if (options.nestJs.length > 0) {
228
236
  if (fileDesc.messageType.find(hasStructTypeField)) {
229
237
  chunks.push(makeProtobufStructWrapper(options));
230
238
  }
@@ -232,14 +240,18 @@ function generateFile(ctx, fileDesc) {
232
240
  let hasServerStreamingMethods = false;
233
241
  let hasStreamingMethods = false;
234
242
  (0, visit_1.visitServices)(fileDesc, sourceInfo, (serviceDesc, sInfo) => {
235
- if (options.nestJs) {
243
+ if (options.nestJs.length > 0) {
236
244
  // NestJS is sufficiently different that we special case the client/server interfaces
237
- // generate nestjs grpc client interface
238
- chunks.push((0, generate_nestjs_1.generateNestjsServiceClient)(ctx, fileDesc, sInfo, serviceDesc));
239
- // and the service controller interface
240
- chunks.push((0, generate_nestjs_1.generateNestjsServiceController)(ctx, fileDesc, sInfo, serviceDesc));
241
- // generate nestjs grpc service controller decorator
242
- chunks.push((0, generate_nestjs_1.generateNestjsGrpcServiceMethodsDecorator)(ctx, fileDesc, serviceDesc));
245
+ if (options.nestJs.includes("client")) {
246
+ // generate nestjs grpc client interface
247
+ chunks.push((0, generate_nestjs_1.generateNestjsServiceClient)(ctx, fileDesc, sInfo, serviceDesc));
248
+ }
249
+ if (options.nestJs.includes("server")) {
250
+ // generate nestjs grpc service controller interface
251
+ chunks.push((0, generate_nestjs_1.generateNestjsServiceController)(ctx, fileDesc, sInfo, serviceDesc));
252
+ // generate nestjs grpc service controller decorator
253
+ chunks.push((0, generate_nestjs_1.generateNestjsGrpcServiceMethodsDecorator)(ctx, fileDesc, serviceDesc));
254
+ }
243
255
  let serviceConstName = `${(0, case_1.camelToSnake)(serviceDesc.name)}_NAME`;
244
256
  if (!serviceDesc.name.toLowerCase().endsWith("service")) {
245
257
  serviceConstName = `${(0, case_1.camelToSnake)(serviceDesc.name)}_SERVICE_NAME`;
@@ -694,7 +706,7 @@ function makeObjectIdMethods() {
694
706
  return { fromJsonObjectId, fromProtoObjectId, toProtoObjectId };
695
707
  }
696
708
  function makeTimestampMethods(options, longs, bytes) {
697
- const Timestamp = (0, utils_1.impProto)(options, "google/protobuf/timestamp", (0, utils_1.wrapTypeName)(options, "Timestamp"));
709
+ const Timestamp = (0, utils_1.impProto)(options, "google/protobuf/timestamp", (0, utils_1.wrapTypeName)(options, "Timestamp"), options.outputStandaloneFunctions);
698
710
  const NanoDate = (0, ts_poet_1.imp)("NanoDate=nano-date");
699
711
  let seconds = "Math.trunc(date.getTime() / 1_000)";
700
712
  let toNumberCode = "t.seconds";
@@ -800,6 +812,7 @@ function makeTimestampMethods(options, longs, bytes) {
800
812
  `);
801
813
  // Declared once per file, so the regex isn't compiled on each fromJsonTimestamp call
802
814
  const timestampFractionRegex = (0, ts_poet_1.conditionalOutput)("timestampFractionRegex", (0, ts_poet_1.code) `const timestampFractionRegex = /:\\d{2}\\.\\d+/;`);
815
+ const timestampMessageFromJson = (0, utils_1.impProtoMethod)(options, "google/protobuf/timestamp", (0, utils_1.wrapTypeName)(options, "Timestamp"), "fromJSON");
803
816
  const fromJsonTimestamp = (0, ts_poet_1.conditionalOutput)("fromJsonTimestamp", options.useDate === options_1.DateOption.DATE
804
817
  ? (0, ts_poet_1.code) `
805
818
  function fromJsonTimestamp(o: any): Date {
@@ -808,7 +821,7 @@ function makeTimestampMethods(options, longs, bytes) {
808
821
  } else if (typeof o === "string") {
809
822
  return new ${bytes.globalThis}.Date(o);
810
823
  } else {
811
- return ${fromTimestamp}(${(0, utils_1.wrapTypeName)(options, "Timestamp")}.fromJSON(o));
824
+ return ${fromTimestamp}(${timestampMessageFromJson}(o));
812
825
  }
813
826
  }
814
827
  `
@@ -820,7 +833,7 @@ function makeTimestampMethods(options, longs, bytes) {
820
833
  } else if (typeof o === "string") {
821
834
  return ${bytes.globalThis}.Temporal.Instant.from(o);
822
835
  } else {
823
- return ${fromTimestamp}(${(0, utils_1.wrapTypeName)(options, "Timestamp")}.fromJSON(o));
836
+ return ${fromTimestamp}(${timestampMessageFromJson}(o));
824
837
  }
825
838
  }
826
839
  `
@@ -842,7 +855,7 @@ function makeTimestampMethods(options, longs, bytes) {
842
855
  );
843
856
  return { ...timestamp, nanos: (timestamp.nanos ?? 0) + (fractionNanos % 1_000_000) };
844
857
  } else {
845
- return ${options.typePrefix}Timestamp${options.typeSuffix}.fromJSON(o);
858
+ return ${timestampMessageFromJson}(o);
846
859
  }
847
860
  }
848
861
  `);
@@ -1123,14 +1136,13 @@ function getDecodeReadSnippet(ctx, field) {
1123
1136
  }
1124
1137
  }
1125
1138
  else if ((0, types_1.isValueType)(ctx, field)) {
1126
- const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
1127
1139
  const unwrap = (decodedValue) => {
1128
1140
  if ((0, types_1.isListValueType)(field) || (0, types_1.isStructType)(field) || (0, types_1.isAnyValueType)(field) || (0, types_1.isFieldMaskType)(field)) {
1129
- return (0, ts_poet_1.code) `${type}.unwrap(${decodedValue})`;
1141
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, field.typeName, "unwrap")}(${decodedValue})`;
1130
1142
  }
1131
1143
  return (0, ts_poet_1.code) `${decodedValue}.value`;
1132
1144
  };
1133
- const decoder = (0, ts_poet_1.code) `${type}.decode(reader, reader.uint32())`;
1145
+ const decoder = (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, field.typeName, "decode")}(reader, reader.uint32())`;
1134
1146
  readSnippet = (0, ts_poet_1.code) `${unwrap(decoder)}`;
1135
1147
  }
1136
1148
  else if ((0, types_1.isTimestamp)(field) &&
@@ -1138,20 +1150,20 @@ function getDecodeReadSnippet(ctx, field) {
1138
1150
  options.useDate === options_1.DateOption.STRING ||
1139
1151
  options.useDate === options_1.DateOption.STRING_NANO ||
1140
1152
  options.useDate === options_1.DateOption.TEMPORAL)) {
1141
- const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
1142
- readSnippet = (0, ts_poet_1.code) `${utils.fromTimestamp}(${type}.decode(reader, reader.uint32()))`;
1153
+ const decode = (0, types_1.getMessageMethod)(ctx, field.typeName, "decode");
1154
+ readSnippet = (0, ts_poet_1.code) `${utils.fromTimestamp}(${decode}(reader, reader.uint32()))`;
1143
1155
  }
1144
1156
  else if ((0, types_1.isObjectId)(field) && options.useMongoObjectId) {
1145
1157
  const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
1146
1158
  readSnippet = (0, ts_poet_1.code) `${utils.fromProtoObjectId}(${type}.decode(reader, reader.uint32()))`;
1147
1159
  }
1148
1160
  else if ((0, types_1.isMessage)(field)) {
1149
- const type = (0, types_1.basicTypeName)(ctx, field);
1161
+ const decode = (0, types_1.getMessageMethod)(ctx, field.typeName, "decode");
1150
1162
  if (field.type == ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_GROUP) {
1151
- readSnippet = (0, ts_poet_1.code) `${type}.decode(reader)`;
1163
+ readSnippet = (0, ts_poet_1.code) `${decode}(reader)`;
1152
1164
  }
1153
1165
  else {
1154
- readSnippet = (0, ts_poet_1.code) `${type}.decode(reader, reader.uint32())`;
1166
+ readSnippet = (0, ts_poet_1.code) `${decode}(reader, reader.uint32())`;
1155
1167
  }
1156
1168
  }
1157
1169
  else {
@@ -1159,10 +1171,10 @@ function getDecodeReadSnippet(ctx, field) {
1159
1171
  }
1160
1172
  return readSnippet;
1161
1173
  }
1162
- function generateEmptyDecode(fullName) {
1174
+ function generateEmptyDecode(ctx, fullName) {
1163
1175
  const BinaryReader = (0, ts_poet_1.imp)("t:BinaryReader@@bufbuild/protobuf/wire");
1164
1176
  return (0, ts_poet_1.code) `
1165
- decode(
1177
+ ${(0, utils_1.messageMethodHead)(ctx.options, fullName, "decode")}(
1166
1178
  _: ${BinaryReader} | Uint8Array,
1167
1179
  length?: number,
1168
1180
  ): ${fullName} {
@@ -1181,7 +1193,7 @@ function generateDecode(ctx, fullName, messageDesc) {
1181
1193
  const BinaryReader = (0, ts_poet_1.imp)("BinaryReader@@bufbuild/protobuf/wire");
1182
1194
  // create the basic function declaration
1183
1195
  chunks.push((0, ts_poet_1.code) `
1184
- decode(
1196
+ ${(0, utils_1.messageMethodHead)(options, fullName, "decode")}(
1185
1197
  input: ${BinaryReader} | Uint8Array,
1186
1198
  length?: number,
1187
1199
  ): ${fullName} {
@@ -1411,38 +1423,38 @@ function getEncodeWriteSnippet(ctx, field) {
1411
1423
  options.useDate === options_1.DateOption.STRING_NANO ||
1412
1424
  options.useDate === options_1.DateOption.TEMPORAL)) {
1413
1425
  const tag = ((field.number << 3) | 2) >>> 0;
1414
- const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
1415
- return (place) => (0, ts_poet_1.code) `${type}.encode(${utils.toTimestamp}(${place}), writer.uint32(${tag}).fork()).join()`;
1426
+ const encode = (0, types_1.getMessageMethod)(ctx, field.typeName, "encode");
1427
+ return (place) => (0, ts_poet_1.code) `${encode}(${utils.toTimestamp}(${place}), writer.uint32(${tag}).fork()).join()`;
1416
1428
  }
1417
1429
  else if ((0, types_1.isValueType)(ctx, field)) {
1418
1430
  const maybeTypeField = (0, options_1.addTypeToMessages)(options) ? `$type: '${field.typeName.slice(1)}',` : "";
1419
- const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
1431
+ const encode = (0, types_1.getMessageMethod)(ctx, field.typeName, "encode");
1420
1432
  const wrappedValue = (place) => {
1421
1433
  if ((0, types_1.isAnyValueType)(field) || (0, types_1.isListValueType)(field) || (0, types_1.isStructType)(field) || (0, types_1.isFieldMaskType)(field)) {
1422
- return (0, ts_poet_1.code) `${type}.wrap(${place})`;
1434
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, field.typeName, "wrap")}(${place})`;
1423
1435
  }
1424
1436
  return (0, ts_poet_1.code) `{${maybeTypeField} value: ${place}!}`;
1425
1437
  };
1426
1438
  const tag = ((field.number << 3) | 2) >>> 0;
1427
- return (place) => (0, ts_poet_1.code) `${type}.encode(${wrappedValue(place)}, writer.uint32(${tag}).fork()).join()`;
1439
+ return (place) => (0, ts_poet_1.code) `${encode}(${wrappedValue(place)}, writer.uint32(${tag}).fork()).join()`;
1428
1440
  }
1429
1441
  else if ((0, types_1.isMessage)(field)) {
1430
- const type = (0, types_1.basicTypeName)(ctx, field);
1442
+ const encode = (0, types_1.getMessageMethod)(ctx, field.typeName, "encode");
1431
1443
  if (field.type == ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_GROUP) {
1432
1444
  const startTag = ((field.number << 3) | 3) >>> 0, endTag = ((field.number << 3) | 4) >>> 0;
1433
- return (place) => (0, ts_poet_1.code) `${type}.encode(${place}, writer.uint32(${startTag})).uint32(${endTag})`;
1445
+ return (place) => (0, ts_poet_1.code) `${encode}(${place}, writer.uint32(${startTag})).uint32(${endTag})`;
1434
1446
  }
1435
1447
  const tag = ((field.number << 3) | 2) >>> 0;
1436
- return (place) => (0, ts_poet_1.code) `${type}.encode(${place}, writer.uint32(${tag}).fork()).join()`;
1448
+ return (place) => (0, ts_poet_1.code) `${encode}(${place}, writer.uint32(${tag}).fork()).join()`;
1437
1449
  }
1438
1450
  else {
1439
1451
  throw new Error(`Unhandled field ${field}`);
1440
1452
  }
1441
1453
  }
1442
- function generateEmptyEncode(fullName) {
1454
+ function generateEmptyEncode(ctx, fullName) {
1443
1455
  const BinaryWriter = (0, ts_poet_1.imp)("BinaryWriter@@bufbuild/protobuf/wire");
1444
1456
  return (0, ts_poet_1.code) `
1445
- encode(
1457
+ ${(0, utils_1.messageMethodHead)(ctx.options, fullName, "encode")}(
1446
1458
  _: ${fullName},
1447
1459
  writer: ${BinaryWriter} = new ${BinaryWriter}(),
1448
1460
  ): ${BinaryWriter} {
@@ -1457,7 +1469,7 @@ function generateEncode(ctx, fullName, messageDesc) {
1457
1469
  const BinaryWriter = (0, ts_poet_1.imp)("BinaryWriter@@bufbuild/protobuf/wire");
1458
1470
  // create the basic function declaration
1459
1471
  chunks.push((0, ts_poet_1.code) `
1460
- encode(
1472
+ ${(0, utils_1.messageMethodHead)(options, fullName, "encode")}(
1461
1473
  ${messageDesc.field.length > 0 || options.unknownFields ? "message" : "_"}: ${fullName},
1462
1474
  writer: ${BinaryWriter} = new ${BinaryWriter}(),
1463
1475
  ): ${BinaryWriter} {
@@ -1673,7 +1685,7 @@ function generateEncode(ctx, fullName, messageDesc) {
1673
1685
  }
1674
1686
  function generateSetExtension(ctx, fullName) {
1675
1687
  return (0, ts_poet_1.code) `
1676
- setExtension <T> (message: ${fullName}, extension: ${ctx.utils.Extension}<T>, value: T): void {
1688
+ ${(0, utils_1.messageMethodHead)(ctx.options, fullName, "setExtension")} <T> (message: ${fullName}, extension: ${ctx.utils.Extension}<T>, value: T): void {
1677
1689
  const encoded = extension.encode!(value);
1678
1690
 
1679
1691
  if (message._unknownFields !== undefined) {
@@ -1699,7 +1711,7 @@ function generateSetExtension(ctx, fullName) {
1699
1711
  }
1700
1712
  function generateGetExtension(ctx, fullName) {
1701
1713
  return (0, ts_poet_1.code) `
1702
- getExtension <T> (message: ${fullName}, extension: ${ctx.utils.Extension}<T>): T | undefined {
1714
+ ${(0, utils_1.messageMethodHead)(ctx.options, fullName, "getExtension")} <T> (message: ${fullName}, extension: ${ctx.utils.Extension}<T>): T | undefined {
1703
1715
  let results: T | undefined = undefined;
1704
1716
 
1705
1717
  if (message._unknownFields === undefined) {
@@ -1787,27 +1799,27 @@ function generateExtension(ctx, message, extension) {
1787
1799
  options.useDate === options_1.DateOption.STRING ||
1788
1800
  options.useDate === options_1.DateOption.STRING_NANO ||
1789
1801
  options.useDate === options_1.DateOption.TEMPORAL)) {
1790
- const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
1791
- return (place) => (0, ts_poet_1.code) `${type}.encode(${utils.toTimestamp}(${place}), writer.fork()).join()`;
1802
+ const encode = (0, types_1.getMessageMethod)(ctx, field.typeName, "encode");
1803
+ return (place) => (0, ts_poet_1.code) `${encode}(${utils.toTimestamp}(${place}), writer.fork()).join()`;
1792
1804
  }
1793
1805
  else if ((0, types_1.isValueType)(ctx, field)) {
1794
1806
  const maybeTypeField = (0, options_1.addTypeToMessages)(options) ? `$type: '${field.typeName.slice(1)}',` : "";
1795
- const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
1807
+ const encode = (0, types_1.getMessageMethod)(ctx, field.typeName, "encode");
1796
1808
  const wrappedValue = (place) => {
1797
1809
  if ((0, types_1.isAnyValueType)(field) || (0, types_1.isListValueType)(field) || (0, types_1.isStructType)(field) || (0, types_1.isFieldMaskType)(field)) {
1798
- return (0, ts_poet_1.code) `${type}.wrap(${place})`;
1810
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, field.typeName, "wrap")}(${place})`;
1799
1811
  }
1800
1812
  return (0, ts_poet_1.code) `{${maybeTypeField} value: ${place}!}`;
1801
1813
  };
1802
- return (place) => (0, ts_poet_1.code) `${type}.encode(${wrappedValue(place)}, writer.fork()).join()`;
1814
+ return (place) => (0, ts_poet_1.code) `${encode}(${wrappedValue(place)}, writer.fork()).join()`;
1803
1815
  }
1804
1816
  else if ((0, types_1.isMessage)(field)) {
1805
- const type = (0, types_1.basicTypeName)(ctx, field);
1817
+ const encode = (0, types_1.getMessageMethod)(ctx, field.typeName, "encode");
1806
1818
  if (field.type == ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_GROUP) {
1807
1819
  const endTag = ((field.number << 3) | 4) >>> 0;
1808
- return (place) => (0, ts_poet_1.code) `${type}.encode(${place}, writer).uint32(${endTag})`;
1820
+ return (place) => (0, ts_poet_1.code) `${encode}(${place}, writer).uint32(${endTag})`;
1809
1821
  }
1810
- return (place) => (0, ts_poet_1.code) `${type}.encode(${place}, writer.fork()).join()`;
1822
+ return (place) => (0, ts_poet_1.code) `${encode}(${place}, writer.fork()).join()`;
1811
1823
  }
1812
1824
  else {
1813
1825
  throw new Error(`Unhandled field ${field}`);
@@ -1962,7 +1974,7 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1962
1974
  break;
1963
1975
  }
1964
1976
  return (0, ts_poet_1.code) `
1965
- fromJSON(object: string): ${fullName} {
1977
+ ${(0, utils_1.messageMethodHead)(options, fullName, "fromJSON")}(object: string): ${fullName} {
1966
1978
  if (!object.endsWith("s")) throw new Error("Invalid duration string");
1967
1979
  const body = object.slice(0, -1);
1968
1980
  const negative = body.startsWith("-");
@@ -1982,21 +1994,21 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1982
1994
  if (fullTypeName === "google.protobuf.Timestamp") {
1983
1995
  // The canonical JSON of a Timestamp is an RFC 3339 string; the object form is still accepted.
1984
1996
  chunks.push((0, ts_poet_1.code) `
1985
- fromJSON(object: any): ${fullName} {
1997
+ ${(0, utils_1.messageMethodHead)(options, fullName, "fromJSON")}(object: any): ${fullName} {
1986
1998
  if (typeof object === "string") {
1987
- return ${fullName}.fromJSON(${utils.timestampFromJson}(object));
1999
+ return ${(0, utils_1.localMessageMethod)(options, fullName, "fromJSON")}(${utils.timestampFromJson}(object));
1988
2000
  }
1989
2001
  return {
1990
2002
  `);
1991
2003
  }
1992
2004
  else {
1993
2005
  chunks.push((0, ts_poet_1.code) `
1994
- fromJSON(${messageDesc.field.length > 0 ? "object" : "_"}: any): ${fullName} {
2006
+ ${(0, utils_1.messageMethodHead)(options, fullName, "fromJSON")}(${messageDesc.field.length > 0 ? "object" : "_"}: any): ${fullName} {
1995
2007
  return {
1996
2008
  `);
1997
2009
  }
1998
2010
  if ((0, options_1.addTypeToMessages)(options)) {
1999
- chunks.push((0, ts_poet_1.code) `$type: ${fullName}.$type,`);
2011
+ chunks.push(options.outputStandaloneFunctions ? (0, ts_poet_1.code) `$type: '${fullTypeName}',` : (0, ts_poet_1.code) `$type: ${fullName}.$type,`);
2000
2012
  }
2001
2013
  const oneofFieldsCases = messageDesc.oneofDecl.map((oneof, oneofIndex) => messageDesc.field.filter(types_1.isWithinOneOf).filter((field) => field.oneofIndex === oneofIndex));
2002
2014
  const canonicalFromJson = {
@@ -2065,8 +2077,9 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
2065
2077
  return (0, ts_poet_1.code) `${from}`;
2066
2078
  }
2067
2079
  else if ((0, types_1.isFieldMaskType)(field)) {
2068
- const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
2069
- return (0, ts_poet_1.code) `${type}.unwrap(${type}.fromJSON(${from}))`;
2080
+ const unwrap = (0, types_1.getMessageMethod)(ctx, field.typeName, "unwrap");
2081
+ const fromJson = (0, types_1.getMessageMethod)(ctx, field.typeName, "fromJSON");
2082
+ return (0, ts_poet_1.code) `${unwrap}(${fromJson}(${from}))`;
2070
2083
  }
2071
2084
  else if ((0, types_1.isListValueType)(field)) {
2072
2085
  return (0, ts_poet_1.code) `[...${from}]`;
@@ -2125,12 +2138,11 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
2125
2138
  return (0, ts_poet_1.code) `${from}`;
2126
2139
  }
2127
2140
  else {
2128
- return (0, ts_poet_1.code) `${valueType}.fromJSON(${from})`;
2141
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, valueField.typeName, "fromJSON")}(${from})`;
2129
2142
  }
2130
2143
  }
2131
2144
  else {
2132
- const type = (0, types_1.basicTypeName)(ctx, field);
2133
- return (0, ts_poet_1.code) `${type}.fromJSON(${from})`;
2145
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, field.typeName, "fromJSON")}(${from})`;
2134
2146
  }
2135
2147
  }
2136
2148
  else {
@@ -2300,12 +2312,13 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
2300
2312
  chunks.push((0, ts_poet_1.code) `}`);
2301
2313
  return (0, ts_poet_1.joinCode)(chunks, { on: "\n" });
2302
2314
  }
2303
- function generateCanonicalToJson(fullName, fullProtobufTypeName, { useOptionals, useNullAsOptional, useDuration, useJsonTimestamp, forceLong }, utils) {
2315
+ function generateCanonicalToJson(fullName, fullProtobufTypeName, options, utils) {
2316
+ const { useOptionals, useNullAsOptional, useDuration, useJsonTimestamp, forceLong } = options;
2304
2317
  if ((0, types_1.isFieldMaskTypeName)(fullProtobufTypeName)) {
2305
2318
  const returnType = useOptionals === "all" ? `string | ${(0, utils_1.nullOrUndefined)({ useNullAsOptional })}` : "string";
2306
2319
  const pathModifier = useOptionals === "all" ? "?" : "";
2307
2320
  return (0, ts_poet_1.code) `
2308
- toJSON(message: ${fullName}): ${returnType} {
2321
+ ${(0, utils_1.messageMethodHead)(options, fullName, "toJSON")}(message: ${fullName}): ${returnType} {
2309
2322
  return message.paths${pathModifier}.join(',');
2310
2323
  }
2311
2324
  `;
@@ -2334,7 +2347,7 @@ function generateCanonicalToJson(fullName, fullProtobufTypeName, { useOptionals,
2334
2347
  break;
2335
2348
  }
2336
2349
  return (0, ts_poet_1.code) `
2337
- toJSON(message: ${fullName}): string {
2350
+ ${(0, utils_1.messageMethodHead)(options, fullName, "toJSON")}(message: ${fullName}): string {
2338
2351
  const negative = ${isNegSeconds} || message.nanos < 0;
2339
2352
  const sign = negative ? "-" : "";
2340
2353
  const absSeconds = ${absSeconds};
@@ -2351,7 +2364,7 @@ function generateCanonicalToJson(fullName, fullProtobufTypeName, { useOptionals,
2351
2364
  ? (0, ts_poet_1.code) `message.seconds?.toNumber() ?? 0`
2352
2365
  : (0, ts_poet_1.code) `${utils.globalThis}.Number(message.seconds ?? 0)`;
2353
2366
  return (0, ts_poet_1.code) `
2354
- toJSON(message: ${fullName}): string {
2367
+ ${(0, utils_1.messageMethodHead)(options, fullName, "toJSON")}(message: ${fullName}): string {
2355
2368
  return ${utils.timestampToJson}(${seconds}, message.nanos ?? 0);
2356
2369
  }
2357
2370
  `;
@@ -2381,7 +2394,7 @@ function generateCanonicalAnyToJson(ctx, fullName, messageDesc) {
2381
2394
  const typeUrl = (0, utils_1.getPropertyAccessor)("message", (0, utils_1.getFieldName)(typeUrlField, options));
2382
2395
  const value = (0, utils_1.getPropertyAccessor)("message", (0, utils_1.getFieldName)(valueField, options));
2383
2396
  return (0, ts_poet_1.code) `
2384
- toJSON(message: ${fullName}): unknown {
2397
+ ${(0, utils_1.messageMethodHead)(options, fullName, "toJSON")}(message: ${fullName}): unknown {
2385
2398
  const typeUrl = ${typeUrl} ?? "";
2386
2399
  if (typeUrl === "") {
2387
2400
  return {};
@@ -2408,7 +2421,7 @@ function generateCanonicalAnyFromJson(ctx, fullName, messageDesc) {
2408
2421
  const typeField = (0, options_1.addTypeToMessages)(options) ? (0, ts_poet_1.code) `$type: ${fullName}.$type,` : "";
2409
2422
  const bytes = options.env === options_1.EnvOption.NODE ? (0, ts_poet_1.code) `Buffer.from(bytes)` : (0, ts_poet_1.code) `bytes`;
2410
2423
  return (0, ts_poet_1.code) `
2411
- fromJSON(object: any): ${fullName} {
2424
+ ${(0, utils_1.messageMethodHead)(options, fullName, "fromJSON")}(object: any): ${fullName} {
2412
2425
  const typeUrl = ${utils.isSet}(object?.["@type"]) ? ${utils.globalThis}.String(object["@type"]) : "";
2413
2426
  if (typeUrl === "") {
2414
2427
  return { ${typeField} ${typeUrlKey}: ${(0, types_1.defaultValue)(ctx, typeUrlField)}, ${valueKey}: ${(0, types_1.defaultValue)(ctx, valueField)} };
@@ -2442,7 +2455,7 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
2442
2455
  }
2443
2456
  // create the basic function declaration
2444
2457
  chunks.push((0, ts_poet_1.code) `
2445
- toJSON(${messageDesc.field.length > 0 ? "message" : "_"}: ${fullName}): unknown {
2458
+ ${(0, utils_1.messageMethodHead)(options, fullName, "toJSON")}(${messageDesc.field.length > 0 ? "message" : "_"}: ${fullName}): unknown {
2446
2459
  const obj: any = {};
2447
2460
  `);
2448
2461
  let currentIfTarget = "";
@@ -2528,20 +2541,19 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
2528
2541
  return (0, ts_poet_1.code) `${from}`;
2529
2542
  }
2530
2543
  else {
2531
- const type = (0, types_1.basicTypeName)(ctx, valueType);
2532
- return (0, ts_poet_1.code) `${type}.toJSON(${from})`;
2544
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, valueType.typeName, "toJSON")}(${from})`;
2533
2545
  }
2534
2546
  }
2535
2547
  else if ((0, types_1.isAnyValueType)(field)) {
2536
2548
  return (0, ts_poet_1.code) `${from}`;
2537
2549
  }
2538
2550
  else if ((0, types_1.isFieldMaskType)(field)) {
2539
- const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
2540
- return (0, ts_poet_1.code) `${type}.toJSON(${type}.wrap(${from}))`;
2551
+ const toJson = (0, types_1.getMessageMethod)(ctx, field.typeName, "toJSON");
2552
+ const wrap = (0, types_1.getMessageMethod)(ctx, field.typeName, "wrap");
2553
+ return (0, ts_poet_1.code) `${toJson}(${wrap}(${from}))`;
2541
2554
  }
2542
2555
  else if ((0, types_1.isMessage)(field) && !(0, types_1.isValueType)(ctx, field) && !(0, types_1.isMapType)(ctx, messageDesc, field)) {
2543
- const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
2544
- return (0, ts_poet_1.code) `${type}.toJSON(${from})`;
2556
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, field.typeName, "toJSON")}(${from})`;
2545
2557
  }
2546
2558
  else if ((0, types_1.isBytes)(field)) {
2547
2559
  return (0, ts_poet_1.code) `${utils.base64FromBytes}(${from})`;
@@ -2641,31 +2653,32 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
2641
2653
  function generateFromPartial(ctx, fullName, messageDesc) {
2642
2654
  const { options, utils } = ctx;
2643
2655
  const chunks = [];
2656
+ const maybeComma = options.outputStandaloneFunctions ? "" : ",";
2644
2657
  // create the create function definition
2645
2658
  if (ctx.options.useExactTypes) {
2646
2659
  chunks.push((0, ts_poet_1.code) `
2647
- create<I extends ${utils.Exact}<${utils.DeepPartial}<${fullName}>, I>>(base?: I): ${fullName} {
2648
- return ${fullName}.fromPartial(base ?? ({} as any));
2649
- },
2660
+ ${(0, utils_1.messageMethodHead)(options, fullName, "create")}<I extends ${utils.Exact}<${utils.DeepPartial}<${fullName}>, I>>(base?: I): ${fullName} {
2661
+ return ${(0, utils_1.localMessageMethod)(options, fullName, "fromPartial")}(base ?? ({} as any));
2662
+ }${maybeComma}
2650
2663
  `);
2651
2664
  }
2652
2665
  else {
2653
2666
  chunks.push((0, ts_poet_1.code) `
2654
- create(base?: ${utils.DeepPartial}<${fullName}>): ${fullName} {
2655
- return ${fullName}.fromPartial(base ?? {});
2656
- },
2667
+ ${(0, utils_1.messageMethodHead)(options, fullName, "create")}(base?: ${utils.DeepPartial}<${fullName}>): ${fullName} {
2668
+ return ${(0, utils_1.localMessageMethod)(options, fullName, "fromPartial")}(base ?? {});
2669
+ }${maybeComma}
2657
2670
  `);
2658
2671
  }
2659
2672
  // create the fromPartial function declaration
2660
2673
  const paramName = messageDesc.field.length > 0 ? "object" : "_";
2661
2674
  if (ctx.options.useExactTypes) {
2662
2675
  chunks.push((0, ts_poet_1.code) `
2663
- fromPartial<I extends ${utils.Exact}<${utils.DeepPartial}<${fullName}>, I>>(${paramName}: I): ${fullName} {
2676
+ ${(0, utils_1.messageMethodHead)(options, fullName, "fromPartial")}<I extends ${utils.Exact}<${utils.DeepPartial}<${fullName}>, I>>(${paramName}: I): ${fullName} {
2664
2677
  `);
2665
2678
  }
2666
2679
  else {
2667
2680
  chunks.push((0, ts_poet_1.code) `
2668
- fromPartial(${paramName}: ${utils.DeepPartial}<${fullName}>): ${fullName} {
2681
+ ${(0, utils_1.messageMethodHead)(options, fullName, "fromPartial")}(${paramName}: ${utils.DeepPartial}<${fullName}>): ${fullName} {
2669
2682
  `);
2670
2683
  }
2671
2684
  let createBase = (0, ts_poet_1.code) `createBase${fullName}()`;
@@ -2745,16 +2758,14 @@ function generateFromPartial(ctx, fullName, messageDesc) {
2745
2758
  return (0, ts_poet_1.code) `${from}`;
2746
2759
  }
2747
2760
  else {
2748
- const type = (0, types_1.basicTypeName)(ctx, valueField);
2749
- return (0, ts_poet_1.code) `${type}.fromPartial(${from})`;
2761
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, valueField.typeName, "fromPartial")}(${from})`;
2750
2762
  }
2751
2763
  }
2752
2764
  else if ((0, types_1.isAnyValueType)(field)) {
2753
2765
  return (0, ts_poet_1.code) `${from}`;
2754
2766
  }
2755
2767
  else {
2756
- const type = (0, types_1.basicTypeName)(ctx, field);
2757
- return (0, ts_poet_1.code) `${type}.fromPartial(${from})`;
2768
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, field.typeName, "fromPartial")}(${from})`;
2758
2769
  }
2759
2770
  }
2760
2771
  else {
@@ -69,6 +69,7 @@ export type Options = {
69
69
  outputDecodeIncludeTypes: string;
70
70
  outputJsonMethods: true | false | "to-only" | "from-only";
71
71
  outputPartialMethods: boolean;
72
+ outputStandaloneFunctions: boolean;
72
73
  outputTypeAnnotations: boolean | "static-only" | "optional";
73
74
  outputTypeRegistry: boolean;
74
75
  stringEnums: boolean;
@@ -83,7 +84,7 @@ export type Options = {
83
84
  useNestjsFqnServiceName: boolean;
84
85
  returnObservable: boolean;
85
86
  lowerCaseServiceMethods: boolean;
86
- nestJs: boolean;
87
+ nestJs: Array<"client" | "server">;
87
88
  env: EnvOption;
88
89
  unrecognizedEnum: boolean;
89
90
  unrecognizedEnumName: string;
@@ -86,6 +86,7 @@ function defaultOptions() {
86
86
  outputDecodeIncludeTypes: "",
87
87
  outputJsonMethods: true,
88
88
  outputPartialMethods: true,
89
+ outputStandaloneFunctions: false,
89
90
  outputTypeAnnotations: false,
90
91
  outputTypeRegistry: false,
91
92
  stringEnums: false,
@@ -99,7 +100,7 @@ function defaultOptions() {
99
100
  metadataType: undefined,
100
101
  addNestjsRestParameter: false,
101
102
  useNestjsFqnServiceName: false,
102
- nestJs: false,
103
+ nestJs: [],
103
104
  env: EnvOption.BOTH,
104
105
  unrecognizedEnum: true,
105
106
  unrecognizedEnumName: "UNRECOGNIZED",
@@ -161,17 +162,32 @@ function optionsFromParameter(parameter) {
161
162
  }
162
163
  Object.assign(options, parsed);
163
164
  }
165
+ // Treat nestJs=true as both the client & server interfaces, and nestJs=false as neither
166
+ if (options.nestJs === true) {
167
+ options.nestJs = ["client", "server"];
168
+ }
169
+ else if (options.nestJs === false) {
170
+ options.nestJs = [];
171
+ }
172
+ else if (typeof options.nestJs === "string") {
173
+ options.nestJs = [options.nestJs];
174
+ }
175
+ for (const value of options.nestJs) {
176
+ if (value !== "client" && value !== "server") {
177
+ throw new Error(`nestJs must be true, false, client, or server, but got '${value}'`);
178
+ }
179
+ }
164
180
  // onlyTypes=true implies outputJsonMethods=false,outputEncodeMethods=false,outputClientImpl=false,nestJs=false
165
181
  if (options.onlyTypes) {
166
182
  options.outputJsonMethods = false;
167
183
  options.outputEncodeMethods = false;
168
184
  options.outputClientImpl = false;
169
- options.nestJs = false;
185
+ options.nestJs = [];
170
186
  }
171
187
  else if (!options.outputJsonMethods &&
172
188
  !options.outputEncodeMethods &&
173
189
  !options.outputClientImpl &&
174
- !options.nestJs) {
190
+ options.nestJs.length === 0) {
175
191
  options.onlyTypes = true;
176
192
  }
177
193
  // Treat forceLong=true as LONG
@@ -188,11 +204,11 @@ function optionsFromParameter(parameter) {
188
204
  }
189
205
  // Assume the user wants the default service output, unless they're using nestJs, which has
190
206
  // its own controllers output (although nestjs users can ask for other services too).
191
- if (options.outputServices.length == 0 && !options.nestJs) {
207
+ if (options.outputServices.length == 0 && options.nestJs.length === 0) {
192
208
  options.outputServices = [ServiceOption.DEFAULT];
193
209
  }
194
210
  // If using nestJs + other services, add the encode methods back
195
- if (options.nestJs && options.outputServices.length > 0) {
211
+ if (options.nestJs.length > 0 && options.outputServices.length > 0) {
196
212
  options.outputEncodeMethods = true;
197
213
  }
198
214
  // Handle outputSchema=true
@@ -241,7 +257,7 @@ function optionsFromParameter(parameter) {
241
257
  options.useDate = DateOption.STRING;
242
258
  }
243
259
  }
244
- if (options.nestJs) {
260
+ if (options.nestJs.length > 0) {
245
261
  options.initializeFieldsAsUndefined = false;
246
262
  }
247
263
  else {
@@ -262,6 +278,14 @@ function optionsFromParameter(parameter) {
262
278
  // Make sure to cast number options to an actual number
263
279
  options.unrecognizedEnumValue = Number(options.unrecognizedEnumValue);
264
280
  }
281
+ if (options.outputStandaloneFunctions &&
282
+ (options.outputTypeRegistry ||
283
+ options.outputTypeAnnotations === "static-only" ||
284
+ options.outputServices.includes(ServiceOption.GENERIC) ||
285
+ options.nestJs.length > 0 ||
286
+ options.useMongoObjectId)) {
287
+ throw new Error("outputStandaloneFunctions=true can't be used with outputTypeRegistry=true, outputTypeAnnotations=static-only, outputServices=generic-definitions, nestJs=true, or useMongoObjectId=true");
288
+ }
265
289
  return options;
266
290
  }
267
291
  // A very naive parse function, eventually could/should use iots/runtypes
@@ -61,7 +61,7 @@ function generateSchema(ctx, fileDesc, sourceInfo) {
61
61
  references.push((0, ts_poet_1.code) `'.${(0, utils_1.maybePrefixPackage)(fileDesc, localName.replace(/_/g, "."))}': ${symbol}`);
62
62
  }
63
63
  (0, visit_1.visit)(fileDesc, sourceInfo, (fullName) => {
64
- if (options.outputEncodeMethods) {
64
+ if (options.outputEncodeMethods && !options.outputStandaloneFunctions) {
65
65
  addReference(fullName, fullName);
66
66
  }
67
67
  }, options, (fullName) => {
@@ -147,7 +147,7 @@ function generateSchema(ctx, fileDesc, sourceInfo) {
147
147
  }
148
148
  function getExtensionValue(ctx, extension, data) {
149
149
  if (extension.type == ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_MESSAGE) {
150
- const typeName = (0, types_1.basicTypeName)(ctx, extension);
150
+ const decode = (0, types_1.getMessageMethod)(ctx, extension.typeName, "decode");
151
151
  const resultBuffer = Buffer.concat(data.map((d) => {
152
152
  // Skip length byte
153
153
  const bytes = new wire_1.BinaryReader(d).bytes();
@@ -157,7 +157,7 @@ function getExtensionValue(ctx, extension, data) {
157
157
  const encoded = ctx.options.env === options_1.EnvOption.NODE
158
158
  ? (0, ts_poet_1.code) `Buffer.from('${result}', 'base64')`
159
159
  : (0, ts_poet_1.code) `${ctx.utils.bytesFromBase64}("${result}")`;
160
- return (0, ts_poet_1.code) `'${extension.name}': ${typeName}.decode(${encoded})`;
160
+ return (0, ts_poet_1.code) `'${extension.name}': ${decode}(${encoded})`;
161
161
  }
162
162
  else {
163
163
  const reader = new wire_1.BinaryReader(data[0]);
@@ -59,6 +59,7 @@ export declare function messageToTypeName(ctx: Context, protoType: string, typeO
59
59
  repeated?: boolean;
60
60
  }): Code;
61
61
  export declare function getEnumMethod(ctx: Context, enumProtoType: string, methodSuffix: string): Import;
62
+ export declare function getMessageMethod(ctx: Context, messageProtoType: string, method: string): Code;
62
63
  /** Return the TypeName for any field (primitive/message/etc.) as exposed in the interface. */
63
64
  export declare function toTypeName(ctx: Context, messageDesc: DescriptorProto | undefined, field: FieldDescriptorProto, ensureOptional?: boolean): Code;
64
65
  /**
@@ -41,6 +41,7 @@ exports.valueTypeName = valueTypeName;
41
41
  exports.wrapperTypeName = wrapperTypeName;
42
42
  exports.messageToTypeName = messageToTypeName;
43
43
  exports.getEnumMethod = getEnumMethod;
44
+ exports.getMessageMethod = getMessageMethod;
44
45
  exports.toTypeName = toTypeName;
45
46
  exports.shouldGenerateJSMapType = shouldGenerateJSMapType;
46
47
  exports.detectMapType = detectMapType;
@@ -645,8 +646,8 @@ function messageToTypeName(ctx, protoType, typeOptions = {}) {
645
646
  if (!typeOptions.keepValueType && options.useMongoObjectId && protoType.endsWith(".ObjectId")) {
646
647
  return (0, ts_poet_1.code) `mongodb.ObjectId`;
647
648
  }
648
- const [module, type] = toModuleAndType(typeMap, protoType);
649
- return (0, ts_poet_1.code) `${(0, utils_1.impProto)(options, module, type)}`;
649
+ const [module, type, descriptor] = toModuleAndType(typeMap, protoType);
650
+ return (0, ts_poet_1.code) `${(0, utils_1.impProto)(options, module, type, options.outputStandaloneFunctions && "field" in descriptor)}`;
650
651
  }
651
652
  /** Breaks `.some_proto_namespace.Some.Message` into `['some_proto_namespace', 'Some_Message', Descriptor]. */
652
653
  function toModuleAndType(typeMap, protoType) {
@@ -656,6 +657,10 @@ function getEnumMethod(ctx, enumProtoType, methodSuffix) {
656
657
  const [module, type] = toModuleAndType(ctx.typeMap, enumProtoType);
657
658
  return (0, utils_1.impProto)(ctx.options, module, `${(0, case_1.uncapitalize)(type)}${methodSuffix}`);
658
659
  }
660
+ function getMessageMethod(ctx, messageProtoType, method) {
661
+ const [module, type] = toModuleAndType(ctx.typeMap, messageProtoType);
662
+ return (0, utils_1.impProtoMethod)(ctx.options, module, type, method);
663
+ }
659
664
  /** Return the TypeName for any field (primitive/message/etc.) as exposed in the interface. */
660
665
  function toTypeName(ctx, messageDesc, field, ensureOptional = false) {
661
666
  function finalize(type, isOptional) {
@@ -65,7 +65,11 @@ export declare function safeAccessor(propertyName: string): string;
65
65
  */
66
66
  export declare function getPropertyAccessor(objectName: string, propertyName: string, optional?: boolean): string;
67
67
  export declare function impFile(options: Options, spec: string): Import;
68
- export declare function impProto(options: Options, module: string, type: string): Import;
68
+ export declare function impProto(options: Options, module: string, type: string, typeOnly?: boolean): Import;
69
+ export declare function messageFunctionName(type: string, method: string): string;
70
+ export declare function impProtoMethod(options: Options, module: string, type: string, method: string): Code;
71
+ export declare function localMessageMethod(options: Options, type: string, method: string): string;
72
+ export declare function messageMethodHead(options: Options, type: string, method: string, isAsyncGenerator?: boolean): Code;
69
73
  export declare function tryCatchBlock(tryBlock: Code | string, handleErrorBlock: Code | string): Code;
70
74
  export declare function arrowFunction(params: string, body: Code | string, isOneLine?: boolean): Code;
71
75
  export declare function nullOrUndefined(options: Pick<Options, "useNullAsOptional">, hasProto3Optional?: boolean): string;
@@ -17,6 +17,10 @@ exports.safeAccessor = safeAccessor;
17
17
  exports.getPropertyAccessor = getPropertyAccessor;
18
18
  exports.impFile = impFile;
19
19
  exports.impProto = impProto;
20
+ exports.messageFunctionName = messageFunctionName;
21
+ exports.impProtoMethod = impProtoMethod;
22
+ exports.localMessageMethod = localMessageMethod;
23
+ exports.messageMethodHead = messageMethodHead;
20
24
  exports.tryCatchBlock = tryCatchBlock;
21
25
  exports.arrowFunction = arrowFunction;
22
26
  exports.nullOrUndefined = nullOrUndefined;
@@ -243,14 +247,32 @@ function getPropertyAccessor(objectName, propertyName, optional = false) {
243
247
  function impFile(options, spec) {
244
248
  return (0, ts_poet_1.imp)(`${spec}${options.importSuffix}`);
245
249
  }
246
- function impProto(options, module, type) {
247
- const prefix = options.onlyTypes ? "t:" : "";
250
+ function impProto(options, module, type, typeOnly = false) {
251
+ const prefix = options.onlyTypes || typeOnly ? "t:" : "";
248
252
  const protoFile = `${module}.proto`;
249
253
  if (options.M[protoFile]) {
250
254
  return (0, ts_poet_1.imp)(`${prefix}${type}@${options.M[protoFile]}`);
251
255
  }
252
256
  return (0, ts_poet_1.imp)(`${prefix}${type}@./${module}${options.fileSuffix}${options.importSuffix}`);
253
257
  }
258
+ function messageFunctionName(type, method) {
259
+ return (0, case_1.uncapitalize)(type) + (0, case_1.capitalize)(method);
260
+ }
261
+ function impProtoMethod(options, module, type, method) {
262
+ if (options.outputStandaloneFunctions) {
263
+ return (0, ts_poet_1.code) `${impProto(options, module, messageFunctionName(type, method))}`;
264
+ }
265
+ return (0, ts_poet_1.code) `${impProto(options, module, type)}.${method}`;
266
+ }
267
+ function localMessageMethod(options, type, method) {
268
+ return options.outputStandaloneFunctions ? messageFunctionName(type, method) : `${type}.${method}`;
269
+ }
270
+ function messageMethodHead(options, type, method, isAsyncGenerator = false) {
271
+ if (options.outputStandaloneFunctions) {
272
+ return (0, ts_poet_1.code) `export ${isAsyncGenerator ? "async function*" : "function"} ${(0, ts_poet_1.def)(messageFunctionName(type, method))}`;
273
+ }
274
+ return (0, ts_poet_1.code) `${isAsyncGenerator ? "async *" : ""}${method}`;
275
+ }
254
276
  function tryCatchBlock(tryBlock, handleErrorBlock) {
255
277
  return (0, ts_poet_1.code) `try {
256
278
  ${tryBlock}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-proto",
3
- "version": "2.18.6",
3
+ "version": "2.20.0",
4
4
  "description": "",
5
5
  "main": "build/src/plugin.js",
6
6
  "repository": "github:stephenh/ts-proto",