Skip to content
6 changes: 6 additions & 0 deletions internal/compiler/emitHost.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,9 @@ func (host *emitHost) GetEmitResolver(file *ast.SourceFile, skipDiagnostics bool
defer done()
return checker.GetEmitResolver(file, skipDiagnostics)
}

func (host *emitHost) IsSourceFileFromExternalLibrary(file *ast.SourceFile) bool {
// Use the Program's proper tracking mechanism which mirrors the TypeScript implementation
// This tracks files that were found while searching node_modules during module resolution
return host.program.IsSourceFileFromExternalLibrary(file)
}
6 changes: 1 addition & 5 deletions internal/compiler/emitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package compiler

import (
"encoding/base64"
"strings"

"github.com/microsoft/typescript-go/internal/ast"
"github.com/microsoft/typescript-go/internal/core"
Expand Down Expand Up @@ -305,10 +304,7 @@ func sourceFileMayBeEmitted(sourceFile *ast.SourceFile, host printer.EmitHost, f
return false
}

// !!! Source file from node_modules are not emitted. In Strada, this depends on module resolution and uses
// `sourceFilesFoundSearchingNodeModules` in `createProgram`. For now, we will just check for `/node_modules/` in
// the file name.
if strings.Contains(sourceFile.FileName(), "/node_modules/") {
if host.IsSourceFileFromExternalLibrary(sourceFile) {
return false
}

Expand Down
51 changes: 34 additions & 17 deletions internal/compiler/fileloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ type processedFiles struct {
importHelpersImportSpecifiers map[tspath.Path]*ast.Node
// List of present unsupported extensions
unsupportedExtensions []string
// Track which source files were found while searching node_modules
// Similar to TypeScript's sourceFilesFoundSearchingNodeModules map
sourceFilesFoundSearchingNodeModules map[tspath.Path]bool
}

type jsxRuntimeImportSpecifier struct {
Expand Down Expand Up @@ -111,6 +114,7 @@ func processAllProgramFiles(
var jsxRuntimeImportSpecifiers map[tspath.Path]*jsxRuntimeImportSpecifier
var importHelpersImportSpecifiers map[tspath.Path]*ast.Node
var unsupportedExtensions []string
var sourceFilesFoundSearchingNodeModules map[tspath.Path]bool

loader.parseTasks.collect(&loader, loader.rootTasks, func(task *parseTask, _ []tspath.Path) {
file := task.file
Expand Down Expand Up @@ -148,22 +152,30 @@ func processAllProgramFiles(
if slices.Contains(tspath.SupportedJSExtensionsFlat, extension) {
unsupportedExtensions = core.AppendIfUnique(unsupportedExtensions, extension)
}
// Track files from external libraries using the proper module resolution flag
if task.isFromExternalLibrary {
if sourceFilesFoundSearchingNodeModules == nil {
sourceFilesFoundSearchingNodeModules = make(map[tspath.Path]bool, totalFileCount)
}
sourceFilesFoundSearchingNodeModules[path] = true
}
})
loader.sortLibs(libFiles)

allFiles := append(libFiles, files...)

return processedFiles{
resolver: loader.resolver,
files: allFiles,
filesByPath: filesByPath,
projectReferenceFileMapper: loader.projectReferenceFileMapper,
resolvedModules: resolvedModules,
typeResolutionsInFile: typeResolutionsInFile,
sourceFileMetaDatas: sourceFileMetaDatas,
jsxRuntimeImportSpecifiers: jsxRuntimeImportSpecifiers,
importHelpersImportSpecifiers: importHelpersImportSpecifiers,
unsupportedExtensions: unsupportedExtensions,
resolver: loader.resolver,
files: allFiles,
filesByPath: filesByPath,
projectReferenceFileMapper: loader.projectReferenceFileMapper,
resolvedModules: resolvedModules,
typeResolutionsInFile: typeResolutionsInFile,
sourceFileMetaDatas: sourceFileMetaDatas,
jsxRuntimeImportSpecifiers: jsxRuntimeImportSpecifiers,
importHelpersImportSpecifiers: importHelpersImportSpecifiers,
unsupportedExtensions: unsupportedExtensions,
sourceFilesFoundSearchingNodeModules: sourceFilesFoundSearchingNodeModules,
}
}

Expand Down Expand Up @@ -301,7 +313,10 @@ func (p *fileLoader) resolveTripleslashPathReference(moduleName string, containi
referencedFileName = tspath.CombinePaths(basePath, moduleName)
}
return resolvedRef{
fileName: tspath.NormalizePath(referencedFileName),
fileName: tspath.NormalizePath(referencedFileName),
increaseDepth: false,
elideOnDepth: false,
isFromExternalLibrary: false, // Triple-slash references are always local files
}
}

Expand All @@ -319,9 +334,10 @@ func (p *fileLoader) resolveTypeReferenceDirectives(file *ast.SourceFile, meta a
typeResolutionsInFile[module.ModeAwareCacheKey{Name: ref.FileName, Mode: resolutionMode}] = resolved
if resolved.IsResolved() {
toParse = append(toParse, resolvedRef{
fileName: resolved.ResolvedFileName,
increaseDepth: resolved.IsExternalLibraryImport,
elideOnDepth: false,
fileName: resolved.ResolvedFileName,
increaseDepth: resolved.IsExternalLibraryImport,
elideOnDepth: false,
isFromExternalLibrary: resolved.IsExternalLibraryImport,
})
}
}
Expand Down Expand Up @@ -412,9 +428,10 @@ func (p *fileLoader) resolveImportsAndModuleAugmentations(file *ast.SourceFile,

if shouldAddFile {
toParse = append(toParse, resolvedRef{
fileName: resolvedFileName,
increaseDepth: resolvedModule.IsExternalLibraryImport,
elideOnDepth: isJsFileFromNodeModules,
fileName: resolvedFileName,
increaseDepth: resolvedModule.IsExternalLibraryImport,
elideOnDepth: isJsFileFromNodeModules,
isFromExternalLibrary: isFromNodeModulesSearch,
})
}
}
Expand Down
19 changes: 15 additions & 4 deletions internal/compiler/parsetask.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ type parseTask struct {
jsxRuntimeImportSpecifier *jsxRuntimeImportSpecifier
increaseDepth bool
elideOnDepth bool

// Track if this file is from an external library (node_modules)
// This mirrors the TypeScript currentNodeModulesDepth > 0 check
isFromExternalLibrary bool
}

func (t *parseTask) FileName() string {
Expand Down Expand Up @@ -98,14 +102,21 @@ func (t *parseTask) redirect(loader *fileLoader, fileName string) {
}

type resolvedRef struct {
fileName string
increaseDepth bool
elideOnDepth bool
fileName string
increaseDepth bool
elideOnDepth bool
isFromExternalLibrary bool
}

func (t *parseTask) addSubTask(ref resolvedRef, isLib bool) {
normalizedFilePath := tspath.NormalizePath(ref.fileName)
subTask := &parseTask{normalizedFilePath: normalizedFilePath, isLib: isLib, increaseDepth: ref.increaseDepth, elideOnDepth: ref.elideOnDepth}
subTask := &parseTask{
normalizedFilePath: normalizedFilePath,
isLib: isLib,
increaseDepth: ref.increaseDepth,
elideOnDepth: ref.elideOnDepth,
isFromExternalLibrary: ref.isFromExternalLibrary || t.isFromExternalLibrary, // Propagate external library status
}
t.subTasks = append(t.subTasks, subTask)
}

Expand Down
31 changes: 26 additions & 5 deletions internal/compiler/program.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
commonSourceDirectoryOnce sync.Once

declarationDiagnosticCache collections.SyncMap[*ast.SourceFile, []*ast.Diagnostic]

sourceFilesFoundSearchingNodeModules collections.SyncMap[tspath.Path, bool]
}

// FileExists implements checker.Program.
Expand Down Expand Up @@ -203,6 +205,14 @@

p.processedFiles = processAllProgramFiles(p.opts, libs, p.singleThreaded())

// Populate sourceFilesFoundSearchingNodeModules from the processed files
// This mirrors the TypeScript implementation's tracking behavior
if p.processedFiles.sourceFilesFoundSearchingNodeModules != nil {
for path, isExternal := range p.processedFiles.sourceFilesFoundSearchingNodeModules {
p.sourceFilesFoundSearchingNodeModules.Store(path, isExternal)
}
}

return p
}

Expand All @@ -215,11 +225,12 @@
return NewProgram(p.opts), false
}
result := &Program{
opts: p.opts,
nodeModules: p.nodeModules,
comparePathsOptions: p.comparePathsOptions,
processedFiles: p.processedFiles,
usesUriStyleNodeCoreModules: p.usesUriStyleNodeCoreModules,
opts: p.opts,
nodeModules: p.nodeModules,
comparePathsOptions: p.comparePathsOptions,
processedFiles: p.processedFiles,
usesUriStyleNodeCoreModules: p.usesUriStyleNodeCoreModules,
sourceFilesFoundSearchingNodeModules: p.sourceFilesFoundSearchingNodeModules,

Check failure on line 233 in internal/compiler/program.go

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

copylocks: literal copies lock value from p.sourceFilesFoundSearchingNodeModules: github.com/microsoft/typescript-go/internal/collections.SyncMap[github.com/microsoft/typescript-go/internal/tspath.Path, bool] contains sync.Map contains sync.noCopy (govet)
}
result.initCheckerPool()
index := core.FindIndex(result.files, func(file *ast.SourceFile) bool { return file.Path() == newFile.Path() })
Expand Down Expand Up @@ -820,6 +831,16 @@
return p.GetDefaultResolutionModeForFile(sourceFile)
}

