fix(extensibility): treat Windows drive-letter paths as filesystem in legacy-pi mirror
isUrlLikeSpecifier matched Windows absolute paths (e.g. `C:\foo`) because the URL-scheme regex `^[A-Za-z][A-Za-z\d+.-]*:` happily eats a single drive letter. When a legacy plugin extension imported a bare-specifier dep from its own `node_modules`, rewriteBareImportsForLegacyExtension resolved it to an absolute path, then toRewrittenImportSpecifier short-circuited pathToFileURL and embedded the raw Windows path into the mirrored TS source. The TS string-literal parser then ate \n, \U, \y and friends, producing nonsense package specifiers like `C:Usersjames.ompagentextensionssupipowers\node_modulesyamldistindex.js` that Bun rejected with `Cannot find package …`. Net effect: every legacy extension that pulls in any node_modules dep failed to load on Windows. Fix: reject `^[A-Za-z]:[\\/]` in isUrlLikeSpecifier before the URL-scheme test so drive-letter paths flow through pathToFileURL and reach the mirror as proper `file:///C:/...` URLs.
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed legacy plugin extensions failing to load on Windows when they import a bare-specifier dependency from their own `node_modules` (e.g. `import YAML from "yaml"` in `supipowers`). The legacy-pi mirror resolved the dependency to its absolute path and then ran the path through `isUrlLikeSpecifier`, whose `^[A-Za-z][A-Za-z\d+.-]*:` regex matched the Windows drive letter (`C:`) and short-circuited the `pathToFileURL` conversion. The raw path was emitted into the mirrored TS source as `import x from "C:\\Users\\...\\dep\\dist\\index.js"`, where `\n`, `\U`, `\y` and other backslash sequences were eaten by the TS string-literal parser, producing nonsense package specifiers like `C:Usersjames.ompagentextensionssupipowers\node_modulesyamldistindex.js` that Bun's resolver rejected with `Cannot find package …`. `isUrlLikeSpecifier` now rejects `^[A-Za-z]:[\\/]` first, so Windows absolute paths flow through `pathToFileURL` like every other absolute path and reach the mirror as proper `file:///C:/...` URLs.
|
||||
|
||||
## [15.0.2] - 2026-05-15
|
||||
|
||||
### Added
|
||||
|
||||
@@ -99,6 +99,12 @@ const ANY_IMPORT_SPECIFIER_REGEX = /((?:from\s+|import\s*\(\s*)["'])([^"']+)(["'
|
||||
|
||||
/** Resolve bare imports against the extension directory before loading mirrored legacy Pi files. */
|
||||
function isUrlLikeSpecifier(specifier: string): boolean {
|
||||
// Windows drive-letter paths (e.g. `C:\foo` or `C:/foo`) also match the URL
|
||||
// scheme shape `[A-Za-z][A-Za-z\d+.-]*:`. Treat them as filesystem paths so
|
||||
// `toRewrittenImportSpecifier` converts them to `file://` URLs instead of
|
||||
// emitting raw paths whose `\n`, `\U`, ... get eaten by TS string-literal
|
||||
// escapes inside the mirrored extension file.
|
||||
if (/^[a-zA-Z]:[\\/]/.test(specifier)) return false;
|
||||
return /^[a-zA-Z][a-zA-Z\d+.-]*:/.test(specifier);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user