From bb6b1d4942d924bcb4ee3ad15f4823f2d9c1ab22 Mon Sep 17 00:00:00 2001 From: Aleksandr Batsuev Date: Wed, 17 Aug 2022 12:27:22 -0500 Subject: [PATCH] feat: valuesOptions for enums (#1358) * enum valuesOptions support * update tests a little, fix api docs * tests: reverting bad conflict resolution * test: put test.end() in its proper place Co-authored-by: Alexander Fenster Co-authored-by: Alexander Fenster --- src/enum.js | 31 ++++++++++++++++++++++++------- src/parse.js | 11 +++++++++-- tests/api_enum.js | 7 +++++++ tests/comp_options-textformat.js | 8 ++++++++ 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/enum.js b/src/enum.js index b11014be3..1c016209f 100644 --- a/src/enum.js +++ b/src/enum.js @@ -18,8 +18,9 @@ var Namespace = require("./namespace"), * @param {Object.} [options] Declared options * @param {string} [comment] The comment for this enum * @param {Object.} [comments] The value comments for this enum + * @param {Object.>|undefined} [valuesOptions] The value options for this enum */ -function Enum(name, values, options, comment, comments) { +function Enum(name, values, options, comment, comments, valuesOptions) { ReflectionObject.call(this, name, options); if (values && typeof values !== "object") @@ -49,6 +50,12 @@ function Enum(name, values, options, comment, comments) { */ this.comments = comments || {}; + /** + * Values options, if any + * @type {Object>|undefined} + */ + this.valuesOptions = valuesOptions; + /** * Reserved ranges, if any. * @type {Array.} @@ -93,11 +100,12 @@ Enum.fromJSON = function fromJSON(name, json) { Enum.prototype.toJSON = function toJSON(toJSONOptions) { var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false; return util.toObject([ - "options" , this.options, - "values" , this.values, - "reserved" , this.reserved && this.reserved.length ? this.reserved : undefined, - "comment" , keepComments ? this.comment : undefined, - "comments" , keepComments ? this.comments : undefined + "options" , this.options, + "valuesOptions" , this.valuesOptions, + "values" , this.values, + "reserved" , this.reserved && this.reserved.length ? this.reserved : undefined, + "comment" , keepComments ? this.comment : undefined, + "comments" , keepComments ? this.comments : undefined ]); }; @@ -106,11 +114,12 @@ Enum.prototype.toJSON = function toJSON(toJSONOptions) { * @param {string} name Value name * @param {number} id Value id * @param {string} [comment] Comment, if any + * @param {Object.|undefined} [options] Options, if any * @returns {Enum} `this` * @throws {TypeError} If arguments are invalid * @throws {Error} If there is already a value with this name or id */ -Enum.prototype.add = function add(name, id, comment) { +Enum.prototype.add = function add(name, id, comment, options) { // utilized by the parser but not by .fromJSON if (!util.isString(name)) @@ -135,6 +144,12 @@ Enum.prototype.add = function add(name, id, comment) { } else this.valuesById[this.values[name] = id] = name; + if (options) { + if (this.valuesOptions === undefined) + this.valuesOptions = {}; + this.valuesOptions[name] = options || null; + } + this.comments[name] = comment || null; return this; }; @@ -158,6 +173,8 @@ Enum.prototype.remove = function remove(name) { delete this.valuesById[val]; delete this.values[name]; delete this.comments[name]; + if (this.valuesOptions) + delete this.valuesOptions[name]; return this; }; diff --git a/src/parse.js b/src/parse.js index dd589f580..bfdabf0a5 100644 --- a/src/parse.js +++ b/src/parse.js @@ -543,7 +543,14 @@ function parse(source, root, options) { skip("="); var value = parseId(next(), true), - dummy = {}; + dummy = { + options: undefined + }; + dummy.setOption = function(name, value) { + if (this.options === undefined) + this.options = {}; + this.options[name] = value; + }; ifBlock(dummy, function parseEnumValue_block(token) { /* istanbul ignore else */ @@ -556,7 +563,7 @@ function parse(source, root, options) { }, function parseEnumValue_line() { parseInlineOptions(dummy); // skip }); - parent.add(token, value, dummy.comment); + parent.add(token, value, dummy.comment, dummy.options); } function parseOption(parent, token) { diff --git a/tests/api_enum.js b/tests/api_enum.js index 705491331..051bc51c4 100644 --- a/tests/api_enum.js +++ b/tests/api_enum.js @@ -80,5 +80,12 @@ tape.test("reflected enums", function(test) { b: 0 }); + enm.add('e', 4, undefined, {'(test_option)': 'test_value'}); + test.same( enm.valuesOptions, { + 'e': { + '(test_option)': 'test_value' + } + }); + test.end(); }); diff --git a/tests/comp_options-textformat.js b/tests/comp_options-textformat.js index 325aaa958..83e6ac08c 100644 --- a/tests/comp_options-textformat.js +++ b/tests/comp_options-textformat.js @@ -11,19 +11,27 @@ message MyOptions {\ extend google.protobuf.FieldOptions {\ MyOptions my_options = 50000;\ }\ +extend google.protobuf.EnumValueOptions {\ + MyOptions my_value_option = 50001;\ +}\ message Test {\ string value = 1 [(my_options) = { a: \"foo\" b: \"bar\" }];\ string value2 = 2 [(my_options) = { a: \"foo\" b { c: \"bar\" } }];\ string value3 = 3 [(my_options) = { a: \"foo\", b: \"bar\" }];\ string value4 = 4 [(my_options) = { a: \"foo\"; b: \"bar\" }];\ +}\ +enum TestEnum {\ + TEST_ITEM = 0 [(my_value_option) = { a: \"foo\", b: \"bar\" }];\ }"; tape.test("options in textformat", function(test) { var root = protobuf.parse(proto).root; var Test = root.lookup("Test"); + var TestEnum = root.lookup("TestEnum"); test.same(Test.fields.value.options, { "(my_options).a": "foo", "(my_options).b": "bar" }, "should parse correctly"); test.same(Test.fields.value2.options, { "(my_options).a": "foo", "(my_options).b.c": "bar" }, "should parse correctly when nested"); test.same(Test.fields.value3.options, { "(my_options).a": "foo", "(my_options).b": "bar" }, "should parse correctly when comma-separated"); test.same(Test.fields.value4.options, { "(my_options).a": "foo", "(my_options).b": "bar" }, "should parse correctly when semicolon-separated"); + test.same(TestEnum.valuesOptions["TEST_ITEM"], { "(my_value_option).a": "foo", "(my_value_option).b": "bar" }, "should parse correctly in enum"); test.end(); });