This file contains code for parsing TypeScript syntax. The parser just skips over type expressions as if they are whitespace and doesn't bother generating an AST because nothing uses type information.

package js_parser

import (
	
	
	
)

func ( *parser) () {
	switch .lexer.Token {
	case js_lexer.TIdentifier, js_lexer.TThis:
		.lexer.Next()

	case js_lexer.TOpenBracket:
		.lexer.Next()
"[, , a]"
		for .lexer.Token == js_lexer.TComma {
			.lexer.Next()
		}
"[a, b]"
		for .lexer.Token != js_lexer.TCloseBracket {
			.()
			if .lexer.Token != js_lexer.TComma {
				break
			}
			.lexer.Next()
		}

		.lexer.Expect(js_lexer.TCloseBracket)

	case js_lexer.TOpenBrace:
		.lexer.Next()

		for .lexer.Token != js_lexer.TCloseBrace {
			 := false

			switch .lexer.Token {
"{x}" "{x: y}"
				 = true
				.lexer.Next()
"{1: y}" "{'x': y}"
"{if: x}"
					.lexer.Next()
				} else {
					.lexer.Unexpected()
				}
			}

			if .lexer.Token == js_lexer.TColon || ! {
				.lexer.Expect(js_lexer.TColon)
				.()
			}

			if .lexer.Token != js_lexer.TComma {
				break
			}
			.lexer.Next()
		}

		.lexer.Expect(js_lexer.TCloseBrace)

	default:
		.lexer.Unexpected()
	}
}

func ( *parser) () {
	.lexer.Expect(js_lexer.TOpenParen)

"(a?)"
"(a, b)"
This is a spot where the TypeScript grammar is highly ambiguous. Here are some cases that are valid: let x = (y: any): (() => {}) => { }; let x = (y: any): () => {} => { }; let x = (y: any): (y) => {} => { }; let x = (y: any): (y[]) => {}; let x = (y: any): (a | b) => {}; Here are some cases that aren't valid: let x = (y: any): (y) => {}; let x = (y: any): (y) => {return 0}; let x = (y: any): asserts y is (y) => {};
Skip over "function assert(x: boolean): asserts x"
	if .lexer.IsContextualKeyword("asserts") {
		.lexer.Next()
"function assert(x: boolean): asserts" is also valid
		if .lexer.Token != js_lexer.TIdentifier && .lexer.Token != js_lexer.TThis {
			return
		}
		.lexer.Next()
Support things like "type Foo = | A | B" and "type Foo = & A & B"
		.lexer.Next()
		.()

"new () => Foo" "new <T>() => Foo<T>"
"(number | string)"
		.skipTypeScriptParenOrFnType()

	case js_lexer.TIdentifier:
		switch .lexer.Identifier {
		case "keyof", "readonly", "infer":
			.lexer.Next()
			.skipTypeScriptType(js_ast.LPrefix)

		case "unique":
			.lexer.Next()
			if .lexer.IsContextualKeyword("symbol") {
				.lexer.Next()
			}
This was added in TypeScript 4.2
		case "abstract":
			.lexer.Next()
			if .lexer.Token == js_lexer.TNew {
				.()
			}

		default:
			.lexer.Next()
		}

	case js_lexer.TTypeof:
		.lexer.Next()
"typeof import('fs')"
			.()
"typeof x" "typeof x.y"
			for {
				if !.lexer.IsIdentifierOrKeyword() {
					.lexer.Expected(js_lexer.TIdentifier)
				}
				.lexer.Next()
				if .lexer.Token != js_lexer.TDot {
					break
				}
				.lexer.Next()
			}
		}

"`${'a' | 'b'}-${'c' | 'd'}`"
A postfix "!" is allowed in JSDoc types in TypeScript, which are only present in comments. While it's not valid in a non-comment position, it's still parsed and turned into a soft error by the TypeScript compiler. It turns out parsing this is important for correctness for "as" casts because the "!" token must still be consumed.
"{ ['x']: string \n ['y']: string }" must not become a single type
"let foo: any \n <number>foo" must not become a single type
			if .lexer.HasNewlineBefore {
				return
			}
			.lexer.ExpectLessThan(false /* isInsideJSXElement */)
			for {
				.skipTypeScriptType(js_ast.LLowest)
				if .lexer.Token != js_lexer.TComma {
					break
				}
				.lexer.Next()
			}
			.lexer.ExpectGreaterThan(false /* isInsideJSXElement */)

"{ x: number \n extends: boolean }" must not become a single type
			if .lexer.HasNewlineBefore ||  >= js_ast.LConditional {
				return
			}
			.lexer.Next()
The type following "extends" is not permitted to be another conditional type
"{ -readonly [K in keyof T]: T[K] }" "{ +readonly [K in keyof T]: T[K] }"
Skip over modifiers and the property identifier
Index signature or computed property
"{ [key: string]: number }" "{ readonly [K in keyof T]: T[K] }"
"{ [K in keyof T as `get-${K}`]: T[K] }"
"{ [K in keyof T]+?: T[K] }" "{ [K in keyof T]-?: T[K] }"
			if .lexer.Token == js_lexer.TPlus || .lexer.Token == js_lexer.TMinus {
				.lexer.Next()
			}

			 = true
		}
