@ttsc/wasm 0.28.4 → 0.28.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "schema": 1,
3
- "identity": "92d9b25262007347543905a8d01c409fafbf97f7fc1277adbcfacdc9c2463fcb",
3
+ "identity": "5b7306db740afa230fbfe61a2c809466a005338a77e31a76c93f1c5f79b58706",
4
4
  "artifacts": [
5
5
  {
6
6
  "path": "/home/runner/work/ttsc/ttsc/packages/wasm/dist/ttsc.wasm",
7
7
  "type": "file",
8
- "sha256": "65f224e0973f6cd1c459cd5ba6464e31377427412c5b681bbc67ab5d5e800c74"
8
+ "sha256": "d3a8605e1c83784bc750712706932ee94e25eccf2d481c82f0605014b27aa09d"
9
9
  },
10
10
  {
11
11
  "path": "/home/runner/work/ttsc/ttsc/packages/wasm/dist/wasm_exec.js",
@@ -147,7 +147,11 @@
147
147
  },
148
148
  {
149
149
  "path": "compiler/incremental.go",
150
- "sha256": "3c873bed3659cfe1969a97caea105d230dad510e66d8da6e4ca2c4dc6617a04c"
150
+ "sha256": "0fc791767af7c9013a555276179b38521df77a750e03b55f1af6cde3393847e4"
151
+ },
152
+ {
153
+ "path": "compiler/resolution.go",
154
+ "sha256": "8bb3b7e3e16d31286fd16212a9adf100501df1d250ecd0064521b38df01e62e8"
151
155
  },
152
156
  {
153
157
  "path": "compiler/shim.go",
@@ -171,7 +175,7 @@
171
175
  },
172
176
  {
173
177
  "path": "core/shim.go",
174
- "sha256": "a3cf692a939eade582138fbafd3e13352d72417830bd5d2db773a97892e6500f"
178
+ "sha256": "f81ceac2ae56764704b04cd7fbe190213e8d7f9a6d72e9085eb73dd69760e07f"
175
179
  },
176
180
  {
177
181
  "path": "diagnosticwriter/go.mod",
package/dist/ttsc.wasm CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttsc/wasm",
3
- "version": "0.28.4",
3
+ "version": "0.28.6",
4
4
  "description": "Build in-browser ttsc playgrounds. Compose ttsc + typescript-go with your own plugins via the Go host helper.",
5
5
  "main": "lib/src/index.js",
6
6
  "types": "lib/src/index.d.ts",
@@ -20,6 +20,7 @@ import (
20
20
  innerast "github.com/microsoft/typescript-go/internal/ast"
21
21
  "github.com/microsoft/typescript-go/internal/collections"
22
22
  innercompiler "github.com/microsoft/typescript-go/internal/compiler"
23
+ innertsoptions "github.com/microsoft/typescript-go/internal/tsoptions"
23
24
  "github.com/microsoft/typescript-go/internal/tspath"
24
25
 
25
26
  // Imported for EmitFreshWithBuildInfo below, and for the linknamed symbols
@@ -74,18 +75,69 @@ func incrementalFileAffectsGlobalScope(file *innerast.SourceFile) bool
74
75
  // The returned strings are tspath.Path values (case-canonicalized on
75
76
  // case-insensitive filesystems); map them back to real file names through
76
77
  // Program.GetSourceFileByPath when the original spelling matters.
78
+ // Extensionless path references are replaced with the source file Program
79
+ // actually loaded because the upstream incremental helper retains their raw
80
+ // directive path instead of the selected extension-bearing path.
77
81
  func GetReferencedFilePaths(program *Program, file *innerast.SourceFile) []string {
78
82
  set := incrementalGetReferencedFiles(program, file)
79
83
  if set == nil {
80
84
  return nil
81
85
  }
86
+ resolvedPathReferences := make(map[tspath.Path]tspath.Path, len(file.ReferencedFiles))
87
+ sourceDirectory := tspath.GetDirectoryPath(file.FileName())
88
+ for _, reference := range file.ReferencedFiles {
89
+ referencedFile := reference.FileName
90
+ if redirect := program.GetParseFileRedirect(referencedFile); redirect != "" {
91
+ referencedFile = redirect
92
+ }
93
+ rawPath := tspath.ToPath(referencedFile, sourceDirectory, program.UseCaseSensitiveFileNames())
94
+ if resolved := getSourceFileFromReference(program, file, reference); resolved != nil {
95
+ resolvedPathReferences[rawPath] = resolved.Path()
96
+ }
97
+ }
82
98
  out := make([]string, 0, set.Len())
99
+ seen := collections.Set[tspath.Path]{}
83
100
  for path := range set.Keys() {
101
+ if resolved := resolvedPathReferences[path]; resolved != "" {
102
+ path = resolved
103
+ }
104
+ if seen.Has(path) {
105
+ continue
106
+ }
107
+ seen.Add(path)
84
108
  out = append(out, string(path))
85
109
  }
86
110
  return out
87
111
  }
88
112
 
113
+ // getSourceFileFromReference extends TypeScript-Go's resident-file lookup with
114
+ // the virtual declaration outputs its project-reference filesystem accepts.
115
+ // The upstream helper cannot see an unbuilt output in Program.filesByPath, but
116
+ // the project-reference mapper retains the output-to-source redirect that made
117
+ // the reference valid while the Program was loaded.
118
+ func getSourceFileFromReference(program *Program, file *innerast.SourceFile, reference *innerast.FileReference) *innerast.SourceFile {
119
+ if resolved := program.GetSourceFileFromReference(file, reference); resolved != nil {
120
+ return resolved
121
+ }
122
+ referencedFile := tspath.ResolvePath(tspath.GetDirectoryPath(file.FileName()), reference.FileName)
123
+ if tspath.HasExtension(referencedFile) {
124
+ return nil
125
+ }
126
+ supportedExtensions := innertsoptions.GetSupportedExtensions(program.Options(), nil)
127
+ supportedExtensions = innertsoptions.GetSupportedExtensionsWithJsonIfResolveJsonModule(program.Options(), supportedExtensions)
128
+ for _, extension := range supportedExtensions[0] {
129
+ outputPath := tspath.ToPath(referencedFile+extension, program.GetCurrentDirectory(), program.UseCaseSensitiveFileNames())
130
+ redirect := program.GetProjectReferenceFromOutputDts(outputPath)
131
+ if redirect == nil {
132
+ continue
133
+ }
134
+ if source := program.GetSourceFile(redirect.Source); source != nil {
135
+ return source
136
+ }
137
+ }
138
+ return nil
139
+ }
140
+
89
141
  // FileAffectsGlobalScope reports whether editing `file` can change the global
90
142
  // scope: global-scope module augmentations, ambient declaration files, and
91
143
  // script (non-module) files. Mirrors the predicate tsgo's incremental engine
@@ -0,0 +1,444 @@
1
+ // gen_shims:hand-maintained
2
+
3
+ package compiler
4
+
5
+ import (
6
+ "strings"
7
+ "time"
8
+
9
+ "github.com/microsoft/typescript-go/internal/ast"
10
+ "github.com/microsoft/typescript-go/internal/collections"
11
+ "github.com/microsoft/typescript-go/internal/core"
12
+ "github.com/microsoft/typescript-go/internal/module"
13
+ "github.com/microsoft/typescript-go/internal/symlinks"
14
+ "github.com/microsoft/typescript-go/internal/tsoptions"
15
+ "github.com/microsoft/typescript-go/internal/tspath"
16
+ "github.com/microsoft/typescript-go/internal/vfs"
17
+ "github.com/microsoft/typescript-go/internal/vfs/cachedvfs"
18
+ )
19
+
20
+ // ProgramResolutionKind distinguishes module and type-reference resolution.
21
+ type ProgramResolutionKind uint8
22
+
23
+ const (
24
+ ProgramResolutionKindModule ProgramResolutionKind = iota
25
+ ProgramResolutionKindTypeReference
26
+ )
27
+
28
+ // ProgramResolutionTask is one resolution already performed by a resident
29
+ // Program. The exported fields provide deterministic host ordering while the
30
+ // unexported fields retain the exact compiler context needed for replay.
31
+ type ProgramResolutionTask struct {
32
+ ContainingFile string
33
+ Kind ProgramResolutionKind
34
+ Mode core.ResolutionMode
35
+ Name string
36
+ ResolvedFile string
37
+ SourceFile string
38
+ TargetFile string
39
+ Universal bool
40
+
41
+ compilerOptions *core.CompilerOptions
42
+ currentDirectory string
43
+ expected programResolutionResult
44
+ projectReferences *projectReferenceResolutionContext
45
+ redirectedReference module.ResolvedProjectReference
46
+ }
47
+
48
+ // ProgramResolutionTasks returns every cached module and type-reference
49
+ // resolution, including unresolved entries and automatic type directives.
50
+ func ProgramResolutionTasks(program *Program) []ProgramResolutionTask {
51
+ if program == nil {
52
+ return nil
53
+ }
54
+ projectReferences := newProjectReferenceResolutionContext(program)
55
+ tasks := []ProgramResolutionTask{}
56
+ appendTask := func(kind ProgramResolutionKind, name string, mode core.ResolutionMode, filePath tspath.Path, expected programResolutionResult) {
57
+ containingFile := string(filePath)
58
+ sourceFile := ""
59
+ targetFile := ""
60
+ var redirectedReference module.ResolvedProjectReference
61
+ if source := program.GetSourceFileByPath(filePath); source != nil {
62
+ sourceFile = source.FileName()
63
+ redirectedReference, containingFile = programResolutionContext(program, source)
64
+ }
65
+ if target := program.GetSourceFileForResolvedModule(expected.resolvedFileName); target != nil {
66
+ targetFile = target.FileName()
67
+ }
68
+ tasks = append(tasks, ProgramResolutionTask{
69
+ ContainingFile: containingFile,
70
+ Kind: kind,
71
+ Mode: mode,
72
+ Name: name,
73
+ ResolvedFile: expected.resolvedFileName,
74
+ SourceFile: sourceFile,
75
+ TargetFile: targetFile,
76
+ Universal: strings.HasSuffix(containingFile, module.InferredTypesContainingFile),
77
+ compilerOptions: program.Options(),
78
+ currentDirectory: program.GetCurrentDirectory(),
79
+ expected: expected,
80
+ projectReferences: projectReferences,
81
+ redirectedReference: redirectedReference,
82
+ })
83
+ }
84
+ program.ForEachResolvedModule(func(resolution *module.ResolvedModule, name string, mode core.ResolutionMode, filePath tspath.Path) {
85
+ appendTask(ProgramResolutionKindModule, name, mode, filePath, moduleResolutionResult(resolution))
86
+ }, nil)
87
+ program.ForEachResolvedTypeReferenceDirective(func(resolution *module.ResolvedTypeReferenceDirective, name string, mode core.ResolutionMode, filePath tspath.Path) {
88
+ appendTask(ProgramResolutionKindTypeReference, name, mode, filePath, typeReferenceResolutionResult(resolution))
89
+ }, nil)
90
+ return tasks
91
+ }
92
+
93
+ // programResolutionContext mirrors projectReferenceFileMapper's containing
94
+ // file substitution using the public Program maps. The selected source path is
95
+ // part of resolution semantics, not merely diagnostic provenance.
96
+ func programResolutionContext(program *Program, source ast.HasFileName) (module.ResolvedProjectReference, string) {
97
+ if redirected := program.GetProjectReferenceFromSource(source.Path()); redirected != nil {
98
+ return redirected.Resolved, redirected.Source
99
+ }
100
+ if redirected := program.GetProjectReferenceFromOutputDts(source.Path()); redirected != nil {
101
+ return redirected.Resolved, redirected.Source
102
+ }
103
+ redirect := program.GetRedirectForResolution(source)
104
+ if redirect == nil {
105
+ return nil, source.FileName()
106
+ }
107
+ // The remaining redirect form is a preserved node_modules symlink whose
108
+ // physical declaration belongs to a project reference. Resolve the same
109
+ // physical key the compiler mapper used and retain the original source name.
110
+ realpath := program.Host().FS().Realpath(source.FileName())
111
+ path := tspath.ToPath(realpath, program.GetCurrentDirectory(), program.UseCaseSensitiveFileNames())
112
+ if redirected := program.GetProjectReferenceFromOutputDts(path); redirected != nil {
113
+ return redirected.Resolved, redirected.Source
114
+ }
115
+ // A concurrent retarget can make the public lookup disappear after the
116
+ // resident redirect was cached. Keep the redirect so replay necessarily
117
+ // disagrees with the resident result or its observed identity proof fails.
118
+ return redirect, source.FileName()
119
+ }
120
+
121
+ // ReplayProgramResolutions resolves one source's tasks with one fresh upstream
122
+ // resolver and reports whether every result still matches the resident Program.
123
+ func ReplayProgramResolutions(tasks []ProgramResolutionTask, filesystem vfs.FS) bool {
124
+ if len(tasks) == 0 || filesystem == nil || tasks[0].compilerOptions == nil {
125
+ return false
126
+ }
127
+ first := tasks[0]
128
+ host := resolutionHost{
129
+ filesystem: first.projectReferences.filesystem(filesystem),
130
+ currentDirectory: first.currentDirectory,
131
+ }
132
+ resolver := module.NewResolver(host, first.compilerOptions, "", "")
133
+ matches := true
134
+ for _, task := range tasks {
135
+ var actual programResolutionResult
136
+ switch task.Kind {
137
+ case ProgramResolutionKindModule:
138
+ resolution, _ := resolver.ResolveModuleName(task.Name, task.ContainingFile, task.Mode, task.redirectedReference)
139
+ actual = moduleResolutionResult(resolution)
140
+ case ProgramResolutionKindTypeReference:
141
+ resolution, _ := resolver.ResolveTypeReferenceDirective(task.Name, task.ContainingFile, task.Mode, task.redirectedReference)
142
+ actual = typeReferenceResolutionResult(resolution)
143
+ default:
144
+ matches = false
145
+ continue
146
+ }
147
+ if actual != task.expected {
148
+ matches = false
149
+ }
150
+ }
151
+ return matches
152
+ }
153
+
154
+ // projectReferenceResolutionContext snapshots the immutable metadata needed to
155
+ // recreate fileLoader's project-reference declaration view for every replay
156
+ // filesystem. A referenced output declaration may be absent on disk while its
157
+ // source exists; the resolver must see the virtual declaration before Program
158
+ // substitutes that source into the loaded graph.
159
+ type projectReferenceResolutionContext struct {
160
+ currentDirectory string
161
+ dtsDirectories collections.Set[tspath.Path]
162
+ outputDtsToProjectReference map[tspath.Path]*tsoptions.SourceOutputAndProjectReference
163
+ }
164
+
165
+ func newProjectReferenceResolutionContext(program *Program) *projectReferenceResolutionContext {
166
+ if program == nil {
167
+ return nil
168
+ }
169
+ outputDtsToProjectReference := map[tspath.Path]*tsoptions.SourceOutputAndProjectReference{}
170
+ dtsDirectories := collections.Set[tspath.Path]{}
171
+ useSourceOfProjectReference := false
172
+ program.RangeResolvedProjectReference(func(_ tspath.Path, config *tsoptions.ParsedCommandLine, _ *tsoptions.ParsedCommandLine, _ int) bool {
173
+ if config == nil {
174
+ return true
175
+ }
176
+ config.ParseInputOutputNames()
177
+ for path := range config.SourceToProjectReference() {
178
+ useSourceOfProjectReference = useSourceOfProjectReference || program.IsSourceFromProjectReference(path)
179
+ }
180
+ for path, reference := range config.OutputDtsToProjectReference() {
181
+ outputDtsToProjectReference[path] = reference
182
+ }
183
+ declarationDirectory := config.CompilerOptions().DeclarationDir
184
+ if declarationDirectory == "" {
185
+ declarationDirectory = config.CompilerOptions().OutDir
186
+ }
187
+ if declarationDirectory != "" {
188
+ dtsDirectories.Add(tspath.ToPath(declarationDirectory, program.GetCurrentDirectory(), program.UseCaseSensitiveFileNames()))
189
+ }
190
+ return true
191
+ })
192
+ if !useSourceOfProjectReference || len(outputDtsToProjectReference) == 0 {
193
+ return nil
194
+ }
195
+ return &projectReferenceResolutionContext{
196
+ currentDirectory: program.GetCurrentDirectory(),
197
+ dtsDirectories: dtsDirectories,
198
+ outputDtsToProjectReference: outputDtsToProjectReference,
199
+ }
200
+ }
201
+
202
+ func (context *projectReferenceResolutionContext) filesystem(filesystem vfs.FS) vfs.FS {
203
+ if context == nil || filesystem == nil {
204
+ return filesystem
205
+ }
206
+ return cachedvfs.From(&projectReferenceResolutionFS{
207
+ filesystem: filesystem,
208
+ currentDirectory: context.currentDirectory,
209
+ dtsDirectories: context.dtsDirectories,
210
+ knownSymlinks: symlinks.KnownSymlinks{},
211
+ outputDtsToProjectReference: context.outputDtsToProjectReference,
212
+ })
213
+ }
214
+
215
+ // projectReferenceResolutionFS mirrors TypeScript-Go's
216
+ // projectReferenceDtsFakingVfs over the caller's observation filesystem.
217
+ type projectReferenceResolutionFS struct {
218
+ filesystem vfs.FS
219
+ currentDirectory string
220
+ dtsDirectories collections.Set[tspath.Path]
221
+ knownSymlinks symlinks.KnownSymlinks
222
+ outputDtsToProjectReference map[tspath.Path]*tsoptions.SourceOutputAndProjectReference
223
+ }
224
+
225
+ var _ vfs.FS = (*projectReferenceResolutionFS)(nil)
226
+
227
+ func (fs *projectReferenceResolutionFS) UseCaseSensitiveFileNames() bool {
228
+ return fs.filesystem.UseCaseSensitiveFileNames()
229
+ }
230
+
231
+ func (fs *projectReferenceResolutionFS) FileExists(path string) bool {
232
+ if fs.filesystem.FileExists(path) {
233
+ return true
234
+ }
235
+ if !tspath.IsDeclarationFileName(path) {
236
+ return false
237
+ }
238
+ return fs.fileOrDirectoryExistsUsingSource(path, true)
239
+ }
240
+
241
+ func (fs *projectReferenceResolutionFS) ReadFile(path string) (string, bool) {
242
+ return fs.filesystem.ReadFile(path)
243
+ }
244
+
245
+ func (fs *projectReferenceResolutionFS) WriteFile(string, string) error {
246
+ panic("should not be called by resolver")
247
+ }
248
+
249
+ func (fs *projectReferenceResolutionFS) AppendFile(string, string) error {
250
+ panic("should not be called by resolver")
251
+ }
252
+
253
+ func (fs *projectReferenceResolutionFS) Remove(string) error {
254
+ panic("should not be called by resolver")
255
+ }
256
+
257
+ func (fs *projectReferenceResolutionFS) Chtimes(string, time.Time, time.Time) error {
258
+ panic("should not be called by resolver")
259
+ }
260
+
261
+ func (fs *projectReferenceResolutionFS) DirectoryExists(path string) bool {
262
+ if fs.filesystem.DirectoryExists(path) {
263
+ fs.handleDirectoryCouldBeSymlink(path)
264
+ return true
265
+ }
266
+ return fs.fileOrDirectoryExistsUsingSource(path, false)
267
+ }
268
+
269
+ func (fs *projectReferenceResolutionFS) GetAccessibleEntries(string) vfs.Entries {
270
+ panic("should not be called by resolver")
271
+ }
272
+
273
+ func (fs *projectReferenceResolutionFS) Stat(string) vfs.FileInfo {
274
+ panic("should not be called by resolver")
275
+ }
276
+
277
+ func (fs *projectReferenceResolutionFS) WalkDir(string, vfs.WalkDirFunc) error {
278
+ panic("should not be called by resolver")
279
+ }
280
+
281
+ func (fs *projectReferenceResolutionFS) Realpath(path string) string {
282
+ if result, ok := fs.knownSymlinks.Files().Load(fs.toPath(path)); ok {
283
+ return result
284
+ }
285
+ return fs.filesystem.Realpath(path)
286
+ }
287
+
288
+ func (fs *projectReferenceResolutionFS) toPath(path string) tspath.Path {
289
+ return tspath.ToPath(path, fs.currentDirectory, fs.UseCaseSensitiveFileNames())
290
+ }
291
+
292
+ func (fs *projectReferenceResolutionFS) handleDirectoryCouldBeSymlink(directory string) {
293
+ if tspath.ContainsIgnoredPath(directory) || !strings.Contains(directory, "/node_modules/") {
294
+ return
295
+ }
296
+ directoryPath := tspath.Path(tspath.EnsureTrailingDirectorySeparator(string(fs.toPath(directory))))
297
+ if _, ok := fs.knownSymlinks.Directories().Load(directoryPath); ok {
298
+ return
299
+ }
300
+ realDirectory := fs.Realpath(directory)
301
+ if realDirectory == directory {
302
+ return
303
+ }
304
+ realPath := tspath.Path(tspath.EnsureTrailingDirectorySeparator(string(fs.toPath(realDirectory))))
305
+ if realPath == directoryPath {
306
+ return
307
+ }
308
+ fs.knownSymlinks.SetDirectory(directory, directoryPath, &symlinks.KnownDirectoryLink{
309
+ Real: tspath.EnsureTrailingDirectorySeparator(realDirectory),
310
+ RealPath: realPath,
311
+ })
312
+ }
313
+
314
+ func (fs *projectReferenceResolutionFS) fileOrDirectoryExistsUsingSource(fileOrDirectory string, isFile bool) bool {
315
+ existence := fs.directoryExistsIfProjectReferenceDeclarationDirectory
316
+ if isFile {
317
+ existence = fs.fileExistsIfProjectReferenceDeclaration
318
+ }
319
+ result := existence(fileOrDirectory)
320
+ if result != core.TSUnknown {
321
+ return result == core.TSTrue
322
+ }
323
+ knownDirectoryLinks := fs.knownSymlinks.Directories()
324
+ if knownDirectoryLinks.Size() == 0 {
325
+ return false
326
+ }
327
+ fileOrDirectoryPath := fs.toPath(fileOrDirectory)
328
+ if !strings.Contains(string(fileOrDirectoryPath), "/node_modules/") {
329
+ return false
330
+ }
331
+ if isFile {
332
+ if _, ok := fs.knownSymlinks.Files().Load(fileOrDirectoryPath); ok {
333
+ return true
334
+ }
335
+ }
336
+ exists := false
337
+ knownDirectoryLinks.Range(func(directoryPath tspath.Path, knownDirectoryLink *symlinks.KnownDirectoryLink) bool {
338
+ relative, hasPrefix := strings.CutPrefix(string(fileOrDirectoryPath), string(directoryPath))
339
+ if !hasPrefix {
340
+ return true
341
+ }
342
+ if exists = existence(string(knownDirectoryLink.RealPath) + relative).IsTrue(); !exists {
343
+ return true
344
+ }
345
+ if isFile {
346
+ absolutePath := tspath.GetNormalizedAbsolutePath(fileOrDirectory, fs.currentDirectory)
347
+ fs.knownSymlinks.SetFile(
348
+ absolutePath,
349
+ fileOrDirectoryPath,
350
+ knownDirectoryLink.Real+absolutePath[len(directoryPath):],
351
+ )
352
+ }
353
+ return false
354
+ })
355
+ return exists
356
+ }
357
+
358
+ func (fs *projectReferenceResolutionFS) fileExistsIfProjectReferenceDeclaration(file string) core.Tristate {
359
+ reference := fs.outputDtsToProjectReference[fs.toPath(file)]
360
+ if reference == nil {
361
+ return core.TSUnknown
362
+ }
363
+ return core.IfElse(fs.filesystem.FileExists(reference.Source), core.TSTrue, core.TSFalse)
364
+ }
365
+
366
+ func (fs *projectReferenceResolutionFS) directoryExistsIfProjectReferenceDeclarationDirectory(directory string) core.Tristate {
367
+ directoryPath := fs.toPath(directory)
368
+ directoryPathWithSeparator := directoryPath + "/"
369
+ for declarationDirectoryPath := range fs.dtsDirectories.Keys() {
370
+ if directoryPath == declarationDirectoryPath || strings.HasPrefix(string(declarationDirectoryPath), string(directoryPathWithSeparator)) || strings.HasPrefix(string(directoryPath), string(declarationDirectoryPath)+"/") {
371
+ return core.TSTrue
372
+ }
373
+ }
374
+ return core.TSUnknown
375
+ }
376
+
377
+ // ReplayAutomaticTypeDirectiveDiscovery repeats the compiler's exact wildcard
378
+ // type-root enumeration over filesystem so a host can observe its inputs.
379
+ func ReplayAutomaticTypeDirectiveDiscovery(program *Program, filesystem vfs.FS) {
380
+ if program == nil || filesystem == nil || program.Options() == nil {
381
+ return
382
+ }
383
+ module.GetAutomaticTypeDirectiveNames(program.Options(), resolutionHost{
384
+ filesystem: filesystem,
385
+ currentDirectory: program.GetCurrentDirectory(),
386
+ })
387
+ }
388
+
389
+ type resolutionHost struct {
390
+ filesystem vfs.FS
391
+ currentDirectory string
392
+ }
393
+
394
+ func (host resolutionHost) FS() vfs.FS { return host.filesystem }
395
+
396
+ func (host resolutionHost) GetCurrentDirectory() string { return host.currentDirectory }
397
+
398
+ type programResolutionResult struct {
399
+ alternateResult string
400
+ extension string
401
+ isExternalLibraryImport bool
402
+ originalPath string
403
+ packageName string
404
+ packagePeerDependencies string
405
+ packageSubModuleName string
406
+ packageVersion string
407
+ primary bool
408
+ resolvedFileName string
409
+ resolvedUsingTsExtension bool
410
+ }
411
+
412
+ func moduleResolutionResult(resolution *module.ResolvedModule) programResolutionResult {
413
+ if resolution == nil {
414
+ return programResolutionResult{}
415
+ }
416
+ return programResolutionResult{
417
+ alternateResult: resolution.AlternateResult,
418
+ extension: resolution.Extension,
419
+ isExternalLibraryImport: resolution.IsExternalLibraryImport,
420
+ originalPath: resolution.OriginalPath,
421
+ packageName: resolution.PackageId.Name,
422
+ packagePeerDependencies: resolution.PackageId.PeerDependencies,
423
+ packageSubModuleName: resolution.PackageId.SubModuleName,
424
+ packageVersion: resolution.PackageId.Version,
425
+ resolvedFileName: resolution.ResolvedFileName,
426
+ resolvedUsingTsExtension: resolution.ResolvedUsingTsExtension,
427
+ }
428
+ }
429
+
430
+ func typeReferenceResolutionResult(resolution *module.ResolvedTypeReferenceDirective) programResolutionResult {
431
+ if resolution == nil {
432
+ return programResolutionResult{}
433
+ }
434
+ return programResolutionResult{
435
+ isExternalLibraryImport: resolution.IsExternalLibraryImport,
436
+ originalPath: resolution.OriginalPath,
437
+ packageName: resolution.PackageId.Name,
438
+ packagePeerDependencies: resolution.PackageId.PeerDependencies,
439
+ packageSubModuleName: resolution.PackageId.SubModuleName,
440
+ packageVersion: resolution.PackageId.Version,
441
+ primary: resolution.Primary,
442
+ resolvedFileName: resolution.ResolvedFileName,
443
+ }
444
+ }
@@ -6,7 +6,10 @@
6
6
  // primitives without exposing the full internal surface.
7
7
  package core
8
8
 
9
- import innercore "github.com/microsoft/typescript-go/internal/core"
9
+ import (
10
+ innercore "github.com/microsoft/typescript-go/internal/core"
11
+ innersemver "github.com/microsoft/typescript-go/internal/semver"
12
+ )
10
13
 
11
14
  // CompilerOptions holds the parsed tsconfig compiler options passed to the
12
15
  // TypeScript-Go program host.
@@ -96,6 +99,17 @@ const (
96
99
  // consumer can tell which checker resolved the facts it is reading.
97
100
  func Version() string { return innercore.Version() }
98
101
 
102
+ // TypeScriptVersionSatisfiesRange reports whether the compiler's own version
103
+ // satisfies a typesVersions range under TypeScript-Go's semver grammar.
104
+ func TypeScriptVersionSatisfiesRange(text string) bool {
105
+ versionRange, ok := innersemver.TryParseVersionRange(text)
106
+ if !ok {
107
+ return false
108
+ }
109
+ version, err := innersemver.TryParseVersion(innercore.Version())
110
+ return err == nil && versionRange.Test(&version)
111
+ }
112
+
99
113
  // ComputeECMALineStarts applies the compiler's LF, CRLF, CR, LS, and PS line
100
114
  // model to UTF-8 source text.
101
115
  func ComputeECMALineStarts(text string) ECMALineStarts {