Created
October 27, 2022 13:41
-
-
Save timostamm/9bafd4133e886978cf6647b4fa0b26c1 to your computer and use it in GitHub Desktop.
Using exports and imports in @bufbuild/protoplugin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {localName, GeneratedFile, ImportSymbol, Schema} from "@bufbuild/protoplugin/ecmascript"; | |
import type {DescMessage} from "@bufbuild/protobuf"; | |
export function generateTs(schema: Schema) { | |
const map = new Map<DescMessage, ImportSymbol>(); | |
function getFunctionName(f: GeneratedFile, message: DescMessage): ImportSymbol { | |
let s = map.get(message); | |
if (!s) { | |
s = f.export(`validate${localName(message)}`); | |
map.set(message, s); | |
} | |
return s; | |
} | |
function generateMessage(f: GeneratedFile, message: DescMessage) { | |
f.print("export function ", getFunctionName(f, message), "() {"); | |
for (const field of message.fields) { | |
if (field.fieldKind === "message") { | |
f.print(" ", getFunctionName(f, field.message), "();"); | |
} | |
} | |
f.print("}"); | |
for (const nestedMessage of message.nestedMessages) { | |
generateMessage(f, nestedMessage); | |
} | |
} | |
for (const file of schema.files) { | |
const f = schema.generateFile(file.name + "_validate.ts"); | |
for (const message of file.messages) { | |
generateMessage(f, message); | |
} | |
} | |
} |
Ah, I see how the original thing above breaks!
(using buf generate https://github.com/bufbuild/protoc-gen-validate.git#ref=65fff7348be4c0b042657182ae2610290aadc21d
)
The flaw is that it was using schema.files
(only the proto files that the plugin was asked to generate) instead of schema.allFiles
(all compiled proto files).
Even though the buf generate
command above does generates all files, it does so by splitting the input files by directory and making separate plugin invocations in parallel.
This fixes it:
function generateTs(schema: Schema) {
const map = new Map<DescMessage, ImportSymbol>();
function getFunctionName(f: GeneratedFile, message: DescMessage): ImportSymbol {
let s = map.get(message);
if (!s) {
s = f.export(`validate${localName(message)}`);
map.set(message, s);
}
return s;
}
function generateMessage(f: GeneratedFile, message: DescMessage) {
const name = getFunctionName(f, message);
// note we only actually generate for files we were asked to
if (schema.files.includes(message.file)) {
f.print("export function ", name, "() {");
for (const field of message.fields) {
if (field.fieldKind === "message") {
f.print(" ", getFunctionName(f, field.message), "();");
}
}
f.print("}");
}
for (const nestedMessage of message.nestedMessages) {
generateMessage(f, nestedMessage);
}
}
for (const file of schema.allFiles) { // note we are walking through *all* files now
const f = schema.generateFile(file.name + "_validate.ts");
for (const message of file.messages) {
generateMessage(f, message);
}
}
}
But quite frankly, this is pretty awkward 🙈
Your f.import(name, ...
above seems much more straight forward!
function generateTs(schema: Schema) {
function getFunctionName(f: GeneratedFile, message: DescMessage): ImportSymbol {
const name = `validate${localName(message)}`;
return f.import(name, `./${message.file.name}_validate.js`);
}
function generateMessage(f: GeneratedFile, message: DescMessage) {
f.print("export function ", getFunctionName(f, message), "() {");
for (const field of message.fields) {
if (field.fieldKind === "message") {
f.print(" ", getFunctionName(f, field.message), "();");
}
}
f.print("}");
for (const nestedMessage of message.nestedMessages) {
generateMessage(f, nestedMessage);
}
}
for (const file of schema.files) {
const f = schema.generateFile(file.name + "_validate.ts");
for (const message of file.messages) {
generateMessage(f, message);
}
}
}
Thanks for shaking this out ❤️
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
... Or even simpler, this works interestingly (just not when using it with f.export and the registry approach: