Skip to content

Commit 04a8564

Browse files
committed
Insert pnp in LSP and typecheck mode
1 parent 0e4dadc commit 04a8564

File tree

9 files changed

+262
-10
lines changed

9 files changed

+262
-10
lines changed

cmd/tsgo/sys.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import (
88

99
"github.com/microsoft/typescript-go/internal/bundled"
1010
"github.com/microsoft/typescript-go/internal/execute/tsc"
11+
"github.com/microsoft/typescript-go/internal/pnp"
1112
"github.com/microsoft/typescript-go/internal/tspath"
1213
"github.com/microsoft/typescript-go/internal/vfs"
1314
"github.com/microsoft/typescript-go/internal/vfs/osvfs"
15+
"github.com/microsoft/typescript-go/internal/vfs/pnpvfs"
1416
"golang.org/x/term"
1517
)
1618

@@ -66,9 +68,16 @@ func newSystem() *osSys {
6668
os.Exit(int(tsc.ExitStatusInvalidProject_OutputsSkipped))
6769
}
6870

71+
var fs vfs.FS = osvfs.FS()
72+
73+
pnpApi := pnp.InitPnpApi(fs, tspath.NormalizePath(cwd))
74+
if pnpApi != nil {
75+
fs = pnpvfs.From(fs)
76+
}
77+
6978
return &osSys{
7079
cwd: tspath.NormalizePath(cwd),
71-
fs: bundled.WrapFS(osvfs.FS()),
80+
fs: bundled.WrapFS(fs),
7281
defaultLibraryPath: bundled.LibPath(),
7382
writer: os.Stdout,
7483
start: time.Now(),

internal/api/server.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ import (
1515
"github.com/microsoft/typescript-go/internal/bundled"
1616
"github.com/microsoft/typescript-go/internal/core"
1717
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
18+
"github.com/microsoft/typescript-go/internal/pnp"
1819
"github.com/microsoft/typescript-go/internal/project"
1920
"github.com/microsoft/typescript-go/internal/project/logging"
2021
"github.com/microsoft/typescript-go/internal/vfs"
2122
"github.com/microsoft/typescript-go/internal/vfs/osvfs"
23+
"github.com/microsoft/typescript-go/internal/vfs/pnpvfs"
2224
)
2325

2426
//go:generate go tool golang.org/x/tools/cmd/stringer -type=MessageType -output=stringer_generated.go
@@ -93,12 +95,19 @@ func NewServer(options *ServerOptions) *Server {
9395
panic("Cwd is required")
9496
}
9597

98+
var fs vfs.FS = osvfs.FS()
99+
100+
pnpApi := pnp.InitPnpApi(fs, options.Cwd)
101+
if pnpApi != nil {
102+
fs = pnpvfs.From(fs)
103+
}
104+
96105
server := &Server{
97106
r: bufio.NewReader(options.In),
98107
w: bufio.NewWriter(options.Out),
99108
stderr: options.Err,
100109
cwd: options.Cwd,
101-
fs: bundled.WrapFS(osvfs.FS()),
110+
fs: bundled.WrapFS(fs),
102111
defaultLibraryPath: options.DefaultLibraryPath,
103112
}
104113
logger := logging.NewLogger(options.Err)

internal/core/compileroptions.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"sync"
77

88
"github.com/microsoft/typescript-go/internal/collections"
9+
"github.com/microsoft/typescript-go/internal/pnp"
910
"github.com/microsoft/typescript-go/internal/tspath"
1011
)
1112

@@ -316,6 +317,14 @@ func (options *CompilerOptions) GetEffectiveTypeRoots(currentDirectory string) (
316317
}
317318
}
318319

