Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
14e7b32
Create SourceFileParseOptions
jakebailey Jun 10, 2025
db149ad
Fix parsing mode
jakebailey Jun 10, 2025
d8c50f8
Script kind maybe
jakebailey Jun 10, 2025
b795913
partial
jakebailey Jun 10, 2025
10aa6ee
Missed one
jakebailey Jun 10, 2025
73ec3d9
Consolidate JSON parsing
jakebailey Jun 10, 2025
adfea3b
Tweak test
jakebailey Jun 10, 2025
c6b2b07
Binder doesn't need options anymore
jakebailey Jun 10, 2025
c3144c4
lint
jakebailey Jun 10, 2025
12f1795
Don't set ExternalModuleIndicator on JSON files
jakebailey Jun 10, 2025
a127ce6
Refactor a bit
jakebailey Jun 10, 2025
251e04a
Fix generator
jakebailey Jun 10, 2025
4cb0223
Remove TODOs
jakebailey Jun 10, 2025
a9bf41c
Shift code around, remove dead
jakebailey Jun 10, 2025
636eaf0
fmt
jakebailey Jun 11, 2025
b786e30
Merge branch 'main' into jabaile/external-module-indicator-parse-options
jakebailey Jun 11, 2025
f647de4
Merge branch 'main' into jabaile/external-module-indicator-parse-options
jakebailey Jun 16, 2025
17da1a7
Merge branch 'main' into jabaile/external-module-indicator-parse-options
jakebailey Jun 16, 2025
645fa76
value type
jakebailey Jun 16, 2025
60f6c21
Shift everything around a bunch, new finer grained key
jakebailey Jun 17, 2025
7783c4a
TODOs
jakebailey Jun 17, 2025
64ec265
Merge branch 'main' into jabaile/external-module-indicator-parse-options
jakebailey Jun 17, 2025
bc84ad6
Condense key down even more, awesome
jakebailey Jun 17, 2025
02183a2
No source file affecting for declaration files, amazing
jakebailey Jun 17, 2025
fa9628c
Move code around
jakebailey Jun 17, 2025
f7e3067
fmt
jakebailey Jun 17, 2025
9f01650
move again
jakebailey Jun 17, 2025
64249aa
Restore fileName for debugging
jakebailey Jun 17, 2025
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
22 changes: 11 additions & 11 deletions internal/api/encoder/encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,21 @@ import (
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/parser"
"github.com/microsoft/typescript-go/internal/repo"
"github.com/microsoft/typescript-go/internal/scanner"
"github.com/microsoft/typescript-go/internal/testutil/baseline"
"gotest.tools/v3/assert"
)

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