"?" indicates an optional property "!" indicates an initialization assertion
		if  && (.lexer.Token == js_lexer.TQuestion || .lexer.Token == js_lexer.TExclamation) {
			.lexer.Next()
		}
Type parameters come right after the optional mark
Regular property
Method signature
This is the type parameter declarations that go with other symbol declarations (class, function, type, etc.)
"class Foo<T extends number> {}"
"class Foo<T = void> {}"
			if .lexer.Token == js_lexer.TEquals {
				.lexer.Next()
				.skipTypeScriptType(js_ast.LLowest)
			}

			if .lexer.Token != js_lexer.TComma {
				break
			}
			.lexer.Next()
			if .lexer.Token == js_lexer.TGreaterThan {
				break
			}
		}

		.lexer.ExpectGreaterThan(false /* isInsideJSXElement */)
	}
}

func ( *parser) ( bool) bool {
	if .lexer.Token != js_lexer.TLessThan {
		return false
	}

	.lexer.Next()

	for {
		.skipTypeScriptType(js_ast.LLowest)
		if .lexer.Token != js_lexer.TComma {
			break
		}
		.lexer.Next()
	}
This type argument list must end with a ">"
	.lexer.ExpectGreaterThan()
	return true
}

func ( *parser) () bool {
	 := .lexer
	.lexer.IsLogDisabled = true
Implement backtracking by restoring the lexer's memory to its original state
	defer func() {
		 := recover()
		if ,  := .(js_lexer.LexerPanic);  {
			.lexer = 
		} else if  != nil {
			panic()
		}
	}()

	.skipTypeScriptTypeArguments(false /* isInsideJSXElement */)
Check the token after this and backtrack if it's the wrong one
Restore the log disabled flag. Note that we can't just set it back to false because it may have been true to start with.
Implement backtracking by restoring the lexer's memory to its original state
	defer func() {
		 := recover()
		if ,  := .(js_lexer.LexerPanic);  {
			.lexer = 
		} else if  != nil {
			panic()
		}
	}()

	.skipTypeScriptTypeParameters()
	if .lexer.Token != js_lexer.TOpenParen {
		.lexer.Unexpected()
	}
Restore the log disabled flag. Note that we can't just set it back to false because it may have been true to start with.
Implement backtracking by restoring the lexer's memory to its original state
	defer func() {
		 := recover()
		if ,  := .(js_lexer.LexerPanic);  {
			.lexer = 
		} else if  != nil {
			panic()
		}
	}()

	.lexer.Expect(js_lexer.TColon)
	.skipTypeScriptReturnType()
Check the token after this and backtrack if it's the wrong one
Restore the log disabled flag. Note that we can't just set it back to false because it may have been true to start with.
Implement backtracking by restoring the lexer's memory to its original state
	defer func() {
		 := recover()
		if ,  := .(js_lexer.LexerPanic);  {
			.lexer = 
		} else if  != nil {
			panic()
		}
	}()

	.skipTypeScriptFnArgs()
	.lexer.Expect(js_lexer.TEqualsGreaterThan)
Restore the log disabled flag. Note that we can't just set it back to false because it may have been true to start with.
	.lexer.IsLogDisabled = .IsLogDisabled
	return true
}
This function is taken from the official TypeScript compiler source code: https://github.com/microsoft/TypeScript/blob/master/src/compiler/parser.ts
These are the only tokens can legally follow a type argument list. So we definitely want to treat them as type arg lists.
		js_lexer.TOpenParen,                     // foo<x>(
		js_lexer.TNoSubstitutionTemplateLiteral, // foo<T> `...`
		js_lexer.TTemplateHead:                  // foo<T> `...${100}...`
		return true

