@bufbuild/protoplugin 2.0.0-alpha.1 → 2.0.0-alpha.2
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/dist/cjs/ecmascript/file-preamble.js +3 -0
- package/dist/cjs/ecmascript/jsdoc.js +17 -5
- package/dist/cjs/ecmascript/parameter.js +1 -1
- package/dist/cjs/ecmascript/schema.js +9 -1
- package/dist/cjs/source-code-info.d.ts +6 -1
- package/dist/cjs/source-code-info.js +72 -45
- package/dist/esm/ecmascript/file-preamble.js +4 -1
- package/dist/esm/ecmascript/jsdoc.js +18 -6
- package/dist/esm/ecmascript/parameter.js +1 -1
- package/dist/esm/ecmascript/schema.js +9 -1
- package/dist/esm/source-code-info.d.ts +6 -1
- package/dist/esm/source-code-info.js +73 -47
- package/package.json +2 -2
|
@@ -64,6 +64,9 @@ function makeFilePreamble(file, pluginName, pluginVersion, parameter, tsNoCheck)
|
|
|
64
64
|
break;
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
|
+
for (const o of (0, source_code_info_js_1.getFeatureOptionStrings)(file)) {
|
|
68
|
+
builder.push(`// option ${o};\n`);
|
|
69
|
+
}
|
|
67
70
|
builder.push("/* eslint-disable */\n");
|
|
68
71
|
if (tsNoCheck) {
|
|
69
72
|
builder.push("// @ts-nocheck\n");
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
16
|
exports.formatJsDocBlock = exports.createJsDocTextFromDesc = void 0;
|
|
17
17
|
const source_code_info_js_1 = require("../source-code-info.js");
|
|
18
|
+
const reflect_1 = require("@bufbuild/protobuf/reflect");
|
|
18
19
|
function createJsDocTextFromDesc(desc) {
|
|
19
20
|
const comments = (0, source_code_info_js_1.getComments)(desc);
|
|
20
21
|
let text = "";
|
|
@@ -50,18 +51,29 @@ function createJsDocTextFromDesc(desc) {
|
|
|
50
51
|
case "extension":
|
|
51
52
|
text += `@generated from extension: ${(0, source_code_info_js_1.getDeclarationString)(desc)};`;
|
|
52
53
|
break;
|
|
54
|
+
case "message":
|
|
55
|
+
case "enum": {
|
|
56
|
+
text += `@generated from ${desc.toString()}`;
|
|
57
|
+
const featureOptions = (0, source_code_info_js_1.getFeatureOptionStrings)(desc);
|
|
58
|
+
if (featureOptions.length > 0) {
|
|
59
|
+
text += `\n@generated with ${featureOptions.length > 1 ? "options" : "option"} ${featureOptions.join(", ")}`;
|
|
60
|
+
}
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
53
63
|
default:
|
|
54
64
|
text += `@generated from ${desc.toString()}`;
|
|
55
65
|
break;
|
|
56
66
|
}
|
|
57
|
-
let deprecated
|
|
67
|
+
let deprecated;
|
|
58
68
|
switch (desc.kind) {
|
|
59
|
-
case "
|
|
60
|
-
case "
|
|
61
|
-
case "
|
|
62
|
-
deprecated =
|
|
69
|
+
case "field":
|
|
70
|
+
case "enum_value":
|
|
71
|
+
case "rpc":
|
|
72
|
+
deprecated = desc.deprecated;
|
|
63
73
|
break;
|
|
64
74
|
default:
|
|
75
|
+
deprecated =
|
|
76
|
+
desc.deprecated || (0, reflect_1.parentTypes)(desc).some((d) => d.deprecated);
|
|
65
77
|
break;
|
|
66
78
|
}
|
|
67
79
|
if (deprecated) {
|
|
@@ -21,7 +21,7 @@ function parseParameter(parameter, parseExtraOption) {
|
|
|
21
21
|
let bootstrapWkt = false;
|
|
22
22
|
let keepEmptyFiles = false;
|
|
23
23
|
const rewriteImports = [];
|
|
24
|
-
let importExtension = "
|
|
24
|
+
let importExtension = "";
|
|
25
25
|
let jsImportStyle = "module";
|
|
26
26
|
const rawParameters = [];
|
|
27
27
|
for (const { key, value, raw } of splitParameter(parameter)) {
|
|
@@ -92,8 +92,16 @@ function getFilesToGenerate(request, minimumEdition, maximumEdition) {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
|
+
// Our goal is to provide options with source retention to plugin authors.
|
|
96
|
+
// CodeGeneratorRequest.proto_file elides options with source retention for
|
|
97
|
+
// files to generate. For these files, we take the file from source_file_descriptors,
|
|
98
|
+
// which does include options with source retention.
|
|
99
|
+
const allProtoWithSourceOptions = request.protoFile.map((protoFile) => {
|
|
100
|
+
const sourceFile = request.sourceFileDescriptors.find((s) => s.name == protoFile.name);
|
|
101
|
+
return sourceFile !== null && sourceFile !== void 0 ? sourceFile : protoFile;
|
|
102
|
+
});
|
|
95
103
|
const registry = (0, reflect_1.createFileRegistry)((0, protobuf_1.create)(wkt_1.FileDescriptorSetDesc, {
|
|
96
|
-
file:
|
|
104
|
+
file: allProtoWithSourceOptions,
|
|
97
105
|
}));
|
|
98
106
|
const allFiles = [];
|
|
99
107
|
const filesToGenerate = [];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AnyDesc, type DescComments, type DescEnumValue, type DescExtension, type DescField, type DescFile } from "@bufbuild/protobuf";
|
|
2
2
|
/**
|
|
3
3
|
* Get comments on the package element in the protobuf source.
|
|
4
4
|
*/
|
|
@@ -11,6 +11,11 @@ export declare function getSyntaxComments(desc: DescFile): DescComments;
|
|
|
11
11
|
* Get comments on the element in the protobuf source.
|
|
12
12
|
*/
|
|
13
13
|
export declare function getComments(desc: Exclude<AnyDesc, DescFile>): DescComments;
|
|
14
|
+
/**
|
|
15
|
+
* Get feature options set on the element in the protobuf source. This returns
|
|
16
|
+
* compact (e.g. fields) or regular options (e.g. files) as an array of strings.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getFeatureOptionStrings(desc: AnyDesc): string[];
|
|
14
19
|
/**
|
|
15
20
|
* Return a string that matches the definition of a field in the protobuf
|
|
16
21
|
* source. Does not take custom options into account.
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// See the License for the specific language governing permissions and
|
|
14
14
|
// limitations under the License.
|
|
15
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
-
exports.getDeclarationString = exports.getComments = exports.getSyntaxComments = exports.getPackageComments = void 0;
|
|
16
|
+
exports.getDeclarationString = exports.getFeatureOptionStrings = exports.getComments = exports.getSyntaxComments = exports.getPackageComments = void 0;
|
|
17
17
|
const protobuf_1 = require("@bufbuild/protobuf");
|
|
18
18
|
const reflect_1 = require("@bufbuild/protobuf/reflect");
|
|
19
19
|
const wkt_1 = require("@bufbuild/protobuf/wkt");
|
|
@@ -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
|
-
|
|
25
|
+
wkt_1.FileDescriptorProtoDesc.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
|
-
|
|
34
|
+
wkt_1.FileDescriptorProtoDesc.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
|
-
|
|
49
|
+
wkt_1.DescriptorProtoDesc.field.enumType.number,
|
|
50
50
|
desc.parent.proto.enumType.indexOf(desc.proto),
|
|
51
51
|
]
|
|
52
52
|
: [
|
|
53
|
-
|
|
53
|
+
wkt_1.FileDescriptorProtoDesc.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
|
-
|
|
61
|
+
wkt_1.DescriptorProtoDesc.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
|
-
|
|
70
|
+
wkt_1.DescriptorProtoDesc.field.nestedType.number,
|
|
71
71
|
desc.parent.proto.nestedType.indexOf(desc.proto),
|
|
72
72
|
]
|
|
73
73
|
: [
|
|
74
|
-
|
|
74
|
+
wkt_1.FileDescriptorProtoDesc.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
|
-
|
|
82
|
+
wkt_1.EnumDescriptorProtoDesc.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
|
-
|
|
90
|
+
wkt_1.DescriptorProtoDesc.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
|
-
|
|
99
|
+
wkt_1.DescriptorProtoDesc.field.extension.number,
|
|
100
100
|
desc.parent.proto.extension.indexOf(desc.proto),
|
|
101
101
|
]
|
|
102
102
|
: [
|
|
103
|
-
|
|
103
|
+
wkt_1.FileDescriptorProtoDesc.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
|
-
|
|
110
|
+
wkt_1.FileDescriptorProtoDesc.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
|
-
|
|
118
|
+
wkt_1.ServiceDescriptorProtoDesc.field.method.number,
|
|
119
119
|
desc.parent.proto.method.indexOf(desc.proto),
|
|
120
120
|
];
|
|
121
121
|
file = desc.parent.file;
|
|
@@ -124,6 +124,30 @@ function getComments(desc) {
|
|
|
124
124
|
return findComments(file.proto.sourceCodeInfo, path);
|
|
125
125
|
}
|
|
126
126
|
exports.getComments = getComments;
|
|
127
|
+
/**
|
|
128
|
+
* Get feature options set on the element in the protobuf source. This returns
|
|
129
|
+
* compact (e.g. fields) or regular options (e.g. files) as an array of strings.
|
|
130
|
+
*/
|
|
131
|
+
function getFeatureOptionStrings(desc) {
|
|
132
|
+
var _a, _b;
|
|
133
|
+
const strings = [];
|
|
134
|
+
const features = (_a = desc.proto.options) === null || _a === void 0 ? void 0 : _a.features;
|
|
135
|
+
if (features !== undefined) {
|
|
136
|
+
const r = (0, reflect_1.reflect)(wkt_1.FeatureSetDesc, features);
|
|
137
|
+
for (const f of r.fields) {
|
|
138
|
+
if (f.fieldKind != "enum" || !r.isSet(f)) {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const val = r.get(f);
|
|
142
|
+
const name = (_b = f.enum.values.find((v) => v.number == val)) === null || _b === void 0 ? void 0 : _b.name;
|
|
143
|
+
if (name !== undefined) {
|
|
144
|
+
strings.push(`features.${f.name} = ${name}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return strings;
|
|
149
|
+
}
|
|
150
|
+
exports.getFeatureOptionStrings = getFeatureOptionStrings;
|
|
127
151
|
/**
|
|
128
152
|
* Return a string that matches the definition of a field in the protobuf
|
|
129
153
|
* source. Does not take custom options into account.
|
|
@@ -137,7 +161,6 @@ function getDeclarationString(desc) {
|
|
|
137
161
|
}
|
|
138
162
|
return str;
|
|
139
163
|
}
|
|
140
|
-
const file = desc.kind === "extension" ? desc.file : desc.parent.file;
|
|
141
164
|
const parts = [];
|
|
142
165
|
function typeName(f) {
|
|
143
166
|
if (f.message) {
|
|
@@ -152,12 +175,10 @@ function getDeclarationString(desc) {
|
|
|
152
175
|
case "scalar":
|
|
153
176
|
case "enum":
|
|
154
177
|
case "message":
|
|
155
|
-
if (
|
|
156
|
-
(0, protobuf_1.isFieldSet)(wkt_1.FieldDescriptorProtoDesc, desc.proto, "label") &&
|
|
157
|
-
desc.proto.label == wkt_1.FieldDescriptorProto_Label.REQUIRED) {
|
|
178
|
+
if (fieldHasRequiredKeyword(desc)) {
|
|
158
179
|
parts.push("required");
|
|
159
180
|
}
|
|
160
|
-
if (desc
|
|
181
|
+
if (fieldHasOptionalKeyword(desc)) {
|
|
161
182
|
parts.push("optional");
|
|
162
183
|
}
|
|
163
184
|
parts.push(typeName(desc));
|
|
@@ -176,10 +197,10 @@ function getDeclarationString(desc) {
|
|
|
176
197
|
const options = [];
|
|
177
198
|
const protoOptions = desc.proto.options;
|
|
178
199
|
if (protoOptions !== undefined &&
|
|
179
|
-
(0, protobuf_1.isFieldSet)(wkt_1.FieldOptionsDesc
|
|
200
|
+
(0, protobuf_1.isFieldSet)(protoOptions, wkt_1.FieldOptionsDesc.field.packed)) {
|
|
180
201
|
options.push(`packed = ${protoOptions.packed.toString()}`);
|
|
181
202
|
}
|
|
182
|
-
if ((0, protobuf_1.isFieldSet)(
|
|
203
|
+
if ((0, protobuf_1.isFieldSet)(desc.proto, wkt_1.FieldDescriptorProtoDesc.field.defaultValue)) {
|
|
183
204
|
let defaultValue = desc.proto.defaultValue;
|
|
184
205
|
if (desc.proto.type == wkt_1.FieldDescriptorProto_Type.BYTES ||
|
|
185
206
|
desc.proto.type == wkt_1.FieldDescriptorProto_Type.STRING) {
|
|
@@ -191,19 +212,45 @@ function getDeclarationString(desc) {
|
|
|
191
212
|
options.push(`json_name = "${desc.jsonName}"`);
|
|
192
213
|
}
|
|
193
214
|
if (protoOptions !== undefined &&
|
|
194
|
-
(0, protobuf_1.isFieldSet)(wkt_1.FieldOptionsDesc
|
|
215
|
+
(0, protobuf_1.isFieldSet)(protoOptions, wkt_1.FieldOptionsDesc.field.jstype)) {
|
|
195
216
|
options.push(`jstype = ${wkt_1.FieldOptions_JSType[protoOptions.jstype]}`);
|
|
196
217
|
}
|
|
197
218
|
if (protoOptions !== undefined &&
|
|
198
|
-
(0, protobuf_1.isFieldSet)(wkt_1.FieldOptionsDesc
|
|
219
|
+
(0, protobuf_1.isFieldSet)(protoOptions, wkt_1.FieldOptionsDesc.field.deprecated)) {
|
|
199
220
|
options.push(`deprecated = true`);
|
|
200
221
|
}
|
|
222
|
+
options.push(...getFeatureOptionStrings(desc));
|
|
201
223
|
if (options.length > 0) {
|
|
202
224
|
parts.push("[" + options.join(", ") + "]");
|
|
203
225
|
}
|
|
204
226
|
return parts.join(" ");
|
|
205
227
|
}
|
|
206
228
|
exports.getDeclarationString = getDeclarationString;
|
|
229
|
+
/**
|
|
230
|
+
* Whether this field was declared with `required` in the protobuf source.
|
|
231
|
+
*/
|
|
232
|
+
function fieldHasRequiredKeyword(field) {
|
|
233
|
+
const edition = (field.kind == "extension" ? field.file : field.parent.file)
|
|
234
|
+
.edition;
|
|
235
|
+
return (edition == wkt_1.Edition.EDITION_PROTO2 &&
|
|
236
|
+
field.proto.label == wkt_1.FieldDescriptorProto_Label.REQUIRED);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Whether this field was declared with `optional` in the protobuf source.
|
|
240
|
+
* Note that message fields are always optional. It is impossible to determine
|
|
241
|
+
* whether the keyword was used.
|
|
242
|
+
*/
|
|
243
|
+
function fieldHasOptionalKeyword(field) {
|
|
244
|
+
const edition = (field.kind == "extension" ? field.file : field.parent.file)
|
|
245
|
+
.edition;
|
|
246
|
+
if (edition == wkt_1.Edition.EDITION_PROTO2) {
|
|
247
|
+
return (!field.oneof && field.proto.label == wkt_1.FieldDescriptorProto_Label.OPTIONAL);
|
|
248
|
+
}
|
|
249
|
+
if (edition == wkt_1.Edition.EDITION_PROTO3) {
|
|
250
|
+
return field.proto.proto3Optional;
|
|
251
|
+
}
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
207
254
|
/**
|
|
208
255
|
* Find comments.
|
|
209
256
|
*/
|
|
@@ -223,10 +270,10 @@ function findComments(sourceCodeInfo, sourcePath) {
|
|
|
223
270
|
}
|
|
224
271
|
return {
|
|
225
272
|
leadingDetached: location.leadingDetachedComments,
|
|
226
|
-
leading: (0, protobuf_1.isFieldSet)(wkt_1.SourceCodeInfo_LocationDesc
|
|
273
|
+
leading: (0, protobuf_1.isFieldSet)(location, wkt_1.SourceCodeInfo_LocationDesc.field.leadingComments)
|
|
227
274
|
? location.leadingComments
|
|
228
275
|
: undefined,
|
|
229
|
-
trailing: (0, protobuf_1.isFieldSet)(wkt_1.SourceCodeInfo_LocationDesc
|
|
276
|
+
trailing: (0, protobuf_1.isFieldSet)(location, wkt_1.SourceCodeInfo_LocationDesc.field.trailingComments)
|
|
230
277
|
? location.trailingComments
|
|
231
278
|
: undefined,
|
|
232
279
|
sourcePath,
|
|
@@ -237,23 +284,3 @@ function findComments(sourceCodeInfo, sourcePath) {
|
|
|
237
284
|
sourcePath,
|
|
238
285
|
};
|
|
239
286
|
}
|
|
240
|
-
/**
|
|
241
|
-
* The following field numbers are used to find comments in
|
|
242
|
-
* google.protobuf.SourceCodeInfo.
|
|
243
|
-
*/
|
|
244
|
-
var FieldNumber;
|
|
245
|
-
(function (FieldNumber) {
|
|
246
|
-
FieldNumber[FieldNumber["FileDescriptorProto_Package"] = 2] = "FileDescriptorProto_Package";
|
|
247
|
-
FieldNumber[FieldNumber["FileDescriptorProto_MessageType"] = 4] = "FileDescriptorProto_MessageType";
|
|
248
|
-
FieldNumber[FieldNumber["FileDescriptorProto_EnumType"] = 5] = "FileDescriptorProto_EnumType";
|
|
249
|
-
FieldNumber[FieldNumber["FileDescriptorProto_Service"] = 6] = "FileDescriptorProto_Service";
|
|
250
|
-
FieldNumber[FieldNumber["FileDescriptorProto_Extension"] = 7] = "FileDescriptorProto_Extension";
|
|
251
|
-
FieldNumber[FieldNumber["FileDescriptorProto_Syntax"] = 12] = "FileDescriptorProto_Syntax";
|
|
252
|
-
FieldNumber[FieldNumber["DescriptorProto_Field"] = 2] = "DescriptorProto_Field";
|
|
253
|
-
FieldNumber[FieldNumber["DescriptorProto_NestedType"] = 3] = "DescriptorProto_NestedType";
|
|
254
|
-
FieldNumber[FieldNumber["DescriptorProto_EnumType"] = 4] = "DescriptorProto_EnumType";
|
|
255
|
-
FieldNumber[FieldNumber["DescriptorProto_Extension"] = 6] = "DescriptorProto_Extension";
|
|
256
|
-
FieldNumber[FieldNumber["DescriptorProto_OneofDecl"] = 8] = "DescriptorProto_OneofDecl";
|
|
257
|
-
FieldNumber[FieldNumber["EnumDescriptorProto_Value"] = 2] = "EnumDescriptorProto_Value";
|
|
258
|
-
FieldNumber[FieldNumber["ServiceDescriptorProto_Method"] = 2] = "ServiceDescriptorProto_Method";
|
|
259
|
-
})(FieldNumber || (FieldNumber = {}));
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// See the License for the specific language governing permissions and
|
|
13
13
|
// limitations under the License.
|
|
14
14
|
import { Edition } from "@bufbuild/protobuf/wkt";
|
|
15
|
-
import { getPackageComments, getSyntaxComments } from "../source-code-info.js";
|
|
15
|
+
import { getPackageComments, getSyntaxComments, getFeatureOptionStrings, } from "../source-code-info.js";
|
|
16
16
|
export function makeFilePreamble(file, pluginName, pluginVersion, parameter, tsNoCheck) {
|
|
17
17
|
const builder = [];
|
|
18
18
|
const trimSuffix = (str, suffix) => str.endsWith(suffix) ? str.substring(0, str.length - suffix.length) : str;
|
|
@@ -61,6 +61,9 @@ export function makeFilePreamble(file, pluginName, pluginVersion, parameter, tsN
|
|
|
61
61
|
break;
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
|
+
for (const o of getFeatureOptionStrings(file)) {
|
|
65
|
+
builder.push(`// option ${o};\n`);
|
|
66
|
+
}
|
|
64
67
|
builder.push("/* eslint-disable */\n");
|
|
65
68
|
if (tsNoCheck) {
|
|
66
69
|
builder.push("// @ts-nocheck\n");
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
// See the License for the specific language governing permissions and
|
|
13
13
|
// limitations under the License.
|
|
14
|
-
import { getComments, getDeclarationString } from "../source-code-info.js";
|
|
14
|
+
import { getComments, getDeclarationString, getFeatureOptionStrings, } from "../source-code-info.js";
|
|
15
|
+
import { parentTypes } from "@bufbuild/protobuf/reflect";
|
|
15
16
|
export function createJsDocTextFromDesc(desc) {
|
|
16
17
|
const comments = getComments(desc);
|
|
17
18
|
let text = "";
|
|
@@ -47,18 +48,29 @@ export function createJsDocTextFromDesc(desc) {
|
|
|
47
48
|
case "extension":
|
|
48
49
|
text += `@generated from extension: ${getDeclarationString(desc)};`;
|
|
49
50
|
break;
|
|
51
|
+
case "message":
|
|
52
|
+
case "enum": {
|
|
53
|
+
text += `@generated from ${desc.toString()}`;
|
|
54
|
+
const featureOptions = getFeatureOptionStrings(desc);
|
|
55
|
+
if (featureOptions.length > 0) {
|
|
56
|
+
text += `\n@generated with ${featureOptions.length > 1 ? "options" : "option"} ${featureOptions.join(", ")}`;
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
50
60
|
default:
|
|
51
61
|
text += `@generated from ${desc.toString()}`;
|
|
52
62
|
break;
|
|
53
63
|
}
|
|
54
|
-
let deprecated
|
|
64
|
+
let deprecated;
|
|
55
65
|
switch (desc.kind) {
|
|
56
|
-
case "
|
|
57
|
-
case "
|
|
58
|
-
case "
|
|
59
|
-
deprecated =
|
|
66
|
+
case "field":
|
|
67
|
+
case "enum_value":
|
|
68
|
+
case "rpc":
|
|
69
|
+
deprecated = desc.deprecated;
|
|
60
70
|
break;
|
|
61
71
|
default:
|
|
72
|
+
deprecated =
|
|
73
|
+
desc.deprecated || parentTypes(desc).some((d) => d.deprecated);
|
|
62
74
|
break;
|
|
63
75
|
}
|
|
64
76
|
if (deprecated) {
|
|
@@ -18,7 +18,7 @@ export function parseParameter(parameter, parseExtraOption) {
|
|
|
18
18
|
let bootstrapWkt = false;
|
|
19
19
|
let keepEmptyFiles = false;
|
|
20
20
|
const rewriteImports = [];
|
|
21
|
-
let importExtension = "
|
|
21
|
+
let importExtension = "";
|
|
22
22
|
let jsImportStyle = "module";
|
|
23
23
|
const rawParameters = [];
|
|
24
24
|
for (const { key, value, raw } of splitParameter(parameter)) {
|
|
@@ -88,8 +88,16 @@ function getFilesToGenerate(request, minimumEdition, maximumEdition) {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
+
// Our goal is to provide options with source retention to plugin authors.
|
|
92
|
+
// CodeGeneratorRequest.proto_file elides options with source retention for
|
|
93
|
+
// files to generate. For these files, we take the file from source_file_descriptors,
|
|
94
|
+
// which does include options with source retention.
|
|
95
|
+
const allProtoWithSourceOptions = request.protoFile.map((protoFile) => {
|
|
96
|
+
const sourceFile = request.sourceFileDescriptors.find((s) => s.name == protoFile.name);
|
|
97
|
+
return sourceFile !== null && sourceFile !== void 0 ? sourceFile : protoFile;
|
|
98
|
+
});
|
|
91
99
|
const registry = createFileRegistry(create(FileDescriptorSetDesc, {
|
|
92
|
-
file:
|
|
100
|
+
file: allProtoWithSourceOptions,
|
|
93
101
|
}));
|
|
94
102
|
const allFiles = [];
|
|
95
103
|
const filesToGenerate = [];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AnyDesc, type DescComments, type DescEnumValue, type DescExtension, type DescField, type DescFile } from "@bufbuild/protobuf";
|
|
2
2
|
/**
|
|
3
3
|
* Get comments on the package element in the protobuf source.
|
|
4
4
|
*/
|
|
@@ -11,6 +11,11 @@ export declare function getSyntaxComments(desc: DescFile): DescComments;
|
|
|
11
11
|
* Get comments on the element in the protobuf source.
|
|
12
12
|
*/
|
|
13
13
|
export declare function getComments(desc: Exclude<AnyDesc, DescFile>): DescComments;
|
|
14
|
+
/**
|
|
15
|
+
* Get feature options set on the element in the protobuf source. This returns
|
|
16
|
+
* compact (e.g. fields) or regular options (e.g. files) as an array of strings.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getFeatureOptionStrings(desc: AnyDesc): string[];
|
|
14
19
|
/**
|
|
15
20
|
* Return a string that matches the definition of a field in the protobuf
|
|
16
21
|
* source. Does not take custom options into account.
|
|
@@ -11,15 +11,15 @@
|
|
|
11
11
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
// See the License for the specific language governing permissions and
|
|
13
13
|
// limitations under the License.
|
|
14
|
-
import { isFieldSet } from "@bufbuild/protobuf";
|
|
15
|
-
import { ScalarType,
|
|
16
|
-
import { Edition, FieldDescriptorProto_Label, FieldDescriptorProto_Type, FieldDescriptorProtoDesc, FieldOptions_JSType, FieldOptionsDesc, SourceCodeInfo_LocationDesc, } from "@bufbuild/protobuf/wkt";
|
|
14
|
+
import { isFieldSet, } from "@bufbuild/protobuf";
|
|
15
|
+
import { protoCamelCase, reflect, ScalarType, } from "@bufbuild/protobuf/reflect";
|
|
16
|
+
import { Edition, FieldDescriptorProto_Label, FieldDescriptorProto_Type, FieldDescriptorProtoDesc, FieldOptions_JSType, FieldOptionsDesc, FeatureSetDesc, SourceCodeInfo_LocationDesc, FileDescriptorProtoDesc, DescriptorProtoDesc, EnumDescriptorProtoDesc, ServiceDescriptorProtoDesc, } from "@bufbuild/protobuf/wkt";
|
|
17
17
|
/**
|
|
18
18
|
* Get comments on the package element in the protobuf source.
|
|
19
19
|
*/
|
|
20
20
|
export function getPackageComments(desc) {
|
|
21
21
|
return findComments(desc.proto.sourceCodeInfo, [
|
|
22
|
-
|
|
22
|
+
FileDescriptorProtoDesc.field.package.number,
|
|
23
23
|
]);
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
@@ -27,7 +27,7 @@ export function getPackageComments(desc) {
|
|
|
27
27
|
*/
|
|
28
28
|
export function getSyntaxComments(desc) {
|
|
29
29
|
return findComments(desc.proto.sourceCodeInfo, [
|
|
30
|
-
|
|
30
|
+
FileDescriptorProtoDesc.field.syntax.number,
|
|
31
31
|
]);
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
@@ -41,11 +41,11 @@ export function getComments(desc) {
|
|
|
41
41
|
path = desc.parent
|
|
42
42
|
? [
|
|
43
43
|
...getComments(desc.parent).sourcePath,
|
|
44
|
-
|
|
44
|
+
DescriptorProtoDesc.field.enumType.number,
|
|
45
45
|
desc.parent.proto.enumType.indexOf(desc.proto),
|
|
46
46
|
]
|
|
47
47
|
: [
|
|
48
|
-
|
|
48
|
+
FileDescriptorProtoDesc.field.enumType.number,
|
|
49
49
|
desc.file.proto.enumType.indexOf(desc.proto),
|
|
50
50
|
];
|
|
51
51
|
file = desc.file;
|
|
@@ -53,7 +53,7 @@ export function getComments(desc) {
|
|
|
53
53
|
case "oneof":
|
|
54
54
|
path = [
|
|
55
55
|
...getComments(desc.parent).sourcePath,
|
|
56
|
-
|
|
56
|
+
DescriptorProtoDesc.field.oneofDecl.number,
|
|
57
57
|
desc.parent.proto.oneofDecl.indexOf(desc.proto),
|
|
58
58
|
];
|
|
59
59
|
file = desc.parent.file;
|
|
@@ -62,11 +62,11 @@ export function getComments(desc) {
|
|
|
62
62
|
path = desc.parent
|
|
63
63
|
? [
|
|
64
64
|
...getComments(desc.parent).sourcePath,
|
|
65
|
-
|
|
65
|
+
DescriptorProtoDesc.field.nestedType.number,
|
|
66
66
|
desc.parent.proto.nestedType.indexOf(desc.proto),
|
|
67
67
|
]
|
|
68
68
|
: [
|
|
69
|
-
|
|
69
|
+
FileDescriptorProtoDesc.field.messageType.number,
|
|
70
70
|
desc.file.proto.messageType.indexOf(desc.proto),
|
|
71
71
|
];
|
|
72
72
|
file = desc.file;
|
|
@@ -74,7 +74,7 @@ export function getComments(desc) {
|
|
|
74
74
|
case "enum_value":
|
|
75
75
|
path = [
|
|
76
76
|
...getComments(desc.parent).sourcePath,
|
|
77
|
-
|
|
77
|
+
EnumDescriptorProtoDesc.field.value.number,
|
|
78
78
|
desc.parent.proto.value.indexOf(desc.proto),
|
|
79
79
|
];
|
|
80
80
|
file = desc.parent.file;
|
|
@@ -82,7 +82,7 @@ export function getComments(desc) {
|
|
|
82
82
|
case "field":
|
|
83
83
|
path = [
|
|
84
84
|
...getComments(desc.parent).sourcePath,
|
|
85
|
-
|
|
85
|
+
DescriptorProtoDesc.field.field.number,
|
|
86
86
|
desc.parent.proto.field.indexOf(desc.proto),
|
|
87
87
|
];
|
|
88
88
|
file = desc.parent.file;
|
|
@@ -91,18 +91,18 @@ export function getComments(desc) {
|
|
|
91
91
|
path = desc.parent
|
|
92
92
|
? [
|
|
93
93
|
...getComments(desc.parent).sourcePath,
|
|
94
|
-
|
|
94
|
+
DescriptorProtoDesc.field.extension.number,
|
|
95
95
|
desc.parent.proto.extension.indexOf(desc.proto),
|
|
96
96
|
]
|
|
97
97
|
: [
|
|
98
|
-
|
|
98
|
+
FileDescriptorProtoDesc.field.extension.number,
|
|
99
99
|
desc.file.proto.extension.indexOf(desc.proto),
|
|
100
100
|
];
|
|
101
101
|
file = desc.file;
|
|
102
102
|
break;
|
|
103
103
|
case "service":
|
|
104
104
|
path = [
|
|
105
|
-
|
|
105
|
+
FileDescriptorProtoDesc.field.service.number,
|
|
106
106
|
desc.file.proto.service.indexOf(desc.proto),
|
|
107
107
|
];
|
|
108
108
|
file = desc.file;
|
|
@@ -110,7 +110,7 @@ export function getComments(desc) {
|
|
|
110
110
|
case "rpc":
|
|
111
111
|
path = [
|
|
112
112
|
...getComments(desc.parent).sourcePath,
|
|
113
|
-
|
|
113
|
+
ServiceDescriptorProtoDesc.field.method.number,
|
|
114
114
|
desc.parent.proto.method.indexOf(desc.proto),
|
|
115
115
|
];
|
|
116
116
|
file = desc.parent.file;
|
|
@@ -118,6 +118,29 @@ export function getComments(desc) {
|
|
|
118
118
|
}
|
|
119
119
|
return findComments(file.proto.sourceCodeInfo, path);
|
|
120
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Get feature options set on the element in the protobuf source. This returns
|
|
123
|
+
* compact (e.g. fields) or regular options (e.g. files) as an array of strings.
|
|
124
|
+
*/
|
|
125
|
+
export function getFeatureOptionStrings(desc) {
|
|
126
|
+
var _a, _b;
|
|
127
|
+
const strings = [];
|
|
128
|
+
const features = (_a = desc.proto.options) === null || _a === void 0 ? void 0 : _a.features;
|
|
129
|
+
if (features !== undefined) {
|
|
130
|
+
const r = reflect(FeatureSetDesc, features);
|
|
131
|
+
for (const f of r.fields) {
|
|
132
|
+
if (f.fieldKind != "enum" || !r.isSet(f)) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const val = r.get(f);
|
|
136
|
+
const name = (_b = f.enum.values.find((v) => v.number == val)) === null || _b === void 0 ? void 0 : _b.name;
|
|
137
|
+
if (name !== undefined) {
|
|
138
|
+
strings.push(`features.${f.name} = ${name}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return strings;
|
|
143
|
+
}
|
|
121
144
|
/**
|
|
122
145
|
* Return a string that matches the definition of a field in the protobuf
|
|
123
146
|
* source. Does not take custom options into account.
|
|
@@ -131,7 +154,6 @@ export function getDeclarationString(desc) {
|
|
|
131
154
|
}
|
|
132
155
|
return str;
|
|
133
156
|
}
|
|
134
|
-
const file = desc.kind === "extension" ? desc.file : desc.parent.file;
|
|
135
157
|
const parts = [];
|
|
136
158
|
function typeName(f) {
|
|
137
159
|
if (f.message) {
|
|
@@ -146,12 +168,10 @@ export function getDeclarationString(desc) {
|
|
|
146
168
|
case "scalar":
|
|
147
169
|
case "enum":
|
|
148
170
|
case "message":
|
|
149
|
-
if (
|
|
150
|
-
isFieldSet(FieldDescriptorProtoDesc, desc.proto, "label") &&
|
|
151
|
-
desc.proto.label == FieldDescriptorProto_Label.REQUIRED) {
|
|
171
|
+
if (fieldHasRequiredKeyword(desc)) {
|
|
152
172
|
parts.push("required");
|
|
153
173
|
}
|
|
154
|
-
if (desc
|
|
174
|
+
if (fieldHasOptionalKeyword(desc)) {
|
|
155
175
|
parts.push("optional");
|
|
156
176
|
}
|
|
157
177
|
parts.push(typeName(desc));
|
|
@@ -170,10 +190,10 @@ export function getDeclarationString(desc) {
|
|
|
170
190
|
const options = [];
|
|
171
191
|
const protoOptions = desc.proto.options;
|
|
172
192
|
if (protoOptions !== undefined &&
|
|
173
|
-
isFieldSet(
|
|
193
|
+
isFieldSet(protoOptions, FieldOptionsDesc.field.packed)) {
|
|
174
194
|
options.push(`packed = ${protoOptions.packed.toString()}`);
|
|
175
195
|
}
|
|
176
|
-
if (isFieldSet(
|
|
196
|
+
if (isFieldSet(desc.proto, FieldDescriptorProtoDesc.field.defaultValue)) {
|
|
177
197
|
let defaultValue = desc.proto.defaultValue;
|
|
178
198
|
if (desc.proto.type == FieldDescriptorProto_Type.BYTES ||
|
|
179
199
|
desc.proto.type == FieldDescriptorProto_Type.STRING) {
|
|
@@ -185,18 +205,44 @@ export function getDeclarationString(desc) {
|
|
|
185
205
|
options.push(`json_name = "${desc.jsonName}"`);
|
|
186
206
|
}
|
|
187
207
|
if (protoOptions !== undefined &&
|
|
188
|
-
isFieldSet(
|
|
208
|
+
isFieldSet(protoOptions, FieldOptionsDesc.field.jstype)) {
|
|
189
209
|
options.push(`jstype = ${FieldOptions_JSType[protoOptions.jstype]}`);
|
|
190
210
|
}
|
|
191
211
|
if (protoOptions !== undefined &&
|
|
192
|
-
isFieldSet(
|
|
212
|
+
isFieldSet(protoOptions, FieldOptionsDesc.field.deprecated)) {
|
|
193
213
|
options.push(`deprecated = true`);
|
|
194
214
|
}
|
|
215
|
+
options.push(...getFeatureOptionStrings(desc));
|
|
195
216
|
if (options.length > 0) {
|
|
196
217
|
parts.push("[" + options.join(", ") + "]");
|
|
197
218
|
}
|
|
198
219
|
return parts.join(" ");
|
|
199
220
|
}
|
|
221
|
+
/**
|
|
222
|
+
* Whether this field was declared with `required` in the protobuf source.
|
|
223
|
+
*/
|
|
224
|
+
function fieldHasRequiredKeyword(field) {
|
|
225
|
+
const edition = (field.kind == "extension" ? field.file : field.parent.file)
|
|
226
|
+
.edition;
|
|
227
|
+
return (edition == Edition.EDITION_PROTO2 &&
|
|
228
|
+
field.proto.label == FieldDescriptorProto_Label.REQUIRED);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Whether this field was declared with `optional` in the protobuf source.
|
|
232
|
+
* Note that message fields are always optional. It is impossible to determine
|
|
233
|
+
* whether the keyword was used.
|
|
234
|
+
*/
|
|
235
|
+
function fieldHasOptionalKeyword(field) {
|
|
236
|
+
const edition = (field.kind == "extension" ? field.file : field.parent.file)
|
|
237
|
+
.edition;
|
|
238
|
+
if (edition == Edition.EDITION_PROTO2) {
|
|
239
|
+
return (!field.oneof && field.proto.label == FieldDescriptorProto_Label.OPTIONAL);
|
|
240
|
+
}
|
|
241
|
+
if (edition == Edition.EDITION_PROTO3) {
|
|
242
|
+
return field.proto.proto3Optional;
|
|
243
|
+
}
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
200
246
|
/**
|
|
201
247
|
* Find comments.
|
|
202
248
|
*/
|
|
@@ -216,10 +262,10 @@ function findComments(sourceCodeInfo, sourcePath) {
|
|
|
216
262
|
}
|
|
217
263
|
return {
|
|
218
264
|
leadingDetached: location.leadingDetachedComments,
|
|
219
|
-
leading: isFieldSet(
|
|
265
|
+
leading: isFieldSet(location, SourceCodeInfo_LocationDesc.field.leadingComments)
|
|
220
266
|
? location.leadingComments
|
|
221
267
|
: undefined,
|
|
222
|
-
trailing: isFieldSet(
|
|
268
|
+
trailing: isFieldSet(location, SourceCodeInfo_LocationDesc.field.trailingComments)
|
|
223
269
|
? location.trailingComments
|
|
224
270
|
: undefined,
|
|
225
271
|
sourcePath,
|
|
@@ -230,23 +276,3 @@ function findComments(sourceCodeInfo, sourcePath) {
|
|
|
230
276
|
sourcePath,
|
|
231
277
|
};
|
|
232
278
|
}
|
|
233
|
-
/**
|
|
234
|
-
* The following field numbers are used to find comments in
|
|
235
|
-
* google.protobuf.SourceCodeInfo.
|
|
236
|
-
*/
|
|
237
|
-
var FieldNumber;
|
|
238
|
-
(function (FieldNumber) {
|
|
239
|
-
FieldNumber[FieldNumber["FileDescriptorProto_Package"] = 2] = "FileDescriptorProto_Package";
|
|
240
|
-
FieldNumber[FieldNumber["FileDescriptorProto_MessageType"] = 4] = "FileDescriptorProto_MessageType";
|
|
241
|
-
FieldNumber[FieldNumber["FileDescriptorProto_EnumType"] = 5] = "FileDescriptorProto_EnumType";
|
|
242
|
-
FieldNumber[FieldNumber["FileDescriptorProto_Service"] = 6] = "FileDescriptorProto_Service";
|
|
243
|
-
FieldNumber[FieldNumber["FileDescriptorProto_Extension"] = 7] = "FileDescriptorProto_Extension";
|
|
244
|
-
FieldNumber[FieldNumber["FileDescriptorProto_Syntax"] = 12] = "FileDescriptorProto_Syntax";
|
|
245
|
-
FieldNumber[FieldNumber["DescriptorProto_Field"] = 2] = "DescriptorProto_Field";
|
|
246
|
-
FieldNumber[FieldNumber["DescriptorProto_NestedType"] = 3] = "DescriptorProto_NestedType";
|
|
247
|
-
FieldNumber[FieldNumber["DescriptorProto_EnumType"] = 4] = "DescriptorProto_EnumType";
|
|
248
|
-
FieldNumber[FieldNumber["DescriptorProto_Extension"] = 6] = "DescriptorProto_Extension";
|
|
249
|
-
FieldNumber[FieldNumber["DescriptorProto_OneofDecl"] = 8] = "DescriptorProto_OneofDecl";
|
|
250
|
-
FieldNumber[FieldNumber["EnumDescriptorProto_Value"] = 2] = "EnumDescriptorProto_Value";
|
|
251
|
-
FieldNumber[FieldNumber["ServiceDescriptorProto_Method"] = 2] = "ServiceDescriptorProto_Method";
|
|
252
|
-
})(FieldNumber || (FieldNumber = {}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bufbuild/protoplugin",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.2",
|
|
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": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@bufbuild/protobuf": "2.0.0-alpha.
|
|
39
|
+
"@bufbuild/protobuf": "2.0.0-alpha.2",
|
|
40
40
|
"@typescript/vfs": "^1.4.0",
|
|
41
41
|
"typescript": "4.5.2"
|
|
42
42
|
},
|