diff --git a/internal/api/encoder/encoder_test.go b/internal/api/encoder/encoder_test.go index d72fafe5ae..95459fbefa 100644 --- a/internal/api/encoder/encoder_test.go +++ b/internal/api/encoder/encoder_test.go @@ -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(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(a: string, b: string): any {}\nfoo();", core.ScriptKindTS) t.Run("baseline", func(t *testing.T) { t.Parallel() buf, err := encoder.EncodeSourceFile(sourceFile, "") @@ -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, "") diff --git a/internal/ast/ast.go b/internal/ast/ast.go index ddd62ebed4..58205a3135 100644 --- a/internal/ast/ast.go +++ b/internal/ast/ast.go @@ -9985,17 +9985,14 @@ type SourceFile struct { compositeNodeBase // Fields set by NewSourceFile - - text string - fileName string - path tspath.Path - Statements *NodeList // NodeList[*Statement] + fileName string // For debugging convenience + 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 @@ -10040,30 +10037,36 @@ type SourceFile struct { tokenCache map[core.TextRange]*Node } -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.fileName = opts.FileName + 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) 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 { @@ -10120,7 +10123,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 @@ -10141,7 +10143,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) @@ -10153,7 +10155,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) } diff --git a/internal/ast/parseoptions.go b/internal/ast/parseoptions.go new file mode 100644 index 0000000000..465728e64a --- /dev/null +++ b/internal/ast/parseoptions.go @@ -0,0 +1,162 @@ +package ast + +import ( + "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/tspath" +) + +type JSDocParsingMode int + +const ( + JSDocParsingModeParseAll JSDocParsingMode = iota + JSDocParsingModeParseNone + JSDocParsingModeParseForTypeErrors + JSDocParsingModeParseForTypeInfo +) + +type SourceFileParseOptions struct { + FileName string + Path tspath.Path + CompilerOptions core.SourceFileAffectingCompilerOptions + ExternalModuleIndicatorOptions ExternalModuleIndicatorOptions + JSDocParsingMode JSDocParsingMode +} + +func GetSourceFileAffectingCompilerOptions(fileName string, options *core.CompilerOptions) core.SourceFileAffectingCompilerOptions { + // Declaration files are not parsed/bound differently depending on compiler options. + if tspath.IsDeclarationFileName(fileName) { + return core.SourceFileAffectingCompilerOptions{} + } + return options.SourceFileAffecting() +} + +type ExternalModuleIndicatorOptions struct { + jsx bool + force bool +} + +func GetExternalModuleIndicatorOptions(fileName string, options *core.CompilerOptions, metadata SourceFileMetaData) ExternalModuleIndicatorOptions { + if tspath.IsDeclarationFileName(fileName) { + return ExternalModuleIndicatorOptions{} + } + + switch options.GetEmitModuleDetectionKind() { + case core.ModuleDetectionKindForce: + // All non-declaration files are modules, declaration files still do the usual isFileProbablyExternalModule + return ExternalModuleIndicatorOptions{force: true} + case core.ModuleDetectionKindLegacy: + // Files are modules if they have imports, exports, or import.meta + return ExternalModuleIndicatorOptions{} + case core.ModuleDetectionKindAuto: + // If module is nodenext or node16, all esm format files are modules + // If jsx is react-jsx or react-jsxdev then jsx tags force module-ness + // otherwise, the presence of import or export statments (or import.meta) implies module-ness + return ExternalModuleIndicatorOptions{ + jsx: options.Jsx == core.JsxEmitReactJSX || options.Jsx == core.JsxEmitReactJSXDev, + force: isFileForcedToBeModuleByFormat(fileName, options, metadata), + } + default: + return ExternalModuleIndicatorOptions{} + } +} + +var isFileForcedToBeModuleByFormatExtensions = []string{tspath.ExtensionCjs, tspath.ExtensionCts, tspath.ExtensionMjs, tspath.ExtensionMts} + +func isFileForcedToBeModuleByFormat(fileName string, options *core.CompilerOptions, metadata SourceFileMetaData) bool { + // Excludes declaration files - they still require an explicit `export {}` or the like + // for back compat purposes. The only non-declaration files _not_ forced to be a module are `.js` files + // that aren't esm-mode (meaning not in a `type: module` scope). + if GetImpliedNodeFormatForEmitWorker(fileName, options.GetEmitModuleKind(), metadata) == core.ModuleKindESNext || tspath.FileExtensionIsOneOf(fileName, isFileForcedToBeModuleByFormatExtensions) { + return true + } + return false +} + +func SetExternalModuleIndicator(file *SourceFile, opts ExternalModuleIndicatorOptions) { + file.ExternalModuleIndicator = getExternalModuleIndicator(file, opts) +} + +func getExternalModuleIndicator(file *SourceFile, opts ExternalModuleIndicatorOptions) *Node { + if file.ScriptKind == core.ScriptKindJSON { + return nil + } + + if node := isFileProbablyExternalModule(file); node != nil { + return node + } + + if file.IsDeclarationFile { + return nil + } + + if opts.jsx { + if node := isFileModuleFromUsingJSXTag(file); node != nil { + return node + } + } + + if opts.force { + return file.AsNode() + } + + return nil +} + +func isFileProbablyExternalModule(sourceFile *SourceFile) *Node { + for _, statement := range sourceFile.Statements.Nodes { + if IsExternalModuleIndicator(statement) { + return statement + } + } + return getImportMetaIfNecessary(sourceFile) +} + +func getImportMetaIfNecessary(sourceFile *SourceFile) *Node { + if sourceFile.AsNode().Flags&NodeFlagsPossiblyContainsImportMeta != 0 { + return findChildNode(sourceFile.AsNode(), IsImportMeta) + } + return nil +} + +func findChildNode(root *Node, check func(*Node) bool) *Node { + var result *Node + var visit func(*Node) bool + visit = func(node *Node) bool { + if check(node) { + result = node + return true + } + return node.ForEachChild(visit) + } + visit(root) + return result +} + +func isFileModuleFromUsingJSXTag(file *SourceFile) *Node { + return walkTreeForJSXTags(file.AsNode()) +} + +// This is a somewhat unavoidable full tree walk to locate a JSX tag - `import.meta` requires the same, +// but we avoid that walk (or parts of it) if at all possible using the `PossiblyContainsImportMeta` node flag. +// Unfortunately, there's no `NodeFlag` space to do the same for JSX. +func walkTreeForJSXTags(node *Node) *Node { + var found *Node + + var visitor func(node *Node) bool + visitor = func(node *Node) bool { + if found != nil { + return true + } + if node.SubtreeFacts()&SubtreeContainsJsx == 0 { + return false + } + if IsJsxOpeningElement(node) || IsJsxFragment(node) { + found = node + return true + } + return node.ForEachChild(visitor) + } + visitor(node) + + return found +} diff --git a/internal/ast/utilities.go b/internal/ast/utilities.go index 946979917e..ea3fef8edc 100644 --- a/internal/ast/utilities.go +++ b/internal/ast/utilities.go @@ -2549,7 +2549,7 @@ 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 @@ -2557,19 +2557,16 @@ func GetEmitModuleFormatOfFileWorker(fileName string, options *core.CompilerOpti 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 @@ -2899,15 +2896,6 @@ func GetClassLikeDeclarationOfSymbol(symbol *Symbol) *Node { return core.Find(symbol.Declarations, IsClassLike) } -func GetLanguageVariant(scriptKind core.ScriptKind) core.LanguageVariant { - switch scriptKind { - case core.ScriptKindTSX, core.ScriptKindJSX, core.ScriptKindJS, core.ScriptKindJSON: - // .tsx and .jsx files are treated as jsx language variant. - return core.LanguageVariantJSX - } - return core.LanguageVariantStandard -} - func IsCallLikeExpression(node *Node) bool { switch node.Kind { case KindJsxOpeningElement, KindJsxSelfClosingElement, KindJsxOpeningFragment, KindCallExpression, KindNewExpression, diff --git a/internal/astnav/tokens_test.go b/internal/astnav/tokens_test.go index 208b137d60..30f425c080 100644 --- a/internal/astnav/tokens_test.go +++ b/internal/astnav/tokens_test.go @@ -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" @@ -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, } @@ -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)) }) } @@ -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) @@ -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) }) diff --git a/internal/binder/binder.go b/internal/binder/binder.go index 393d4a8efb..ce8e4defd8 100644 --- a/internal/binder/binder.go +++ b/internal/binder/binder.go @@ -42,7 +42,6 @@ const ( type Binder struct { file *ast.SourceFile - options *core.SourceFileAffectingCompilerOptions languageVersion core.ScriptTarget bindFunc func(*ast.Node) bool unreachableFlow *ast.FlowNode @@ -77,6 +76,10 @@ type Binder struct { singleDeclarationsPool core.Pool[*ast.Node] } +func (b *Binder) options() core.SourceFileAffectingCompilerOptions { + return b.file.ParseOptions().CompilerOptions +} + type ActiveLabel struct { next *ActiveLabel breakTarget *ast.FlowLabel @@ -88,11 +91,11 @@ type ActiveLabel struct { func (label *ActiveLabel) BreakTarget() *ast.FlowNode { return label.breakTarget } func (label *ActiveLabel) ContinueTarget() *ast.FlowNode { return label.continueTarget } -func BindSourceFile(file *ast.SourceFile, options *core.SourceFileAffectingCompilerOptions) { +func BindSourceFile(file *ast.SourceFile) { // This is constructed this way to make the compiler "out-line" the function, // avoiding most work in the common case where the file has already been bound. if !file.IsBound() { - bindSourceFile(file, options) + bindSourceFile(file) } } @@ -113,14 +116,13 @@ func putBinder(b *Binder) { binderPool.Put(b) } -func bindSourceFile(file *ast.SourceFile, options *core.SourceFileAffectingCompilerOptions) { +func bindSourceFile(file *ast.SourceFile) { file.BindOnce(func() { b := getBinder() defer putBinder(b) b.file = file - b.options = options - b.languageVersion = options.EmitScriptTarget - b.inStrictMode = options.BindInStrictMode && !file.IsDeclarationFile || ast.IsExternalModule(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) b.bind(file.AsNode()) @@ -1441,7 +1443,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 && b.options().EmitScriptTarget >= core.ScriptTargetES2015 { data := node.AsLabeledStatement() if ast.IsDeclarationStatement(data.Statement) || ast.IsVariableStatement(data.Statement) { b.errorOnFirstToken(data.Label, diagnostics.A_label_is_not_allowed_here) @@ -1614,7 +1616,7 @@ func (b *Binder) bindChildren(node *ast.Node) { return } kind := node.Kind - if kind >= ast.KindFirstStatement && kind <= ast.KindLastStatement && (b.options.AllowUnreachableCode != core.TSTrue || kind == ast.KindReturnStatement) { + if kind >= ast.KindFirstStatement && kind <= ast.KindLastStatement && (b.options().AllowUnreachableCode != core.TSTrue || kind == ast.KindReturnStatement) { hasFlowNodeData := node.FlowNodeData() if hasFlowNodeData != nil { hasFlowNodeData.FlowNode = b.currentFlow @@ -1749,11 +1751,11 @@ func (b *Binder) checkUnreachable(node *ast.Node) bool { // report errors on instantiated modules reportError := ast.IsStatementButNotDeclaration(node) && !ast.IsEmptyStatement(node) || ast.IsClassDeclaration(node) || - isEnumDeclarationWithPreservedEmit(node, b.options) || + isEnumDeclarationWithPreservedEmit(node, b.options()) || ast.IsModuleDeclaration(node) && b.shouldReportErrorOnModuleDeclaration(node) if reportError { b.currentFlow = b.reportedUnreachableFlow - if b.options.AllowUnreachableCode != core.TSTrue { + if b.options().AllowUnreachableCode != core.TSTrue { // unreachable code is reported if // - user has explicitly asked about it AND // - statement is in not ambient context (statements in ambient context is already an error @@ -1763,7 +1765,7 @@ func (b *Binder) checkUnreachable(node *ast.Node) bool { // - node is not block scoped variable statement and at least one variable declaration has initializer // Rationale: we don't want to report errors on non-initialized var's since they are hoisted // On the other side we do want to report errors on non-initialized 'lets' because of TDZ - isError := unreachableCodeIsError(b.options) && node.Flags&ast.NodeFlagsAmbient == 0 && (!ast.IsVariableStatement(node) || + isError := unreachableCodeIsError(b.options()) && node.Flags&ast.NodeFlagsAmbient == 0 && (!ast.IsVariableStatement(node) || ast.GetCombinedNodeFlags(node.AsVariableStatement().DeclarationList)&ast.NodeFlagsBlockScoped != 0 || core.Some(node.AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes, func(d *ast.Node) bool { return d.AsVariableDeclaration().Initializer != nil @@ -1777,7 +1779,7 @@ func (b *Binder) checkUnreachable(node *ast.Node) bool { func (b *Binder) shouldReportErrorOnModuleDeclaration(node *ast.Node) bool { instanceState := ast.GetModuleInstanceState(node) - return instanceState == ast.ModuleInstanceStateInstantiated || (instanceState == ast.ModuleInstanceStateConstEnumOnly && b.options.ShouldPreserveConstEnums) + return instanceState == ast.ModuleInstanceStateInstantiated || (instanceState == ast.ModuleInstanceStateConstEnumOnly && b.options().ShouldPreserveConstEnums) } func (b *Binder) errorOnEachUnreachableRange(node *ast.Node, isError bool) { @@ -1820,7 +1822,7 @@ func (b *Binder) isPurelyTypeDeclaration(s *ast.Node) bool { case ast.KindModuleDeclaration: return ast.GetModuleInstanceState(s) != ast.ModuleInstanceStateInstantiated case ast.KindEnumDeclaration: - return !isEnumDeclarationWithPreservedEmit(s, b.options) + return !isEnumDeclarationWithPreservedEmit(s, b.options()) default: return false } @@ -2171,7 +2173,7 @@ func (b *Binder) bindCaseBlock(node *ast.Node) { clause := clauses[i] b.bind(clause) fallthroughFlow = b.currentFlow - if b.currentFlow.Flags&ast.FlowFlagsUnreachable == 0 && i != len(clauses)-1 && b.options.NoFallthroughCasesInSwitch == core.TSTrue { + if b.currentFlow.Flags&ast.FlowFlagsUnreachable == 0 && i != len(clauses)-1 && b.options().NoFallthroughCasesInSwitch == core.TSTrue { clause.AsCaseOrDefaultClause().FallthroughFlowNode = b.currentFlow } } @@ -2216,8 +2218,8 @@ func (b *Binder) bindLabeledStatement(node *ast.Node) { } b.bind(stmt.Label) b.bind(stmt.Statement) - if !b.activeLabelList.referenced && b.options.AllowUnusedLabels != core.TSTrue { - b.errorOrSuggestionOnNode(unusedLabelIsError(b.options), stmt.Label, diagnostics.Unused_label) + if !b.activeLabelList.referenced && b.options().AllowUnusedLabels != core.TSTrue { + b.errorOrSuggestionOnNode(unusedLabelIsError(b.options()), stmt.Label, diagnostics.Unused_label) } b.activeLabelList = b.activeLabelList.next b.addAntecedent(postStatementLabel, b.currentFlow) @@ -2539,7 +2541,7 @@ func (b *Binder) bindInitializer(node *ast.Node) { b.currentFlow = b.finishFlowLabel(exitFlow) } -func isEnumDeclarationWithPreservedEmit(node *ast.Node, options *core.SourceFileAffectingCompilerOptions) bool { +func isEnumDeclarationWithPreservedEmit(node *ast.Node, options core.SourceFileAffectingCompilerOptions) bool { return node.Kind == ast.KindEnumDeclaration && (!ast.IsEnumConst(node) || options.ShouldPreserveConstEnums) } @@ -2871,11 +2873,11 @@ func isFunctionSymbol(symbol *ast.Symbol) bool { return false } -func unreachableCodeIsError(options *core.SourceFileAffectingCompilerOptions) bool { +func unreachableCodeIsError(options core.SourceFileAffectingCompilerOptions) bool { return options.AllowUnreachableCode == core.TSFalse } -func unusedLabelIsError(options *core.SourceFileAffectingCompilerOptions) bool { +func unusedLabelIsError(options core.SourceFileAffectingCompilerOptions) bool { return options.AllowUnusedLabels == core.TSFalse } diff --git a/internal/binder/binder_test.go b/internal/binder/binder_test.go index 776fc717f0..afffa138e0 100644 --- a/internal/binder/binder_test.go +++ b/internal/binder/binder_test.go @@ -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" @@ -25,9 +24,17 @@ 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: sourceAffecting, + 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. @@ -37,7 +44,7 @@ func BenchmarkBind(b *testing.B) { b.ResetTimer() for i := range b.N { - BindSourceFile(sourceFiles[i], sourceAffecting) + BindSourceFile(sourceFiles[i]) } }) } diff --git a/internal/bundled/generate.go b/internal/bundled/generate.go index 5c1e667583..c39032bcd9 100644 --- a/internal/bundled/generate.go +++ b/internal/bundled/generate.go @@ -12,6 +12,8 @@ import ( "slices" "strings" + "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/repo" "github.com/microsoft/typescript-go/internal/tspath" @@ -140,7 +142,10 @@ func readLibs() []lib { log.Fatalf("failed to open libs.json: %v", err) } - sourceFile := parser.ParseJSONText(libsFile, tspath.Path(libsFile), string(b)) + sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: libsFile, + Path: tspath.Path(libsFile), + }, string(b), core.ScriptKindJSON) diags := sourceFile.Diagnostics() if len(diags) > 0 { diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 77b5ff3b1d..fca04dd588 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -534,7 +534,7 @@ type Program interface { GetImpliedNodeFormatForEmit(sourceFile ast.HasFileName) core.ModuleKind GetResolvedModule(currentSourceFile ast.HasFileName, moduleReference string, mode core.ResolutionMode) *module.ResolvedModule GetResolvedModules() map[tspath.Path]module.ModeAwareCache[*module.ResolvedModule] - GetSourceFileMetaData(path tspath.Path) *ast.SourceFileMetaData + GetSourceFileMetaData(path tspath.Path) ast.SourceFileMetaData GetJSXRuntimeImportSpecifier(path tspath.Path) (moduleReference string, specifier *ast.Node) GetImportHelpersImportSpecifier(path tspath.Path) *ast.Node SourceFileMayBeEmitted(sourceFile *ast.SourceFile, forceDtsEmit bool) bool @@ -10261,7 +10261,7 @@ 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 { + 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 { diff --git a/internal/checker/grammarchecks.go b/internal/checker/grammarchecks.go index acd23758e7..cd3cca23f3 100644 --- a/internal/checker/grammarchecks.go +++ b/internal/checker/grammarchecks.go @@ -1230,7 +1230,7 @@ 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 { + 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 } @@ -1737,7 +1737,7 @@ func (c *Checker) checkGrammarAwaitOrAwaitUsing(node *ast.Node) bool { core.ModuleKindNode18, core.ModuleKindNodeNext: sourceFileMetaData := c.program.GetSourceFileMetaData(sourceFile.Path()) - if sourceFileMetaData != nil && sourceFileMetaData.ImpliedNodeFormat == core.ModuleKindCommonJS { + if sourceFileMetaData.ImpliedNodeFormat == core.ModuleKindCommonJS { if !spanCalculated { span = scanner.GetRangeOfTokenAtPosition(sourceFile, node.Pos()) } diff --git a/internal/compiler/fileloader.go b/internal/compiler/fileloader.go index 78140ef85f..2a9b962262 100644 --- a/internal/compiler/fileloader.go +++ b/internal/compiler/fileloader.go @@ -44,7 +44,7 @@ type processedFiles struct { missingFiles []string resolvedModules map[tspath.Path]module.ModeAwareCache[*module.ResolvedModule] typeResolutionsInFile map[tspath.Path]module.ModeAwareCache[*module.ResolvedTypeReferenceDirective] - sourceFileMetaDatas map[tspath.Path]*ast.SourceFileMetaData + sourceFileMetaDatas map[tspath.Path]ast.SourceFileMetaData jsxRuntimeImportSpecifiers map[tspath.Path]*jsxRuntimeImportSpecifier importHelpersImportSpecifiers map[tspath.Path]*ast.Node // List of present unsupported extensions @@ -103,7 +103,7 @@ func processAllProgramFiles( filesByPath := make(map[tspath.Path]*ast.SourceFile, totalFileCount) resolvedModules := make(map[tspath.Path]module.ModeAwareCache[*module.ResolvedModule], totalFileCount) typeResolutionsInFile := make(map[tspath.Path]module.ModeAwareCache[*module.ResolvedTypeReferenceDirective], totalFileCount) - sourceFileMetaDatas := make(map[tspath.Path]*ast.SourceFileMetaData, totalFileCount) + sourceFileMetaDatas := make(map[tspath.Path]ast.SourceFileMetaData, totalFileCount) var jsxRuntimeImportSpecifiers map[tspath.Path]*jsxRuntimeImportSpecifier var importHelpersImportSpecifiers map[tspath.Path]*ast.Node var unsupportedExtensions []string @@ -259,7 +259,7 @@ func (p *fileLoader) getDefaultLibFilePriority(a *ast.SourceFile) int { return len(tsoptions.Libs) + 2 } -func (p *fileLoader) loadSourceFileMetaData(fileName string) *ast.SourceFileMetaData { +func (p *fileLoader) loadSourceFileMetaData(fileName string) ast.SourceFileMetaData { packageJsonScope := p.resolver.GetPackageJsonScopeIfApplicable(fileName) var packageJsonType, packageJsonDirectory string if packageJsonScope.Exists() { @@ -269,7 +269,7 @@ func (p *fileLoader) loadSourceFileMetaData(fileName string) *ast.SourceFileMeta } } impliedNodeFormat := ast.GetImpliedNodeFormatForFile(fileName, packageJsonType) - return &ast.SourceFileMetaData{ + return ast.SourceFileMetaData{ PackageJsonType: packageJsonType, PackageJsonDirectory: packageJsonDirectory, ImpliedNodeFormat: impliedNodeFormat, @@ -278,7 +278,14 @@ func (p *fileLoader) loadSourceFileMetaData(fileName string) *ast.SourceFileMeta func (p *fileLoader) parseSourceFile(t *parseTask) *ast.SourceFile { path := p.toPath(t.normalizedFilePath) - sourceFile := p.opts.Host.GetSourceFile(t.normalizedFilePath, path, p.projectReferenceFileMapper.getCompilerOptionsForFile(t).SourceFileAffecting(), t.metadata) + options := p.projectReferenceFileMapper.getCompilerOptionsForFile(t) + sourceFile := p.opts.Host.GetSourceFile(ast.SourceFileParseOptions{ + FileName: t.normalizedFilePath, + Path: path, + CompilerOptions: ast.GetSourceFileAffectingCompilerOptions(t.normalizedFilePath, options), + ExternalModuleIndicatorOptions: ast.GetExternalModuleIndicatorOptions(t.normalizedFilePath, options, t.metadata), + JSDocParsingMode: p.opts.JSDocParsingMode, + }) return sourceFile } @@ -292,7 +299,7 @@ func (p *fileLoader) resolveTripleslashPathReference(moduleName string, containi return tspath.NormalizePath(referencedFileName) } -func (p *fileLoader) resolveTypeReferenceDirectives(file *ast.SourceFile, meta *ast.SourceFileMetaData) ( +func (p *fileLoader) resolveTypeReferenceDirectives(file *ast.SourceFile, meta ast.SourceFileMetaData) ( toParse []string, typeResolutionsInFile module.ModeAwareCache[*module.ResolvedTypeReferenceDirective], ) { @@ -314,7 +321,7 @@ func (p *fileLoader) resolveTypeReferenceDirectives(file *ast.SourceFile, meta * const externalHelpersModuleNameText = "tslib" // TODO(jakebailey): dedupe -func (p *fileLoader) resolveImportsAndModuleAugmentations(file *ast.SourceFile, meta *ast.SourceFileMetaData) ( +func (p *fileLoader) resolveImportsAndModuleAugmentations(file *ast.SourceFile, meta ast.SourceFileMetaData) ( toParse []string, resolutionsInFile module.ModeAwareCache[*module.ResolvedModule], importHelpersImportSpecifier *ast.Node, @@ -397,7 +404,7 @@ func (p *fileLoader) resolveImportsAndModuleAugmentations(file *ast.SourceFile, return toParse, resolutionsInFile, importHelpersImportSpecifier, jsxRuntimeImportSpecifier_ } -func (p *fileLoader) resolveModuleNames(entries []*ast.Node, file *ast.SourceFile, meta *ast.SourceFileMetaData, redirect *tsoptions.ParsedCommandLine) []*resolution { +func (p *fileLoader) resolveModuleNames(entries []*ast.Node, file *ast.SourceFile, meta ast.SourceFileMetaData, redirect *tsoptions.ParsedCommandLine) []*resolution { if len(entries) == 0 { return nil } @@ -434,7 +441,7 @@ type resolution struct { resolvedModule *module.ResolvedModule } -func getModeForTypeReferenceDirectiveInFile(ref *ast.FileReference, file *ast.SourceFile, meta *ast.SourceFileMetaData, options *core.CompilerOptions) core.ResolutionMode { +func getModeForTypeReferenceDirectiveInFile(ref *ast.FileReference, file *ast.SourceFile, meta ast.SourceFileMetaData, options *core.CompilerOptions) core.ResolutionMode { if ref.ResolutionMode != core.ResolutionModeNone { return ref.ResolutionMode } else { @@ -442,7 +449,7 @@ func getModeForTypeReferenceDirectiveInFile(ref *ast.FileReference, file *ast.So } } -func getDefaultResolutionModeForFile(fileName string, meta *ast.SourceFileMetaData, options *core.CompilerOptions) core.ResolutionMode { +func getDefaultResolutionModeForFile(fileName string, meta ast.SourceFileMetaData, options *core.CompilerOptions) core.ResolutionMode { if importSyntaxAffectsModuleResolution(options) { return ast.GetImpliedNodeFormatForEmitWorker(fileName, options.GetEmitModuleKind(), meta) } else { @@ -450,7 +457,7 @@ func getDefaultResolutionModeForFile(fileName string, meta *ast.SourceFileMetaDa } } -func getModeForUsageLocation(fileName string, meta *ast.SourceFileMetaData, usage *ast.StringLiteralLike, options *core.CompilerOptions) core.ResolutionMode { +func getModeForUsageLocation(fileName string, meta ast.SourceFileMetaData, usage *ast.StringLiteralLike, options *core.CompilerOptions) core.ResolutionMode { if ast.IsImportDeclaration(usage.Parent) || ast.IsExportDeclaration(usage.Parent) || ast.IsJSDocImportTag(usage.Parent) { isTypeOnly := ast.IsExclusivelyTypeOnlyImportOrExport(usage.Parent) if isTypeOnly { @@ -488,7 +495,7 @@ func importSyntaxAffectsModuleResolution(options *core.CompilerOptions) bool { options.GetResolvePackageJsonExports() || options.GetResolvePackageJsonImports() } -func getEmitSyntaxForUsageLocationWorker(fileName string, meta *ast.SourceFileMetaData, usage *ast.Node, options *core.CompilerOptions) core.ResolutionMode { +func getEmitSyntaxForUsageLocationWorker(fileName string, meta ast.SourceFileMetaData, usage *ast.Node, options *core.CompilerOptions) core.ResolutionMode { if ast.IsRequireCall(usage.Parent, false /*requireStringLiteralLikeArgument*/) || ast.IsExternalModuleReference(usage.Parent) && ast.IsImportEqualsDeclaration(usage.Parent.Parent) { return core.ModuleKindCommonJS } diff --git a/internal/compiler/host.go b/internal/compiler/host.go index fcaef38c6f..82c8c697a3 100644 --- a/internal/compiler/host.go +++ b/internal/compiler/host.go @@ -5,7 +5,6 @@ import ( "github.com/microsoft/typescript-go/internal/collections" "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/tsoptions" "github.com/microsoft/typescript-go/internal/tspath" "github.com/microsoft/typescript-go/internal/vfs" @@ -18,7 +17,7 @@ type CompilerHost interface { GetCurrentDirectory() string NewLine() string Trace(msg string) - GetSourceFile(fileName string, path tspath.Path, options *core.SourceFileAffectingCompilerOptions, metadata *ast.SourceFileMetaData) *ast.SourceFile + GetSourceFile(opts ast.SourceFileParseOptions) *ast.SourceFile GetResolvedProjectReference(fileName string, path tspath.Path) *tsoptions.ParsedCommandLine } @@ -90,15 +89,12 @@ func (h *compilerHost) Trace(msg string) { //!!! TODO: implement } -func (h *compilerHost) GetSourceFile(fileName string, path tspath.Path, options *core.SourceFileAffectingCompilerOptions, metadata *ast.SourceFileMetaData) *ast.SourceFile { - text, ok := h.FS().ReadFile(fileName) +func (h *compilerHost) GetSourceFile(opts ast.SourceFileParseOptions) *ast.SourceFile { + text, ok := h.FS().ReadFile(opts.FileName) if !ok { return nil } - if tspath.FileExtensionIs(fileName, tspath.ExtensionJson) { - return parser.ParseJSONText(fileName, path, text) - } - return parser.ParseSourceFile(fileName, path, text, options, metadata, scanner.JSDocParsingModeParseForTypeErrors) + return parser.ParseSourceFile(opts, text, core.GetScriptKindFromFileName(opts.FileName)) } func (h *compilerHost) GetResolvedProjectReference(fileName string, path tspath.Path) *tsoptions.ParsedCommandLine { diff --git a/internal/compiler/parsetask.go b/internal/compiler/parsetask.go index 5c4e506918..3143336e72 100644 --- a/internal/compiler/parsetask.go +++ b/internal/compiler/parsetask.go @@ -16,7 +16,7 @@ type parseTask struct { isRedirected bool subTasks []*parseTask - metadata *ast.SourceFileMetaData + metadata ast.SourceFileMetaData resolutionsInFile module.ModeAwareCache[*module.ResolvedModule] typeResolutionsInFile module.ModeAwareCache[*module.ResolvedTypeReferenceDirective] importHelpersImportSpecifier *ast.Node diff --git a/internal/compiler/program.go b/internal/compiler/program.go index 3be053f2d7..8cea5d5dea 100644 --- a/internal/compiler/program.go +++ b/internal/compiler/program.go @@ -30,6 +30,7 @@ type ProgramOptions struct { CreateCheckerPool func(*Program) CheckerPool TypingsLocation string ProjectName string + JSDocParsingMode ast.JSDocParsingMode } func (p *ProgramOptions) canUseProjectReferenceSource() bool { @@ -225,9 +226,7 @@ func NewProgram(opts ProgramOptions) *Program { // In addition to a new program, return a boolean indicating whether the data of the old program was reused. func (p *Program) UpdateProgram(changedFilePath tspath.Path) (*Program, bool) { oldFile := p.filesByPath[changedFilePath] - // TODO(jakebailey): is wrong because the new file may have new metadata? - metadata := p.sourceFileMetaDatas[changedFilePath] - newFile := p.Host().GetSourceFile(oldFile.FileName(), changedFilePath, p.Options().SourceFileAffecting(), metadata) + newFile := p.Host().GetSourceFile(oldFile.ParseOptions()) if !canReplaceFileInProgram(oldFile, newFile) { return NewProgram(p.opts), false } @@ -257,14 +256,8 @@ func (p *Program) initCheckerPool() { } func canReplaceFileInProgram(file1 *ast.SourceFile, file2 *ast.SourceFile) bool { - // TODO(jakebailey): metadata?? return file2 != nil && - file1.FileName() == file2.FileName() && - file1.Path() == file2.Path() && - file1.LanguageVersion == file2.LanguageVersion && - file1.LanguageVariant == file2.LanguageVariant && - file1.ScriptKind == file2.ScriptKind && - file1.IsDeclarationFile == file2.IsDeclarationFile && + file1.ParseOptions() == file2.ParseOptions() && file1.HasNoDefaultLib == file2.HasNoDefaultLib && file1.UsesUriStyleNodeCoreModules == file2.UsesUriStyleNodeCoreModules && slices.EqualFunc(file1.Imports(), file2.Imports(), equalModuleSpecifiers) && @@ -308,7 +301,7 @@ func (p *Program) BindSourceFiles() { for _, file := range p.files { if !file.IsBound() { wg.Queue(func() { - binder.BindSourceFile(file, p.projectReferenceFileMapper.getCompilerOptionsForFile(file).SourceFileAffecting()) + binder.BindSourceFile(file) }) } } @@ -601,7 +594,7 @@ func compactAndMergeRelatedInfos(diagnostics []*ast.Diagnostic) []*ast.Diagnosti func (p *Program) getDiagnosticsHelper(ctx context.Context, sourceFile *ast.SourceFile, ensureBound bool, ensureChecked bool, getDiagnostics func(context.Context, *ast.SourceFile) []*ast.Diagnostic) []*ast.Diagnostic { if sourceFile != nil { if ensureBound { - binder.BindSourceFile(sourceFile, p.projectReferenceFileMapper.getCompilerOptionsForFile(sourceFile).SourceFileAffecting()) + binder.BindSourceFile(sourceFile) } return SortAndDeduplicateDiagnostics(getDiagnostics(ctx, sourceFile)) } @@ -670,7 +663,7 @@ func (p *Program) InstantiationCount() int { return count } -func (p *Program) GetSourceFileMetaData(path tspath.Path) *ast.SourceFileMetaData { +func (p *Program) GetSourceFileMetaData(path tspath.Path) ast.SourceFileMetaData { return p.sourceFileMetaDatas[path] } diff --git a/internal/core/compileroptions.go b/internal/core/compileroptions.go index e6c7f859e9..c7c84e3259 100644 --- a/internal/core/compileroptions.go +++ b/internal/core/compileroptions.go @@ -149,7 +149,7 @@ type CompilerOptions struct { Quiet Tristate `json:"quiet,omitzero"` sourceFileAffectingCompilerOptionsOnce sync.Once - sourceFileAffectingCompilerOptions *SourceFileAffectingCompilerOptions + sourceFileAffectingCompilerOptions SourceFileAffectingCompilerOptions } // noCopy may be embedded into structs which must not be copied @@ -355,24 +355,18 @@ type SourceFileAffectingCompilerOptions struct { AllowUnreachableCode Tristate AllowUnusedLabels Tristate BindInStrictMode bool - EmitModuleDetectionKind ModuleDetectionKind - EmitModuleKind ModuleKind EmitScriptTarget ScriptTarget - JsxEmit JsxEmit NoFallthroughCasesInSwitch Tristate ShouldPreserveConstEnums bool } -func (options *CompilerOptions) SourceFileAffecting() *SourceFileAffectingCompilerOptions { +func (options *CompilerOptions) SourceFileAffecting() SourceFileAffectingCompilerOptions { options.sourceFileAffectingCompilerOptionsOnce.Do(func() { - options.sourceFileAffectingCompilerOptions = &SourceFileAffectingCompilerOptions{ + options.sourceFileAffectingCompilerOptions = SourceFileAffectingCompilerOptions{ AllowUnreachableCode: options.AllowUnreachableCode, AllowUnusedLabels: options.AllowUnusedLabels, BindInStrictMode: options.AlwaysStrict.IsTrue() || options.Strict.IsTrue(), - EmitModuleDetectionKind: options.GetEmitModuleDetectionKind(), - EmitModuleKind: options.GetEmitModuleKind(), EmitScriptTarget: options.GetEmitScriptTarget(), - JsxEmit: options.Jsx, NoFallthroughCasesInSwitch: options.NoFallthroughCasesInSwitch, ShouldPreserveConstEnums: options.ShouldPreserveConstEnums(), } diff --git a/internal/execute/tsc.go b/internal/execute/tsc.go index a252f6e584..3a6a4f31cf 100644 --- a/internal/execute/tsc.go +++ b/internal/execute/tsc.go @@ -17,7 +17,6 @@ import ( "github.com/microsoft/typescript-go/internal/format" "github.com/microsoft/typescript-go/internal/parser" "github.com/microsoft/typescript-go/internal/pprof" - "github.com/microsoft/typescript-go/internal/scanner" "github.com/microsoft/typescript-go/internal/tsoptions" "github.com/microsoft/typescript-go/internal/tspath" ) @@ -74,16 +73,14 @@ func fmtMain(sys System, input, output string) ExitStatus { } text := fileContent pathified := tspath.ToPath(input, sys.GetCurrentDirectory(), true) - sourceFile := parser.ParseSourceFile( - string(pathified), - pathified, - text, - &core.SourceFileAffectingCompilerOptions{ + sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: string(pathified), + Path: pathified, + CompilerOptions: core.SourceFileAffectingCompilerOptions{ EmitScriptTarget: core.ScriptTargetLatest, }, - nil, - scanner.JSDocParsingModeParseAll, - ) + JSDocParsingMode: ast.JSDocParsingModeParseAll, + }, text, core.GetScriptKindFromFileName(string(pathified))) ast.SetParentInChildren(sourceFile.AsNode()) edits := format.FormatDocument(ctx, sourceFile) newText := applyBulkEdits(text, edits) @@ -246,8 +243,9 @@ func performCompilation( // todo: cache, statistics, tracing parseStart := sys.Now() program := compiler.NewProgram(compiler.ProgramOptions{ - Config: config, - Host: host, + Config: config, + Host: host, + JSDocParsingMode: ast.JSDocParsingModeParseForTypeErrors, }) parseTime := sys.Now().Sub(parseStart) diff --git a/internal/execute/watch.go b/internal/execute/watch.go index 84e49c78a4..6d587951d1 100644 --- a/internal/execute/watch.go +++ b/internal/execute/watch.go @@ -4,6 +4,7 @@ import ( "fmt" "time" + "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/compiler" ) @@ -36,8 +37,9 @@ func (w *watcher) doCycle() { } // updateProgram() w.program = compiler.NewProgram(compiler.ProgramOptions{ - Config: w.options, - Host: w.host, + Config: w.options, + Host: w.host, + JSDocParsingMode: ast.JSDocParsingModeParseForTypeErrors, }) if w.hasBeenModified(w.program) { fmt.Fprint(w.sys.Writer(), "build starting at ", w.sys.Now(), w.sys.NewLine()) diff --git a/internal/format/api_test.go b/internal/format/api_test.go index d60227f7dd..76e00e5113 100644 --- a/internal/format/api_test.go +++ b/internal/format/api_test.go @@ -12,7 +12,6 @@ import ( "github.com/microsoft/typescript-go/internal/parser" "github.com/microsoft/typescript-go/internal/printer" "github.com/microsoft/typescript-go/internal/repo" - "github.com/microsoft/typescript-go/internal/scanner" "gotest.tools/v3/assert" ) @@ -34,7 +33,7 @@ func applyBulkEdits(text string, edits []core.TextChange) string { return b.String() } -var parseCompilerOptions = &core.SourceFileAffectingCompilerOptions{ +var parseCompilerOptions = core.SourceFileAffectingCompilerOptions{ EmitScriptTarget: core.ScriptTargetLatest, } @@ -60,14 +59,11 @@ func TestFormat(t *testing.T) { fileContent, err := os.ReadFile(filePath) assert.NilError(t, err) text := string(fileContent) - sourceFile := parser.ParseSourceFile( - "/checker.ts", - "/checker.ts", - text, - parseCompilerOptions, - nil, - scanner.JSDocParsingModeParseAll, - ) + sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/checker.ts", + Path: "/checker.ts", + CompilerOptions: parseCompilerOptions, + }, text, core.ScriptKindTS) ast.SetParentInChildren(sourceFile.AsNode()) edits := format.FormatDocument(ctx, sourceFile) newText := applyBulkEdits(text, edits) @@ -94,14 +90,11 @@ func BenchmarkFormat(b *testing.B) { fileContent, err := os.ReadFile(filePath) assert.NilError(b, err) text := string(fileContent) - sourceFile := parser.ParseSourceFile( - "/checker.ts", - "/checker.ts", - text, - parseCompilerOptions, - nil, - scanner.JSDocParsingModeParseAll, - ) + sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/checker.ts", + Path: "/checker.ts", + CompilerOptions: parseCompilerOptions, + }, text, core.ScriptKindTS) ast.SetParentInChildren(sourceFile.AsNode()) b.Run("format checker.ts", func(b *testing.B) { diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index 3090fcc8ae..c299f819ae 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -76,21 +76,8 @@ var sourceFileCache collections.SyncMap[harnessutil.SourceFileCacheKey, *ast.Sou type parsedFileCache struct{} -func (c *parsedFileCache) GetFile( - fileName string, - path tspath.Path, - text string, - options *core.SourceFileAffectingCompilerOptions, - metadata *ast.SourceFileMetaData, -) *ast.SourceFile { - key := harnessutil.GetSourceFileCacheKey( - fileName, - path, - text, - options, - metadata, - ) - +func (c *parsedFileCache) GetFile(opts ast.SourceFileParseOptions, text string, scriptKind core.ScriptKind) *ast.SourceFile { + key := harnessutil.GetSourceFileCacheKey(opts, text, scriptKind) cachedFile, ok := sourceFileCache.Load(key) if !ok { return nil @@ -98,21 +85,8 @@ func (c *parsedFileCache) GetFile( return cachedFile } -func (c *parsedFileCache) CacheFile( - fileName string, - path tspath.Path, - text string, - options *core.SourceFileAffectingCompilerOptions, - metadata *ast.SourceFileMetaData, - sourceFile *ast.SourceFile, -) { - key := harnessutil.GetSourceFileCacheKey( - fileName, - path, - text, - options, - metadata, - ) +func (c *parsedFileCache) CacheFile(opts ast.SourceFileParseOptions, text string, scriptKind core.ScriptKind, sourceFile *ast.SourceFile) { + key := harnessutil.GetSourceFileCacheKey(opts, text, scriptKind) sourceFileCache.Store(key, sourceFile) } diff --git a/internal/ls/completions.go b/internal/ls/completions.go index 3d1927f49a..47e2a7f518 100644 --- a/internal/ls/completions.go +++ b/internal/ls/completions.go @@ -1513,7 +1513,7 @@ func (l *LanguageService) completionInfoFromData( defer done() // Verify if the file is JSX language variant - if ast.GetLanguageVariant(file.ScriptKind) == core.LanguageVariantJSX { + if file.LanguageVariant == core.LanguageVariantJSX { list := l.getJsxClosingTagCompletion(data.location, file, position, clientOptions) if list != nil { return list diff --git a/internal/ls/completions_test.go b/internal/ls/completions_test.go index 028153adcc..7dbdeca8ab 100644 --- a/internal/ls/completions_test.go +++ b/internal/ls/completions_test.go @@ -2172,7 +2172,7 @@ func assertIncludesItem(t *testing.T, actual *lsproto.CompletionList, expected * func createLanguageService(ctx context.Context, fileName string, files map[string]any) (*ls.LanguageService, func()) { projectService, _ := projecttestutil.Setup(files, nil) - projectService.OpenFile(fileName, files[fileName].(string), core.ScriptKindTS, "") + projectService.OpenFile(fileName, files[fileName].(string), core.GetScriptKindFromFileName(fileName), "") project := projectService.Projects()[0] return project.GetLanguageServiceForRequest(ctx) } diff --git a/internal/packagejson/packagejson_test.go b/internal/packagejson/packagejson_test.go index 389580490d..e216d9c1d2 100644 --- a/internal/packagejson/packagejson_test.go +++ b/internal/packagejson/packagejson_test.go @@ -6,6 +6,8 @@ import ( "testing" json2 "github.com/go-json-experiment/json" + "github.com/microsoft/typescript-go/internal/ast" + "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/packagejson" "github.com/microsoft/typescript-go/internal/parser" "github.com/microsoft/typescript-go/internal/repo" @@ -48,7 +50,10 @@ func BenchmarkPackageJSON(b *testing.B) { b.Run(f.Name(), func(b *testing.B) { fileName := "/" + f.Name() for b.Loop() { - parser.ParseJSONText(fileName, tspath.Path(fileName), string(content)) + parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: fileName, + Path: tspath.Path(fileName), + }, string(content), core.ScriptKindJSON) } }) }) diff --git a/internal/parser/jsdoc.go b/internal/parser/jsdoc.go index 55a80b572e..e9e9604d73 100644 --- a/internal/parser/jsdoc.go +++ b/internal/parser/jsdoc.go @@ -127,7 +127,6 @@ func (p *Parser) parseJSDocComment(parent *ast.Node, start int, end int, fullSta saveToken := p.token saveContextFlags := p.contextFlags saveParsingContexts := p.parsingContexts - saveParsingMode := p.scanner.JSDocParsingMode saveScannerState := p.scanner.Mark() saveDiagnosticsLength := len(p.diagnostics) saveHasParseError := p.hasParseError @@ -157,7 +156,6 @@ func (p *Parser) parseJSDocComment(parent *ast.Node, start int, end int, fullSta p.scanner.SetText(p.sourceText) p.parsingContexts = saveParsingContexts p.contextFlags = saveContextFlags - p.scanner.JSDocParsingMode = saveParsingMode p.scanner.Rewind(saveScannerState) p.token = saveToken p.hasParseError = saveHasParseError diff --git a/internal/parser/parser.go b/internal/parser/parser.go index de189f3d19..1952d6ffe8 100644 --- a/internal/parser/parser.go +++ b/internal/parser/parser.go @@ -50,12 +50,9 @@ type Parser struct { scanner *scanner.Scanner factory ast.NodeFactory - fileName string - path tspath.Path - sourceText string - options *core.SourceFileAffectingCompilerOptions - metadata *ast.SourceFileMetaData - languageVersion core.ScriptTarget + opts ast.SourceFileParseOptions + sourceText string + scriptKind core.ScriptKind languageVariant core.LanguageVariant diagnostics []*ast.Diagnostic @@ -99,19 +96,18 @@ func putParser(p *Parser) { parserPool.Put(p) } -func ParseSourceFile(fileName string, path tspath.Path, sourceText string, options *core.SourceFileAffectingCompilerOptions, metadata *ast.SourceFileMetaData, jsdocParsingMode scanner.JSDocParsingMode) *ast.SourceFile { +func ParseSourceFile(opts ast.SourceFileParseOptions, sourceText string, scriptKind core.ScriptKind) *ast.SourceFile { p := getParser() defer putParser(p) - p.initializeState(fileName, path, sourceText, options, metadata, core.ScriptKindUnknown, jsdocParsingMode) + p.initializeState(opts, sourceText, scriptKind) p.nextToken() + if p.scriptKind == core.ScriptKindJSON { + return p.parseJSONText() + } return p.parseSourceFileWorker() } -func ParseJSONText(fileName string, path tspath.Path, sourceText string) *ast.SourceFile { - p := getParser() - defer putParser(p) - p.initializeState(fileName, path, sourceText, &core.SourceFileAffectingCompilerOptions{EmitScriptTarget: core.ScriptTargetES2015}, nil, core.ScriptKindJSON, scanner.JSDocParsingModeParseAll) - p.nextToken() +func (p *Parser) parseJSONText() *ast.SourceFile { pos := p.nodePos() var statements *ast.NodeList @@ -172,40 +168,41 @@ func ParseJSONText(fileName string, path tspath.Path, sourceText string) *ast.So statements = p.newNodeList(core.NewTextRange(pos, p.nodePos()), []*ast.Node{statement}) p.parseExpectedToken(ast.KindEndOfFile) } - node := p.factory.NewSourceFile(p.sourceText, p.fileName, p.path, statements) + node := p.factory.NewSourceFile(p.opts, p.sourceText, statements) p.finishNode(node, pos) result := node.AsSourceFile() - result.ScriptKind = core.ScriptKindJSON - result.LanguageVersion = core.ScriptTargetES2015 - result.Flags |= p.sourceFlags - result.SetDiagnostics(attachFileToDiagnostics(p.diagnostics, result)) - result.SetJSDocDiagnostics(attachFileToDiagnostics(p.jsdocDiagnostics, result)) + p.finishSourceFile(result, false) return result } func ParseIsolatedEntityName(text string, languageVersion core.ScriptTarget) *ast.EntityName { p := getParser() defer putParser(p) - p.initializeState("", "", text, &core.SourceFileAffectingCompilerOptions{EmitScriptTarget: languageVersion}, nil, core.ScriptKindJS, scanner.JSDocParsingModeParseAll) + p.initializeState(ast.SourceFileParseOptions{ + CompilerOptions: core.SourceFileAffectingCompilerOptions{ + EmitScriptTarget: languageVersion, + }, + JSDocParsingMode: ast.JSDocParsingModeParseAll, + }, text, core.ScriptKindJS) p.nextToken() entityName := p.parseEntityName(true, nil) return core.IfElse(p.token == ast.KindEndOfFile && len(p.diagnostics) == 0, entityName, nil) } -func (p *Parser) initializeState(fileName string, path tspath.Path, sourceText string, options *core.SourceFileAffectingCompilerOptions, metadata *ast.SourceFileMetaData, scriptKind core.ScriptKind, jsdocParsingMode scanner.JSDocParsingMode) { +func (p *Parser) initializeState(opts ast.SourceFileParseOptions, sourceText string, scriptKind core.ScriptKind) { + if scriptKind == core.ScriptKindUnknown { + panic("ScriptKind must be specified when parsing source files.") + } + if p.scanner == nil { p.scanner = scanner.NewScanner() } else { p.scanner.Reset() } - p.fileName = fileName - p.path = path + p.opts = opts p.sourceText = sourceText - p.options = options - p.metadata = metadata - p.languageVersion = options.EmitScriptTarget - p.scriptKind = ensureScriptKind(fileName, scriptKind) - p.languageVariant = ast.GetLanguageVariant(p.scriptKind) + p.scriptKind = scriptKind + p.languageVariant = getLanguageVariant(p.scriptKind) switch p.scriptKind { case core.ScriptKindJS, core.ScriptKindJSX: p.contextFlags = ast.NodeFlagsJavaScriptFile @@ -216,10 +213,10 @@ func (p *Parser) initializeState(fileName string, path tspath.Path, sourceText s } p.scanner.SetText(p.sourceText) p.scanner.SetOnError(p.scanError) - p.scanner.SetScriptTarget(p.languageVersion) + p.scanner.SetScriptTarget(p.opts.CompilerOptions.EmitScriptTarget) p.scanner.SetLanguageVariant(p.languageVariant) p.scanner.SetScriptKind(p.scriptKind) - p.scanner.SetJSDocParsingMode(jsdocParsingMode) + p.scanner.SetJSDocParsingMode(p.opts.JSDocParsingMode) } func (p *Parser) scanError(message *diagnostics.Message, pos int, length int, args ...any) { @@ -317,7 +314,7 @@ func (p *Parser) hasPrecedingJSDocComment() bool { } func (p *Parser) parseSourceFileWorker() *ast.SourceFile { - isDeclarationFile := tspath.IsDeclarationFileName(p.fileName) + isDeclarationFile := tspath.IsDeclarationFileName(p.opts.FileName) if isDeclarationFile { p.contextFlags |= ast.NodeFlagsAmbient } @@ -327,7 +324,7 @@ func (p *Parser) parseSourceFileWorker() *ast.SourceFile { if eof.Kind != ast.KindEndOfFile { panic("Expected end of file token from scanner.") } - node := p.factory.NewSourceFile(p.sourceText, p.fileName, p.path, statements) + node := p.factory.NewSourceFile(p.opts, p.sourceText, statements) p.finishNode(node, pos) result := node.AsSourceFile() p.finishSourceFile(result, isDeclarationFile) @@ -348,9 +345,9 @@ func (p *Parser) finishSourceFile(result *ast.SourceFile, isDeclarationFile bool result.Pragmas = getCommentPragmas(&p.factory, p.sourceText) p.processPragmasIntoFields(result) result.SetDiagnostics(attachFileToDiagnostics(p.diagnostics, result)) + result.SetJSDocDiagnostics(attachFileToDiagnostics(p.jsdocDiagnostics, result)) result.CommonJSModuleIndicator = p.commonJSModuleIndicator result.IsDeclarationFile = isDeclarationFile - result.LanguageVersion = p.languageVersion result.LanguageVariant = p.languageVariant result.ScriptKind = p.scriptKind result.Flags |= p.sourceFlags @@ -359,82 +356,7 @@ func (p *Parser) finishSourceFile(result *ast.SourceFile, isDeclarationFile bool result.TextCount = p.factory.TextCount() result.IdentifierCount = p.identifierCount result.SetJSDocCache(p.jsdocCache) - result.ExternalModuleIndicator = getExternalModuleIndicator(result, p.options, p.metadata) -} - -func getExternalModuleIndicator(file *ast.SourceFile, options *core.SourceFileAffectingCompilerOptions, metadata *ast.SourceFileMetaData) *ast.Node { - // All detection kinds start by checking this. - if node := isFileProbablyExternalModule(file); node != nil { - return node - } - - switch options.EmitModuleDetectionKind { - case core.ModuleDetectionKindForce: - // All non-declaration files are modules, declaration files still do the usual isFileProbablyExternalModule - if !file.IsDeclarationFile { - return file.AsNode() - } - return nil - case core.ModuleDetectionKindLegacy: - // Files are modules if they have imports, exports, or import.meta - return nil - case core.ModuleDetectionKindAuto: - // If module is nodenext or node16, all esm format files are modules - // If jsx is react-jsx or react-jsxdev then jsx tags force module-ness - // otherwise, the presence of import or export statments (or import.meta) implies module-ness - if options.JsxEmit == core.JsxEmitReactJSX || options.JsxEmit == core.JsxEmitReactJSXDev { - if node := isFileModuleFromUsingJSXTag(file); node != nil { - return node - } - } - return isFileForcedToBeModuleByFormat(file, options, metadata) - default: - return nil - } -} - -func isFileModuleFromUsingJSXTag(file *ast.SourceFile) *ast.Node { - if file.IsDeclarationFile { - return nil - } - return walkTreeForJSXTags(file.AsNode()) -} - -// This is a somewhat unavoidable full tree walk to locate a JSX tag - `import.meta` requires the same, -// but we avoid that walk (or parts of it) if at all possible using the `PossiblyContainsImportMeta` node flag. -// Unfortunately, there's no `NodeFlag` space to do the same for JSX. -func walkTreeForJSXTags(node *ast.Node) *ast.Node { - var found *ast.Node - - var visitor func(node *ast.Node) bool - visitor = func(node *ast.Node) bool { - if found != nil { - return true - } - if node.SubtreeFacts()&ast.SubtreeContainsJsx == 0 { - return false - } - if ast.IsJsxOpeningElement(node) || ast.IsJsxFragment(node) { - found = node - return true - } - return node.ForEachChild(visitor) - } - visitor(node) - - return found -} - -var isFileForcedToBeModuleByFormatExtensions = []string{tspath.ExtensionCjs, tspath.ExtensionCts, tspath.ExtensionMjs, tspath.ExtensionMts} - -func isFileForcedToBeModuleByFormat(file *ast.SourceFile, options *core.SourceFileAffectingCompilerOptions, metadata *ast.SourceFileMetaData) *ast.Node { - // Excludes declaration files - they still require an explicit `export {}` or the like - // for back compat purposes. The only non-declaration files _not_ forced to be a module are `.js` files - // that aren't esm-mode (meaning not in a `type: module` scope). - if !file.IsDeclarationFile && (ast.GetImpliedNodeFormatForEmitWorker(file.FileName(), options.EmitModuleKind, metadata) == core.ModuleKindESNext || tspath.FileExtensionIsOneOf(file.FileName(), isFileForcedToBeModuleByFormatExtensions)) { - return file.AsNode() - } - return nil + ast.SetExternalModuleIndicator(result, p.opts.ExternalModuleIndicatorOptions) } func (p *Parser) parseToplevelStatement(i int) *ast.Node { @@ -539,7 +461,7 @@ func (p *Parser) reparseTopLevelAwait(sourceFile *ast.SourceFile) *ast.Node { } } - return p.factory.NewSourceFile(sourceFile.Text(), sourceFile.FileName(), sourceFile.Path(), p.newNodeList(sourceFile.Statements.Loc, statements)) + return p.factory.NewSourceFile(sourceFile.ParseOptions(), p.sourceText, p.newNodeList(sourceFile.Statements.Loc, statements)) } func (p *Parser) parseListIndex(kind ParsingContext, parseElement func(p *Parser, index int) *ast.Node) *ast.NodeList { @@ -6428,36 +6350,6 @@ func isReservedWord(token ast.Kind) bool { return ast.KindFirstReservedWord <= token && token <= ast.KindLastReservedWord } -func isFileProbablyExternalModule(sourceFile *ast.SourceFile) *ast.Node { - for _, statement := range sourceFile.Statements.Nodes { - if ast.IsExternalModuleIndicator(statement) { - return statement - } - } - return getImportMetaIfNecessary(sourceFile) -} - -func getImportMetaIfNecessary(sourceFile *ast.SourceFile) *ast.Node { - if sourceFile.AsNode().Flags&ast.NodeFlagsPossiblyContainsImportMeta != 0 { - return findChildNode(sourceFile.AsNode(), ast.IsImportMeta) - } - return nil -} - -func findChildNode(root *ast.Node, check func(*ast.Node) bool) *ast.Node { - var result *ast.Node - var visit func(*ast.Node) bool - visit = func(node *ast.Node) bool { - if check(node) { - result = node - return true - } - return node.ForEachChild(visit) - } - visit(root) - return result -} - func tagNamesAreEquivalent(lhs *ast.Expression, rhs *ast.Expression) bool { if lhs.Kind != rhs.Kind { return false diff --git a/internal/parser/parser_test.go b/internal/parser/parser_test.go index 0833bd4b14..11a01b0220 100644 --- a/internal/parser/parser_test.go +++ b/internal/parser/parser_test.go @@ -7,10 +7,10 @@ import ( "path/filepath" "testing" + "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/collections" "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/repo" - "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" @@ -20,10 +20,10 @@ import ( func BenchmarkParse(b *testing.B) { jsdocModes := []struct { name string - mode scanner.JSDocParsingMode + mode ast.JSDocParsingMode }{ - {"tsc", scanner.JSDocParsingModeParseForTypeErrors}, - {"server", scanner.JSDocParsingModeParseAll}, + {"tsc", ast.JSDocParsingModeParseForTypeErrors}, + {"server", ast.JSDocParsingModeParseAll}, } for _, f := range fixtures.BenchFixtures { @@ -33,15 +33,23 @@ func BenchmarkParse(b *testing.B) { fileName := tspath.GetNormalizedAbsolutePath(f.Path(), "/") path := tspath.ToPath(fileName, "/", osvfs.FS().UseCaseSensitiveFileNames()) sourceText := f.ReadFile(b) - options := &core.SourceFileAffectingCompilerOptions{ - EmitScriptTarget: core.ScriptTargetESNext, - } + scriptKind := core.GetScriptKindFromFileName(fileName) for _, jsdoc := range jsdocModes { b.Run(jsdoc.name, func(b *testing.B) { jsdocMode := jsdoc.mode + + opts := ast.SourceFileParseOptions{ + FileName: fileName, + Path: path, + CompilerOptions: core.SourceFileAffectingCompilerOptions{ + EmitScriptTarget: core.ScriptTargetESNext, + }, + JSDocParsingMode: jsdocMode, + } + for b.Loop() { - ParseSourceFile(fileName, path, sourceText, options, nil, jsdocMode) + ParseSourceFile(opts, sourceText, scriptKind) } }) } @@ -106,13 +114,13 @@ func FuzzParser(f *testing.F) { sourceText, err := os.ReadFile(file.path) assert.NilError(f, err) extension := tspath.TryGetExtensionFromPath(file.path) - f.Add(extension, string(sourceText), int(core.ScriptTargetESNext), int(scanner.JSDocParsingModeParseAll)) + f.Add(extension, string(sourceText), int(core.ScriptTargetESNext), int(ast.JSDocParsingModeParseAll)) } } f.Fuzz(func(t *testing.T, extension string, sourceText string, scriptTarget_ int, jsdocParsingMode_ int) { scriptTarget := core.ScriptTarget(scriptTarget_) - jsdocParsingMode := scanner.JSDocParsingMode(jsdocParsingMode_) + jsdocParsingMode := ast.JSDocParsingMode(jsdocParsingMode_) if !extensions.Has(extension) { t.Skip() @@ -122,22 +130,22 @@ func FuzzParser(f *testing.F) { t.Skip() } - if jsdocParsingMode < scanner.JSDocParsingModeParseAll || jsdocParsingMode > scanner.JSDocParsingModeParseNone { + if jsdocParsingMode < ast.JSDocParsingModeParseAll || jsdocParsingMode > ast.JSDocParsingModeParseNone { t.Skip() } fileName := "/index" + extension path := tspath.Path(fileName) - if extension == ".json" { - ParseJSONText(fileName, path, sourceText) - return - } - - options := &core.SourceFileAffectingCompilerOptions{ - EmitScriptTarget: scriptTarget, + opts := ast.SourceFileParseOptions{ + FileName: fileName, + Path: path, + CompilerOptions: core.SourceFileAffectingCompilerOptions{ + EmitScriptTarget: scriptTarget, + }, + JSDocParsingMode: jsdocParsingMode, } - ParseSourceFile(fileName, path, sourceText, options, nil, jsdocParsingMode) + ParseSourceFile(opts, sourceText, core.GetScriptKindFromFileName(fileName)) }) } diff --git a/internal/parser/utilities.go b/internal/parser/utilities.go index b2487f9539..ca9715f247 100644 --- a/internal/parser/utilities.go +++ b/internal/parser/utilities.go @@ -8,20 +8,13 @@ import ( "github.com/microsoft/typescript-go/internal/scanner" ) -func ensureScriptKind(fileName string, scriptKind core.ScriptKind) core.ScriptKind { - // Using scriptKind as a condition handles both: - // - 'scriptKind' is unspecified and thus it is `undefined` - // - 'scriptKind' is set and it is `Unknown` (0) - // If the 'scriptKind' is 'undefined' or 'Unknown' then we attempt - // to get the ScriptKind from the file name. If it cannot be resolved - // from the file name then the default 'TS' script kind is returned. - if scriptKind == core.ScriptKindUnknown { - scriptKind = core.GetScriptKindFromFileName(fileName) +func getLanguageVariant(scriptKind core.ScriptKind) core.LanguageVariant { + switch scriptKind { + case core.ScriptKindTSX, core.ScriptKindJSX, core.ScriptKindJS, core.ScriptKindJSON: + // .tsx and .jsx files are treated as jsx language variant. + return core.LanguageVariantJSX } - if scriptKind == core.ScriptKindUnknown { - scriptKind = core.ScriptKindTS - } - return scriptKind + return core.LanguageVariantStandard } func tokenIsIdentifierOrKeyword(token ast.Kind) bool { diff --git a/internal/printer/namegenerator_test.go b/internal/printer/namegenerator_test.go index 220bf606e6..26d638a884 100644 --- a/internal/printer/namegenerator_test.go +++ b/internal/printer/namegenerator_test.go @@ -5,14 +5,11 @@ import ( "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/binder" - "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/printer" "github.com/microsoft/typescript-go/internal/testutil/parsetestutil" "gotest.tools/v3/assert" ) -var defaultSourceFileAffectingOptions = (&core.CompilerOptions{}).SourceFileAffecting() - func TestTempVariable1(t *testing.T) { t.Parallel() @@ -260,7 +257,7 @@ func TestGeneratedNameForIdentifier1(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("function f() {}", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) n := file.Statements.Nodes[0].Name() name1 := ec.Factory.NewGeneratedNameForNode(n) @@ -277,7 +274,7 @@ func TestGeneratedNameForIdentifier2(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("function f() {}", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) n := file.Statements.Nodes[0].Name() name1 := ec.Factory.NewGeneratedNameForNodeEx(n, printer.AutoGenerateOptions{ @@ -297,7 +294,7 @@ func TestGeneratedNameForIdentifier3(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("function f() {}", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) n := file.Statements.Nodes[0].Name() name1 := ec.Factory.NewGeneratedNameForNodeEx(n, printer.AutoGenerateOptions{ @@ -319,7 +316,7 @@ func TestGeneratedNameForNamespace1(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("namespace foo { }", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) ns1 := file.Statements.Nodes[0] name1 := ec.Factory.NewGeneratedNameForNode(ns1) @@ -337,7 +334,7 @@ func TestGeneratedNameForNamespace2(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("namespace foo { var foo; }", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) ns1 := file.Statements.Nodes[0] name1 := ec.Factory.NewGeneratedNameForNode(ns1) @@ -355,7 +352,7 @@ func TestGeneratedNameForNamespace3(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("namespace ns1 { namespace foo { var foo; } } namespace ns2 { namespace foo { var foo; } }", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) ns1 := file.Statements.Nodes[0].AsModuleDeclaration().Body.AsModuleBlock().Statements.Nodes[0] ns2 := file.Statements.Nodes[1].AsModuleDeclaration().Body.AsModuleBlock().Statements.Nodes[0] @@ -377,7 +374,7 @@ func TestGeneratedNameForNamespace4(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("namespace ns1 { namespace foo { var foo; } } namespace ns2 { namespace foo { var foo; } }", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) ns1 := file.Statements.Nodes[0].AsModuleDeclaration().Body.AsModuleBlock().Statements.Nodes[0] ns2 := file.Statements.Nodes[1].AsModuleDeclaration().Body.AsModuleBlock().Statements.Nodes[0] @@ -404,7 +401,7 @@ func TestGeneratedNameForNodeCached(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("namespace foo { var foo; }", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) ns1 := file.Statements.Nodes[0] name1 := ec.Factory.NewGeneratedNameForNode(ns1) @@ -424,7 +421,7 @@ func TestGeneratedNameForImport(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("import * as foo from 'foo'", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) n := file.Statements.Nodes[0] name1 := ec.Factory.NewGeneratedNameForNode(n) @@ -441,7 +438,7 @@ func TestGeneratedNameForExport(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("export * as foo from 'foo'", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) n := file.Statements.Nodes[0] name1 := ec.Factory.NewGeneratedNameForNode(n) @@ -458,7 +455,7 @@ func TestGeneratedNameForFunctionDeclaration1(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("export function f() {}", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) n := file.Statements.Nodes[0] name1 := ec.Factory.NewGeneratedNameForNode(n) @@ -475,7 +472,7 @@ func TestGeneratedNameForFunctionDeclaration2(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("export default function () {}", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) n := file.Statements.Nodes[0] name1 := ec.Factory.NewGeneratedNameForNode(n) @@ -492,7 +489,7 @@ func TestGeneratedNameForClassDeclaration1(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("export class C {}", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) n := file.Statements.Nodes[0] name1 := ec.Factory.NewGeneratedNameForNode(n) @@ -509,7 +506,7 @@ func TestGeneratedNameForClassDeclaration2(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("export default class {}", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) n := file.Statements.Nodes[0] name1 := ec.Factory.NewGeneratedNameForNode(n) @@ -526,7 +523,7 @@ func TestGeneratedNameForExportAssignment(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("export default 0", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) n := file.Statements.Nodes[0] name1 := ec.Factory.NewGeneratedNameForNode(n) @@ -543,7 +540,7 @@ func TestGeneratedNameForClassExpression(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("(class {})", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) n := file.Statements.Nodes[0].AsExpressionStatement().Expression.AsParenthesizedExpression().Expression name1 := ec.Factory.NewGeneratedNameForNode(n) @@ -560,7 +557,7 @@ func TestGeneratedNameForMethod1(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("class C { m() {} }", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) n := file.Statements.Nodes[0].AsClassDeclaration().Members.Nodes[0] name1 := ec.Factory.NewGeneratedNameForNode(n) @@ -577,7 +574,7 @@ func TestGeneratedNameForMethod2(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("class C { 0() {} }", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) n := file.Statements.Nodes[0].AsClassDeclaration().Members.Nodes[0] name1 := ec.Factory.NewGeneratedNameForNode(n) @@ -594,7 +591,7 @@ func TestGeneratedPrivateNameForMethod(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("class C { m() {} }", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) n := file.Statements.Nodes[0].AsClassDeclaration().Members.Nodes[0] name1 := ec.Factory.NewGeneratedPrivateNameForNode(n) @@ -611,7 +608,7 @@ func TestGeneratedNameForComputedPropertyName(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("class C { [x] }", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) n := file.Statements.Nodes[0].AsClassDeclaration().Members.Nodes[0].Name() name1 := ec.Factory.NewGeneratedNameForNode(n) @@ -628,7 +625,7 @@ func TestGeneratedNameForOther(t *testing.T) { ec := printer.NewEmitContext() file := parsetestutil.ParseTypeScript("class C { [x] }", false /*jsx*/) - binder.BindSourceFile(file, defaultSourceFileAffectingOptions) + binder.BindSourceFile(file) n := ec.Factory.NewObjectLiteralExpression( ec.Factory.NewNodeList([]*ast.Node{}), diff --git a/internal/printer/printer.go b/internal/printer/printer.go index 21e36e3ef3..9184bd3274 100644 --- a/internal/printer/printer.go +++ b/internal/printer/printer.go @@ -844,7 +844,7 @@ func (p *Printer) shouldAllowTrailingComma(node *ast.Node, list *ast.NodeList) b return false } - target := p.currentSourceFile.LanguageVersion + target := p.currentSourceFile.LanguageVersion() switch node.Kind { case ast.KindObjectLiteralExpression: return target >= core.ScriptTargetES5 diff --git a/internal/printer/printer_test.go b/internal/printer/printer_test.go index 2e4fdd46a1..90fb6e2f56 100644 --- a/internal/printer/printer_test.go +++ b/internal/printer/printer_test.go @@ -590,7 +590,7 @@ func TestParenthesizeDecorator(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewClassDeclaration( factory.NewModifierList( @@ -623,7 +623,7 @@ func TestParenthesizeComputedPropertyName(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewClassDeclaration( nil, /*modifiers*/ @@ -660,7 +660,7 @@ func TestParenthesizeArrayLiteral(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewArrayLiteralExpression( @@ -690,7 +690,7 @@ func TestParenthesizePropertyAccess1(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewPropertyAccessExpression( @@ -718,7 +718,7 @@ func TestParenthesizePropertyAccess2(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewPropertyAccessExpression( @@ -745,7 +745,7 @@ func TestParenthesizePropertyAccess3(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewPropertyAccessExpression( @@ -771,7 +771,7 @@ func TestParenthesizeElementAccess1(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewElementAccessExpression( @@ -799,7 +799,7 @@ func TestParenthesizeElementAccess2(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewElementAccessExpression( @@ -826,7 +826,7 @@ func TestParenthesizeElementAccess3(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewElementAccessExpression( @@ -852,7 +852,7 @@ func TestParenthesizeCall1(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewCallExpression( @@ -881,7 +881,7 @@ func TestParenthesizeCall2(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewCallExpression( @@ -909,7 +909,7 @@ func TestParenthesizeCall3(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewCallExpression( @@ -936,7 +936,7 @@ func TestParenthesizeCall4(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewCallExpression( @@ -966,7 +966,7 @@ func TestParenthesizeNew1(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewNewExpression( @@ -993,7 +993,7 @@ func TestParenthesizeNew2(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewNewExpression( @@ -1020,7 +1020,7 @@ func TestParenthesizeNew3(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewNewExpression( @@ -1048,7 +1048,7 @@ func TestParenthesizeTaggedTemplate1(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewTaggedTemplateExpression( @@ -1077,7 +1077,7 @@ func TestParenthesizeTaggedTemplate2(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewTaggedTemplateExpression( @@ -1105,7 +1105,7 @@ func TestParenthesizeTypeAssertion1(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewTypeAssertion( @@ -1134,7 +1134,7 @@ func TestParenthesizeArrowFunction1(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewArrowFunction( @@ -1161,7 +1161,7 @@ func TestParenthesizeArrowFunction2(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewArrowFunction( @@ -1193,7 +1193,7 @@ func TestParenthesizeDelete(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewDeleteExpression( @@ -1218,7 +1218,7 @@ func TestParenthesizeVoid(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewVoidExpression( @@ -1243,7 +1243,7 @@ func TestParenthesizeTypeOf(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewTypeOfExpression( @@ -1268,7 +1268,7 @@ func TestParenthesizeAwait(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewAwaitExpression( @@ -1394,7 +1394,7 @@ func TestParenthesizeBinary(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewBinaryExpression( @@ -1418,7 +1418,7 @@ func TestParenthesizeConditional1(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewConditionalExpression( @@ -1447,7 +1447,7 @@ func TestParenthesizeConditional2(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewConditionalExpression( @@ -1476,7 +1476,7 @@ func TestParenthesizeConditional3(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewConditionalExpression( @@ -1509,7 +1509,7 @@ func TestParenthesizeConditional4(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewConditionalExpression( @@ -1532,7 +1532,7 @@ func TestParenthesizeConditional5(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewConditionalExpression( @@ -1561,7 +1561,7 @@ func TestParenthesizeConditional6(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewConditionalExpression( @@ -1590,7 +1590,7 @@ func TestParenthesizeYield1(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewYieldExpression( @@ -1620,7 +1620,7 @@ func TestParenthesizeSpreadElement1(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewArrayLiteralExpression( @@ -1652,7 +1652,7 @@ func TestParenthesizeSpreadElement2(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewCallExpression( @@ -1687,7 +1687,7 @@ func TestParenthesizeSpreadElement3(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewNewExpression( @@ -1720,7 +1720,7 @@ func TestParenthesizeExpressionWithTypeArguments(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewExpressionWithTypeArguments( @@ -1753,7 +1753,7 @@ func TestParenthesizeAsExpression(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewAsExpression( @@ -1782,7 +1782,7 @@ func TestParenthesizeSatisfiesExpression(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewSatisfiesExpression( @@ -1811,7 +1811,7 @@ func TestParenthesizeNonNullExpression(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewNonNullExpression( @@ -1837,7 +1837,7 @@ func TestParenthesizeExpressionStatement1(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewObjectLiteralExpression( @@ -1858,7 +1858,7 @@ func TestParenthesizeExpressionStatement2(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewFunctionExpression( @@ -1887,7 +1887,7 @@ func TestParenthesizeExpressionStatement3(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExpressionStatement( factory.NewClassExpression( @@ -1911,7 +1911,7 @@ func TestParenthesizeExpressionDefault1(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExportAssignment( nil, /*modifiers*/ @@ -1939,7 +1939,7 @@ func TestParenthesizeExpressionDefault2(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExportAssignment( nil, /*modifiers*/ @@ -1974,7 +1974,7 @@ func TestParenthesizeExpressionDefault3(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewExportAssignment( nil, /*modifiers*/ @@ -2000,7 +2000,7 @@ func TestParenthesizeArrayType(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewTypeAliasDeclaration( nil, /*modifiers*/ @@ -2029,7 +2029,7 @@ func TestParenthesizeOptionalType(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewTypeAliasDeclaration( nil, /*modifiers*/ @@ -2064,7 +2064,7 @@ func TestParenthesizeUnionType1(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewTypeAliasDeclaration( nil, /*modifiers*/ @@ -2097,7 +2097,7 @@ func TestParenthesizeUnionType2(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewTypeAliasDeclaration( nil, /*modifiers*/ @@ -2131,7 +2131,7 @@ func TestParenthesizeIntersectionType(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewTypeAliasDeclaration( nil, /*modifiers*/ @@ -2165,7 +2165,7 @@ func TestParenthesizeReadonlyTypeOperator1(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewTypeAliasDeclaration( nil, /*modifiers*/ @@ -2195,7 +2195,7 @@ func TestParenthesizeReadonlyTypeOperator2(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewTypeAliasDeclaration( nil, /*modifiers*/ @@ -2221,7 +2221,7 @@ func TestParenthesizeKeyofTypeOperator(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewTypeAliasDeclaration( nil, /*modifiers*/ @@ -2251,7 +2251,7 @@ func TestParenthesizeIndexedAccessType(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewTypeAliasDeclaration( nil, /*modifiers*/ @@ -2281,7 +2281,7 @@ func TestParenthesizeConditionalType1(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewTypeAliasDeclaration( nil, /*modifiers*/ @@ -2312,7 +2312,7 @@ func TestParenthesizeConditionalType2(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewTypeAliasDeclaration( nil, /*modifiers*/ @@ -2342,7 +2342,7 @@ func TestParenthesizeConditionalType3(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList( + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList( []*ast.Node{ factory.NewTypeAliasDeclaration( nil, /*modifiers*/ @@ -2380,7 +2380,7 @@ func TestParenthesizeConditionalType4(t *testing.T) { t.Parallel() var factory ast.NodeFactory - file := factory.NewSourceFile("", "/file.ts", "/file.ts", factory.NewNodeList([]*ast.Node{ + file := factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", factory.NewNodeList([]*ast.Node{ factory.NewTypeAliasDeclaration( nil, /*modifiers*/ factory.NewIdentifier("_"), /*name*/ @@ -2422,7 +2422,7 @@ func TestParenthesizeConditionalType4(t *testing.T) { func TestNameGeneration(t *testing.T) { t.Parallel() ec := printer.NewEmitContext() - file := ec.Factory.NewSourceFile("", "/file.ts", "/file.ts", ec.Factory.NewNodeList([]*ast.Node{ + file := ec.Factory.NewSourceFile(ast.SourceFileParseOptions{FileName: "/file.ts", Path: "/file.ts"}, "", ec.Factory.NewNodeList([]*ast.Node{ ec.Factory.NewVariableStatement(nil, ec.Factory.NewVariableDeclarationList( ast.NodeFlagsNone, ec.Factory.NewNodeList([]*ast.Node{ diff --git a/internal/project/documentregistry.go b/internal/project/documentregistry.go index dc497f320d..add8801864 100644 --- a/internal/project/documentregistry.go +++ b/internal/project/documentregistry.go @@ -7,23 +7,18 @@ import ( "github.com/microsoft/typescript-go/internal/collections" "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/tspath" ) type registryKey struct { - core.SourceFileAffectingCompilerOptions - ast.SourceFileMetaData - path tspath.Path + ast.SourceFileParseOptions scriptKind core.ScriptKind } -func newRegistryKey(options *core.CompilerOptions, path tspath.Path, scriptKind core.ScriptKind, metadata *ast.SourceFileMetaData) registryKey { +func newRegistryKey(opts ast.SourceFileParseOptions, scriptKind core.ScriptKind) registryKey { return registryKey{ - SourceFileAffectingCompilerOptions: *options.SourceFileAffecting(), - SourceFileMetaData: *metadata, - path: path, - scriptKind: scriptKind, + SourceFileParseOptions: opts, + scriptKind: scriptKind, } } @@ -58,18 +53,17 @@ type DocumentRegistry struct { // LanguageService instance over time, as well as across multiple instances. Here, we still // reuse files across multiple LanguageServices, but we only reuse them across Program updates // when the files haven't changed. -func (r *DocumentRegistry) AcquireDocument(scriptInfo *ScriptInfo, compilerOptions *core.CompilerOptions, metadata *ast.SourceFileMetaData, oldSourceFile *ast.SourceFile, oldCompilerOptions *core.CompilerOptions, oldMetadata *ast.SourceFileMetaData) *ast.SourceFile { - key := newRegistryKey(compilerOptions, scriptInfo.path, scriptInfo.scriptKind, metadata) - document := r.getDocumentWorker(scriptInfo, compilerOptions, metadata, key) - if oldSourceFile != nil && oldCompilerOptions != nil { - oldKey := newRegistryKey(oldCompilerOptions, scriptInfo.path, oldSourceFile.ScriptKind, oldMetadata) - r.releaseDocumentWithKey(oldKey) +func (r *DocumentRegistry) AcquireDocument(scriptInfo *ScriptInfo, opts ast.SourceFileParseOptions, oldSourceFile *ast.SourceFile) *ast.SourceFile { + key := newRegistryKey(opts, scriptInfo.scriptKind) + document := r.getDocumentWorker(scriptInfo, key) + if oldSourceFile != nil { + r.releaseDocumentWithKey(key) } return document } -func (r *DocumentRegistry) ReleaseDocument(file *ast.SourceFile, compilerOptions *core.CompilerOptions, metadata *ast.SourceFileMetaData) { - key := newRegistryKey(compilerOptions, file.Path(), file.ScriptKind, metadata) +func (r *DocumentRegistry) ReleaseDocument(file *ast.SourceFile) { + key := newRegistryKey(file.ParseOptions(), file.ScriptKind) r.releaseDocumentWithKey(key) } @@ -87,20 +81,14 @@ func (r *DocumentRegistry) releaseDocumentWithKey(key registryKey) { } } -func (r *DocumentRegistry) getDocumentWorker( - scriptInfo *ScriptInfo, - compilerOptions *core.CompilerOptions, - metadata *ast.SourceFileMetaData, - key registryKey, -) *ast.SourceFile { - scriptTarget := core.IfElse(scriptInfo.scriptKind == core.ScriptKindJSON, core.ScriptTargetJSON, compilerOptions.GetEmitScriptTarget()) +func (r *DocumentRegistry) getDocumentWorker(scriptInfo *ScriptInfo, key registryKey) *ast.SourceFile { scriptInfoVersion := scriptInfo.Version() scriptInfoText := scriptInfo.Text() if entry, ok := r.documents.Load(key); ok { // We have an entry for this file. However, it may be for a different version of // the script snapshot. If so, update it appropriately. if entry.version != scriptInfoVersion { - sourceFile := r.getParsedFile(scriptInfo.fileName, scriptInfo.path, scriptInfoText, scriptTarget, compilerOptions, metadata) + sourceFile := r.getParsedFile(key.SourceFileParseOptions, scriptInfoText, key.scriptKind) entry.mu.Lock() defer entry.mu.Unlock() entry.sourceFile = sourceFile @@ -110,7 +98,7 @@ func (r *DocumentRegistry) getDocumentWorker( return entry.sourceFile } else { // Have never seen this file with these settings. Create a new source file for it. - sourceFile := r.getParsedFile(scriptInfo.fileName, scriptInfo.path, scriptInfoText, scriptTarget, compilerOptions, metadata) + sourceFile := r.getParsedFile(key.SourceFileParseOptions, scriptInfoText, key.scriptKind) entry, _ := r.documents.LoadOrStore(key, ®istryEntry{ sourceFile: sourceFile, refCount: 0, @@ -123,30 +111,23 @@ func (r *DocumentRegistry) getDocumentWorker( } } -func (r *DocumentRegistry) getFileVersion(file *ast.SourceFile, options *core.CompilerOptions, metadata *ast.SourceFileMetaData) int { - key := newRegistryKey(options, file.Path(), file.ScriptKind, metadata) +func (r *DocumentRegistry) getFileVersion(file *ast.SourceFile) int { + key := newRegistryKey(file.ParseOptions(), file.ScriptKind) if entry, ok := r.documents.Load(key); ok && entry.sourceFile == file { return entry.version } return -1 } -func (r *DocumentRegistry) getParsedFile( - fileName string, - path tspath.Path, - sourceText string, - scriptTarget core.ScriptTarget, - options *core.CompilerOptions, - metadata *ast.SourceFileMetaData, -) *ast.SourceFile { +func (r *DocumentRegistry) getParsedFile(opts ast.SourceFileParseOptions, text string, scriptKind core.ScriptKind) *ast.SourceFile { if r.parsedFileCache != nil { - if file := r.parsedFileCache.GetFile(fileName, path, sourceText, options.SourceFileAffecting(), metadata); file != nil { + if file := r.parsedFileCache.GetFile(opts, text, scriptKind); file != nil { return file } } - file := parser.ParseSourceFile(fileName, path, sourceText, options.SourceFileAffecting(), metadata, scanner.JSDocParsingModeParseAll) + file := parser.ParseSourceFile(opts, text, scriptKind) if r.parsedFileCache != nil { - r.parsedFileCache.CacheFile(fileName, path, sourceText, options.SourceFileAffecting(), metadata, file) + r.parsedFileCache.CacheFile(opts, text, scriptKind, file) } return file } @@ -157,19 +138,6 @@ func (r *DocumentRegistry) size() int { } type ParsedFileCache interface { - GetFile( - fileName string, - path tspath.Path, - text string, - options *core.SourceFileAffectingCompilerOptions, - metadata *ast.SourceFileMetaData, - ) *ast.SourceFile - CacheFile( - fileName string, - path tspath.Path, - text string, - options *core.SourceFileAffectingCompilerOptions, - metadata *ast.SourceFileMetaData, - sourceFile *ast.SourceFile, - ) + GetFile(opts ast.SourceFileParseOptions, text string, scriptKind core.ScriptKind) *ast.SourceFile + CacheFile(opts ast.SourceFileParseOptions, text string, scriptKind core.ScriptKind, sourceFile *ast.SourceFile) } diff --git a/internal/project/project.go b/internal/project/project.go index 4680e75279..3ed15c5096 100644 --- a/internal/project/project.go +++ b/internal/project/project.go @@ -48,7 +48,7 @@ type snapshot struct { func (s *snapshot) GetLineMap(fileName string) *ls.LineMap { file := s.program.GetSourceFile(fileName) scriptInfo := s.project.host.GetScriptInfoByPath(file.Path()) - if s.project.getFileVersion(file, s.program.Options(), s.program.GetSourceFileMetaData(file.Path())) == scriptInfo.Version() { + if s.project.getFileVersion(file) == scriptInfo.Version() { return scriptInfo.LineMap() } return ls.ComputeLineStarts(file.Text()) @@ -273,20 +273,14 @@ func (p *Project) GetCompilerOptions() *core.CompilerOptions { } // GetSourceFile implements compiler.CompilerHost. -func (p *Project) GetSourceFile(fileName string, path tspath.Path, options *core.SourceFileAffectingCompilerOptions, metadata *ast.SourceFileMetaData) *ast.SourceFile { - scriptKind := p.getScriptKind(fileName) - if scriptInfo := p.getOrCreateScriptInfoAndAttachToProject(fileName, scriptKind); scriptInfo != nil { - var ( - oldSourceFile *ast.SourceFile - oldCompilerOptions *core.CompilerOptions - oldMetadata *ast.SourceFileMetaData - ) +func (p *Project) GetSourceFile(opts ast.SourceFileParseOptions) *ast.SourceFile { + scriptKind := p.getScriptKind(opts.FileName) + if scriptInfo := p.getOrCreateScriptInfoAndAttachToProject(opts.FileName, scriptKind); scriptInfo != nil { + var oldSourceFile *ast.SourceFile if p.program != nil { oldSourceFile = p.program.GetSourceFileByPath(scriptInfo.path) - oldCompilerOptions = p.program.Options() - oldMetadata = p.program.GetSourceFileMetaData(scriptInfo.path) } - return p.host.DocumentRegistry().AcquireDocument(scriptInfo, p.compilerOptions, metadata, oldSourceFile, oldCompilerOptions, oldMetadata) + return p.host.DocumentRegistry().AcquireDocument(scriptInfo, opts, oldSourceFile) } return nil } @@ -525,7 +519,7 @@ func (p *Project) updateGraph() (*compiler.Program, bool) { if oldProgram != nil { for _, oldSourceFile := range oldProgram.GetSourceFiles() { if p.program.GetSourceFileByPath(oldSourceFile.Path()) == nil { - p.host.DocumentRegistry().ReleaseDocument(oldSourceFile, oldProgram.Options(), oldProgram.GetSourceFileMetaData(oldSourceFile.Path())) + p.host.DocumentRegistry().ReleaseDocument(oldSourceFile) p.detachScriptInfoIfNotInferredRoot(oldSourceFile.Path()) } } @@ -591,6 +585,7 @@ func (p *Project) updateProgram() bool { p.checkerPool = newCheckerPool(4, program, p.Log) return p.checkerPool }, + JSDocParsingMode: ast.JSDocParsingModeParseAll, }) } else { // The only change in the current program is the contents of the file named by p.dirtyFilePath. @@ -1005,13 +1000,12 @@ func (p *Project) print(writeFileNames bool, writeFileExplanation bool, writeFil builder.WriteString("\n\tFiles (0) NoProgram\n") } else { sourceFiles := p.program.GetSourceFiles() - options := p.program.Options() builder.WriteString(fmt.Sprintf("\n\tFiles (%d)\n", len(sourceFiles))) if writeFileNames { for _, sourceFile := range sourceFiles { builder.WriteString("\n\t\t" + sourceFile.FileName()) if writeFileVersionAndText { - builder.WriteString(fmt.Sprintf(" %d %s", p.getFileVersion(sourceFile, options, p.program.GetSourceFileMetaData(sourceFile.Path())), sourceFile.Text())) + builder.WriteString(fmt.Sprintf(" %d %s", p.getFileVersion(sourceFile), sourceFile.Text())) } } // !!! @@ -1022,8 +1016,8 @@ func (p *Project) print(writeFileNames bool, writeFileExplanation bool, writeFil return builder.String() } -func (p *Project) getFileVersion(file *ast.SourceFile, options *core.CompilerOptions, metadata *ast.SourceFileMetaData) int { - return p.host.DocumentRegistry().getFileVersion(file, options, metadata) +func (p *Project) getFileVersion(file *ast.SourceFile) int { + return p.host.DocumentRegistry().getFileVersion(file) } func (p *Project) Log(s string) { @@ -1049,7 +1043,7 @@ func (p *Project) Close() { if p.program != nil { for _, sourceFile := range p.program.GetSourceFiles() { - p.host.DocumentRegistry().ReleaseDocument(sourceFile, p.program.Options(), p.program.GetSourceFileMetaData(sourceFile.Path())) + p.host.DocumentRegistry().ReleaseDocument(sourceFile) // Detach script info if its not root or is root of non inferred project p.detachScriptInfoIfNotInferredRoot(sourceFile.Path()) } diff --git a/internal/scanner/scanner.go b/internal/scanner/scanner.go index 69df81e277..5ca20bacfa 100644 --- a/internal/scanner/scanner.go +++ b/internal/scanner/scanner.go @@ -195,15 +195,6 @@ var ( unicodeESNextIdentifierPart = []rune{48, 57, 65, 90, 95, 95, 97, 122, 170, 170, 181, 181, 183, 183, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 768, 884, 886, 887, 890, 893, 895, 895, 902, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1155, 1159, 1162, 1327, 1329, 1366, 1369, 1369, 1376, 1416, 1425, 1469, 1471, 1471, 1473, 1474, 1476, 1477, 1479, 1479, 1488, 1514, 1519, 1522, 1552, 1562, 1568, 1641, 1646, 1747, 1749, 1756, 1759, 1768, 1770, 1788, 1791, 1791, 1808, 1866, 1869, 1969, 1984, 2037, 2042, 2042, 2045, 2045, 2048, 2093, 2112, 2139, 2144, 2154, 2160, 2183, 2185, 2190, 2200, 2273, 2275, 2403, 2406, 2415, 2417, 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2500, 2503, 2504, 2507, 2510, 2519, 2519, 2524, 2525, 2527, 2531, 2534, 2545, 2556, 2556, 2558, 2558, 2561, 2563, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2641, 2641, 2649, 2652, 2654, 2654, 2662, 2677, 2689, 2691, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, 2787, 2790, 2799, 2809, 2815, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2876, 2884, 2887, 2888, 2891, 2893, 2901, 2903, 2908, 2909, 2911, 2915, 2918, 2927, 2929, 2929, 2946, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3024, 3024, 3031, 3031, 3046, 3055, 3072, 3084, 3086, 3088, 3090, 3112, 3114, 3129, 3132, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3160, 3162, 3165, 3165, 3168, 3171, 3174, 3183, 3200, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3260, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3293, 3294, 3296, 3299, 3302, 3311, 3313, 3315, 3328, 3340, 3342, 3344, 3346, 3396, 3398, 3400, 3402, 3406, 3412, 3415, 3423, 3427, 3430, 3439, 3450, 3455, 3457, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3558, 3567, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3718, 3722, 3724, 3747, 3749, 3749, 3751, 3773, 3776, 3780, 3782, 3782, 3784, 3790, 3792, 3801, 3804, 3807, 3840, 3840, 3864, 3865, 3872, 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3948, 3953, 3972, 3974, 3991, 3993, 4028, 4038, 4038, 4096, 4169, 4176, 4253, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4957, 4959, 4969, 4977, 4992, 5007, 5024, 5109, 5112, 5117, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5880, 5888, 5909, 5919, 5940, 5952, 5971, 5984, 5996, 5998, 6000, 6002, 6003, 6016, 6099, 6103, 6103, 6108, 6109, 6112, 6121, 6155, 6157, 6159, 6169, 6176, 6264, 6272, 6314, 6320, 6389, 6400, 6430, 6432, 6443, 6448, 6459, 6470, 6509, 6512, 6516, 6528, 6571, 6576, 6601, 6608, 6618, 6656, 6683, 6688, 6750, 6752, 6780, 6783, 6793, 6800, 6809, 6823, 6823, 6832, 6845, 6847, 6862, 6912, 6988, 6992, 7001, 7019, 7027, 7040, 7155, 7168, 7223, 7232, 7241, 7245, 7293, 7296, 7304, 7312, 7354, 7357, 7359, 7376, 7378, 7380, 7418, 7424, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8204, 8205, 8255, 8256, 8276, 8276, 8305, 8305, 8319, 8319, 8336, 8348, 8400, 8412, 8417, 8417, 8421, 8432, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8472, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11492, 11499, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11647, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11744, 11775, 12293, 12295, 12321, 12335, 12337, 12341, 12344, 12348, 12353, 12438, 12441, 12447, 12449, 12543, 12549, 12591, 12593, 12686, 12704, 12735, 12784, 12799, 13312, 19903, 19968, 42124, 42192, 42237, 42240, 42508, 42512, 42539, 42560, 42607, 42612, 42621, 42623, 42737, 42775, 42783, 42786, 42888, 42891, 42954, 42960, 42961, 42963, 42963, 42965, 42969, 42994, 43047, 43052, 43052, 43072, 43123, 43136, 43205, 43216, 43225, 43232, 43255, 43259, 43259, 43261, 43309, 43312, 43347, 43360, 43388, 43392, 43456, 43471, 43481, 43488, 43518, 43520, 43574, 43584, 43597, 43600, 43609, 43616, 43638, 43642, 43714, 43739, 43741, 43744, 43759, 43762, 43766, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43824, 43866, 43868, 43881, 43888, 44010, 44012, 44013, 44016, 44025, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65024, 65039, 65056, 65071, 65075, 65076, 65101, 65103, 65136, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65381, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, 65536, 65547, 65549, 65574, 65576, 65594, 65596, 65597, 65599, 65613, 65616, 65629, 65664, 65786, 65856, 65908, 66045, 66045, 66176, 66204, 66208, 66256, 66272, 66272, 66304, 66335, 66349, 66378, 66384, 66426, 66432, 66461, 66464, 66499, 66504, 66511, 66513, 66517, 66560, 66717, 66720, 66729, 66736, 66771, 66776, 66811, 66816, 66855, 66864, 66915, 66928, 66938, 66940, 66954, 66956, 66962, 66964, 66965, 66967, 66977, 66979, 66993, 66995, 67001, 67003, 67004, 67072, 67382, 67392, 67413, 67424, 67431, 67456, 67461, 67463, 67504, 67506, 67514, 67584, 67589, 67592, 67592, 67594, 67637, 67639, 67640, 67644, 67644, 67647, 67669, 67680, 67702, 67712, 67742, 67808, 67826, 67828, 67829, 67840, 67861, 67872, 67897, 67968, 68023, 68030, 68031, 68096, 68099, 68101, 68102, 68108, 68115, 68117, 68119, 68121, 68149, 68152, 68154, 68159, 68159, 68192, 68220, 68224, 68252, 68288, 68295, 68297, 68326, 68352, 68405, 68416, 68437, 68448, 68466, 68480, 68497, 68608, 68680, 68736, 68786, 68800, 68850, 68864, 68903, 68912, 68921, 69248, 69289, 69291, 69292, 69296, 69297, 69373, 69404, 69415, 69415, 69424, 69456, 69488, 69509, 69552, 69572, 69600, 69622, 69632, 69702, 69734, 69749, 69759, 69818, 69826, 69826, 69840, 69864, 69872, 69881, 69888, 69940, 69942, 69951, 69956, 69959, 69968, 70003, 70006, 70006, 70016, 70084, 70089, 70092, 70094, 70106, 70108, 70108, 70144, 70161, 70163, 70199, 70206, 70209, 70272, 70278, 70280, 70280, 70282, 70285, 70287, 70301, 70303, 70312, 70320, 70378, 70384, 70393, 70400, 70403, 70405, 70412, 70415, 70416, 70419, 70440, 70442, 70448, 70450, 70451, 70453, 70457, 70459, 70468, 70471, 70472, 70475, 70477, 70480, 70480, 70487, 70487, 70493, 70499, 70502, 70508, 70512, 70516, 70656, 70730, 70736, 70745, 70750, 70753, 70784, 70853, 70855, 70855, 70864, 70873, 71040, 71093, 71096, 71104, 71128, 71133, 71168, 71232, 71236, 71236, 71248, 71257, 71296, 71352, 71360, 71369, 71424, 71450, 71453, 71467, 71472, 71481, 71488, 71494, 71680, 71738, 71840, 71913, 71935, 71942, 71945, 71945, 71948, 71955, 71957, 71958, 71960, 71989, 71991, 71992, 71995, 72003, 72016, 72025, 72096, 72103, 72106, 72151, 72154, 72161, 72163, 72164, 72192, 72254, 72263, 72263, 72272, 72345, 72349, 72349, 72368, 72440, 72704, 72712, 72714, 72758, 72760, 72768, 72784, 72793, 72818, 72847, 72850, 72871, 72873, 72886, 72960, 72966, 72968, 72969, 72971, 73014, 73018, 73018, 73020, 73021, 73023, 73031, 73040, 73049, 73056, 73061, 73063, 73064, 73066, 73102, 73104, 73105, 73107, 73112, 73120, 73129, 73440, 73462, 73472, 73488, 73490, 73530, 73534, 73538, 73552, 73561, 73648, 73648, 73728, 74649, 74752, 74862, 74880, 75075, 77712, 77808, 77824, 78895, 78912, 78933, 82944, 83526, 92160, 92728, 92736, 92766, 92768, 92777, 92784, 92862, 92864, 92873, 92880, 92909, 92912, 92916, 92928, 92982, 92992, 92995, 93008, 93017, 93027, 93047, 93053, 93071, 93760, 93823, 93952, 94026, 94031, 94087, 94095, 94111, 94176, 94177, 94179, 94180, 94192, 94193, 94208, 100343, 100352, 101589, 101632, 101640, 110576, 110579, 110581, 110587, 110589, 110590, 110592, 110882, 110898, 110898, 110928, 110930, 110933, 110933, 110948, 110951, 110960, 111355, 113664, 113770, 113776, 113788, 113792, 113800, 113808, 113817, 113821, 113822, 118528, 118573, 118576, 118598, 119141, 119145, 119149, 119154, 119163, 119170, 119173, 119179, 119210, 119213, 119362, 119364, 119808, 119892, 119894, 119964, 119966, 119967, 119970, 119970, 119973, 119974, 119977, 119980, 119982, 119993, 119995, 119995, 119997, 120003, 120005, 120069, 120071, 120074, 120077, 120084, 120086, 120092, 120094, 120121, 120123, 120126, 120128, 120132, 120134, 120134, 120138, 120144, 120146, 120485, 120488, 120512, 120514, 120538, 120540, 120570, 120572, 120596, 120598, 120628, 120630, 120654, 120656, 120686, 120688, 120712, 120714, 120744, 120746, 120770, 120772, 120779, 120782, 120831, 121344, 121398, 121403, 121452, 121461, 121461, 121476, 121476, 121499, 121503, 121505, 121519, 122624, 122654, 122661, 122666, 122880, 122886, 122888, 122904, 122907, 122913, 122915, 122916, 122918, 122922, 122928, 122989, 123023, 123023, 123136, 123180, 123184, 123197, 123200, 123209, 123214, 123214, 123536, 123566, 123584, 123641, 124112, 124153, 124896, 124902, 124904, 124907, 124909, 124910, 124912, 124926, 124928, 125124, 125136, 125142, 125184, 125259, 125264, 125273, 126464, 126467, 126469, 126495, 126497, 126498, 126500, 126500, 126503, 126503, 126505, 126514, 126516, 126519, 126521, 126521, 126523, 126523, 126530, 126530, 126535, 126535, 126537, 126537, 126539, 126539, 126541, 126543, 126545, 126546, 126548, 126548, 126551, 126551, 126553, 126553, 126555, 126555, 126557, 126557, 126559, 126559, 126561, 126562, 126564, 126564, 126567, 126570, 126572, 126578, 126580, 126583, 126585, 126588, 126590, 126590, 126592, 126601, 126603, 126619, 126625, 126627, 126629, 126633, 126635, 126651, 130032, 130041, 131072, 173791, 173824, 177977, 177984, 178205, 178208, 183969, 183984, 191456, 191472, 192093, 194560, 195101, 196608, 201546, 201552, 205743, 917760, 917999} ) -type JSDocParsingMode int - -const ( - JSDocParsingModeParseAll JSDocParsingMode = iota - JSDocParsingModeParseNone - JSDocParsingModeParseForTypeErrors - JSDocParsingModeParseForTypeInfo -) - type ScannerState struct { pos int // Current position in text (and ending position of current token) fullStartPos int // Starting position of current token including preceding whitespace @@ -222,7 +213,7 @@ type Scanner struct { languageVariant core.LanguageVariant onError ErrorCallback skipTrivia bool - JSDocParsingMode JSDocParsingMode + JSDocParsingMode ast.JSDocParsingMode scriptKind core.ScriptKind ScannerState } @@ -356,7 +347,7 @@ func (s *Scanner) SetScriptKind(scriptKind core.ScriptKind) { s.scriptKind = scriptKind } -func (s *Scanner) SetJSDocParsingMode(kind JSDocParsingMode) { +func (s *Scanner) SetJSDocParsingMode(kind ast.JSDocParsingMode) { s.JSDocParsingMode = kind } @@ -398,16 +389,16 @@ func (s *Scanner) charAndSize() (rune, int) { func (s *Scanner) shouldParseJSDoc() bool { switch s.JSDocParsingMode { - case JSDocParsingModeParseAll: + case ast.JSDocParsingModeParseAll: return true - case JSDocParsingModeParseNone: + case ast.JSDocParsingModeParseNone: return false } if s.scriptKind != core.ScriptKindTS && s.scriptKind != core.ScriptKindTSX { // If outside of TS, we need JSDoc to get any type info. return true } - if s.JSDocParsingMode == JSDocParsingModeParseForTypeInfo { + if s.JSDocParsingMode == ast.JSDocParsingModeParseForTypeInfo { // If we're in TS, but we don't need to produce reliable errors, // we don't need to parse to find @see or @link. return false @@ -2246,7 +2237,7 @@ func GetScannerForSourceFile(sourceFile *ast.SourceFile, pos int) *Scanner { s := NewScanner() s.text = sourceFile.Text() s.pos = pos - s.languageVersion = sourceFile.LanguageVersion + s.languageVersion = sourceFile.LanguageVersion() s.languageVariant = sourceFile.LanguageVariant s.Scan() return s diff --git a/internal/testrunner/test_case_parser.go b/internal/testrunner/test_case_parser.go index 6984acc8c6..62fa71de79 100644 --- a/internal/testrunner/test_case_parser.go +++ b/internal/testrunner/test_case_parser.go @@ -5,6 +5,8 @@ import ( "slices" "strings" + "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/harnessutil" @@ -72,7 +74,10 @@ func makeUnitsFromTest(code string, fileName string) testCaseContent { if harnessutil.GetConfigNameFromFileName(data.name) != "" { configFileName := tspath.GetNormalizedAbsolutePath(data.name, currentDirectory) path := tspath.ToPath(data.name, parseConfigHost.GetCurrentDirectory(), parseConfigHost.Vfs.UseCaseSensitiveFileNames()) - configJson := parser.ParseJSONText(configFileName, path, data.content) + configJson := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: configFileName, + Path: path, + }, data.content, core.ScriptKindJSON) tsConfigSourceFile := &tsoptions.TsConfigSourceFile{ SourceFile: configJson, } diff --git a/internal/testutil/harnessutil/harnessutil.go b/internal/testutil/harnessutil/harnessutil.go index f816bde694..acce099b89 100644 --- a/internal/testutil/harnessutil/harnessutil.go +++ b/internal/testutil/harnessutil/harnessutil.go @@ -23,7 +23,6 @@ import ( "github.com/microsoft/typescript-go/internal/outputpaths" "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/sourcemap" "github.com/microsoft/typescript-go/internal/testutil" "github.com/microsoft/typescript-go/internal/tsoptions" @@ -467,62 +466,42 @@ func getOptionValue(t *testing.T, option *tsoptions.CommandLineOption, value str type cachedCompilerHost struct { compiler.CompilerHost - options *core.CompilerOptions } var sourceFileCache collections.SyncMap[SourceFileCacheKey, *ast.SourceFile] type SourceFileCacheKey struct { - core.SourceFileAffectingCompilerOptions - ast.SourceFileMetaData - fileName string - path tspath.Path - text string + opts ast.SourceFileParseOptions + text string + scriptKind core.ScriptKind } -func GetSourceFileCacheKey( - fileName string, - path tspath.Path, - text string, - options *core.SourceFileAffectingCompilerOptions, - metadata *ast.SourceFileMetaData, -) SourceFileCacheKey { +func GetSourceFileCacheKey(opts ast.SourceFileParseOptions, text string, scriptKind core.ScriptKind) SourceFileCacheKey { return SourceFileCacheKey{ - SourceFileAffectingCompilerOptions: *options, - SourceFileMetaData: *metadata, - fileName: fileName, - path: path, - text: text, + opts: opts, + text: text, + scriptKind: scriptKind, } } -func (h *cachedCompilerHost) GetSourceFile(fileName string, path tspath.Path, options *core.SourceFileAffectingCompilerOptions, metadata *ast.SourceFileMetaData) *ast.SourceFile { - text, ok := h.FS().ReadFile(fileName) +func (h *cachedCompilerHost) GetSourceFile(opts ast.SourceFileParseOptions) *ast.SourceFile { + text, ok := h.FS().ReadFile(opts.FileName) if !ok { return nil } - key := GetSourceFileCacheKey( - fileName, - path, - text, - h.options.SourceFileAffecting(), - metadata, - ) + scriptKind := core.GetScriptKindFromFileName(opts.FileName) + if scriptKind == core.ScriptKindUnknown { + panic("Unknown script kind for file " + opts.FileName) + } + + key := GetSourceFileCacheKey(opts, text, scriptKind) if cached, ok := sourceFileCache.Load(key); ok { return cached } - // !!! dedupe with compiler.compilerHost - var sourceFile *ast.SourceFile - if tspath.FileExtensionIs(fileName, tspath.ExtensionJson) { - sourceFile = parser.ParseJSONText(fileName, path, text) - } else { - // !!! JSDocParsingMode - sourceFile = parser.ParseSourceFile(fileName, path, text, options, metadata, scanner.JSDocParsingModeParseAll) - } - + sourceFile := parser.ParseSourceFile(opts, text, scriptKind) result, _ := sourceFileCache.LoadOrStore(key, sourceFile) return result } @@ -530,7 +509,6 @@ func (h *cachedCompilerHost) GetSourceFile(fileName string, path tspath.Path, op func createCompilerHost(fs vfs.FS, defaultLibraryPath string, options *core.CompilerOptions, currentDirectory string) compiler.CompilerHost { return &cachedCompilerHost{ CompilerHost: compiler.NewCompilerHost(options, currentDirectory, fs, defaultLibraryPath, nil), - options: options, } } diff --git a/internal/testutil/parsetestutil/parsetestutil.go b/internal/testutil/parsetestutil/parsetestutil.go index 76833960d0..73fbc556ce 100644 --- a/internal/testutil/parsetestutil/parsetestutil.go +++ b/internal/testutil/parsetestutil/parsetestutil.go @@ -8,18 +8,22 @@ import ( "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/diagnosticwriter" "github.com/microsoft/typescript-go/internal/parser" - "github.com/microsoft/typescript-go/internal/scanner" "github.com/microsoft/typescript-go/internal/tspath" ) -var parseCompilerOptions = &core.SourceFileAffectingCompilerOptions{ +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(fileName, tspath.Path(fileName), text, parseCompilerOptions, nil, scanner.JSDocParsingModeParseNone) + file := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: fileName, + Path: tspath.Path(fileName), + CompilerOptions: parseCompilerOptions, + JSDocParsingMode: ast.JSDocParsingModeParseNone, + }, text, core.GetScriptKindFromFileName(fileName)) ast.SetParentInChildren(file.AsNode()) return file } diff --git a/internal/testutil/tsbaseline/js_emit_baseline.go b/internal/testutil/tsbaseline/js_emit_baseline.go index ea9d78be7a..5e29b07404 100644 --- a/internal/testutil/tsbaseline/js_emit_baseline.go +++ b/internal/testutil/tsbaseline/js_emit_baseline.go @@ -5,9 +5,9 @@ import ( "strings" "testing" + "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/baseline" "github.com/microsoft/typescript-go/internal/testutil/harnessutil" "github.com/microsoft/typescript-go/internal/tspath" @@ -61,14 +61,11 @@ func DoJSEmitBaseline( jsCode.WriteString("\r\n") } if len(result.Diagnostics) == 0 && strings.HasSuffix(file.UnitName, tspath.ExtensionJson) { - fileParseResult := parser.ParseSourceFile( - file.UnitName, - tspath.Path(file.UnitName), - file.Content, - options.SourceFileAffecting(), - nil, // TODO(jakebailey): need to grab this somehow? - scanner.JSDocParsingModeParseAll, - ) + fileParseResult := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: file.UnitName, + Path: tspath.Path(file.UnitName), + CompilerOptions: options.SourceFileAffecting(), + }, file.Content, core.ScriptKindJSON) if len(fileParseResult.Diagnostics()) > 0 { jsCode.WriteString(getErrorBaseline(t, []*harnessutil.TestFile{file}, fileParseResult.Diagnostics(), false /*pretty*/)) continue diff --git a/internal/transformers/commonjsmodule_test.go b/internal/transformers/commonjsmodule_test.go index 0fe35fe055..a62a3c4ff6 100644 --- a/internal/transformers/commonjsmodule_test.go +++ b/internal/transformers/commonjsmodule_test.go @@ -1031,17 +1031,16 @@ exports.a = a;`, } compilerOptions.Module = core.ModuleKindCommonJS - sourceFileAffecting := compilerOptions.SourceFileAffecting() file := parsetestutil.ParseTypeScript(rec.input, rec.jsx) parsetestutil.CheckDiagnostics(t, file) - binder.BindSourceFile(file, sourceFileAffecting) + binder.BindSourceFile(file) var other *ast.SourceFile if len(rec.other) > 0 { other = parsetestutil.ParseTypeScript(rec.other, rec.jsx) parsetestutil.CheckDiagnostics(t, other) - binder.BindSourceFile(other, sourceFileAffecting) + binder.BindSourceFile(other) } emitContext := printer.NewEmitContext() diff --git a/internal/transformers/esmodule_test.go b/internal/transformers/esmodule_test.go index 94e592978d..7c7c38b58f 100644 --- a/internal/transformers/esmodule_test.go +++ b/internal/transformers/esmodule_test.go @@ -224,16 +224,15 @@ var __rewriteRelativeImportExtension;`, compilerOptions = &core.CompilerOptions{} } - sourceFileAffecting := compilerOptions.SourceFileAffecting() file := parsetestutil.ParseTypeScript(rec.input, rec.jsx) parsetestutil.CheckDiagnostics(t, file) - binder.BindSourceFile(file, sourceFileAffecting) + binder.BindSourceFile(file) var other *ast.SourceFile if len(rec.other) > 0 { other = parsetestutil.ParseTypeScript(rec.other, rec.jsx) parsetestutil.CheckDiagnostics(t, other) - binder.BindSourceFile(other, sourceFileAffecting) + binder.BindSourceFile(other) } emitContext := printer.NewEmitContext() diff --git a/internal/transformers/importelision_test.go b/internal/transformers/importelision_test.go index 5bfc261266..c46aa9e037 100644 --- a/internal/transformers/importelision_test.go +++ b/internal/transformers/importelision_test.go @@ -104,7 +104,7 @@ func (p *fakeProgram) BindSourceFiles() { for _, file := range p.files { if !file.IsBound() { wg.Queue(func() { - binder.BindSourceFile(file, p.compilerOptions.SourceFileAffecting()) + binder.BindSourceFile(file) }) } } @@ -139,8 +139,8 @@ func (p *fakeProgram) GetSourceFileForResolvedModule(FileName string) *ast.Sourc return p.getSourceFileForResolvedModule(FileName) } -func (p *fakeProgram) GetSourceFileMetaData(path tspath.Path) *ast.SourceFileMetaData { - return nil +func (p *fakeProgram) GetSourceFileMetaData(path tspath.Path) ast.SourceFileMetaData { + return ast.SourceFileMetaData{} } func (p *fakeProgram) GetImportHelpersImportSpecifier(path tspath.Path) *ast.Node { diff --git a/internal/transformers/runtimesyntax_test.go b/internal/transformers/runtimesyntax_test.go index f102b5aec5..617d3bbb21 100644 --- a/internal/transformers/runtimesyntax_test.go +++ b/internal/transformers/runtimesyntax_test.go @@ -233,7 +233,7 @@ var E; options := &core.CompilerOptions{} file := parsetestutil.ParseTypeScript(rec.input, false /*jsx*/) parsetestutil.CheckDiagnostics(t, file) - binder.BindSourceFile(file, options.SourceFileAffecting()) + binder.BindSourceFile(file) emitContext := printer.NewEmitContext() resolver := binder.NewReferenceResolver(options, binder.ReferenceResolverHooks{}) emittestutil.CheckEmit(t, emitContext, NewRuntimeSyntaxTransformer(emitContext, options, resolver).TransformSourceFile(file), rec.output) @@ -411,7 +411,7 @@ func TestNamespaceTransformer(t *testing.T) { options := &core.CompilerOptions{} file := parsetestutil.ParseTypeScript(rec.input, false /*jsx*/) parsetestutil.CheckDiagnostics(t, file) - binder.BindSourceFile(file, options.SourceFileAffecting()) + binder.BindSourceFile(file) emitContext := printer.NewEmitContext() resolver := binder.NewReferenceResolver(options, binder.ReferenceResolverHooks{}) emittestutil.CheckEmit(t, emitContext, NewRuntimeSyntaxTransformer(emitContext, options, resolver).TransformSourceFile(file), rec.output) @@ -447,7 +447,7 @@ func TestParameterPropertyTransformer(t *testing.T) { options := &core.CompilerOptions{} file := parsetestutil.ParseTypeScript(rec.input, false /*jsx*/) parsetestutil.CheckDiagnostics(t, file) - binder.BindSourceFile(file, options.SourceFileAffecting()) + binder.BindSourceFile(file) emitContext := printer.NewEmitContext() resolver := binder.NewReferenceResolver(options, binder.ReferenceResolverHooks{}) file = NewTypeEraserTransformer(emitContext, options).TransformSourceFile(file) diff --git a/internal/tsoptions/tsconfigparsing.go b/internal/tsoptions/tsconfigparsing.go index 9cb90e150f..3128fa3cbc 100644 --- a/internal/tsoptions/tsconfigparsing.go +++ b/internal/tsoptions/tsconfigparsing.go @@ -252,7 +252,10 @@ func tsconfigToSourceFile(tsconfigSourceFile *TsConfigSourceFile) *ast.SourceFil } func NewTsconfigSourceFileFromFilePath(configFileName string, configPath tspath.Path, configSourceText string) *TsConfigSourceFile { - sourceFile := parser.ParseJSONText(configFileName, configPath, configSourceText) + sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: configFileName, + Path: configPath, + }, configSourceText, core.ScriptKindJSON) return &TsConfigSourceFile{ SourceFile: sourceFile, } @@ -624,7 +627,10 @@ func directoryOfCombinedPath(fileName string, basePath string) string { // fileName is the path to the config file // jsonText is the text of the config file func ParseConfigFileTextToJson(fileName string, path tspath.Path, jsonText string) (any, []*ast.Diagnostic) { - jsonSourceFile := parser.ParseJSONText(fileName, path, jsonText) + jsonSourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: fileName, + Path: path, + }, jsonText, core.ScriptKindJSON) config, errors := convertConfigFileToObject(jsonSourceFile /*jsonConversionNotifier*/, nil) if len(jsonSourceFile.Diagnostics()) > 0 { errors = []*ast.Diagnostic{jsonSourceFile.Diagnostics()[0]} @@ -876,11 +882,14 @@ func readJsonConfigFile(fileName string, path tspath.Path, readFile func(fileNam text, diagnostic := tryReadFile(fileName, readFile, []*ast.Diagnostic{}) if text != "" { return &TsConfigSourceFile{ - SourceFile: parser.ParseJSONText(fileName, path, text), + SourceFile: parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: fileName, + Path: path, + }, text, core.ScriptKindJSON), }, diagnostic } else { file := &TsConfigSourceFile{ - SourceFile: (&ast.NodeFactory{}).NewSourceFile("", fileName, path, nil).AsSourceFile(), + SourceFile: (&ast.NodeFactory{}).NewSourceFile(ast.SourceFileParseOptions{FileName: fileName, Path: path}, "", nil).AsSourceFile(), } file.SourceFile.SetDiagnostics(diagnostic) return file, diagnostic diff --git a/internal/tsoptions/tsconfigparsing_test.go b/internal/tsoptions/tsconfigparsing_test.go index 36fcb9b6d0..071dca0942 100644 --- a/internal/tsoptions/tsconfigparsing_test.go +++ b/internal/tsoptions/tsconfigparsing_test.go @@ -11,6 +11,7 @@ import ( "testing" "github.com/google/go-cmp/cmp/cmpopts" + "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/diagnosticwriter" "github.com/microsoft/typescript-go/internal/parser" @@ -590,7 +591,10 @@ func TestParseJsonSourceFileConfigFileContent(t *testing.T) { func getParsedWithJsonSourceFileApi(config testConfig, host tsoptions.ParseConfigHost, basePath string) *tsoptions.ParsedCommandLine { configFileName := tspath.GetNormalizedAbsolutePath(config.configFileName, basePath) path := tspath.ToPath(config.configFileName, basePath, host.FS().UseCaseSensitiveFileNames()) - parsed := parser.ParseJSONText(configFileName, path, config.jsonText) + parsed := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: configFileName, + Path: path, + }, config.jsonText, core.ScriptKindJSON) tsConfigSourceFile := &tsoptions.TsConfigSourceFile{ SourceFile: parsed, } @@ -808,7 +812,10 @@ func TestParseSrcCompiler(t *testing.T) { jsonText, ok := fs.ReadFile(tsconfigFileName) assert.Assert(t, ok) tsconfigPath := tspath.ToPath(tsconfigFileName, compilerDir, fs.UseCaseSensitiveFileNames()) - parsed := parser.ParseJSONText(tsconfigFileName, tsconfigPath, jsonText) + parsed := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: tsconfigFileName, + Path: tsconfigPath, + }, jsonText, core.ScriptKindJSON) if len(parsed.Diagnostics()) > 0 { for _, error := range parsed.Diagnostics() { @@ -975,7 +982,10 @@ func BenchmarkParseSrcCompiler(b *testing.B) { jsonText, ok := fs.ReadFile(tsconfigFileName) assert.Assert(b, ok) tsconfigPath := tspath.ToPath(tsconfigFileName, compilerDir, fs.UseCaseSensitiveFileNames()) - parsed := parser.ParseJSONText(tsconfigFileName, tsconfigPath, jsonText) + parsed := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: tsconfigFileName, + Path: tsconfigPath, + }, jsonText, core.ScriptKindJSON) b.ReportAllocs()