fix(lint): dynamically resolve rootDir for Windows compatibility#300
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes Windows-specific TS6059 errors during TypeScript lint-config evaluation by avoiding a hardcoded POSIX root ("/") and instead computing a platform-appropriate volume root for the ephemeral loader project used by @ttsc/lint.
Changes:
- Update the JS lint-config loader tsconfig synthesis to set
rootDirto the detected volume root (instead of"/"). - Update the Go sidecar lint-config loader tsconfig synthesis to set
rootDirto the detected volume root (instead of"/").
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| packages/lint/src/index.ts | Uses path.parse(tempDir).root (normalized to /) for the ephemeral loader tsconfig rootDir to improve Windows compatibility. |
| packages/lint/linthost/config.go | Uses filepath.VolumeName() to derive a Windows volume root for the ephemeral loader tsconfig rootDir. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
565
to
568
| outDir: path.join(tempDir, "out").replace(/\\/g, "/"), | ||
| rewriteRelativeImportExtensions: true, | ||
| rootDir: "/", | ||
| rootDir: path.parse(tempDir).root.replace(/\\/g, "/"), | ||
| skipLibCheck: true, |
Comment on lines
+1356
to
+1362
| "rootDir": func() string { | ||
| vol := filepath.VolumeName(outDir) | ||
| if vol == "" { | ||
| return "/" | ||
| } | ||
| return filepath.ToSlash(vol + "\\") | ||
| }(), |
This was referenced Jul 2, 2026
samchon
added a commit
that referenced
this pull request
Jul 2, 2026
…#308) * fix(lint,banner,strip): make TS config loaders volume-aware on Windows The lint fix from #300 left two byte-identical siblings hardcoding the loader tsconfig's rootDir to "/", which is never an ancestor of drive-letter paths (TS6059, #304). Extract the volume-root resolution into a named loaderRootDir helper (also restoring gofmt-stable formatting in linthost) and apply it to the banner and strip drivers. Rooting at the volume is still not enough when the system temp dir and the config file live on different drives: no single rootDir spans two volumes and relative import specifiers cannot cross them (#305). Create the ephemeral loader tree under the config's nearest node_modules/.cache in that case — on all three Go drivers and the lint JS factory — keeping the system temp dir whenever the volumes already match. Also normalize separators in the runtime hooks' isWithin so the slash-form manifest rootDir the loader tsconfig now emits (C:/) matches native real paths, and align the ttsx e2e fixture that mirrored the loader's rootDir synthesis. Resolves #304, resolves #305. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ttsc): copy file-symlink virtual entries when symlinks need privilege linkVirtualEntry handled directories, plain files, and directory-target symlinks in a Windows-safe way, but its final branch re-symlinked file symlinks with a bare fs.symlinkSync — which needs SeCreateSymbolicLinkPrivilege on Windows and crashed the run with EPERM without admin rights or Developer Mode (#306, same class as #218). Mirror the plain-file branch's hard-link/copy fallback, and skip a link whose target no longer exists: it can serve no module and none of the fallbacks can materialize it. Resolves #306. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(lint,banner,strip,ttsc): close the loader-volume and symlink edges Driving the whole loader chain end-to-end on a two-volume Windows machine surfaced three gaps in the previous commit: - A linked node_modules (junction/symlink) broke the loader: the ESM runtime realpaths the loader module at import time, so a relative config specifier computed from the link-form .cache path resolved against the wrong directory. The temp base is realpathed now; NTFS junctions defeat filepath.EvalSymlinks, so the Go drivers chase the link component with os.Readlink first. - Cross-volume configs with no usable node_modules/.cache fell back to the system temp dir — guaranteed to fail. They now fall back to the config's own directory, which is always on the right volume and keeps the relative import a plain "./". - isWithin now compares case-insensitively on Windows (a lowercase TEMP yields a c:-rooted manifest rootDir for the volume real paths spell C:), and is exported alongside linkVirtualEntry so the e2e suite can pin the Windows normalization and EPERM-fallback branches that a spawned run cannot reach on CI. New coverage: the temp-base tests pin the blocked-.cache, missing node_modules, and junction realpath branches; api e2e tests drive linkVirtualEntry's copy fallback and dangling-entry skip (the dangling fixture is a junction, so it exercises the real privilege-less EPERM path on Windows) and isWithin's root/slash/case matching. Verified on Windows 11 with the project on D: and TEMP on C:, including live cross-drive config evaluation through real ttsx + tsgo on both the JS factory and the Go driver paths. Refs #304, #305, #306. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ci(test): add a Windows Go-suite lane and make it green Add a windows-latest matrix entry running `pnpm run test:go` as the minimal Windows safety net — the Go unit suites cover the platform-sensitive layers (config loaders, path handling) without the POSIX-only e2e runner, and only need the ttsx launcher build. Everything that kept that lane red gets fixed with it: - scripts/test-go-utility-plugins.cjs wrote forward-slash `use` paths into its go.work; Go's workspace-module matching on Windows rejects them ("directory ... is not one of the workspace modules"), so every suite failed at setup. Write native separators. - packages/ttsc's build script copied README with unix `cp`, which cmd has no notion of; use a node one-liner. - The banner suites faked launchers as extensionless `#!/bin/sh` scripts, which Windows cannot spawn. A new writeDirectLauncher helper emits the sh script on POSIX and an equivalent `.cmd` on Windows, keeping both off the node-routed extension list. - The tempdir-failure case pointed TMPDIR at a file; os.TempDir reads TMP/TEMP on Windows, so override those there. - Two assertions were unhermetic on machines with a stray drive-root node_modules; they now tolerate discoveries outside the fixture. The relative-config-path case surfaced a real regression in the new loaderTempBase helpers: a volume-less location compared unequal to the system temp's volume and was misrouted to the cross-volume branch, breaking the Rel-failure contract (and creating loader dirs relative to the cwd). All four helpers now keep the historical default for volume-less locations, with test scenarios pinning it. Refs #304, #305. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore: drop a leaked paths test fixture from the tree A locally-run paths Go test materializes its external-file fixture inside the package directory and leaves it behind; the previous commit swept it up unintentionally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(paths,ci): unblock the Windows Go lane on split-volume runners Two problems surfaced running the paths suite on a machine whose repo and temp dir live on different drives (the windows-latest layout): - TestCommandRewritesAllModuleSpecifierForms materialized its external files-list fixture inside the package directory. With the project in the system temp dir that makes the tsconfig `files` list span two volumes, and project loading hangs until the go test timeout (#310 tracks the sidecar behavior; tsc errors fast on the same input). The fixture moves to a sibling temp dir — still outside the tsconfig directory, same volume, and it can no longer leak into the tree when a test dies mid-run. - The utility-plugin runner now prewarms the plugin/driver build before `go test`: the command tests `go run ./plugin` during test execution, so on a cold CI cache the full typescript-go compile counted against the 10-minute test timeout. With these, all three utility suites pass on Windows for the first time (banner 16s, paths 20s, strip 27s locally). Refs #308, #310. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore: drop leaked paths fixtures again Residue from the two timed-out suite runs predating the fixture relocation; the previous commit swept them up. The relocation itself prevents any further leaks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test: normalize the cross-volume temp-base expectation like the helper CI Windows runners hand out an 8.3 short-name TEMP (RUNNER~1), so the helper's EvalSymlinks-normalized result never compared equal to a raw Join of the fixture root even though both name the same directory. Normalize the expectation the same way. Refs #308. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test: narrow the Dirent fixture lookup before use assert.ok on `entry?.isSymbolicLink()` narrows that expression, not `entry`, so the `Dirent | undefined` from Array.find reached linkVirtualEntry and failed typecheck. Assert existence first. Refs #308. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test: front the stderr redirect in the Windows fake launcher A trailing `>&2` glued to a payload ending in a digit would turn that digit into a file-descriptor redirect; putting the redirect first sidesteps both that and the trailing-space form. Also document the cmd-metacharacter constraint on payloads. Refs #308. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Resolves the
TS6059compilation error when evaluating TypeScript lint configs on Windows by dynamically detecting the system's volume root instead of using the hardcoded"/".Changes
packages/lint/src/index.ts): Replaced"rootDir": "/"withrootDir: path.parse(tempDir).root.replace(/\\/g, "/").packages/lint/linthost/config.go): Replaced"rootDir": "/"with a volume root dynamic resolver usingfilepath.VolumeName().Related Issue