ts-proto 2.21.0 → 2.22.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 +17 -0
- package/build/src/main.js +6 -2
- package/build/src/options.js +58 -1
- package/package.json +1 -1
package/README.markdown
CHANGED
|
@@ -39,6 +39,7 @@ Any tips or tricks for others on the migration would also be appreciated!
|
|
|
39
39
|
- [Highlights](#highlights)
|
|
40
40
|
- [Auto-Batching / N+1 Prevention](#auto-batching--n1-prevention)
|
|
41
41
|
- [Usage](#usage)
|
|
42
|
+
- [Options file](#options-file)
|
|
42
43
|
- [Supported options](#supported-options)
|
|
43
44
|
- [NestJS Support](#nestjs-support)
|
|
44
45
|
- [Watch Mode](#watch-mode)
|
|
@@ -309,6 +310,22 @@ protobuf {
|
|
|
309
310
|
|
|
310
311
|
Generated code will be placed in the Gradle build directory.
|
|
311
312
|
|
|
313
|
+
### Options file
|
|
314
|
+
|
|
315
|
+
If you pass many options, you can put them in a JSON file and pass its path with `--ts_proto_opt=optionsFile=<path>`, e.g. `--ts_proto_opt=optionsFile=ts-proto.json` with a `ts-proto.json` of:
|
|
316
|
+
|
|
317
|
+
```json
|
|
318
|
+
{
|
|
319
|
+
"esModuleInterop": true,
|
|
320
|
+
"forceLong": "bigint",
|
|
321
|
+
"outputServices": ["nice-grpc", "generic-definitions"],
|
|
322
|
+
"useDate": "string",
|
|
323
|
+
"Mgoogle/protobuf/empty.proto": "./google3/protobuf/empty"
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
The keys and values are the same as the `--ts_proto_opt` options below, and options that can be passed multiple times (like `outputServices`) are given as arrays. The path is relative to the directory that `protoc` is run from, and any options also passed as `--ts_proto_opt`s take precedence over the ones in the file. Since the plugin reads the file itself, this needs a local `protoc-gen-ts_proto`, i.e. it doesn't work with the remote Buf Registry plugin.
|
|
328
|
+
|
|
312
329
|
### Supported options
|
|
313
330
|
|
|
314
331
|
- With `--ts_proto_opt=globalThisPolyfill=true`, ts-proto will include a polyfill for globalThis.
|
package/build/src/main.js
CHANGED
|
@@ -1932,7 +1932,11 @@ function valueTypeFromJson(ctx, field, from) {
|
|
|
1932
1932
|
return (0, ts_poet_1.code) `BigInt(${from})`;
|
|
1933
1933
|
}
|
|
1934
1934
|
else if ((0, types_1.isBytesValueType)(field)) {
|
|
1935
|
-
|
|
1935
|
+
// BytesValue is a base64 string in JSON, like a plain `bytes` field.
|
|
1936
|
+
if (options.env === options_1.EnvOption.NODE) {
|
|
1937
|
+
return (0, ts_poet_1.code) `Buffer.from(${ctx.utils.bytesFromBase64}(${from}))`;
|
|
1938
|
+
}
|
|
1939
|
+
return (0, ts_poet_1.code) `${ctx.utils.bytesFromBase64}(${from})`;
|
|
1936
1940
|
}
|
|
1937
1941
|
else {
|
|
1938
1942
|
return (0, ts_poet_1.code) `${(0, case_1.capitalize)(valueType.toCodeString([]))}(${from})`;
|
|
@@ -2555,7 +2559,7 @@ function generateToJson(ctx, fullName, fullProtobufTypeName, messageDesc) {
|
|
|
2555
2559
|
else if ((0, types_1.isMessage)(field) && !(0, types_1.isValueType)(ctx, field) && !(0, types_1.isMapType)(ctx, messageDesc, field)) {
|
|
2556
2560
|
return (0, ts_poet_1.code) `${(0, types_1.getMessageMethod)(ctx, field.typeName, "toJSON")}(${from})`;
|
|
2557
2561
|
}
|
|
2558
|
-
else if ((0, types_1.isBytes)(field)) {
|
|
2562
|
+
else if ((0, types_1.isBytes)(field) || (0, types_1.isBytesValueType)(field)) {
|
|
2559
2563
|
return (0, ts_poet_1.code) `${utils.base64FromBytes}(${from})`;
|
|
2560
2564
|
}
|
|
2561
2565
|
else if (isLongValueTypeAsObject(options, field)) {
|
package/build/src/options.js
CHANGED
|
@@ -5,6 +5,7 @@ exports.defaultOptions = defaultOptions;
|
|
|
5
5
|
exports.optionsFromParameter = optionsFromParameter;
|
|
6
6
|
exports.getTsPoetOpts = getTsPoetOpts;
|
|
7
7
|
exports.addTypeToMessages = addTypeToMessages;
|
|
8
|
+
const fs_1 = require("fs");
|
|
8
9
|
var LongOption;
|
|
9
10
|
(function (LongOption) {
|
|
10
11
|
LongOption["NUMBER"] = "number";
|
|
@@ -156,7 +157,7 @@ const nestJsOptions = {
|
|
|
156
157
|
function optionsFromParameter(parameter) {
|
|
157
158
|
const options = defaultOptions();
|
|
158
159
|
if (parameter) {
|
|
159
|
-
const parsed = parseParameter(parameter);
|
|
160
|
+
const parsed = withOptionsFile(parseParameter(parameter));
|
|
160
161
|
if (parsed.nestJs) {
|
|
161
162
|
Object.assign(options, nestJsOptions);
|
|
162
163
|
}
|
|
@@ -323,6 +324,62 @@ function parseParameter(parameter) {
|
|
|
323
324
|
function parseParamValue(value) {
|
|
324
325
|
return value === "true" ? true : value === "false" ? false : value;
|
|
325
326
|
}
|
|
327
|
+
// Merges the options from an `optionsFile=<path>` JSON file, if one was given, into the
|
|
328
|
+
// options parsed from the protoc parameter, which take precedence over the file's values.
|
|
329
|
+
function withOptionsFile(parsed) {
|
|
330
|
+
const { optionsFile, ...params } = parsed;
|
|
331
|
+
if (optionsFile === undefined) {
|
|
332
|
+
return parsed;
|
|
333
|
+
}
|
|
334
|
+
if (typeof optionsFile !== "string" || optionsFile === "") {
|
|
335
|
+
throw new Error(`optionsFile must be set to a single file path, but got '${optionsFile}'`);
|
|
336
|
+
}
|
|
337
|
+
const fromFile = readOptionsFile(optionsFile);
|
|
338
|
+
return { ...fromFile, ...params, M: { ...fromFile.M, ...params.M } };
|
|
339
|
+
}
|
|
340
|
+
// Reads a JSON object of options, e.g. `{ "useDate": "string", "outputServices": ["grpc-js", "generic-definitions"] }`,
|
|
341
|
+
// and returns the same values that `parseParameter` would for the equivalent protoc parameters.
|
|
342
|
+
function readOptionsFile(path) {
|
|
343
|
+
let json;
|
|
344
|
+
try {
|
|
345
|
+
json = JSON.parse((0, fs_1.readFileSync)(path, "utf-8"));
|
|
346
|
+
}
|
|
347
|
+
catch (e) {
|
|
348
|
+
throw new Error(`Could not read optionsFile '${path}': ${e.message}`);
|
|
349
|
+
}
|
|
350
|
+
if (typeof json !== "object" || json === null || Array.isArray(json)) {
|
|
351
|
+
throw new Error(`optionsFile '${path}' must contain a JSON object of options`);
|
|
352
|
+
}
|
|
353
|
+
const options = { M: {} };
|
|
354
|
+
for (const [key, value] of Object.entries(json)) {
|
|
355
|
+
if (key === "optionsFile") {
|
|
356
|
+
throw new Error(`optionsFile '${path}' can't set optionsFile`);
|
|
357
|
+
}
|
|
358
|
+
else if (key.charAt(0) === "M") {
|
|
359
|
+
if (typeof value !== "string") {
|
|
360
|
+
throw new Error(`optionsFile '${path}' must set ${key} to a string, but got ${JSON.stringify(value)}`);
|
|
361
|
+
}
|
|
362
|
+
options.M[key.substring(1)] = value;
|
|
363
|
+
}
|
|
364
|
+
else if (isOptionValue(value)) {
|
|
365
|
+
options[key] = normalizeOptionValue(value);
|
|
366
|
+
}
|
|
367
|
+
else if (Array.isArray(value) && value.length > 0 && value.every(isOptionValue)) {
|
|
368
|
+
// A single-element array is the same as passing the option once
|
|
369
|
+
options[key] = value.length === 1 ? normalizeOptionValue(value[0]) : value.map(normalizeOptionValue);
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
throw new Error(`optionsFile '${path}' must set ${key} to a string, number, boolean, or non-empty array of them, but got ${JSON.stringify(value)}`);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return options;
|
|
376
|
+
}
|
|
377
|
+
function isOptionValue(value) {
|
|
378
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
379
|
+
}
|
|
380
|
+
function normalizeOptionValue(value) {
|
|
381
|
+
return parseParamValue(String(value));
|
|
382
|
+
}
|
|
326
383
|
function getTsPoetOpts(options, tsProtoVersion, protocVersion, fileName) {
|
|
327
384
|
const { importSuffix, esModuleInterop } = options;
|
|
328
385
|
const pbjs = "protobufjs/minimal" + importSuffix;
|