These cases can't legally follow a type arg list. However, they're not legal expressions either. The user is probably in the middle of a generic type. So treat it as such.
		js_lexer.TDot,                     // foo<x>.
		js_lexer.TCloseParen,              // foo<x>)
		js_lexer.TCloseBracket,            // foo<x>]
		js_lexer.TColon,                   // foo<x>:
		js_lexer.TSemicolon,               // foo<x>;
		js_lexer.TQuestion,                // foo<x>?
		js_lexer.TEqualsEquals,            // foo<x> ==
		js_lexer.TEqualsEqualsEquals,      // foo<x> ===
		js_lexer.TExclamationEquals,       // foo<x> !=
		js_lexer.TExclamationEqualsEquals, // foo<x> !==
		js_lexer.TAmpersandAmpersand,      // foo<x> &&
		js_lexer.TBarBar,                  // foo<x> ||
		js_lexer.TQuestionQuestion,        // foo<x> ??
		js_lexer.TCaret,                   // foo<x> ^
		js_lexer.TAmpersand,               // foo<x> &
		js_lexer.TBar,                     // foo<x> |
		js_lexer.TCloseBrace,              // foo<x> }
		js_lexer.TEndOfFile:               // foo<x>
		return true

We don't want to treat these as type arguments. Otherwise we'll parse this as an invocation expression. Instead, we want to parse out the expression in isolation from the type arguments.
		js_lexer.TComma,     // foo<x>,
		js_lexer.TOpenBrace: // foo<x> {
		return false

Anything else treat as an expression.
Parse a new/call expression with "exprFlagTSDecorator" so we ignore EIndex expressions, since they may be part of a computed property: class Foo { @foo ['computed']() {} } This matches the behavior of the TypeScript compiler.
			 = append(, .parseExprWithFlags(js_ast.LNew, exprFlagTSDecorator))
		}
	}
	return 
}

func ( *parser) ( logger.Loc,  parseStmtOpts) js_ast.Stmt {
	.lexer.Expect(js_lexer.TEnum)
	 := .lexer.Loc()
	 := .lexer.Identifier
	.lexer.Expect(js_lexer.TIdentifier)
	 := js_ast.LocRef{Loc: , Ref: js_ast.InvalidRef}
	 := js_ast.InvalidRef
	if !.isTypeScriptDeclare {
		.Ref = .declareSymbol(js_ast.SymbolTSEnum, , )
		.pushScopeForParsePass(js_ast.ScopeEntry, )
		 = .declareSymbol(js_ast.SymbolHoisted, , )
	}
	.lexer.Expect(js_lexer.TOpenBrace)

	 := []js_ast.EnumValue{}

	for .lexer.Token != js_lexer.TCloseBrace {
		 := js_ast.EnumValue{
			Loc: .lexer.Loc(),
			Ref: js_ast.InvalidRef,
		}
Identifiers can be referenced by other values
Parse the initializer
		if .lexer.Token == js_lexer.TEquals {
			.lexer.Next()
			 := .parseExpr(js_ast.LComma)
			.Value = &
		}

		 = append(, )

		if .lexer.Token != js_lexer.TComma && .lexer.Token != js_lexer.TSemicolon {
			break
		}
		.lexer.Next()
	}

	if !.isTypeScriptDeclare {
		.popScope()
	}

	.lexer.Expect(js_lexer.TCloseBrace)
	return js_ast.Stmt{Loc: , Data: &js_ast.SEnum{
		Name:     ,
		Arg:      ,
		Values:   ,
		IsExport: .isExport,
	}}
}
This assumes the caller has already parsed the "import" token
"import ns = require('x')"
"import Foo = Bar" "import Foo = Bar.Baz"
		for .lexer.Token == js_lexer.TDot {
			.lexer.Next()
			.Data = &js_ast.EDot{
				Target:  ,
				Name:    .lexer.Identifier,
				NameLoc: .lexer.Loc(),
			}
			.lexer.Expect(js_lexer.TIdentifier)
		}
	}

	.lexer.ExpectOrInsertSemicolon()
	 := .declareSymbol(js_ast.SymbolConst, , )
	 := []js_ast.Decl{{
		Binding: js_ast.Binding{Loc: , Data: &js_ast.BIdentifier{Ref: }},
		Value:   &,
	}}

	return js_ast.Stmt{Loc: , Data: &js_ast.SLocal{
		Kind:              ,
		Decls:             ,
		IsExport:          .isExport,
		WasTSImportEquals: true,
	}}
}

