mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-04-27 07:48:01 -07:00
99 lines
4 KiB
JavaScript
99 lines
4 KiB
JavaScript
// @ts-check
|
|
/**
|
|
* Custom protoc-gen-es sibling plugin. Emits `src/generated/index.ts`, a
|
|
* single rollup that re-exports every generated `_pb` module and adds
|
|
* `MessageInitShape<T>` param aliases for every `Command_*` message.
|
|
*
|
|
* Wired into `buf.gen.yaml` as a second local plugin. Runs with the same
|
|
* descriptor set protoc-gen-es consumes, so output always tracks the protos.
|
|
*/
|
|
import { createEcmaScriptPlugin, runNodeJs } from '@bufbuild/protoplugin';
|
|
|
|
const HEADER = [
|
|
'// @generated by protoc-gen-data. DO NOT EDIT.',
|
|
'// Rollup of all proto modules + MessageInitShape param aliases for every Command_*.',
|
|
'/* eslint-disable */',
|
|
'',
|
|
'',
|
|
].join('\n');
|
|
|
|
const inner = createEcmaScriptPlugin({
|
|
name: 'protoc-gen-data',
|
|
version: 'v0.1.0',
|
|
generateTs(schema) {
|
|
const f = schema.generateFile('index.ts');
|
|
|
|
const MessageInitShape = f.import('MessageInitShape', '@bufbuild/protobuf', true);
|
|
const MessageType = f.import('Message', '@bufbuild/protobuf', true);
|
|
const GenExtensionType = f.import('GenExtension', '@bufbuild/protobuf/codegenv2', true);
|
|
|
|
const sortedFiles = [...schema.files].sort((a, b) => a.name.localeCompare(b.name));
|
|
|
|
for (const file of sortedFiles) {
|
|
f.print('export * from ', f.string(`./proto/${file.name}_pb`), ';');
|
|
}
|
|
f.print();
|
|
|
|
const commandMessages = [];
|
|
for (const file of sortedFiles) {
|
|
for (const msg of file.messages) {
|
|
if (msg.name.startsWith('Command_')) {
|
|
commandMessages.push(msg);
|
|
}
|
|
}
|
|
}
|
|
commandMessages.sort((a, b) => a.name.localeCompare(b.name));
|
|
|
|
// importSchema() resolves paths relative to this plugin's `out` dir, which
|
|
// yields `./<name>_pb` — but the _pb files live under ./proto/ (protoc-gen-es's
|
|
// out). Build the import path explicitly so it points inside the proto subdir.
|
|
for (const msg of commandMessages) {
|
|
const alias = msg.name.slice('Command_'.length) + 'Params';
|
|
const schemaName = `${msg.name}Schema`;
|
|
const schemaSym = f.import(schemaName, `./proto/${msg.file.name}_pb`, true);
|
|
f.print('export type ', alias, ' = ', MessageInitShape, '<typeof ', schemaSym, '>;');
|
|
}
|
|
f.print();
|
|
|
|
// Generic extension registry infrastructure. Consolidates the three
|
|
// near-duplicate registry types and helpers that used to live in
|
|
// src/websocket/services/protobuf-types.ts into one generic pair.
|
|
// Specialised aliases (Session/Room/Game) still live in protobuf-types.ts
|
|
// because GameExtensionRegistry needs GameEventMeta — a hand-written
|
|
// domain type whose import would create a generated/ ↔ types/ cycle.
|
|
f.print('export type RegistryEntry<V, T extends ', MessageType, ', M = unknown> = [');
|
|
f.print(' ', GenExtensionType, '<T, V>,');
|
|
f.print(' (value: V, meta: M) => void,');
|
|
f.print('];');
|
|
f.print();
|
|
// Return type widens V to `unknown` so the heterogeneous entries that
|
|
// callers build can be stored in a homogeneous `RegistryEntry<unknown, T, M>[]`
|
|
// array. This is the actual value-add over a bare tuple literal.
|
|
f.print('export function makeEntry<T extends ', MessageType, ', V, M = unknown>(');
|
|
f.print(' ext: ', GenExtensionType, '<T, V>,');
|
|
f.print(' handler: (value: V, meta: M) => void,');
|
|
f.print('): RegistryEntry<unknown, T, M> {');
|
|
f.print(' return [ext, handler] as unknown as RegistryEntry<unknown, T, M>;');
|
|
f.print('}');
|
|
},
|
|
});
|
|
|
|
// Skip f.preamble() above and inject a custom rollup-aware header here instead —
|
|
// preamble() would write "@generated from file X.proto" which is misleading for
|
|
// a rollup file built from every input proto.
|
|
/** @type {import('@bufbuild/protoplugin').Plugin} */
|
|
const plugin = {
|
|
name: inner.name,
|
|
version: inner.version,
|
|
run(request) {
|
|
const response = inner.run(request);
|
|
for (const file of response.file) {
|
|
if (file.name === 'index.ts' && typeof file.content === 'string') {
|
|
file.content = HEADER + file.content;
|
|
}
|
|
}
|
|
return response;
|
|
},
|
|
};
|
|
|
|
runNodeJs(plugin);
|