@@ -6713,6 +6713,10 @@ func (p *parser) parseDecorator() js_ast.Expr {
67136713
67146714 memberExpr := js_ast.Expr{Loc: nameRange.Loc, Data: &js_ast.EIdentifier{Ref: p.storeNameInRef(name)}}
67156715
6716+ // Custom error reporting for error recovery
6717+ var syntaxError logger.MsgData
6718+ wrapRange := nameRange
6719+
67166720loop:
67176721 for {
67186722 switch p.lexer.Token {
@@ -6724,10 +6728,17 @@ loop:
67246728 if !p.options.ts.Parse {
67256729 p.lexer.Unexpected()
67266730 }
6731+ wrapRange.Len = p.lexer.Range().End() - wrapRange.Loc.Start
67276732 p.lexer.Next()
67286733
6729- case js_lexer.TDot:
6734+ case js_lexer.TDot, js_lexer.TQuestionDot:
6735+ // The grammar for "DecoratorMemberExpression" currently forbids "?."
6736+ if p.lexer.Token == js_lexer.TQuestionDot && syntaxError.Location == nil {
6737+ syntaxError = p.tracker.MsgData(p.lexer.Range(), "JavaScript decorator syntax does not allow \"?.\" here")
6738+ }
6739+
67306740 p.lexer.Next()
6741+ wrapRange.Len = p.lexer.Range().End() - wrapRange.Loc.Start
67316742
67326743 if p.lexer.Token == js_lexer.TPrivateIdentifier {
67336744 name := p.lexer.Identifier
@@ -6746,10 +6757,6 @@ loop:
67466757 p.lexer.Expect(js_lexer.TIdentifier)
67476758 }
67486759
6749- case js_lexer.TQuestionDot:
6750- // The grammar for "DecoratorMemberExpression" currently forbids "?."
6751- p.lexer.Expect(js_lexer.TDot)
6752-
67536760 case js_lexer.TOpenParen:
67546761 args, closeParenLoc, isMultiLine := p.parseCallArgs()
67556762 memberExpr.Data = &js_ast.ECall{
@@ -6759,6 +6766,15 @@ loop:
67596766 IsMultiLine: isMultiLine,
67606767 Kind: js_ast.TargetWasOriginallyPropertyAccess,
67616768 }
6769+ wrapRange.Len = closeParenLoc.Start + 1 - wrapRange.Loc.Start
6770+
6771+ // The grammar for "DecoratorCallExpression" currently forbids anything after it
6772+ if p.lexer.Token == js_lexer.TDot {
6773+ if syntaxError.Location == nil {
6774+ syntaxError = p.tracker.MsgData(p.lexer.Range(), "JavaScript decorator syntax does not allow \".\" after a call expression")
6775+ }
6776+ continue
6777+ }
67626778 break loop
67636779
67646780 default:
@@ -6770,6 +6786,21 @@ loop:
67706786 }
67716787 }
67726788
6789+ // Suggest that non-decorator expressions be wrapped in parentheses
6790+ if syntaxError.Location != nil {
6791+ var notes []logger.MsgData
6792+ if text := p.source.TextForRange(wrapRange); !strings.ContainsRune(text, '\n') {
6793+ note := p.tracker.MsgData(wrapRange, "Wrap this decorator in parentheses to allow arbitrary expressions:")
6794+ note.Location.Suggestion = fmt.Sprintf("(%s)", text)
6795+ notes = []logger.MsgData{note}
6796+ }
6797+ p.log.AddMsg(logger.Msg{
6798+ Kind: logger.Error,
6799+ Data: syntaxError,
6800+ Notes: notes,
6801+ })
6802+ }
6803+
67736804 return memberExpr
67746805}
67756806
0 commit comments