@@ -13,6 +13,7 @@ var tokenize = require("./tokenize"),
13
13
Enum = require ( "./enum" ) ,
14
14
Service = require ( "./service" ) ,
15
15
Method = require ( "./method" ) ,
16
+ ReflectionObject = require ( "./object" ) ,
16
17
types = require ( "./types" ) ,
17
18
util = require ( "./util" ) ;
18
19
@@ -26,7 +27,11 @@ var base10Re = /^[1-9][0-9]*$/,
26
27
nameRe = / ^ [ a - z A - Z _ ] [ a - z A - Z _ 0 - 9 ] * $ / ,
27
28
typeRefRe = / ^ (?: \. ? [ a - z A - Z _ ] [ a - z A - Z _ 0 - 9 ] * ) (?: \. [ a - z A - Z _ ] [ a - z A - Z _ 0 - 9 ] * ) * $ / ,
28
29
fqTypeRefRe = / ^ (?: \. [ a - z A - Z _ ] [ a - z A - Z _ 0 - 9 ] * ) + $ / ,
29
- featuresRefRe = / f e a t u r e s \. ( [ a - z A - Z _ ] * ) / ;
30
+ featuresTypeRefRe = / ^ ( f e a t u r e s ) ( .* ) / ;
31
+
32
+ var editions2023Defaults = { features : { enum_type : 'OPEN' , field_presence : 'EXPLICIT' , json_format : 'ALLOW' , message_encoding : 'LENGTH_PREFIXED' , repeated_field_encoding : 'PACKED' , utf8_validation : 'VERIFY' } }
33
+ var proto2Defaults = { features : { enum_type : 'CLOSED' , field_presence : 'EXPLICIT' , json_format : 'LEGACY_BEST_EFFORT' , message_encoding : 'LENGTH_PREFIXED' , repeated_field_encoding : 'EXPANDED' , utf8_validation : 'NONE' } }
34
+ var proto3Defaults = { features : { enum_type : 'OPEN' , field_presence : 'IMPLICIT' , json_format : 'ALLOW' , message_encoding : 'LENGTH_PREFIXED' , repeated_field_encoding : 'PACKED' , utf8_validation : 'VERIFY' } }
30
35
31
36
/**
32
37
* Result object returned from {@link parse}.
@@ -269,6 +274,16 @@ function parse(source, root, options) {
269
274
// Otherwise the meaning is ambiguous between proto2 and proto3
270
275
root . setOption ( "syntax" , syntax ) ;
271
276
277
+ if ( isProto3 ) {
278
+ for ( var key of Object . keys ( proto3Defaults ) ) {
279
+ setParsedOption ( root , key , proto3Defaults [ key ] )
280
+ }
281
+ } else {
282
+ for ( var key of Object . keys ( proto2Defaults ) ) {
283
+ setParsedOption ( root , key , proto2Defaults [ key ] )
284
+ }
285
+ }
286
+
272
287
skip ( ";" ) ;
273
288
}
274
289
@@ -283,6 +298,9 @@ function parse(source, root, options) {
283
298
284
299
root . setOption ( "edition" , edition ) ;
285
300
301
+ for ( var key of Object . keys ( editions2023Defaults ) ) {
302
+ setParsedOption ( root , key , editions2023Defaults [ key ] )
303
+ }
286
304
skip ( ";" ) ;
287
305
}
288
306
@@ -355,13 +373,17 @@ function parse(source, root, options) {
355
373
356
374
case "required" :
357
375
case "repeated" :
376
+ if ( edition )
377
+ throw illegal ( token )
358
378
parseField ( type , token ) ;
359
379
break ;
360
380
361
381
case "optional" :
362
382
/* istanbul ignore if */
363
383
if ( isProto3 ) {
364
384
parseField ( type , "proto3_optional" ) ;
385
+ } else if ( edition ) {
386
+ throw illegal ( token ) ;
365
387
} else {
366
388
parseField ( type , "optional" ) ;
367
389
}
@@ -416,6 +438,7 @@ function parse(source, root, options) {
416
438
var name = next ( ) ;
417
439
418
440
/* istanbul ignore if */
441
+
419
442
if ( ! nameRe . test ( name ) )
420
443
throw illegal ( name , "name" ) ;
421
444
@@ -605,13 +628,43 @@ function parse(source, root, options) {
605
628
dummy . setOption = function ( name , value ) {
606
629
if ( this . options === undefined )
607
630
this . options = { } ;
631
+
608
632
this . options [ name ] = value ;
609
633
} ;
610
- dummy . setFeature = function ( name , value ) {
611
- if ( this . features === undefined )
612
- this . features = { } ;
613
- this . features [ name ] = value ;
614
- } ;
634
+ dummy . setParsedOption = function ( name , value , propName ) {
635
+ if ( ! this . parsedOptions ) {
636
+ this . parsedOptions = [ ] ;
637
+ }
638
+ var parsedOptions = this . parsedOptions ;
639
+ if ( propName ) {
640
+ // If setting a sub property of an option then try to merge it
641
+ // with an existing option
642
+ var opt = parsedOptions . find ( function ( opt ) {
643
+ return Object . prototype . hasOwnProperty . call ( opt , name ) ;
644
+ } ) ;
645
+ if ( opt ) {
646
+ // If we found an existing option - just merge the property value
647
+ // (If it's a feature, will just write over)
648
+ var newValue = opt [ name ] ;
649
+ util . setProperty ( newValue , propName , value ) ;
650
+ } else {
651
+ // otherwise, create a new option, set its property and add it to the list
652
+ opt = { } ;
653
+ opt [ name ] = util . setProperty ( { } , propName , value ) ;
654
+ parsedOptions . push ( opt ) ;
655
+ }
656
+ } else {
657
+ // Always create a new option when setting the value of the option itself
658
+ var newOpt = { } ;
659
+ newOpt [ name ] = value ;
660
+ parsedOptions . push ( newOpt ) ;
661
+ }
662
+
663
+ if ( / f e a t u r e s / . test ( name ) ) {
664
+ var features = parsedOptions . find ( x => { return x . hasOwnProperty ( "features" ) } ) ;
665
+ this . _features = features . features || { } ;
666
+ }
667
+ }
615
668
ifBlock ( dummy , function parseEnumValue_block ( token ) {
616
669
617
670
/* istanbul ignore else */
@@ -624,48 +677,52 @@ function parse(source, root, options) {
624
677
} , function parseEnumValue_line ( ) {
625
678
parseInlineOptions ( dummy ) ; // skip
626
679
} ) ;
627
- parent . add ( token , value , dummy . comment , dummy . options , dummy . features ) ;
680
+ parent . add ( token , value , dummy . comment , dummy . parsedOptions ) ;
628
681
}
629
682
630
683
function parseOption ( parent , token ) {
631
- // console.log(featuresRefRe.test(token = next()))
632
- if ( featuresRefRe . test ( peek ( ) ) ) {
684
+ var name ;
685
+ var option ;
686
+ var optionValue ;
687
+ var propName ;
688
+ // The two logic branches below are parallel tracks, but with different regexes for the following use cases:
689
+ // features expects: option features.abc.amazing_feature = A;
690
+ // custom options expects: option (mo_single_msg).nested.value = "x";
691
+ if ( featuresTypeRefRe . test ( peek ( ) ) ) {
633
692
var token = next ( ) ;
634
- var name = token . match ( featuresRefRe ) [ 1 ]
635
- skip ( "=" ) ;
636
- setFeature ( parent , name , token = next ( ) )
693
+ name = token ;
694
+ option = token . match ( featuresTypeRefRe ) [ 1 ] ;
695
+ var propNameWithPeriod = token . match ( featuresTypeRefRe ) [ 2 ] ;
696
+ if ( fqTypeRefRe . test ( propNameWithPeriod ) ) {
697
+ propName = propNameWithPeriod . slice ( 1 ) ; //remove '.' before property name
698
+ }
637
699
} else {
638
700
var isCustom = skip ( "(" , true ) ;
639
701
if ( ! typeRefRe . test ( token = next ( ) ) )
640
702
throw illegal ( token , "name" ) ;
641
703
642
704
643
- var name = token ;
644
- var option = name ;
645
- var propName ;
705
+ name = token ;
706
+ option = name ;
646
707
647
708
if ( isCustom ) {
648
709
skip ( ")" ) ;
649
710
name = "(" + name + ")" ;
650
711
option = name ;
651
712
token = peek ( ) ;
652
- console . log ( 'in custom?' + token )
653
713
if ( fqTypeRefRe . test ( token ) ) {
654
714
propName = token . slice ( 1 ) ; //remove '.' before property name
655
715
name += token ;
656
716
next ( ) ;
657
717
}
658
718
}
659
-
660
- console . log ( token )
719
+ }
661
720
skip ( "=" ) ;
662
721
var optionValue = parseOptionValue ( parent , name ) ;
663
722
setParsedOption ( parent , option , optionValue , propName ) ;
664
- }
665
723
}
666
724
667
725
function parseOptionValue ( parent , name ) {
668
- // { a: "foo" b { c: "bar" } }
669
726
if ( skip ( "{" , true ) ) {
670
727
var objectResult = { } ;
671
728
@@ -683,12 +740,9 @@ function parse(source, root, options) {
683
740
684
741
skip ( ":" , true ) ;
685
742
686
- if ( peek ( ) === "{" )
743
+ if ( peek ( ) === "{" ) {
687
744
value = parseOptionValue ( parent , name + "." + token ) ;
688
- else if ( peek ( ) === "[" ) {
689
- // option (my_option) = {
690
- // repeated_value: [ "foo", "bar" ]
691
- // };
745
+ } else if ( peek ( ) === "[" ) {
692
746
value = [ ] ;
693
747
var lastValue ;
694
748
if ( skip ( "[" , true ) ) {
@@ -732,12 +786,6 @@ function parse(source, root, options) {
732
786
parent . setOption ( name , value ) ;
733
787
}
734
788
735
- function setFeature ( parent , name , value ) {
736
- if ( parent . setFeature ) {
737
- parent . setFeature ( name , value ) ;
738
- }
739
- }
740
-
741
789
function setParsedOption ( parent , name , value , propName ) {
742
790
if ( parent . setParsedOption )
743
791
parent . setParsedOption ( name , value , propName ) ;
@@ -761,8 +809,9 @@ function parse(source, root, options) {
761
809
762
810
var service = new Service ( token ) ;
763
811
ifBlock ( service , function parseService_block ( token ) {
764
- if ( parseCommon ( service , token ) )
812
+ if ( parseCommon ( service , token ) ) {
765
813
return ;
814
+ }
766
815
767
816
/* istanbul ignore else */
768
817
if ( token === "rpc" )
@@ -849,7 +898,7 @@ function parse(source, root, options) {
849
898
850
899
default :
851
900
/* istanbul ignore if */
852
- if ( ! isProto3 || ! typeRefRe . test ( token ) )
901
+ if ( ( ! isProto3 && ! edition ) || ! typeRefRe . test ( token ) )
853
902
throw illegal ( token ) ;
854
903
push ( token ) ;
855
904
parseField ( parent , "optional" , reference ) ;
0 commit comments