@@ -409,22 +409,23 @@ function buildType(ref, type) {
409
409
prop = prop . substring ( 1 , prop . charAt ( 0 ) === "[" ? prop . length - 1 : prop . length ) ;
410
410
var jsType = toJsType ( field ) ;
411
411
var nullable = false ;
412
-
413
- // New behaviour - respect explicit optional semantics in both proto2 and proto3
414
- if ( config [ "force-optional" ] ) {
412
+ if ( config [ "null-semantics" ] ) {
413
+ // With semantic nulls, decide which fields are required for the current protobuf version
414
+ // Fields with implicit defaults in proto3 are required for the purpose of constructing objects
415
+ // Optional fields can be undefined, i.e. they can be omitted for the source object altogether
415
416
if ( isOptional ( field , syntax ) || field . partOf || field . repeated || field . map ) {
416
- jsType = jsType + "|null" ;
417
+ jsType = jsType + "|null|undefined " ;
417
418
nullable = true ;
418
419
}
419
420
}
420
- // Old behaviour - field.optional is true for all fields in proto3
421
421
else {
422
+ // Without semantic nulls, everything is optional in proto3
423
+ // Do not allow |undefined to keep backwards compatibility
422
424
if ( field . optional ) {
423
425
jsType = jsType + "|null" ;
424
426
nullable = true ;
425
427
}
426
428
}
427
-
428
429
typeDef . push ( "@property {" + jsType + "} " + ( nullable ? "[" + prop + "]" : prop ) + " " + ( field . comment || type . name + " " + field . name ) ) ;
429
430
} ) ;
430
431
push ( "" ) ;
@@ -451,19 +452,19 @@ function buildType(ref, type) {
451
452
if ( config . comments ) {
452
453
push ( "" ) ;
453
454
var jsType = toJsType ( field ) ;
454
-
455
- // New behaviour - fields explicitly marked as optional and members of a one-of are nullable
456
- // Maps and repeated fields are not nullable, they default to empty instances
457
- if ( config [ "force-optional" ] ) {
455
+ if ( config [ "null-semantics" ] ) {
456
+ // With semantic nulls, fields are nullable if they are explicitly optional or part of a one-of
457
+ // Maps, repeated values and fields with implicit defaults are never null after construction
458
+ // Members are never undefined, at a minimum they are initialized to null
458
459
if ( isOptional ( field , syntax ) || field . partOf )
459
- jsType = jsType + "|null|undefined " ;
460
+ jsType = jsType + "|null" ;
460
461
}
461
- // Old behaviour - field.optional is true for all fields in proto3
462
462
else {
463
+ // Without semantic nulls, everything is optional in proto3
464
+ // Keep |undefined for backwards compatibility
463
465
if ( field . optional && ! field . map && ! field . repeated && ( field . resolvedType instanceof Type || config [ "null-defaults" ] ) || field . partOf )
464
466
jsType = jsType + "|null|undefined" ;
465
467
}
466
-
467
468
pushComment ( [
468
469
field . comment || type . name + " " + field . name + "." ,
469
470
"@member {" + jsType + "} " + field . name ,
@@ -474,9 +475,9 @@ function buildType(ref, type) {
474
475
push ( "" ) ;
475
476
firstField = false ;
476
477
}
477
- // New behaviour sets a null default when the optional keyword is used explicitly
478
- // Old behaviour considers all proto3 fields optional and uses the null-defaults config flag
479
- var nullDefault = config [ "force-optional " ]
478
+ // Semantic nulls respect the optional semantics for the current protobuf version
479
+ // Otherwise use field.optional, which doesn't consider proto3, maps, repeated fields etc.
480
+ var nullDefault = config [ "null-semantics " ]
480
481
? isOptional ( field , syntax )
481
482
: field . optional && config [ "null-defaults" ] ;
482
483
if ( field . repeated )
0 commit comments