@tabnas/proto
v0.4.6
Published
Parse Protocol Buffers .proto IDL (proto2, proto3, edition 2023/2024) into FileDescriptorProto-shaped JSON, using the Tabnas parser and an ABNF grammar.
Maintainers
Readme
@tabnas/proto
Parse Protocol Buffers .proto IDL — proto2, proto3, and editions 2023
/ 2024 — into FileDescriptorProto-shaped JSON, using the
Tabnas parser driven by an
ABNF grammar.
const { parse } = require('@tabnas/proto')
const fdp = parse(`
syntax = "proto3";
package example;
message Person {
string name = 1;
repeated string emails = 2;
}
`)
fdp.syntax // => 'proto3'
fdp.package // => 'example'
fdp.messageType[0].name // => 'Person'
fdp.messageType[0].field[1].label // => 'LABEL_REPEATED'
fdp.messageType[0].field[0].type // => 'TYPE_STRING'Versions
The version is auto-detected from the file's syntax / edition
declaration, and/or set explicitly with the version option:
const { parse } = require('@tabnas/proto')
parse('edition = "2023";').edition // => 'EDITION_2023'
parse('message M {}', { version: 'proto3' }).syntax // => 'proto3'When both an explicit version and a declaration are present they must
agree (reconcile: true, the default) or parse throws; set
reconcile: false to let the declaration win.
API
parse(src, options?) => FileDescriptorProto— parse a.protostring.Proto— the Tabnas plugin;new Tabnas().use(Proto)installs the grammar sotn.parse(src)returns the raw{rule, src, kids}CST.toDescriptor(cst, options?)— turn a parsed CST into a FileDescriptorProto.
Options: { version?: 'proto2'|'proto3'|'2023'|'2024' | null,
reconcile?: boolean }.
What it produces
A FileDescriptorProto-shaped object (the descriptor.proto JSON shape):
package, dependency (+ publicDependency / weakDependency /
optionDependency), messageType (recursive DescriptorProto with
field, nestedType, enumType, oneofDecl, extensionRange,
reservedRange), enumType, service, extension, options, and
syntax / edition. map<K,V> fields are expanded to a repeated message
field plus a synthesised …Entry nested message with
options.mapEntry = true, groups to a TYPE_GROUP field plus a nested
message, and a proto3 explicit optional to a synthetic _<field> oneof —
exactly as protoc does. Type names are stored as written and type is
left unset for them; cross-file resolution is a separate concern.
Two things are deliberately shaped for readability rather than byte-for-byte
protoc parity: options are a plain { name: value } map (not an
uninterpretedOption list), and defaultValue keeps the literal as
written. See doc/reference.md.
Conformance
Checked against protoc 35.1's own parser test corpus (extracted from
parser_unittest.cc): every one of the 71 in-scope valid cases and all
50 accept-only cases, run by test/protobuf-conformance.test.ts. The 11
excluded cases declare protoc-internal editions (UNSTABLE,
99998_TEST_ONLY) outside the proto2 / proto3 / 2023 / 2024 support this
package claims.
See doc/tutorial.md, doc/guide.md, doc/reference.md, and doc/concepts.md.
