Skip to content

Remove ScriptTarget from source affecting options #1205

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 4 additions & 10 deletions internal/api/encoder/encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,11 @@ import (
"gotest.tools/v3/assert"
)

var parseCompilerOptions = core.SourceFileAffectingCompilerOptions{
EmitScriptTarget: core.ScriptTargetLatest,
}

func TestEncodeSourceFile(t *testing.T) {
t.Parallel()
sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{
FileName: "/test.ts",
Path: "/test.ts",
CompilerOptions: parseCompilerOptions,
FileName: "/test.ts",
Path: "/test.ts",
}, "import { bar } from \"bar\";\nexport function foo<T, U>(a: string, b: string): any {}\nfoo();", core.ScriptKindTS)
t.Run("baseline", func(t *testing.T) {
t.Parallel()
Expand All @@ -46,9 +41,8 @@ func BenchmarkEncodeSourceFile(b *testing.B) {
fileContent, err := os.ReadFile(filePath)
assert.NilError(b, err)
sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{
FileName: "/checker.ts",
Path: "/checker.ts",
CompilerOptions: parseCompilerOptions,
FileName: "/checker.ts",
Path: "/checker.ts",
}, string(fileContent), core.ScriptKindTS)

for b.Loop() {
Expand Down
4 changes: 0 additions & 4 deletions internal/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -10053,10 +10053,6 @@ func (node *SourceFile) ParseOptions() SourceFileParseOptions {
return node.parseOptions
}

func (node *SourceFile) LanguageVersion() core.ScriptTarget {
return node.parseOptions.CompilerOptions.EmitScriptTarget
}

func (node *SourceFile) Text() string {
return node.text
}
Expand Down
19 changes: 6 additions & 13 deletions internal/astnav/tokens_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ var testFiles = []string{
filepath.Join(repo.TypeScriptSubmodulePath, "src/services/mapCode.ts"),
}

var parseCompilerOptions = core.SourceFileAffectingCompilerOptions{
EmitScriptTarget: core.ScriptTargetLatest,
}

func TestGetTokenAtPosition(t *testing.T) {
t.Parallel()
repo.SkipIfNoTypeScriptSubmodule(t)
Expand Down Expand Up @@ -57,9 +53,8 @@ func TestGetTokenAtPosition(t *testing.T) {
}
`
file := parser.ParseSourceFile(ast.SourceFileParseOptions{
FileName: "/file.ts",
Path: "/file.ts",
CompilerOptions: parseCompilerOptions,
FileName: "/file.ts",
Path: "/file.ts",
}, fileText, core.ScriptKindTS)
assert.Equal(t, astnav.GetTokenAtPosition(file, 0), astnav.GetTokenAtPosition(file, 0))
})
Expand Down Expand Up @@ -96,9 +91,8 @@ func baselineTokens(t *testing.T, testName string, includeEOF bool, getTSTokens
}
tsTokens := getTSTokens(string(fileText), positions)
file := parser.ParseSourceFile(ast.SourceFileParseOptions{
FileName: "/file.ts",
Path: "/file.ts",
CompilerOptions: parseCompilerOptions,
FileName: "/file.ts",
Path: "/file.ts",
}, string(fileText), core.ScriptKindTS)

var output strings.Builder
Expand Down Expand Up @@ -433,9 +427,8 @@ export function isAnyDirectorySeparator(charCode: number): boolean {
t.Run(testCase.name, func(t *testing.T) {
t.Parallel()
file := parser.ParseSourceFile(ast.SourceFileParseOptions{
FileName: "/file.ts",
Path: "/file.ts",
CompilerOptions: parseCompilerOptions,
FileName: "/file.ts",
Path: "/file.ts",
}, testCase.fileContent, core.ScriptKindTS)
token := astnav.FindPrecedingToken(file, testCase.position)
assert.Equal(t, token.Kind, testCase.expectedKind)
Expand Down
16 changes: 1 addition & 15 deletions internal/binder/binder.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ const (

type Binder struct {
file *ast.SourceFile
languageVersion core.ScriptTarget
bindFunc func(*ast.Node) bool
unreachableFlow *ast.FlowNode
reportedUnreachableFlow *ast.FlowNode
Expand Down Expand Up @@ -121,7 +120,6 @@ func bindSourceFile(file *ast.SourceFile) {
b := getBinder()
defer putBinder(b)
b.file = file
b.languageVersion = b.options().EmitScriptTarget
b.inStrictMode = b.options().BindInStrictMode && !file.IsDeclarationFile || ast.IsExternalModule(file)
b.unreachableFlow = b.newFlowNode(ast.FlowFlagsUnreachable)
b.reportedUnreachableFlow = b.newFlowNode(ast.FlowFlagsUnreachable)
Expand Down Expand Up @@ -1181,7 +1179,6 @@ func (b *Binder) bindParameter(node *ast.Node) {
func (b *Binder) bindFunctionDeclaration(node *ast.Node) {
b.checkStrictModeFunctionName(node)
if b.inStrictMode {
b.checkStrictModeFunctionDeclaration(node)
b.bindBlockScopedDeclaration(node, ast.SymbolFlagsFunction, ast.SymbolFlagsFunctionExcludes)
} else {
b.declareSymbolAndAddToSymbolTable(node, ast.SymbolFlagsFunction, ast.SymbolFlagsFunctionExcludes)
Expand Down Expand Up @@ -1364,17 +1361,6 @@ func (b *Binder) checkStrictModeFunctionName(node *ast.Node) {
}
}

func (b *Binder) checkStrictModeFunctionDeclaration(node *ast.Node) {
if b.languageVersion < core.ScriptTargetES2015 {
// Report error if function is not top level function declaration
if b.blockScopeContainer.Kind != ast.KindSourceFile && b.blockScopeContainer.Kind != ast.KindModuleDeclaration && !ast.IsFunctionLikeOrClassStaticBlockDeclaration(b.blockScopeContainer) {
// We check first if the name is inside class declaration or class expression; if so give explicit message
// otherwise report generic error message.
b.errorOnNode(node, b.getStrictModeBlockScopeFunctionDeclarationMessage(node))
}
}
}

func (b *Binder) getStrictModeBlockScopeFunctionDeclarationMessage(node *ast.Node) *diagnostics.Message {
// Provide specialized messages to help the user understand why we think they're in strict mode.
if ast.GetContainingClass(node) != nil {
Expand Down Expand Up @@ -1443,7 +1429,7 @@ func (b *Binder) checkStrictModeWithStatement(node *ast.Node) {

func (b *Binder) checkStrictModeLabeledStatement(node *ast.Node) {
// Grammar checking for labeledStatement
if b.inStrictMode && b.options().EmitScriptTarget >= core.ScriptTargetES2015 {
if b.inStrictMode {
data := node.AsLabeledStatement()
if ast.IsDeclarationStatement(data.Statement) || ast.IsVariableStatement(data.Statement) {
b.errorOnFirstToken(data.Label, diagnostics.A_label_is_not_allowed_here)
Expand Down
2 changes: 1 addition & 1 deletion internal/checker/jsx.go
Original file line number Diff line number Diff line change
Expand Up @@ -1422,7 +1422,7 @@ func (c *Checker) getJsxFragmentFactoryEntity(location *ast.Node) *ast.EntityNam
}

func (c *Checker) parseIsolatedEntityName(name string) *ast.Node {
result := parser.ParseIsolatedEntityName(name, c.languageVersion)
result := parser.ParseIsolatedEntityName(name)
if result != nil {
markAsSynthetic(result)
}
Expand Down
2 changes: 0 additions & 2 deletions internal/core/compileroptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,6 @@ type SourceFileAffectingCompilerOptions struct {
AllowUnreachableCode Tristate
AllowUnusedLabels Tristate
BindInStrictMode bool
EmitScriptTarget ScriptTarget
ShouldPreserveConstEnums bool
}

Expand All @@ -365,7 +364,6 @@ func (options *CompilerOptions) SourceFileAffecting() SourceFileAffectingCompile
AllowUnreachableCode: options.AllowUnreachableCode,
AllowUnusedLabels: options.AllowUnusedLabels,
BindInStrictMode: options.AlwaysStrict.IsTrue() || options.Strict.IsTrue(),
EmitScriptTarget: options.GetEmitScriptTarget(),
ShouldPreserveConstEnums: options.ShouldPreserveConstEnums(),
}
})
Expand Down
7 changes: 2 additions & 5 deletions internal/execute/tsc.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,8 @@ func fmtMain(sys System, input, output string) ExitStatus {
text := fileContent
pathified := tspath.ToPath(input, sys.GetCurrentDirectory(), true)
sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{
FileName: string(pathified),
Path: pathified,
CompilerOptions: core.SourceFileAffectingCompilerOptions{
EmitScriptTarget: core.ScriptTargetLatest,
},
FileName: string(pathified),
Path: pathified,
JSDocParsingMode: ast.JSDocParsingModeParseAll,
}, text, core.GetScriptKindFromFileName(string(pathified)))
ast.SetParentInChildren(sourceFile.AsNode())
Expand Down
14 changes: 4 additions & 10 deletions internal/format/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ func applyBulkEdits(text string, edits []core.TextChange) string {
return b.String()
}

var parseCompilerOptions = core.SourceFileAffectingCompilerOptions{
EmitScriptTarget: core.ScriptTargetLatest,
}

func TestFormat(t *testing.T) {
t.Parallel()

Expand All @@ -60,9 +56,8 @@ func TestFormat(t *testing.T) {
assert.NilError(t, err)
text := string(fileContent)
sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{
FileName: "/checker.ts",
Path: "/checker.ts",
CompilerOptions: parseCompilerOptions,
FileName: "/checker.ts",
Path: "/checker.ts",
}, text, core.ScriptKindTS)
ast.SetParentInChildren(sourceFile.AsNode())
edits := format.FormatDocument(ctx, sourceFile)
Expand Down Expand Up @@ -91,9 +86,8 @@ func BenchmarkFormat(b *testing.B) {
assert.NilError(b, err)
text := string(fileContent)
sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{
FileName: "/checker.ts",
Path: "/checker.ts",
CompilerOptions: parseCompilerOptions,
FileName: "/checker.ts",
Path: "/checker.ts",
}, text, core.ScriptKindTS)
ast.SetParentInChildren(sourceFile.AsNode())

Expand Down
6 changes: 1 addition & 5 deletions internal/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,13 +175,10 @@ func (p *Parser) parseJSONText() *ast.SourceFile {
return result
}

func ParseIsolatedEntityName(text string, languageVersion core.ScriptTarget) *ast.EntityName {
func ParseIsolatedEntityName(text string) *ast.EntityName {
p := getParser()
defer putParser(p)
p.initializeState(ast.SourceFileParseOptions{
CompilerOptions: core.SourceFileAffectingCompilerOptions{
EmitScriptTarget: languageVersion,
},
JSDocParsingMode: ast.JSDocParsingModeParseAll,
}, text, core.ScriptKindJS)
p.nextToken()
Expand Down Expand Up @@ -213,7 +210,6 @@ func (p *Parser) initializeState(opts ast.SourceFileParseOptions, sourceText str
}
p.scanner.SetText(p.sourceText)
p.scanner.SetOnError(p.scanError)
p.scanner.SetScriptTarget(p.opts.CompilerOptions.EmitScriptTarget)
p.scanner.SetLanguageVariant(p.languageVariant)
p.scanner.SetScriptKind(p.scriptKind)
p.scanner.SetJSDocParsingMode(p.opts.JSDocParsingMode)
Expand Down
14 changes: 4 additions & 10 deletions internal/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,8 @@ func BenchmarkParse(b *testing.B) {
jsdocMode := jsdoc.mode

opts := ast.SourceFileParseOptions{
FileName: fileName,
Path: path,
CompilerOptions: core.SourceFileAffectingCompilerOptions{
EmitScriptTarget: core.ScriptTargetESNext,
},
FileName: fileName,
Path: path,
JSDocParsingMode: jsdocMode,
}

Expand Down Expand Up @@ -138,11 +135,8 @@ func FuzzParser(f *testing.F) {
path := tspath.Path(fileName)

opts := ast.SourceFileParseOptions{
FileName: fileName,
Path: path,
CompilerOptions: core.SourceFileAffectingCompilerOptions{
EmitScriptTarget: scriptTarget,
},
FileName: fileName,
Path: path,
JSDocParsingMode: jsdocParsingMode,
}

Expand Down
9 changes: 4 additions & 5 deletions internal/printer/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -844,10 +844,9 @@ func (p *Printer) shouldAllowTrailingComma(node *ast.Node, list *ast.NodeList) b
return false
}

target := p.currentSourceFile.LanguageVersion()
switch node.Kind {
case ast.KindObjectLiteralExpression:
return target >= core.ScriptTargetES5
return true
case ast.KindArrayLiteralExpression,
ast.KindArrowFunction,
ast.KindConstructor,
Expand All @@ -874,11 +873,11 @@ func (p *Printer) shouldAllowTrailingComma(node *ast.Node, list *ast.NodeList) b
case ast.KindFunctionDeclaration,
ast.KindFunctionExpression,
ast.KindMethodDeclaration:
return target >= core.ScriptTargetES2015 || list == node.FunctionLikeData().TypeParameters
return true
case ast.KindCallExpression:
return target >= core.ScriptTargetES2015 || list == node.AsCallExpression().TypeArguments
return true
case ast.KindNewExpression:
return target >= core.ScriptTargetES2015 || list == node.AsNewExpression().TypeArguments
return true
}

return false
Expand Down
11 changes: 2 additions & 9 deletions internal/scanner/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,7 @@ type ScannerState struct {
}

type Scanner struct {
text string
// TODO: remove this? unused except for (unimplemented) regex checking
languageVersion core.ScriptTarget
text string
languageVariant core.LanguageVariant
onError ErrorCallback
skipTrivia bool
Expand All @@ -222,7 +220,7 @@ func defaultScanner() Scanner {
// Using a function rather than a global is intentional; this function is
// inlined as pure code (zeroing + moves), whereas a global requires write
// barriers since the memory is mutable.
return Scanner{languageVersion: core.ScriptTargetLatest, skipTrivia: true}
return Scanner{skipTrivia: true}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I make skipTrivia a method, then flip the default, then we can also reset scanners with zeroing, which would be amazing.

}

func NewScanner() *Scanner {
Expand Down Expand Up @@ -339,10 +337,6 @@ func (s *Scanner) SetOnError(errorCallback ErrorCallback) {
s.onError = errorCallback
}

func (s *Scanner) SetScriptTarget(scriptTarget core.ScriptTarget) {
s.languageVersion = scriptTarget
}

func (s *Scanner) SetScriptKind(scriptKind core.ScriptKind) {
s.scriptKind = scriptKind
}
Expand Down Expand Up @@ -2237,7 +2231,6 @@ func GetScannerForSourceFile(sourceFile *ast.SourceFile, pos int) *Scanner {
s := NewScanner()
s.text = sourceFile.Text()
s.pos = pos
s.languageVersion = sourceFile.LanguageVersion()
s.languageVariant = sourceFile.LanguageVariant
s.Scan()
return s
Expand Down
5 changes: 0 additions & 5 deletions internal/testutil/parsetestutil/parsetestutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,12 @@ import (
"github.com/microsoft/typescript-go/internal/tspath"
)

var parseCompilerOptions = core.SourceFileAffectingCompilerOptions{
EmitScriptTarget: core.ScriptTargetLatest,
}

// Simplifies parsing an input string into a SourceFile for testing purposes.
func ParseTypeScript(text string, jsx bool) *ast.SourceFile {
fileName := core.IfElse(jsx, "/main.tsx", "/main.ts")
file := parser.ParseSourceFile(ast.SourceFileParseOptions{
FileName: fileName,
Path: tspath.Path(fileName),
CompilerOptions: parseCompilerOptions,
JSDocParsingMode: ast.JSDocParsingModeParseNone,
}, text, core.GetScriptKindFromFileName(fileName))
ast.SetParentInChildren(file.AsNode())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
blockScopedFunctionDeclarationInStrictClass.ts(4,22): error TS1251: Function declarations are not allowed inside blocks in strict mode when targeting 'ES5'. Class definitions are automatically in strict mode.
blockScopedFunctionDeclarationInStrictClass.ts(7,9): error TS2304: Cannot find name 'foo'.


==== blockScopedFunctionDeclarationInStrictClass.ts (2 errors) ====
==== blockScopedFunctionDeclarationInStrictClass.ts (1 errors) ====
class c {
method() {
if (true) {
function foo() { }
~~~
!!! error TS1251: Function declarations are not allowed inside blocks in strict mode when targeting 'ES5'. Class definitions are automatically in strict mode.
foo(); // ok
}
foo(); // not ok
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--- old.blockScopedFunctionDeclarationInStrictClass.errors.txt
+++ new.blockScopedFunctionDeclarationInStrictClass.errors.txt
@@= skipped -0, +0 lines =@@
-blockScopedFunctionDeclarationInStrictClass.ts(4,22): error TS1251: Function declarations are not allowed inside blocks in strict mode when targeting 'ES5'. Class definitions are automatically in strict mode.
blockScopedFunctionDeclarationInStrictClass.ts(7,9): error TS2304: Cannot find name 'foo'.


-==== blockScopedFunctionDeclarationInStrictClass.ts (2 errors) ====
+==== blockScopedFunctionDeclarationInStrictClass.ts (1 errors) ====
class c {
method() {
if (true) {
function foo() { }
- ~~~
-!!! error TS1251: Function declarations are not allowed inside blocks in strict mode when targeting 'ES5'. Class definitions are automatically in strict mode.
foo(); // ok
}
foo(); // not ok
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
blockScopedFunctionDeclarationInStrictModule.ts(2,14): error TS1252: Function declarations are not allowed inside blocks in strict mode when targeting 'ES5'. Modules are automatically in strict mode.
blockScopedFunctionDeclarationInStrictModule.ts(6,10): error TS2304: Cannot find name 'foo'.


==== blockScopedFunctionDeclarationInStrictModule.ts (2 errors) ====
==== blockScopedFunctionDeclarationInStrictModule.ts (1 errors) ====
if (true) {
function foo() { }
~~~
!!! error TS1252: Function declarations are not allowed inside blocks in strict mode when targeting 'ES5'. Modules are automatically in strict mode.
foo(); // ok
}

Expand Down
Loading