bimba-cli 0.7.3 → 0.7.5
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/package.json +1 -1
- package/serve.js +26 -86
package/package.json
CHANGED
package/serve.js
CHANGED
|
@@ -409,16 +409,6 @@ function findHtml(flagHtml) {
|
|
|
409
409
|
}
|
|
410
410
|
|
|
411
411
|
// ─── Node modules resolution ─────────────────────────────────────────────────
|
|
412
|
-
//
|
|
413
|
-
// Packages with conditional exports (e.g. highlight.js) map subpaths like
|
|
414
|
-
// "./lib/languages/*" to different files for `require` vs `import`. The browser
|
|
415
|
-
// import map uses a simple trailing-slash prefix mapping, so
|
|
416
|
-
// `highlight.js/lib/languages/javascript` → `/node_modules/highlight.js/lib/languages/javascript`.
|
|
417
|
-
// But that's the CJS file — the browser needs the ESM one under `es/`.
|
|
418
|
-
//
|
|
419
|
-
// We solve this at the HTTP level: when serving a JS file from node_modules,
|
|
420
|
-
// check if the file is CJS and the package has an ESM alternative via its
|
|
421
|
-
// `exports` field. If so, rewrite to the ESM path.
|
|
422
412
|
|
|
423
413
|
const _pkgJsonCache = new Map() // pkg root dir → parsed package.json
|
|
424
414
|
|
|
@@ -434,71 +424,13 @@ async function readPkgJson(pkgDir) {
|
|
|
434
424
|
}
|
|
435
425
|
}
|
|
436
426
|
|
|
437
|
-
//
|
|
438
|
-
//
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
//
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
if (nmIdx === -1) return null
|
|
445
|
-
|
|
446
|
-
const pkgName = parts[nmIdx + 1].startsWith('@')
|
|
447
|
-
? parts[nmIdx + 1] + '/' + parts[nmIdx + 2]
|
|
448
|
-
: parts[nmIdx + 1]
|
|
449
|
-
const pkgDir = parts.slice(0, nmIdx + 1 + (pkgName.includes('/') ? 2 : 1)).join('/')
|
|
450
|
-
const depPkg = await readPkgJson(pkgDir)
|
|
451
|
-
if (!depPkg?.exports || typeof depPkg.exports === 'string') return null
|
|
452
|
-
|
|
453
|
-
// Build the subpath relative to pkg root: "./lib/languages/javascript"
|
|
454
|
-
const pkgParts = pkgName.includes('/') ? 2 : 1
|
|
455
|
-
const subParts = parts.slice(nmIdx + 1 + pkgParts)
|
|
456
|
-
const subpath = './' + subParts.join('/')
|
|
457
|
-
|
|
458
|
-
const exp = depPkg.exports
|
|
459
|
-
|
|
460
|
-
// Try exact match first: exports["./lib/core"]
|
|
461
|
-
if (exp[subpath]) {
|
|
462
|
-
const target = exp[subpath]
|
|
463
|
-
const esm = typeof target === 'string' ? target : (target?.import || target?.default)
|
|
464
|
-
if (esm) {
|
|
465
|
-
const resolved = path.join(pkgDir, esm)
|
|
466
|
-
if (existsSync(resolved)) return resolved
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
// Try with .js extension: exports["./lib/core"] for request "./lib/core"
|
|
471
|
-
const subpathJs = subpath + '.js'
|
|
472
|
-
if (exp[subpathJs]) {
|
|
473
|
-
const target = exp[subpathJs]
|
|
474
|
-
const esm = typeof target === 'string' ? target : (target?.import || target?.default)
|
|
475
|
-
if (esm) {
|
|
476
|
-
const resolved = path.join(pkgDir, esm)
|
|
477
|
-
if (existsSync(resolved)) return resolved
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
// Try wildcard match: exports["./lib/languages/*"]
|
|
482
|
-
for (const [pattern, target] of Object.entries(exp)) {
|
|
483
|
-
if (!pattern.includes('*')) continue
|
|
484
|
-
const prefix = pattern.slice(0, pattern.indexOf('*'))
|
|
485
|
-
const suffix = pattern.slice(pattern.indexOf('*') + 1)
|
|
486
|
-
|
|
487
|
-
// Check both with and without .js extension
|
|
488
|
-
for (const sp of [subpath, subpathJs]) {
|
|
489
|
-
if (!sp.startsWith(prefix)) continue
|
|
490
|
-
if (suffix && !sp.endsWith(suffix)) continue
|
|
491
|
-
const stem = sp.slice(prefix.length, suffix ? -suffix.length || undefined : undefined)
|
|
492
|
-
|
|
493
|
-
const esm = typeof target === 'string' ? target : (target?.import || target?.default)
|
|
494
|
-
if (!esm || !esm.includes('*')) continue
|
|
495
|
-
|
|
496
|
-
const resolved = path.join(pkgDir, esm.replace('*', stem))
|
|
497
|
-
if (existsSync(resolved)) return resolved
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
return null
|
|
427
|
+
// Wrap a CommonJS file as an ESM module so the browser can import it.
|
|
428
|
+
// Detects CJS by checking for `module.exports` or top-level `exports.` usage.
|
|
429
|
+
function wrapCJS(code) {
|
|
430
|
+
if (!code.includes('module.exports') && !code.includes('exports.')) return null
|
|
431
|
+
// Already has ESM syntax — don't wrap (dual-format files)
|
|
432
|
+
if (/^\s*(export\s|import\s)/m.test(code)) return null
|
|
433
|
+
return `var module = { exports: {} }, exports = module.exports;\n${code}\nexport default module.exports;\nexport { module };`
|
|
502
434
|
}
|
|
503
435
|
|
|
504
436
|
// Resolve the ESM entry point for an npm package.
|
|
@@ -750,23 +682,26 @@ export function serve(entrypoint, flags) {
|
|
|
750
682
|
}
|
|
751
683
|
}
|
|
752
684
|
|
|
753
|
-
// node_modules:
|
|
685
|
+
// node_modules: entry point resolution, .imba compilation, CJS→ESM wrapping.
|
|
754
686
|
// The import map just maps bare specifiers to /node_modules/pkg/ URLs.
|
|
755
|
-
//
|
|
756
|
-
// (CJS→ESM), subpath resolution, .imba compilation.
|
|
687
|
+
// All smart resolution happens here at request time.
|
|
757
688
|
if (pathname.startsWith('/node_modules/')) {
|
|
758
689
|
const filepath = '.' + pathname
|
|
759
690
|
|
|
760
|
-
// Serve a resolved file
|
|
691
|
+
// Serve a resolved file: compile .imba, wrap CJS as ESM, pass ESM through
|
|
761
692
|
const serveResolved = async (filePath) => {
|
|
762
693
|
if (filePath.endsWith('.imba')) {
|
|
694
|
+
const f = Bun.file(filePath)
|
|
695
|
+
if (!(await f.exists())) return null
|
|
763
696
|
const out = await compileFile(filePath)
|
|
764
697
|
if (out.errors?.length) return new Response(out.errors.map(e => e.message).join('\n'), { status: 500 })
|
|
765
698
|
return new Response(out.js, { headers: { 'Content-Type': 'application/javascript' } })
|
|
766
699
|
}
|
|
767
700
|
const f = Bun.file(filePath)
|
|
768
|
-
if (await f.exists()) return
|
|
769
|
-
|
|
701
|
+
if (!(await f.exists())) return null
|
|
702
|
+
const code = await f.text()
|
|
703
|
+
const wrapped = wrapCJS(code)
|
|
704
|
+
return new Response(wrapped || code, { headers: { 'Content-Type': 'application/javascript' } })
|
|
770
705
|
}
|
|
771
706
|
|
|
772
707
|
// Resolve entry point for root package requests (/node_modules/pkg/ or /node_modules/pkg)
|
|
@@ -788,11 +723,16 @@ export function serve(entrypoint, flags) {
|
|
|
788
723
|
}
|
|
789
724
|
}
|
|
790
725
|
|
|
791
|
-
// Subpath:
|
|
792
|
-
const
|
|
793
|
-
if (
|
|
794
|
-
|
|
795
|
-
|
|
726
|
+
// Subpath: try the exact path, then with extensions
|
|
727
|
+
const resp = await serveResolved(filepath)
|
|
728
|
+
if (resp) return resp
|
|
729
|
+
|
|
730
|
+
// Extensionless: try .imba, .js, .mjs
|
|
731
|
+
if (!filepath.includes('.', filepath.lastIndexOf('/') + 1)) {
|
|
732
|
+
for (const ext of ['.imba', '.js', '.mjs']) {
|
|
733
|
+
const resp = await serveResolved(filepath + ext)
|
|
734
|
+
if (resp) return resp
|
|
735
|
+
}
|
|
796
736
|
}
|
|
797
737
|
}
|
|
798
738
|
|