Skip to content

Commit a8313d2

Browse files
committed
use "check" for decorator validation, not "guess"
1 parent d6a1255 commit a8313d2

4 files changed

Lines changed: 70 additions & 116 deletions

File tree

internal/js_ast/js_ast.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,7 @@ var EUndefinedShared = &EUndefined{}
548548
var SDebuggerShared = &SDebugger{}
549549
var SEmptyShared = &SEmpty{}
550550
var STypeScriptShared = &STypeScript{}
551+
var STypeScriptSharedWasDeclareClass = &STypeScript{WasDeclareClass: true}
551552

552553
type ENew struct {
553554
Target Expr
@@ -918,7 +919,9 @@ type SBlock struct {
918919
type SEmpty struct{}
919920

920921
// This is a stand-in for a TypeScript type declaration
921-
type STypeScript struct{}
922+
type STypeScript struct {
923+
WasDeclareClass bool
924+
}
922925

923926
type SComment struct {
924927
Text string

internal/js_parser/js_parser.go

Lines changed: 39 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -3588,16 +3588,8 @@ func (p *parser) parsePrefix(level js_ast.L, errors *deferredErrors, flags exprF
35883588
return p.parseClassExpr(nil)
35893589

35903590
case js_lexer.TAt:
3591-
// Parse decorators before class statements, which are potentially exported
3592-
scopeIndex := len(p.scopesInOrder)
3591+
// Parse decorators before class expressions
35933592
decorators := p.parseDecorators(p.currentScope, logger.Range{}, decoratorBeforeClassExpr)
3594-
3595-
// "@decorator class {}"
3596-
// "@decorator class Foo {}"
3597-
if p.lexer.Token != js_lexer.TClass {
3598-
p.logDecoratorWithoutFollowingClassError(loc, scopeIndex)
3599-
}
3600-
36013593
return p.parseClassExpr(decorators)
36023594

36033595
case js_lexer.TNew:
@@ -6139,7 +6131,8 @@ func (p *parser) parseClassStmt(loc logger.Loc, opts parseStmtOpts) js_ast.Stmt
61396131
p.hasNonLocalExportDeclareInsideNamespace = true
61406132
}
61416133

6142-
return js_ast.Stmt{Loc: loc, Data: js_ast.STypeScriptShared}
6134+
// Remember that this was a "declare class" so we can allow decorators on it
6135+
return js_ast.Stmt{Loc: loc, Data: js_ast.STypeScriptSharedWasDeclareClass}
61436136
}
61446137

61456138
p.popScope()
@@ -6149,7 +6142,7 @@ func (p *parser) parseClassStmt(loc logger.Loc, opts parseStmtOpts) js_ast.Stmt
61496142
func (p *parser) parseClassExpr(decorators []js_ast.Decorator) js_ast.Expr {
61506143
classKeyword := p.lexer.Range()
61516144
p.markSyntaxFeature(compat.Class, classKeyword)
6152-
p.lexer.Next()
6145+
p.lexer.Expect(js_lexer.TClass)
61536146
var name *ast.LocRef
61546147

61556148
opts := parseClassOpts{
@@ -6545,11 +6538,6 @@ func (p *parser) parseFnStmt(loc logger.Loc, opts parseStmtOpts, isAsync bool, a
65456538

65466539
type deferredDecorators struct {
65476540
decorators []js_ast.Decorator
6548-
6549-
// If this turns out to be a "declare class" statement, we need to undo the
6550-
// scopes that were potentially pushed while parsing the decorator arguments.
6551-
scopeIndex int
6552-
65536541
firstAtLoc logger.Loc
65546542
}
65556543

@@ -6697,20 +6685,6 @@ func (p *parser) parseDecorator() js_ast.Expr {
66976685
return memberExpr
66986686
}
66996687

6700-
func (p *parser) logDecoratorWithoutFollowingClassError(firstAtLoc logger.Loc, scopeIndex int) {
6701-
found := fmt.Sprintf("%q", p.lexer.Raw())
6702-
if p.lexer.Token == js_lexer.TEndOfFile {
6703-
found = "end of file"
6704-
}
6705-
6706-
// Try to be helpful by pointing out the decorator
6707-
p.lexer.AddRangeErrorWithNotes(p.lexer.Range(), fmt.Sprintf("Expected \"class\" after decorator but found %s", found), []logger.MsgData{
6708-
p.tracker.MsgData(logger.Range{Loc: firstAtLoc, Len: 1}, "The preceding decorator is here:"),
6709-
{Text: "Decorators can only be used with class declarations."},
6710-
})
6711-
p.discardScopesUpTo(scopeIndex)
6712-
}
6713-
67146688
type lexicalDecl uint8
67156689

67166690
const (
@@ -6759,18 +6733,6 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt {
67596733
}
67606734
p.lexer.Next()
67616735

6762-
// TypeScript decorators only work on class declarations
6763-
// "@decorator export class Foo {}"
6764-
// "@decorator export abstract class Foo {}"
6765-
// "@decorator export default class Foo {}"
6766-
// "@decorator export default abstract class Foo {}"
6767-
// "@decorator export declare class Foo {}"
6768-
// "@decorator export declare abstract class Foo {}"
6769-
if opts.deferredDecorators != nil && p.lexer.Token != js_lexer.TClass && p.lexer.Token != js_lexer.TDefault &&
6770-
!p.lexer.IsContextualKeyword("abstract") && !p.lexer.IsContextualKeyword("declare") {
6771-
p.logDecoratorWithoutFollowingClassError(opts.deferredDecorators.firstAtLoc, opts.deferredDecorators.scopeIndex)
6772-
}
6773-
67746736
switch p.lexer.Token {
67756737
case js_lexer.TClass, js_lexer.TConst, js_lexer.TFunction, js_lexer.TVar:
67766738
opts.isExport = true
@@ -6877,13 +6839,6 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt {
68776839
return defaultName
68786840
}
68796841

6880-
// TypeScript decorators only work on class declarations
6881-
// "@decorator export default class Foo {}"
6882-
// "@decorator export default abstract class Foo {}"
6883-
if opts.deferredDecorators != nil && p.lexer.Token != js_lexer.TClass && !p.lexer.IsContextualKeyword("abstract") {
6884-
p.logDecoratorWithoutFollowingClassError(opts.deferredDecorators.firstAtLoc, opts.deferredDecorators.scopeIndex)
6885-
}
6886-
68876842
if p.lexer.IsContextualKeyword("async") {
68886843
asyncRange := p.lexer.Range()
68896844
p.lexer.Next()
@@ -7095,25 +7050,37 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt {
70957050
opts.deferredDecorators = &deferredDecorators{
70967051
firstAtLoc: loc,
70977052
decorators: decorators,
7098-
scopeIndex: scopeIndex,
70997053
}
71007054

7101-
// "@decorator class Foo {}"
7102-
// "@decorator abstract class Foo {}"
7103-
// "@decorator declare class Foo {}"
7104-
// "@decorator declare abstract class Foo {}"
7105-
// "@decorator export class Foo {}"
7106-
// "@decorator export abstract class Foo {}"
7107-
// "@decorator export declare class Foo {}"
7108-
// "@decorator export declare abstract class Foo {}"
7109-
// "@decorator export default class Foo {}"
7110-
// "@decorator export default abstract class Foo {}"
7111-
if p.lexer.Token != js_lexer.TClass && p.lexer.Token != js_lexer.TExport &&
7112-
(!p.options.ts.Parse || (!p.lexer.IsContextualKeyword("abstract") && !p.lexer.IsContextualKeyword("declare"))) {
7113-
p.logDecoratorWithoutFollowingClassError(opts.deferredDecorators.firstAtLoc, opts.deferredDecorators.scopeIndex)
7055+
stmt := p.parseStmt(opts)
7056+
7057+
// Check for valid decorator targets
7058+
switch s := stmt.Data.(type) {
7059+
case *js_ast.SClass:
7060+
return stmt
7061+
7062+
case *js_ast.SExportDefault:
7063+
switch s.Value.Data.(type) {
7064+
case *js_ast.SClass:
7065+
return stmt
7066+
}
7067+
7068+
case *js_ast.STypeScript:
7069+
if s.WasDeclareClass {
7070+
// If this is a type declaration, discard any scopes that were pushed
7071+
// while parsing decorators. Unlike with the class statements above,
7072+
// these scopes won't end up being visited during the upcoming visit
7073+
// pass because type declarations aren't visited at all.
7074+
p.discardScopesUpTo(scopeIndex)
7075+
return stmt
7076+
}
71147077
}
71157078

7116-
return p.parseStmt(opts)
7079+
// Forbid decorators on anything other than a class statement
7080+
p.log.AddError(&p.tracker, logger.Range{Loc: loc, Len: 1}, "Decorators are not valid here")
7081+
stmt.Data = js_ast.STypeScriptShared
7082+
p.discardScopesUpTo(scopeIndex)
7083+
return stmt
71177084

71187085
case js_lexer.TClass:
71197086
if opts.lexicalDecl != lexicalDeclAllowAll {
@@ -7857,12 +7824,6 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt {
78577824
opts.lexicalDecl = lexicalDeclAllowAll
78587825
opts.isTypeScriptDeclare = true
78597826

7860-
// "@decorator declare class Foo {}"
7861-
// "@decorator declare abstract class Foo {}"
7862-
if opts.deferredDecorators != nil && p.lexer.Token != js_lexer.TClass && !p.lexer.IsContextualKeyword("abstract") {
7863-
p.logDecoratorWithoutFollowingClassError(opts.deferredDecorators.firstAtLoc, opts.deferredDecorators.scopeIndex)
7864-
}
7865-
78667827
// "declare global { ... }"
78677828
if p.lexer.IsContextualKeyword("global") {
78687829
p.lexer.Next()
@@ -7876,12 +7837,16 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt {
78767837
scopeIndex := len(p.scopesInOrder)
78777838
oldLexer := p.lexer
78787839
stmt := p.parseStmt(opts)
7879-
switch stmt.Data.(type) {
7840+
typeDeclarationData := js_ast.STypeScriptShared
7841+
switch s := stmt.Data.(type) {
78807842
case *js_ast.SEmpty:
78817843
return js_ast.Stmt{Loc: loc, Data: &js_ast.SExpr{Value: expr}}
78827844

78837845
case *js_ast.STypeScript:
7884-
// Type declarations are expected
7846+
// Type declarations are expected. Propagate the "declare class"
7847+
// status in case our caller is a decorator that needs to know
7848+
// this was a "declare class" statement.
7849+
typeDeclarationData = s
78857850

78867851
case *js_ast.SLocal:
78877852
// This is also a type declaration (but doesn't use "STypeScript"
@@ -7900,11 +7865,7 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt {
79007865
p.lexer = oldLexer
79017866
p.lexer.Unexpected()
79027867
}
7903-
if opts.deferredDecorators != nil {
7904-
p.discardScopesUpTo(opts.deferredDecorators.scopeIndex)
7905-
} else {
7906-
p.discardScopesUpTo(scopeIndex)
7907-
}
7868+
p.discardScopesUpTo(scopeIndex)
79087869

79097870
// Unlike almost all uses of "declare", statements that use
79107871
// "export declare" with "var/let/const" inside a namespace affect
@@ -7942,7 +7903,7 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt {
79427903
}
79437904
}
79447905

7945-
return js_ast.Stmt{Loc: loc, Data: js_ast.STypeScriptShared}
7906+
return js_ast.Stmt{Loc: loc, Data: typeDeclarationData}
79467907
}
79477908
}
79487909
}

internal/js_parser/js_parser_test.go

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2027,19 +2027,16 @@ func TestDecorators(t *testing.T) {
20272027
expectPrinted(t, "@(() => {}) class Foo {}", "@(() => {\n})\nclass Foo {\n}\n")
20282028
expectPrinted(t, "class Foo { #x = @y.#x.y.#x class {} }", "class Foo {\n #x = @y.#x.y.#x class {\n };\n}\n")
20292029
expectParseError(t, "@123 class Foo {}", "<stdin>: ERROR: Expected identifier but found \"123\"\n")
2030-
expectParseError(t, "@x[y] class Foo {}",
2031-
"<stdin>: ERROR: Expected \"class\" after decorator but found \"[\"\n<stdin>: NOTE: The preceding decorator is here:\n"+
2032-
"NOTE: Decorators can only be used with class declarations.\n<stdin>: ERROR: Expected \";\" but found \"class\"\n")
2030+
expectParseError(t, "@x[y] class Foo {}", "<stdin>: ERROR: Expected \";\" but found \"class\"\n")
20332031
expectParseError(t, "@x?.() class Foo {}", "<stdin>: ERROR: Expected \".\" but found \"?.\"\n")
20342032
expectParseError(t, "@x?.y() class Foo {}", "<stdin>: ERROR: Expected \".\" but found \"?.\"\n")
20352033
expectParseError(t, "@x?.[y]() class Foo {}", "<stdin>: ERROR: Expected \".\" but found \"?.\"\n")
20362034
expectParseError(t, "@new Function() class Foo {}", "<stdin>: ERROR: Expected identifier but found \"new\"\n")
20372035
expectParseError(t, "@() => {} class Foo {}", "<stdin>: ERROR: Unexpected \")\"\n")
2036+
expectParseError(t, "x = @y function() {}", "<stdin>: ERROR: Expected \"class\" but found \"function\"\n")
20382037

20392038
// See: https://github.com/microsoft/TypeScript/issues/55336
2040-
expectParseError(t, "@x().y() class Foo {}",
2041-
"<stdin>: ERROR: Expected \"class\" after decorator but found \".\"\n"+
2042-
"<stdin>: NOTE: The preceding decorator is here:\nNOTE: Decorators can only be used with class declarations.\n")
2039+
expectParseError(t, "@x().y() class Foo {}", "<stdin>: ERROR: Unexpected \".\"\n")
20432040

20442041
errorText := "<stdin>: ERROR: Transforming JavaScript decorators to the configured target environment is not supported yet\n"
20452042
expectParseErrorWithUnsupportedFeatures(t, compat.Decorators, "@dec class Foo {}", errorText)
@@ -2051,13 +2048,8 @@ func TestDecorators(t *testing.T) {
20512048
expectParseErrorWithUnsupportedFeatures(t, compat.Decorators, "class Foo { @dec static accessor x }", errorText)
20522049

20532050
// Check ASI for "abstract"
2054-
expectParseError(t, "@x abstract class Foo {}",
2055-
"<stdin>: ERROR: Expected \"class\" after decorator but found \"abstract\"\n"+
2056-
"<stdin>: NOTE: The preceding decorator is here:\nNOTE: Decorators can only be used with class declarations.\n"+
2057-
"<stdin>: ERROR: Expected \";\" but found \"class\"\n")
2058-
expectParseError(t, "@x abstract\nclass Foo {}",
2059-
"<stdin>: ERROR: Expected \"class\" after decorator but found \"abstract\"\n"+
2060-
"<stdin>: NOTE: The preceding decorator is here:\nNOTE: Decorators can only be used with class declarations.\n")
2051+
expectParseError(t, "@x abstract class Foo {}", "<stdin>: ERROR: Expected \";\" but found \"class\"\n")
2052+
expectParseError(t, "@x abstract\nclass Foo {}", "<stdin>: ERROR: Decorators are not valid here\n")
20612053
}
20622054

20632055
func TestGenerator(t *testing.T) {

internal/js_parser/ts_parser_test.go

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1859,24 +1859,22 @@ func TestTSExperimentalDecorator(t *testing.T) {
18591859
expectPrintedExperimentalDecoratorTS(t, "declare class Foo { foo(@dec(() => 0) x) } {let foo}", "{\n let foo;\n}\n")
18601860

18611861
// Decorators must only work on class statements
1862-
notes := "<stdin>: NOTE: The preceding decorator is here:\n" +
1863-
"NOTE: Decorators can only be used with class declarations.\n"
1864-
expectParseErrorExperimentalDecoratorTS(t, "@dec enum foo {}", "<stdin>: ERROR: Expected \"class\" after decorator but found \"enum\"\n"+notes)
1865-
expectParseErrorExperimentalDecoratorTS(t, "@dec namespace foo {}", "<stdin>: ERROR: Expected \"class\" after decorator but found \"namespace\"\n"+notes)
1866-
expectParseErrorExperimentalDecoratorTS(t, "@dec function foo() {}", "<stdin>: ERROR: Expected \"class\" after decorator but found \"function\"\n"+notes)
1862+
expectParseErrorExperimentalDecoratorTS(t, "@dec enum foo {}", "<stdin>: ERROR: Decorators are not valid here\n")
1863+
expectParseErrorExperimentalDecoratorTS(t, "@dec namespace foo {}", "<stdin>: ERROR: Decorators are not valid here\n")
1864+
expectParseErrorExperimentalDecoratorTS(t, "@dec function foo() {}", "<stdin>: ERROR: Decorators are not valid here\n")
18671865
expectParseErrorExperimentalDecoratorTS(t, "@dec abstract", "<stdin>: ERROR: Expected \"class\" but found end of file\n")
1868-
expectParseErrorExperimentalDecoratorTS(t, "@dec declare: x", "<stdin>: ERROR: Expected \"class\" after decorator but found \":\"\n"+notes)
1869-
expectParseErrorExperimentalDecoratorTS(t, "@dec declare enum foo {}", "<stdin>: ERROR: Expected \"class\" after decorator but found \"enum\"\n"+notes)
1870-
expectParseErrorExperimentalDecoratorTS(t, "@dec declare namespace foo {}", "<stdin>: ERROR: Expected \"class\" after decorator but found \"namespace\"\n"+notes)
1871-
expectParseErrorExperimentalDecoratorTS(t, "@dec declare function foo()", "<stdin>: ERROR: Expected \"class\" after decorator but found \"function\"\n"+notes)
1872-
expectParseErrorExperimentalDecoratorTS(t, "@dec export {}", "<stdin>: ERROR: Expected \"class\" after decorator but found \"{\"\n"+notes)
1873-
expectParseErrorExperimentalDecoratorTS(t, "@dec export enum foo {}", "<stdin>: ERROR: Expected \"class\" after decorator but found \"enum\"\n"+notes)
1874-
expectParseErrorExperimentalDecoratorTS(t, "@dec export namespace foo {}", "<stdin>: ERROR: Expected \"class\" after decorator but found \"namespace\"\n"+notes)
1875-
expectParseErrorExperimentalDecoratorTS(t, "@dec export function foo() {}", "<stdin>: ERROR: Expected \"class\" after decorator but found \"function\"\n"+notes)
1866+
expectParseErrorExperimentalDecoratorTS(t, "@dec declare: x", "<stdin>: ERROR: Unexpected \":\"\n")
1867+
expectParseErrorExperimentalDecoratorTS(t, "@dec declare enum foo {}", "<stdin>: ERROR: Decorators are not valid here\n")
1868+
expectParseErrorExperimentalDecoratorTS(t, "@dec declare namespace foo {}", "<stdin>: ERROR: Decorators are not valid here\n")
1869+
expectParseErrorExperimentalDecoratorTS(t, "@dec declare function foo()", "<stdin>: ERROR: Decorators are not valid here\n")
1870+
expectParseErrorExperimentalDecoratorTS(t, "@dec export {}", "<stdin>: ERROR: Decorators are not valid here\n")
1871+
expectParseErrorExperimentalDecoratorTS(t, "@dec export enum foo {}", "<stdin>: ERROR: Decorators are not valid here\n")
1872+
expectParseErrorExperimentalDecoratorTS(t, "@dec export namespace foo {}", "<stdin>: ERROR: Decorators are not valid here\n")
1873+
expectParseErrorExperimentalDecoratorTS(t, "@dec export function foo() {}", "<stdin>: ERROR: Decorators are not valid here\n")
18761874
expectParseErrorExperimentalDecoratorTS(t, "@dec export default abstract", "<stdin>: ERROR: Expected \"class\" but found end of file\n")
1877-
expectParseErrorExperimentalDecoratorTS(t, "@dec export declare enum foo {}", "<stdin>: ERROR: Expected \"class\" after decorator but found \"enum\"\n"+notes)
1878-
expectParseErrorExperimentalDecoratorTS(t, "@dec export declare namespace foo {}", "<stdin>: ERROR: Expected \"class\" after decorator but found \"namespace\"\n"+notes)
1879-
expectParseErrorExperimentalDecoratorTS(t, "@dec export declare function foo()", "<stdin>: ERROR: Expected \"class\" after decorator but found \"function\"\n"+notes)
1875+
expectParseErrorExperimentalDecoratorTS(t, "@dec export declare enum foo {}", "<stdin>: ERROR: Decorators are not valid here\n")
1876+
expectParseErrorExperimentalDecoratorTS(t, "@dec export declare namespace foo {}", "<stdin>: ERROR: Decorators are not valid here\n")
1877+
expectParseErrorExperimentalDecoratorTS(t, "@dec export declare function foo()", "<stdin>: ERROR: Decorators are not valid here\n")
18801878

18811879
// Decorators must be forbidden outside class statements
18821880
note := "<stdin>: NOTE: This is a class expression, not a class declaration:\n"
@@ -1994,14 +1992,15 @@ func TestTSExperimentalDecorator(t *testing.T) {
19941992
expectPrintedExperimentalDecoratorTS(t, "@x?.y() class Foo {}", "let Foo = class {\n};\nFoo = __decorateClass([\n x?.y()\n], Foo);\n")
19951993
expectPrintedExperimentalDecoratorTS(t, "@x?.[y]() class Foo {}", "let Foo = class {\n};\nFoo = __decorateClass([\n x?.[y]()\n], Foo);\n")
19961994
expectPrintedExperimentalDecoratorTS(t, "@new Function() class Foo {}", "let Foo = class {\n};\nFoo = __decorateClass([\n new Function()\n], Foo);\n")
1997-
expectParseErrorExperimentalDecoratorTS(t, "@x[y] class Foo {}",
1998-
"<stdin>: ERROR: Expected \"class\" after decorator but found \"[\"\n<stdin>: NOTE: The preceding decorator is here:\n"+
1999-
"NOTE: Decorators can only be used with class declarations.\n<stdin>: ERROR: Expected \";\" but found \"class\"\n")
1995+
expectParseErrorExperimentalDecoratorTS(t, "@x[y] class Foo {}", "<stdin>: ERROR: Expected \";\" but found \"class\"\n")
20001996
expectParseErrorExperimentalDecoratorTS(t, "@() => {} class Foo {}", "<stdin>: ERROR: Unexpected \")\"\n")
1997+
expectParseErrorExperimentalDecoratorTS(t, "x = @y function() {}",
1998+
"<stdin>: ERROR: Experimental decorators cannot be used in expression position in TypeScript\n"+
1999+
"<stdin>: ERROR: Expected \"class\" but found \"function\"\n")
20012000

20022001
// Check ASI for "abstract"
20032002
expectPrintedExperimentalDecoratorTS(t, "@x abstract class Foo {}", "let Foo = class {\n};\nFoo = __decorateClass([\n x\n], Foo);\n")
2004-
expectParseErrorExperimentalDecoratorTS(t, "@x abstract\nclass Foo {}", "") // TODO
2003+
expectParseErrorExperimentalDecoratorTS(t, "@x abstract\nclass Foo {}", "<stdin>: ERROR: Decorators are not valid here\n")
20052004
}
20062005

20072006
func TestTSDecorators(t *testing.T) {
@@ -2033,14 +2032,13 @@ func TestTSDecorators(t *testing.T) {
20332032
expectPrintedTS(t, "@(() => {}) class Foo {}", "@(() => {\n})\nclass Foo {\n}\n")
20342033
expectPrintedTS(t, "class Foo { #x = @y.#x.y.#x class {} }", "class Foo {\n #x = @y.#x.y.#x class {\n };\n}\n")
20352034
expectParseErrorTS(t, "@123 class Foo {}", "<stdin>: ERROR: Expected identifier but found \"123\"\n")
2036-
expectParseErrorTS(t, "@x[y] class Foo {}",
2037-
"<stdin>: ERROR: Expected \"class\" after decorator but found \"[\"\n<stdin>: NOTE: The preceding decorator is here:\n"+
2038-
"NOTE: Decorators can only be used with class declarations.\n<stdin>: ERROR: Expected \";\" but found \"class\"\n")
2035+
expectParseErrorTS(t, "@x[y] class Foo {}", "<stdin>: ERROR: Expected \";\" but found \"class\"\n")
20392036
expectParseErrorTS(t, "@x?.() class Foo {}", "<stdin>: ERROR: Expected \".\" but found \"?.\"\n")
20402037
expectParseErrorTS(t, "@x?.y() class Foo {}", "<stdin>: ERROR: Expected \".\" but found \"?.\"\n")
20412038
expectParseErrorTS(t, "@x?.[y]() class Foo {}", "<stdin>: ERROR: Expected \".\" but found \"?.\"\n")
20422039
expectParseErrorTS(t, "@new Function() class Foo {}", "<stdin>: ERROR: Expected identifier but found \"new\"\n")
20432040
expectParseErrorTS(t, "@() => {} class Foo {}", "<stdin>: ERROR: Unexpected \")\"\n")
2041+
expectParseErrorTS(t, "x = @y function() {}", "<stdin>: ERROR: Expected \"class\" but found \"function\"\n")
20442042

20452043
expectPrintedTS(t, "class Foo { @x<{}> y: any }", "class Foo {\n @x\n y;\n}\n")
20462044
expectPrintedTS(t, "class Foo { @x<{}>() y: any }", "class Foo {\n @x()\n y;\n}\n")
@@ -2063,7 +2061,7 @@ func TestTSDecorators(t *testing.T) {
20632061

20642062
// Check ASI for "abstract"
20652063
expectPrintedTS(t, "@x abstract class Foo {}", "@x\nclass Foo {\n}\n")
2066-
expectParseErrorTS(t, "@x abstract\nclass Foo {}", "") // TODO
2064+
expectParseErrorTS(t, "@x abstract\nclass Foo {}", "<stdin>: ERROR: Decorators are not valid here\n")
20672065
}
20682066

20692067
func TestTSTry(t *testing.T) {

0 commit comments

Comments
 (0)