@@ -625,11 +625,18 @@ pp.parseClass = function (node, isStatement, optionalId) {
625
625
} ;
626
626
627
627
pp . isClassProperty = function ( ) {
628
- return this . match ( tt . eq ) || this . isLineTerminator ( ) ;
628
+ return this . match ( tt . eq ) || this . match ( tt . semi ) || this . match ( tt . braceR ) ;
629
629
} ;
630
630
631
- pp . isClassMutatorStarter = function ( ) {
632
- return false ;
631
+ pp . isClassMethod = function ( ) {
632
+ return this . match ( tt . parenL ) ;
633
+ } ;
634
+
635
+ pp . isNonstaticConstructor = function ( method ) {
636
+ return ! method . computed && ! method . static && (
637
+ ( method . key . name === "constructor" ) || // Identifier
638
+ ( method . key . value === "constructor" ) // Literal
639
+ ) ;
633
640
} ;
634
641
635
642
pp . parseClassBody = function ( node ) {
@@ -667,92 +674,102 @@ pp.parseClassBody = function (node) {
667
674
decorators = [ ] ;
668
675
}
669
676
670
- let isConstructorCall = false ;
671
- const isMaybeStatic = this . match ( tt . name ) && this . state . value === "static" ;
672
- let isGenerator = this . eat ( tt . star ) ;
673
- let isGetSet = false ;
674
- let isAsync = false ;
675
-
676
- this . parsePropertyName ( method ) ;
677
-
678
- method . static = isMaybeStatic && ! this . match ( tt . parenL ) ;
679
- if ( method . static ) {
680
- isGenerator = this . eat ( tt . star ) ;
681
- this . parsePropertyName ( method ) ;
682
- }
683
-
684
- if ( ! isGenerator ) {
685
- if ( this . isClassProperty ( ) ) {
677
+ method . static = false ;
678
+ if ( this . match ( tt . name ) && this . state . value === "static" ) {
679
+ const key = this . parseIdentifier ( true ) ; // eats 'static'
680
+ if ( this . isClassMethod ( ) ) {
681
+ // a method named 'static'
682
+ method . kind = "method" ;
683
+ method . computed = false ;
684
+ method . key = key ;
685
+ this . parseClassMethod ( classBody , method , false , false ) ;
686
+ continue ;
687
+ } else if ( this . isClassProperty ( ) ) {
688
+ // a property named 'static'
689
+ method . computed = false ;
690
+ method . key = key ;
686
691
classBody . body . push ( this . parseClassProperty ( method ) ) ;
687
692
continue ;
688
693
}
689
-
690
- if ( method . key . type === "Identifier" && ! method . computed && this . hasPlugin ( "classConstructorCall" ) && method . key . name === "call" && this . match ( tt . name ) && this . state . value === "constructor" ) {
691
- isConstructorCall = true ;
692
- this . parsePropertyName ( method ) ;
693
- }
694
+ // otherwise something static
695
+ method . static = true ;
694
696
}
695
697
696
- const isAsyncMethod = ! this . match ( tt . parenL ) && ! method . computed && method . key . type === "Identifier" && method . key . name === "async" ;
697
- if ( isAsyncMethod ) {
698
- if ( this . hasPlugin ( "asyncGenerators" ) && this . eat ( tt . star ) ) isGenerator = true ;
699
- isAsync = true ;
698
+ if ( this . eat ( tt . star ) ) {
699
+ // a generator
700
+ method . kind = "method" ;
700
701
this . parsePropertyName ( method ) ;
701
- }
702
-
703
- method . kind = "method" ;
704
-
705
- if ( ! method . computed ) {
706
- let { key } = method ;
707
-
708
- // handle get/set methods
709
- // eg. class Foo { get bar() {} set bar() {} }
710
- if ( ! isAsync && ! isGenerator && ! this . isClassMutatorStarter ( ) && key . type === "Identifier" && ! this . match ( tt . parenL ) && ( key . name === "get" || key . name === "set" ) ) {
711
- isGetSet = true ;
712
- method . kind = key . name ;
713
- key = this . parsePropertyName ( method ) ;
702
+ if ( this . isNonstaticConstructor ( method ) ) {
703
+ this . raise ( method . key . start , "Constructor can't be a generator" ) ;
714
704
}
715
-
716
- // disallow invalid constructors
717
- const isConstructor = ! isConstructorCall && ! method . static && (
718
- ( key . name === "constructor" ) || // Identifier
719
- ( key . value === "constructor" ) // Literal
720
- ) ;
721
- if ( isConstructor ) {
722
- if ( hadConstructor ) this . raise ( key . start , "Duplicate constructor in the same class" ) ;
723
- if ( isGetSet ) this . raise ( key . start , "Constructor can't have get/set modifier" ) ;
724
- if ( isGenerator ) this . raise ( key . start , "Constructor can't be a generator" ) ;
725
- if ( isAsync ) this . raise ( key . start , "Constructor can't be an async function" ) ;
726
- method . kind = "constructor" ;
727
- hadConstructor = true ;
705
+ if ( ! method . computed && method . static && ( method . key . name === "prototype" || method . key . value === "prototype" ) ) {
706
+ this . raise ( method . key . start , "Classes may not have static property named prototype" ) ;
728
707
}
729
-
730
- // disallow static prototype method
731
- const isStaticPrototype = method . static && (
732
- ( key . name === "prototype" ) || // Identifier
733
- ( key . value === "prototype" ) // Literal
734
- ) ;
735
- if ( isStaticPrototype ) {
736
- this . raise ( key . start , "Classes may not have static property named prototype" ) ;
708
+ this . parseClassMethod ( classBody , method , true , false ) ;
709
+ } else {
710
+ const isSimple = this . match ( tt . name ) ;
711
+ const key = this . parsePropertyName ( method ) ;
712
+ if ( ! method . computed && method . static && ( method . key . name === "prototype" || method . key . value === "prototype" ) ) {
713
+ this . raise ( method . key . start , "Classes may not have static property named prototype" ) ;
714
+ }
715
+ if ( this . isClassMethod ( ) ) {
716
+ // a normal method
717
+ if ( this . isNonstaticConstructor ( method ) ) {
718
+ if ( hadConstructor ) {
719
+ this . raise ( key . start , "Duplicate constructor in the same class" ) ;
720
+ } else if ( method . decorators ) {
721
+ this . raise ( method . start , "You can't attach decorators to a class constructor" ) ;
722
+ }
723
+ hadConstructor = true ;
724
+ method . kind = "constructor" ;
725
+ } else {
726
+ method . kind = "method" ;
727
+ }
728
+ this . parseClassMethod ( classBody , method , false , false ) ;
729
+ } else if ( this . isClassProperty ( ) ) {
730
+ // a normal property
731
+ if ( this . isNonstaticConstructor ( method ) ) {
732
+ this . raise ( method . key . start , "Classes may not have a non-static field named 'constructor'" ) ;
733
+ }
734
+ classBody . body . push ( this . parseClassProperty ( method ) ) ;
735
+ } else if ( isSimple && key . name === "async" && ! this . isLineTerminator ( ) ) {
736
+ // an async method
737
+ const isGenerator = this . hasPlugin ( "asyncGenerators" ) && this . eat ( tt . star ) ;
738
+ method . kind = "method" ;
739
+ this . parsePropertyName ( method ) ;
740
+ if ( this . isNonstaticConstructor ( method ) ) {
741
+ this . raise ( method . key . start , "Constructor can't be an async function" ) ;
742
+ }
743
+ this . parseClassMethod ( classBody , method , isGenerator , true ) ;
744
+ } else if ( isSimple && ( key . name === "get" || key . name === "set" ) && ! ( this . isLineTerminator ( ) && this . match ( tt . star ) ) ) { // `get\n*` is an uninitialized property named 'get' followed by a generator.
745
+ // a getter or setter
746
+ method . kind = key . name ;
747
+ this . parsePropertyName ( method ) ;
748
+ if ( this . isNonstaticConstructor ( method ) ) {
749
+ this . raise ( method . key . start , "Constructor can't have get/set modifier" ) ;
750
+ }
751
+ this . parseClassMethod ( classBody , method , false , false ) ;
752
+ this . checkGetterSetterParamCount ( method ) ;
753
+ } else if ( this . hasPlugin ( "classConstructorCall" ) && isSimple && key . name === "call" && this . match ( tt . name ) && this . state . value === "constructor" ) {
754
+ // a (deprecated) call constructor
755
+ if ( hadConstructorCall ) {
756
+ this . raise ( method . start , "Duplicate constructor call in the same class" ) ;
757
+ } else if ( method . decorators ) {
758
+ this . raise ( method . start , "You can't attach decorators to a class constructor" ) ;
759
+ }
760
+ hadConstructorCall = true ;
761
+ method . kind = "constructorCall" ;
762
+ this . parsePropertyName ( method ) ; // consume "constructor" and make it the method's name
763
+ this . parseClassMethod ( classBody , method , false , false ) ;
764
+ } else if ( this . isLineTerminator ( ) ) {
765
+ // an uninitialized class property (due to ASI, since we don't otherwise recognize the next token)
766
+ if ( this . isNonstaticConstructor ( method ) ) {
767
+ this . raise ( method . key . start , "Classes may not have a non-static field named 'constructor'" ) ;
768
+ }
769
+ classBody . body . push ( this . parseClassProperty ( method ) ) ;
770
+ } else {
771
+ this . unexpected ( ) ;
737
772
}
738
- }
739
-
740
- // convert constructor to a constructor call
741
- if ( isConstructorCall ) {
742
- if ( hadConstructorCall ) this . raise ( method . start , "Duplicate constructor call in the same class" ) ;
743
- method . kind = "constructorCall" ;
744
- hadConstructorCall = true ;
745
- }
746
-
747
- // disallow decorators on class constructors
748
- if ( ( method . kind === "constructor" || method . kind === "constructorCall" ) && method . decorators ) {
749
- this . raise ( method . start , "You can't attach decorators to a class constructor" ) ;
750
- }
751
-
752
- this . parseClassMethod ( classBody , method , isGenerator , isAsync ) ;
753
-
754
- if ( isGetSet ) {
755
- this . checkGetterSetterParamCount ( method ) ;
756
773
}
757
774
}
758
775
0 commit comments