ttsc 0.26.1 → 0.27.0
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.
- package/README.md +10 -1
- package/cmd/ttsc/api_transform.go +17 -3
- package/cmd/ttscgraph/auxiliary_identity_state_tracks_retargets_not_source_contents_test.go +85 -0
- package/cmd/ttscgraph/disk_realpath_other.go +16 -0
- package/cmd/ttscgraph/disk_realpath_windows.go +56 -0
- package/cmd/ttscgraph/serve.go +104 -35
- package/driver/diagnostics_preamble.go +284 -0
- package/driver/emit_plugin.go +71 -19
- package/driver/graph.go +64 -11
- package/driver/input_observation.go +273 -0
- package/driver/input_observation_test.go +149 -0
- package/driver/plugins.go +384 -4
- package/driver/program.go +81 -15
- package/driver/resolution_candidates.go +13 -5
- package/driver/rewrite.go +47 -4
- package/internal/graph/diagnostics.go +4 -3
- package/internal/graph/provenance.go +10 -1
- package/lib/TtscCompiler.d.ts +12 -11
- package/lib/TtscCompiler.js +44 -29
- package/lib/TtscCompiler.js.map +1 -1
- package/lib/compiler/internal/captureProcessOutput.js +2 -2
- package/lib/compiler/internal/captureProcessOutput.js.map +1 -1
- package/lib/compiler/internal/compileProjectInMemory.js +11 -3
- package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
- package/lib/compiler/internal/resolveEmittedJavaScript.d.ts +2 -0
- package/lib/compiler/internal/resolveEmittedJavaScript.js +3 -0
- package/lib/compiler/internal/resolveEmittedJavaScript.js.map +1 -1
- package/lib/compiler/internal/runBuild.d.ts +29 -1
- package/lib/compiler/internal/runBuild.js +117 -32
- package/lib/compiler/internal/runBuild.js.map +1 -1
- package/lib/compiler/internal/runSingleFileEmit.js +9 -2
- package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
- package/lib/compiler/internal/sharedHostHelpers.d.ts +28 -0
- package/lib/compiler/internal/sharedHostHelpers.js +39 -0
- package/lib/compiler/internal/sharedHostHelpers.js.map +1 -1
- package/lib/compiler/internal/startResidentTransform.js +12 -4
- package/lib/compiler/internal/startResidentTransform.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.d.ts +3 -0
- package/lib/compiler/internal/transformProjectInMemory.js +239 -35
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/flags/schema.js +33 -5
- package/lib/flags/schema.js.map +1 -1
- package/lib/internal/createCanonicalTempDirectory.d.ts +17 -0
- package/lib/internal/createCanonicalTempDirectory.js +42 -0
- package/lib/internal/createCanonicalTempDirectory.js.map +1 -0
- package/lib/internal/projectInputPathIdentity.d.ts +3 -0
- package/lib/internal/projectInputPathIdentity.js +11 -5
- package/lib/internal/projectInputPathIdentity.js.map +1 -1
- package/lib/internal/resolveNodeBinary.d.ts +14 -0
- package/lib/internal/resolveNodeBinary.js +150 -0
- package/lib/internal/resolveNodeBinary.js.map +1 -0
- package/lib/internal/resolveSafeCacheCleanupTargets.d.ts +15 -0
- package/lib/internal/resolveSafeCacheCleanupTargets.js +61 -0
- package/lib/internal/resolveSafeCacheCleanupTargets.js.map +1 -0
- package/lib/launcher/internal/assertNoSolutionBuild.d.ts +31 -0
- package/lib/launcher/internal/assertNoSolutionBuild.js +38 -0
- package/lib/launcher/internal/assertNoSolutionBuild.js.map +1 -0
- package/lib/launcher/internal/prepareExecution.d.ts +3 -0
- package/lib/launcher/internal/prepareExecution.js +73 -26
- package/lib/launcher/internal/prepareExecution.js.map +1 -1
- package/lib/launcher/internal/runTtsc.js +27 -13
- package/lib/launcher/internal/runTtsc.js.map +1 -1
- package/lib/launcher/internal/runTtscserver.js +18 -3
- package/lib/launcher/internal/runTtscserver.js.map +1 -1
- package/lib/launcher/internal/runTtsx.js +4 -0
- package/lib/launcher/internal/runTtsx.js.map +1 -1
- package/lib/launcher/internal/runtimeHooks.d.ts +37 -1
- package/lib/launcher/internal/runtimeHooks.js +660 -62
- package/lib/launcher/internal/runtimeHooks.js.map +1 -1
- package/lib/plugin/internal/buildSourcePlugin.d.ts +62 -8
- package/lib/plugin/internal/buildSourcePlugin.js +754 -72
- package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/loadProjectPlugins.d.ts +17 -5
- package/lib/plugin/internal/loadProjectPlugins.js +1339 -77
- package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
- package/lib/register.d.ts +1 -0
- package/lib/register.js +46 -0
- package/lib/register.js.map +1 -0
- package/lib/structures/ITtscCompilerContext.d.ts +6 -3
- package/lib/structures/ITtscCompilerTransformation.d.ts +31 -0
- package/lib/structures/ITtscPlugin.d.ts +33 -0
- package/package.json +16 -9
- package/shim/checker/go.mod +9 -0
- package/shim/checker/go.sum +22 -0
- package/shim/checker/shim.go +75 -0
- package/shim/compiler/emit_sourcemap.go +56 -15
- package/shim/compiler/incremental.go +45 -8
- package/src/TtscCompiler.ts +55 -33
- package/src/compiler/internal/captureProcessOutput.ts +3 -2
- package/src/compiler/internal/compileProjectInMemory.ts +11 -3
- package/src/compiler/internal/resolveEmittedJavaScript.ts +6 -0
- package/src/compiler/internal/runBuild.ts +172 -36
- package/src/compiler/internal/runSingleFileEmit.ts +9 -2
- package/src/compiler/internal/sharedHostHelpers.ts +44 -0
- package/src/compiler/internal/startResidentTransform.ts +12 -3
- package/src/compiler/internal/transformProjectInMemory.ts +410 -39
- package/src/flags/schema.ts +35 -5
- package/src/internal/createCanonicalTempDirectory.ts +53 -0
- package/src/internal/projectInputPathIdentity.ts +17 -4
- package/src/internal/resolveNodeBinary.ts +173 -0
- package/src/internal/resolveSafeCacheCleanupTargets.ts +85 -0
- package/src/launcher/internal/assertNoSolutionBuild.ts +40 -0
- package/src/launcher/internal/prepareExecution.ts +78 -26
- package/src/launcher/internal/runTtsc.ts +26 -13
- package/src/launcher/internal/runTtscserver.ts +18 -3
- package/src/launcher/internal/runTtsx.ts +4 -0
- package/src/launcher/internal/runtimeHooks.ts +830 -66
- package/src/plugin/internal/buildSourcePlugin.ts +984 -79
- package/src/plugin/internal/loadProjectPlugins.ts +1718 -104
- package/src/register.ts +47 -0
- package/src/structures/ITtscCompilerContext.ts +6 -3
- package/src/structures/ITtscCompilerTransformation.ts +39 -0
- package/src/structures/ITtscPlugin.ts +36 -0
- package/tools/shim_audit/baseline.json +0 -1
- package/utility/host.go +9 -3
- package/lib/internal/assertSafeExplicitCacheDirectory.d.ts +0 -5
- package/lib/internal/assertSafeExplicitCacheDirectory.js +0 -26
- package/lib/internal/assertSafeExplicitCacheDirectory.js.map +0 -1
- package/src/internal/assertSafeExplicitCacheDirectory.ts +0 -29
package/README.md
CHANGED
|
@@ -30,6 +30,15 @@ npx ttsc --watch # rebuild on save
|
|
|
30
30
|
|
|
31
31
|
`ttsx` runs a file the way `tsx` or `ts-node` does, but it type-checks the whole project first, so a type error stops the run before anything executes.
|
|
32
32
|
|
|
33
|
+
Preload the same checked runtime when Node or a test runner owns the process:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
node --require ttsc/register src/index.ts
|
|
37
|
+
mocha --require ttsc/register --extension ts,tsx "test/**/*.ts"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`ttsc/register` discovers the nearest `tsconfig.json` for each TypeScript root, applies its plugins, and refuses to execute when the project does not type-check.
|
|
41
|
+
|
|
33
42
|
That covers the CLI. The integrations each have a short guide:
|
|
34
43
|
|
|
35
44
|
- [`@ttsc/unplugin`](https://ttsc.dev/docs/setup/unplugin): Vite, Rollup, Rolldown, esbuild, webpack, Rspack, Next.js, Turbopack, Farm, and Bun.
|
|
@@ -38,7 +47,7 @@ That covers the CLI. The integrations each have a short guide:
|
|
|
38
47
|
|
|
39
48
|
## Lint
|
|
40
49
|
|
|
41
|
-
Lint and format inside the type-check you already run. 720+ rules across 21 families, plus a formatter
|
|
50
|
+
Lint and format inside the type-check you already run. 720+ rules across 21 families, plus a formatter whose rules are ported from Prettier 3.8.3 — see the [format guide](https://ttsc.dev/docs/lint/format) for the shapes it covers and the ones it leaves alone.
|
|
42
51
|
|
|
43
52
|
```ts
|
|
44
53
|
// src/index.ts
|
|
@@ -26,6 +26,11 @@ type apiTransformResult struct {
|
|
|
26
26
|
// content can influence a transformed module, so bundler caches invalidate
|
|
27
27
|
// soundly without per-plugin reporting.
|
|
28
28
|
Graph *driver.TransformGraph `json:"graph,omitempty"`
|
|
29
|
+
// HostInputs are absolute native plugin config files evaluated while this
|
|
30
|
+
// generation loaded. JavaScript hosts merge them with descriptor inputs.
|
|
31
|
+
HostInputs []string `json:"hostInputs,omitempty"`
|
|
32
|
+
HostInputHashes map[string]*string `json:"hostInputHashes,omitempty"`
|
|
33
|
+
HostInputRealpaths map[string]*string `json:"hostInputRealpaths,omitempty"`
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
// runAPITransform implements the `api-transform` sub-command. It loads the
|
|
@@ -70,6 +75,9 @@ func runAPITransform(args []string) int {
|
|
|
70
75
|
}
|
|
71
76
|
typescript := map[string]string{}
|
|
72
77
|
var graph *driver.TransformGraph
|
|
78
|
+
var hostInputs []string
|
|
79
|
+
var hostInputHashes map[string]*string
|
|
80
|
+
var hostInputRealpaths map[string]*string
|
|
73
81
|
if prog != nil {
|
|
74
82
|
defer prog.Close()
|
|
75
83
|
// Compute the reference graph before SourceFiles() runs linked plugin
|
|
@@ -81,12 +89,18 @@ func runAPITransform(args []string) int {
|
|
|
81
89
|
typescript[apiOutputKey(cwd, file.FileName())] = file.Text()
|
|
82
90
|
}
|
|
83
91
|
diags = append(diags, prog.Diagnostics()...)
|
|
92
|
+
hostInputs = prog.PluginHostInputs()
|
|
93
|
+
hostInputHashes = prog.PluginHostInputHashes()
|
|
94
|
+
hostInputRealpaths = prog.PluginHostInputRealpaths()
|
|
84
95
|
}
|
|
85
96
|
|
|
86
97
|
result := apiTransformResult{
|
|
87
|
-
Diagnostics:
|
|
88
|
-
|
|
89
|
-
|
|
98
|
+
Diagnostics: make([]apiCompileDiagnostic, 0, len(diags)),
|
|
99
|
+
Graph: graph,
|
|
100
|
+
HostInputs: hostInputs,
|
|
101
|
+
HostInputHashes: hostInputHashes,
|
|
102
|
+
HostInputRealpaths: hostInputRealpaths,
|
|
103
|
+
TypeScript: typescript,
|
|
90
104
|
}
|
|
91
105
|
for _, diag := range diags {
|
|
92
106
|
result.Diagnostics = append(result.Diagnostics, toAPICompileDiagnostic(diag))
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
"os/exec"
|
|
6
|
+
"path/filepath"
|
|
7
|
+
"runtime"
|
|
8
|
+
"testing"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// TestAuxiliaryIdentityStateTracksRetargetsNotSourceContents proves the two
|
|
12
|
+
// owners of a selected lexical module path stay separate:
|
|
13
|
+
//
|
|
14
|
+
// 1. ordinary source bytes are owned by graphSession.sourceHashes, so an
|
|
15
|
+
// identity-only auxiliary state must not turn their edit into a reload;
|
|
16
|
+
// 2. retargeting the same lexical symlink or junction must invalidate even
|
|
17
|
+
// when the old and new target bytes agree.
|
|
18
|
+
func TestAuxiliaryIdentityStateTracksRetargetsNotSourceContents(t *testing.T) {
|
|
19
|
+
root := t.TempDir()
|
|
20
|
+
first := filepath.Join(root, "first")
|
|
21
|
+
second := filepath.Join(root, "second")
|
|
22
|
+
if err := os.MkdirAll(first, 0o755); err != nil {
|
|
23
|
+
t.Fatal(err)
|
|
24
|
+
}
|
|
25
|
+
if err := os.MkdirAll(second, 0o755); err != nil {
|
|
26
|
+
t.Fatal(err)
|
|
27
|
+
}
|
|
28
|
+
for _, directory := range []string{first, second} {
|
|
29
|
+
if err := os.WriteFile(filepath.Join(directory, "selection.ts"), []byte("export const value = 1;\n"), 0o644); err != nil {
|
|
30
|
+
t.Fatal(err)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
link := filepath.Join(root, "linked")
|
|
35
|
+
createAuxiliaryDirectoryLink(t, first, link)
|
|
36
|
+
selected := filepath.Join(link, "selection.ts")
|
|
37
|
+
previous := captureDiskStates([]auxiliaryInput{{path: selected, identityOnly: true}})
|
|
38
|
+
initial := previous[selected]
|
|
39
|
+
if !initial.Exists || initial.Realpath == "" || !initial.IdentityOnly {
|
|
40
|
+
t.Fatalf("initial identity state = %+v", initial)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if err := os.WriteFile(filepath.Join(first, "selection.ts"), []byte("export const value = 2;\n"), 0o644); err != nil {
|
|
44
|
+
t.Fatal(err)
|
|
45
|
+
}
|
|
46
|
+
if diskStatesChanged(previous) {
|
|
47
|
+
t.Fatal("selected source contents leaked into identity-only auxiliary invalidation")
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if err := os.Remove(link); err != nil {
|
|
51
|
+
t.Fatal(err)
|
|
52
|
+
}
|
|
53
|
+
createAuxiliaryDirectoryLink(t, second, link)
|
|
54
|
+
if !diskStatesChanged(previous) {
|
|
55
|
+
t.Fatal("same-byte lexical link retarget did not invalidate its physical identity")
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
merged := compactAuxiliaryInputs([]auxiliaryInput{
|
|
59
|
+
{path: selected, identityOnly: true},
|
|
60
|
+
{path: selected},
|
|
61
|
+
})
|
|
62
|
+
if len(merged) != 1 || merged[0].identityOnly {
|
|
63
|
+
t.Fatalf("content-sensitive duplicate did not win: %+v", merged)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
func createAuxiliaryDirectoryLink(t *testing.T, target, link string) {
|
|
68
|
+
t.Helper()
|
|
69
|
+
if runtime.GOOS == "windows" {
|
|
70
|
+
command := exec.Command(
|
|
71
|
+
"node",
|
|
72
|
+
"-e",
|
|
73
|
+
`require("node:fs").symlinkSync(process.argv[1], process.argv[2], "junction")`,
|
|
74
|
+
target,
|
|
75
|
+
link,
|
|
76
|
+
)
|
|
77
|
+
if output, err := command.CombinedOutput(); err != nil {
|
|
78
|
+
t.Skipf("directory junction unavailable on this host: %v: %s", err, output)
|
|
79
|
+
}
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
if err := os.Symlink(target, link); err != nil {
|
|
83
|
+
t.Skipf("directory symlink unavailable on this host: %v", err)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//go:build !windows
|
|
2
|
+
|
|
3
|
+
package main
|
|
4
|
+
|
|
5
|
+
import "path/filepath"
|
|
6
|
+
|
|
7
|
+
func diskRealpath(path string) string {
|
|
8
|
+
resolved, err := filepath.EvalSymlinks(path)
|
|
9
|
+
if err != nil {
|
|
10
|
+
return ""
|
|
11
|
+
}
|
|
12
|
+
if absolute, err := filepath.Abs(resolved); err == nil {
|
|
13
|
+
resolved = absolute
|
|
14
|
+
}
|
|
15
|
+
return filepath.Clean(resolved)
|
|
16
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
//go:build windows
|
|
2
|
+
|
|
3
|
+
package main
|
|
4
|
+
|
|
5
|
+
import (
|
|
6
|
+
"path/filepath"
|
|
7
|
+
"strings"
|
|
8
|
+
|
|
9
|
+
"golang.org/x/sys/windows"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
// diskRealpath asks the opened object for its final path. filepath.EvalSymlinks
|
|
13
|
+
// can leave a readable file below a directory junction unresolved on Windows,
|
|
14
|
+
// which would erase the physical identity this state exists to retain.
|
|
15
|
+
func diskRealpath(path string) string {
|
|
16
|
+
pointer, err := windows.UTF16PtrFromString(path)
|
|
17
|
+
if err != nil {
|
|
18
|
+
return ""
|
|
19
|
+
}
|
|
20
|
+
handle, err := windows.CreateFile(
|
|
21
|
+
pointer,
|
|
22
|
+
windows.FILE_READ_ATTRIBUTES,
|
|
23
|
+
windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE,
|
|
24
|
+
nil,
|
|
25
|
+
windows.OPEN_EXISTING,
|
|
26
|
+
windows.FILE_FLAG_BACKUP_SEMANTICS,
|
|
27
|
+
0,
|
|
28
|
+
)
|
|
29
|
+
if err != nil {
|
|
30
|
+
return ""
|
|
31
|
+
}
|
|
32
|
+
defer windows.CloseHandle(handle)
|
|
33
|
+
|
|
34
|
+
buffer := make([]uint16, windows.MAX_PATH)
|
|
35
|
+
for {
|
|
36
|
+
length, err := windows.GetFinalPathNameByHandle(
|
|
37
|
+
handle,
|
|
38
|
+
&buffer[0],
|
|
39
|
+
uint32(len(buffer)),
|
|
40
|
+
0,
|
|
41
|
+
)
|
|
42
|
+
if err != nil {
|
|
43
|
+
return ""
|
|
44
|
+
}
|
|
45
|
+
if length < uint32(len(buffer)) {
|
|
46
|
+
resolved := windows.UTF16ToString(buffer[:length])
|
|
47
|
+
if strings.HasPrefix(resolved, `\\?\UNC\`) {
|
|
48
|
+
resolved = `\\` + strings.TrimPrefix(resolved, `\\?\UNC\`)
|
|
49
|
+
} else {
|
|
50
|
+
resolved = strings.TrimPrefix(resolved, `\\?\`)
|
|
51
|
+
}
|
|
52
|
+
return filepath.Clean(resolved)
|
|
53
|
+
}
|
|
54
|
+
buffer = make([]uint16, length+1)
|
|
55
|
+
}
|
|
56
|
+
}
|
package/cmd/ttscgraph/serve.go
CHANGED
|
@@ -385,9 +385,11 @@ func (s *graphSession) captureState() error {
|
|
|
385
385
|
return err
|
|
386
386
|
}
|
|
387
387
|
inputs := auxiliaryInputs(program, configs, s.cwd)
|
|
388
|
-
|
|
388
|
+
for _, path := range missingRootInputs(configs, sourceHashes) {
|
|
389
|
+
inputs = append(inputs, auxiliaryInput{path: path})
|
|
390
|
+
}
|
|
389
391
|
s.configHashes = configHashes
|
|
390
|
-
s.auxStates = captureDiskStates(
|
|
392
|
+
s.auxStates = captureDiskStates(compactAuxiliaryInputs(inputs))
|
|
391
393
|
s.sourceHashes = sourceHashes
|
|
392
394
|
s.diskDigests = diskDigests
|
|
393
395
|
s.rootFiles = projectRootFilesFromConfigs(configs, false)
|
|
@@ -661,8 +663,19 @@ func changedSources(previous map[string][sha256.Size]byte) (map[string]string, b
|
|
|
661
663
|
}
|
|
662
664
|
|
|
663
665
|
type diskState struct {
|
|
664
|
-
Hash
|
|
665
|
-
Exists
|
|
666
|
+
Hash [sha256.Size]byte
|
|
667
|
+
Exists bool
|
|
668
|
+
Realpath string
|
|
669
|
+
IdentityOnly bool
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// auxiliaryInput distinguishes speculative inputs whose contents select the
|
|
673
|
+
// build universe from the lexical spelling of the source the compiler already
|
|
674
|
+
// selected. The resident source hash owns the latter's contents; this input
|
|
675
|
+
// owns only whether the spelling still reaches the same physical file.
|
|
676
|
+
type auxiliaryInput struct {
|
|
677
|
+
path string
|
|
678
|
+
identityOnly bool
|
|
666
679
|
}
|
|
667
680
|
|
|
668
681
|
// captureDiskStates records the freshness state of speculative resolution
|
|
@@ -671,29 +684,35 @@ type diskState struct {
|
|
|
671
684
|
// Windows), so any path that is neither a readable file nor a directory is
|
|
672
685
|
// recorded as absent instead of failing the snapshot: the recorded state only
|
|
673
686
|
// needs to flip when the candidate becomes resolvable.
|
|
674
|
-
func captureDiskStates(
|
|
675
|
-
states := make(map[string]diskState, len(
|
|
676
|
-
for _,
|
|
677
|
-
|
|
687
|
+
func captureDiskStates(inputs []auxiliaryInput) map[string]diskState {
|
|
688
|
+
states := make(map[string]diskState, len(inputs))
|
|
689
|
+
for _, input := range inputs {
|
|
690
|
+
state := diskState{IdentityOnly: input.identityOnly}
|
|
691
|
+
content, err := os.ReadFile(input.path)
|
|
678
692
|
if err != nil {
|
|
679
|
-
if info, statErr := os.Stat(path); statErr == nil && info.IsDir() {
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
states[path] = diskState{}
|
|
693
|
+
if info, statErr := os.Stat(input.path); statErr == nil && info.IsDir() {
|
|
694
|
+
state.Exists = true
|
|
695
|
+
state.Realpath = diskRealpath(input.path)
|
|
683
696
|
}
|
|
697
|
+
states[input.path] = state
|
|
684
698
|
continue
|
|
685
699
|
}
|
|
686
|
-
|
|
700
|
+
state.Exists = true
|
|
701
|
+
state.Realpath = diskRealpath(input.path)
|
|
702
|
+
if !input.identityOnly {
|
|
703
|
+
state.Hash = sha256.Sum256(content)
|
|
704
|
+
}
|
|
705
|
+
states[input.path] = state
|
|
687
706
|
}
|
|
688
707
|
return states
|
|
689
708
|
}
|
|
690
709
|
|
|
691
710
|
func diskStatesChanged(previous map[string]diskState) bool {
|
|
692
|
-
|
|
693
|
-
for path := range previous {
|
|
694
|
-
|
|
711
|
+
inputs := make([]auxiliaryInput, 0, len(previous))
|
|
712
|
+
for path, state := range previous {
|
|
713
|
+
inputs = append(inputs, auxiliaryInput{path: path, identityOnly: state.IdentityOnly})
|
|
695
714
|
}
|
|
696
|
-
current := captureDiskStates(
|
|
715
|
+
current := captureDiskStates(inputs)
|
|
697
716
|
for path, state := range previous {
|
|
698
717
|
if current[path] != state {
|
|
699
718
|
return true
|
|
@@ -702,16 +721,16 @@ func diskStatesChanged(previous map[string]diskState) bool {
|
|
|
702
721
|
return false
|
|
703
722
|
}
|
|
704
723
|
|
|
705
|
-
func auxiliaryInputs(program *driver.Program, configs []*shimtsoptions.ParsedCommandLine, cwd string) []
|
|
706
|
-
inputs := []
|
|
707
|
-
filepath.Join(cwd, ".gitignore"),
|
|
708
|
-
filepath.Join(cwd, ".git", "info", "exclude"),
|
|
709
|
-
filepath.Join(cwd, "package.json"),
|
|
710
|
-
filepath.Join(cwd, "package-lock.json"),
|
|
711
|
-
filepath.Join(cwd, "pnpm-lock.yaml"),
|
|
712
|
-
filepath.Join(cwd, "yarn.lock"),
|
|
713
|
-
filepath.Join(cwd, "bun.lock"),
|
|
714
|
-
filepath.Join(cwd, "bun.lockb"),
|
|
724
|
+
func auxiliaryInputs(program *driver.Program, configs []*shimtsoptions.ParsedCommandLine, cwd string) []auxiliaryInput {
|
|
725
|
+
inputs := []auxiliaryInput{
|
|
726
|
+
{path: filepath.Join(cwd, ".gitignore")},
|
|
727
|
+
{path: filepath.Join(cwd, ".git", "info", "exclude")},
|
|
728
|
+
{path: filepath.Join(cwd, "package.json")},
|
|
729
|
+
{path: filepath.Join(cwd, "package-lock.json")},
|
|
730
|
+
{path: filepath.Join(cwd, "pnpm-lock.yaml")},
|
|
731
|
+
{path: filepath.Join(cwd, "yarn.lock")},
|
|
732
|
+
{path: filepath.Join(cwd, "bun.lock")},
|
|
733
|
+
{path: filepath.Join(cwd, "bun.lockb")},
|
|
715
734
|
}
|
|
716
735
|
for _, source := range program.TSProgram.SourceFiles() {
|
|
717
736
|
file := source.FileName()
|
|
@@ -719,12 +738,18 @@ func auxiliaryInputs(program *driver.Program, configs []*shimtsoptions.ParsedCom
|
|
|
719
738
|
continue
|
|
720
739
|
}
|
|
721
740
|
directory := filepath.Dir(file)
|
|
722
|
-
|
|
741
|
+
for _, path := range appendAncestorInputs(nil, directory, cwd) {
|
|
742
|
+
inputs = append(inputs, auxiliaryInput{path: path})
|
|
743
|
+
}
|
|
723
744
|
for _, reference := range source.ReferencedFiles {
|
|
724
|
-
|
|
745
|
+
for _, path := range driver.FileCandidates(filepath.Join(directory, filepath.FromSlash(reference.FileName))) {
|
|
746
|
+
inputs = append(inputs, auxiliaryInput{path: path})
|
|
747
|
+
}
|
|
725
748
|
}
|
|
726
749
|
for _, reference := range source.TypeReferenceDirectives {
|
|
727
|
-
|
|
750
|
+
for _, path := range driver.TypeReferenceCandidates(configs, directory, cwd, reference.FileName) {
|
|
751
|
+
inputs = append(inputs, auxiliaryInput{path: path})
|
|
752
|
+
}
|
|
728
753
|
}
|
|
729
754
|
for _, specifier := range driver.SourceModuleSpecifiers(source) {
|
|
730
755
|
context := driver.ModuleResolutionContext{
|
|
@@ -738,7 +763,7 @@ func auxiliaryInputs(program *driver.Program, configs []*shimtsoptions.ParsedCom
|
|
|
738
763
|
}
|
|
739
764
|
resolved := program.TSProgram.GetResolvedModuleFromModuleSpecifier(source, specifier)
|
|
740
765
|
if resolved != nil && resolved.IsResolved() {
|
|
741
|
-
|
|
766
|
+
predecessors := driver.ModuleResolutionPredecessors(
|
|
742
767
|
configs,
|
|
743
768
|
directory,
|
|
744
769
|
cwd,
|
|
@@ -746,10 +771,18 @@ func auxiliaryInputs(program *driver.Program, configs []*shimtsoptions.ParsedCom
|
|
|
746
771
|
resolved.ResolvedFileName,
|
|
747
772
|
program.FS.UseCaseSensitiveFileNames(),
|
|
748
773
|
context,
|
|
749
|
-
)
|
|
774
|
+
)
|
|
775
|
+
for _, path := range predecessors {
|
|
776
|
+
inputs = append(inputs, auxiliaryInput{
|
|
777
|
+
path: path,
|
|
778
|
+
identityOnly: sameExistingAuxiliaryPath(path, resolved.ResolvedFileName),
|
|
779
|
+
})
|
|
780
|
+
}
|
|
750
781
|
continue
|
|
751
782
|
}
|
|
752
|
-
|
|
783
|
+
for _, path := range driver.ModuleResolutionCandidates(configs, directory, cwd, specifier.Text(), context) {
|
|
784
|
+
inputs = append(inputs, auxiliaryInput{path: path})
|
|
785
|
+
}
|
|
753
786
|
}
|
|
754
787
|
}
|
|
755
788
|
// Config `types` entries request type packages without any source syntax, so
|
|
@@ -760,10 +793,46 @@ func auxiliaryInputs(program *driver.Program, configs []*shimtsoptions.ParsedCom
|
|
|
760
793
|
continue
|
|
761
794
|
}
|
|
762
795
|
for _, name := range parsed.ParsedConfig.CompilerOptions.Types {
|
|
763
|
-
|
|
796
|
+
for _, path := range driver.TypeReferenceCandidates(configs, parsed.GetCurrentDirectory(), cwd, name) {
|
|
797
|
+
inputs = append(inputs, auxiliaryInput{path: path})
|
|
798
|
+
}
|
|
764
799
|
}
|
|
765
800
|
}
|
|
766
|
-
return
|
|
801
|
+
return compactAuxiliaryInputs(inputs)
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
func sameExistingAuxiliaryPath(left, right string) bool {
|
|
805
|
+
leftInfo, err := os.Stat(left)
|
|
806
|
+
if err != nil {
|
|
807
|
+
return false
|
|
808
|
+
}
|
|
809
|
+
rightInfo, err := os.Stat(right)
|
|
810
|
+
return err == nil && os.SameFile(leftInfo, rightInfo)
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
func compactAuxiliaryInputs(inputs []auxiliaryInput) []auxiliaryInput {
|
|
814
|
+
byPath := make(map[string]auxiliaryInput, len(inputs))
|
|
815
|
+
for _, input := range inputs {
|
|
816
|
+
if strings.TrimSpace(input.path) == "" {
|
|
817
|
+
continue
|
|
818
|
+
}
|
|
819
|
+
if previous, exists := byPath[input.path]; exists {
|
|
820
|
+
// A path that also participates as a manifest or other content-bearing
|
|
821
|
+
// input keeps the stronger content-sensitive contract.
|
|
822
|
+
input.identityOnly = previous.identityOnly && input.identityOnly
|
|
823
|
+
}
|
|
824
|
+
byPath[input.path] = input
|
|
825
|
+
}
|
|
826
|
+
paths := make([]string, 0, len(byPath))
|
|
827
|
+
for path := range byPath {
|
|
828
|
+
paths = append(paths, path)
|
|
829
|
+
}
|
|
830
|
+
sort.Strings(paths)
|
|
831
|
+
output := make([]auxiliaryInput, 0, len(paths))
|
|
832
|
+
for _, path := range paths {
|
|
833
|
+
output = append(output, byPath[path])
|
|
834
|
+
}
|
|
835
|
+
return output
|
|
767
836
|
}
|
|
768
837
|
|
|
769
838
|
func appendAncestorInputs(inputs []string, directory, stop string) []string {
|