ts-proto 2.18.5 → 2.19.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.
@@ -493,7 +499,7 @@ With `--ts_proto_opt=protoJsonFormat=false`, strict proto3 compliance is disable
493
499
 
494
500
  - With `--ts_proto_opt=outputTypeAnnotations=true`, each message will be given a `$type` field containing its fully-qualified name. You can use `--ts_proto_opt=outputTypeAnnotations=static-only` to omit it from the `interface` declaration, or `--ts_proto_opt=outputTypeAnnotations=optional` to make it an optional property on the `interface` definition. The latter option may be useful if you want to use the `$type` field for runtime type checking on responses from a server.
495
501
 
496
- - With `--ts_proto_opt=outputTypeRegistry=true`, the type registry will be generated that can be used to resolve message types by fully-qualified name. Also, each message will be given a `$type` field containing its fully-qualified name.
502
+ - With `--ts_proto_opt=outputTypeRegistry=true`, the type registry will be generated that can be used to resolve message types by fully-qualified name. Also, each message will be given a `$type` field containing its fully-qualified name. The registry's `MessageType` only declares the methods that are generated, so it also works with options like `outputEncodeMethods=encode-only` or `outputJsonMethods=to-only`.
497
503
 
498
504
  - With `--ts_proto_opt=outputServices=grpc-js`, ts-proto will output service definitions and server / client stubs in [grpc-js](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js) format.
499
505
 
@@ -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
  }
