Skip to content

Commit

Permalink
Make FieldMask JSON read/write (snake_case <-> camelCase) conforming (#…
Browse files Browse the repository at this point in the history
…552)

Fixes #396
  • Loading branch information
jcready authored Jul 31, 2023
1 parent 7cfd1a5 commit 52c9df5
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,9 @@ export class WellKnownTypes implements CustomMethodGenerator {
* Encode \`${descriptor.name}\` to JSON object.
*/
function internalJsonWrite(message: ${FieldMask}, options: ${JsonWriteOptions}): ${JsonValue} {
const invalidFieldMaskJsonRegex = /[A-Z]|(_([.0-9_]|$))/g;
return message.paths.map(p => {
if (p.match(/_[0-9]?_/g) || p.match(/[A-Z]/g))
if (invalidFieldMaskJsonRegex.test(p))
throw new Error("Unable to encode FieldMask to JSON. lowerCamelCase of path name \\""+p+"\\" is irreversible.");
return ${lowerCamelCase}(p);
}).join(",");
Expand All @@ -379,7 +380,7 @@ export class WellKnownTypes implements CustomMethodGenerator {
if (str.includes('_'))
throw new Error("Unable to parse FieldMask from JSON. Path names must be lowerCamelCase.");
let sc = str.replace(/[A-Z]/g, letter => "_" + letter.toLowerCase());
return (sc[0] === "_") ? sc.substring(1) : sc;
return sc;
};
target.paths = json.split(",").map(camelToSnake);
return target;
Expand Down
32 changes: 31 additions & 1 deletion packages/test-generated/spec/google.protobuf.field_mask.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,27 @@ import {FieldMask} from "../ts-out/google/protobuf/field_mask";

describe('google.protobuf.FieldMask', function () {


describe('toJson()', function () {
// Based on https://github.com/protocolbuffers/protobuf/blob/e8ae137c96444ea313485ed1118c5e43b2099cf1/src/google/protobuf/util/field_mask_util_test.cc#L69-L82
it('converts snake_case to camelCase', function () {
let mask: FieldMask = { paths: [] };
function snakeToCamel(s: string) {
mask.paths[0] = s;
return FieldMask.toJson(mask);
}
expect(snakeToCamel('foo_bar')).toBe('fooBar');
expect(snakeToCamel('_foo_bar')).toBe('FooBar');
expect(snakeToCamel('foo3_bar')).toBe('foo3Bar');
// No uppercase letter is allowed.
expect(() => snakeToCamel('Foo')).toThrowError();
// Any character after a "_" must be a lowercase letter.
// 1. "_" cannot be followed by another "_".
// 2. "_" cannot be followed by a digit.
// 3. "_" cannot appear as the last character.
expect(() => snakeToCamel('foo__bar')).toThrowError();
expect(() => snakeToCamel('foo_3bar')).toThrowError();
expect(() => snakeToCamel('foo_bar_')).toThrowError();
});
it('returns expected JSON', function () {
let mask: FieldMask = {
paths: [
Expand All @@ -29,6 +48,17 @@ describe('google.protobuf.FieldMask', function () {
});

describe('fromJson()', function () {
// Based on https://github.com/protocolbuffers/protobuf/blob/e8ae137c96444ea313485ed1118c5e43b2099cf1/src/google/protobuf/util/field_mask_util_test.cc#L84-L90
it('converts camelCase to snake_case', function () {
function camelToSnake(s: string) {
return FieldMask.fromJson(s).paths[0];
}
expect(camelToSnake('fooBar')).toBe('foo_bar');
expect(camelToSnake('FooBar')).toBe('_foo_bar');
expect(camelToSnake('foo3Bar')).toBe('foo3_bar');
// "_"s are not allowed.
expect(() => camelToSnake('foo_bar')).toThrowError();
});
it('parses JSON as expected', function () {
let expected: FieldMask = {
paths: [
Expand Down

0 comments on commit 52c9df5

Please sign in to comment.