// IsSourceFileFromExternalLibrary returns true if the source file is from an external library.
// This mirrors the TypeScript implementation which tracks files found while searching node_modules.
func (p *Program) IsSourceFileFromExternalLibrary(file *ast.SourceFile) bool {
if file == nil {
return false
}
isExternal, exists := p.sourceFilesFoundSearchingNodeModules.Load(file.Path())
return exists && isExternal
}

type FileIncludeKind int

const (
Expand Down
1 change: 1 addition & 0 deletions internal/printer/emithost.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ type EmitHost interface {
GetEmitModuleFormatOfFile(file ast.HasFileName) core.ModuleKind
GetEmitResolver(file *ast.SourceFile, skipDiagnostics bool) EmitResolver
GetOutputAndProjectReference(path tspath.Path) *tsoptions.OutputDtsAndProjectReference
IsSourceFileFromExternalLibrary(file *ast.SourceFile) bool
}
1 change: 1 addition & 0 deletions internal/project/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,7 @@ func (p *Project) GetFileNames(excludeFilesFromExternalLibraries bool, excludeCo
result := []string{}
sourceFiles := p.program.GetSourceFiles()
for _, sourceFile := range sourceFiles {
// !! This is probably ready to be implemented now?
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because we have IsSourceFileFromExternalLibrary

// if excludeFilesFromExternalLibraries && p.program.IsSourceFileFromExternalLibrary(sourceFile) {
// continue;
// }
Expand Down
Loading