@swissjs/swite 0.3.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.
Files changed (163) hide show
  1. package/.changeset/config.json +11 -0
  2. package/.github/workflows/ci.yml +59 -0
  3. package/.github/workflows/publish.yml +50 -0
  4. package/.github/workflows/release.yml +53 -0
  5. package/BUILD_ANALYSIS.md +89 -0
  6. package/BUILD_STRATEGY.md +75 -0
  7. package/CHANGELOG.md +53 -0
  8. package/DIRECTIVE.md +488 -0
  9. package/__tests__/css-extraction.test.ts +261 -0
  10. package/__tests__/css-injection-integration.test.ts +247 -0
  11. package/__tests__/css-middleware.test.ts +191 -0
  12. package/__tests__/import-rewriter-bug.test.ts +135 -0
  13. package/dist/builder.d.ts +36 -0
  14. package/dist/builder.d.ts.map +1 -0
  15. package/dist/builder.js +772 -0
  16. package/dist/cache/compilation-cache.d.ts +33 -0
  17. package/dist/cache/compilation-cache.d.ts.map +1 -0
  18. package/dist/cache/compilation-cache.js +130 -0
  19. package/dist/cli.d.ts +3 -0
  20. package/dist/cli.d.ts.map +1 -0
  21. package/dist/cli.js +85 -0
  22. package/dist/config-loader.d.ts +8 -0
  23. package/dist/config-loader.d.ts.map +1 -0
  24. package/dist/config-loader.js +40 -0
  25. package/dist/config.d.ts +29 -0
  26. package/dist/config.d.ts.map +1 -0
  27. package/dist/config.js +7 -0
  28. package/dist/dev/pythonDevManager.d.ts +12 -0
  29. package/dist/dev/pythonDevManager.d.ts.map +1 -0
  30. package/dist/dev/pythonDevManager.js +85 -0
  31. package/dist/env.d.ts +19 -0
  32. package/dist/env.d.ts.map +1 -0
  33. package/dist/env.js +112 -0
  34. package/dist/handlers/base-handler.d.ts +21 -0
  35. package/dist/handlers/base-handler.d.ts.map +1 -0
  36. package/dist/handlers/base-handler.js +38 -0
  37. package/dist/handlers/js-handler.d.ts +10 -0
  38. package/dist/handlers/js-handler.d.ts.map +1 -0
  39. package/dist/handlers/js-handler.js +87 -0
  40. package/dist/handlers/mjs-handler.d.ts +8 -0
  41. package/dist/handlers/mjs-handler.d.ts.map +1 -0
  42. package/dist/handlers/mjs-handler.js +44 -0
  43. package/dist/handlers/node-module-handler.d.ts +16 -0
  44. package/dist/handlers/node-module-handler.d.ts.map +1 -0
  45. package/dist/handlers/node-module-handler.js +267 -0
  46. package/dist/handlers/ts-handler.d.ts +11 -0
  47. package/dist/handlers/ts-handler.d.ts.map +1 -0
  48. package/dist/handlers/ts-handler.js +120 -0
  49. package/dist/handlers/ui-handler.d.ts +12 -0
  50. package/dist/handlers/ui-handler.d.ts.map +1 -0
  51. package/dist/handlers/ui-handler.js +182 -0
  52. package/dist/handlers/uix-handler.d.ts +12 -0
  53. package/dist/handlers/uix-handler.d.ts.map +1 -0
  54. package/dist/handlers/uix-handler.js +135 -0
  55. package/dist/hmr.d.ts +20 -0
  56. package/dist/hmr.d.ts.map +1 -0
  57. package/dist/hmr.js +265 -0
  58. package/dist/import-rewriter.d.ts +3 -0
  59. package/dist/import-rewriter.d.ts.map +1 -0
  60. package/dist/import-rewriter.js +351 -0
  61. package/dist/index.d.ts +14 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +13 -0
  64. package/dist/middleware/hmr-routes.d.ts +12 -0
  65. package/dist/middleware/hmr-routes.d.ts.map +1 -0
  66. package/dist/middleware/hmr-routes.js +97 -0
  67. package/dist/middleware/middleware-setup.d.ts +23 -0
  68. package/dist/middleware/middleware-setup.d.ts.map +1 -0
  69. package/dist/middleware/middleware-setup.js +596 -0
  70. package/dist/middleware/static-files.d.ts +15 -0
  71. package/dist/middleware/static-files.d.ts.map +1 -0
  72. package/dist/middleware/static-files.js +585 -0
  73. package/dist/proxy/SwiteProxyError.d.ts +6 -0
  74. package/dist/proxy/SwiteProxyError.d.ts.map +1 -0
  75. package/dist/proxy/SwiteProxyError.js +9 -0
  76. package/dist/proxy/proxyToPython.d.ts +28 -0
  77. package/dist/proxy/proxyToPython.d.ts.map +1 -0
  78. package/dist/proxy/proxyToPython.js +66 -0
  79. package/dist/resolver/bare-import-resolver.d.ts +9 -0
  80. package/dist/resolver/bare-import-resolver.d.ts.map +1 -0
  81. package/dist/resolver/bare-import-resolver.js +363 -0
  82. package/dist/resolver/symlink-registry.d.ts +13 -0
  83. package/dist/resolver/symlink-registry.d.ts.map +1 -0
  84. package/dist/resolver/symlink-registry.js +98 -0
  85. package/dist/resolver/url-resolver.d.ts +11 -0
  86. package/dist/resolver/url-resolver.d.ts.map +1 -0
  87. package/dist/resolver/url-resolver.js +268 -0
  88. package/dist/resolver/workspace-package-resolver.d.ts +10 -0
  89. package/dist/resolver/workspace-package-resolver.d.ts.map +1 -0
  90. package/dist/resolver/workspace-package-resolver.js +185 -0
  91. package/dist/resolver.d.ts +17 -0
  92. package/dist/resolver.d.ts.map +1 -0
  93. package/dist/resolver.js +191 -0
  94. package/dist/router/file-router.d.ts +19 -0
  95. package/dist/router/file-router.d.ts.map +1 -0
  96. package/dist/router/file-router.js +114 -0
  97. package/dist/server.d.ts +22 -0
  98. package/dist/server.d.ts.map +1 -0
  99. package/dist/server.js +122 -0
  100. package/dist/utils/cdn-fallback.d.ts +14 -0
  101. package/dist/utils/cdn-fallback.d.ts.map +1 -0
  102. package/dist/utils/cdn-fallback.js +36 -0
  103. package/dist/utils/file-path-resolver.d.ts +9 -0
  104. package/dist/utils/file-path-resolver.d.ts.map +1 -0
  105. package/dist/utils/file-path-resolver.js +187 -0
  106. package/dist/utils/generate-import-map-cli.d.ts +3 -0
  107. package/dist/utils/generate-import-map-cli.d.ts.map +1 -0
  108. package/dist/utils/generate-import-map-cli.js +32 -0
  109. package/dist/utils/generate-import-map.d.ts +21 -0
  110. package/dist/utils/generate-import-map.d.ts.map +1 -0
  111. package/dist/utils/generate-import-map.js +119 -0
  112. package/dist/utils/package-finder.d.ts +24 -0
  113. package/dist/utils/package-finder.d.ts.map +1 -0
  114. package/dist/utils/package-finder.js +161 -0
  115. package/dist/utils/package-registry.d.ts +36 -0
  116. package/dist/utils/package-registry.d.ts.map +1 -0
  117. package/dist/utils/package-registry.js +159 -0
  118. package/dist/utils/workspace.d.ts +6 -0
  119. package/dist/utils/workspace.d.ts.map +1 -0
  120. package/dist/utils/workspace.js +65 -0
  121. package/docs/IMPORT_REWRITING.md +164 -0
  122. package/docs/IMPORT_REWRITING_TROUBLESHOOTING.md +139 -0
  123. package/docs/PATH_RESOLUTION_GUIDE.md +221 -0
  124. package/package.json +49 -0
  125. package/src/adapters/proxy/SwiteProxyError.ts +12 -0
  126. package/src/adapters/proxy/proxyToPython.ts +88 -0
  127. package/src/build-engine/builder.ts +960 -0
  128. package/src/cli.ts +109 -0
  129. package/src/config/config-loader.ts +46 -0
  130. package/src/config/config.ts +34 -0
  131. package/src/config/env.ts +98 -0
  132. package/src/dev-engine/handlers/base-handler.ts +68 -0
  133. package/src/dev-engine/handlers/js-handler.ts +134 -0
  134. package/src/dev-engine/handlers/mjs-handler.ts +65 -0
  135. package/src/dev-engine/handlers/node-module-handler.ts +339 -0
  136. package/src/dev-engine/handlers/ts-handler.ts +143 -0
  137. package/src/dev-engine/handlers/ui-handler.ts +105 -0
  138. package/src/dev-engine/handlers/uix-handler.ts +90 -0
  139. package/src/dev-engine/hmr/hmr-client-template.ts +122 -0
  140. package/src/dev-engine/hmr/hmr.ts +173 -0
  141. package/src/dev-engine/middleware/hmr-routes.ts +120 -0
  142. package/src/dev-engine/middleware/middleware-setup.ts +351 -0
  143. package/src/dev-engine/middleware/static-files.ts +728 -0
  144. package/src/dev-engine/pythonDevManager.ts +116 -0
  145. package/src/dev-engine/router/file-router.ts +164 -0
  146. package/src/dev-engine/server.ts +152 -0
  147. package/src/index.ts +26 -0
  148. package/src/internal/cache/compilation-cache.ts +182 -0
  149. package/src/internal/generate-import-map-cli.ts +40 -0
  150. package/src/internal/generate-import-map.ts +154 -0
  151. package/src/kernel/package-finder.ts +164 -0
  152. package/src/kernel/package-registry.ts +198 -0
  153. package/src/kernel/workspace.ts +62 -0
  154. package/src/resolution/bare-import-resolver.ts +400 -0
  155. package/src/resolution/cdn/cdn-fallback.ts +37 -0
  156. package/src/resolution/path/file-path-resolver.ts +190 -0
  157. package/src/resolution/path/path-fixup.ts +19 -0
  158. package/src/resolution/resolver.ts +198 -0
  159. package/src/resolution/rewriting/import-rewriter.ts +237 -0
  160. package/src/resolution/symlink-registry.ts +114 -0
  161. package/src/resolution/url-resolver.ts +231 -0
  162. package/src/resolution/workspace-package-resolver.ts +94 -0
  163. package/tsconfig.json +37 -0
