Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: kidlisp bundler query parameter handling in module imports

- Strip query parameters from import paths before resolution (e.g., l5.mjs?v=...)
- Rewrite imports to preserve query params after path resolution
- Fix dependency discovery to correctly identify imports with cache-bust parameters
- Add lib/l5.mjs to ESSENTIAL_FILES (required by disk.mjs)

Fixes "Failed to resolve module specifier" errors when packing KidLisp pieces.
Query parameters like ?v=20260330-runtime-support were being treated as part of
the filename, breaking module resolution in packed .lisp.html files.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

+19 -18
+19 -18
system/backend/kidlisp-bundler.mjs
··· 60 60 'lib/store.mjs', 61 61 'lib/platform.mjs', 62 62 'lib/pack-mode.mjs', 63 + 'lib/l5.mjs', // 🔧 Wasmoon/Lua runtime required by disk.mjs 63 64 64 65 // BIOS dependencies (required by imports) 65 66 'lib/keyboard.mjs', ··· 116 117 code = code.replace(/from\s*['"]aesthetic\.computer\/disks\/([^'"]+)['"]/g, (match, p) => { 117 118 return 'from \'ac/disks/' + p + '\''; 118 119 }); 119 - 120 + 120 121 code = code.replace(/import\s*\((['"]aesthetic\.computer\/disks\/([^'"]+)['")])\)/g, (match, fullPath, p) => { 121 122 return 'import(\'ac/disks/' + p + '\')'; 122 123 }); 123 - 124 - // Rewrite relative imports 125 - code = code.replace(/from\s*['"](\.\.\/[^'"]+|\.\/[^'"]+)['"]/g, (match, p) => { 124 + 125 + // Rewrite relative imports (strip query params for resolution, then re-add) 126 + code = code.replace(/from\s*['"](\.\.\/[^'"?]+|\.\/[^'"?]+)(\?[^'"]*)?['"]/g, (match, p, query) => { 126 127 const resolved = resolvePath(filepath, p); 127 - return 'from"' + resolved + '"'; 128 + return 'from"' + resolved + (query || '') + '"'; 128 129 }); 129 - 130 - // Rewrite dynamic imports 131 - code = code.replace(/import\s*\((['"](\.\.\/[^'"]+|\.\/[^'"]+)['")])\)/g, (match, fullPath, p) => { 130 + 131 + // Rewrite dynamic imports (strip query params for resolution, then re-add) 132 + code = code.replace(/import\s*\((['"](\.\.\/[^'"?]+|\.\/[^'"?]+)(\?[^'"]*)?)['"](\))\)/g, (match, fullPath, p, query, closing) => { 132 133 const resolved = resolvePath(filepath, p); 133 - return 'import("' + resolved + '")'; 134 + return 'import("' + resolved + (query || '') + '")'; 134 135 }); 135 - 136 - code = code.replace(/import\s*\(\`(\.\.\/[^\`]+|\.\/[^\`]+)\`\)/g, (match, p) => { 136 + 137 + code = code.replace(/import\s*\(\`(\.\.\/[^\`?]+)(\?[^\`]*)?\`\)/g, (match, p, query) => { 137 138 const resolved = resolvePath(filepath, p); 138 - return 'import("' + resolved + '")'; 139 + return 'import("' + resolved + (query || '') + '")'; 139 140 }); 140 - 141 + 141 142 return code; 142 143 } 143 144 ··· 219 220 try { 220 221 const content = await fs.readFile(fullPath, 'utf8'); 221 222 222 - // Find all relative imports 223 - const importRegex = /from\s+["'](\.\.[^"']+|\.\/[^"']+)["']/g; 224 - const dynamicImportRegex = /import\s*\(\s*["'](\.\.[^"']+|\.\/[^"']+)["']\s*\)/g; 225 - 223 + // Find all relative imports (strip query params for path resolution) 224 + const importRegex = /from\s+["'](\.\.[^"'?]+|\.\/[^"'?]+)(\?[^"']*)?["']/g; 225 + const dynamicImportRegex = /import\s*\(\s*["'](\.\.[^"'?]+|\.\/[^"'?]+)(\?[^"']*)?["']\s*\)/g; 226 + 226 227 let match; 227 228 while ((match = importRegex.exec(content)) !== null) { 228 - const importPath = match[1]; 229 + const importPath = match[1]; // just the path, not the query 229 230 const resolved = resolvePath(file, importPath); 230 231 231 232 if (skipFiles.some(skip => resolved.includes(skip))) {