protoc-plugin-js v0.5.2
protoc-plugin-js
protocplugin generating minimal JS codecs with typings and a focus on small bundle size
Example
protoc \
--plugin=protoc-gen-js="$(npm bin)/protoc-plugin-js" \
--js_out="./build" \
-I "vega/protos/sources" \
vega/commands/v1/transaction.protoMain Ideas
Each package, namespace, message and enum is split into separate files to help tree-shaking and minimise the final bundle size, if the user imports only the messages needed. Generated files are CommonJS, as that's the only format thats both compabitle with CommonJS and ESM consumers.
All field names are transformed into their "JSON" form by protoc,
eg. my_field in protobuf will be myField in JS.
Currently merging of field is not supported.
Encoding
Falsy values are not encoded as they coincide with default values in protobuf,
with the exception of repeated elements, which are checked against the length
of a possible array.
Unrecognised properties are not encoded as no mapping exists from an unknown
key to a fieldNumber.
oneofs are namespaced under the name of the oneof, eg.
message Example {
oneof pick {
uint32 before = 1;
uint32 after = 2;
}
}can be set as { pick: { before: 2000 } } or { pick: { after: 2000 } }.
{ pick: {} } will encode to nothing, as none of the fields in the oneof are given.
As a fallback for how most golang proto-to-JSON marshallers work, you can also give after: 2000
for the encoding direction, however the encoder will always prefer the more specific .pick.after.
Types
tagis encoded as a pair offieldNumberandwireType.fieldNumbercan be at most 29 bitsbytesandstringare defined in the spec to be at most 2GB, however that is not validated currentlyuint64,int64,uint32andint32can be both encoded asvarintandfixed{32,64}. This library encodes them asvarintcurrently- While not entirely clear in the spec,
varintwill encode up to 64 bits, even if the format could encode arbitrary size numbers optionalvalues and unusedoneofs are decoded asnullto distinguish them fromundefinedfields, as "explicit presence"
Decoding
Decoding is done in three steps:
- A
readerwill iterate over the full protobuf message, emitting akey/valuepair for eachtagencountered values are decoded based on theirwireTypeinto one ofvarint,bytes,fixed64orfixed32- The compiled decoder will switch based on the
fieldNumberand apply a "view" based on thetypegiven in the protobuf message file, eg.stringwill decode abytesinto a JS string,sint64will decode avarintand apply zig-zag decoding into a JSBigInt
Unknown fields and duplicate fields will still go through step 1 and 2, but may be discarded or overwrite a previous field in step 3.
Nested messages default to {} (empty object) since