@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,231 @@
1
+ /*
2
+ * URL Resolver - Converts file paths to URLs
3
+ * Extracted from resolver.ts for modularity
4
+ */
5
+
6
+ import path from "node:path";
7
+ import { promises as fs } from "node:fs";
8
+ import { findSwissLibMonorepo } from "../kernel/package-finder.js";
9
+ import { lookupInSymlinkRegistry } from "./symlink-registry.js";
10
+
11
+ export interface UrlResolverContext {
12
+ root: string;
13
+ getWorkspaceRoot: () => Promise<string | null>;
14
+ fileExists: (filePath: string) => Promise<boolean>;
15
+ }
16
+
17
+ export type WorkspacePackageResolverContext = UrlResolverContext;
18
+
19
+ function normalizeResult(result: string): string {
20
+ return result.replace(/\\/g, '/');
21
+ }
22
+
23
+ /**
24
+ * Convert file path to URL for browser
25
+ */
26
+ export async function toUrl(
27
+ filePath: string,
28
+ context: UrlResolverContext
29
+ ): Promise<string> {
30
+ const normalized = filePath.replace(/\\/g, "/");
31
+
32
+ // CG-03: Check symlink registry FIRST.
33
+ // Absolute filesystem paths (both realpath-resolved and unresolved symlinks)
34
+ // must be mapped back to browser URLs before the startsWith("/") early-return
35
+ // fires and mangled by normalizeResult().
36
+ // The registry maps realpath → /node_modules/<pkg> browser URL prefix.
37
+ if (path.isAbsolute(filePath)) {
38
+ // Direct lookup (path is already a realpath, e.g. from fs.realpath() in ts-handler)
39
+ let registryUrl = lookupInSymlinkRegistry(normalized);
40
+
41
+ // Fallback: resolve symlinks and retry (path may still contain symlink segments,
42
+ // e.g. app/node_modules/@alpine/core/... where app/node_modules is itself a symlink)
43
+ if (!registryUrl) {
44
+ try {
45
+ const realPath = (await fs.realpath(filePath)).replace(/\\/g, "/");
46
+ if (realPath !== normalized) {
47
+ registryUrl = lookupInSymlinkRegistry(realPath);
48
+ }
49
+ } catch {
50
+ // file may not exist yet; ignore
51
+ }
52
+ }
53
+
54
+ if (registryUrl) {
55
+ console.log(
56
+ `[SWITE] toUrl: symlink registry hit: ${filePath} → ${registryUrl}`
57
+ );
58
+ return registryUrl;
59
+ }
60
+
61
+ // If the absolute filesystem path contains /node_modules/, convert it to a
62
+ // browser-relative URL (/node_modules/...) before the startsWith("/") early
63
+ // return below swallows it as an already-resolved URL.
64
+ if (normalized.toLowerCase().includes("/node_modules/")) {
65
+ const nodeModulesIndex = normalized.toLowerCase().indexOf("/node_modules/");
66
+ const afterNodeModules = normalized.slice(nodeModulesIndex + "/node_modules/".length);
67
+ const url = "/node_modules/" + afterNodeModules;
68
+ console.log(`[SWITE] toUrl: abs→node_modules URL: ${filePath} → ${url}`);
69
+ return normalizeResult(url);
70
+ }
71
+
72
+ // Convert absolute workspace/app paths to browser-relative URLs before the
73
+ // startsWith("/") early-return below treats them as already-resolved URLs.
74
+ // e.g. /app/modules/pos/src/index.ui → /modules/pos/src/index.ui
75
+ const workspaceRootForAbs = await context.getWorkspaceRoot();
76
+ const normalizedLower = normalized.toLowerCase();
77
+ if (workspaceRootForAbs) {
78
+ const wsRoot = path.resolve(workspaceRootForAbs).replace(/\\/g, "/");
79
+ if (normalizedLower.startsWith(wsRoot.toLowerCase() + "/") || normalizedLower === wsRoot.toLowerCase()) {
80
+ const relative = normalized.slice(wsRoot.length);
81
+ const url = relative.startsWith("/") ? relative : "/" + relative;
82
+ console.log(`[SWITE] toUrl: abs→workspace URL: ${filePath} → ${url}`);
83
+ return normalizeResult(url);
84
+ }
85
+ }
86
+ const appRoot = path.resolve(context.root).replace(/\\/g, "/");
87
+ if (normalizedLower.startsWith(appRoot.toLowerCase() + "/") || normalizedLower === appRoot.toLowerCase()) {
88
+ const relative = normalized.slice(appRoot.length);
89
+ const url = relative.startsWith("/") ? relative : "/" + relative;
90
+ console.log(`[SWITE] toUrl: abs→approot URL: ${filePath} → ${url}`);
91
+ return normalizeResult(url);
92
+ }
93
+ }
94
+
95
+ // If path is already a URL (starts with / or http), prefer src over dist for workspace packages
96
+ if (normalized.startsWith("/") || normalized.startsWith("http")) {
97
+ // Only prefer src over dist for workspace packages — never for node_modules
98
+ if (normalized.includes("/dist/") && !normalized.includes("/src/") && !normalized.includes("/node_modules/")) {
99
+ const srcPath = normalized.replace("/dist/", "/src/").replace(/\.js$/, ".ts");
100
+ const { resolveFilePath } = await import("../path/file-path-resolver.js");
101
+ const workspaceRoot = await context.getWorkspaceRoot();
102
+ const srcFilePath = await resolveFilePath(srcPath, context.root, workspaceRoot);
103
+ if (await context.fileExists(srcFilePath)) {
104
+ return normalizeResult(srcPath);
105
+ }
106
+ }
107
+ return normalizeResult(normalized);
108
+ }
109
+
110
+ // If path is absolute, convert to a browser-relative URL
111
+ if (path.isAbsolute(filePath)) {
112
+ const workspaceRoot = await context.getWorkspaceRoot();
113
+
114
+ // Check if the file lives in a co-located framework monorepo's packages/ directory.
115
+ // Serve those files under /swiss-packages/ so the browser can request them distinctly
116
+ // from the app's own files. Works for any framework at any directory name.
117
+ const monorepo = await findSwissLibMonorepo(context.root);
118
+ if (monorepo) {
119
+ const packagesPath = path.join(monorepo, "packages");
120
+
121
+ let resolvedPackages: string;
122
+ let resolvedFilePath: string;
123
+ try {
124
+ resolvedPackages = await fs.realpath(packagesPath);
125
+ resolvedFilePath = await fs.realpath(filePath);
126
+ } catch {
127
+ resolvedPackages = path.resolve(packagesPath);
128
+ resolvedFilePath = path.resolve(filePath);
129
+ }
130
+
131
+ const normalizedPackages = resolvedPackages.replace(/\\/g, "/").toLowerCase();
132
+ const normalizedResolved = resolvedFilePath.replace(/\\/g, "/").toLowerCase();
133
+
134
+ if (normalizedResolved.startsWith(normalizedPackages)) {
135
+ const origPackages = resolvedPackages.replace(/\\/g, "/");
136
+ const origFile = resolvedFilePath.replace(/\\/g, "/");
137
+ const relative = origFile.slice(origPackages.length);
138
+ const url = "/swiss-packages" + (relative.startsWith("/") ? relative : "/" + relative);
139
+
140
+ if (url.includes("/dist/") && !url.includes("/src/")) {
141
+ const srcUrl = url.replace("/dist/", "/src/").replace(/\.js$/, ".ts");
142
+ const srcRelative = srcUrl.replace("/swiss-packages/", "");
143
+ const srcFilePath = path.join(packagesPath, srcRelative);
144
+ if (await context.fileExists(srcFilePath)) {
145
+ return normalizeResult(srcUrl);
146
+ }
147
+ }
148
+
149
+ return normalizeResult(url);
150
+ }
151
+ }
152
+
153
+ // node_modules absolute path → browser /node_modules/... URL
154
+ const origFilePathNormalized = path.resolve(filePath).replace(/\\/g, "/");
155
+ if (origFilePathNormalized.toLowerCase().includes("/node_modules/")) {
156
+ const nodeModulesIndex = origFilePathNormalized.toLowerCase().indexOf("/node_modules/");
157
+ const afterNodeModules = origFilePathNormalized.slice(nodeModulesIndex + "/node_modules/".length);
158
+ return normalizeResult("/node_modules/" + afterNodeModules);
159
+ }
160
+
161
+ const normalizedFilePath = path.resolve(filePath).replace(/\\/g, "/").toLowerCase();
162
+
163
+ // Try relative to app root first
164
+ const normalizedRoot = path.resolve(context.root).replace(/\\/g, "/").toLowerCase();
165
+ if (normalizedFilePath.startsWith(normalizedRoot)) {
166
+ const origRoot = path.resolve(context.root).replace(/\\/g, "/");
167
+ const origFilePath = path.resolve(filePath).replace(/\\/g, "/");
168
+ const relative = origFilePath.slice(origRoot.length);
169
+ return normalizeResult(relative.startsWith("/") ? relative : "/" + relative);
170
+ }
171
+
172
+ // Try workspace root
173
+ if (workspaceRoot) {
174
+ const normalizedWorkspaceRoot = path.resolve(workspaceRoot).replace(/\\/g, "/").toLowerCase();
175
+
176
+ if (normalizedFilePath.startsWith(normalizedWorkspaceRoot)) {
177
+ const origWorkspaceRoot = path.resolve(workspaceRoot).replace(/\\/g, "/");
178
+ const origFilePath = path.resolve(filePath).replace(/\\/g, "/");
179
+ const relative = origFilePath.slice(origWorkspaceRoot.length);
180
+ let url = relative.startsWith("/") ? relative : "/" + relative;
181
+
182
+ // Prefer src over dist for workspace packages in dev
183
+ if (url.includes("/packages/") && url.includes("/dist/") && !(await context.fileExists(filePath))) {
184
+ const srcPath = filePath
185
+ .replace(/[/\\]dist[/\\]/, path.sep + "src" + path.sep)
186
+ .replace(/\.js$/i, ".ts");
187
+ if (await context.fileExists(srcPath)) {
188
+ const srcRelative = path.relative(workspaceRoot, srcPath).replace(/\\/g, "/");
189
+ url = "/" + srcRelative;
190
+ }
191
+ }
192
+
193
+ return normalizeResult(url);
194
+ }
195
+ }
196
+
197
+ // Fallback
198
+ const baseRoot = workspaceRoot || context.root;
199
+ const rawRelative = path.relative(baseRoot, filePath);
200
+ // CG-03: guard against absolute result from path.relative() on cross-drive/WSL paths
201
+ let url: string;
202
+ if (path.isAbsolute(rawRelative) || rawRelative.startsWith("..")) {
203
+ const normalizedBase = path.resolve(baseRoot).replace(/\\/g, "/");
204
+ const normalizedFile = path.resolve(filePath).replace(/\\/g, "/");
205
+ const stripped = normalizedFile.startsWith(normalizedBase)
206
+ ? normalizedFile.slice(normalizedBase.length)
207
+ : "/" + normalizedFile;
208
+ url = stripped.startsWith("/") ? stripped : "/" + stripped;
209
+ } else {
210
+ url = "/" + rawRelative.replace(/\\/g, "/");
211
+ }
212
+ console.warn(`[SWITE] toUrl fallback: ${filePath} -> ${url}`);
213
+ return normalizeResult(url);
214
+ }
215
+
216
+ // Default: make relative to root
217
+ const rawRelative = path.relative(context.root, filePath);
218
+ // CG-03: guard against absolute result from path.relative() on cross-drive/WSL paths.
219
+ let defaultUrl: string;
220
+ if (path.isAbsolute(rawRelative) || rawRelative.startsWith("..")) {
221
+ const normalizedRoot = path.resolve(context.root).replace(/\\/g, "/");
222
+ const normalizedFile = path.resolve(filePath).replace(/\\/g, "/");
223
+ const stripped = normalizedFile.startsWith(normalizedRoot)
224
+ ? normalizedFile.slice(normalizedRoot.length)
225
+ : "/" + normalizedFile;
226
+ defaultUrl = stripped.startsWith("/") ? stripped : "/" + stripped;
227
+ } else {
228
+ defaultUrl = "/" + rawRelative.replace(/\\/g, "/");
229
+ }
230
+ return normalizeResult(defaultUrl);
231
+ }
@@ -0,0 +1,94 @@
1
+ /*
2
+ * Workspace Package Resolver - Finds packages in workspace
3
+ * Uses dynamic package registry instead of hardcoded paths
4
+ */
5
+
6
+ import path from "node:path";
7
+ import { findSwissLibMonorepo } from "../kernel/package-finder.js";
8
+ import { getPackageRegistry } from "../kernel/package-registry.js";
9
+
10
+ export interface WorkspacePackageResolverContext {
11
+ root: string;
12
+ getWorkspaceRoot: () => Promise<string | null>;
13
+ fileExists: (filePath: string) => Promise<boolean>;
14
+ }
15
+
16
+ /**
17
+ * Resolve workspace package location
18
+ */
19
+ export async function resolveWorkspacePackage(
20
+ pkgName: string,
21
+ context: WorkspacePackageResolverContext
22
+ ): Promise<string | null> {
23
+ // Build the ordered list of roots to scan for workspace packages.
24
+ // Works for any package name/scope — no hardcoded scope guards.
25
+ const workspaceRoots: string[] = [];
26
+
27
+ let workspaceRoot = await context.getWorkspaceRoot();
28
+ if (workspaceRoot) {
29
+ workspaceRoots.push(workspaceRoot);
30
+ } else {
31
+ // Walk up from app root looking for common workspace markers
32
+ for (const candidate of [
33
+ path.join(context.root, ".."),
34
+ path.join(context.root, "..", ".."),
35
+ ]) {
36
+ const normalized = path.resolve(candidate);
37
+ if (
38
+ (await context.fileExists(path.join(normalized, "pnpm-workspace.yaml"))) ||
39
+ (await context.fileExists(path.join(normalized, "modules"))) ||
40
+ (await context.fileExists(path.join(normalized, "libraries")))
41
+ ) {
42
+ workspaceRoot = normalized;
43
+ workspaceRoots.push(normalized);
44
+ break;
45
+ }
46
+ }
47
+ if (!workspaceRoots.length) {
48
+ workspaceRoots.push(path.join(context.root, "..", ".."));
49
+ }
50
+ }
51
+
52
+ // Also include any co-located framework monorepo (any workspace with packages/)
53
+ try {
54
+ const monorepo = await findSwissLibMonorepo(context.root);
55
+ if (monorepo && !workspaceRoots.includes(monorepo)) {
56
+ workspaceRoots.unshift(monorepo);
57
+ }
58
+ if (monorepo) {
59
+ const packagesDir = path.join(monorepo, "packages");
60
+ if (await context.fileExists(packagesDir) && !workspaceRoots.includes(packagesDir)) {
61
+ workspaceRoots.unshift(packagesDir);
62
+ }
63
+ }
64
+ } catch {
65
+ // monorepo not found — continue without it
66
+ }
67
+
68
+ const registry = getPackageRegistry();
69
+ const primaryRoot = workspaceRoots[0] ?? context.root;
70
+ const additionalRoots = workspaceRoots.slice(1);
71
+
72
+ if (!registry.getPackageCount() && primaryRoot) {
73
+ try {
74
+ await registry.scanWorkspace(primaryRoot, additionalRoots);
75
+ } catch (error: any) {
76
+ console.error(`[SWITE] Error scanning package registry:`, error.message);
77
+ }
78
+ }
79
+
80
+ let packageInfo = registry.findPackage(pkgName);
81
+ if (packageInfo) {
82
+ return packageInfo.path;
83
+ }
84
+
85
+ // Rescan in case the package was added after the initial scan
86
+ await registry.rescan();
87
+ packageInfo = registry.findPackage(pkgName);
88
+ if (packageInfo) {
89
+ return packageInfo.path;
90
+ }
91
+
92
+ console.log(`[SWITE] Package ${pkgName} not found in workspace (scanned ${registry.getPackageCount()} packages)`);
93
+ return null;
94
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "extends": "../swiss-lib/tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src",
6
+ "declaration": true,
7
+ "declarationMap": true,
8
+ "module": "Node16",
9
+ "moduleResolution": "node16",
10
+ "skipLibCheck": true,
11
+ "noEmitOnError": false,
12
+ "downlevelIteration": true,
13
+ "target": "ES2020",
14
+ "composite": true,
15
+ "tsBuildInfoFile": "./dist/.tsbuildinfo",
16
+ "noUnusedLocals": false,
17
+ "noUnusedParameters": false
18
+ },
19
+ "include": [
20
+ "src/**/*.ts"
21
+ ],
22
+ "exclude": [
23
+ "node_modules",
24
+ "dist"
25
+ ],
26
+ "references": [
27
+ {
28
+ "path": "../swiss-lib/runtime"
29
+ },
30
+ {
31
+ "path": "../swiss-lib/compiler"
32
+ },
33
+ {
34
+ "path": "../swiss-lib/plugins/file-router"
35
+ }
36
+ ]
37
+ }