@@ -33,14 +33,25 @@ function generateMessageType(ctx) {
33
33
  else {
34
34
  chunks.push((0, ts_poet_1.code) `$type: string;`);
35
35
  }
36
- if (ctx.options.outputEncodeMethods) {
37
- const BinaryReader = (0, ts_poet_1.imp)("t:BinaryReader@@bufbuild/protobuf/wire");
38
- const BinaryWriter = (0, ts_poet_1.imp)("t:BinaryWriter@@bufbuild/protobuf/wire");
36
+ // Only declare the methods that are actually generated on each message, e.g. with
37
+ // `outputJsonMethods=to-only` the messages have no `fromJSON` to register.
38
+ const { outputEncodeMethods, outputJsonMethods } = ctx.options;
39
+ const hasEncode = outputEncodeMethods === true ||
40
+ outputEncodeMethods === "encode-only" ||
41
+ outputEncodeMethods === "encode-no-creation";
42
+ const hasDecode = outputEncodeMethods === true || outputEncodeMethods === "decode-only";
43
+ const BinaryReader = (0, ts_poet_1.imp)("t:BinaryReader@@bufbuild/protobuf/wire");
44
+ const BinaryWriter = (0, ts_poet_1.imp)("t:BinaryWriter@@bufbuild/protobuf/wire");
45
+ if (hasEncode) {
39
46
  chunks.push((0, ts_poet_1.code) `encode(message: Message, writer?: ${BinaryWriter}): ${BinaryWriter};`);
47
+ }
48
+ if (hasDecode) {
40
49
  chunks.push((0, ts_poet_1.code) `decode(input: ${BinaryReader} | Uint8Array, length?: number): Message;`);
41
50
  }
42
- if (ctx.options.outputJsonMethods) {
51
+ if (outputJsonMethods === true || outputJsonMethods === "from-only") {
43
52
  chunks.push((0, ts_poet_1.code) `fromJSON(object: any): Message;`);
53
+ }
54
+ if (outputJsonMethods === true || outputJsonMethods === "to-only") {
44
55
  chunks.push((0, ts_poet_1.code) `toJSON(message: Message): unknown;`);
45
56
  }
46
57
  if (ctx.options.outputPartialMethods) {
package/build/src/main.js CHANGED
@@ -103,13 +103,18 @@ function generateFile(ctx, fileDesc) {
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") {
@@ -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(", ");
@@ -694,7 +702,7 @@ function makeObjectIdMethods() {
694
702
  return { fromJsonObjectId, fromProtoObjectId, toProtoObjectId };
695
703
  }
696
704
  function makeTimestampMethods(options, longs, bytes) {
697
- const Timestamp = (0, utils_1.impProto)(options, "google/protobuf/timestamp", (0, utils_1.wrapTypeName)(options, "Timestamp"));
705
+ const Timestamp = (0, utils_1.impProto)(options, "google/protobuf/timestamp", (0, utils_1.wrapTypeName)(options, "Timestamp"), options.outputStandaloneFunctions);
698
706
  const NanoDate = (0, ts_poet_1.imp)("NanoDate=nano-date");
699
707
  let seconds = "Math.trunc(date.getTime() / 1_000)";
700
708
  let toNumberCode = "t.seconds";
@@ -800,6 +808,7 @@ function makeTimestampMethods(options, longs, bytes) {
800
808
  `);
801
809
  // Declared once per file, so the regex isn't compiled on each fromJsonTimestamp call
802
810
  const timestampFractionRegex = (0, ts_poet_1.conditionalOutput)("timestampFractionRegex", (0, ts_poet_1.code) `const timestampFractionRegex = /:\\d{2}\\.\\d+/;`);
811
+ const timestampMessageFromJson = (0, utils_1.impProtoMethod)(options, "google/protobuf/timestamp", (0, utils_1.wrapTypeName)(options, "Timestamp"), "fromJSON");
803
812
  const fromJsonTimestamp = (0, ts_poet_1.conditionalOutput)("fromJsonTimestamp", options.useDate === options_1.DateOption.DATE
804
813
  ? (0, ts_poet_1.code) `
805
814
  function fromJsonTimestamp(o: any): Date {
@@ -808,7 +817,7 @@ function makeTimestampMethods(options, longs, bytes) {
808
817
  } else if (typeof o === "string") {
809
818
  return new ${bytes.globalThis}.Date(o);
810
819
  } else {
811
- return ${fromTimestamp}(${(0, utils_1.wrapTypeName)(options, "Timestamp")}.fromJSON(o));
820
+ return ${fromTimestamp}(${timestampMessageFromJson}(o));
812
821
  }
813
822
  }
814
823
  `
@@ -820,7 +829,7 @@ function makeTimestampMethods(options, longs, bytes) {
820
829
  } else if (typeof o === "string") {
821
830
  return ${bytes.globalThis}.Temporal.Instant.from(o);
822
831
  } else {
823
- return ${fromTimestamp}(${(0, utils_1.wrapTypeName)(options, "Timestamp")}.fromJSON(o));
832
+ return ${fromTimestamp}(${timestampMessageFromJson}(o));
824
833
  }
825
834
  }
826
835
  `
@@ -842,7 +851,7 @@ function makeTimestampMethods(options, longs, bytes) {
842
851
  );
843
852
  return { ...timestamp, nanos: (timestamp.nanos ?? 0) + (fractionNanos % 1_000_000) };
844
853
  } else {
845
- return ${options.typePrefix}Timestamp${options.typeSuffix}.fromJSON(o);
854
+ return ${timestampMessageFromJson}(o);
846
855
  }
847
856
  }
848
857
  `);
@@ -1123,14 +1132,13 @@ function getDecodeReadSnippet(ctx, field) {
1123
1132
  }
1124
1133
  }
1125
1134
  else if ((0, types_1.isValueType)(ctx, field)) {
1126
- const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
1127
1135
  const unwrap = (decodedValue) => {
1128
1136
  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})`;
1137
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, field.typeName, "unwrap")}(${decodedValue})`;
1130
1138
  }
1131
1139
  return (0, ts_poet_1.code) `${decodedValue}.value`;
1132
1140
  };
1133
- const decoder = (0, ts_poet_1.code) `${type}.decode(reader, reader.uint32())`;
1141
+ const decoder = (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, field.typeName, "decode")}(reader, reader.uint32())`;
1134
1142
  readSnippet = (0, ts_poet_1.code) `${unwrap(decoder)}`;
1135
1143
  }
1136
1144
  else if ((0, types_1.isTimestamp)(field) &&
@@ -1138,20 +1146,20 @@ function getDecodeReadSnippet(ctx, field) {
1138
1146
  options.useDate === options_1.DateOption.STRING ||
1139
1147
  options.useDate === options_1.DateOption.STRING_NANO ||
1140
1148
  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()))`;
1149
+ const decode = (0, types_1.getMessageMethod)(ctx, field.typeName, "decode");
1150
+ readSnippet = (0, ts_poet_1.code) `${utils.fromTimestamp}(${decode}(reader, reader.uint32()))`;
1143
1151
  }
1144
1152
  else if ((0, types_1.isObjectId)(field) && options.useMongoObjectId) {
1145
1153
  const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
1146
1154
  readSnippet = (0, ts_poet_1.code) `${utils.fromProtoObjectId}(${type}.decode(reader, reader.uint32()))`;
1147
1155
  }
1148
1156
  else if ((0, types_1.isMessage)(field)) {
1149
- const type = (0, types_1.basicTypeName)(ctx, field);
1157
+ const decode = (0, types_1.getMessageMethod)(ctx, field.typeName, "decode");
1150
1158
  if (field.type == ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_GROUP) {
1151
- readSnippet = (0, ts_poet_1.code) `${type}.decode(reader)`;
1159
+ readSnippet = (0, ts_poet_1.code) `${decode}(reader)`;
1152
1160
  }
1153
1161
  else {
1154
- readSnippet = (0, ts_poet_1.code) `${type}.decode(reader, reader.uint32())`;
1162
+ readSnippet = (0, ts_poet_1.code) `${decode}(reader, reader.uint32())`;
1155
1163
  }
1156
1164
  }
1157
1165
  else {
@@ -1159,10 +1167,10 @@ function getDecodeReadSnippet(ctx, field) {
1159
1167
  }
1160
1168
  return readSnippet;
1161
1169
  }
1162
- function generateEmptyDecode(fullName) {
1170
+ function generateEmptyDecode(ctx, fullName) {
1163
1171
  const BinaryReader = (0, ts_poet_1.imp)("t:BinaryReader@@bufbuild/protobuf/wire");
1164
1172
  return (0, ts_poet_1.code) `
1165
- decode(
1173
+ ${(0, utils_1.messageMethodHead)(ctx.options, fullName, "decode")}(
1166
1174
  _: ${BinaryReader} | Uint8Array,
1167
1175
  length?: number,
1168
1176
  ): ${fullName} {
@@ -1181,7 +1189,7 @@ function generateDecode(ctx, fullName, messageDesc) {
1181
1189
  const BinaryReader = (0, ts_poet_1.imp)("BinaryReader@@bufbuild/protobuf/wire");
1182
1190
  // create the basic function declaration
1183
1191
  chunks.push((0, ts_poet_1.code) `
1184
- decode(
1192
+ ${(0, utils_1.messageMethodHead)(options, fullName, "decode")}(
1185
1193
  input: ${BinaryReader} | Uint8Array,
1186
1194
  length?: number,
1187
1195
  ): ${fullName} {
@@ -1411,38 +1419,38 @@ function getEncodeWriteSnippet(ctx, field) {
1411
1419
  options.useDate === options_1.DateOption.STRING_NANO ||
1412
1420
  options.useDate === options_1.DateOption.TEMPORAL)) {
1413
1421
  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()`;
1422
+ const encode = (0, types_1.getMessageMethod)(ctx, field.typeName, "encode");
1423
+ return (place) => (0, ts_poet_1.code) `${encode}(${utils.toTimestamp}(${place}), writer.uint32(${tag}).fork()).join()`;
1416
1424
  }
1417
1425
  else if ((0, types_1.isValueType)(ctx, field)) {
1418
1426
  const maybeTypeField = (0, options_1.addTypeToMessages)(options) ? `$type: '${field.typeName.slice(1)}',` : "";
1419
- const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
1427
+ const encode = (0, types_1.getMessageMethod)(ctx, field.typeName, "encode");
1420
1428
  const wrappedValue = (place) => {
1421
1429
  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})`;
1430
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, field.typeName, "wrap")}(${place})`;
1423
1431
  }
1424
1432
  return (0, ts_poet_1.code) `{${maybeTypeField} value: ${place}!}`;
1425
1433
  };
1426
1434
  const tag = ((field.number << 3) | 2) >>> 0;
1427
- return (place) => (0, ts_poet_1.code) `${type}.encode(${wrappedValue(place)}, writer.uint32(${tag}).fork()).join()`;
1435
+ return (place) => (0, ts_poet_1.code) `${encode}(${wrappedValue(place)}, writer.uint32(${tag}).fork()).join()`;
1428
1436
  }
1429
1437
  else if ((0, types_1.isMessage)(field)) {
1430
- const type = (0, types_1.basicTypeName)(ctx, field);
1438
+ const encode = (0, types_1.getMessageMethod)(ctx, field.typeName, "encode");
1431
1439
  if (field.type == ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_GROUP) {
1432
1440
  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})`;
1441
+ return (place) => (0, ts_poet_1.code) `${encode}(${place}, writer.uint32(${startTag})).uint32(${endTag})`;
1434
1442
  }
1435
1443
  const tag = ((field.number << 3) | 2) >>> 0;
1436
- return (place) => (0, ts_poet_1.code) `${type}.encode(${place}, writer.uint32(${tag}).fork()).join()`;
1444
+ return (place) => (0, ts_poet_1.code) `${encode}(${place}, writer.uint32(${tag}).fork()).join()`;
1437
1445
  }
1438
1446
  else {
1439
1447
  throw new Error(`Unhandled field ${field}`);
1440
1448
  }
1441
1449
  }
1442
- function generateEmptyEncode(fullName) {
1450
+ function generateEmptyEncode(ctx, fullName) {
1443
1451
  const BinaryWriter = (0, ts_poet_1.imp)("BinaryWriter@@bufbuild/protobuf/wire");
1444
1452
  return (0, ts_poet_1.code) `
1445
- encode(
1453
+ ${(0, utils_1.messageMethodHead)(ctx.options, fullName, "encode")}(
1446
1454
  _: ${fullName},
1447
1455
  writer: ${BinaryWriter} = new ${BinaryWriter}(),
1448
1456
  ): ${BinaryWriter} {
@@ -1457,7 +1465,7 @@ function generateEncode(ctx, fullName, messageDesc) {
1457
1465
  const BinaryWriter = (0, ts_poet_1.imp)("BinaryWriter@@bufbuild/protobuf/wire");
1458
1466
  // create the basic function declaration
1459
1467
  chunks.push((0, ts_poet_1.code) `
1460
- encode(
1468
+ ${(0, utils_1.messageMethodHead)(options, fullName, "encode")}(
1461
1469
  ${messageDesc.field.length > 0 || options.unknownFields ? "message" : "_"}: ${fullName},
1462
1470
  writer: ${BinaryWriter} = new ${BinaryWriter}(),
1463
1471
  ): ${BinaryWriter} {
@@ -1673,7 +1681,7 @@ function generateEncode(ctx, fullName, messageDesc) {
1673
1681
  }
1674
1682
  function generateSetExtension(ctx, fullName) {
1675
1683
  return (0, ts_poet_1.code) `
1676
- setExtension <T> (message: ${fullName}, extension: ${ctx.utils.Extension}<T>, value: T): void {
1684
+ ${(0, utils_1.messageMethodHead)(ctx.options, fullName, "setExtension")} <T> (message: ${fullName}, extension: ${ctx.utils.Extension}<T>, value: T): void {
1677
1685
  const encoded = extension.encode!(value);
1678
1686
 
1679
1687
  if (message._unknownFields !== undefined) {
@@ -1699,7 +1707,7 @@ function generateSetExtension(ctx, fullName) {
1699
1707
  }
1700
1708
  function generateGetExtension(ctx, fullName) {
1701
1709
  return (0, ts_poet_1.code) `
1702
- getExtension <T> (message: ${fullName}, extension: ${ctx.utils.Extension}<T>): T | undefined {
1710
+ ${(0, utils_1.messageMethodHead)(ctx.options, fullName, "getExtension")} <T> (message: ${fullName}, extension: ${ctx.utils.Extension}<T>): T | undefined {
1703
1711
  let results: T | undefined = undefined;
1704
1712
 
1705
1713
  if (message._unknownFields === undefined) {
@@ -1787,27 +1795,27 @@ function generateExtension(ctx, message, extension) {
1787
1795
  options.useDate === options_1.DateOption.STRING ||
1788
1796
  options.useDate === options_1.DateOption.STRING_NANO ||
1789
1797
  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()`;
1798
+ const encode = (0, types_1.getMessageMethod)(ctx, field.typeName, "encode");
1799
+ return (place) => (0, ts_poet_1.code) `${encode}(${utils.toTimestamp}(${place}), writer.fork()).join()`;
1792
1800
  }
1793
1801
  else if ((0, types_1.isValueType)(ctx, field)) {
1794
1802
  const maybeTypeField = (0, options_1.addTypeToMessages)(options) ? `$type: '${field.typeName.slice(1)}',` : "";
1795
- const type = (0, types_1.basicTypeName)(ctx, field, { keepValueType: true });
1803
+ const encode = (0, types_1.getMessageMethod)(ctx, field.typeName, "encode");
1796
1804
  const wrappedValue = (place) => {
1797
1805
  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})`;
1806
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, field.typeName, "wrap")}(${place})`;
1799
1807
  }
1800
1808
  return (0, ts_poet_1.code) `{${maybeTypeField} value: ${place}!}`;
1801
1809
  };
1802
- return (place) => (0, ts_poet_1.code) `${type}.encode(${wrappedValue(place)}, writer.fork()).join()`;
1810
+ return (place) => (0, ts_poet_1.code) `${encode}(${wrappedValue(place)}, writer.fork()).join()`;
1803
1811
  }
1804
1812
  else if ((0, types_1.isMessage)(field)) {
1805
- const type = (0, types_1.basicTypeName)(ctx, field);
1813
+ const encode = (0, types_1.getMessageMethod)(ctx, field.typeName, "encode");
1806
1814
  if (field.type == ts_proto_descriptors_1.FieldDescriptorProto_Type.TYPE_GROUP) {
1807
1815
  const endTag = ((field.number << 3) | 4) >>> 0;
1808
- return (place) => (0, ts_poet_1.code) `${type}.encode(${place}, writer).uint32(${endTag})`;
1816
+ return (place) => (0, ts_poet_1.code) `${encode}(${place}, writer).uint32(${endTag})`;
1809
1817
  }
1810
- return (place) => (0, ts_poet_1.code) `${type}.encode(${place}, writer.fork()).join()`;
1818
+ return (place) => (0, ts_poet_1.code) `${encode}(${place}, writer.fork()).join()`;
1811
1819
  }
1812
1820
  else {
1813
1821
  throw new Error(`Unhandled field ${field}`);
@@ -1962,7 +1970,7 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1962
1970
  break;
1963
1971
  }
1964
1972
  return (0, ts_poet_1.code) `
1965
- fromJSON(object: string): ${fullName} {
1973
+ ${(0, utils_1.messageMethodHead)(options, fullName, "fromJSON")}(object: string): ${fullName} {
1966
1974
  if (!object.endsWith("s")) throw new Error("Invalid duration string");
1967
1975
  const body = object.slice(0, -1);
1968
1976
  const negative = body.startsWith("-");
@@ -1982,21 +1990,21 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
1982
1990
  if (fullTypeName === "google.protobuf.Timestamp") {
1983
1991
  // The canonical JSON of a Timestamp is an RFC 3339 string; the object form is still accepted.
1984
1992
  chunks.push((0, ts_poet_1.code) `
1985
- fromJSON(object: any): ${fullName} {
1993
+ ${(0, utils_1.messageMethodHead)(options, fullName, "fromJSON")}(object: any): ${fullName} {
1986
1994
  if (typeof object === "string") {
1987
- return ${fullName}.fromJSON(${utils.timestampFromJson}(object));
1995
+ return ${(0, utils_1.localMessageMethod)(options, fullName, "fromJSON")}(${utils.timestampFromJson}(object));
1988
1996
  }
1989
1997
  return {
1990
1998
  `);
1991
1999
  }
1992
2000
  else {
1993
2001
  chunks.push((0, ts_poet_1.code) `
1994
- fromJSON(${messageDesc.field.length > 0 ? "object" : "_"}: any): ${fullName} {
2002
+ ${(0, utils_1.messageMethodHead)(options, fullName, "fromJSON")}(${messageDesc.field.length > 0 ? "object" : "_"}: any): ${fullName} {
1995
2003
  return {
1996
2004
  `);
1997
2005
  }
1998
2006
  if ((0, options_1.addTypeToMessages)(options)) {
1999
- chunks.push((0, ts_poet_1.code) `$type: ${fullName}.$type,`);
2007
+ chunks.push(options.outputStandaloneFunctions ? (0, ts_poet_1.code) `$type: '${fullTypeName}',` : (0, ts_poet_1.code) `$type: ${fullName}.$type,`);
2000
2008
  }
2001
2009
  const oneofFieldsCases = messageDesc.oneofDecl.map((oneof, oneofIndex) => messageDesc.field.filter(types_1.isWithinOneOf).filter((field) => field.oneofIndex === oneofIndex));
2002
2010
  const canonicalFromJson = {
@@ -2065,8 +2073,9 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
2065
2073
  return (0, ts_poet_1.code) `${from}`;
2066
2074
  }
2067
2075
  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}))`;
2076
+ const unwrap = (0, types_1.getMessageMethod)(ctx, field.typeName, "unwrap");
2077
+ const fromJson = (0, types_1.getMessageMethod)(ctx, field.typeName, "fromJSON");
2078
+ return (0, ts_poet_1.code) `${unwrap}(${fromJson}(${from}))`;
2070
2079
  }
2071
2080
  else if ((0, types_1.isListValueType)(field)) {
2072
2081
  return (0, ts_poet_1.code) `[...${from}]`;
@@ -2125,12 +2134,11 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
2125
2134
  return (0, ts_poet_1.code) `${from}`;
2126
2135
  }
2127
2136
  else {
2128
- return (0, ts_poet_1.code) `${valueType}.fromJSON(${from})`;
2137
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, valueField.typeName, "fromJSON")}(${from})`;
2129
2138
  }
2130
2139
  }
2131
2140
  else {
2132
- const type = (0, types_1.basicTypeName)(ctx, field);
2133
- return (0, ts_poet_1.code) `${type}.fromJSON(${from})`;
2141
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, field.typeName, "fromJSON")}(${from})`;
2134
2142
  }
2135
2143
  }
2136
2144
  else {
@@ -2300,12 +2308,13 @@ function generateFromJson(ctx, fullName, fullTypeName, messageDesc) {
2300
2308
  chunks.push((0, ts_poet_1.code) `}`);
2301
2309
  return (0, ts_poet_1.joinCode)(chunks, { on: "\n" });
2302
2310
  }
2303
- function generateCanonicalToJson(fullName, fullProtobufTypeName, { useOptionals, useNullAsOptional, useDuration, useJsonTimestamp, forceLong }, utils) {
2311
+ function generateCanonicalToJson(fullName, fullProtobufTypeName, options, utils) {
2312
+ const { useOptionals, useNullAsOptional, useDuration, useJsonTimestamp, forceLong } = options;
2304
2313
  if ((0, types_1.isFieldMaskTypeName)(fullProtobufTypeName)) {
2305
2314
  const returnType = useOptionals === "all" ? `string | ${(0, utils_1.nullOrUndefined)({ useNullAsOptional })}` : "string";
2306
2315
  const pathModifier = useOptionals === "all" ? "?" : "";
2307
2316
  return (0, ts_poet_1.code) `
2308
- toJSON(message: ${fullName}): ${returnType} {
2317
+ ${(0, utils_1.messageMethodHead)(options, fullName, "toJSON")}(message: ${fullName}): ${returnType} {
2309
2318
  return message.paths${pathModifier}.join(',');
2310
2319
  }
2311
2320
  `;
@@ -2334,7 +2343,7 @@ function generateCanonicalToJson(fullName, fullProtobufTypeName, { useOptionals,
2334
2343
  break;
2335
2344
  }
2336
2345
  return (0, ts_poet_1.code) `
2337
- toJSON(message: ${fullName}): string {
2346
+ ${(0, utils_1.messageMethodHead)(options, fullName, "toJSON")}(message: ${fullName}): string {
2338
2347
  const negative = ${isNegSeconds} || message.nanos < 0;
2339
2348
  const sign = negative ? "-" : "";
2340
2349
  const absSeconds = ${absSeconds};
@@ -2351,7 +2360,7 @@ function generateCanonicalToJson(fullName, fullProtobufTypeName, { useOptionals,
2351
2360
  ? (0, ts_poet_1.code) `message.seconds?.toNumber() ?? 0`
2352
2361
  : (0, ts_poet_1.code) `${utils.globalThis}.Number(message.seconds ?? 0)`;
2353
2362
  return (0, ts_poet_1.code) `
2354
- toJSON(message: ${fullName}): string {
2363
+ ${(0, utils_1.messageMethodHead)(options, fullName, "toJSON")}(message: ${fullName}): string {
2355
2364
  return ${utils.timestampToJson}(${seconds}, message.nanos ?? 0);
2356
2365
  }
2357
2366
  `;
@@ -2381,7 +2390,7 @@ function generateCanonicalAnyToJson(ctx, fullName, messageDesc) {
2381
2390
  const typeUrl = (0, utils_1.getPropertyAccessor)("message", (0, utils_1.getFieldName)(typeUrlField, options));
2382
2391
  const value = (0, utils_1.getPropertyAccessor)("message", (0, utils_1.getFieldName)(valueField, options));
2383
2392
  return (0, ts_poet_1.code) `
2384
- toJSON(message: ${fullName}): unknown {
2393
+ ${(0, utils_1.messageMethodHead)(options, fullName, "toJSON")}(message: ${fullName}): unknown {
2385
2394
  const typeUrl = ${typeUrl} ?? "";
2386
2395
  if (typeUrl === "") {
2387
2396
  return {};
@@ -2408,7 +2417,7 @@ function generateCanonicalAnyFromJson(ctx, fullName, messageDesc) {
2408
2417
  const typeField = (0, options_1.addTypeToMessages)(options) ? (0, ts_poet_1.code) `$type: ${fullName}.$type,` : "";
2409
2418
  const bytes = options.env === options_1.EnvOption.NODE ? (0, ts_poet_1.code) `Buffer.from(bytes)` : (0, ts_poet_1.code) `bytes`;
2410
2419
  return (0, ts_poet_1.code) `
2411
- fromJSON(object: any): ${fullName} {
2420
+ ${(0, utils_1.messageMethodHead)(options, fullName, "fromJSON")}(object: any): ${fullName} {
2412
2421
  const typeUrl = ${utils.isSet}(object?.["@type"]) ? ${utils.globalThis}.String(object["@type"]) : "";
2413
2422
  if (typeUrl === "") {
2414
2423
  return { ${typeField} ${typeUrlKey}: ${(0, types_1.defaultValue)(ctx, typeUrlField)}, ${valueKey}: ${(0, types_1.defaultValue)(ctx, valueField)} };
@@ -2442,7 +2451,7 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
2442
2451
  }
2443
2452
  // create the basic function declaration
2444
2453
  chunks.push((0, ts_poet_1.code) `
2445
- toJSON(${messageDesc.field.length > 0 ? "message" : "_"}: ${fullName}): unknown {
2454
+ ${(0, utils_1.messageMethodHead)(options, fullName, "toJSON")}(${messageDesc.field.length > 0 ? "message" : "_"}: ${fullName}): unknown {
2446
2455
  const obj: any = {};
2447
2456
  `);
2448
2457
  let currentIfTarget = "";
@@ -2528,20 +2537,19 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
2528
2537
  return (0, ts_poet_1.code) `${from}`;
2529
2538
  }
2530
2539
  else {
2531
- const type = (0, types_1.basicTypeName)(ctx, valueType);
2532
- return (0, ts_poet_1.code) `${type}.toJSON(${from})`;
2540
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, valueType.typeName, "toJSON")}(${from})`;
2533
2541
  }
2534
2542
  }
2535
2543
  else if ((0, types_1.isAnyValueType)(field)) {
2536
2544
  return (0, ts_poet_1.code) `${from}`;
2537
2545
  }
2538
2546
  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}))`;
2547
+ const toJson = (0, types_1.getMessageMethod)(ctx, field.typeName, "toJSON");
2548
+ const wrap = (0, types_1.getMessageMethod)(ctx, field.typeName, "wrap");
2549
+ return (0, ts_poet_1.code) `${toJson}(${wrap}(${from}))`;
2541
2550
  }
2542
2551
  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})`;
2552
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, field.typeName, "toJSON")}(${from})`;
2545
2553
  }
2546
2554
  else if ((0, types_1.isBytes)(field)) {
2547
2555
  return (0, ts_poet_1.code) `${utils.base64FromBytes}(${from})`;
@@ -2641,31 +2649,32 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
2641
2649
  function generateFromPartial(ctx, fullName, messageDesc) {
2642
2650
  const { options, utils } = ctx;
2643
2651
  const chunks = [];
2652
+ const maybeComma = options.outputStandaloneFunctions ? "" : ",";
2644
2653
  // create the create function definition
2645
2654
  if (ctx.options.useExactTypes) {
2646
2655
  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
- },
2656
+ ${(0, utils_1.messageMethodHead)(options, fullName, "create")}<I extends ${utils.Exact}<${utils.DeepPartial}<${fullName}>, I>>(base?: I): ${fullName} {
2657
+ return ${(0, utils_1.localMessageMethod)(options, fullName, "fromPartial")}(base ?? ({} as any));
2658
+ }${maybeComma}
2650
2659
  `);
2651
2660
  }
2652
2661
  else {
2653
2662
  chunks.push((0, ts_poet_1.code) `
2654
- create(base?: ${utils.DeepPartial}<${fullName}>): ${fullName} {
2655
- return ${fullName}.fromPartial(base ?? {});
2656
- },
2663
+ ${(0, utils_1.messageMethodHead)(options, fullName, "create")}(base?: ${utils.DeepPartial}<${fullName}>): ${fullName} {
2664
+ return ${(0, utils_1.localMessageMethod)(options, fullName, "fromPartial")}(base ?? {});
2665
+ }${maybeComma}
2657
2666
  `);
2658
2667
  }
2659
2668
  // create the fromPartial function declaration
2660
2669
  const paramName = messageDesc.field.length > 0 ? "object" : "_";
2661
2670
  if (ctx.options.useExactTypes) {
2662
2671
  chunks.push((0, ts_poet_1.code) `
2663
- fromPartial<I extends ${utils.Exact}<${utils.DeepPartial}<${fullName}>, I>>(${paramName}: I): ${fullName} {
2672
+ ${(0, utils_1.messageMethodHead)(options, fullName, "fromPartial")}<I extends ${utils.Exact}<${utils.DeepPartial}<${fullName}>, I>>(${paramName}: I): ${fullName} {
2664
2673
  `);
2665
2674
  }
2666
2675
  else {
2667
2676
  chunks.push((0, ts_poet_1.code) `
2668
- fromPartial(${paramName}: ${utils.DeepPartial}<${fullName}>): ${fullName} {
2677
+ ${(0, utils_1.messageMethodHead)(options, fullName, "fromPartial")}(${paramName}: ${utils.DeepPartial}<${fullName}>): ${fullName} {
2669
2678
  `);
2670
2679
  }
2671
2680
  let createBase = (0, ts_poet_1.code) `createBase${fullName}()`;
@@ -2745,16 +2754,14 @@ function generateFromPartial(ctx, fullName, messageDesc) {
2745
2754
  return (0, ts_poet_1.code) `${from}`;
2746
2755
  }
2747
2756
  else {
2748
- const type = (0, types_1.basicTypeName)(ctx, valueField);
2749
- return (0, ts_poet_1.code) `${type}.fromPartial(${from})`;
2757
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, valueField.typeName, "fromPartial")}(${from})`;
2750
2758
  }
2751
2759
  }
2752
2760
  else if ((0, types_1.isAnyValueType)(field)) {
2753
2761
  return (0, ts_poet_1.code) `${from}`;
2754
2762
  }
2755
2763
  else {
2756
- const type = (0, types_1.basicTypeName)(ctx, field);
2757
- return (0, ts_poet_1.code) `${type}.fromPartial(${from})`;
2764
+ return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, field.typeName, "fromPartial")}(${from})`;
2758
2765
  }
2759
2766
  }
2760
2767
  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;
@@ -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,
@@ -262,6 +263,14 @@ function optionsFromParameter(parameter) {
262
263
  // Make sure to cast number options to an actual number
263
264
  options.unrecognizedEnumValue = Number(options.unrecognizedEnumValue);
264
265
  }
266
+ if (options.outputStandaloneFunctions &&
267
+ (options.outputTypeRegistry ||
268
+ options.outputTypeAnnotations === "static-only" ||
269
+ options.outputServices.includes(ServiceOption.GENERIC) ||
270
+ options.nestJs ||
271
+ options.useMongoObjectId)) {
272
+ throw new Error("outputStandaloneFunctions=true can't be used with outputTypeRegistry=true, outputTypeAnnotations=static-only, outputServices=generic-definitions, nestJs=true, or useMongoObjectId=true");
273
+ }
265
274
  return options;
266
275
  }
267
276
  // 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.5",
3
+ "version": "2.19.0",
4
4
  "description": "",
5
5
  "main": "build/src/plugin.js",
6
6
  "repository": "github:stephenh/ts-proto",