func TestEncodeSourceFile(t *testing.T) {
t.Parallel()
sourceFile := parser.ParseSourceFile("/test.ts", "/test.ts", "import { bar } from \"bar\";\nexport function foo<T, U>(a: string, b: string): any {}\nfoo();", parseCompilerOptions, nil, scanner.JSDocParsingModeParseAll)
sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{
FileName: "/test.ts",
Path: "/test.ts",
CompilerOptions: parseCompilerOptions,
}, "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()
buf, err := encoder.EncodeSourceFile(sourceFile, "")
Expand All @@ -42,14 +45,11 @@ func BenchmarkEncodeSourceFile(b *testing.B) {
filePath := filepath.Join(repo.TypeScriptSubmodulePath, "src/compiler/checker.ts")
fileContent, err := os.ReadFile(filePath)
assert.NilError(b, err)
sourceFile := parser.ParseSourceFile(
"/checker.ts",
"/checker.ts",
string(fileContent),
parseCompilerOptions,
nil,
scanner.JSDocParsingModeParseAll,
)
sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{
FileName: "/checker.ts",
Path: "/checker.ts",
CompilerOptions: parseCompilerOptions,
}, string(fileContent), core.ScriptKindTS)

for b.Loop() {
_, err := encoder.EncodeSourceFile(sourceFile, "")
Expand Down
59 changes: 40 additions & 19 deletions internal/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -9955,6 +9955,23 @@ type CommentDirective struct {

// SourceFile

type JSDocParsingMode int

const (
JSDocParsingModeParseAll JSDocParsingMode = iota
JSDocParsingModeParseNone
JSDocParsingModeParseForTypeErrors
JSDocParsingModeParseForTypeInfo
)

type SourceFileParseOptions struct {
FileName string
Path tspath.Path
CompilerOptions core.SourceFileAffectingCompilerOptions
Metadata SourceFileMetaData
JSDocParsingMode JSDocParsingMode
}

type SourceFileMetaData struct {
PackageJsonType string
PackageJsonDirectory string
Expand All @@ -9978,17 +9995,13 @@ type SourceFile struct {
compositeNodeBase

// Fields set by NewSourceFile

text string
fileName string
path tspath.Path
Statements *NodeList // NodeList[*Statement]
parseOptions SourceFileParseOptions
text string
Statements *NodeList // NodeList[*Statement]

// Fields set by parser

diagnostics []*Diagnostic
jsdocDiagnostics []*Diagnostic
LanguageVersion core.ScriptTarget
LanguageVariant core.LanguageVariant
ScriptKind core.ScriptKind
IsDeclarationFile bool
Expand Down Expand Up @@ -10035,30 +10048,39 @@ type SourceFile struct {
JSGlobalAugmentations SymbolTable // !!! remove me
}

func (f *NodeFactory) NewSourceFile(text string, fileName string, path tspath.Path, statements *NodeList) *Node {
if (tspath.GetEncodedRootLength(fileName) == 0 && !strings.HasPrefix(fileName, "^/")) || fileName != tspath.NormalizePath(fileName) {
panic(fmt.Sprintf("fileName should be normalized and absolute: %q", fileName))
func (f *NodeFactory) NewSourceFile(opts SourceFileParseOptions, text string, statements *NodeList) *Node {
if (tspath.GetEncodedRootLength(opts.FileName) == 0 && !strings.HasPrefix(opts.FileName, "^/")) || opts.FileName != tspath.NormalizePath(opts.FileName) {
panic(fmt.Sprintf("fileName should be normalized and absolute: %q", opts.FileName))
}

data := &SourceFile{}
data.parseOptions = opts
data.text = text
data.fileName = fileName
data.path = path
data.Statements = statements
data.LanguageVersion = core.ScriptTargetLatest
return f.newNode(KindSourceFile, data)
}

func (node *SourceFile) ParseOptions() SourceFileParseOptions {
return node.parseOptions
}

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

func (node *SourceFile) Metadata() SourceFileMetaData {
return node.parseOptions.Metadata
}

func (node *SourceFile) Text() string {
return node.text
}

func (node *SourceFile) FileName() string {
return node.fileName
return node.parseOptions.FileName
}

func (node *SourceFile) Path() tspath.Path {
return node.path
return node.parseOptions.Path
}

func (node *SourceFile) OriginalFileName() string {
Expand Down Expand Up @@ -10115,7 +10137,6 @@ func (node *SourceFile) IsJS() bool {

func (node *SourceFile) copyFrom(other *SourceFile) {
// Do not copy fields set by NewSourceFile (Text, FileName, Path, or Statements)
node.LanguageVersion = other.LanguageVersion
node.LanguageVariant = other.LanguageVariant
node.ScriptKind = other.ScriptKind
node.IsDeclarationFile = other.IsDeclarationFile
Expand All @@ -10137,7 +10158,7 @@ func (node *SourceFile) copyFrom(other *SourceFile) {
}

func (node *SourceFile) Clone(f NodeFactoryCoercible) *Node {
updated := f.AsNodeFactory().NewSourceFile(node.Text(), node.FileName(), node.Path(), node.Statements)
updated := f.AsNodeFactory().NewSourceFile(node.parseOptions, node.text, node.Statements)
newFile := updated.AsSourceFile()
newFile.copyFrom(node)
return cloneNode(updated, node.AsNode(), f.AsNodeFactory().hooks)
Expand All @@ -10149,7 +10170,7 @@ func (node *SourceFile) computeSubtreeFacts() SubtreeFacts {

func (f *NodeFactory) UpdateSourceFile(node *SourceFile, statements *StatementList) *Node {
if statements != node.Statements {
updated := f.NewSourceFile(node.Text(), node.fileName, node.path, statements).AsSourceFile()
updated := f.NewSourceFile(node.parseOptions, node.text, statements).AsSourceFile()
updated.copyFrom(node)
return updateNode(updated.AsNode(), node.AsNode(), f.hooks)
}
Expand Down
11 changes: 4 additions & 7 deletions internal/ast/utilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -2523,27 +2523,24 @@ func GetImpliedNodeFormatForFile(path string, packageJsonType string) core.Modul
return impliedNodeFormat
}

func GetEmitModuleFormatOfFileWorker(fileName string, options *core.CompilerOptions, sourceFileMetaData *SourceFileMetaData) core.ModuleKind {
func GetEmitModuleFormatOfFileWorker(fileName string, options *core.CompilerOptions, sourceFileMetaData SourceFileMetaData) core.ModuleKind {
result := GetImpliedNodeFormatForEmitWorker(fileName, options.GetEmitModuleKind(), sourceFileMetaData)
if result != core.ModuleKindNone {
return result
}
return options.GetEmitModuleKind()
}

func GetImpliedNodeFormatForEmitWorker(fileName string, emitModuleKind core.ModuleKind, sourceFileMetaData *SourceFileMetaData) core.ResolutionMode {
func GetImpliedNodeFormatForEmitWorker(fileName string, emitModuleKind core.ModuleKind, sourceFileMetaData SourceFileMetaData) core.ResolutionMode {
if core.ModuleKindNode16 <= emitModuleKind && emitModuleKind <= core.ModuleKindNodeNext {
if sourceFileMetaData == nil {
return core.ModuleKindNone
}
return sourceFileMetaData.ImpliedNodeFormat
}
if sourceFileMetaData != nil && sourceFileMetaData.ImpliedNodeFormat == core.ModuleKindCommonJS &&
if sourceFileMetaData.ImpliedNodeFormat == core.ModuleKindCommonJS &&
(sourceFileMetaData.PackageJsonType == "commonjs" ||
tspath.FileExtensionIsOneOf(fileName, []string{tspath.ExtensionCjs, tspath.ExtensionCts})) {
return core.ModuleKindCommonJS
}
if sourceFileMetaData != nil && sourceFileMetaData.ImpliedNodeFormat == core.ModuleKindESNext &&
if sourceFileMetaData.ImpliedNodeFormat == core.ModuleKindESNext &&
(sourceFileMetaData.PackageJsonType == "module" ||
tspath.FileExtensionIsOneOf(fileName, []string{tspath.ExtensionMjs, tspath.ExtensionMts})) {
return core.ModuleKindESNext
Expand Down
21 changes: 16 additions & 5 deletions internal/astnav/tokens_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/parser"
"github.com/microsoft/typescript-go/internal/repo"
"github.com/microsoft/typescript-go/internal/scanner"
"github.com/microsoft/typescript-go/internal/testutil/baseline"
"github.com/microsoft/typescript-go/internal/testutil/jstest"
"gotest.tools/v3/assert"
Expand All @@ -26,7 +25,7 @@ var testFiles = []string{
filepath.Join(repo.TypeScriptSubmodulePath, "src/services/mapCode.ts"),
}

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

Expand Down Expand Up @@ -57,7 +56,11 @@ func TestGetTokenAtPosition(t *testing.T) {
return 0;
}
`
file := parser.ParseSourceFile("/file.ts", "/file.ts", fileText, parseCompilerOptions, nil, scanner.JSDocParsingModeParseAll)
file := parser.ParseSourceFile(ast.SourceFileParseOptions{
FileName: "/file.ts",
Path: "/file.ts",
CompilerOptions: parseCompilerOptions,
}, fileText, core.ScriptKindTS)
assert.Equal(t, astnav.GetTokenAtPosition(file, 0), astnav.GetTokenAtPosition(file, 0))
})
}
Expand Down Expand Up @@ -92,7 +95,11 @@ func baselineTokens(t *testing.T, testName string, includeEOF bool, getTSTokens
positions[i] = i
}
tsTokens := getTSTokens(string(fileText), positions)
file := parser.ParseSourceFile("/file.ts", "/file.ts", string(fileText), parseCompilerOptions, nil, scanner.JSDocParsingModeParseAll)
file := parser.ParseSourceFile(ast.SourceFileParseOptions{
FileName: "/file.ts",
Path: "/file.ts",
CompilerOptions: parseCompilerOptions,
}, string(fileText), core.ScriptKindTS)

var output strings.Builder
currentRange := core.NewTextRange(0, 0)
Expand Down Expand Up @@ -425,7 +432,11 @@ export function isAnyDirectorySeparator(charCode: number): boolean {
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
t.Parallel()
file := parser.ParseSourceFile("/file.ts", "/file.ts", testCase.fileContent, parseCompilerOptions, nil, scanner.JSDocParsingModeParseAll)
file := parser.ParseSourceFile(ast.SourceFileParseOptions{
FileName: "/file.ts",
Path: "/file.ts",
CompilerOptions: parseCompilerOptions,
}, testCase.fileContent, core.ScriptKindTS)
token := astnav.FindPrecedingToken(file, testCase.position)
assert.Equal(t, token.Kind, testCase.expectedKind)
})
Expand Down
14 changes: 12 additions & 2 deletions internal/binder/binder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"github.com/microsoft/typescript-go/internal/ast"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/parser"
"github.com/microsoft/typescript-go/internal/scanner"
"github.com/microsoft/typescript-go/internal/testutil/fixtures"
"github.com/microsoft/typescript-go/internal/tspath"
"github.com/microsoft/typescript-go/internal/vfs/osvfs"
Expand All @@ -25,9 +24,20 @@ func BenchmarkBind(b *testing.B) {
compilerOptions := &core.CompilerOptions{Target: core.ScriptTargetESNext, Module: core.ModuleKindNodeNext}
sourceAffecting := compilerOptions.SourceFileAffecting()

parseOptions := ast.SourceFileParseOptions{
FileName: fileName,
Path: path,
CompilerOptions: core.SourceFileAffectingCompilerOptions{
EmitScriptTarget: compilerOptions.Target,
EmitModuleKind: compilerOptions.Module,
},
JSDocParsingMode: ast.JSDocParsingModeParseAll,
}
scriptKind := core.GetScriptKindFromFileName(fileName)

sourceFiles := make([]*ast.SourceFile, b.N)
for i := range b.N {
sourceFiles[i] = parser.ParseSourceFile(fileName, path, sourceText, sourceAffecting, nil, scanner.JSDocParsingModeParseAll)
sourceFiles[i] = parser.ParseSourceFile(parseOptions, sourceText, scriptKind)
}

// The above parses do a lot of work; ensure GC is finished before we start collecting performance data.
Expand Down
15 changes: 7 additions & 8 deletions internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -529,12 +529,11 @@ type Program interface {
FileExists(fileName string) bool
GetSourceFile(fileName string) *ast.SourceFile
GetSourceFileForResolvedModule(fileName string) *ast.SourceFile
GetEmitModuleFormatOfFile(sourceFile ast.HasFileName) core.ModuleKind
GetEmitSyntaxForUsageLocation(sourceFile ast.HasFileName, usageLocation *ast.StringLiteralLike) core.ResolutionMode
GetImpliedNodeFormatForEmit(sourceFile ast.HasFileName) core.ModuleKind
GetResolvedModule(currentSourceFile ast.HasFileName, moduleReference string, mode core.ResolutionMode) *module.ResolvedModule
GetEmitModuleFormatOfFile(sourceFile *ast.SourceFile) core.ModuleKind
GetEmitSyntaxForUsageLocation(sourceFile *ast.SourceFile, usageLocation *ast.StringLiteralLike) core.ResolutionMode
GetImpliedNodeFormatForEmit(sourceFile *ast.SourceFile) core.ModuleKind
GetResolvedModule(currentSourceFile *ast.SourceFile, moduleReference string, mode core.ResolutionMode) *module.ResolvedModule
GetResolvedModules() map[tspath.Path]module.ModeAwareCache[*module.ResolvedModule]
GetSourceFileMetaData(path tspath.Path) *ast.SourceFileMetaData
GetJSXRuntimeImportSpecifier(path tspath.Path) (moduleReference string, specifier *ast.Node)
GetImportHelpersImportSpecifier(path tspath.Path) *ast.Node
IsSourceFromProjectReference(path tspath.Path) bool
Expand Down Expand Up @@ -10256,8 +10255,8 @@ func (c *Checker) checkNewTargetMetaProperty(node *ast.Node) *Type {

func (c *Checker) checkImportMetaProperty(node *ast.Node) *Type {
if core.ModuleKindNode16 <= c.moduleKind && c.moduleKind <= core.ModuleKindNodeNext {
sourceFileMetaData := c.program.GetSourceFileMetaData(ast.GetSourceFileOfNode(node).Path())
if sourceFileMetaData == nil || sourceFileMetaData.ImpliedNodeFormat != core.ModuleKindESNext {
sourceFileMetaData := ast.GetSourceFileOfNode(node).Metadata()
if sourceFileMetaData.ImpliedNodeFormat != core.ModuleKindESNext {
c.error(node, diagnostics.The_import_meta_meta_property_is_not_allowed_in_files_which_will_build_into_CommonJS_output)
}
} else if c.moduleKind < core.ModuleKindES2020 && c.moduleKind != core.ModuleKindSystem {
Expand Down Expand Up @@ -14699,7 +14698,7 @@ func (c *Checker) createModuleNotFoundChain(resolvedModule *module.ResolvedModul
func (c *Checker) createModeMismatchDetails(sourceFile *ast.SourceFile, errorNode *ast.Node) *ast.Diagnostic {
ext := tspath.TryGetExtensionFromPath(sourceFile.FileName())
targetExt := core.IfElse(ext == tspath.ExtensionTs, tspath.ExtensionMts, core.IfElse(ext == tspath.ExtensionJs, tspath.ExtensionMjs, ""))
meta := c.program.GetSourceFileMetaData(sourceFile.Path())
meta := sourceFile.Metadata()
packageJsonType := meta.PackageJsonType
packageJsonDirectory := meta.PackageJsonDirectory
var result *ast.Diagnostic
Expand Down
8 changes: 4 additions & 4 deletions internal/checker/grammarchecks.go
Original file line number Diff line number Diff line change
Expand Up @@ -1226,8 +1226,8 @@ func (c *Checker) checkGrammarForInOrForOfStatement(forInOrOfStatement *ast.ForI
}
switch c.moduleKind {
case core.ModuleKindNode16, core.ModuleKindNode18, core.ModuleKindNodeNext:
sourceFileMetaData := c.program.GetSourceFileMetaData(sourceFile.Path())
if sourceFileMetaData != nil && sourceFileMetaData.ImpliedNodeFormat == core.ModuleKindCommonJS {
sourceFileMetaData := sourceFile.Metadata()
if sourceFileMetaData.ImpliedNodeFormat == core.ModuleKindCommonJS {
c.diagnostics.Add(createDiagnosticForNode(forInOrOfStatement.AwaitModifier, diagnostics.The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level))
break
}
Expand Down Expand Up @@ -1733,8 +1733,8 @@ func (c *Checker) checkGrammarAwaitOrAwaitUsing(node *ast.Node) bool {
case core.ModuleKindNode16,
core.ModuleKindNode18,
core.ModuleKindNodeNext:
sourceFileMetaData := c.program.GetSourceFileMetaData(sourceFile.Path())
if sourceFileMetaData != nil && sourceFileMetaData.ImpliedNodeFormat == core.ModuleKindCommonJS {
sourceFileMetaData := sourceFile.Metadata()
if sourceFileMetaData.ImpliedNodeFormat == core.ModuleKindCommonJS {
if !spanCalculated {
span = scanner.GetRangeOfTokenAtPosition(sourceFile, node.Pos())
}
Expand Down
8 changes: 4 additions & 4 deletions internal/compiler/emitHost.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,19 @@ type emitHost struct {
program *Program
}

func (host *emitHost) GetModeForUsageLocation(file ast.HasFileName, moduleSpecifier *ast.StringLiteralLike) core.ResolutionMode {
func (host *emitHost) GetModeForUsageLocation(file *ast.SourceFile, moduleSpecifier *ast.StringLiteralLike) core.ResolutionMode {
return host.program.GetModeForUsageLocation(file, moduleSpecifier)
}

func (host *emitHost) GetResolvedModuleFromModuleSpecifier(file ast.HasFileName, moduleSpecifier *ast.StringLiteralLike) *module.ResolvedModule {
func (host *emitHost) GetResolvedModuleFromModuleSpecifier(file *ast.SourceFile, moduleSpecifier *ast.StringLiteralLike) *module.ResolvedModule {
return host.program.GetResolvedModuleFromModuleSpecifier(file, moduleSpecifier)
}

func (host *emitHost) GetDefaultResolutionModeForFile(file ast.HasFileName) core.ResolutionMode {
func (host *emitHost) GetDefaultResolutionModeForFile(file *ast.SourceFile) core.ResolutionMode {
return host.program.GetDefaultResolutionModeForFile(file)
}

func (host *emitHost) GetEmitModuleFormatOfFile(file ast.HasFileName) core.ModuleKind {
func (host *emitHost) GetEmitModuleFormatOfFile(file *ast.SourceFile) core.ModuleKind {
return host.program.GetEmitModuleFormatOfFile(file)
}

Expand Down
Loading
Loading