"namespace Foo {}"
Import assignments may be only used in type expressions, not value expressions. If this is the case, the TypeScript compiler removes them entirely from the output. That can cause the namespace itself to be considered empty and thus be removed.
	 := 0
	for ,  := range  {
		if ,  := .Data.(*js_ast.SLocal);  && .WasTSImportEquals && !.IsExport {
			++
		}
	}
TypeScript omits namespaces without values. These namespaces are only allowed to be used in type expressions. They are allowed to be exported, but can also only be used in type expressions when imported. So we shouldn't count them as a real export either.
	if len() ==  || .isTypeScriptDeclare {
		.popAndDiscardScope()
		if .isModuleScope {
			.localTypeNames[] = true
		}
		return js_ast.Stmt{Loc: , Data: &js_ast.STypeScript{}}
	}

	 := js_ast.InvalidRef
Avoid a collision with the namespace closure argument variable if the namespace exports a symbol with the same name as the namespace itself: namespace foo { export let foo = 123 console.log(foo) } TypeScript generates the following code in this case: var foo; (function (foo_1) { foo_1.foo = 123; console.log(foo_1.foo); })(foo || (foo = {}));
Add a "_" to make tests easier to read, since non-bundler tests don't run the renamer. For external-facing things the renamer will avoid collisions automatically so this isn't important for correctness.
			 = .newSymbol(js_ast.SymbolHoisted, "_"+)
			.currentScope.Generated = append(.currentScope.Generated, )
		} else {
			 = .declareSymbol(js_ast.SymbolHoisted, , )
		}
	}

	.popScope()
	if !.isTypeScriptDeclare {
		.Ref = .declareSymbol(js_ast.SymbolTSNamespace, , )
	}
	return js_ast.Stmt{Loc: , Data: &js_ast.SNamespace{
		Name:     ,
		Arg:      ,
		Stmts:    ,
		IsExport: .isExport,
	}}
}

func ( *parser) (
	 []js_ast.Stmt,  logger.Loc,  bool,  logger.Loc,
	 js_ast.Ref,  js_ast.Ref,  []js_ast.Stmt,
Follow the link chain in case symbols were merged
	 := .symbols[.InnerIndex]
	for .Link != js_ast.InvalidRef {
		 = .Link
		 = .symbols[.InnerIndex]
	}
Make sure to only emit a variable once for a given namespace, since there can be multiple namespace blocks for the same namespace
	if (.Kind == js_ast.SymbolTSNamespace || .Kind == js_ast.SymbolTSEnum) && !.emittedNamespaceVars[] {
		.emittedNamespaceVars[] = true
Top-level namespace
			 = append(, js_ast.Stmt{Loc: , Data: &js_ast.SLocal{
				Kind:     js_ast.LocalVar,
				Decls:    []js_ast.Decl{{Binding: js_ast.Binding{Loc: , Data: &js_ast.BIdentifier{Ref: }}}},
				IsExport: ,
			}})
Nested namespace
			 = append(, js_ast.Stmt{Loc: , Data: &js_ast.SLocal{
				Kind:  js_ast.LocalLet,
				Decls: []js_ast.Decl{{Binding: js_ast.Binding{Loc: , Data: &js_ast.BIdentifier{Ref: }}}},
			}})
		}
	}

	var  js_ast.Expr
"name = enclosing.name || (enclosing.name = {})"
"name || (name = {})"
		 = js_ast.Expr{Loc: , Data: &js_ast.EBinary{
			Op:   js_ast.BinOpLogicalOr,
			Left: js_ast.Expr{Loc: , Data: &js_ast.EIdentifier{Ref: }},
			Right: js_ast.Assign(
				js_ast.Expr{Loc: , Data: &js_ast.EIdentifier{Ref: }},
				js_ast.Expr{Loc: , Data: &js_ast.EObject{}},
			),
		}}
		.recordUsage()
		.recordUsage()
	}
Call the closure with the name object
	 = append(, js_ast.Stmt{Loc: , Data: &js_ast.SExpr{Value: js_ast.Expr{Loc: , Data: &js_ast.ECall{
		Target: js_ast.Expr{Loc: , Data: &js_ast.EFunction{Fn: js_ast.Fn{
			Args: []js_ast.Arg{{Binding: js_ast.Binding{Loc: , Data: &js_ast.BIdentifier{Ref: }}}},
			Body: js_ast.FnBody{Loc: , Stmts: },
		}}},
		Args: []js_ast.Expr{},
	}}}})

	return