Skip to content

Commit 90a49a3

Browse files
authored
Project references in a program (#1078)
1 parent 393f055 commit 90a49a3

File tree

54 files changed

+2577
-626
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2577
-626
lines changed

internal/api/api.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ type API struct {
2929
host APIHost
3030
options APIOptions
3131

32-
documentRegistry *project.DocumentRegistry
33-
scriptInfosMu sync.RWMutex
34-
scriptInfos map[tspath.Path]*project.ScriptInfo
32+
documentRegistry *project.DocumentRegistry
33+
scriptInfosMu sync.RWMutex
34+
scriptInfos map[tspath.Path]*project.ScriptInfo
35+
configFileRegistry *project.ConfigFileRegistry
3536

3637
projects handleMap[project.Project]
3738
filesMu sync.Mutex
@@ -65,6 +66,9 @@ func NewAPI(host APIHost, options APIOptions) *API {
6566
},
6667
},
6768
}
69+
api.configFileRegistry = &project.ConfigFileRegistry{
70+
Host: api,
71+
}
6872
return api
6973
}
7074

@@ -83,6 +87,11 @@ func (api *API) DocumentRegistry() *project.DocumentRegistry {
8387
return api.documentRegistry
8488
}
8589

90+
// ConfigFileRegistry implements ProjectHost.
91+
func (api *API) ConfigFileRegistry() *project.ConfigFileRegistry {
92+
return api.configFileRegistry
93+
}
94+
8695
// FS implements ProjectHost.
8796
func (api *API) FS() vfs.FS {
8897
return api.host.FS()

internal/ast/utilities.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3589,3 +3589,23 @@ func IsTrivia(token Kind) bool {
35893589
func HasDecorators(node *Node) bool {
35903590
return HasSyntacticModifier(node, ModifierFlagsDecorator)
35913591
}
3592+
3593+
type hasFileNameImpl struct {
3594+
fileName string
3595+
path tspath.Path
3596+
}
3597+
3598+
func NewHasFileName(fileName string, path tspath.Path) HasFileName {
3599+
return &hasFileNameImpl{
3600+
fileName: fileName,
3601+
path: path,
3602+
}
3603+
}
3604+
3605+
func (h *hasFileNameImpl) FileName() string {
3606+
return h.fileName
3607+
}
3608+
3609+
func (h *hasFileNameImpl) Path() tspath.Path {
3610+
return h.path
3611+
}

internal/checker/checker.go

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/microsoft/typescript-go/internal/printer"
2626
"github.com/microsoft/typescript-go/internal/scanner"
2727
"github.com/microsoft/typescript-go/internal/stringutil"
28+
"github.com/microsoft/typescript-go/internal/tsoptions"
2829
"github.com/microsoft/typescript-go/internal/tspath"
2930
)
3031

@@ -527,6 +528,7 @@ type Program interface {
527528
BindSourceFiles()
528529
FileExists(fileName string) bool
529530
GetSourceFile(fileName string) *ast.SourceFile
531+
GetSourceFileForResolvedModule(fileName string) *ast.SourceFile
530532
GetEmitModuleFormatOfFile(sourceFile ast.HasFileName) core.ModuleKind
531533
GetEmitSyntaxForUsageLocation(sourceFile ast.HasFileName, usageLocation *ast.StringLiteralLike) core.ResolutionMode
532534
GetImpliedNodeFormatForEmit(sourceFile ast.HasFileName) core.ModuleKind
@@ -535,6 +537,8 @@ type Program interface {
535537
GetSourceFileMetaData(path tspath.Path) *ast.SourceFileMetaData
536538
GetJSXRuntimeImportSpecifier(path tspath.Path) (moduleReference string, specifier *ast.Node)
537539
GetImportHelpersImportSpecifier(path tspath.Path) *ast.Node
540+
IsSourceFromProjectReference(path tspath.Path) bool
541+
GetSourceAndProjectReference(path tspath.Path) *tsoptions.SourceAndProjectReference
538542
}
539543

540544
type Host interface {
@@ -2086,7 +2090,7 @@ func (c *Checker) getSymbol(symbols ast.SymbolTable, name string, meaning ast.Sy
20862090
}
20872091

20882092
func (c *Checker) CheckSourceFile(ctx context.Context, sourceFile *ast.SourceFile) {
2089-
if SkipTypeChecking(sourceFile, c.compilerOptions) {
2093+
if SkipTypeChecking(sourceFile, c.compilerOptions, c.program) {
20902094
return
20912095
}
20922096
c.checkSourceFile(ctx, sourceFile)
@@ -6462,15 +6466,13 @@ func (c *Checker) checkAliasSymbol(node *ast.Node) {
64626466
// in files that are unambiguously CommonJS in this mode.
64636467
c.error(node, diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_module_is_set_to_preserve)
64646468
}
6465-
// !!!
6466-
6467-
// if c.compilerOptions.VerbatimModuleSyntax.IsTrue() && !ast.IsTypeOnlyImportOrExportDeclaration(node) && node.Flags&ast.NodeFlagsAmbient == 0 && targetFlags&ast.SymbolFlagsConstEnum != 0 {
6468-
// constEnumDeclaration := target.ValueDeclaration
6469-
// redirect := host.getRedirectReferenceForResolutionFromSourceOfProject(ast.GetSourceFileOfNode(constEnumDeclaration).ResolvedPath)
6470-
// if constEnumDeclaration.Flags&ast.NodeFlagsAmbient != 0 && (redirect == nil || !shouldPreserveConstEnums(redirect.commandLine.options)) {
6471-
// c.error(node, diagnostics.Cannot_access_ambient_const_enums_when_0_is_enabled, c.getIsolatedModulesLikeFlagName())
6472-
// }
6473-
// }
6469+
if c.compilerOptions.VerbatimModuleSyntax.IsTrue() && !ast.IsTypeOnlyImportOrExportDeclaration(node) && node.Flags&ast.NodeFlagsAmbient == 0 && targetFlags&ast.SymbolFlagsConstEnum != 0 {
6470+
constEnumDeclaration := target.ValueDeclaration
6471+
redirect := c.program.GetSourceAndProjectReference(ast.GetSourceFileOfNode(constEnumDeclaration).Path())
6472+
if constEnumDeclaration.Flags&ast.NodeFlagsAmbient != 0 && (redirect == nil || !redirect.Resolved.CompilerOptions().ShouldPreserveConstEnums()) {
6473+
c.error(node, diagnostics.Cannot_access_ambient_const_enums_when_0_is_enabled, c.getIsolatedModulesLikeFlagName())
6474+
}
6475+
}
64746476
}
64756477
if ast.IsImportSpecifier(node) {
64766478
targetSymbol := c.resolveAliasWithDeprecationCheck(symbol, node)
@@ -7184,15 +7186,14 @@ func (c *Checker) checkConstEnumAccess(node *ast.Node, t *Type) {
71847186
// --verbatimModuleSyntax only gets checked here when the enum usage does not
71857187
// resolve to an import, because imports of ambient const enums get checked
71867188
// separately in `checkAliasSymbol`.
7187-
// !!!
7188-
// if c.compilerOptions.IsolatedModules.IsTrue() || c.compilerOptions.VerbatimModuleSyntax.IsTrue() && ok && c.resolveName(node, getFirstIdentifier(node).Text(), ast.SymbolFlagsAlias, nil, false, true) == nil {
7189-
// // Debug.assert(t.symbol.Flags&ast.SymbolFlagsConstEnum != 0)
7190-
// constEnumDeclaration := t.symbol.ValueDeclaration
7191-
// redirect := host.getRedirectReferenceForResolutionFromSourceOfProject(ast.GetSourceFileOfNode(constEnumDeclaration).ResolvedPath)
7192-
// if constEnumDeclaration.Flags&ast.NodeFlagsAmbient != 0 && !isValidTypeOnlyAliasUseSite(node) && (redirect == nil || !shouldPreserveConstEnums(redirect.commandLine.options)) {
7193-
// c.error(node, diagnostics.Cannot_access_ambient_const_enums_when_0_is_enabled, c.getIsolatedModulesLikeFlagName())
7194-
// }
7195-
// }
7189+
if c.compilerOptions.IsolatedModules.IsTrue() || c.compilerOptions.VerbatimModuleSyntax.IsTrue() && ok && c.resolveName(node, ast.GetFirstIdentifier(node).Text(), ast.SymbolFlagsAlias, nil, false, true) == nil {
7190+
// Debug.assert(t.symbol.Flags&ast.SymbolFlagsConstEnum != 0)
7191+
constEnumDeclaration := t.symbol.ValueDeclaration
7192+
redirect := c.program.GetSourceAndProjectReference(ast.GetSourceFileOfNode(constEnumDeclaration).Path())
7193+
if constEnumDeclaration.Flags&ast.NodeFlagsAmbient != 0 && !ast.IsValidTypeOnlyAliasUseSite(node) && (redirect == nil || !redirect.Resolved.CompilerOptions().ShouldPreserveConstEnums()) {
7194+
c.error(node, diagnostics.Cannot_access_ambient_const_enums_when_0_is_enabled, c.getIsolatedModulesLikeFlagName())
7195+
}
7196+
}
71967197
}
71977198

71987199
func (c *Checker) instantiateTypeWithSingleGenericCallSignature(node *ast.Node, t *Type, checkMode CheckMode) *Type {
@@ -14467,7 +14468,7 @@ func (c *Checker) resolveExternalModule(location *ast.Node, moduleReference stri
1446714468
var sourceFile *ast.SourceFile
1446814469
resolvedModule := c.program.GetResolvedModule(importingSourceFile, moduleReference, mode)
1446914470
if resolvedModule.IsResolved() {
14470-
sourceFile = c.program.GetSourceFile(resolvedModule.ResolvedFileName)
14471+
sourceFile = c.program.GetSourceFileForResolvedModule(resolvedModule.ResolvedFileName)
1447114472
}
1447214473

1447314474
if sourceFile != nil {
@@ -14573,6 +14574,21 @@ func (c *Checker) resolveExternalModule(location *ast.Node, moduleReference stri
1457314574
}
1457414575

1457514576
if moduleNotFoundError != nil {
14577+
14578+
// See if this was possibly a projectReference redirect
14579+
if resolvedModule.IsResolved() {
14580+
redirect := c.program.GetOutputAndProjectReference(tspath.ToPath(resolvedModule.ResolvedFileName, c.program.GetCurrentDirectory(), c.program.UseCaseSensitiveFileNames()))
14581+
if redirect != nil && redirect.OutputDts != "" {
14582+
c.error(
14583+
errorNode,
14584+
diagnostics.Output_file_0_has_not_been_built_from_source_file_1,
14585+
redirect.OutputDts,
14586+
resolvedModule.ResolvedFileName,
14587+
)
14588+
return nil
14589+
}
14590+
}
14591+
1457614592
// !!!
1457714593
isExtensionlessRelativePathImport := tspath.PathIsRelative(moduleReference) && !tspath.HasExtension(moduleReference)
1457814594
resolutionIsNode16OrNext := c.moduleResolutionKind == core.ModuleResolutionKindNode16 || c.moduleResolutionKind == core.ModuleResolutionKindNodeNext

internal/checker/checker_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ foo.bar;`
3636
fs = bundled.WrapFS(fs)
3737

3838
cd := "/"
39-
host := compiler.NewCompilerHost(nil, cd, fs, bundled.LibPath())
39+
host := compiler.NewCompilerHost(nil, cd, fs, bundled.LibPath(), nil)
4040

4141
parsed, errors := tsoptions.GetParsedCommandLineOfConfigFile("/tsconfig.json", &core.CompilerOptions{}, host, nil)
4242
assert.Equal(t, len(errors), 0, "Expected no errors in parsed command line")
@@ -70,7 +70,7 @@ func TestCheckSrcCompiler(t *testing.T) {
7070

7171
rootPath := tspath.CombinePaths(tspath.NormalizeSlashes(repo.TypeScriptSubmodulePath), "src", "compiler")
7272

73-
host := compiler.NewCompilerHost(nil, rootPath, fs, bundled.LibPath())
73+
host := compiler.NewCompilerHost(nil, rootPath, fs, bundled.LibPath(), nil)
7474
parsed, errors := tsoptions.GetParsedCommandLineOfConfigFile(tspath.CombinePaths(rootPath, "tsconfig.json"), &core.CompilerOptions{}, host, nil)
7575
assert.Equal(t, len(errors), 0, "Expected no errors in parsed command line")
7676
p := compiler.NewProgram(compiler.ProgramOptions{
@@ -87,7 +87,7 @@ func BenchmarkNewChecker(b *testing.B) {
8787

8888
rootPath := tspath.CombinePaths(tspath.NormalizeSlashes(repo.TypeScriptSubmodulePath), "src", "compiler")
8989

90-
host := compiler.NewCompilerHost(nil, rootPath, fs, bundled.LibPath())
90+
host := compiler.NewCompilerHost(nil, rootPath, fs, bundled.LibPath(), nil)
9191
parsed, errors := tsoptions.GetParsedCommandLineOfConfigFile(tspath.CombinePaths(rootPath, "tsconfig.json"), &core.CompilerOptions{}, host, nil)
9292
assert.Equal(b, len(errors), 0, "Expected no errors in parsed command line")
9393
p := compiler.NewProgram(compiler.ProgramOptions{

internal/checker/utilities.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1471,10 +1471,11 @@ func forEachYieldExpression(body *ast.Node, visitor func(expr *ast.Node)) {
14711471
traverse(body)
14721472
}
14731473

1474-
func SkipTypeChecking(sourceFile *ast.SourceFile, options *core.CompilerOptions) bool {
1474+
func SkipTypeChecking(sourceFile *ast.SourceFile, options *core.CompilerOptions, host Program) bool {
14751475
return options.NoCheck.IsTrue() ||
14761476
options.SkipLibCheck.IsTrue() && sourceFile.IsDeclarationFile ||
14771477
options.SkipDefaultLibCheck.IsTrue() && sourceFile.HasNoDefaultLib ||
1478+
host.IsSourceFromProjectReference(sourceFile.Path()) ||
14781479
!canIncludeBindAndCheckDiagnostics(sourceFile, options)
14791480
}
14801481

internal/compiler/emitHost.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/microsoft/typescript-go/internal/outputpaths"
1111
"github.com/microsoft/typescript-go/internal/printer"
1212
"github.com/microsoft/typescript-go/internal/transformers/declarations"
13+
"github.com/microsoft/typescript-go/internal/tsoptions"
1314
"github.com/microsoft/typescript-go/internal/tspath"
1415
)
1516

@@ -73,18 +74,14 @@ func (host *emitHost) GetPackageJsonInfo(pkgJsonPath string) modulespecifiers.Pa
7374
return host.program.GetPackageJsonInfo(pkgJsonPath)
7475
}
7576

76-
func (host *emitHost) GetProjectReferenceRedirect(path string) string {
77-
return host.program.GetProjectReferenceRedirect(path)
77+
func (host *emitHost) GetOutputAndProjectReference(path tspath.Path) *tsoptions.OutputDtsAndProjectReference {
78+
return host.program.GetOutputAndProjectReference(path)
7879
}
7980

8081
func (host *emitHost) GetRedirectTargets(path tspath.Path) []string {
8182
return host.program.GetRedirectTargets(path)
8283
}
8384

84-
func (host *emitHost) IsSourceOfProjectReferenceRedirect(path string) bool {
85-
return host.program.IsSourceOfProjectReferenceRedirect(path)
86-
}
87-
8885
func (host *emitHost) GetEffectiveDeclarationFlags(node *ast.Node, flags ast.ModifierFlags) ast.ModifierFlags {
8986
return host.GetEmitResolver(ast.GetSourceFileOfNode(node), true).GetEffectiveDeclarationFlags(node, flags)
9087
}

internal/compiler/emitter.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,10 @@ func sourceFileMayBeEmitted(sourceFile *ast.SourceFile, host printer.EmitHost, f
317317
return true
318318
}
319319

320-
// !!! Source files from referenced projects are not emitted
320+
// Source files from referenced projects are not emitted
321+
if host.GetOutputAndProjectReference(sourceFile.Path()) != nil {
322+
return false
323+
}
321324

322325
// Any non json file should be emitted
323326
if !ast.IsJsonSourceFile(sourceFile) {

0 commit comments

Comments
 (0)