Skip to content

feat: Add spec-compliant protojson extension#2297

Merged
dcodeIO merged 8 commits into
masterfrom
patch/ext-protojson
Jun 4, 2026
Merged

feat: Add spec-compliant protojson extension#2297
dcodeIO merged 8 commits into
masterfrom
patch/ext-protojson

Conversation

@dcodeIO

@dcodeIO dcodeIO commented Jun 2, 2026

Copy link
Copy Markdown
Member

Adds a spec-compliant ProtoJSON extension derived from proto3-json-serializer. Cc @alexander-fenster as the original author.

ProtoJSON is exposed via ext/protojson with explicit fromJson, fromJsonString, toJson, and toJsonString APIs, plus an optional install() helper for reflected Type convenience methods.

Example usage:

import protobuf from "protobufjs";
import protojson from "protobufjs/ext/protojson.js";

const root = ...;
const MyType = root.lookupType("MyType");
const message = protojson.fromJson(MyType, { value: 1 });
const json = protojson.toJson(MyType, message);

Also updates conformance reporting and README documentation to show binary, ProtoJSON, and Text Format coverage.

A future major release may move some of this functionality into the main library, but keeping it as an extension is the cleanest way to support ProtoJSON for now.

Fixes #677
Fixes #839
Fixes #916
Fixes #1108
Fixes #1304
Fixes #1312
Fixes #1922

Supersedes #1265

Also covers the reflection/runtime ProtoJSON parts of #2201. Static-module integration may become relevant again if we decide to move ProtoJSON support closer to the main library.

@dcodeIO dcodeIO requested a review from alexander-fenster June 2, 2026 18:27
@dcodeIO dcodeIO force-pushed the patch/ext-protojson branch from 0a4e11f to 8e945cd Compare June 2, 2026 21:56
@alexander-fenster

Copy link
Copy Markdown
Contributor

That's great!

One thing I noticed in my tests that if an protobuf object is created with .create(), the JSON serializer will include default values. E.g. for the proto message

message Test {
  int32 int_value = 1;
}

the code

const Test = root.lookup('Test');
console.log(protojson.toJson(Test, Test.create({intValue: 0})));

will emit { intValue: 0 } as opposed to an empty object as expected.

Otherwise, passes my tests :)

Comment thread ext/protojson.js
WKT_FROM[".google.protobuf.Timestamp"] = function (type, value) {
if (typeof value !== "string")
throw invalid(type.fullName, value, "expected timestamp string");
var match = /^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T([01]\d|2[0-3]):([0-5]\d):([0-5]\d)(?:\.(\d{1,9}))?(Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.exec(value);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what the :[0-5]\d means at the end of the regex; I think it blocks valid timestamps like '2026-06-03T09:19:00.000-0700' from being parsed properly (returning "invalid timestamp").

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here :[0-5]\d is the minutes portion of a timezone offset, like in -07:59, whereas -0700 is not valid RFC 3339 iiuc, and hence not ProtoJSON that protoc accepts. Is asserted by the conformance harness in TimestampWithMissingColonInOffset.

@dcodeIO dcodeIO merged commit ffd3d51 into master Jun 4, 2026
5 checks passed
@github-actions github-actions Bot mentioned this pull request Jun 4, 2026
@dcodeIO dcodeIO deleted the patch/ext-protojson branch June 5, 2026 00:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants