@swissjs/swite 0.3.0 → 0.3.1
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/dist/adapters/proxy/SwiteProxyError.d.ts.map +1 -0
- package/dist/{proxy → adapters/proxy}/proxyToPython.d.ts +1 -1
- package/dist/adapters/proxy/proxyToPython.d.ts.map +1 -0
- package/dist/build-engine/builder.d.ts.map +1 -0
- package/dist/{builder.js → build-engine/builder.js} +8 -14
- package/dist/cli.js +5 -5
- package/dist/config/config-loader.d.ts.map +1 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/env.d.ts +25 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +84 -0
- package/dist/{handlers → dev-engine/handlers}/base-handler.d.ts +3 -1
- package/dist/dev-engine/handlers/base-handler.d.ts.map +1 -0
- package/dist/{handlers → dev-engine/handlers}/base-handler.js +22 -2
- package/dist/dev-engine/handlers/js-handler.d.ts.map +1 -0
- package/dist/{handlers → dev-engine/handlers}/js-handler.js +1 -1
- package/dist/dev-engine/handlers/mjs-handler.d.ts.map +1 -0
- package/dist/{handlers → dev-engine/handlers}/mjs-handler.js +1 -1
- package/dist/dev-engine/handlers/node-module-handler.d.ts.map +1 -0
- package/dist/{handlers → dev-engine/handlers}/node-module-handler.js +4 -4
- package/dist/{handlers → dev-engine/handlers}/ts-handler.d.ts +0 -4
- package/dist/dev-engine/handlers/ts-handler.d.ts.map +1 -0
- package/dist/{handlers → dev-engine/handlers}/ts-handler.js +5 -28
- package/dist/{handlers → dev-engine/handlers}/ui-handler.d.ts +0 -4
- package/dist/dev-engine/handlers/ui-handler.d.ts.map +1 -0
- package/dist/dev-engine/handlers/ui-handler.js +84 -0
- package/dist/{handlers → dev-engine/handlers}/uix-handler.d.ts +0 -4
- package/dist/dev-engine/handlers/uix-handler.d.ts.map +1 -0
- package/dist/dev-engine/handlers/uix-handler.js +70 -0
- package/dist/dev-engine/hmr/hmr-client-template.d.ts +10 -0
- package/dist/dev-engine/hmr/hmr-client-template.d.ts.map +1 -0
- package/dist/dev-engine/hmr/hmr-client-template.js +122 -0
- package/dist/dev-engine/hmr/hmr.d.ts.map +1 -0
- package/dist/{hmr.js → dev-engine/hmr/hmr.js} +2 -134
- package/dist/{middleware → dev-engine/middleware}/hmr-routes.d.ts +2 -2
- package/dist/dev-engine/middleware/hmr-routes.d.ts.map +1 -0
- package/dist/{middleware → dev-engine/middleware}/hmr-routes.js +1 -1
- package/dist/dev-engine/middleware/middleware-setup.d.ts +34 -0
- package/dist/dev-engine/middleware/middleware-setup.d.ts.map +1 -0
- package/dist/dev-engine/middleware/middleware-setup.js +327 -0
- package/dist/dev-engine/middleware/static-files.d.ts.map +1 -0
- package/dist/{middleware → dev-engine/middleware}/static-files.js +2 -2
- package/dist/{dev → dev-engine}/pythonDevManager.d.ts +1 -1
- package/dist/dev-engine/pythonDevManager.d.ts.map +1 -0
- package/dist/{dev → dev-engine}/pythonDevManager.js +1 -1
- package/dist/{router → dev-engine/router}/file-router.d.ts +4 -4
- package/dist/dev-engine/router/file-router.d.ts.map +1 -0
- package/dist/{router → dev-engine/router}/file-router.js +4 -4
- package/dist/dev-engine/server.d.ts.map +1 -0
- package/dist/{server.js → dev-engine/server.js} +6 -6
- package/dist/index.d.ts +13 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -9
- package/dist/internal/cache/compilation-cache.d.ts.map +1 -0
- package/dist/{cache → internal/cache}/compilation-cache.js +3 -2
- package/dist/internal/generate-import-map-cli.d.ts.map +1 -0
- package/dist/{utils → internal}/generate-import-map-cli.js +1 -1
- package/dist/internal/generate-import-map.d.ts.map +1 -0
- package/dist/{utils → internal}/generate-import-map.js +3 -3
- package/dist/{utils → kernel}/package-finder.d.ts +3 -1
- package/dist/kernel/package-finder.d.ts.map +1 -0
- package/dist/{utils → kernel}/package-finder.js +29 -52
- package/dist/kernel/package-registry.d.ts.map +1 -0
- package/dist/kernel/workspace.d.ts.map +1 -0
- package/dist/{resolver → resolution}/bare-import-resolver.d.ts +1 -1
- package/dist/resolution/bare-import-resolver.d.ts.map +1 -0
- package/dist/{resolver → resolution}/bare-import-resolver.js +12 -49
- package/dist/resolution/cdn/cdn-fallback.d.ts.map +1 -0
- package/dist/resolution/path/file-path-resolver.d.ts.map +1 -0
- package/dist/{utils → resolution/path}/file-path-resolver.js +11 -20
- package/dist/resolution/path/path-fixup.d.ts +13 -0
- package/dist/resolution/path/path-fixup.d.ts.map +1 -0
- package/dist/resolution/path/path-fixup.js +20 -0
- package/dist/{resolver.d.ts → resolution/resolver.d.ts} +1 -1
- package/dist/resolution/resolver.d.ts.map +1 -0
- package/dist/{resolver.js → resolution/resolver.js} +8 -37
- package/dist/{import-rewriter.d.ts → resolution/rewriting/import-rewriter.d.ts} +1 -1
- package/dist/resolution/rewriting/import-rewriter.d.ts.map +1 -0
- package/dist/resolution/rewriting/import-rewriter.js +199 -0
- package/dist/{resolver → resolution}/symlink-registry.d.ts +1 -1
- package/dist/resolution/symlink-registry.d.ts.map +1 -0
- package/dist/{resolver → resolution}/symlink-registry.js +1 -1
- package/dist/resolution/url-resolver.d.ts.map +1 -0
- package/dist/{resolver → resolution}/url-resolver.js +38 -109
- package/dist/resolution/workspace-package-resolver.d.ts.map +1 -0
- package/dist/resolution/workspace-package-resolver.js +77 -0
- package/package.json +24 -15
- package/src/cli.ts +1 -1
- package/src/resolution/url-resolver.ts +1 -1
- package/dist/builder.d.ts.map +0 -1
- package/dist/cache/compilation-cache.d.ts.map +0 -1
- package/dist/config-loader.d.ts.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/dev/pythonDevManager.d.ts.map +0 -1
- package/dist/env.d.ts +0 -19
- package/dist/env.d.ts.map +0 -1
- package/dist/env.js +0 -112
- package/dist/handlers/base-handler.d.ts.map +0 -1
- package/dist/handlers/js-handler.d.ts.map +0 -1
- package/dist/handlers/mjs-handler.d.ts.map +0 -1
- package/dist/handlers/node-module-handler.d.ts.map +0 -1
- package/dist/handlers/ts-handler.d.ts.map +0 -1
- package/dist/handlers/ui-handler.d.ts.map +0 -1
- package/dist/handlers/ui-handler.js +0 -182
- package/dist/handlers/uix-handler.d.ts.map +0 -1
- package/dist/handlers/uix-handler.js +0 -135
- package/dist/hmr.d.ts.map +0 -1
- package/dist/import-rewriter.d.ts.map +0 -1
- package/dist/import-rewriter.js +0 -351
- package/dist/middleware/hmr-routes.d.ts.map +0 -1
- package/dist/middleware/middleware-setup.d.ts +0 -23
- package/dist/middleware/middleware-setup.d.ts.map +0 -1
- package/dist/middleware/middleware-setup.js +0 -596
- package/dist/middleware/static-files.d.ts.map +0 -1
- package/dist/proxy/SwiteProxyError.d.ts.map +0 -1
- package/dist/proxy/proxyToPython.d.ts.map +0 -1
- package/dist/resolver/bare-import-resolver.d.ts.map +0 -1
- package/dist/resolver/symlink-registry.d.ts.map +0 -1
- package/dist/resolver/url-resolver.d.ts.map +0 -1
- package/dist/resolver/workspace-package-resolver.d.ts.map +0 -1
- package/dist/resolver/workspace-package-resolver.js +0 -185
- package/dist/resolver.d.ts.map +0 -1
- package/dist/router/file-router.d.ts.map +0 -1
- package/dist/server.d.ts.map +0 -1
- package/dist/utils/cdn-fallback.d.ts.map +0 -1
- package/dist/utils/file-path-resolver.d.ts.map +0 -1
- package/dist/utils/generate-import-map-cli.d.ts.map +0 -1
- package/dist/utils/generate-import-map.d.ts.map +0 -1
- package/dist/utils/package-finder.d.ts.map +0 -1
- package/dist/utils/package-registry.d.ts.map +0 -1
- package/dist/utils/workspace.d.ts.map +0 -1
- /package/dist/{proxy → adapters/proxy}/SwiteProxyError.d.ts +0 -0
- /package/dist/{proxy → adapters/proxy}/SwiteProxyError.js +0 -0
- /package/dist/{proxy → adapters/proxy}/proxyToPython.js +0 -0
- /package/dist/{builder.d.ts → build-engine/builder.d.ts} +0 -0
- /package/dist/{config-loader.d.ts → config/config-loader.d.ts} +0 -0
- /package/dist/{config-loader.js → config/config-loader.js} +0 -0
- /package/dist/{config.d.ts → config/config.d.ts} +0 -0
- /package/dist/{config.js → config/config.js} +0 -0
- /package/dist/{handlers → dev-engine/handlers}/js-handler.d.ts +0 -0
- /package/dist/{handlers → dev-engine/handlers}/mjs-handler.d.ts +0 -0
- /package/dist/{handlers → dev-engine/handlers}/node-module-handler.d.ts +0 -0
- /package/dist/{hmr.d.ts → dev-engine/hmr/hmr.d.ts} +0 -0
- /package/dist/{middleware → dev-engine/middleware}/static-files.d.ts +0 -0
- /package/dist/{server.d.ts → dev-engine/server.d.ts} +0 -0
- /package/dist/{cache → internal/cache}/compilation-cache.d.ts +0 -0
- /package/dist/{utils → internal}/generate-import-map-cli.d.ts +0 -0
- /package/dist/{utils → internal}/generate-import-map.d.ts +0 -0
- /package/dist/{utils → kernel}/package-registry.d.ts +0 -0
- /package/dist/{utils → kernel}/package-registry.js +0 -0
- /package/dist/{utils → kernel}/workspace.d.ts +0 -0
- /package/dist/{utils → kernel}/workspace.js +0 -0
- /package/dist/{utils → resolution/cdn}/cdn-fallback.d.ts +0 -0
- /package/dist/{utils → resolution/cdn}/cdn-fallback.js +0 -0
- /package/dist/{utils → resolution/path}/file-path-resolver.d.ts +0 -0
- /package/dist/{resolver → resolution}/url-resolver.d.ts +0 -0
- /package/dist/{resolver → resolution}/workspace-package-resolver.d.ts +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/resolution/resolver.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAMpE,qBAAa,cAAc;IAIb,OAAO,CAAC,IAAI;IAHxB,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,SAAS,CAA0B;gBAEvB,IAAI,EAAE,MAAM;IAEhC;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI;YAWjC,gBAAgB;IAMxB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YA8HrD,UAAU;YASV,uBAAuB;YAavB,KAAK;CAUpB"}
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { promises as fs } from "node:fs";
|
|
6
6
|
import chalk from "chalk";
|
|
7
|
-
import {
|
|
8
|
-
import { toUrl } from "./
|
|
9
|
-
import { resolveWorkspacePackage } from "./
|
|
10
|
-
import { resolveBareImport } from "./
|
|
7
|
+
import { findWorkspaceRoot } from "../kernel/workspace.js";
|
|
8
|
+
import { toUrl } from "./url-resolver.js";
|
|
9
|
+
import { resolveWorkspacePackage } from "./workspace-package-resolver.js";
|
|
10
|
+
import { resolveBareImport } from "./bare-import-resolver.js";
|
|
11
11
|
export class ModuleResolver {
|
|
12
12
|
constructor(root) {
|
|
13
13
|
this.root = root;
|
|
@@ -26,28 +26,10 @@ export class ModuleResolver {
|
|
|
26
26
|
async getWorkspaceRoot() {
|
|
27
27
|
if (this.workspaceRoot)
|
|
28
28
|
return this.workspaceRoot;
|
|
29
|
-
const findWorkspaceRoot = async (startDir) => {
|
|
30
|
-
let current = startDir;
|
|
31
|
-
for (let i = 0; i < 5; i++) {
|
|
32
|
-
const workspaceFile = path.join(current, "pnpm-workspace.yaml");
|
|
33
|
-
const packageJson = path.join(current, "package.json");
|
|
34
|
-
if ((await this.fileExists(workspaceFile)) ||
|
|
35
|
-
((await this.fileExists(packageJson)) &&
|
|
36
|
-
JSON.parse(await fs.readFile(packageJson, "utf-8")).workspaces)) {
|
|
37
|
-
return current;
|
|
38
|
-
}
|
|
39
|
-
const parent = path.dirname(current);
|
|
40
|
-
if (parent === current)
|
|
41
|
-
break;
|
|
42
|
-
current = parent;
|
|
43
|
-
}
|
|
44
|
-
return null;
|
|
45
|
-
};
|
|
46
29
|
this.workspaceRoot = await findWorkspaceRoot(this.root);
|
|
47
30
|
return this.workspaceRoot;
|
|
48
31
|
}
|
|
49
32
|
async resolve(specifier, importer) {
|
|
50
|
-
console.log(`[SWITE] resolve CALLED: specifier: ${specifier}, importer: ${importer}`);
|
|
51
33
|
// Check import map first (fast path)
|
|
52
34
|
if (this.importMap && !specifier.startsWith(".") && !specifier.startsWith("/")) {
|
|
53
35
|
const mapped = this.importMap.imports[specifier];
|
|
@@ -81,9 +63,7 @@ export class ModuleResolver {
|
|
|
81
63
|
fileExists: (p) => this.fileExists(p),
|
|
82
64
|
resolveWorkspacePackage: (pkgName) => this.resolveWorkspacePackage(pkgName),
|
|
83
65
|
};
|
|
84
|
-
|
|
85
|
-
console.log(`[SWITE] resolve RESULT: ${specifier} -> ${result}`);
|
|
86
|
-
return result;
|
|
66
|
+
return await resolveBareImport(specifier, context);
|
|
87
67
|
}
|
|
88
68
|
// Handle absolute paths (already URLs)
|
|
89
69
|
if (specifier.startsWith("/")) {
|
|
@@ -126,30 +106,21 @@ export class ModuleResolver {
|
|
|
126
106
|
// This preserves .ui/.uix extensions for SWISS files
|
|
127
107
|
const hasExtension = /\.(ui|uix|ts|tsx|js|jsx|mjs)$/.test(specifier);
|
|
128
108
|
if (hasExtension) {
|
|
129
|
-
// Specifier has extension, resolve it directly
|
|
130
109
|
const resolved = path.resolve(importerDir, specifier);
|
|
131
|
-
console.log(`[SWITE] resolve relative (hasExt): ${specifier}, importerDir: ${importerDir}, resolved: ${resolved}, exists: ${await this.fileExists(resolved)}`);
|
|
132
110
|
if (await this.fileExists(resolved)) {
|
|
133
|
-
|
|
134
|
-
console.log(`[SWITE] resolve relative: ${specifier} -> ${resolved} -> ${url}`);
|
|
135
|
-
return url;
|
|
111
|
+
return await this.toUrl(resolved);
|
|
136
112
|
}
|
|
137
113
|
}
|
|
138
114
|
// If no extension or file not found, try adding extensions
|
|
139
115
|
// Strip any existing extension from specifier (but preserve .ui/.uix if present)
|
|
140
116
|
const specifierWithoutExt = specifier.replace(/\.(js|ts|jsx|tsx|mjs)$/, "");
|
|
141
117
|
const resolved = path.resolve(importerDir, specifierWithoutExt);
|
|
142
|
-
console.log(`[SWITE] resolve relative (trying extensions): specifierWithoutExt: ${specifierWithoutExt}, resolved: ${resolved}`);
|
|
143
118
|
// Try adding extensions (prioritize .ui and .uix for SWISS files)
|
|
144
119
|
const extensions = [".ui", ".uix", ".ts", ".tsx", ".js", ".jsx", ".mjs"];
|
|
145
120
|
for (const ext of extensions) {
|
|
146
121
|
const withExt = resolved + ext;
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (exists) {
|
|
150
|
-
const url = await this.toUrl(withExt);
|
|
151
|
-
console.log(`[SWITE] found with ${ext}: ${url}`);
|
|
152
|
-
return url;
|
|
122
|
+
if (await this.fileExists(withExt)) {
|
|
123
|
+
return await this.toUrl(withExt);
|
|
153
124
|
}
|
|
154
125
|
}
|
|
155
126
|
// Try index files
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-rewriter.d.ts","sourceRoot":"","sources":["../../../src/resolution/rewriting/import-rewriter.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAYhD,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,MAAM,CAAC,CAqHjB"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Import Rewriter for SWITE
|
|
3
|
+
*
|
|
4
|
+
* Design: collect-then-apply-right-to-left
|
|
5
|
+
*
|
|
6
|
+
* es-module-lexer gives positions {s, e} in the ORIGINAL string. The previous
|
|
7
|
+
* implementation tracked a running `offset` as replacements were applied, which
|
|
8
|
+
* accumulated errors when quote handling changed string lengths in unexpected
|
|
9
|
+
* ways and required three layers of fallback replacement logic.
|
|
10
|
+
*
|
|
11
|
+
* Instead we now:
|
|
12
|
+
* 1. Collect every replacement as {start, end, text} in original-string coordinates
|
|
13
|
+
* 2. Sort descending by start position
|
|
14
|
+
* 3. Apply right-to-left — each substitution cannot shift the position of any
|
|
15
|
+
* replacement to its left, so no offset tracking is needed at all.
|
|
16
|
+
*/
|
|
17
|
+
import { init, parse } from "es-module-lexer";
|
|
18
|
+
import { ModuleResolver } from "../resolver.js";
|
|
19
|
+
import { promises as fs } from "node:fs";
|
|
20
|
+
import path from "node:path";
|
|
21
|
+
import chalk from "chalk";
|
|
22
|
+
import { shouldUseCdnFallback } from "../cdn/cdn-fallback.js";
|
|
23
|
+
export async function rewriteImports(code, importer, resolver) {
|
|
24
|
+
await init;
|
|
25
|
+
try {
|
|
26
|
+
const [imports] = parse(code);
|
|
27
|
+
if (imports.length === 0)
|
|
28
|
+
return code;
|
|
29
|
+
const replacements = [];
|
|
30
|
+
for (const imp of imports) {
|
|
31
|
+
const { s: rawStart, e: rawEnd } = imp;
|
|
32
|
+
const rawSpecifier = code.slice(rawStart, rawEnd);
|
|
33
|
+
// Skip CSS imports — handled as static assets
|
|
34
|
+
if (rawSpecifier.includes(".css"))
|
|
35
|
+
continue;
|
|
36
|
+
// Determine actual specifier string and the span in `code` that includes quotes
|
|
37
|
+
const { specifier, start, end } = resolveQuotedSpan(code, rawSpecifier, rawStart, rawEnd);
|
|
38
|
+
if (specifier === null)
|
|
39
|
+
continue;
|
|
40
|
+
// Fix compiler bug: .uix/.ui imports emitted as .js or .tsx
|
|
41
|
+
if (specifier.startsWith(".") &&
|
|
42
|
+
(specifier.endsWith(".js") || specifier.endsWith(".tsx")) &&
|
|
43
|
+
!specifier.includes("node_modules")) {
|
|
44
|
+
const newExt = await resolveExtensionFix(specifier, importer);
|
|
45
|
+
if (newExt) {
|
|
46
|
+
const base = specifier.endsWith(".tsx") ? specifier.slice(0, -4) : specifier.slice(0, -3);
|
|
47
|
+
replacements.push({ start, end, text: `"${base}${newExt}"` });
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Skip relative and absolute path imports (already resolved)
|
|
52
|
+
if (specifier.startsWith(".") || specifier.startsWith("/"))
|
|
53
|
+
continue;
|
|
54
|
+
if (!/^[@a-zA-Z]/.test(specifier)) {
|
|
55
|
+
console.warn(`[SWITE] import-rewriter: Invalid specifier format: ${specifier}`);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
// Resolve bare import
|
|
59
|
+
let resolved;
|
|
60
|
+
try {
|
|
61
|
+
resolved = await resolver.resolve(specifier, importer);
|
|
62
|
+
if (!resolved || resolved === specifier || (!resolved.startsWith("/") && !resolved.startsWith("http"))) {
|
|
63
|
+
console.warn(chalk.yellow(`[SWITE] import-rewriter: Resolver returned invalid result for ${specifier}, using CDN fallback`));
|
|
64
|
+
resolved = shouldUseCdnFallback(specifier)
|
|
65
|
+
? `https://cdn.jsdelivr.net/npm/${specifier}/+esm`
|
|
66
|
+
: `/node_modules/${specifier}`;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
console.error(chalk.red(`[SWITE] import-rewriter: Error resolving ${specifier}:`), error);
|
|
71
|
+
resolved = shouldUseCdnFallback(specifier)
|
|
72
|
+
? `https://cdn.jsdelivr.net/npm/${specifier}/+esm`
|
|
73
|
+
: `/node_modules/${specifier}`;
|
|
74
|
+
}
|
|
75
|
+
// Prefer src/ over dist/ for workspace/swiss packages in dev
|
|
76
|
+
if (resolved.includes("/dist/") && (resolved.includes("/swiss-packages/") || resolved.includes("/packages/"))) {
|
|
77
|
+
resolved = resolved.replace("/dist/", "/src/").replace(/\.js$/, ".ts");
|
|
78
|
+
}
|
|
79
|
+
replacements.push({ start, end, text: `"${resolved}"` });
|
|
80
|
+
}
|
|
81
|
+
// Apply right-to-left so earlier positions are never shifted by later replacements
|
|
82
|
+
replacements.sort((a, b) => b.start - a.start);
|
|
83
|
+
let result = code;
|
|
84
|
+
for (const { start, end, text } of replacements) {
|
|
85
|
+
result = result.slice(0, start) + text + result.slice(end);
|
|
86
|
+
}
|
|
87
|
+
// Safety net: catch any bare scoped imports the lexer may have missed
|
|
88
|
+
const barePattern = /(?:import|from|export)\s+['"](@[^'"]+\/[^'"]+)[^'"]*['"]/g;
|
|
89
|
+
for (const match of Array.from(result.matchAll(barePattern))) {
|
|
90
|
+
const bareImport = match[1];
|
|
91
|
+
if (!bareImport.startsWith("/") && !bareImport.startsWith("http") && !bareImport.startsWith(".")) {
|
|
92
|
+
console.error(chalk.red(`[SWITE] import-rewriter: CRITICAL — bare import "${bareImport}" still present after rewriting`));
|
|
93
|
+
const replacement = shouldUseCdnFallback(bareImport)
|
|
94
|
+
? `https://cdn.jsdelivr.net/npm/${bareImport}/+esm`
|
|
95
|
+
: `/node_modules/${bareImport}`;
|
|
96
|
+
result = result.replace(new RegExp(bareImport.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), replacement);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Regex fallback: fix relative .js/.tsx extension mismatches the lexer may have missed
|
|
100
|
+
const normalizedImporter = importer.replace(/\\/g, "/");
|
|
101
|
+
const isSwissPackage = normalizedImporter.includes("/swiss-packages/");
|
|
102
|
+
const isUixFile = normalizedImporter.endsWith(".uix") || normalizedImporter.endsWith(".ui");
|
|
103
|
+
result = result.replace(/from\s+(["'])(\.\.?\/[^"']*?)(\.js|\.tsx)(\1)/g, (match, quote, importPath, _ext, endQuote) => {
|
|
104
|
+
if (importPath.includes("node_modules") || !importPath.startsWith("."))
|
|
105
|
+
return match;
|
|
106
|
+
const isLibPath = normalizedImporter.includes("/lib/");
|
|
107
|
+
let newExt;
|
|
108
|
+
if (isSwissPackage || isLibPath) {
|
|
109
|
+
newExt = ".ts";
|
|
110
|
+
}
|
|
111
|
+
else if (isUixFile) {
|
|
112
|
+
newExt = normalizedImporter.endsWith(".ui") ? ".ui" : ".uix";
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
newExt = ".ts";
|
|
116
|
+
}
|
|
117
|
+
return `from ${quote}${importPath}${newExt}${endQuote}`;
|
|
118
|
+
});
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
console.error(chalk.red(`[SWITE] import-rewriter: Error rewriting imports in ${importer}:`), error);
|
|
123
|
+
return code;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Given a raw specifier token from es-module-lexer, find the full quoted span
|
|
128
|
+
* in `code` (including the surrounding quote characters) and extract the clean
|
|
129
|
+
* specifier string. Returns `{specifier: null}` when the span cannot be found.
|
|
130
|
+
*/
|
|
131
|
+
function resolveQuotedSpan(code, rawSpecifier, rawStart, rawEnd) {
|
|
132
|
+
const first = rawSpecifier[0];
|
|
133
|
+
const last = rawSpecifier[rawSpecifier.length - 1];
|
|
134
|
+
// Case 1: lexer returned the specifier WITH surrounding quotes
|
|
135
|
+
if ((first === '"' || first === "'") && first === last) {
|
|
136
|
+
return {
|
|
137
|
+
specifier: rawSpecifier.slice(1, -1),
|
|
138
|
+
start: rawStart,
|
|
139
|
+
end: rawEnd,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
// Case 2: lexer returned the bare specifier; look one char back/forward for quotes
|
|
143
|
+
const charBefore = rawStart > 0 ? code[rawStart - 1] : "";
|
|
144
|
+
const charAfter = rawEnd < code.length ? code[rawEnd] : "";
|
|
145
|
+
if ((charBefore === '"' || charBefore === "'") && charBefore === charAfter) {
|
|
146
|
+
return {
|
|
147
|
+
specifier: rawSpecifier,
|
|
148
|
+
start: rawStart - 1,
|
|
149
|
+
end: rawEnd + 1,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
// Case 3: search nearby for a quoted pattern
|
|
153
|
+
const escaped = rawSpecifier.replace(/[.*+?^${}()|[\]\\-]/g, "\\$&");
|
|
154
|
+
const pattern = new RegExp(`(['"])${escaped}\\1`);
|
|
155
|
+
const match = pattern.exec(code);
|
|
156
|
+
if (match) {
|
|
157
|
+
return {
|
|
158
|
+
specifier: rawSpecifier,
|
|
159
|
+
start: match.index,
|
|
160
|
+
end: match.index + match[0].length,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
console.warn(`[SWITE] import-rewriter: Could not find quotes for specifier: ${rawSpecifier}`);
|
|
164
|
+
return { specifier: null, start: rawStart, end: rawEnd };
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Determine what extension a .js/.tsx import should be rewritten to,
|
|
168
|
+
* based on the importer's context and the actual files present on disk.
|
|
169
|
+
* Returns null when no rewrite is needed.
|
|
170
|
+
*/
|
|
171
|
+
async function resolveExtensionFix(specifier, importer) {
|
|
172
|
+
const normalizedImporter = importer.replace(/\\/g, "/");
|
|
173
|
+
const isSwissPackage = normalizedImporter.includes("/swiss-packages/");
|
|
174
|
+
const isLibPath = normalizedImporter.includes("/lib/");
|
|
175
|
+
const isUixFile = normalizedImporter.endsWith(".uix") || normalizedImporter.endsWith(".ui");
|
|
176
|
+
if (isSwissPackage || isLibPath)
|
|
177
|
+
return ".ts";
|
|
178
|
+
if (isUixFile) {
|
|
179
|
+
const base = specifier.endsWith(".tsx") ? specifier.slice(0, -4) : specifier.slice(0, -3);
|
|
180
|
+
const currentDir = path.dirname(importer);
|
|
181
|
+
const cleanPath = base.startsWith("./") ? base.slice(2) : base;
|
|
182
|
+
const uiPath = path.resolve(currentDir, cleanPath + ".ui");
|
|
183
|
+
const uixPath = path.resolve(currentDir, cleanPath + ".uix");
|
|
184
|
+
try {
|
|
185
|
+
await fs.access(uiPath);
|
|
186
|
+
return ".ui";
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
try {
|
|
190
|
+
await fs.access(uixPath);
|
|
191
|
+
return ".uix";
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
return ".ui";
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return ".ts";
|
|
199
|
+
}
|
|
@@ -7,7 +7,7 @@ export declare function buildSymlinkRegistry(nodeModulesDirs: string[]): Promise
|
|
|
7
7
|
*
|
|
8
8
|
* Example:
|
|
9
9
|
* /mnt/c/.../swiss-lib/packages/core/src/index.ts
|
|
10
|
-
* → /node_modules/@
|
|
10
|
+
* → /node_modules/@swissjs/core/src/index.ts
|
|
11
11
|
*/
|
|
12
12
|
export declare function lookupInSymlinkRegistry(absolutePath: string): string | null;
|
|
13
13
|
//# sourceMappingURL=symlink-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symlink-registry.d.ts","sourceRoot":"","sources":["../../src/resolution/symlink-registry.ts"],"names":[],"mappings":"AAoBA,wBAAsB,oBAAoB,CACxC,eAAe,EAAE,MAAM,EAAE,GACxB,OAAO,CAAC,IAAI,CAAC,CAQf;AA8DD;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAW3E"}
|
|
@@ -82,7 +82,7 @@ async function registerSymlink(symlinkPath, pkgName) {
|
|
|
82
82
|
*
|
|
83
83
|
* Example:
|
|
84
84
|
* /mnt/c/.../swiss-lib/packages/core/src/index.ts
|
|
85
|
-
* → /node_modules/@
|
|
85
|
+
* → /node_modules/@swissjs/core/src/index.ts
|
|
86
86
|
*/
|
|
87
87
|
export function lookupInSymlinkRegistry(absolutePath) {
|
|
88
88
|
const normalized = absolutePath.replace(/\\/g, "/");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-resolver.d.ts","sourceRoot":"","sources":["../../src/resolution/url-resolver.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC/C,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACpD;AAED,MAAM,MAAM,+BAA+B,GAAG,kBAAkB,CAAC;AAMjE;;GAEG;AACH,wBAAsB,KAAK,CACzB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,MAAM,CAAC,CA0MjB"}
|
|
@@ -4,24 +4,10 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { promises as fs } from "node:fs";
|
|
7
|
-
import { findSwissLibMonorepo } from "../
|
|
7
|
+
import { findSwissLibMonorepo } from "../kernel/package-finder.js";
|
|
8
8
|
import { lookupInSymlinkRegistry } from "./symlink-registry.js";
|
|
9
|
-
/**
|
|
10
|
-
* Normalize result to ensure no /swiss-lib/ paths leak to browser
|
|
11
|
-
*/
|
|
12
9
|
function normalizeResult(result) {
|
|
13
|
-
|
|
14
|
-
if (result.includes('/swiss-lib/')) {
|
|
15
|
-
console.log(`[SWITE] normalizeResult: Found /swiss-lib/ in "${result}", fixing...`);
|
|
16
|
-
result = result.replace(/\/swiss-lib\/packages\//g, '/swiss-packages/');
|
|
17
|
-
result = result.replace(/\/swiss-lib\//g, '/swiss-packages/');
|
|
18
|
-
console.log(`[SWITE] normalizeResult: Fixed to "${result}"`);
|
|
19
|
-
}
|
|
20
|
-
result = result.replace(/\\/g, '/');
|
|
21
|
-
if (original !== result && original.includes('swiss-lib')) {
|
|
22
|
-
console.log(`[SWITE] normalizeResult: Final result "${result}" (was "${original}")`);
|
|
23
|
-
}
|
|
24
|
-
return result;
|
|
10
|
+
return result.replace(/\\/g, '/');
|
|
25
11
|
}
|
|
26
12
|
/**
|
|
27
13
|
* Convert file path to URL for browser
|
|
@@ -85,103 +71,72 @@ export async function toUrl(filePath, context) {
|
|
|
85
71
|
return normalizeResult(url);
|
|
86
72
|
}
|
|
87
73
|
}
|
|
88
|
-
// If path is already a URL (starts with / or http),
|
|
74
|
+
// If path is already a URL (starts with / or http), prefer src over dist for workspace packages
|
|
89
75
|
if (normalized.startsWith("/") || normalized.startsWith("http")) {
|
|
90
|
-
|
|
91
|
-
if (normalized.includes("/
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (workingPath.includes("/dist/") && !workingPath.includes("/src/")) {
|
|
95
|
-
const srcPath = workingPath.replace("/dist/", "/src/").replace(/\.js$/, ".ts");
|
|
96
|
-
console.log(`[SWITE] toUrl: Checking for source file: ${srcPath}`);
|
|
97
|
-
const { resolveFilePath } = await import("../utils/file-path-resolver.js");
|
|
98
|
-
const workspaceRoot = await context.getWorkspaceRoot();
|
|
99
|
-
const srcFilePath = await resolveFilePath(srcPath, context.root, workspaceRoot);
|
|
100
|
-
console.log(`[SWITE] toUrl: Resolved source file path: ${srcFilePath}, exists: ${await context.fileExists(srcFilePath)}`);
|
|
101
|
-
if (await context.fileExists(srcFilePath)) {
|
|
102
|
-
console.log(`[SWITE] toUrl: Preferring source over dist: ${srcPath}`);
|
|
103
|
-
return normalizeResult(srcPath);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return normalizeResult(workingPath);
|
|
107
|
-
}
|
|
108
|
-
// Only prefer src over dist for workspace/swiss packages — never for node_modules
|
|
109
|
-
// (published packages only ship dist; the swiss-lib monorepo finder can
|
|
110
|
-
// accidentally resolve src/index.ts from a sibling repo for npm packages)
|
|
111
|
-
if (workingPath.includes("/dist/") && !workingPath.includes("/src/") && !workingPath.includes("/node_modules/")) {
|
|
112
|
-
const srcPath = workingPath.replace("/dist/", "/src/").replace(/\.js$/, ".ts");
|
|
113
|
-
console.log(`[SWITE] toUrl: Checking for source file: ${srcPath}`);
|
|
114
|
-
const { resolveFilePath } = await import("../utils/file-path-resolver.js");
|
|
76
|
+
// Only prefer src over dist for workspace packages — never for node_modules
|
|
77
|
+
if (normalized.includes("/dist/") && !normalized.includes("/src/") && !normalized.includes("/node_modules/")) {
|
|
78
|
+
const srcPath = normalized.replace("/dist/", "/src/").replace(/\.js$/, ".ts");
|
|
79
|
+
const { resolveFilePath } = await import("./path/file-path-resolver.js");
|
|
115
80
|
const workspaceRoot = await context.getWorkspaceRoot();
|
|
116
81
|
const srcFilePath = await resolveFilePath(srcPath, context.root, workspaceRoot);
|
|
117
|
-
console.log(`[SWITE] toUrl: Resolved source file path: ${srcFilePath}, exists: ${await context.fileExists(srcFilePath)}`);
|
|
118
82
|
if (await context.fileExists(srcFilePath)) {
|
|
119
|
-
console.log(`[SWITE] toUrl: Preferring source over dist: ${srcPath}`);
|
|
120
83
|
return normalizeResult(srcPath);
|
|
121
84
|
}
|
|
122
85
|
}
|
|
123
|
-
return normalizeResult(
|
|
86
|
+
return normalizeResult(normalized);
|
|
124
87
|
}
|
|
125
|
-
// If path is absolute,
|
|
88
|
+
// If path is absolute, convert to a browser-relative URL
|
|
126
89
|
if (path.isAbsolute(filePath)) {
|
|
127
90
|
const workspaceRoot = await context.getWorkspaceRoot();
|
|
128
|
-
// Check if
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
91
|
+
// Check if the file lives in a co-located framework monorepo's packages/ directory.
|
|
92
|
+
// Serve those files under /swiss-packages/ so the browser can request them distinctly
|
|
93
|
+
// from the app's own files. Works for any framework at any directory name.
|
|
94
|
+
const monorepo = await findSwissLibMonorepo(context.root);
|
|
95
|
+
if (monorepo) {
|
|
96
|
+
const packagesPath = path.join(monorepo, "packages");
|
|
97
|
+
let resolvedPackages;
|
|
134
98
|
let resolvedFilePath;
|
|
135
99
|
try {
|
|
136
|
-
|
|
100
|
+
resolvedPackages = await fs.realpath(packagesPath);
|
|
137
101
|
resolvedFilePath = await fs.realpath(filePath);
|
|
138
102
|
}
|
|
139
103
|
catch {
|
|
140
|
-
|
|
104
|
+
resolvedPackages = path.resolve(packagesPath);
|
|
141
105
|
resolvedFilePath = path.resolve(filePath);
|
|
142
106
|
}
|
|
143
|
-
const
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
const origFilePath = resolvedFilePath.replace(/\\/g, "/");
|
|
150
|
-
const relative = origFilePath.slice(origSwissPackages.length);
|
|
107
|
+
const normalizedPackages = resolvedPackages.replace(/\\/g, "/").toLowerCase();
|
|
108
|
+
const normalizedResolved = resolvedFilePath.replace(/\\/g, "/").toLowerCase();
|
|
109
|
+
if (normalizedResolved.startsWith(normalizedPackages)) {
|
|
110
|
+
const origPackages = resolvedPackages.replace(/\\/g, "/");
|
|
111
|
+
const origFile = resolvedFilePath.replace(/\\/g, "/");
|
|
112
|
+
const relative = origFile.slice(origPackages.length);
|
|
151
113
|
const url = "/swiss-packages" + (relative.startsWith("/") ? relative : "/" + relative);
|
|
152
114
|
if (url.includes("/dist/") && !url.includes("/src/")) {
|
|
153
115
|
const srcUrl = url.replace("/dist/", "/src/").replace(/\.js$/, ".ts");
|
|
154
116
|
const srcRelative = srcUrl.replace("/swiss-packages/", "");
|
|
155
|
-
const srcFilePath = path.join(
|
|
156
|
-
console.log(`[SWITE] toUrl: Checking source file: ${srcFilePath}, exists: ${await context.fileExists(srcFilePath)}`);
|
|
117
|
+
const srcFilePath = path.join(packagesPath, srcRelative);
|
|
157
118
|
if (await context.fileExists(srcFilePath)) {
|
|
158
|
-
console.log(`[SWITE] toUrl: Preferring source over dist: ${srcUrl}`);
|
|
159
119
|
return normalizeResult(srcUrl);
|
|
160
120
|
}
|
|
161
121
|
}
|
|
162
|
-
console.log(`[SWITE] toUrl: ${filePath} -> ${url} (swiss-lib package)`);
|
|
163
122
|
return normalizeResult(url);
|
|
164
123
|
}
|
|
165
124
|
}
|
|
166
|
-
//
|
|
125
|
+
// node_modules absolute path → browser /node_modules/... URL
|
|
167
126
|
const origFilePathNormalized = path.resolve(filePath).replace(/\\/g, "/");
|
|
168
127
|
if (origFilePathNormalized.toLowerCase().includes("/node_modules/")) {
|
|
169
128
|
const nodeModulesIndex = origFilePathNormalized.toLowerCase().indexOf("/node_modules/");
|
|
170
129
|
const afterNodeModules = origFilePathNormalized.slice(nodeModulesIndex + "/node_modules/".length);
|
|
171
|
-
|
|
172
|
-
console.log(`[SWITE] toUrl: ${filePath} -> ${url} (node_modules, preserving case)`);
|
|
173
|
-
return normalizeResult(url);
|
|
130
|
+
return normalizeResult("/node_modules/" + afterNodeModules);
|
|
174
131
|
}
|
|
175
|
-
// Try relative to app root FIRST
|
|
176
|
-
const normalizedRoot = path.resolve(context.root).replace(/\\/g, "/").toLowerCase();
|
|
177
132
|
const normalizedFilePath = path.resolve(filePath).replace(/\\/g, "/").toLowerCase();
|
|
133
|
+
// Try relative to app root first
|
|
134
|
+
const normalizedRoot = path.resolve(context.root).replace(/\\/g, "/").toLowerCase();
|
|
178
135
|
if (normalizedFilePath.startsWith(normalizedRoot)) {
|
|
179
136
|
const origRoot = path.resolve(context.root).replace(/\\/g, "/");
|
|
180
137
|
const origFilePath = path.resolve(filePath).replace(/\\/g, "/");
|
|
181
138
|
const relative = origFilePath.slice(origRoot.length);
|
|
182
|
-
|
|
183
|
-
console.log(`[SWITE] toUrl: ${filePath} -> ${url} (app root: ${context.root})`);
|
|
184
|
-
return normalizeResult(url);
|
|
139
|
+
return normalizeResult(relative.startsWith("/") ? relative : "/" + relative);
|
|
185
140
|
}
|
|
186
141
|
// Try workspace root
|
|
187
142
|
if (workspaceRoot) {
|
|
@@ -189,51 +144,25 @@ export async function toUrl(filePath, context) {
|
|
|
189
144
|
if (normalizedFilePath.startsWith(normalizedWorkspaceRoot)) {
|
|
190
145
|
const origWorkspaceRoot = path.resolve(workspaceRoot).replace(/\\/g, "/");
|
|
191
146
|
const origFilePath = path.resolve(filePath).replace(/\\/g, "/");
|
|
192
|
-
// CRITICAL: Check if this is a swiss-lib path BEFORE computing relative
|
|
193
|
-
const normalizedOrigFilePath = origFilePath.toLowerCase();
|
|
194
|
-
console.log(`[SWITE] toUrl DEBUG: origFilePath="${origFilePath}", normalized="${normalizedOrigFilePath}", checking for swiss-lib...`);
|
|
195
|
-
if (normalizedOrigFilePath.includes("/swiss-lib/packages/") || normalizedOrigFilePath.includes("\\swiss-lib\\packages\\")) {
|
|
196
|
-
console.log(`[SWITE] toUrl DEBUG: ✅ Found swiss-lib in path!`);
|
|
197
|
-
const swissLibIndex = normalizedOrigFilePath.indexOf("/swiss-lib/packages/");
|
|
198
|
-
const swissLibIndexBackslash = normalizedOrigFilePath.indexOf("\\swiss-lib\\packages\\");
|
|
199
|
-
const index = swissLibIndex >= 0 ? swissLibIndex : swissLibIndexBackslash;
|
|
200
|
-
const separator = swissLibIndex >= 0 ? "/swiss-lib/packages/" : "\\swiss-lib\\packages\\";
|
|
201
|
-
const afterSwissLib = origFilePath.slice(index + separator.length);
|
|
202
|
-
const url = "/swiss-packages/" + afterSwissLib.replace(/\\/g, "/");
|
|
203
|
-
console.log(`[SWITE] toUrl: ${filePath} -> ${url} (swiss-lib via workspace root - FIXED)`);
|
|
204
|
-
return normalizeResult(url);
|
|
205
|
-
}
|
|
206
147
|
const relative = origFilePath.slice(origWorkspaceRoot.length);
|
|
207
148
|
let url = relative.startsWith("/") ? relative : "/" + relative;
|
|
208
|
-
// Prefer src over dist for workspace
|
|
209
|
-
if (url.includes("/packages/") &&
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
149
|
+
// Prefer src over dist for workspace packages in dev
|
|
150
|
+
if (url.includes("/packages/") && url.includes("/dist/") && !(await context.fileExists(filePath))) {
|
|
151
|
+
const srcPath = filePath
|
|
152
|
+
.replace(/[/\\]dist[/\\]/, path.sep + "src" + path.sep)
|
|
153
|
+
.replace(/\.js$/i, ".ts");
|
|
213
154
|
if (await context.fileExists(srcPath)) {
|
|
214
155
|
const srcRelative = path.relative(workspaceRoot, srcPath).replace(/\\/g, "/");
|
|
215
156
|
url = "/" + srcRelative;
|
|
216
|
-
console.log(`[SWITE] toUrl: Preferring src over dist (packages): ${url}`);
|
|
217
157
|
}
|
|
218
158
|
}
|
|
219
|
-
console.log(`[SWITE] toUrl DOUBLE CHECK: url="${url}", lowercase="${url.toLowerCase()}", includes="/swiss-lib/"=${url.toLowerCase().includes("/swiss-lib/")}`);
|
|
220
|
-
// DOUBLE CHECK: If computed URL contains /swiss-lib/, fix it
|
|
221
|
-
if (url.toLowerCase().includes("/swiss-lib/")) {
|
|
222
|
-
console.log(`[SWITE] toUrl DOUBLE CHECK: ✅ MATCHED! Fixing URL...`);
|
|
223
|
-
const fixedUrl = url.replace(/\/swiss-lib\/packages\//gi, "/swiss-packages/").replace(/\/swiss-lib\//gi, "/swiss-packages/");
|
|
224
|
-
console.log(`[SWITE] toUrl: ${filePath} -> ${fixedUrl} (workspace root - FIXED /swiss-lib/ in URL)`);
|
|
225
|
-
return normalizeResult(fixedUrl);
|
|
226
|
-
}
|
|
227
|
-
console.log(`[SWITE] toUrl: ${filePath} -> ${url} (workspace: ${workspaceRoot})`);
|
|
228
159
|
return normalizeResult(url);
|
|
229
160
|
}
|
|
230
161
|
}
|
|
231
162
|
// Fallback
|
|
232
|
-
const
|
|
233
|
-
const baseRoot = fallbackWorkspaceRoot || context.root;
|
|
163
|
+
const baseRoot = workspaceRoot || context.root;
|
|
234
164
|
const rawRelative = path.relative(baseRoot, filePath);
|
|
235
|
-
// CG-03:
|
|
236
|
-
// Guard: if the result is absolute or escapes root with '..', strip prefix directly.
|
|
165
|
+
// CG-03: guard against absolute result from path.relative() on cross-drive/WSL paths
|
|
237
166
|
let url;
|
|
238
167
|
if (path.isAbsolute(rawRelative) || rawRelative.startsWith("..")) {
|
|
239
168
|
const normalizedBase = path.resolve(baseRoot).replace(/\\/g, "/");
|
|
@@ -246,7 +175,7 @@ export async function toUrl(filePath, context) {
|
|
|
246
175
|
else {
|
|
247
176
|
url = "/" + rawRelative.replace(/\\/g, "/");
|
|
248
177
|
}
|
|
249
|
-
console.warn(`[SWITE] toUrl fallback: ${filePath} -> ${url}
|
|
178
|
+
console.warn(`[SWITE] toUrl fallback: ${filePath} -> ${url}`);
|
|
250
179
|
return normalizeResult(url);
|
|
251
180
|
}
|
|
252
181
|
// Default: make relative to root
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-package-resolver.d.ts","sourceRoot":"","sources":["../../src/resolution/workspace-package-resolver.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,+BAA+B;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC/C,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACpD;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwExB"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Workspace Package Resolver - Finds packages in workspace
|
|
3
|
+
* Uses dynamic package registry instead of hardcoded paths
|
|
4
|
+
*/
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { findSwissLibMonorepo } from "../kernel/package-finder.js";
|
|
7
|
+
import { getPackageRegistry } from "../kernel/package-registry.js";
|
|
8
|
+
/**
|
|
9
|
+
* Resolve workspace package location
|
|
10
|
+
*/
|
|
11
|
+
export async function resolveWorkspacePackage(pkgName, context) {
|
|
12
|
+
// Build the ordered list of roots to scan for workspace packages.
|
|
13
|
+
// Works for any package name/scope — no hardcoded scope guards.
|
|
14
|
+
const workspaceRoots = [];
|
|
15
|
+
let workspaceRoot = await context.getWorkspaceRoot();
|
|
16
|
+
if (workspaceRoot) {
|
|
17
|
+
workspaceRoots.push(workspaceRoot);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
// Walk up from app root looking for common workspace markers
|
|
21
|
+
for (const candidate of [
|
|
22
|
+
path.join(context.root, ".."),
|
|
23
|
+
path.join(context.root, "..", ".."),
|
|
24
|
+
]) {
|
|
25
|
+
const normalized = path.resolve(candidate);
|
|
26
|
+
if ((await context.fileExists(path.join(normalized, "pnpm-workspace.yaml"))) ||
|
|
27
|
+
(await context.fileExists(path.join(normalized, "modules"))) ||
|
|
28
|
+
(await context.fileExists(path.join(normalized, "libraries")))) {
|
|
29
|
+
workspaceRoot = normalized;
|
|
30
|
+
workspaceRoots.push(normalized);
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (!workspaceRoots.length) {
|
|
35
|
+
workspaceRoots.push(path.join(context.root, "..", ".."));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Also include any co-located framework monorepo (any workspace with packages/)
|
|
39
|
+
try {
|
|
40
|
+
const monorepo = await findSwissLibMonorepo(context.root);
|
|
41
|
+
if (monorepo && !workspaceRoots.includes(monorepo)) {
|
|
42
|
+
workspaceRoots.unshift(monorepo);
|
|
43
|
+
}
|
|
44
|
+
if (monorepo) {
|
|
45
|
+
const packagesDir = path.join(monorepo, "packages");
|
|
46
|
+
if (await context.fileExists(packagesDir) && !workspaceRoots.includes(packagesDir)) {
|
|
47
|
+
workspaceRoots.unshift(packagesDir);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// monorepo not found — continue without it
|
|
53
|
+
}
|
|
54
|
+
const registry = getPackageRegistry();
|
|
55
|
+
const primaryRoot = workspaceRoots[0] ?? context.root;
|
|
56
|
+
const additionalRoots = workspaceRoots.slice(1);
|
|
57
|
+
if (!registry.getPackageCount() && primaryRoot) {
|
|
58
|
+
try {
|
|
59
|
+
await registry.scanWorkspace(primaryRoot, additionalRoots);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
console.error(`[SWITE] Error scanning package registry:`, error.message);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
let packageInfo = registry.findPackage(pkgName);
|
|
66
|
+
if (packageInfo) {
|
|
67
|
+
return packageInfo.path;
|
|
68
|
+
}
|
|
69
|
+
// Rescan in case the package was added after the initial scan
|
|
70
|
+
await registry.rescan();
|
|
71
|
+
packageInfo = registry.findPackage(pkgName);
|
|
72
|
+
if (packageInfo) {
|
|
73
|
+
return packageInfo.path;
|
|
74
|
+
}
|
|
75
|
+
console.log(`[SWITE] Package ${pkgName} not found in workspace (scanned ${registry.getPackageCount()} packages)`);
|
|
76
|
+
return null;
|
|
77
|
+
}
|