Skip to content

Commit 94bfbbc

Browse files
Allow undefined values (but not nulls) for implicit presence fields in properties / interfaces
1 parent 8e0027a commit 94bfbbc

File tree

1 file changed

+25
-8
lines changed

1 file changed

+25
-8
lines changed

cli/targets/static.js

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ function syntaxForType(type) {
377377
return syntax !== null ? syntax : "proto2";
378378
}
379379

380-
function isOptional(field, syntax) {
380+
function isExplicitPresence(field, syntax) {
381381

382382
// In proto3, optional fields are explicit
383383
if (syntax === "proto3")
@@ -390,6 +390,19 @@ function isOptional(field, syntax) {
390390
throw new Error("Unknown proto syntax: [" + syntax + "]");
391391
}
392392

393+
function isImplicitPresence(field, syntax) {
394+
395+
// In proto3, everything not marked optional has implicit presence (including maps and repeated fields)
396+
if (syntax === "proto3")
397+
return field.options == null || field.options["proto3_optional"] !== true;
398+
399+
// In proto2, nothing has implicit presence
400+
if (syntax === "proto2")
401+
return false;
402+
403+
throw new Error("Unknown proto syntax: [" + syntax + "]");
404+
}
405+
393406
function isOptionalOneOf(oneof, syntax) {
394407

395408
if (syntax === "proto2")
@@ -419,13 +432,17 @@ function buildType(ref, type) {
419432
var jsType = toJsType(field, /* parentIsInterface = */ true);
420433
var nullable = false;
421434
if (config["null-semantics"]) {
422-
// With semantic nulls, decide which fields are required for the current protobuf version
423-
// Fields with implicit defaults in proto3 are required for the purpose of constructing objects
424-
// Optional fields can be undefined, i.e. they can be omitted for the source object altogether
425-
if (isOptional(field, syntax) || field.partOf || field.repeated || field.map) {
435+
// With semantic nulls, only explicit optional fields and one-of members can be set to null
436+
// Implicit fields (proto3), maps and lists can be omitted, but if specified must be non-null
437+
// Implicit fields will take their default value when the message is constructed
438+
if (isExplicitPresence(field, syntax) || field.partOf) {
426439
jsType = jsType + "|null|undefined";
427440
nullable = true;
428441
}
442+
else if (isImplicitPresence(field, syntax) || field.repeated || field.map) {
443+
jsType = jsType + "|undefined";
444+
nullable = true;
445+
}
429446
}
430447
else {
431448
// Without semantic nulls, everything is optional in proto3
@@ -465,7 +482,7 @@ function buildType(ref, type) {
465482
// With semantic nulls, fields are nullable if they are explicitly optional or part of a one-of
466483
// Maps, repeated values and fields with implicit defaults are never null after construction
467484
// Members are never undefined, at a minimum they are initialized to null
468-
if (isOptional(field, syntax) || field.partOf)
485+
if (isExplicitPresence(field, syntax) || field.partOf)
469486
jsType = jsType + "|null";
470487
}
471488
else {
@@ -484,10 +501,10 @@ function buildType(ref, type) {
484501
push("");
485502
firstField = false;
486503
}
487-
// Semantic nulls respect the optional semantics for the current protobuf version
504+
// With semantic nulls, only explict optional fields and one-of members are null by default
488505
// Otherwise use field.optional, which doesn't consider proto3, maps, repeated fields etc.
489506
var nullDefault = config["null-semantics"]
490-
? isOptional(field, syntax)
507+
? isExplicitPresence(field, syntax)
491508
: field.optional && config["null-defaults"];
492509
if (field.repeated)
493510
push(escapeName(type.name) + ".prototype" + prop + " = $util.emptyArray;"); // overwritten in constructor

0 commit comments

Comments
 (0)