320+
nmTypes, nmFromConfig := options.GetNodeModulesTypeRoots(baseDir)
321+
322+
typeRoots, nmFromConfig := pnp.AppendPnpTypeRoots(nmTypes, baseDir, nmFromConfig)
323+
324+
return typeRoots, nmFromConfig
325+
}
326+
327+
func (options *CompilerOptions) GetNodeModulesTypeRoots(baseDir string) (result []string, fromConfig bool) {
319328
typeRoots := make([]string, 0, strings.Count(baseDir, "/"))
320329
tspath.ForEachAncestorDirectory(baseDir, func(dir string) (any, bool) {
321330
typeRoots = append(typeRoots, tspath.CombinePaths(dir, "node_modules", "@types"))

internal/ls/autoimports.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/microsoft/typescript-go/internal/module"
1919
"github.com/microsoft/typescript-go/internal/modulespecifiers"
2020
"github.com/microsoft/typescript-go/internal/packagejson"
21+
"github.com/microsoft/typescript-go/internal/pnp"
2122
"github.com/microsoft/typescript-go/internal/stringutil"
2223
"github.com/microsoft/typescript-go/internal/tspath"
2324
)
@@ -418,6 +419,11 @@ func (l *LanguageService) isImportable(
418419
// }
419420

420421
fromPath := fromFile.FileName()
422+
pnpApi := pnp.GetPnpApi(fromPath)
423+
if pnpApi != nil {
424+
return pnpApi.IsImportable(fromPath, toFile.FileName())
425+
}
426+
421427
useCaseSensitiveFileNames := moduleSpecifierResolutionHost.UseCaseSensitiveFileNames()
422428
globalTypingsCache := l.GetProgram().GetGlobalTypingsCacheLocation()
423429
modulePaths := modulespecifiers.GetEachFileNameOfModule(

internal/ls/string_completions.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,7 @@ func getStringLiteralCompletionsFromModuleNames(
522522
program *compiler.Program,
523523
) *stringLiteralCompletions {
524524
// !!! needs `getModeForUsageLocationWorker`
525+
// TODO investigate if we will need to update this for pnp, once available
525526
return nil
526527
}
527528

internal/lsp/server.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ import (
1616
"github.com/microsoft/typescript-go/internal/core"
1717
"github.com/microsoft/typescript-go/internal/ls"
1818
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
19+
"github.com/microsoft/typescript-go/internal/pnp"
1920
"github.com/microsoft/typescript-go/internal/project"
2021
"github.com/microsoft/typescript-go/internal/project/ata"
2122
"github.com/microsoft/typescript-go/internal/project/logging"
2223
"github.com/microsoft/typescript-go/internal/tspath"
2324
"github.com/microsoft/typescript-go/internal/vfs"
25+
"github.com/microsoft/typescript-go/internal/vfs/pnpvfs"
2426
"golang.org/x/sync/errgroup"
2527
"golang.org/x/text/language"
2628
)
@@ -699,6 +701,12 @@ func (s *Server) handleInitialized(ctx context.Context, params *lsproto.Initiali
699701
cwd = s.cwd
700702
}
701703

704+
fs := s.fs
705+
pnpApi := pnp.InitPnpApi(fs, cwd)
706+
if pnpApi != nil {
707+
fs = pnpvfs.From(fs)
708+
}
709+
702710
s.session = project.NewSession(&project.SessionInit{
703711
Options: &project.SessionOptions{
704712
CurrentDirectory: cwd,
@@ -709,7 +717,7 @@ func (s *Server) handleInitialized(ctx context.Context, params *lsproto.Initiali
709717
LoggingEnabled: true,
710718
DebounceDelay: 500 * time.Millisecond,
711719
},
712-
FS: s.fs,
720+
FS: fs,
713721
Logger: s.logger,
714722
Client: s,
715723
NpmExecutor: s,

internal/module/resolver.go

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/microsoft/typescript-go/internal/core"
1212
"github.com/microsoft/typescript-go/internal/diagnostics"
1313
"github.com/microsoft/typescript-go/internal/packagejson"
14+
"github.com/microsoft/typescript-go/internal/pnp"
1415
"github.com/microsoft/typescript-go/internal/semver"
1516
"github.com/microsoft/typescript-go/internal/tspath"
1617
)
@@ -474,7 +475,7 @@ func (r *resolutionState) resolveNodeLikeWorker() *ResolvedModule {
474475
resolved := r.nodeLoadModuleByRelativeName(r.extensions, candidate, false, true)
475476
return r.createResolvedModule(
476477
resolved,
477-
resolved != nil && strings.Contains(resolved.path, "/node_modules/"),
478+
resolved != nil && (tspath.IsExternalLibraryImport(resolved.path)),
478479
)
479480
}
480481
return r.createResolvedModule(nil, false)
@@ -913,6 +914,12 @@ func (r *resolutionState) loadModuleFromNearestNodeModulesDirectory(typesScopeOn
913914
}
914915

915916
func (r *resolutionState) loadModuleFromNearestNodeModulesDirectoryWorker(ext extensions, mode core.ResolutionMode, typesScopeOnly bool) *resolved {
917+
pnpApi := pnp.GetPnpApi(r.containingDirectory)
918+
if pnpApi != nil {
919+
// !!! stop at global cache
920+
return r.loadModuleFromImmediateNodeModulesDirectoryPnP(ext, r.containingDirectory, typesScopeOnly)
921+
}
922+
916923
result, _ := tspath.ForEachAncestorDirectory(
917924
r.containingDirectory,
918925
func(directory string) (result *resolved, stop bool) {
@@ -952,11 +959,52 @@ func (r *resolutionState) loadModuleFromImmediateNodeModulesDirectory(extensions
952959
return continueSearching()
953960
}
954961

962+
/*
963+
With Plug and Play, we directly resolve the path of the moduleName using the PnP API, instead of searching for it in the node_modules directory
964+
965+
See github.com/microsoft/typescript-go/internal/pnp package for more details
966+
*/
967+
func (r *resolutionState) loadModuleFromImmediateNodeModulesDirectoryPnP(extensions extensions, directory string, typesScopeOnly bool) *resolved {
968+
if !typesScopeOnly {
969+
if packageResult := r.loadModuleFromPnpResolution(extensions, r.name, directory); !packageResult.shouldContinueSearching() {
970+
return packageResult
971+
}
972+
}
973+
974+
if extensions&extensionsDeclaration != 0 {
975+
result := r.loadModuleFromPnpResolution(extensionsDeclaration, "@types/"+r.mangleScopedPackageName(r.name), directory)
976+
977+
return result
978+
}
979+
980+
return nil
981+
}
982+
983+
func (r *resolutionState) loadModuleFromPnpResolution(ext extensions, moduleName string, issuer string) *resolved {
984+
pnpApi := pnp.GetPnpApi(issuer)
985+
986+
if pnpApi != nil {
987+
packageName, rest := ParsePackageName(moduleName)
988+
// TODO: bubble up yarn resolution errors, instead of _
989+
packageDirectory, _ := pnpApi.ResolveToUnqualified(packageName, issuer)
990+
if packageDirectory != "" {
991+
candidate := tspath.NormalizePath(tspath.CombinePaths(packageDirectory, rest))
992+
return r.loadModuleFromSpecificNodeModulesDirectoryImpl(ext, true /* nodeModulesDirectoryExists */, candidate, rest, packageDirectory)
993+
}
994+
}
995+
996+
return nil
997+
}
998+
955999
func (r *resolutionState) loadModuleFromSpecificNodeModulesDirectory(ext extensions, moduleName string, nodeModulesDirectory string, nodeModulesDirectoryExists bool) *resolved {
9561000
candidate := tspath.NormalizePath(tspath.CombinePaths(nodeModulesDirectory, moduleName))
9571001
packageName, rest := ParsePackageName(moduleName)
9581002
packageDirectory := tspath.CombinePaths(nodeModulesDirectory, packageName)
9591003

1004+
return r.loadModuleFromSpecificNodeModulesDirectoryImpl(ext, nodeModulesDirectoryExists, candidate, rest, packageDirectory)
1005+
}
1006+
1007+
func (r *resolutionState) loadModuleFromSpecificNodeModulesDirectoryImpl(ext extensions, nodeModulesDirectoryExists bool, candidate string, rest string, packageDirectory string) *resolved {
9601008
var rootPackageInfo *packagejson.InfoCacheEntry
9611009
// First look for a nested package.json, as in `node_modules/foo/bar/package.json`
9621010
packageInfo := r.getPackageJsonInfo(candidate, !nodeModulesDirectoryExists)
@@ -1035,7 +1083,7 @@ func (r *resolutionState) loadModuleFromSpecificNodeModulesDirectory(ext extensi
10351083
}
10361084

10371085
func (r *resolutionState) createResolvedModuleHandlingSymlink(resolved *resolved) *ResolvedModule {
1038-
isExternalLibraryImport := resolved != nil && strings.Contains(resolved.path, "/node_modules/")
1086+
isExternalLibraryImport := resolved != nil && (tspath.IsExternalLibraryImport(resolved.path))
10391087
if r.compilerOptions.PreserveSymlinks != core.TSTrue &&
10401088
isExternalLibraryImport &&
10411089
resolved.originalPath == "" &&
@@ -1083,7 +1131,7 @@ func (r *resolutionState) createResolvedTypeReferenceDirective(resolved *resolve
10831131
resolvedTypeReferenceDirective.ResolvedFileName = resolved.path
10841132
resolvedTypeReferenceDirective.Primary = primary
10851133
resolvedTypeReferenceDirective.PackageId = resolved.packageId
1086-
resolvedTypeReferenceDirective.IsExternalLibraryImport = strings.Contains(resolved.path, "/node_modules/")
1134+
resolvedTypeReferenceDirective.IsExternalLibraryImport = tspath.IsExternalLibraryImport(resolved.path)
10871135

10881136
if r.compilerOptions.PreserveSymlinks != core.TSTrue {
10891137
originalPath, resolvedFileName := r.getOriginalAndResolvedFileName(resolved.path)
@@ -1739,8 +1787,19 @@ func (r *resolutionState) readPackageJsonPeerDependencies(packageJsonInfo *packa
17391787
}
17401788
nodeModules := packageDirectory[:nodeModulesIndex+len("/node_modules")] + "/"
17411789
builder := strings.Builder{}
1790+
pnpApi := pnp.GetPnpApi(packageJsonInfo.PackageDirectory)
17421791
for name := range peerDependencies.Value {
1743-
peerPackageJson := r.getPackageJsonInfo(nodeModules+name /*onlyRecordFailures*/, false)
1792+
var peerDependencyPath string
1793+
1794+
if pnpApi != nil {
1795+
peerDependencyPath, _ = pnpApi.ResolveToUnqualified(name, packageDirectory)
1796+
}
1797+
1798+
if peerDependencyPath == "" {
1799+
peerDependencyPath = nodeModules + name
1800+
}
1801+
1802+
peerPackageJson := r.getPackageJsonInfo(peerDependencyPath, false /*onlyRecordFailures*/)
17441803
if peerPackageJson != nil {
17451804
version := peerPackageJson.Contents.Version.Value
17461805
builder.WriteString("+")

0 commit comments

Comments
 (0)