@bufbuild/protoplugin 0.0.10 → 0.1.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.
@@ -27,8 +27,8 @@ function createEcmaScriptPlugin(init, generateFn) {
27
27
  name: init.name,
28
28
  version: init.version,
29
29
  run(req) {
30
- const { targets, tsNocheck, bootstrapWkt } = parseParameter(req.parameter, init.parseOption);
31
- const { schema, toResponse } = (0, schema_js_1.createSchema)(req, targets, init.name, init.version, tsNocheck, bootstrapWkt);
30
+ const { targets, tsNocheck, bootstrapWkt, rewriteImports } = parseParameter(req.parameter, init.parseOption);
31
+ const { schema, toResponse } = (0, schema_js_1.createSchema)(req, targets, init.name, init.version, tsNocheck, bootstrapWkt, rewriteImports);
32
32
  generateFn(schema);
33
33
  const res = new protobuf_1.CodeGeneratorResponse();
34
34
  toResponse(res);
@@ -41,6 +41,7 @@ function parseParameter(parameter, parseOption) {
41
41
  let targets = ["js", "dts"];
42
42
  let tsNocheck = true;
43
43
  let bootstrapWkt = false;
44
+ const rewriteImports = [];
44
45
  for (const { key, value } of splitParameter(parameter)) {
45
46
  switch (key) {
46
47
  case "target":
@@ -88,6 +89,15 @@ function parseParameter(parameter, parseOption) {
88
89
  throw new error_js_1.PluginOptionError(`${key}=${value}`);
89
90
  }
90
91
  break;
92
+ case "rewrite_imports": {
93
+ const parts = value.split(":");
94
+ if (parts.length !== 2) {
95
+ throw new error_js_1.PluginOptionError(`${key}=${value}`, "must be in the form of <pattern>:<target>");
96
+ }
97
+ const [pattern, target] = parts;
98
+ rewriteImports.push({ pattern, target });
99
+ break;
100
+ }
91
101
  default:
92
102
  if (parseOption === undefined) {
93
103
  throw new error_js_1.PluginOptionError(`${key}=${value}`);
@@ -101,7 +111,7 @@ function parseParameter(parameter, parseOption) {
101
111
  break;
102
112
  }
103
113
  }
104
- return { targets, tsNocheck, bootstrapWkt };
114
+ return { targets, tsNocheck, bootstrapWkt, rewriteImports };
105
115
  }
106
116
  function splitParameter(parameter) {
107
117
  if (parameter == undefined) {
@@ -17,8 +17,8 @@ exports.createGeneratedFile = void 0;
17
17
  const protobuf_1 = require("@bufbuild/protobuf");
18
18
  const import_symbol_js_1 = require("./import-symbol.js");
19
19
  const gencommon_js_1 = require("./gencommon.js");
20
- function createGeneratedFile(name, createTypeImport, runtimeImports, preambleSettings) {
21
- const importPath = deriveImportPath(name);
20
+ const import_path_js_1 = require("./import-path.js");
21
+ function createGeneratedFile(name, importPath, createTypeImport, runtimeImports, preambleSettings) {
22
22
  let preamble;
23
23
  const el = [];
24
24
  return {
@@ -55,16 +55,6 @@ function createGeneratedFile(name, createTypeImport, runtimeImports, preambleSet
55
55
  };
56
56
  }
57
57
  exports.createGeneratedFile = createGeneratedFile;
58
- const importPathExtension = ".js";
59
- const knownExtensionsRE = /\.(js|ts|d.ts)$/;
60
- const relativePathRE = /^\.{1,2}\//;
61
- function deriveImportPath(filename) {
62
- let importPath = filename.replace(knownExtensionsRE, importPathExtension);
63
- if (!relativePathRE.test(importPath)) {
64
- importPath = "./" + importPath;
65
- }
66
- return importPath;
67
- }
68
58
  function elToContent(el, importerPath) {
69
59
  const c = [];
70
60
  const symbolToIdentifier = processImports(el, importerPath, (typeOnly, from, names) => {
@@ -221,7 +211,7 @@ function processImports(el, importerPath, makeImportStatement) {
221
211
  // should never happen
222
212
  continue;
223
213
  }
224
- const from = makeImportPathRelative(importerPath, s.from);
214
+ const from = (0, import_path_js_1.makeImportPathRelative)(importerPath, s.from);
225
215
  if (i.types.size > 0) {
226
216
  makeImportStatement(true, from, buildNames(i.types));
227
217
  }
@@ -231,39 +221,6 @@ function processImports(el, importerPath, makeImportStatement) {
231
221
  }
232
222
  return symbolToIdentifier;
233
223
  }
234
- // makeImportPathRelative makes an import path relative to the file importing
235
- // it. For example, consider the following files:
236
- // - foo/foo.js
237
- // - baz.js
238
- // If foo.js wants to import baz.js, we return ../baz.js
239
- function makeImportPathRelative(importer, importPath) {
240
- if (!relativePathRE.test(importPath)) {
241
- // We don't touch absolute imports, like @bufbuild/protobuf
242
- return importPath;
243
- }
244
- let a = importer
245
- .replace(/^\.\//, "")
246
- .split("/")
247
- .filter((p) => p.length > 0)
248
- .slice(0, -1);
249
- let b = importPath
250
- .replace(/^\.\//, "")
251
- .split("/")
252
- .filter((p) => p.length > 0);
253
- let matchingPartCount = 0;
254
- for (let l = Math.min(a.length, b.length); matchingPartCount < l; matchingPartCount++) {
255
- if (a[matchingPartCount] !== b[matchingPartCount]) {
256
- break;
257
- }
258
- }
259
- a = a.slice(matchingPartCount);
260
- b = b.slice(matchingPartCount);
261
- const c = a
262
- .map(() => "..")
263
- .concat(b)
264
- .join("/");
265
- return relativePathRE.test(c) ? c : "./" + c;
266
- }
267
224
  function literalNumber(value) {
268
225
  if (Number.isNaN(value)) {
269
226
  return "globalThis.Number.NaN";
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ // Copyright 2021-2022 Buf Technologies, Inc.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.makeImportPathRelative = exports.deriveImportPath = exports.relativePathRE = exports.makeImportPath = exports.rewriteImportPath = void 0;
17
+ const protobuf_1 = require("@bufbuild/protobuf");
18
+ const cache = new WeakMap();
19
+ /**
20
+ * Apply import rewrites to the given path.
21
+ */
22
+ function rewriteImportPath(importPath, rewriteImports) {
23
+ let ri = cache.get(rewriteImports);
24
+ if (ri === undefined) {
25
+ ri = rewriteImports.map(({ pattern, target }) => {
26
+ return {
27
+ pattern: starToRegExp(pattern),
28
+ target,
29
+ };
30
+ });
31
+ cache.set(rewriteImports, ri);
32
+ }
33
+ for (const { pattern, target } of ri) {
34
+ if (pattern.test(importPath)) {
35
+ return (target.replace(/\/$/, "") + importPath.replace(exports.relativePathRE, "/"));
36
+ }
37
+ }
38
+ return importPath;
39
+ }
40
+ exports.rewriteImportPath = rewriteImportPath;
41
+ function starToRegExp(star) {
42
+ const r = ["^"];
43
+ for (let i = 0; i < star.length; i++) {
44
+ switch (star[i]) {
45
+ case "*":
46
+ if (star[i + 1] === "*" && star[i + 2] === "/") {
47
+ i += 2;
48
+ r.push("([^\\/]+\\/)*");
49
+ break;
50
+ }
51
+ r.push("[^\\/]*");
52
+ break;
53
+ case ".":
54
+ case "+":
55
+ case "?":
56
+ case "^":
57
+ case "$":
58
+ case "{":
59
+ case "}":
60
+ case "(":
61
+ case ")":
62
+ case "|":
63
+ case "[":
64
+ case "]":
65
+ case "\\":
66
+ r.push("\\", star[i]);
67
+ break;
68
+ default:
69
+ r.push(star[i]);
70
+ break;
71
+ }
72
+ }
73
+ r.push("$");
74
+ return new RegExp(r.join(""));
75
+ }
76
+ /**
77
+ * Returns the import path for files generated by the base type generator
78
+ * protoc-gen-es.
79
+ */
80
+ function makeImportPath(file, bootstrapWkt, filesToGenerate) {
81
+ // Well-known types are published with the runtime package. We usually want
82
+ // the generated code to import them from the runtime package, with the
83
+ // following exceptions:
84
+ // 1. We are bootstrapping the runtime package via the plugin option
85
+ // "bootstrap_wkt". In that case, we cannot refer to the runtime package
86
+ // itself.
87
+ // 2. We were explicitly asked to generate the well-known type.
88
+ if (!bootstrapWkt &&
89
+ !filesToGenerate.includes(file) &&
90
+ protobuf_1.codegenInfo.wktSourceFiles.includes(file.name + ".proto")) {
91
+ return protobuf_1.codegenInfo.packageName;
92
+ }
93
+ return "./" + file.name + "_pb.js";
94
+ }
95
+ exports.makeImportPath = makeImportPath;
96
+ exports.relativePathRE = /^\.{1,2}\//;
97
+ /**
98
+ * Derives an ECMAScript module import path from a file path. For example,
99
+ * the path `foo/bar.ts` is transformed into `./foo/bar.js`.
100
+ */
101
+ function deriveImportPath(filename) {
102
+ let importPath = filename.replace(/\.(js|ts|d.ts)$/, ".js");
103
+ if (!exports.relativePathRE.test(importPath)) {
104
+ importPath = "./" + importPath;
105
+ }
106
+ return importPath;
107
+ }
108
+ exports.deriveImportPath = deriveImportPath;
109
+ /**
110
+ * Makes an import path relative to the file importing it. For example,
111
+ * consider the following files:
112
+ * - foo/foo.js
113
+ * - baz.js
114
+ * If foo.js wants to import baz.js, we return ../baz.js
115
+ */
116
+ function makeImportPathRelative(importer, importPath) {
117
+ if (!exports.relativePathRE.test(importPath)) {
118
+ // We don't touch absolute imports, like @bufbuild/protobuf
119
+ return importPath;
120
+ }
121
+ let a = importer
122
+ .replace(/^\.\//, "")
123
+ .split("/")
124
+ .filter((p) => p.length > 0)
125
+ .slice(0, -1);
126
+ let b = importPath
127
+ .replace(/^\.\//, "")
128
+ .split("/")
129
+ .filter((p) => p.length > 0);
130
+ let matchingPartCount = 0;
131
+ for (let l = Math.min(a.length, b.length); matchingPartCount < l; matchingPartCount++) {
132
+ if (a[matchingPartCount] !== b[matchingPartCount]) {
133
+ break;
134
+ }
135
+ }
136
+ a = a.slice(matchingPartCount);
137
+ b = b.slice(matchingPartCount);
138
+ const c = a
139
+ .map(() => "..")
140
+ .concat(b)
141
+ .join("/");
142
+ return exports.relativePathRE.test(c) ? c : "./" + c;
143
+ }
144
+ exports.makeImportPathRelative = makeImportPathRelative;
@@ -18,13 +18,14 @@ const protobuf_1 = require("@bufbuild/protobuf");
18
18
  const generated_file_js_1 = require("./generated-file.js");
19
19
  const runtime_imports_js_1 = require("./runtime-imports.js");
20
20
  const import_symbol_js_1 = require("./import-symbol.js");
21
- function createSchema(request, targets, pluginName, pluginVersion, tsNocheck, bootstrapWkt) {
21
+ const import_path_js_1 = require("./import-path.js");
22
+ function createSchema(request, targets, pluginName, pluginVersion, tsNocheck, bootstrapWkt, rewriteImports) {
22
23
  const descriptorSet = (0, protobuf_1.createDescriptorSet)(request.protoFile);
23
24
  const filesToGenerate = findFilesToGenerate(descriptorSet, request);
24
25
  const runtime = (0, runtime_imports_js_1.createRuntimeImports)(bootstrapWkt);
25
26
  const createTypeImport = (desc) => {
26
27
  const name = protobuf_1.codegenInfo.localName(desc);
27
- const from = makeImportPath(desc.file, bootstrapWkt, filesToGenerate);
28
+ const from = (0, import_path_js_1.rewriteImportPath)((0, import_path_js_1.makeImportPath)(desc.file, bootstrapWkt, filesToGenerate), rewriteImports);
28
29
  return (0, import_symbol_js_1.createImportSymbol)(name, from);
29
30
  };
30
31
  const generatedFiles = [];
@@ -35,7 +36,8 @@ function createSchema(request, targets, pluginName, pluginVersion, tsNocheck, bo
35
36
  files: filesToGenerate,
36
37
  allFiles: descriptorSet.files,
37
38
  generateFile(name) {
38
- const genFile = (0, generated_file_js_1.createGeneratedFile)(name, createTypeImport, runtime, {
39
+ const importPath = (0, import_path_js_1.rewriteImportPath)((0, import_path_js_1.deriveImportPath)(name), rewriteImports);
40
+ const genFile = (0, generated_file_js_1.createGeneratedFile)(name, importPath, createTypeImport, runtime, {
39
41
  pluginName,
40
42
  pluginVersion,
41
43
  parameter: request.parameter,
@@ -63,22 +65,3 @@ function findFilesToGenerate(descriptorSet, request) {
63
65
  }
64
66
  return descriptorSet.files.filter((file) => request.fileToGenerate.includes(file.name + ".proto"));
65
67
  }
66
- /**
67
- * Returns the import path for files generated by the base type generator
68
- * protoc-gen-es.
69
- */
70
- function makeImportPath(file, bootstrapWkt, filesToGenerate) {
71
- // Well-known types are published with the runtime package. We usually want
72
- // the generated code to import them from the runtime package, with the
73
- // following exceptions:
74
- // 1. We are bootstrapping the runtime package via the plugin option
75
- // "bootstrap_wkt". In that case, we cannot refer to the runtime package
76
- // itself.
77
- // 2. We were explicitly asked to generate the well-known type.
78
- if (!bootstrapWkt &&
79
- !filesToGenerate.includes(file) &&
80
- protobuf_1.codegenInfo.wktSourceFiles.includes(file.name + ".proto")) {
81
- return protobuf_1.codegenInfo.packageName;
82
- }
83
- return "./" + file.name + "_pb.js";
84
- }
@@ -24,8 +24,8 @@ export function createEcmaScriptPlugin(init, generateFn) {
24
24
  name: init.name,
25
25
  version: init.version,
26
26
  run(req) {
27
- const { targets, tsNocheck, bootstrapWkt } = parseParameter(req.parameter, init.parseOption);
28
- const { schema, toResponse } = createSchema(req, targets, init.name, init.version, tsNocheck, bootstrapWkt);
27
+ const { targets, tsNocheck, bootstrapWkt, rewriteImports } = parseParameter(req.parameter, init.parseOption);
28
+ const { schema, toResponse } = createSchema(req, targets, init.name, init.version, tsNocheck, bootstrapWkt, rewriteImports);
29
29
  generateFn(schema);
30
30
  const res = new CodeGeneratorResponse();
31
31
  toResponse(res);
@@ -37,6 +37,7 @@ function parseParameter(parameter, parseOption) {
37
37
  let targets = ["js", "dts"];
38
38
  let tsNocheck = true;
39
39
  let bootstrapWkt = false;
40
+ const rewriteImports = [];
40
41
  for (const { key, value } of splitParameter(parameter)) {
41
42
  switch (key) {
42
43
  case "target":
@@ -84,6 +85,15 @@ function parseParameter(parameter, parseOption) {
84
85
  throw new PluginOptionError(`${key}=${value}`);
85
86
  }
86
87
  break;
88
+ case "rewrite_imports": {
89
+ const parts = value.split(":");
90
+ if (parts.length !== 2) {
91
+ throw new PluginOptionError(`${key}=${value}`, "must be in the form of <pattern>:<target>");
92
+ }
93
+ const [pattern, target] = parts;
94
+ rewriteImports.push({ pattern, target });
95
+ break;
96
+ }
87
97
  default:
88
98
  if (parseOption === undefined) {
89
99
  throw new PluginOptionError(`${key}=${value}`);
@@ -97,7 +107,7 @@ function parseParameter(parameter, parseOption) {
97
107
  break;
98
108
  }
99
109
  }
100
- return { targets, tsNocheck, bootstrapWkt };
110
+ return { targets, tsNocheck, bootstrapWkt, rewriteImports };
101
111
  }
102
112
  function splitParameter(parameter) {
103
113
  if (parameter == undefined) {
@@ -14,8 +14,8 @@
14
14
  import { CodeGeneratorResponse_File, } from "@bufbuild/protobuf";
15
15
  import { createImportSymbol } from "./import-symbol.js";
16
16
  import { literalString, makeFilePreamble } from "./gencommon.js";
17
- export function createGeneratedFile(name, createTypeImport, runtimeImports, preambleSettings) {
18
- const importPath = deriveImportPath(name);
17
+ import { makeImportPathRelative } from "./import-path.js";
18
+ export function createGeneratedFile(name, importPath, createTypeImport, runtimeImports, preambleSettings) {
19
19
  let preamble;
20
20
  const el = [];
21
21
  return {
@@ -51,16 +51,6 @@ export function createGeneratedFile(name, createTypeImport, runtimeImports, prea
51
51
  },
52
52
  };
53
53
  }
54
- const importPathExtension = ".js";
55
- const knownExtensionsRE = /\.(js|ts|d.ts)$/;
56
- const relativePathRE = /^\.{1,2}\//;
57
- function deriveImportPath(filename) {
58
- let importPath = filename.replace(knownExtensionsRE, importPathExtension);
59
- if (!relativePathRE.test(importPath)) {
60
- importPath = "./" + importPath;
61
- }
62
- return importPath;
63
- }
64
54
  function elToContent(el, importerPath) {
65
55
  const c = [];
66
56
  const symbolToIdentifier = processImports(el, importerPath, (typeOnly, from, names) => {
@@ -227,39 +217,6 @@ function processImports(el, importerPath, makeImportStatement) {
227
217
  }
228
218
  return symbolToIdentifier;
229
219
  }
230
- // makeImportPathRelative makes an import path relative to the file importing
231
- // it. For example, consider the following files:
232
- // - foo/foo.js
233
- // - baz.js
234
- // If foo.js wants to import baz.js, we return ../baz.js
235
- function makeImportPathRelative(importer, importPath) {
236
- if (!relativePathRE.test(importPath)) {
237
- // We don't touch absolute imports, like @bufbuild/protobuf
238
- return importPath;
239
- }
240
- let a = importer
241
- .replace(/^\.\//, "")
242
- .split("/")
243
- .filter((p) => p.length > 0)
244
- .slice(0, -1);
245
- let b = importPath
246
- .replace(/^\.\//, "")
247
- .split("/")
248
- .filter((p) => p.length > 0);
249
- let matchingPartCount = 0;
250
- for (let l = Math.min(a.length, b.length); matchingPartCount < l; matchingPartCount++) {
251
- if (a[matchingPartCount] !== b[matchingPartCount]) {
252
- break;
253
- }
254
- }
255
- a = a.slice(matchingPartCount);
256
- b = b.slice(matchingPartCount);
257
- const c = a
258
- .map(() => "..")
259
- .concat(b)
260
- .join("/");
261
- return relativePathRE.test(c) ? c : "./" + c;
262
- }
263
220
  function literalNumber(value) {
264
221
  if (Number.isNaN(value)) {
265
222
  return "globalThis.Number.NaN";
@@ -0,0 +1,137 @@
1
+ // Copyright 2021-2022 Buf Technologies, Inc.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ import { codegenInfo } from "@bufbuild/protobuf";
15
+ const cache = new WeakMap();
16
+ /**
17
+ * Apply import rewrites to the given path.
18
+ */
19
+ export function rewriteImportPath(importPath, rewriteImports) {
20
+ let ri = cache.get(rewriteImports);
21
+ if (ri === undefined) {
22
+ ri = rewriteImports.map(({ pattern, target }) => {
23
+ return {
24
+ pattern: starToRegExp(pattern),
25
+ target,
26
+ };
27
+ });
28
+ cache.set(rewriteImports, ri);
29
+ }
30
+ for (const { pattern, target } of ri) {
31
+ if (pattern.test(importPath)) {
32
+ return (target.replace(/\/$/, "") + importPath.replace(relativePathRE, "/"));
33
+ }
34
+ }
35
+ return importPath;
36
+ }
37
+ function starToRegExp(star) {
38
+ const r = ["^"];
39
+ for (let i = 0; i < star.length; i++) {
40
+ switch (star[i]) {
41
+ case "*":
42
+ if (star[i + 1] === "*" && star[i + 2] === "/") {
43
+ i += 2;
44
+ r.push("([^\\/]+\\/)*");
45
+ break;
46
+ }
47
+ r.push("[^\\/]*");
48
+ break;
49
+ case ".":
50
+ case "+":
51
+ case "?":
52
+ case "^":
53
+ case "$":
54
+ case "{":
55
+ case "}":
56
+ case "(":
57
+ case ")":
58
+ case "|":
59
+ case "[":
60
+ case "]":
61
+ case "\\":
62
+ r.push("\\", star[i]);
63
+ break;
64
+ default:
65
+ r.push(star[i]);
66
+ break;
67
+ }
68
+ }
69
+ r.push("$");
70
+ return new RegExp(r.join(""));
71
+ }
72
+ /**
73
+ * Returns the import path for files generated by the base type generator
74
+ * protoc-gen-es.
75
+ */
76
+ export function makeImportPath(file, bootstrapWkt, filesToGenerate) {
77
+ // Well-known types are published with the runtime package. We usually want
78
+ // the generated code to import them from the runtime package, with the
79
+ // following exceptions:
80
+ // 1. We are bootstrapping the runtime package via the plugin option
81
+ // "bootstrap_wkt". In that case, we cannot refer to the runtime package
82
+ // itself.
83
+ // 2. We were explicitly asked to generate the well-known type.
84
+ if (!bootstrapWkt &&
85
+ !filesToGenerate.includes(file) &&
86
+ codegenInfo.wktSourceFiles.includes(file.name + ".proto")) {
87
+ return codegenInfo.packageName;
88
+ }
89
+ return "./" + file.name + "_pb.js";
90
+ }
91
+ export const relativePathRE = /^\.{1,2}\//;
92
+ /**
93
+ * Derives an ECMAScript module import path from a file path. For example,
94
+ * the path `foo/bar.ts` is transformed into `./foo/bar.js`.
95
+ */
96
+ export function deriveImportPath(filename) {
97
+ let importPath = filename.replace(/\.(js|ts|d.ts)$/, ".js");
98
+ if (!relativePathRE.test(importPath)) {
99
+ importPath = "./" + importPath;
100
+ }
101
+ return importPath;
102
+ }
103
+ /**
104
+ * Makes an import path relative to the file importing it. For example,
105
+ * consider the following files:
106
+ * - foo/foo.js
107
+ * - baz.js
108
+ * If foo.js wants to import baz.js, we return ../baz.js
109
+ */
110
+ export function makeImportPathRelative(importer, importPath) {
111
+ if (!relativePathRE.test(importPath)) {
112
+ // We don't touch absolute imports, like @bufbuild/protobuf
113
+ return importPath;
114
+ }
115
+ let a = importer
116
+ .replace(/^\.\//, "")
117
+ .split("/")
118
+ .filter((p) => p.length > 0)
119
+ .slice(0, -1);
120
+ let b = importPath
121
+ .replace(/^\.\//, "")
122
+ .split("/")
123
+ .filter((p) => p.length > 0);
124
+ let matchingPartCount = 0;
125
+ for (let l = Math.min(a.length, b.length); matchingPartCount < l; matchingPartCount++) {
126
+ if (a[matchingPartCount] !== b[matchingPartCount]) {
127
+ break;
128
+ }
129
+ }
130
+ a = a.slice(matchingPartCount);
131
+ b = b.slice(matchingPartCount);
132
+ const c = a
133
+ .map(() => "..")
134
+ .concat(b)
135
+ .join("/");
136
+ return relativePathRE.test(c) ? c : "./" + c;
137
+ }
@@ -15,13 +15,14 @@ import { codegenInfo, CodeGeneratorResponse_Feature, createDescriptorSet, protoI
15
15
  import { createGeneratedFile } from "./generated-file.js";
16
16
  import { createRuntimeImports } from "./runtime-imports.js";
17
17
  import { createImportSymbol } from "./import-symbol.js";
18
- export function createSchema(request, targets, pluginName, pluginVersion, tsNocheck, bootstrapWkt) {
18
+ import { deriveImportPath, makeImportPath, rewriteImportPath, } from "./import-path.js";
19
+ export function createSchema(request, targets, pluginName, pluginVersion, tsNocheck, bootstrapWkt, rewriteImports) {
19
20
  const descriptorSet = createDescriptorSet(request.protoFile);
20
21
  const filesToGenerate = findFilesToGenerate(descriptorSet, request);
21
22
  const runtime = createRuntimeImports(bootstrapWkt);
22
23
  const createTypeImport = (desc) => {
23
24
  const name = codegenInfo.localName(desc);
24
- const from = makeImportPath(desc.file, bootstrapWkt, filesToGenerate);
25
+ const from = rewriteImportPath(makeImportPath(desc.file, bootstrapWkt, filesToGenerate), rewriteImports);
25
26
  return createImportSymbol(name, from);
26
27
  };
27
28
  const generatedFiles = [];
@@ -32,7 +33,8 @@ export function createSchema(request, targets, pluginName, pluginVersion, tsNoch
32
33
  files: filesToGenerate,
33
34
  allFiles: descriptorSet.files,
34
35
  generateFile(name) {
35
- const genFile = createGeneratedFile(name, createTypeImport, runtime, {
36
+ const importPath = rewriteImportPath(deriveImportPath(name), rewriteImports);
37
+ const genFile = createGeneratedFile(name, importPath, createTypeImport, runtime, {
36
38
  pluginName,
37
39
  pluginVersion,
38
40
  parameter: request.parameter,
@@ -59,22 +61,3 @@ function findFilesToGenerate(descriptorSet, request) {
59
61
  }
60
62
  return descriptorSet.files.filter((file) => request.fileToGenerate.includes(file.name + ".proto"));
61
63
  }
62
- /**
63
- * Returns the import path for files generated by the base type generator
64
- * protoc-gen-es.
65
- */
66
- function makeImportPath(file, bootstrapWkt, filesToGenerate) {
67
- // Well-known types are published with the runtime package. We usually want
68
- // the generated code to import them from the runtime package, with the
69
- // following exceptions:
70
- // 1. We are bootstrapping the runtime package via the plugin option
71
- // "bootstrap_wkt". In that case, we cannot refer to the runtime package
72
- // itself.
73
- // 2. We were explicitly asked to generate the well-known type.
74
- if (!bootstrapWkt &&
75
- !filesToGenerate.includes(file) &&
76
- codegenInfo.wktSourceFiles.includes(file.name + ".proto")) {
77
- return codegenInfo.packageName;
78
- }
79
- return "./" + file.name + "_pb.js";
80
- }
@@ -1,7 +1,7 @@
1
1
  import type { DescEnum, DescFile, DescMessage } from "@bufbuild/protobuf";
2
2
  import { CodeGeneratorResponse } from "@bufbuild/protobuf";
3
3
  import type { ImportSymbol } from "./import-symbol.js";
4
- import type { RuntimeImports } from "./runtime-imports";
4
+ import type { RuntimeImports } from "./runtime-imports.js";
5
5
  /**
6
6
  * All types that can be passed to GeneratedFile.print()
7
7
  */
@@ -54,7 +54,7 @@ export interface GenerateFileToResponse {
54
54
  toResponse(res: CodeGeneratorResponse): void;
55
55
  }
56
56
  declare type CreateTypeImportFn = (desc: DescMessage | DescEnum) => ImportSymbol;
57
- export declare function createGeneratedFile(name: string, createTypeImport: CreateTypeImportFn, runtimeImports: RuntimeImports, preambleSettings: {
57
+ export declare function createGeneratedFile(name: string, importPath: string, createTypeImport: CreateTypeImportFn, runtimeImports: RuntimeImports, preambleSettings: {
58
58
  pluginName: string;
59
59
  pluginVersion: string;
60
60
  parameter: string | undefined;
@@ -0,0 +1,64 @@
1
+ import { DescFile } from "@bufbuild/protobuf";
2
+ /**
3
+ * A configuration for rewriting import paths, a feature mainly used for
4
+ * remote code generation in the BSR npm registry, which makes it possible
5
+ * to serve the output of a BSR module and a plugin in an individual package.
6
+ *
7
+ * All plugins based on @bufbuild/protoplugin support the option
8
+ * "rewrite_imports", which is parsed into this type. The option can be given
9
+ * multiple times, in the form of `rewrite_imports=<pattern>:<target>`.
10
+ *
11
+ * The pattern is a very reduced subset of glob:
12
+ * - `*` matches zero or more characters except `/`.
13
+ * - `**` matches zero or more path elements, where an element is one or more
14
+ * characters with a trailing `/`.
15
+ *
16
+ * The target is typically a npm package name, for example `@scope/pkg`.
17
+ *
18
+ * If any generated file imports from a path matching one of the patterns, the
19
+ * import path is rewritten to the corresponding target, by prepending the
20
+ * target to the import path (after replacing any leading ./ or ../ from the
21
+ * import path with / first).
22
+ *
23
+ * Note that the pattern is matched against the import path before it is made
24
+ * relative to the file importing it. The first matching pattern wins.
25
+ *
26
+ * For example, the pattern `./foo/**\/*_pb.js` (escaped for block comment!)
27
+ * matches:
28
+ * - ./foo/bar_pb.js
29
+ * - ./foo/bar/baz_pb.js
30
+ *
31
+ * But neither of:
32
+ * - ./bar_pb.js
33
+ * - ./foo/bar_xx.js
34
+ *
35
+ * With the target `@scope/pkg`, the import path `./foo/bar_pb.js` is
36
+ * transformed to `@scope/pkg/foo/bar_pb.js`.
37
+ */
38
+ export declare type RewriteImports = {
39
+ pattern: string;
40
+ target: string;
41
+ }[];
42
+ /**
43
+ * Apply import rewrites to the given path.
44
+ */
45
+ export declare function rewriteImportPath(importPath: string, rewriteImports: RewriteImports): string;
46
+ /**
47
+ * Returns the import path for files generated by the base type generator
48
+ * protoc-gen-es.
49
+ */
50
+ export declare function makeImportPath(file: DescFile, bootstrapWkt: boolean, filesToGenerate: DescFile[]): string;
51
+ export declare const relativePathRE: RegExp;
52
+ /**
53
+ * Derives an ECMAScript module import path from a file path. For example,
54
+ * the path `foo/bar.ts` is transformed into `./foo/bar.js`.
55
+ */
56
+ export declare function deriveImportPath(filename: string): string;
57
+ /**
58
+ * Makes an import path relative to the file importing it. For example,
59
+ * consider the following files:
60
+ * - foo/foo.js
61
+ * - baz.js
62
+ * If foo.js wants to import baz.js, we return ../baz.js
63
+ */
64
+ export declare function makeImportPathRelative(importer: string, importPath: string): string;
@@ -2,7 +2,8 @@ import type { CodeGeneratorRequest, DescFile } from "@bufbuild/protobuf";
2
2
  import { CodeGeneratorResponse } from "@bufbuild/protobuf";
3
3
  import type { GeneratedFile } from "./generated-file.js";
4
4
  import { RuntimeImports } from "./runtime-imports.js";
5
- import type { Target } from "./target";
5
+ import type { Target } from "./target.js";
6
+ import { RewriteImports } from "./import-path.js";
6
7
  /**
7
8
  * Schema describes the files and types that the plugin is requested to
8
9
  * generate.
@@ -37,5 +38,5 @@ interface SchemaController {
37
38
  schema: Schema;
38
39
  toResponse: (res: CodeGeneratorResponse) => void;
39
40
  }
40
- export declare function createSchema(request: CodeGeneratorRequest, targets: Target[], pluginName: string, pluginVersion: string, tsNocheck: boolean, bootstrapWkt: boolean): SchemaController;
41
+ export declare function createSchema(request: CodeGeneratorRequest, targets: Target[], pluginName: string, pluginVersion: string, tsNocheck: boolean, bootstrapWkt: boolean, rewriteImports: RewriteImports): SchemaController;
41
42
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bufbuild/protoplugin",
3
- "version": "0.0.10",
3
+ "version": "0.1.0",
4
4
  "license": "(Apache-2.0 AND BSD-3-Clause)",
5
5
  "description": "Helps to create your own Protocol Buffers code generators.",
6
6
  "repository": {
@@ -12,20 +12,18 @@
12
12
  "scripts": {
13
13
  "clean": "rm -rf ./dist/cjs/* ./dist/esm/* ./dist/types/*",
14
14
  "build": "npm run build:cjs && npm run build:esm+types",
15
- "build:cjs": "npx tsc --project tsconfig.json --module commonjs --outDir ./dist/cjs && echo >./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
16
- "build:esm+types": "npx tsc --project tsconfig.json --module ES2015 --outDir ./dist/esm --declaration --declarationDir ./dist/types"
15
+ "build:cjs": "../../node_modules/typescript/bin/tsc --project tsconfig.json --module commonjs --outDir ./dist/cjs && echo >./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
16
+ "build:esm+types": "../../node_modules/typescript/bin/tsc --project tsconfig.json --module ES2015 --outDir ./dist/esm --declaration --declarationDir ./dist/types"
17
17
  },
18
18
  "type": "module",
19
19
  "exports": {
20
20
  ".": {
21
21
  "import": "./dist/esm/index.js",
22
- "require": "./dist/cjs/index.js",
23
- "default": "./dist/esm/index.js"
22
+ "require": "./dist/cjs/index.js"
24
23
  },
25
24
  "./ecmascript": {
26
25
  "import": "./dist/esm/ecmascript/index.js",
27
- "require": "./dist/cjs/ecmascript/index.js",
28
- "default": "./dist/esm/ecmascript/index.js"
26
+ "require": "./dist/cjs/ecmascript/index.js"
29
27
  }
30
28
  },
31
29
  "types": "./dist/types/index.d.ts",
@@ -37,7 +35,7 @@
37
35
  }
38
36
  },
39
37
  "dependencies": {
40
- "@bufbuild/protobuf": "0.0.10"
38
+ "@bufbuild/protobuf": "0.1.0"
41
39
  },
42
40
  "devDependencies": {
43
41
  "typescript": "^4.7.4"