@bufbuild/protoplugin 2.0.0-alpha.3 → 2.0.0-beta.1

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.
@@ -27,30 +27,32 @@ function createSchema(request, parameter, pluginName, pluginVersion, minimumEdit
27
27
  const { allFiles, filesToGenerate } = getFilesToGenerate(request, minimumEdition, maximumEdition);
28
28
  let target;
29
29
  const generatedFiles = [];
30
- const runtime = (0, runtime_imports_js_1.createRuntimeImports)(parameter.bootstrapWkt);
31
- const resolveDescImport = (desc, typeOnly) => (0, import_symbol_js_1.createImportSymbol)((0, names_js_1.localDescName)(desc), (0, names_js_1.generateFilePath)(desc.kind == "file" ? desc : desc.file, parameter.bootstrapWkt, filesToGenerate), typeOnly);
32
- const resolveShapeImport = (desc) => (0, import_symbol_js_1.createImportSymbol)((0, names_js_1.localShapeName)(desc), (0, names_js_1.generateFilePath)(desc.file, parameter.bootstrapWkt, filesToGenerate), true);
33
- const createPreamble = (descFile) => (0, file_preamble_js_1.makeFilePreamble)(descFile, pluginName, pluginVersion, parameter.sanitizedParameter, parameter.tsNocheck);
34
- const rewriteImport = (importPath) => (0, import_path_js_1.rewriteImportPath)(importPath, parameter.rewriteImports, parameter.importExtension);
30
+ const runtime = (0, runtime_imports_js_1.createRuntimeImports)(parameter.parsed.bootstrapWkt);
31
+ const resolveDescImport = (desc, typeOnly) => (0, import_symbol_js_1.createImportSymbol)((0, names_js_1.generatedDescName)(desc), (0, names_js_1.generateFilePath)(desc.kind == "file" ? desc : desc.file, parameter.parsed.bootstrapWkt, filesToGenerate), typeOnly);
32
+ const resolveShapeImport = (desc) => (0, import_symbol_js_1.createImportSymbol)((0, names_js_1.generatedShapeName)(desc), (0, names_js_1.generateFilePath)(desc.file, parameter.parsed.bootstrapWkt, filesToGenerate), true);
33
+ const resolveJsonImport = (desc) => (0, import_symbol_js_1.createImportSymbol)((0, names_js_1.generatedJsonTypeName)(desc), (0, names_js_1.generateFilePath)(desc.file, parameter.parsed.bootstrapWkt, filesToGenerate), true);
34
+ const createPreamble = (descFile) => (0, file_preamble_js_1.makeFilePreamble)(descFile, pluginName, pluginVersion, parameter.sanitized, parameter.parsed.tsNocheck);
35
+ const rewriteImport = (importPath) => (0, import_path_js_1.rewriteImportPath)(importPath, parameter.parsed.rewriteImports, parameter.parsed.importExtension);
35
36
  return {
36
- targets: parameter.targets,
37
+ targets: parameter.parsed.targets,
37
38
  proto: request,
38
39
  files: filesToGenerate,
39
40
  allFiles: allFiles,
41
+ options: parameter.parsed,
40
42
  typesInFile: reflect_1.nestedTypes,
41
43
  generateFile(name) {
42
44
  if (target === undefined) {
43
45
  throw new Error("prepareGenerate() must be called before generateFile()");
44
46
  }
45
- const genFile = (0, generated_file_js_1.createGeneratedFile)(name, (0, import_path_js_1.deriveImportPath)(name), target === "js" ? parameter.jsImportStyle : "module", // ts and dts always use import/export, only js may use commonjs
46
- rewriteImport, resolveDescImport, resolveShapeImport, createPreamble, runtime);
47
+ const genFile = (0, generated_file_js_1.createGeneratedFile)(name, (0, import_path_js_1.deriveImportPath)(name), target === "js" ? parameter.parsed.jsImportStyle : "module", // ts and dts always use import/export, only js may use commonjs
48
+ rewriteImport, resolveDescImport, resolveShapeImport, resolveJsonImport, createPreamble, runtime);
47
49
  generatedFiles.push(genFile);
48
50
  return genFile;
49
51
  },
50
52
  getFileInfo() {
51
53
  return generatedFiles
52
54
  .map((f) => f.getFileInfo())
53
- .filter((fi) => parameter.keepEmptyFiles || fi.content.length > 0);
55
+ .filter((fi) => parameter.parsed.keepEmptyFiles || fi.content.length > 0);
54
56
  },
55
57
  prepareGenerate(newTarget) {
56
58
  target = newTarget;
@@ -100,7 +102,7 @@ function getFilesToGenerate(request, minimumEdition, maximumEdition) {
100
102
  const sourceFile = request.sourceFileDescriptors.find((s) => s.name == protoFile.name);
101
103
  return sourceFile !== null && sourceFile !== void 0 ? sourceFile : protoFile;
102
104
  });
103
- const registry = (0, protobuf_1.createFileRegistry)((0, protobuf_1.create)(wkt_1.FileDescriptorSetDesc, {
105
+ const registry = (0, protobuf_1.createFileRegistry)((0, protobuf_1.create)(wkt_1.FileDescriptorSetSchema, {
104
106
  file: allProtoWithSourceOptions,
105
107
  }));
106
108
  const allFiles = [];
@@ -22,7 +22,7 @@ const wkt_1 = require("@bufbuild/protobuf/wkt");
22
22
  */
23
23
  function getPackageComments(desc) {
24
24
  return findComments(desc.proto.sourceCodeInfo, [
25
- wkt_1.FileDescriptorProtoDesc.field.package.number,
25
+ wkt_1.FileDescriptorProtoSchema.field.package.number,
26
26
  ]);
27
27
  }
28
28
  exports.getPackageComments = getPackageComments;
@@ -31,7 +31,7 @@ exports.getPackageComments = getPackageComments;
31
31
  */
32
32
  function getSyntaxComments(desc) {
33
33
  return findComments(desc.proto.sourceCodeInfo, [
34
- wkt_1.FileDescriptorProtoDesc.field.syntax.number,
34
+ wkt_1.FileDescriptorProtoSchema.field.syntax.number,
35
35
  ]);
36
36
  }
37
37
  exports.getSyntaxComments = getSyntaxComments;
@@ -46,11 +46,11 @@ function getComments(desc) {
46
46
  path = desc.parent
47
47
  ? [
48
48
  ...getComments(desc.parent).sourcePath,
49
- wkt_1.DescriptorProtoDesc.field.enumType.number,
49
+ wkt_1.DescriptorProtoSchema.field.enumType.number,
50
50
  desc.parent.proto.enumType.indexOf(desc.proto),
51
51
  ]
52
52
  : [
53
- wkt_1.FileDescriptorProtoDesc.field.enumType.number,
53
+ wkt_1.FileDescriptorProtoSchema.field.enumType.number,
54
54
  desc.file.proto.enumType.indexOf(desc.proto),
55
55
  ];
56
56
  file = desc.file;
@@ -58,7 +58,7 @@ function getComments(desc) {
58
58
  case "oneof":
59
59
  path = [
60
60
  ...getComments(desc.parent).sourcePath,
61
- wkt_1.DescriptorProtoDesc.field.oneofDecl.number,
61
+ wkt_1.DescriptorProtoSchema.field.oneofDecl.number,
62
62
  desc.parent.proto.oneofDecl.indexOf(desc.proto),
63
63
  ];
64
64
  file = desc.parent.file;
@@ -67,11 +67,11 @@ function getComments(desc) {
67
67
  path = desc.parent
68
68
  ? [
69
69
  ...getComments(desc.parent).sourcePath,
70
- wkt_1.DescriptorProtoDesc.field.nestedType.number,
70
+ wkt_1.DescriptorProtoSchema.field.nestedType.number,
71
71
  desc.parent.proto.nestedType.indexOf(desc.proto),
72
72
  ]
73
73
  : [
74
- wkt_1.FileDescriptorProtoDesc.field.messageType.number,
74
+ wkt_1.FileDescriptorProtoSchema.field.messageType.number,
75
75
  desc.file.proto.messageType.indexOf(desc.proto),
76
76
  ];
77
77
  file = desc.file;
@@ -79,7 +79,7 @@ function getComments(desc) {
79
79
  case "enum_value":
80
80
  path = [
81
81
  ...getComments(desc.parent).sourcePath,
82
- wkt_1.EnumDescriptorProtoDesc.field.value.number,
82
+ wkt_1.EnumDescriptorProtoSchema.field.value.number,
83
83
  desc.parent.proto.value.indexOf(desc.proto),
84
84
  ];
85
85
  file = desc.parent.file;
@@ -87,7 +87,7 @@ function getComments(desc) {
87
87
  case "field":
88
88
  path = [
89
89
  ...getComments(desc.parent).sourcePath,
90
- wkt_1.DescriptorProtoDesc.field.field.number,
90
+ wkt_1.DescriptorProtoSchema.field.field.number,
91
91
  desc.parent.proto.field.indexOf(desc.proto),
92
92
  ];
93
93
  file = desc.parent.file;
@@ -96,18 +96,18 @@ function getComments(desc) {
96
96
  path = desc.parent
97
97
  ? [
98
98
  ...getComments(desc.parent).sourcePath,
99
- wkt_1.DescriptorProtoDesc.field.extension.number,
99
+ wkt_1.DescriptorProtoSchema.field.extension.number,
100
100
  desc.parent.proto.extension.indexOf(desc.proto),
101
101
  ]
102
102
  : [
103
- wkt_1.FileDescriptorProtoDesc.field.extension.number,
103
+ wkt_1.FileDescriptorProtoSchema.field.extension.number,
104
104
  desc.file.proto.extension.indexOf(desc.proto),
105
105
  ];
106
106
  file = desc.file;
107
107
  break;
108
108
  case "service":
109
109
  path = [
110
- wkt_1.FileDescriptorProtoDesc.field.service.number,
110
+ wkt_1.FileDescriptorProtoSchema.field.service.number,
111
111
  desc.file.proto.service.indexOf(desc.proto),
112
112
  ];
113
113
  file = desc.file;
@@ -115,7 +115,7 @@ function getComments(desc) {
115
115
  case "rpc":
116
116
  path = [
117
117
  ...getComments(desc.parent).sourcePath,
118
- wkt_1.ServiceDescriptorProtoDesc.field.method.number,
118
+ wkt_1.ServiceDescriptorProtoSchema.field.method.number,
119
119
  desc.parent.proto.method.indexOf(desc.proto),
120
120
  ];
121
121
  file = desc.parent.file;
@@ -133,7 +133,7 @@ function getFeatureOptionStrings(desc) {
133
133
  const strings = [];
134
134
  const features = (_a = desc.proto.options) === null || _a === void 0 ? void 0 : _a.features;
135
135
  if (features !== undefined) {
136
- const r = (0, reflect_1.reflect)(wkt_1.FeatureSetDesc, features);
136
+ const r = (0, reflect_1.reflect)(wkt_1.FeatureSetSchema, features);
137
137
  for (const f of r.fields) {
138
138
  if (f.fieldKind != "enum" || !r.isSet(f)) {
139
139
  continue;
@@ -197,10 +197,10 @@ function getDeclarationString(desc) {
197
197
  const options = [];
198
198
  const protoOptions = desc.proto.options;
199
199
  if (protoOptions !== undefined &&
200
- (0, protobuf_1.isFieldSet)(protoOptions, wkt_1.FieldOptionsDesc.field.packed)) {
200
+ (0, protobuf_1.isFieldSet)(protoOptions, wkt_1.FieldOptionsSchema.field.packed)) {
201
201
  options.push(`packed = ${protoOptions.packed.toString()}`);
202
202
  }
203
- if ((0, protobuf_1.isFieldSet)(desc.proto, wkt_1.FieldDescriptorProtoDesc.field.defaultValue)) {
203
+ if ((0, protobuf_1.isFieldSet)(desc.proto, wkt_1.FieldDescriptorProtoSchema.field.defaultValue)) {
204
204
  let defaultValue = desc.proto.defaultValue;
205
205
  if (desc.proto.type == wkt_1.FieldDescriptorProto_Type.BYTES ||
206
206
  desc.proto.type == wkt_1.FieldDescriptorProto_Type.STRING) {
@@ -212,11 +212,11 @@ function getDeclarationString(desc) {
212
212
  options.push(`json_name = "${desc.jsonName}"`);
213
213
  }
214
214
  if (protoOptions !== undefined &&
215
- (0, protobuf_1.isFieldSet)(protoOptions, wkt_1.FieldOptionsDesc.field.jstype)) {
215
+ (0, protobuf_1.isFieldSet)(protoOptions, wkt_1.FieldOptionsSchema.field.jstype)) {
216
216
  options.push(`jstype = ${wkt_1.FieldOptions_JSType[protoOptions.jstype]}`);
217
217
  }
218
218
  if (protoOptions !== undefined &&
219
- (0, protobuf_1.isFieldSet)(protoOptions, wkt_1.FieldOptionsDesc.field.deprecated)) {
219
+ (0, protobuf_1.isFieldSet)(protoOptions, wkt_1.FieldOptionsSchema.field.deprecated)) {
220
220
  options.push(`deprecated = true`);
221
221
  }
222
222
  options.push(...getFeatureOptionStrings(desc));
@@ -270,10 +270,10 @@ function findComments(sourceCodeInfo, sourcePath) {
270
270
  }
271
271
  return {
272
272
  leadingDetached: location.leadingDetachedComments,
273
- leading: (0, protobuf_1.isFieldSet)(location, wkt_1.SourceCodeInfo_LocationDesc.field.leadingComments)
273
+ leading: (0, protobuf_1.isFieldSet)(location, wkt_1.SourceCodeInfo_LocationSchema.field.leadingComments)
274
274
  ? location.leadingComments
275
275
  : undefined,
276
- trailing: (0, protobuf_1.isFieldSet)(location, wkt_1.SourceCodeInfo_LocationDesc.field.trailingComments)
276
+ trailing: (0, protobuf_1.isFieldSet)(location, wkt_1.SourceCodeInfo_LocationSchema.field.trailingComments)
277
277
  ? location.trailingComments
278
278
  : undefined,
279
279
  sourcePath,
@@ -26,7 +26,7 @@ const defaultOptions = {
26
26
  strict: false,
27
27
  // modules
28
28
  module: typescript_1.default.ModuleKind.ES2020,
29
- moduleResolution: typescript_1.default.ModuleResolutionKind.NodeJs,
29
+ moduleResolution: typescript_1.default.ModuleResolutionKind.Node10,
30
30
  noResolve: true,
31
31
  resolveJsonModule: false,
32
32
  // emit
@@ -39,7 +39,7 @@ const defaultOptions = {
39
39
  checkJs: false,
40
40
  // Language and Environment
41
41
  lib: [],
42
- moduleDetection: "force",
42
+ moduleDetection: typescript_1.default.ModuleDetectionKind.Force,
43
43
  target: typescript_1.default.ScriptTarget.ES2017,
44
44
  // Completeness
45
45
  skipLibCheck: true,
@@ -2,7 +2,8 @@ import { type SupportedEdition } from "@bufbuild/protobuf";
2
2
  import type { Schema } from "./schema.js";
3
3
  import type { FileInfo } from "./generated-file.js";
4
4
  import type { Plugin } from "./plugin.js";
5
- interface PluginInit {
5
+ import type { RawPluginOptions } from "./parameter.js";
6
+ interface PluginInit<Options extends object> {
6
7
  /**
7
8
  * Name of this code generator plugin.
8
9
  */
@@ -15,7 +16,7 @@ interface PluginInit {
15
16
  * An optional parsing function which can be used to parse your own plugin
16
17
  * options.
17
18
  */
18
- parseOption?: (key: string, value: string) => void;
19
+ parseOptions?: (rawOptions: RawPluginOptions) => Options;
19
20
  /**
20
21
  * The earliest edition supported by this plugin. Defaults to the minimum
21
22
  * edition supported by @bufbuild/protobuf.
@@ -32,7 +33,7 @@ interface PluginInit {
32
33
  *
33
34
  * Note that this is required to be provided for plugin initialization.
34
35
  */
35
- generateTs: (schema: Schema, target: "ts") => void;
36
+ generateTs: (schema: Schema<Options>, target: "ts") => void;
36
37
  /**
37
38
  * A optional function which will generate JavaScript files based on proto
38
39
  * input. This function will be invoked by the plugin framework when the
@@ -43,7 +44,7 @@ interface PluginInit {
43
44
  * JavaScript files. If not, the plugin framework will transpile the files
44
45
  * itself.
45
46
  */
46
- generateJs?: (schema: Schema, target: "js") => void;
47
+ generateJs?: (schema: Schema<Options>, target: "js") => void;
47
48
  /**
48
49
  * A optional function which will generate TypeScript declaration files
49
50
  * based on proto input. This function will be invoked by the plugin
@@ -54,7 +55,7 @@ interface PluginInit {
54
55
  * declaration files. If not, the plugin framework will transpile the files
55
56
  * itself.
56
57
  */
57
- generateDts?: (schema: Schema, target: "dts") => void;
58
+ generateDts?: (schema: Schema<Options>, target: "dts") => void;
58
59
  /**
59
60
  * An optional function which will transpile a given set of files.
60
61
  *
@@ -75,5 +76,5 @@ interface PluginInit {
75
76
  * The plugin can generate JavaScript, TypeScript, or TypeScript declaration
76
77
  * files.
77
78
  */
78
- export declare function createEcmaScriptPlugin(init: PluginInit): Plugin;
79
+ export declare function createEcmaScriptPlugin<Options extends object = object>(init: PluginInit<Options>): Plugin;
79
80
  export {};
@@ -13,7 +13,7 @@
13
13
  // limitations under the License.
14
14
  import { create, protoInt64 } from "@bufbuild/protobuf";
15
15
  import { minimumEdition as minimumEditionUpstream, maximumEdition as maximumEditionUpstream, } from "@bufbuild/protobuf";
16
- import { CodeGeneratorResponse_Feature, CodeGeneratorResponseDesc, } from "@bufbuild/protobuf/wkt";
16
+ import { CodeGeneratorResponse_Feature, CodeGeneratorResponseSchema, } from "@bufbuild/protobuf/wkt";
17
17
  import { createSchema } from "./schema.js";
18
18
  import { transpile } from "./transpile.js";
19
19
  import { parseParameter } from "./parameter.js";
@@ -32,7 +32,7 @@ export function createEcmaScriptPlugin(init) {
32
32
  var _a, _b, _c;
33
33
  const minimumEdition = (_a = init.minimumEdition) !== null && _a !== void 0 ? _a : minimumEditionUpstream;
34
34
  const maximumEdition = (_b = init.maximumEdition) !== null && _b !== void 0 ? _b : maximumEditionUpstream;
35
- const parameter = parseParameter(req.parameter, init.parseOption);
35
+ const parameter = parseParameter(req.parameter, init.parseOptions);
36
36
  const schema = createSchema(req, parameter, init.name, init.version, minimumEdition, maximumEdition);
37
37
  const targetTs = schema.targets.includes("ts");
38
38
  const targetJs = schema.targets.includes("js");
@@ -94,7 +94,7 @@ export function createEcmaScriptPlugin(init) {
94
94
  if (transpileJs || transpileDts) {
95
95
  const transpileFn = (_c = init.transpile) !== null && _c !== void 0 ? _c : transpile;
96
96
  // Transpile the TypeScript files and add to the master list of files
97
- const transpiledFiles = transpileFn(tsFiles, transpileJs, transpileDts, parameter.jsImportStyle);
97
+ const transpiledFiles = transpileFn(tsFiles, transpileJs, transpileDts, parameter.parsed.jsImportStyle);
98
98
  files.push(...transpiledFiles);
99
99
  }
100
100
  return toResponse(files, minimumEdition, maximumEdition);
@@ -102,7 +102,7 @@ export function createEcmaScriptPlugin(init) {
102
102
  };
103
103
  }
104
104
  function toResponse(files, minimumEdition, maximumEdition) {
105
- return create(CodeGeneratorResponseDesc, {
105
+ return create(CodeGeneratorResponseSchema, {
106
106
  supportedFeatures: protoInt64.parse(CodeGeneratorResponse_Feature.PROTO3_OPTIONAL |
107
107
  CodeGeneratorResponse_Feature.SUPPORTS_EDITIONS),
108
108
  minimumEdition,
@@ -58,7 +58,7 @@ export interface GeneratedFile {
58
58
  * descriptor. The comment block will contain the original comments from the
59
59
  * protobuf source, and annotations such as `@generated from message MyMessage`.
60
60
  */
61
- jsDoc(desc: Exclude<AnyDesc, DescFile>, indentation?: string): Printable;
61
+ jsDoc(schema: Exclude<AnyDesc, DescFile>, indentation?: string): Printable;
62
62
  /**
63
63
  * Create a printable export statement. For example:
64
64
  *
@@ -79,11 +79,18 @@ export interface GeneratedFile {
79
79
  /**
80
80
  * Import a message or enumeration generated by protoc-gen-es.
81
81
  */
82
- importShape(desc: DescMessage | DescEnum): ImportSymbol;
82
+ importShape(schema: DescMessage | DescEnum): ImportSymbol;
83
+ /**
84
+ * Import a message or enumeration JSON type generated by protoc-gen-es.
85
+ *
86
+ * Note that protoc-gen-es only generates JSON types with the plugin option
87
+ * `json_types=true`.
88
+ */
89
+ importJson(desc: DescMessage | DescEnum): ImportSymbol;
83
90
  /**
84
91
  * Import a descriptor generated by protoc-gen-es.
85
92
  */
86
- importDesc(desc: DescMessage | DescEnum | DescExtension | DescService | DescFile, typeOnly?: boolean): ImportSymbol;
93
+ importSchema(schema: DescMessage | DescEnum | DescExtension | DescService | DescFile, typeOnly?: boolean): ImportSymbol;
87
94
  /**
88
95
  * Import any symbol from a file or package.
89
96
  *
@@ -94,10 +101,15 @@ export interface GeneratedFile {
94
101
  * relative to the project root. The import path is automatically made
95
102
  * relative to the current file.
96
103
  */
97
- import(name: string, from: string): ImportSymbol;
104
+ import(name: string, from: string, typeOnly?: boolean): ImportSymbol;
98
105
  /**
99
106
  * In case you need full control over exports and imports, use print() and
100
107
  * formulate your own imports and exports based on this property.
108
+ *
109
+ * With the plugin option `js_import_style=legacy_commonjs`, this property
110
+ * reports "legacy_commonjs", but only if the current target is "js".
111
+ * This matches the behavior of import(), which also only generates CommonJS
112
+ * under this condition.
101
113
  */
102
114
  readonly jsImportStyle: "module" | "legacy_commonjs";
103
115
  /**
@@ -112,4 +124,4 @@ export type ResolveDescImportFn = (desc: DescMessage | DescEnum | DescExtension
112
124
  export type ResolveShapeImportFn = (desc: DescMessage | DescEnum) => ImportSymbol;
113
125
  export type RewriteImportFn = (path: string) => string;
114
126
  export type CreatePreambleFn = (descFile: DescFile) => string;
115
- export declare function createGeneratedFile(name: string, importPath: string, jsImportStyle: "module" | "legacy_commonjs", rewriteImport: RewriteImportFn, resolveDescImport: ResolveDescImportFn, resolveShapeImport: ResolveShapeImportFn, createPreamble: CreatePreambleFn, runtime: RuntimeImports): GeneratedFileController;
127
+ export declare function createGeneratedFile(name: string, importPath: string, jsImportStyle: "module" | "legacy_commonjs", rewriteImport: RewriteImportFn, resolveDescImport: ResolveDescImportFn, resolveShapeImport: ResolveShapeImportFn, resolveJsonImport: ResolveShapeImportFn, createPreamble: CreatePreambleFn, runtime: RuntimeImports): GeneratedFileController;
@@ -15,7 +15,7 @@ import { protoInt64, ScalarType, } from "@bufbuild/protobuf";
15
15
  import { createImportSymbol } from "./import-symbol.js";
16
16
  import { makeImportPathRelative } from "./import-path.js";
17
17
  import { createJsDocTextFromDesc, formatJsDocBlock } from "./jsdoc.js";
18
- export function createGeneratedFile(name, importPath, jsImportStyle, rewriteImport, resolveDescImport, resolveShapeImport, createPreamble, runtime) {
18
+ export function createGeneratedFile(name, importPath, jsImportStyle, rewriteImport, resolveDescImport, resolveShapeImport, resolveJsonImport, createPreamble, runtime) {
19
19
  let preamble;
20
20
  const el = [];
21
21
  return {
@@ -41,6 +41,7 @@ export function createGeneratedFile(name, importPath, jsImportStyle, rewriteImpo
41
41
  runtime,
42
42
  resolveDescImport,
43
43
  resolveShapeImport,
44
+ resolveJsonImport,
44
45
  }, printables);
45
46
  el.push("\n");
46
47
  },
@@ -57,23 +58,26 @@ export function createGeneratedFile(name, importPath, jsImportStyle, rewriteImpo
57
58
  value: string,
58
59
  };
59
60
  },
60
- jsDoc(textOrDesc, indentation) {
61
+ jsDoc(textOrSchema, indentation) {
61
62
  return {
62
63
  kind: "es_jsdoc",
63
- text: typeof textOrDesc == "string"
64
- ? textOrDesc
65
- : createJsDocTextFromDesc(textOrDesc),
64
+ text: typeof textOrSchema == "string"
65
+ ? textOrSchema
66
+ : createJsDocTextFromDesc(textOrSchema),
66
67
  indentation,
67
68
  };
68
69
  },
69
- importDesc(desc, typeOnly = false) {
70
- return resolveDescImport(desc, typeOnly);
70
+ importSchema(schema, typeOnly = false) {
71
+ return resolveDescImport(schema, typeOnly);
71
72
  },
72
- importShape(desc) {
73
- return resolveShapeImport(desc);
73
+ importShape(schema) {
74
+ return resolveShapeImport(schema);
74
75
  },
75
- import(name, from) {
76
- return createImportSymbol(name, from);
76
+ importJson(desc) {
77
+ return resolveJsonImport(desc);
78
+ },
79
+ import(name, from, typeOnly = false) {
80
+ return createImportSymbol(name, from, typeOnly);
77
81
  },
78
82
  jsImportStyle,
79
83
  runtime,
@@ -219,6 +223,9 @@ function printableToEl(opt, printables) {
219
223
  case "es_shape_ref":
220
224
  el.push(opt.resolveShapeImport(p.desc));
221
225
  break;
226
+ case "es_json_type_ref":
227
+ el.push(opt.resolveJsonImport(p.desc));
228
+ break;
222
229
  case "es_jsdoc":
223
230
  el.push(formatJsDocBlock(p.text, p.indentation));
224
231
  break;
@@ -4,6 +4,7 @@ export { createEcmaScriptPlugin } from "./create-es-plugin.js";
4
4
  export { getComments, getDeclarationString, getPackageComments, getSyntaxComments, } from "./source-code-info.js";
5
5
  export type { Target } from "./target.js";
6
6
  export type { Schema } from "./schema.js";
7
+ export type { EcmaScriptPluginOptions } from "./parameter.js";
7
8
  export type { GeneratedFile, FileInfo } from "./generated-file.js";
8
9
  export type { ImportSymbol } from "./import-symbol.js";
9
10
  export { createImportSymbol } from "./import-symbol.js";
@@ -1,4 +1,17 @@
1
1
  import type { DescEnum, DescExtension, DescFile, DescMessage, DescService } from "@bufbuild/protobuf";
2
+ /**
3
+ * Return a file path for the give file descriptor.
4
+ */
2
5
  export declare function generateFilePath(file: DescFile, bootstrapWkt: boolean, filesToGenerate: DescFile[]): string;
3
- export declare function localDescName(desc: DescFile | DescEnum | DescMessage | DescExtension | DescService): string;
4
- export declare function localShapeName(desc: DescEnum | DescMessage): string;
6
+ /**
7
+ * Return a safe identifier for a generated descriptor.
8
+ */
9
+ export declare function generatedDescName(desc: DescFile | DescEnum | DescMessage | DescExtension | DescService): string;
10
+ /**
11
+ * Return a safe identifier for a generated shape.
12
+ */
13
+ export declare function generatedShapeName(desc: DescEnum | DescMessage): string;
14
+ /**
15
+ * Return a safe identifier for a generated JSON type.
16
+ */
17
+ export declare function generatedJsonTypeName(desc: DescEnum | DescMessage): string;
package/dist/esm/names.js CHANGED
@@ -14,6 +14,9 @@
14
14
  import { wktPublicImportPaths } from "@bufbuild/protobuf/codegenv1";
15
15
  import { nestedTypes } from "@bufbuild/protobuf/reflect";
16
16
  import { safeIdentifier } from "./safe-identifier.js";
17
+ /**
18
+ * Return a file path for the give file descriptor.
19
+ */
17
20
  export function generateFilePath(file, bootstrapWkt, filesToGenerate) {
18
21
  // Well-known types are published with the runtime package. We usually want
19
22
  // the generated code to import them from the runtime package, with the
@@ -30,84 +33,155 @@ export function generateFilePath(file, bootstrapWkt, filesToGenerate) {
30
33
  }
31
34
  return "./" + file.name + "_pb.js";
32
35
  }
33
- export function localDescName(desc) {
36
+ /**
37
+ * Return a safe identifier for a generated descriptor.
38
+ */
39
+ export function generatedDescName(desc) {
34
40
  const file = desc.kind == "file" ? desc : desc.file;
35
41
  const { descNames } = allNames(file);
36
42
  const name = descNames.get(desc);
37
43
  if (name === undefined) {
38
- throw new Error(`unable to determine unique identifier for ${desc.toString()}`);
44
+ throw new Error(`unable to determine unique descriptor name for ${desc.toString()}`);
39
45
  }
40
46
  return name;
41
47
  }
42
- export function localShapeName(desc) {
48
+ /**
49
+ * Return a safe identifier for a generated shape.
50
+ */
51
+ export function generatedShapeName(desc) {
43
52
  const { shapeNames } = allNames(desc.file);
44
53
  const name = shapeNames.get(desc);
45
54
  if (name === undefined) {
46
- throw new Error(`unable to determine unique identifier for ${desc.toString()}`);
55
+ throw new Error(`unable to determine unique shape name for ${desc.toString()}`);
47
56
  }
48
57
  return name;
49
58
  }
59
+ /**
60
+ * Return a safe identifier for a generated JSON type.
61
+ */
62
+ export function generatedJsonTypeName(desc) {
63
+ const { jsonTypeNames } = allNames(desc.file);
64
+ const name = jsonTypeNames.get(desc);
65
+ if (name === undefined) {
66
+ throw new Error(`unable to determine unique json type name for ${desc.toString()}`);
67
+ }
68
+ return name;
69
+ }
70
+ /**
71
+ * Compute the ideal name for a generated descriptor.
72
+ */
50
73
  function idealDescName(desc, i) {
51
74
  const escape = i === 0 ? "" : i === 1 ? "$" : `$${i - 1}`;
75
+ if (desc.kind == "file") {
76
+ const name = "file_" + desc.name.replace(/[^a-zA-Z0-9_]+/g, "_");
77
+ return safeIdentifier(name + escape);
78
+ }
52
79
  switch (desc.kind) {
53
- case "file":
54
- return (safeIdentifier("fileDesc_" + desc.name.replace(/[^a-zA-Z0-9_]+/g, "_")) + escape);
55
80
  case "enum":
56
- return baseName(desc) + "Desc" + escape;
81
+ return safeIdentifier(identifier(desc) + "Schema" + escape);
57
82
  case "message":
58
- return baseName(desc) + "Desc" + escape;
83
+ return safeIdentifier(identifier(desc) + "Schema" + escape);
59
84
  case "extension":
60
- return baseName(desc) + escape;
85
+ return safeIdentifier(identifier(desc) + escape);
61
86
  case "service":
62
- return baseName(desc) + escape;
87
+ return safeIdentifier(identifier(desc) + escape);
63
88
  }
64
89
  }
90
+ /**
91
+ * Compute the ideal name for a generated shape.
92
+ */
65
93
  function idealShapeName(desc, i) {
66
94
  const escape = i === 0 ? "" : i === 1 ? "$" : `$${i - 1}`;
67
- return baseName(desc) + escape;
95
+ return safeIdentifier(identifier(desc) + escape);
68
96
  }
69
- function baseName(desc) {
97
+ /**
98
+ * Compute the ideal name for a generated JSON type.
99
+ */
100
+ function idealJsonTypeName(desc, i) {
101
+ const escape = i === 0 ? "" : i === 1 ? "$" : `$${i - 1}`;
102
+ return safeIdentifier(identifier(desc) + "Json" + escape);
103
+ }
104
+ /**
105
+ * Return an identifier for the given descriptor based on its type name.
106
+ *
107
+ * The type name for a protobuf message is the package name (if any), plus
108
+ * the names of parent messages it is nested in (if any), plus the name of
109
+ * the element, separated by dots. For example: foo.bar.ParentMsg.MyEnum.
110
+ *
111
+ * ECMAScript does not have packages or namespaces, so we need a single
112
+ * identifier. Our convention is to drop the package name, and to join other
113
+ * parts of the name with an underscore. For example: ParentMsg_MyEnum.
114
+ */
115
+ function identifier(desc) {
70
116
  const pkg = desc.file.proto.package;
71
117
  const offset = pkg.length > 0 ? pkg.length + 1 : 0;
72
- const name = desc.typeName.substring(offset).replace(/\./g, "_");
73
- return safeIdentifier(name);
118
+ const nameWithoutPkg = desc.typeName.substring(offset);
119
+ return nameWithoutPkg.replace(/\./g, "_");
74
120
  }
121
+ /**
122
+ * Compute all ideal names for the elements in the file, resolving name clashes.
123
+ */
75
124
  function allNames(file) {
76
125
  const taken = new Set();
126
+ // In the first pass, register shape names
77
127
  const shapeNames = new Map();
128
+ for (const desc of nestedTypes(file)) {
129
+ if (desc.kind != "enum" && desc.kind != "message") {
130
+ continue;
131
+ }
132
+ let name;
133
+ for (let i = 0;; i++) {
134
+ name = idealShapeName(desc, i);
135
+ if (!taken.has(name)) {
136
+ break;
137
+ }
138
+ }
139
+ taken.add(name);
140
+ shapeNames.set(desc, name);
141
+ }
142
+ // In the second pass, register desc names
78
143
  const descNames = new Map();
79
144
  for (const desc of [file, ...nestedTypes(file)]) {
145
+ let name;
80
146
  switch (desc.kind) {
81
147
  case "enum":
82
148
  case "message": {
83
- let descName;
84
- let shapeName;
85
149
  for (let i = 0;; i++) {
86
- descName = idealDescName(desc, i);
87
- shapeName = idealShapeName(desc, i);
88
- if (!taken.has(descName) && !taken.has(shapeName)) {
150
+ name = idealDescName(desc, i);
151
+ if (!taken.has(name)) {
89
152
  break;
90
153
  }
91
154
  }
92
- taken.add(descName);
93
- taken.add(shapeName);
94
- descNames.set(desc, descName);
95
- shapeNames.set(desc, shapeName);
96
155
  break;
97
156
  }
98
157
  default: {
99
- let descName;
100
158
  for (let i = 0;; i++) {
101
- descName = idealDescName(desc, i);
102
- if (!taken.has(descName)) {
159
+ name = idealDescName(desc, i);
160
+ if (!taken.has(name)) {
103
161
  break;
104
162
  }
105
163
  }
106
- taken.add(descName);
107
- descNames.set(desc, descName);
108
164
  break;
109
165
  }
110
166
  }
167
+ taken.add(name);
168
+ descNames.set(desc, name);
169
+ }
170
+ // In the third pass, register json type names
171
+ const jsonTypeNames = new Map();
172
+ for (const desc of nestedTypes(file)) {
173
+ if (desc.kind != "enum" && desc.kind != "message") {
174
+ continue;
175
+ }
176
+ let name;
177
+ for (let i = 0;; i++) {
178
+ name = idealJsonTypeName(desc, i);
179
+ if (!taken.has(name)) {
180
+ break;
181
+ }
182
+ }
183
+ taken.add(name);
184
+ jsonTypeNames.set(desc, name);
111
185
  }
112
- return { shapeNames, descNames };
186
+ return { shapeNames, jsonTypeNames, descNames };
113
187
  }