@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.
- package/.changeset/config.json +11 -0
- package/.github/workflows/ci.yml +59 -0
- package/.github/workflows/publish.yml +50 -0
- package/.github/workflows/release.yml +53 -0
- package/BUILD_ANALYSIS.md +89 -0
- package/BUILD_STRATEGY.md +75 -0
- package/CHANGELOG.md +53 -0
- package/DIRECTIVE.md +488 -0
- package/__tests__/css-extraction.test.ts +261 -0
- package/__tests__/css-injection-integration.test.ts +247 -0
- package/__tests__/css-middleware.test.ts +191 -0
- package/__tests__/import-rewriter-bug.test.ts +135 -0
- package/dist/builder.d.ts +36 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/builder.js +772 -0
- package/dist/cache/compilation-cache.d.ts +33 -0
- package/dist/cache/compilation-cache.d.ts.map +1 -0
- package/dist/cache/compilation-cache.js +130 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +85 -0
- package/dist/config-loader.d.ts +8 -0
- package/dist/config-loader.d.ts.map +1 -0
- package/dist/config-loader.js +40 -0
- package/dist/config.d.ts +29 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +7 -0
- package/dist/dev/pythonDevManager.d.ts +12 -0
- package/dist/dev/pythonDevManager.d.ts.map +1 -0
- package/dist/dev/pythonDevManager.js +85 -0
- package/dist/env.d.ts +19 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +112 -0
- package/dist/handlers/base-handler.d.ts +21 -0
- package/dist/handlers/base-handler.d.ts.map +1 -0
- package/dist/handlers/base-handler.js +38 -0
- package/dist/handlers/js-handler.d.ts +10 -0
- package/dist/handlers/js-handler.d.ts.map +1 -0
- package/dist/handlers/js-handler.js +87 -0
- package/dist/handlers/mjs-handler.d.ts +8 -0
- package/dist/handlers/mjs-handler.d.ts.map +1 -0
- package/dist/handlers/mjs-handler.js +44 -0
- package/dist/handlers/node-module-handler.d.ts +16 -0
- package/dist/handlers/node-module-handler.d.ts.map +1 -0
- package/dist/handlers/node-module-handler.js +267 -0
- package/dist/handlers/ts-handler.d.ts +11 -0
- package/dist/handlers/ts-handler.d.ts.map +1 -0
- package/dist/handlers/ts-handler.js +120 -0
- package/dist/handlers/ui-handler.d.ts +12 -0
- package/dist/handlers/ui-handler.d.ts.map +1 -0
- package/dist/handlers/ui-handler.js +182 -0
- package/dist/handlers/uix-handler.d.ts +12 -0
- package/dist/handlers/uix-handler.d.ts.map +1 -0
- package/dist/handlers/uix-handler.js +135 -0
- package/dist/hmr.d.ts +20 -0
- package/dist/hmr.d.ts.map +1 -0
- package/dist/hmr.js +265 -0
- package/dist/import-rewriter.d.ts +3 -0
- package/dist/import-rewriter.d.ts.map +1 -0
- package/dist/import-rewriter.js +351 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/middleware/hmr-routes.d.ts +12 -0
- package/dist/middleware/hmr-routes.d.ts.map +1 -0
- package/dist/middleware/hmr-routes.js +97 -0
- package/dist/middleware/middleware-setup.d.ts +23 -0
- package/dist/middleware/middleware-setup.d.ts.map +1 -0
- package/dist/middleware/middleware-setup.js +596 -0
- package/dist/middleware/static-files.d.ts +15 -0
- package/dist/middleware/static-files.d.ts.map +1 -0
- package/dist/middleware/static-files.js +585 -0
- package/dist/proxy/SwiteProxyError.d.ts +6 -0
- package/dist/proxy/SwiteProxyError.d.ts.map +1 -0
- package/dist/proxy/SwiteProxyError.js +9 -0
- package/dist/proxy/proxyToPython.d.ts +28 -0
- package/dist/proxy/proxyToPython.d.ts.map +1 -0
- package/dist/proxy/proxyToPython.js +66 -0
- package/dist/resolver/bare-import-resolver.d.ts +9 -0
- package/dist/resolver/bare-import-resolver.d.ts.map +1 -0
- package/dist/resolver/bare-import-resolver.js +363 -0
- package/dist/resolver/symlink-registry.d.ts +13 -0
- package/dist/resolver/symlink-registry.d.ts.map +1 -0
- package/dist/resolver/symlink-registry.js +98 -0
- package/dist/resolver/url-resolver.d.ts +11 -0
- package/dist/resolver/url-resolver.d.ts.map +1 -0
- package/dist/resolver/url-resolver.js +268 -0
- package/dist/resolver/workspace-package-resolver.d.ts +10 -0
- package/dist/resolver/workspace-package-resolver.d.ts.map +1 -0
- package/dist/resolver/workspace-package-resolver.js +185 -0
- package/dist/resolver.d.ts +17 -0
- package/dist/resolver.d.ts.map +1 -0
- package/dist/resolver.js +191 -0
- package/dist/router/file-router.d.ts +19 -0
- package/dist/router/file-router.d.ts.map +1 -0
- package/dist/router/file-router.js +114 -0
- package/dist/server.d.ts +22 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +122 -0
- package/dist/utils/cdn-fallback.d.ts +14 -0
- package/dist/utils/cdn-fallback.d.ts.map +1 -0
- package/dist/utils/cdn-fallback.js +36 -0
- package/dist/utils/file-path-resolver.d.ts +9 -0
- package/dist/utils/file-path-resolver.d.ts.map +1 -0
- package/dist/utils/file-path-resolver.js +187 -0
- package/dist/utils/generate-import-map-cli.d.ts +3 -0
- package/dist/utils/generate-import-map-cli.d.ts.map +1 -0
- package/dist/utils/generate-import-map-cli.js +32 -0
- package/dist/utils/generate-import-map.d.ts +21 -0
- package/dist/utils/generate-import-map.d.ts.map +1 -0
- package/dist/utils/generate-import-map.js +119 -0
- package/dist/utils/package-finder.d.ts +24 -0
- package/dist/utils/package-finder.d.ts.map +1 -0
- package/dist/utils/package-finder.js +161 -0
- package/dist/utils/package-registry.d.ts +36 -0
- package/dist/utils/package-registry.d.ts.map +1 -0
- package/dist/utils/package-registry.js +159 -0
- package/dist/utils/workspace.d.ts +6 -0
- package/dist/utils/workspace.d.ts.map +1 -0
- package/dist/utils/workspace.js +65 -0
- package/docs/IMPORT_REWRITING.md +164 -0
- package/docs/IMPORT_REWRITING_TROUBLESHOOTING.md +139 -0
- package/docs/PATH_RESOLUTION_GUIDE.md +221 -0
- package/package.json +49 -0
- package/src/adapters/proxy/SwiteProxyError.ts +12 -0
- package/src/adapters/proxy/proxyToPython.ts +88 -0
- package/src/build-engine/builder.ts +960 -0
- package/src/cli.ts +109 -0
- package/src/config/config-loader.ts +46 -0
- package/src/config/config.ts +34 -0
- package/src/config/env.ts +98 -0
- package/src/dev-engine/handlers/base-handler.ts +68 -0
- package/src/dev-engine/handlers/js-handler.ts +134 -0
- package/src/dev-engine/handlers/mjs-handler.ts +65 -0
- package/src/dev-engine/handlers/node-module-handler.ts +339 -0
- package/src/dev-engine/handlers/ts-handler.ts +143 -0
- package/src/dev-engine/handlers/ui-handler.ts +105 -0
- package/src/dev-engine/handlers/uix-handler.ts +90 -0
- package/src/dev-engine/hmr/hmr-client-template.ts +122 -0
- package/src/dev-engine/hmr/hmr.ts +173 -0
- package/src/dev-engine/middleware/hmr-routes.ts +120 -0
- package/src/dev-engine/middleware/middleware-setup.ts +351 -0
- package/src/dev-engine/middleware/static-files.ts +728 -0
- package/src/dev-engine/pythonDevManager.ts +116 -0
- package/src/dev-engine/router/file-router.ts +164 -0
- package/src/dev-engine/server.ts +152 -0
- package/src/index.ts +26 -0
- package/src/internal/cache/compilation-cache.ts +182 -0
- package/src/internal/generate-import-map-cli.ts +40 -0
- package/src/internal/generate-import-map.ts +154 -0
- package/src/kernel/package-finder.ts +164 -0
- package/src/kernel/package-registry.ts +198 -0
- package/src/kernel/workspace.ts +62 -0
- package/src/resolution/bare-import-resolver.ts +400 -0
- package/src/resolution/cdn/cdn-fallback.ts +37 -0
- package/src/resolution/path/file-path-resolver.ts +190 -0
- package/src/resolution/path/path-fixup.ts +19 -0
- package/src/resolution/resolver.ts +198 -0
- package/src/resolution/rewriting/import-rewriter.ts +237 -0
- package/src/resolution/symlink-registry.ts +114 -0
- package/src/resolution/url-resolver.ts +231 -0
- package/src/resolution/workspace-package-resolver.ts +94 -0
- package/tsconfig.json +37 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Import Rewriter for SWITE
|
|
3
|
+
*
|
|
4
|
+
* SIMPLIFIED APPROACH:
|
|
5
|
+
* - es-module-lexer ONLY returns static import specifiers (string literals)
|
|
6
|
+
* - If es-module-lexer found it, it's ALWAYS an import, never a variable
|
|
7
|
+
* - Trust the lexer and rewrite everything it finds (except relative imports)
|
|
8
|
+
* - Let the resolver handle resolution, fallback to CDN if needed
|
|
9
|
+
*/
|
|
10
|
+
import { init, parse } from "es-module-lexer";
|
|
11
|
+
import { ModuleResolver } from "./resolver.js";
|
|
12
|
+
import { promises as fs } from "node:fs";
|
|
13
|
+
import path from "node:path";
|
|
14
|
+
import chalk from "chalk";
|
|
15
|
+
import { shouldUseCdnFallback } from "./utils/cdn-fallback.js";
|
|
16
|
+
export async function rewriteImports(code, importer, resolver) {
|
|
17
|
+
await init;
|
|
18
|
+
try {
|
|
19
|
+
const [imports] = parse(code);
|
|
20
|
+
console.log(`[SWITE] import-rewriter: Found ${imports.length} import(s) in ${importer}`);
|
|
21
|
+
if (imports.length === 0) {
|
|
22
|
+
console.log(`[SWITE] import-rewriter: No imports found, returning original code`);
|
|
23
|
+
return code;
|
|
24
|
+
}
|
|
25
|
+
let rewritten = code;
|
|
26
|
+
let offset = 0;
|
|
27
|
+
for (const imp of imports) {
|
|
28
|
+
let { s: start, e: end } = imp;
|
|
29
|
+
const specifier = code.slice(start, end);
|
|
30
|
+
console.log(`[SWITE] import-rewriter: Processing import: "${specifier}"`);
|
|
31
|
+
// Skip CSS imports - these should be handled as static assets, not modules
|
|
32
|
+
if (specifier.includes(".css")) {
|
|
33
|
+
console.log(`[SWITE] import-rewriter: Skipping CSS import: "${specifier}"`);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
// Extract quote character and actual specifier
|
|
37
|
+
const firstChar = specifier[0];
|
|
38
|
+
const lastChar = specifier[specifier.length - 1];
|
|
39
|
+
const hasQuotes = (firstChar === '"' || firstChar === "'") && firstChar === lastChar;
|
|
40
|
+
let actualSpecifier;
|
|
41
|
+
let quoteChar = null;
|
|
42
|
+
if (hasQuotes) {
|
|
43
|
+
actualSpecifier = specifier.slice(1, -1);
|
|
44
|
+
quoteChar = firstChar;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// Unquoted - check surrounding code for quotes
|
|
48
|
+
const codeBefore = code.slice(Math.max(0, start - 1), start);
|
|
49
|
+
const codeAfter = code.slice(end, Math.min(code.length, end + 1));
|
|
50
|
+
if ((codeBefore === '"' || codeBefore === "'") &&
|
|
51
|
+
codeBefore === codeAfter) {
|
|
52
|
+
quoteChar = codeBefore;
|
|
53
|
+
actualSpecifier = specifier;
|
|
54
|
+
start = start - 1;
|
|
55
|
+
end = end + 1;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// No quotes found - this shouldn't happen with es-module-lexer for static imports
|
|
59
|
+
// But if it does, try to find the quoted version in the code
|
|
60
|
+
const escapedSpecifier = specifier.replace(/[.*+?^${}()|[\]\\-]/g, "\\$&");
|
|
61
|
+
const quotedPattern = new RegExp(`(['"])${escapedSpecifier}\\1`);
|
|
62
|
+
const match = quotedPattern.exec(code);
|
|
63
|
+
if (match) {
|
|
64
|
+
quoteChar = match[1];
|
|
65
|
+
actualSpecifier = specifier;
|
|
66
|
+
start = match.index;
|
|
67
|
+
end = match.index + match[0].length;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// Can't find quotes, skip this import (shouldn't happen)
|
|
71
|
+
console.warn(`[SWITE] import-rewriter: Could not find quotes for specifier: ${specifier}`);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// CRITICAL: Fix compiler bug where .uix/.ui imports are changed to .js or .tsx
|
|
77
|
+
// In dev mode, we need to preserve correct extensions for relative imports
|
|
78
|
+
// Context-aware: SWISS packages use .ts, app files use .uix/.ui
|
|
79
|
+
if (actualSpecifier.startsWith(".") && (actualSpecifier.endsWith(".js") || actualSpecifier.endsWith(".tsx")) && !actualSpecifier.includes("node_modules")) {
|
|
80
|
+
console.log(`[SWITE] import-rewriter: 🔧 Found relative .js import that needs fixing: "${actualSpecifier}"`);
|
|
81
|
+
// Determine correct extension based on context
|
|
82
|
+
// IMPORTANT: Check /lib/ and /swiss-packages/ FIRST before checking file extension
|
|
83
|
+
// Normalize path separators for Windows compatibility
|
|
84
|
+
const normalizedImporter = importer.replace(/\\/g, "/");
|
|
85
|
+
const isSwissPackage = normalizedImporter.includes("/swiss-packages/");
|
|
86
|
+
const isLibPath = normalizedImporter.includes("/lib/");
|
|
87
|
+
const isUixFile = normalizedImporter.endsWith(".uix") || normalizedImporter.endsWith(".ui");
|
|
88
|
+
let newExtension;
|
|
89
|
+
if (isSwissPackage) {
|
|
90
|
+
// SWISS packages use .ts files
|
|
91
|
+
newExtension = ".ts";
|
|
92
|
+
}
|
|
93
|
+
else if (isLibPath) {
|
|
94
|
+
// /lib/ paths can have .ts, .ui, or .uix files
|
|
95
|
+
// Default to .ts for /lib/ paths (most common - types, core logic, etc.)
|
|
96
|
+
// Handlers will try .ui/.uix if .ts doesn't exist
|
|
97
|
+
newExtension = ".ts";
|
|
98
|
+
console.log(`[SWITE] import-rewriter: 🎯 /lib/ path detected - using .ts extension (importer: ${importer}, specifier: ${actualSpecifier})`);
|
|
99
|
+
}
|
|
100
|
+
else if (isUixFile) {
|
|
101
|
+
// If importing from a .uix/.ui file, try to preserve the original extension
|
|
102
|
+
// Check if the file exists with .ui extension first, then .uix
|
|
103
|
+
const baseSpecifier = actualSpecifier.endsWith(".tsx") ? actualSpecifier.slice(0, -4) : actualSpecifier.slice(0, -3); // Remove .tsx or .js
|
|
104
|
+
// Get the directory of the CURRENT file being rewritten (not project root)
|
|
105
|
+
const currentDir = path.dirname(importer);
|
|
106
|
+
// Clean the import path - remove leading './' if present
|
|
107
|
+
const cleanImportPath = baseSpecifier.startsWith('./')
|
|
108
|
+
? baseSpecifier.slice(2)
|
|
109
|
+
: baseSpecifier.startsWith('../')
|
|
110
|
+
? baseSpecifier
|
|
111
|
+
: baseSpecifier;
|
|
112
|
+
// Construct the absolute path to the potential .ui dependency
|
|
113
|
+
const absoluteUiPath = path.resolve(currentDir, cleanImportPath + '.ui');
|
|
114
|
+
const absoluteUixPath = path.resolve(currentDir, cleanImportPath + '.uix');
|
|
115
|
+
console.log(`[SWITE] import-rewriter: Checking for .ui/.uix files: baseSpecifier="${baseSpecifier}", currentDir="${currentDir}", cleanImportPath="${cleanImportPath}"`);
|
|
116
|
+
console.log(`[SWITE] import-rewriter: Checking paths: ${absoluteUiPath}, ${absoluteUixPath}`);
|
|
117
|
+
// Check which file exists (prefer .ui since that's what source code uses)
|
|
118
|
+
try {
|
|
119
|
+
await fs.access(absoluteUiPath);
|
|
120
|
+
newExtension = ".ui";
|
|
121
|
+
console.log(`[SWITE] import-rewriter: ✅ Found .ui file: ${absoluteUiPath}`);
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
console.log(`[SWITE] import-rewriter: ❌ .ui file not found: ${absoluteUiPath} (${err instanceof Error ? err.message : String(err)})`);
|
|
125
|
+
try {
|
|
126
|
+
await fs.access(absoluteUixPath);
|
|
127
|
+
newExtension = ".uix";
|
|
128
|
+
console.log(`[SWITE] import-rewriter: ✅ Found .uix file: ${absoluteUixPath}`);
|
|
129
|
+
}
|
|
130
|
+
catch (err2) {
|
|
131
|
+
// Neither exists, default to .ui (matches source code convention)
|
|
132
|
+
newExtension = ".ui";
|
|
133
|
+
console.log(`[SWITE] import-rewriter: ⚠️ Neither .ui nor .uix found, defaulting to .ui for ${baseSpecifier} (checked: ${absoluteUiPath}, ${absoluteUixPath})`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
// Default: TypeScript files use .ts
|
|
139
|
+
newExtension = ".ts";
|
|
140
|
+
}
|
|
141
|
+
const baseSpecifier = actualSpecifier.endsWith(".tsx") ? actualSpecifier.slice(0, -4) : actualSpecifier.slice(0, -3); // Remove .tsx or .js
|
|
142
|
+
const newSpecifier = baseSpecifier + newExtension;
|
|
143
|
+
console.log(`[SWITE] import-rewriter: 🔧 Changing "${actualSpecifier}" -> "${newSpecifier}" (context: ${isSwissPackage ? 'swiss-pkg' : isUixFile ? 'uix' : 'ts'})`);
|
|
144
|
+
// Replace in the code using the original start/end positions
|
|
145
|
+
// If hasQuotes was true, start/end point to specifier WITHOUT quotes
|
|
146
|
+
// If hasQuotes was false but quotes found, start/end were adjusted to include quotes
|
|
147
|
+
const originalLength = end - start;
|
|
148
|
+
const before = rewritten.slice(0, start + offset);
|
|
149
|
+
const after = rewritten.slice(end + offset);
|
|
150
|
+
const finalSpecifier = quoteChar ? quoteChar + newSpecifier + quoteChar : `"${newSpecifier}"`;
|
|
151
|
+
rewritten = before + finalSpecifier + after;
|
|
152
|
+
offset += finalSpecifier.length - originalLength;
|
|
153
|
+
console.log(`[SWITE] import-rewriter: ✅ Fixed relative import: "${actualSpecifier}" -> "${newSpecifier}"`);
|
|
154
|
+
continue; // Don't process further (relative imports don't need module resolution)
|
|
155
|
+
}
|
|
156
|
+
// Skip other relative imports - they don't need rewriting
|
|
157
|
+
// BUT: Convert /swiss-lib/ paths to /swiss-packages/ paths
|
|
158
|
+
// Check for /swiss-lib/ anywhere in the path, not just at the start
|
|
159
|
+
if (actualSpecifier.includes("/swiss-lib/")) {
|
|
160
|
+
// Replace /swiss-lib/packages/ with /swiss-packages/ (not /swiss-packages/packages/)
|
|
161
|
+
const converted = actualSpecifier.replace(/\/swiss-lib\/packages\//g, "/swiss-packages/");
|
|
162
|
+
console.log(`[SWITE] import-rewriter: Converting /swiss-lib/ to /swiss-packages/: "${actualSpecifier}" -> "${converted}"`);
|
|
163
|
+
const originalLength = end - start;
|
|
164
|
+
const before = rewritten.slice(0, start + offset);
|
|
165
|
+
const after = rewritten.slice(end + offset);
|
|
166
|
+
const finalSpecifier = quoteChar ? quoteChar + converted + quoteChar : `"${converted}"`;
|
|
167
|
+
rewritten = before + finalSpecifier + after;
|
|
168
|
+
offset += finalSpecifier.length - originalLength;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (actualSpecifier.startsWith(".") || actualSpecifier.startsWith("/")) {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
// CRITICAL: es-module-lexer only returns static import specifiers
|
|
175
|
+
// If we got here, it's ALWAYS a module specifier, never a variable
|
|
176
|
+
// Just validate basic format (starts with letter or @)
|
|
177
|
+
if (!/^[@a-zA-Z]/.test(actualSpecifier)) {
|
|
178
|
+
console.warn(`[SWITE] import-rewriter: Invalid specifier format: ${actualSpecifier}`);
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
// Resolve the import
|
|
182
|
+
console.log(`[SWITE] import-rewriter: Resolving ${actualSpecifier} from ${importer}`);
|
|
183
|
+
let resolved;
|
|
184
|
+
try {
|
|
185
|
+
resolved = await resolver.resolve(actualSpecifier, importer);
|
|
186
|
+
console.log(`[SWITE] import-rewriter: Resolved ${actualSpecifier} -> ${resolved}`);
|
|
187
|
+
// CRITICAL: If resolver returns unchanged or invalid, use CDN fallback (when allowed).
|
|
188
|
+
if (!resolved ||
|
|
189
|
+
resolved === actualSpecifier ||
|
|
190
|
+
(!resolved.startsWith("/") && !resolved.startsWith("http"))) {
|
|
191
|
+
console.warn(`[SWITE] import-rewriter: Resolver returned invalid/unchanged result for ${actualSpecifier}, using CDN fallback`);
|
|
192
|
+
resolved = shouldUseCdnFallback(actualSpecifier)
|
|
193
|
+
? `https://cdn.jsdelivr.net/npm/${actualSpecifier}/+esm`
|
|
194
|
+
: `/node_modules/${actualSpecifier}`;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
console.error(`[SWITE] import-rewriter: Error resolving ${actualSpecifier}:`, error);
|
|
199
|
+
resolved = shouldUseCdnFallback(actualSpecifier)
|
|
200
|
+
? `https://cdn.jsdelivr.net/npm/${actualSpecifier}/+esm`
|
|
201
|
+
: `/node_modules/${actualSpecifier}`;
|
|
202
|
+
}
|
|
203
|
+
// For development: prefer src/ over dist/ for SWISS and workspace packages
|
|
204
|
+
if (resolved.includes("/dist/")) {
|
|
205
|
+
const isSwissOrPackages = resolved.includes("/swiss-packages/") || resolved.includes("/packages/");
|
|
206
|
+
if (isSwissOrPackages) {
|
|
207
|
+
resolved = resolved.replace("/dist/", "/src/").replace(/\.js$/, ".ts");
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Replace the specifier
|
|
211
|
+
console.log(`[SWITE] import-rewriter: Replacing "${actualSpecifier}" with "${resolved}" (quoteChar: ${quoteChar})`);
|
|
212
|
+
if (quoteChar) {
|
|
213
|
+
const originalLength = end - start;
|
|
214
|
+
const before = rewritten.slice(0, start + offset);
|
|
215
|
+
const after = rewritten.slice(end + offset);
|
|
216
|
+
const finalResolved = quoteChar + resolved + quoteChar;
|
|
217
|
+
rewritten = before + finalResolved + after;
|
|
218
|
+
offset += finalResolved.length - originalLength;
|
|
219
|
+
console.log(`[SWITE] import-rewriter: ✅ Replaced "${actualSpecifier}" with "${finalResolved}"`);
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
// No quote char (shouldn't happen, but handle it)
|
|
223
|
+
const before = rewritten.slice(0, start + offset);
|
|
224
|
+
const after = rewritten.slice(end + offset);
|
|
225
|
+
const finalResolved = `"${resolved}"`;
|
|
226
|
+
rewritten = before + finalResolved + after;
|
|
227
|
+
offset += finalResolved.length - (end - start);
|
|
228
|
+
console.log(`[SWITE] import-rewriter: ✅ Replaced (no quote) "${actualSpecifier}" with "${finalResolved}"`);
|
|
229
|
+
}
|
|
230
|
+
// CRITICAL: Verify the replacement worked
|
|
231
|
+
if (rewritten.includes(actualSpecifier) &&
|
|
232
|
+
!rewritten.includes(resolved)) {
|
|
233
|
+
console.error(`[SWITE] import-rewriter: ⚠️ WARNING - Replacement failed! Import "${actualSpecifier}" still in code but "${resolved}" not found`);
|
|
234
|
+
// FORCE replacement as last resort
|
|
235
|
+
console.error(`[SWITE] import-rewriter: 🔧 FORCING replacement of "${actualSpecifier}" with "${resolved}"`);
|
|
236
|
+
rewritten = rewritten.replace(new RegExp(actualSpecifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), resolved);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// FINAL CHECK: Ensure no bare imports remain
|
|
240
|
+
const bareImportPattern = /(?:import|from|export).*['"](@[^'"]+\/[^'"]+)[^'"]*['"]/;
|
|
241
|
+
if (bareImportPattern.test(rewritten)) {
|
|
242
|
+
const matches = Array.from(rewritten.matchAll(bareImportPattern));
|
|
243
|
+
for (const match of matches) {
|
|
244
|
+
const bareImport = match[1];
|
|
245
|
+
if (!bareImport.startsWith("/") &&
|
|
246
|
+
!bareImport.startsWith("http") &&
|
|
247
|
+
!bareImport.startsWith(".")) {
|
|
248
|
+
console.error(`[SWITE] import-rewriter: ⚠️ CRITICAL - Bare import "${bareImport}" still in code after rewriting!`);
|
|
249
|
+
const replacement = shouldUseCdnFallback(bareImport)
|
|
250
|
+
? `https://cdn.jsdelivr.net/npm/${bareImport}/+esm`
|
|
251
|
+
: `/node_modules/${bareImport}`;
|
|
252
|
+
rewritten = rewritten.replace(new RegExp(bareImport.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), replacement);
|
|
253
|
+
console.error(`[SWITE] import-rewriter: 🔧 FORCED replacement of "${bareImport}" with "${replacement}"`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
// CRITICAL: Apply additional regex-based fix for relative .js imports
|
|
258
|
+
// This catches any cases the lexer-based approach might miss
|
|
259
|
+
// BUT: We need to be context-aware:
|
|
260
|
+
// - If importer is in /swiss-packages/, change .js to .ts (SWISS packages use .ts)
|
|
261
|
+
// - If importer is a .uix/.ui file, change .js to .uix (app files)
|
|
262
|
+
// - Otherwise, change .js to .ts (default for TypeScript files)
|
|
263
|
+
const relativeJsImportRegex = /from\s+(["'])(\.\.?\/[^"']*?)(\.js|\.tsx)(\1)/g;
|
|
264
|
+
const beforeRegexFix = rewritten;
|
|
265
|
+
let regexFixCount = 0;
|
|
266
|
+
// Normalize path separators for Windows compatibility
|
|
267
|
+
const normalizedImporter = importer.replace(/\\/g, "/");
|
|
268
|
+
const isSwissPackage = normalizedImporter.includes("/swiss-packages/");
|
|
269
|
+
const isUixFile = normalizedImporter.endsWith(".uix") || normalizedImporter.endsWith(".ui");
|
|
270
|
+
rewritten = rewritten.replace(relativeJsImportRegex, (match, quote, path, jsExt, endQuote) => {
|
|
271
|
+
// Skip if it's in node_modules or absolute paths
|
|
272
|
+
if (path.includes("node_modules") || !path.startsWith(".")) {
|
|
273
|
+
return match;
|
|
274
|
+
}
|
|
275
|
+
// Determine correct extension based on context
|
|
276
|
+
// IMPORTANT: Check /lib/ and /swiss-packages/ FIRST before checking file extension
|
|
277
|
+
// Normalize path separators for Windows compatibility (importer is a file system path)
|
|
278
|
+
const normalizedImporter = importer.replace(/\\/g, "/");
|
|
279
|
+
const isLibPath = normalizedImporter.includes("/lib/");
|
|
280
|
+
let newExtension;
|
|
281
|
+
if (isSwissPackage) {
|
|
282
|
+
// SWISS packages use .ts files
|
|
283
|
+
newExtension = ".ts";
|
|
284
|
+
}
|
|
285
|
+
else if (isLibPath) {
|
|
286
|
+
// /lib/ paths can have .ts, .ui, or .uix files
|
|
287
|
+
// Default to .ts for /lib/ paths (most common - types, core logic, etc.)
|
|
288
|
+
// Handlers will try .ui/.uix if .ts doesn't exist
|
|
289
|
+
newExtension = ".ts";
|
|
290
|
+
console.log(`[SWITE] import-rewriter: 🎯 Regex /lib/ path detected - using .ts extension (importer: ${importer})`);
|
|
291
|
+
}
|
|
292
|
+
else if (isUixFile) {
|
|
293
|
+
// If importing from a .uix/.ui file, check what the actual file extension is
|
|
294
|
+
// The source code uses .ui, so we should preserve that
|
|
295
|
+
// Only use .uix if the source file is actually .uix
|
|
296
|
+
if (normalizedImporter.endsWith(".ui")) {
|
|
297
|
+
// Source is .ui, so imports should also be .ui (not .uix)
|
|
298
|
+
newExtension = ".ui";
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
// Source is .uix, imports can be .uix
|
|
302
|
+
newExtension = ".uix";
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
// Default: TypeScript files use .ts
|
|
307
|
+
newExtension = ".ts";
|
|
308
|
+
}
|
|
309
|
+
const newPath = path + newExtension;
|
|
310
|
+
console.log(`[SWITE] import-rewriter: 🔧 Regex fix (context: ${isSwissPackage ? 'swiss-pkg' : isUixFile ? 'uix' : 'ts'}): ${match} -> from ${quote}${newPath}${endQuote}`);
|
|
311
|
+
regexFixCount++;
|
|
312
|
+
return `from ${quote}${newPath}${endQuote}`;
|
|
313
|
+
});
|
|
314
|
+
if (regexFixCount > 0) {
|
|
315
|
+
console.log(`[SWITE] import-rewriter: ✅ Regex fix applied ${regexFixCount} change(s)`);
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
// Debug: Check if there are any relative .js imports that weren't caught
|
|
319
|
+
const testRegex = /from\s+["'](\.\.?\/[^"']+\.js)["']/g;
|
|
320
|
+
const testMatches = Array.from(rewritten.matchAll(testRegex));
|
|
321
|
+
if (testMatches.length > 0) {
|
|
322
|
+
console.log(`[SWITE] import-rewriter: ⚠️ Found ${testMatches.length} relative .js import(s) that weren't fixed:`);
|
|
323
|
+
testMatches.slice(0, 3).forEach(m => console.log(` - ${m[0]}`));
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
// Final pass: Convert any remaining /swiss-lib/ paths to /swiss-packages/
|
|
327
|
+
// This catches paths that might have been generated by the compiler or resolver
|
|
328
|
+
// Use multiple passes to catch all variations
|
|
329
|
+
if (rewritten.includes("/swiss-lib/")) {
|
|
330
|
+
const beforeFinal = rewritten;
|
|
331
|
+
// Pass 1: Replace /swiss-lib/packages/ with /swiss-packages/
|
|
332
|
+
rewritten = rewritten.replace(/\/swiss-lib\/packages\//g, "/swiss-packages/");
|
|
333
|
+
// Pass 2: Replace any remaining /swiss-lib/ with /swiss-packages/
|
|
334
|
+
rewritten = rewritten.replace(/\/swiss-lib\//g, "/swiss-packages/");
|
|
335
|
+
// Pass 3: Fix in quoted strings (both single and double quotes)
|
|
336
|
+
rewritten = rewritten.replace(/(['"])\/swiss-lib\//g, '$1/swiss-packages/');
|
|
337
|
+
if (beforeFinal !== rewritten) {
|
|
338
|
+
console.log(chalk.yellow(`[SWITE] import-rewriter: Final pass converted /swiss-lib/ to /swiss-packages/ (${beforeFinal.split('/swiss-lib/').length - 1} occurrences)`));
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
console.log(`[SWITE] import-rewriter: Finished rewriting ${imports.length} import(s) in ${importer}`);
|
|
342
|
+
return rewritten;
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
console.error(`[SWITE] import-rewriter: Error rewriting imports in ${importer}:`, error);
|
|
346
|
+
if (error instanceof Error) {
|
|
347
|
+
console.error(`[SWITE] import-rewriter: Error stack:`, error.stack);
|
|
348
|
+
}
|
|
349
|
+
return code; // Return original on error
|
|
350
|
+
}
|
|
351
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { SwiteServer } from "./server.js";
|
|
2
|
+
export type { SwiteConfig } from "./server.js";
|
|
3
|
+
export { SwiteBuilder, build } from "./builder.js";
|
|
4
|
+
export type { BuildConfig } from "./builder.js";
|
|
5
|
+
export { ModuleResolver } from "./resolver.js";
|
|
6
|
+
export { HMREngine } from "./hmr.js";
|
|
7
|
+
export { defineConfig } from "./config.js";
|
|
8
|
+
export type { SwiteUserConfig, ServerConfig, ServicesConfig, PythonServiceConfig, } from "./config.js";
|
|
9
|
+
export { proxyToPython, initPythonProxy, setProductionMode } from "./proxy/proxyToPython.js";
|
|
10
|
+
export type { ProxyOptions } from "./proxy/proxyToPython.js";
|
|
11
|
+
export { SwiteProxyError } from "./proxy/SwiteProxyError.js";
|
|
12
|
+
export { loadUserConfig } from "./config-loader.js";
|
|
13
|
+
export { startPythonDevService, stopPythonDevService, } from "./dev/pythonDevManager.js";
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACnD,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EACV,eAAe,EACf,YAAY,EACZ,cAAc,EACd,mBAAmB,GACpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7F,YAAY,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EACL,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,2BAA2B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SWITE - SWISS Development Server
|
|
3
|
+
* Main exports
|
|
4
|
+
*/
|
|
5
|
+
export { SwiteServer } from "./server.js";
|
|
6
|
+
export { SwiteBuilder, build } from "./builder.js";
|
|
7
|
+
export { ModuleResolver } from "./resolver.js";
|
|
8
|
+
export { HMREngine } from "./hmr.js";
|
|
9
|
+
export { defineConfig } from "./config.js";
|
|
10
|
+
export { proxyToPython, initPythonProxy, setProductionMode } from "./proxy/proxyToPython.js";
|
|
11
|
+
export { SwiteProxyError } from "./proxy/SwiteProxyError.js";
|
|
12
|
+
export { loadUserConfig } from "./config-loader.js";
|
|
13
|
+
export { startPythonDevService, stopPythonDevService, } from "./dev/pythonDevManager.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Express } from "express";
|
|
2
|
+
import type { RouteDefinition } from "@kibologic/core";
|
|
3
|
+
import { HMREngine } from "../hmr.js";
|
|
4
|
+
export interface HMRRoutesConfig {
|
|
5
|
+
hmr: HMREngine;
|
|
6
|
+
routes: RouteDefinition[];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Setup HMR client endpoint and routes endpoint
|
|
10
|
+
*/
|
|
11
|
+
export declare function setupHMRRoutes(app: Express, config: HMRRoutesConfig): void;
|
|
12
|
+
//# sourceMappingURL=hmr-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hmr-routes.d.ts","sourceRoot":"","sources":["../../src/middleware/hmr-routes.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAqG1E"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2024 Themba Mzumara
|
|
3
|
+
* SWITE - SWISS Development Server
|
|
4
|
+
* Licensed under the MIT License.
|
|
5
|
+
*/
|
|
6
|
+
import { HMREngine } from "../hmr.js";
|
|
7
|
+
/**
|
|
8
|
+
* Setup HMR client endpoint and routes endpoint
|
|
9
|
+
*/
|
|
10
|
+
export function setupHMRRoutes(app, config) {
|
|
11
|
+
// HMR client injection
|
|
12
|
+
app.get("/__swite_hmr_client", (req, res) => {
|
|
13
|
+
res.setHeader("Content-Type", "application/javascript");
|
|
14
|
+
res.send(config.hmr.getClientScript());
|
|
15
|
+
});
|
|
16
|
+
// Routes endpoint - expose route definitions to client
|
|
17
|
+
app.get("/__swite_routes", (req, res) => {
|
|
18
|
+
res.setHeader("Content-Type", "application/json");
|
|
19
|
+
// Serialize routes for client - functions can't be serialized, so we include httpUrl in meta
|
|
20
|
+
// The client will use httpUrl to dynamically import the component
|
|
21
|
+
const serializedRoutes = config.routes.map((route) => ({
|
|
22
|
+
path: route.path,
|
|
23
|
+
meta: route.meta,
|
|
24
|
+
// Include httpUrl from meta so client can import it
|
|
25
|
+
componentUrl: route.meta?.httpUrl || null,
|
|
26
|
+
}));
|
|
27
|
+
res.json({ routes: serializedRoutes });
|
|
28
|
+
});
|
|
29
|
+
// Diagnostic endpoint - check what the server is actually serving
|
|
30
|
+
app.get("/__swite_diagnose", async (req, res) => {
|
|
31
|
+
const url = req.query.url;
|
|
32
|
+
if (!url) {
|
|
33
|
+
res.json({ error: "Missing url query parameter" });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
// Try to fetch what we would serve
|
|
38
|
+
const testRes = await fetch(`http://localhost:${req.socket.localPort}${url}`);
|
|
39
|
+
const content = await testRes.text();
|
|
40
|
+
const hasBareImport = /(?:import|from|export).*['"](@[^'"]+\/[^'"]+)(?!\/)[^'"]*['"]/.test(content);
|
|
41
|
+
res.json({
|
|
42
|
+
url,
|
|
43
|
+
status: testRes.status,
|
|
44
|
+
hasBareImport,
|
|
45
|
+
contentPreview: content.substring(0, 500),
|
|
46
|
+
imports: Array.from(content.matchAll(/(?:import|from|export).*['"]([^'"]+)['"]/g))
|
|
47
|
+
.slice(0, 10)
|
|
48
|
+
.map((m) => m[1]),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
res.json({ error: String(error) });
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
// Force cache clear endpoint - returns HTML with aggressive cache busting
|
|
56
|
+
app.get("/__swite_clear_cache", async (req, res) => {
|
|
57
|
+
res.setHeader("Content-Type", "text/html");
|
|
58
|
+
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate, max-age=0");
|
|
59
|
+
res.setHeader("Pragma", "no-cache");
|
|
60
|
+
res.setHeader("Expires", "0");
|
|
61
|
+
res.send(`
|
|
62
|
+
<!DOCTYPE html>
|
|
63
|
+
<html>
|
|
64
|
+
<head>
|
|
65
|
+
<title>Cache Cleared</title>
|
|
66
|
+
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
|
67
|
+
<meta http-equiv="Pragma" content="no-cache">
|
|
68
|
+
<meta http-equiv="Expires" content="0">
|
|
69
|
+
<script>
|
|
70
|
+
// Clear all caches
|
|
71
|
+
if ('caches' in window) {
|
|
72
|
+
caches.keys().then(names => {
|
|
73
|
+
names.forEach(name => caches.delete(name));
|
|
74
|
+
console.log('All caches cleared');
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
// Clear service workers
|
|
78
|
+
if ('serviceWorker' in navigator) {
|
|
79
|
+
navigator.serviceWorker.getRegistrations().then(registrations => {
|
|
80
|
+
registrations.forEach(reg => reg.unregister());
|
|
81
|
+
console.log('Service workers unregistered');
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
// Redirect to home
|
|
85
|
+
setTimeout(() => {
|
|
86
|
+
window.location.href = '/?nocache=' + Date.now();
|
|
87
|
+
}, 1000);
|
|
88
|
+
</script>
|
|
89
|
+
</head>
|
|
90
|
+
<body>
|
|
91
|
+
<h1>Clearing cache...</h1>
|
|
92
|
+
<p>Redirecting in 1 second...</p>
|
|
93
|
+
</body>
|
|
94
|
+
</html>
|
|
95
|
+
`);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Express } from "express";
|
|
2
|
+
import type { RouteDefinition } from "@kibologic/core";
|
|
3
|
+
import { RouteScanner } from "@kibologic/plugin-file-router/core";
|
|
4
|
+
import { createFileWatcher } from "@kibologic/plugin-file-router/dev";
|
|
5
|
+
import { ModuleResolver } from "../resolver.js";
|
|
6
|
+
import { HMREngine } from "../hmr.js";
|
|
7
|
+
export interface MiddlewareConfig {
|
|
8
|
+
root: string;
|
|
9
|
+
workspaceRoot?: string | null;
|
|
10
|
+
publicDir: string;
|
|
11
|
+
resolver: ModuleResolver;
|
|
12
|
+
hmr: HMREngine;
|
|
13
|
+
}
|
|
14
|
+
export interface MiddlewareResult {
|
|
15
|
+
routes: RouteDefinition[];
|
|
16
|
+
routeScanner: RouteScanner | null;
|
|
17
|
+
routeWatcher: Awaited<ReturnType<typeof createFileWatcher>> | null;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Setup all middleware for the SWITE server
|
|
21
|
+
*/
|
|
22
|
+
export declare function setupMiddleware(app: Express, config: MiddlewareConfig): Promise<MiddlewareResult>;
|
|
23
|
+
//# sourceMappingURL=middleware-setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware-setup.d.ts","sourceRoot":"","sources":["../../src/middleware/middleware-setup.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAmC,MAAM,SAAS,CAAC;AAExE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAItE,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAahD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAItC,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,cAAc,CAAC;IACzB,GAAG,EAAE,SAAS,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,YAAY,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC,GAAG,IAAI,CAAC;CACpE;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,gBAAgB,CAAC,CAw0B3B"}
|