@@ -0,0 +1,268 @@
1
+ /*
2
+ * URL Resolver - Converts file paths to URLs
3
+ * Extracted from resolver.ts for modularity
4
+ */
5
+ import path from "node:path";
6
+ import { promises as fs } from "node:fs";
7
+ import { findSwissLibMonorepo } from "../utils/package-finder.js";
8
+ import { lookupInSymlinkRegistry } from "./symlink-registry.js";
9
+ /**
10
+ * Normalize result to ensure no /swiss-lib/ paths leak to browser
11
+ */
12
+ function normalizeResult(result) {
13
+ const original = result;
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;
25
+ }
26
+ /**
27
+ * Convert file path to URL for browser
28
+ */
29
+ export async function toUrl(filePath, context) {
30
+ const normalized = filePath.replace(/\\/g, "/");
31
+ // CG-03: Check symlink registry FIRST.
32
+ // Absolute filesystem paths (both realpath-resolved and unresolved symlinks)
33
+ // must be mapped back to browser URLs before the startsWith("/") early-return
34
+ // fires and mangled by normalizeResult().
35
+ // The registry maps realpath → /node_modules/<pkg> browser URL prefix.
36
+ if (path.isAbsolute(filePath)) {
37
+ // Direct lookup (path is already a realpath, e.g. from fs.realpath() in ts-handler)
38
+ let registryUrl = lookupInSymlinkRegistry(normalized);
39
+ // Fallback: resolve symlinks and retry (path may still contain symlink segments,
40
+ // e.g. app/node_modules/@alpine/core/... where app/node_modules is itself a symlink)
41
+ if (!registryUrl) {
42
+ try {
43
+ const realPath = (await fs.realpath(filePath)).replace(/\\/g, "/");
44
+ if (realPath !== normalized) {
45
+ registryUrl = lookupInSymlinkRegistry(realPath);
46
+ }
47
+ }
48
+ catch {
49
+ // file may not exist yet; ignore
50
+ }
51
+ }
52
+ if (registryUrl) {
53
+ console.log(`[SWITE] toUrl: symlink registry hit: ${filePath} → ${registryUrl}`);
54
+ return registryUrl;
55
+ }
56
+ // If the absolute filesystem path contains /node_modules/, convert it to a
57
+ // browser-relative URL (/node_modules/...) before the startsWith("/") early
58
+ // return below swallows it as an already-resolved URL.
59
+ if (normalized.toLowerCase().includes("/node_modules/")) {
60
+ const nodeModulesIndex = normalized.toLowerCase().indexOf("/node_modules/");
61
+ const afterNodeModules = normalized.slice(nodeModulesIndex + "/node_modules/".length);
62
+ const url = "/node_modules/" + afterNodeModules;
63
+ console.log(`[SWITE] toUrl: abs→node_modules URL: ${filePath} → ${url}`);
64
+ return normalizeResult(url);
65
+ }
66
+ // Convert absolute workspace/app paths to browser-relative URLs before the
67
+ // startsWith("/") early-return below treats them as already-resolved URLs.
68
+ // e.g. /app/modules/pos/src/index.ui → /modules/pos/src/index.ui
69
+ const workspaceRootForAbs = await context.getWorkspaceRoot();
70
+ const normalizedLower = normalized.toLowerCase();
71
+ if (workspaceRootForAbs) {
72
+ const wsRoot = path.resolve(workspaceRootForAbs).replace(/\\/g, "/");
73
+ if (normalizedLower.startsWith(wsRoot.toLowerCase() + "/") || normalizedLower === wsRoot.toLowerCase()) {
74
+ const relative = normalized.slice(wsRoot.length);
75
+ const url = relative.startsWith("/") ? relative : "/" + relative;
76
+ console.log(`[SWITE] toUrl: abs→workspace URL: ${filePath} → ${url}`);
77
+ return normalizeResult(url);
78
+ }
79
+ }
80
+ const appRoot = path.resolve(context.root).replace(/\\/g, "/");
81
+ if (normalizedLower.startsWith(appRoot.toLowerCase() + "/") || normalizedLower === appRoot.toLowerCase()) {
82
+ const relative = normalized.slice(appRoot.length);
83
+ const url = relative.startsWith("/") ? relative : "/" + relative;
84
+ console.log(`[SWITE] toUrl: abs→approot URL: ${filePath} → ${url}`);
85
+ return normalizeResult(url);
86
+ }
87
+ }
88
+ // If path is already a URL (starts with / or http), check for source file first
89
+ if (normalized.startsWith("/") || normalized.startsWith("http")) {
90
+ let workingPath = normalized;
91
+ if (normalized.includes("/swiss-lib/packages/")) {
92
+ workingPath = normalized.replace(/\/swiss-lib\/packages\//g, "/swiss-packages/");
93
+ console.log(`[SWITE] toUrl: Converting /swiss-lib/ to /swiss-packages/: ${normalized} -> ${workingPath}`);
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");
115
+ const workspaceRoot = await context.getWorkspaceRoot();
116
+ const srcFilePath = await resolveFilePath(srcPath, context.root, workspaceRoot);
117
+ console.log(`[SWITE] toUrl: Resolved source file path: ${srcFilePath}, exists: ${await context.fileExists(srcFilePath)}`);
118
+ if (await context.fileExists(srcFilePath)) {
119
+ console.log(`[SWITE] toUrl: Preferring source over dist: ${srcPath}`);
120
+ return normalizeResult(srcPath);
121
+ }
122
+ }
123
+ return normalizeResult(workingPath);
124
+ }
125
+ // If path is absolute, try to make it relative to workspace root or server root
126
+ if (path.isAbsolute(filePath)) {
127
+ const workspaceRoot = await context.getWorkspaceRoot();
128
+ // Check if this is a swiss-lib monorepo package (@kibologic/*)
129
+ const swissLib = await findSwissLibMonorepo(context.root);
130
+ console.log(`[SWITE] toUrl: swiss-lib check - swissLib=${swissLib}, this.root=${context.root}, filePath=${filePath}`);
131
+ if (swissLib) {
132
+ const swissPackagesPath = path.join(swissLib, "packages");
133
+ let resolvedSwissPackages;
134
+ let resolvedFilePath;
135
+ try {
136
+ resolvedSwissPackages = await fs.realpath(swissPackagesPath);
137
+ resolvedFilePath = await fs.realpath(filePath);
138
+ }
139
+ catch {
140
+ resolvedSwissPackages = path.resolve(swissPackagesPath);
141
+ resolvedFilePath = path.resolve(filePath);
142
+ }
143
+ const normalizedSwissPackages = resolvedSwissPackages.replace(/\\/g, "/").toLowerCase();
144
+ const normalizedFilePath = resolvedFilePath.replace(/\\/g, "/").toLowerCase();
145
+ console.log(`[SWITE] toUrl: swiss-lib path comparison - normalizedSwissPackages="${normalizedSwissPackages}", normalizedFilePath="${normalizedFilePath}", startsWith=${normalizedFilePath.startsWith(normalizedSwissPackages)}`);
146
+ if (normalizedFilePath.startsWith(normalizedSwissPackages)) {
147
+ console.log(`[SWITE] toUrl: ✅ swiss-lib path MATCHED! Converting to /swiss-packages/`);
148
+ const origSwissPackages = resolvedSwissPackages.replace(/\\/g, "/");
149
+ const origFilePath = resolvedFilePath.replace(/\\/g, "/");
150
+ const relative = origFilePath.slice(origSwissPackages.length);
151
+ const url = "/swiss-packages" + (relative.startsWith("/") ? relative : "/" + relative);
152
+ if (url.includes("/dist/") && !url.includes("/src/")) {
153
+ const srcUrl = url.replace("/dist/", "/src/").replace(/\.js$/, ".ts");
154
+ const srcRelative = srcUrl.replace("/swiss-packages/", "");
155
+ const srcFilePath = path.join(swissPackagesPath, srcRelative);
156
+ console.log(`[SWITE] toUrl: Checking source file: ${srcFilePath}, exists: ${await context.fileExists(srcFilePath)}`);
157
+ if (await context.fileExists(srcFilePath)) {
158
+ console.log(`[SWITE] toUrl: Preferring source over dist: ${srcUrl}`);
159
+ return normalizeResult(srcUrl);
160
+ }
161
+ }
162
+ console.log(`[SWITE] toUrl: ${filePath} -> ${url} (swiss-lib package)`);
163
+ return normalizeResult(url);
164
+ }
165
+ }
166
+ // Check if this is a node_modules path
167
+ const origFilePathNormalized = path.resolve(filePath).replace(/\\/g, "/");
168
+ if (origFilePathNormalized.toLowerCase().includes("/node_modules/")) {
169
+ const nodeModulesIndex = origFilePathNormalized.toLowerCase().indexOf("/node_modules/");
170
+ const afterNodeModules = origFilePathNormalized.slice(nodeModulesIndex + "/node_modules/".length);
171
+ const url = "/node_modules/" + afterNodeModules;
172
+ console.log(`[SWITE] toUrl: ${filePath} -> ${url} (node_modules, preserving case)`);
173
+ return normalizeResult(url);
174
+ }
175
+ // Try relative to app root FIRST
176
+ const normalizedRoot = path.resolve(context.root).replace(/\\/g, "/").toLowerCase();
177
+ const normalizedFilePath = path.resolve(filePath).replace(/\\/g, "/").toLowerCase();
178
+ if (normalizedFilePath.startsWith(normalizedRoot)) {
179
+ const origRoot = path.resolve(context.root).replace(/\\/g, "/");
180
+ const origFilePath = path.resolve(filePath).replace(/\\/g, "/");
181
+ const relative = origFilePath.slice(origRoot.length);
182
+ const url = relative.startsWith("/") ? relative : "/" + relative;
183
+ console.log(`[SWITE] toUrl: ${filePath} -> ${url} (app root: ${context.root})`);
184
+ return normalizeResult(url);
185
+ }
186
+ // Try workspace root
187
+ if (workspaceRoot) {
188
+ const normalizedWorkspaceRoot = path.resolve(workspaceRoot).replace(/\\/g, "/").toLowerCase();
189
+ if (normalizedFilePath.startsWith(normalizedWorkspaceRoot)) {
190
+ const origWorkspaceRoot = path.resolve(workspaceRoot).replace(/\\/g, "/");
191
+ 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
+ const relative = origFilePath.slice(origWorkspaceRoot.length);
207
+ let url = relative.startsWith("/") ? relative : "/" + relative;
208
+ // Prefer src over dist for workspace /packages/ in dev (unbuilt packages)
209
+ if (url.includes("/packages/") &&
210
+ url.includes("/dist/") &&
211
+ (await context.fileExists(filePath)) === false) {
212
+ const srcPath = filePath.replace(/[/\\]dist[/\\]/, path.sep + "src" + path.sep).replace(/\.js$/i, ".ts");
213
+ if (await context.fileExists(srcPath)) {
214
+ const srcRelative = path.relative(workspaceRoot, srcPath).replace(/\\/g, "/");
215
+ url = "/" + srcRelative;
216
+ console.log(`[SWITE] toUrl: Preferring src over dist (packages): ${url}`);
217
+ }
218
+ }
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
+ return normalizeResult(url);
229
+ }
230
+ }
231
+ // Fallback
232
+ const fallbackWorkspaceRoot = await context.getWorkspaceRoot();
233
+ const baseRoot = fallbackWorkspaceRoot || context.root;
234
+ const rawRelative = path.relative(baseRoot, filePath);
235
+ // CG-03: path.relative() returns an absolute path when crossing drives or WSL mounts.
236
+ // Guard: if the result is absolute or escapes root with '..', strip prefix directly.
237
+ let url;
238
+ if (path.isAbsolute(rawRelative) || rawRelative.startsWith("..")) {
239
+ const normalizedBase = path.resolve(baseRoot).replace(/\\/g, "/");
240
+ const normalizedFile = path.resolve(filePath).replace(/\\/g, "/");
241
+ const stripped = normalizedFile.startsWith(normalizedBase)
242
+ ? normalizedFile.slice(normalizedBase.length)
243
+ : "/" + normalizedFile;
244
+ url = stripped.startsWith("/") ? stripped : "/" + stripped;
245
+ }
246
+ else {
247
+ url = "/" + rawRelative.replace(/\\/g, "/");
248
+ }
249
+ console.warn(`[SWITE] toUrl fallback: ${filePath} -> ${url} (may not work if path goes outside root)`);
250
+ return normalizeResult(url);
251
+ }
252
+ // Default: make relative to root
253
+ const rawRelative = path.relative(context.root, filePath);
254
+ // CG-03: guard against absolute result from path.relative() on cross-drive/WSL paths.
255
+ let defaultUrl;
256
+ if (path.isAbsolute(rawRelative) || rawRelative.startsWith("..")) {
257
+ const normalizedRoot = path.resolve(context.root).replace(/\\/g, "/");
258
+ const normalizedFile = path.resolve(filePath).replace(/\\/g, "/");
259
+ const stripped = normalizedFile.startsWith(normalizedRoot)
260
+ ? normalizedFile.slice(normalizedRoot.length)
261
+ : "/" + normalizedFile;
262
+ defaultUrl = stripped.startsWith("/") ? stripped : "/" + stripped;
263
+ }
264
+ else {
265
+ defaultUrl = "/" + rawRelative.replace(/\\/g, "/");
266
+ }
267
+ return normalizeResult(defaultUrl);
268
+ }
@@ -0,0 +1,10 @@
1
+ export interface WorkspacePackageResolverContext {
2
+ root: string;
3
+ getWorkspaceRoot: () => Promise<string | null>;
4
+ fileExists: (filePath: string) => Promise<boolean>;
5
+ }
6
+ /**
7
+ * Resolve workspace package location
8
+ */
9
+ export declare function resolveWorkspacePackage(pkgName: string, context: WorkspacePackageResolverContext): Promise<string | null>;
10
+ //# sourceMappingURL=workspace-package-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-package-resolver.d.ts","sourceRoot":"","sources":["../../src/resolver/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,CAiMxB"}
@@ -0,0 +1,185 @@
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 "../utils/package-finder.js";
7
+ import { getPackageRegistry } from "../utils/package-registry.js";
8
+ /**
9
+ * Resolve workspace package location
10
+ */
11
+ export async function resolveWorkspacePackage(pkgName, context) {
12
+ let workspaceRoot = null;
13
+ const workspaceRoots = [];
14
+ if (pkgName.startsWith("@swiss-enterprise/") ||
15
+ pkgName.startsWith("@swiss-module/") ||
16
+ pkgName.startsWith("@kibologic/") ||
17
+ pkgName.startsWith("@swiss-framework/")) {
18
+ console.log(`[SWITE] Looking for SWS root for @swiss-enterprise package...`);
19
+ console.log(`[SWITE] Starting from app root: ${context.root}`);
20
+ const fallbackPaths = [
21
+ path.join(context.root, "..", ".."),
22
+ path.join(context.root, ".."),
23
+ ];
24
+ const detectedWorkspaceRoot = await context.getWorkspaceRoot();
25
+ if (detectedWorkspaceRoot) {
26
+ const hasLibraries = await context.fileExists(path.join(detectedWorkspaceRoot, "libraries"));
27
+ const hasModules = await context.fileExists(path.join(detectedWorkspaceRoot, "modules"));
28
+ if (hasLibraries || hasModules) {
29
+ console.log(`[SWITE] ✅ Found workspace root via getWorkspaceRoot(): ${detectedWorkspaceRoot}`);
30
+ workspaceRoot = detectedWorkspaceRoot;
31
+ workspaceRoots.push(workspaceRoot);
32
+ }
33
+ }
34
+ for (const fallbackPath of fallbackPaths) {
35
+ const normalizedFallback = path.resolve(fallbackPath);
36
+ console.log(`[SWITE] Checking path: ${normalizedFallback}`);
37
+ const hasWorkspace = await context.fileExists(path.join(normalizedFallback, "pnpm-workspace.yaml"));
38
+ const hasModules = await context.fileExists(path.join(normalizedFallback, "modules"));
39
+ const hasLibraries = await context.fileExists(path.join(normalizedFallback, "libraries"));
40
+ const hasPackages = await context.fileExists(path.join(normalizedFallback, "packages"));
41
+ const hasAiAgents = await context.fileExists(path.join(normalizedFallback, "packages", "ai-agents", "package.json"));
42
+ console.log(`[SWITE] hasWorkspace: ${hasWorkspace}, hasModules: ${hasModules}, hasLibraries: ${hasLibraries}, hasPackages: ${hasPackages}, hasAiAgents: ${hasAiAgents}`);
43
+ if (hasWorkspace || hasModules || hasLibraries || hasPackages || hasAiAgents) {
44
+ workspaceRoot = normalizedFallback;
45
+ console.log(`[SWITE] ✅ Found workspace root at: ${workspaceRoot}`);
46
+ workspaceRoots.push(workspaceRoot);
47
+ break;
48
+ }
49
+ }
50
+ if (!workspaceRoot) {
51
+ console.warn(`[SWITE] ⚠️ Could not find workspace root via fallback paths, trying getWorkspaceRoot()...`);
52
+ workspaceRoot = await context.getWorkspaceRoot();
53
+ if (workspaceRoot) {
54
+ console.log(`[SWITE] ✅ Found workspace root via fallback getWorkspaceRoot(): ${workspaceRoot}`);
55
+ workspaceRoots.push(workspaceRoot);
56
+ }
57
+ else {
58
+ console.warn(`[SWITE] ⚠️ Could not find workspace root, using last resort path...`);
59
+ workspaceRoots.push(path.join(context.root, "..", ".."));
60
+ }
61
+ }
62
+ }
63
+ else {
64
+ workspaceRoot = await context.getWorkspaceRoot();
65
+ if (!workspaceRoot) {
66
+ console.log(`[SWITE] Workspace root not found via pnpm-workspace.yaml, trying fallbacks...`);
67
+ const fallbackPaths = [
68
+ path.join(context.root, "..", ".."),
69
+ path.join(context.root, ".."),
70
+ ];
71
+ for (const fallbackPath of fallbackPaths) {
72
+ const normalizedFallback = path.resolve(fallbackPath);
73
+ if ((await context.fileExists(path.join(normalizedFallback, "pnpm-workspace.yaml"))) ||
74
+ (await context.fileExists(path.join(normalizedFallback, "modules"))) ||
75
+ (await context.fileExists(path.join(normalizedFallback, "libraries")))) {
76
+ workspaceRoot = normalizedFallback;
77
+ console.log(`[SWITE] Found workspace root via fallback: ${workspaceRoot}`);
78
+ break;
79
+ }
80
+ }
81
+ }
82
+ if (workspaceRoot) {
83
+ workspaceRoots.push(workspaceRoot);
84
+ }
85
+ else {
86
+ workspaceRoots.push(path.join(context.root, "..", ".."));
87
+ workspaceRoots.push(path.join(context.root, "..", "..", ".."));
88
+ }
89
+ }
90
+ // For @kibologic/* packages, also check swiss-lib monorepo
91
+ if (pkgName.startsWith("@kibologic/")) {
92
+ const swissLib = await findSwissLibMonorepo(context.root);
93
+ if (swissLib) {
94
+ console.log(`[SWITE] Found swiss-lib monorepo at ${swissLib}`);
95
+ workspaceRoots.unshift(swissLib);
96
+ }
97
+ }
98
+ console.log(`[SWITE] Searching for workspace package: ${pkgName}`);
99
+ console.log(`[SWITE] Workspace roots: ${workspaceRoots.map((r) => path.resolve(r)).join(", ")}`);
100
+ // Use dynamic package registry instead of hardcoded directory searches
101
+ const registry = getPackageRegistry();
102
+ // Determine primary workspace root for scanning
103
+ let primaryRoot = workspaceRoots[0] ?? "";
104
+ if (!primaryRoot) {
105
+ primaryRoot = (await context.getWorkspaceRoot()) ?? context.root;
106
+ }
107
+ if (!primaryRoot) {
108
+ primaryRoot = context.root;
109
+ }
110
+ const additionalRoots = workspaceRoots.slice(1);
111
+ // Add swiss-lib monorepo if it exists (for @kibologic/* packages)
112
+ if (pkgName.startsWith("@kibologic/")) {
113
+ try {
114
+ const swissLib = await findSwissLibMonorepo(context.root);
115
+ if (swissLib && !additionalRoots.includes(swissLib) && swissLib !== primaryRoot) {
116
+ additionalRoots.unshift(swissLib); // Prioritize swiss-lib
117
+ }
118
+ // Also add swiss-lib/packages to ensure packages are found
119
+ if (swissLib) {
120
+ const swissLibPackages = path.join(swissLib, "packages");
121
+ if (await context.fileExists(swissLibPackages) && !additionalRoots.includes(swissLibPackages)) {
122
+ console.log(`[SWITE] Adding swiss-lib/packages to scan roots: ${swissLibPackages}`);
123
+ additionalRoots.unshift(swissLibPackages);
124
+ }
125
+ }
126
+ }
127
+ catch (error) {
128
+ console.warn(`[SWITE] Error finding swiss-lib monorepo:`, error.message);
129
+ }
130
+ }
131
+ // Ensure registry is scanned
132
+ if (!registry.getPackageCount() && primaryRoot) {
133
+ console.log(`[SWITE] Package registry not scanned yet, scanning workspace at ${primaryRoot}...`);
134
+ try {
135
+ await registry.scanWorkspace(primaryRoot, additionalRoots);
136
+ }
137
+ catch (error) {
138
+ console.error(`[SWITE] Error scanning package registry:`, error.message);
139
+ console.error(`[SWITE] Stack:`, error.stack);
140
+ }
141
+ }
142
+ else if (registry.getPackageCount() && pkgName.startsWith("@kibologic/")) {
143
+ // Registry already scanned but may not have swiss-lib/packages
144
+ // Check if @kibologic/core is missing from registry
145
+ const existingPkg = registry.findPackage(pkgName);
146
+ if (!existingPkg) {
147
+ console.log(`[SWITE] ${pkgName} not in registry, forcing rescan with swiss-lib/packages...`);
148
+ await registry.rescan();
149
+ // After rescan, if still not found, explicitly scan swiss-lib/packages
150
+ const stillMissing = !registry.findPackage(pkgName);
151
+ if (stillMissing) {
152
+ const swissLib = await findSwissLibMonorepo(context.root);
153
+ if (swissLib) {
154
+ const swissLibPackages = path.join(swissLib, "packages");
155
+ if (await context.fileExists(swissLibPackages)) {
156
+ console.log(`[SWITE] Explicitly scanning swiss-lib/packages: ${swissLibPackages}`);
157
+ await registry.scanWorkspace(swissLibPackages, []);
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
163
+ else if (!primaryRoot) {
164
+ console.warn(`[SWITE] No workspace root found, cannot scan packages`);
165
+ }
166
+ // Look up package in registry
167
+ let packageInfo = registry.findPackage(pkgName);
168
+ if (packageInfo) {
169
+ console.log(`[SWITE] ✅ Found ${pkgName} at ${packageInfo.path} (via dynamic registry)`);
170
+ return packageInfo.path;
171
+ }
172
+ // If not found, try rescanning (in case packages were added or registry was stale)
173
+ console.log(`[SWITE] Package ${pkgName} not in registry, rescanning...`);
174
+ await registry.rescan();
175
+ packageInfo = registry.findPackage(pkgName);
176
+ if (packageInfo) {
177
+ console.log(`[SWITE] ✅ Found ${pkgName} at ${packageInfo.path} (after rescan)`);
178
+ return packageInfo.path;
179
+ }
180
+ // Log all found packages for debugging
181
+ const allPackages = registry.getAllPackages().map(p => p.name).join(", ");
182
+ console.log(`[SWITE] ❌ Package ${pkgName} not found in workspace`);
183
+ console.log(`[SWITE] Scanned ${registry.getPackageCount()} packages: ${allPackages}`);
184
+ return null;
185
+ }
@@ -0,0 +1,17 @@
1
+ import type { ImportMap } from "./utils/generate-import-map.js";
2
+ export declare class ModuleResolver {
3
+ private root;
4
+ private workspaceRoot;
5
+ private importMap;
6
+ constructor(root: string);
7
+ /**
8
+ * Set pre-resolved import map (from build-time generation)
9
+ */
10
+ setImportMap(importMap: ImportMap | null): void;
11
+ private getWorkspaceRoot;
12
+ resolve(specifier: string, importer: string): Promise<string>;
13
+ private fileExists;
14
+ private resolveWorkspacePackage;
15
+ private toUrl;
16
+ }
17
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAMhE,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;IA4BxB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAqJrD,UAAU;YASV,uBAAuB;YAavB,KAAK;CAUpB"}