@protobuf-x/parser
v0.1.0
Published
Zero-dependency .proto file parser with full proto2/proto3/editions 2023 support. Produces a typed AST.
Downloads
118
Maintainers
Readme
@protobuf-x/parser
Zero-dependency
.protofile parser for TypeScript & JavaScript.
A complete, hand-written parser for Protocol Buffers schema files (.proto),
producing a typed AST. Used by @protobuf-x/codegen at codegen time.
- ✅ Zero dependencies — pure TypeScript, no native bindings
- 🔍 Full proto2 / proto3 / editions 2023 support
- 🌳 Typed AST — every node has a precise TypeScript type
- 🧩 Type resolution — resolves cross-file message and enum references
- 📦 Tiny — single-purpose, tree-shakeable
Installation
npm install @protobuf-x/parserYou typically don't import this directly — install @protobuf-x/codegen instead, which uses this parser internally.
Use this package directly only when you need to:
- Build custom tooling on top of
.protofiles (linters, formatters, IDE plugins) - Generate something other than TS/JS (Go, Rust, etc.)
- Inspect proto schemas programmatically
Quick start
import { Tokenizer, ProtoParser } from '@protobuf-x/parser'
const source = `
syntax = "proto3";
package myapp;
message User {
string name = 1;
int32 age = 2;
Role role = 3;
enum Role {
GUEST = 0;
ADMIN = 1;
}
}
`
const tokens = new Tokenizer(source).tokenize()
const parser = new ProtoParser(tokens)
const ast = parser.parse()
console.log(ast.package) // 'myapp'
console.log(ast.messages[0].name) // 'User'
console.log(ast.messages[0].fields) // [...field nodes]Cross-file resolution
import { ProtoLoader, TypeResolver } from '@protobuf-x/parser'
const loader = new ProtoLoader({
importPaths: ['./schemas', './vendor'],
})
// Loads and parses all transitive imports
const graph = await loader.loadFile('schemas/main.proto')
// Resolves type references across files (e.g. `imports.OtherMessage`)
const resolver = new TypeResolver(graph)
resolver.resolve()What's in the AST?
Top-level nodes:
ProtoFileNode— the parsed file (syntax, package, imports, messages, enums, services, options)MessageNode— message definition (fields, oneofs, nested messages, nested enums, reserved ranges, options)FieldNode/MapFieldNode— field definition (number, name, type, label, options, default value)EnumNode— enum definition (values, reserved, options)ServiceNode/MethodNode— service + RPC methods (with streaming flags)OneofNode— oneof groupExtendNode/ExtensionsNode— proto2 extensionsOptionNode— file/message/field/enum/service/method optionsReservedNode— reserved field numbers and namesImportNode— import statements (withpublic/weakflags)
All nodes carry source position info (line, col) for error reporting.
Features
- All proto2 + proto3 syntax: messages, oneofs, maps, packed/unpacked repeated, groups, extensions, services
- Editions 2023: parses
edition = "2023";and feature options - Imports:
import "...",import public "...",import weak "..." - Custom options:
(my.custom.option) = value(preserved asOptionAggregate) - Reserved:
reserved 1, 2, 5 to 10;andreserved "foo", "bar"; - Comments: line
//and block/* */(preserved onBaseNode.leadingComment) - String escapes:
\n,\t,\xHH,\uHHHH,\NNN(octal) - Numeric literals: int, float, hex (
0x...), octal (0...),inf,nan - Error recovery: tries to continue parsing after a syntax error to report multiple issues at once
Errors
import { LexerError, ParseError } from '@protobuf-x/parser'
try {
// ...
} catch (err) {
if (err instanceof ParseError) {
console.error(`Parse error at ${err.line}:${err.col}: ${err.message}`)
}
}Compatibility
- Node.js: 18+
- Universal: works in browsers, Deno, Bun, edge runtimes (no Node-specific APIs)
License
MIT
