ts-proto 2.21.1 → 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 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.
@@ -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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-proto",
3
- "version": "2.21.1",
3
+ "version": "2.22.0",
4
4
  "description": "",
5
5
  "main": "build/src/plugin.js",
6
6
  "repository": "github:stephenh/ts-proto",