bimba-cli 0.7.1 → 0.7.3

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 (2) hide show
  1. package/package.json +1 -1
  2. package/serve.js +51 -30
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bimba-cli",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/HeapVoid/bimba.git"
package/serve.js CHANGED
@@ -524,7 +524,9 @@ function resolveEntry(depPkg) {
524
524
  }
525
525
 
526
526
  // Build an ES import map from package.json dependencies.
527
- // Packages with an .imba entry point are served locally; others via esm.sh.
527
+ // The import map is intentionally simple it just maps bare specifiers
528
+ // to /node_modules/ URLs. All the smart resolution (conditional exports,
529
+ // CJS→ESM, entry points, extensions) happens on the server side.
528
530
  async function buildImportMap() {
529
531
  const imports = {
530
532
  'imba/runtime': 'https://esm.sh/imba/runtime',
@@ -534,26 +536,8 @@ async function buildImportMap() {
534
536
  const pkg = JSON.parse(await Bun.file('./package.json').text());
535
537
  for (const [name] of Object.entries(pkg.dependencies || {})) {
536
538
  if (name === 'imba') continue;
537
- try {
538
- const depPkg = JSON.parse(await Bun.file(`./node_modules/${name}/package.json`).text());
539
- const entry = resolveEntry(depPkg);
540
- if (entry && !entry.startsWith('http')) {
541
- // Local package — serve from node_modules
542
- imports[name] = `/node_modules/${name}/${entry}`;
543
- // Always add trailing-slash mapping for deep/subpath imports
544
- // (e.g. highlight.js/lib/languages/javascript). The browser
545
- // doesn't enforce Node's `exports` restrictions, it just needs
546
- // a URL prefix to resolve bare specifiers like "pkg/sub/path".
547
- imports[name + '/'] = `/node_modules/${name}/`;
548
- } else {
549
- // No resolvable entry — use esm.sh to auto-wrap
550
- imports[name] = `https://esm.sh/${name}`;
551
- imports[name + '/'] = `https://esm.sh/${name}/`;
552
- }
553
- } catch(_) {
554
- imports[name] = `https://esm.sh/${name}`;
555
- imports[name + '/'] = `https://esm.sh/${name}/`;
556
- }
539
+ imports[name] = `/node_modules/${name}/`;
540
+ imports[name + '/'] = `/node_modules/${name}/`;
557
541
  }
558
542
  } catch(_) { /* no package.json */ }
559
543
 
@@ -766,16 +750,49 @@ export function serve(entrypoint, flags) {
766
750
  }
767
751
  }
768
752
 
769
- // node_modules: resolve conditional exports (CJS → ESM) before serving.
770
- // e.g. highlight.js/lib/languages/javascript → es/languages/javascript.js
753
+ // node_modules: all smart resolution happens here.
754
+ // The import map just maps bare specifiers to /node_modules/pkg/ URLs.
755
+ // This block handles: entry point resolution, conditional exports
756
+ // (CJS→ESM), subpath resolution, .imba compilation.
771
757
  if (pathname.startsWith('/node_modules/')) {
772
758
  const filepath = '.' + pathname
759
+
760
+ // Serve a resolved file — compile .imba on the fly, pass JS through
761
+ const serveResolved = async (filePath) => {
762
+ if (filePath.endsWith('.imba')) {
763
+ const out = await compileFile(filePath)
764
+ if (out.errors?.length) return new Response(out.errors.map(e => e.message).join('\n'), { status: 500 })
765
+ return new Response(out.js, { headers: { 'Content-Type': 'application/javascript' } })
766
+ }
767
+ const f = Bun.file(filePath)
768
+ if (await f.exists()) return new Response(f, { headers: { 'Content-Type': 'application/javascript' } })
769
+ return null
770
+ }
771
+
772
+ // Resolve entry point for root package requests (/node_modules/pkg/ or /node_modules/pkg)
773
+ const parts = pathname.slice(1).split('/') // ['node_modules', 'pkg', ...]
774
+ const isScoped = parts[1]?.startsWith('@')
775
+ const pkgParts = isScoped ? 3 : 2 // node_modules/@scope/pkg or node_modules/pkg
776
+ const subParts = parts.slice(pkgParts)
777
+ const isRootRequest = subParts.length === 0 || (subParts.length === 1 && subParts[0] === '')
778
+
779
+ if (isRootRequest) {
780
+ const pkgDir = './' + parts.slice(0, pkgParts).join('/')
781
+ const depPkg = await readPkgJson(pkgDir)
782
+ if (depPkg) {
783
+ const entry = resolveEntry(depPkg)
784
+ if (entry) {
785
+ const resp = await serveResolved(path.join(pkgDir, entry))
786
+ if (resp) return resp
787
+ }
788
+ }
789
+ }
790
+
791
+ // Subpath: resolve via conditional exports (CJS→ESM)
773
792
  const esmPath = await resolveNodeModuleESM(filepath)
774
793
  if (esmPath) {
775
- const file = Bun.file(esmPath)
776
- if (await file.exists()) return new Response(file, {
777
- headers: { 'Content-Type': 'application/javascript' },
778
- })
794
+ const resp = await serveResolved(esmPath)
795
+ if (resp) return resp
779
796
  }
780
797
  }
781
798
 
@@ -785,11 +802,15 @@ export function serve(entrypoint, flags) {
785
802
  const inRoot = Bun.file('.' + pathname)
786
803
  if (await inRoot.exists()) return new Response(inRoot)
787
804
 
788
- // Try .js / .mjs extension for extensionless paths (e.g. node_modules imports)
805
+ // Try extensions for extensionless paths (e.g. node_modules imports)
789
806
  const lastSegment = pathname.split('/').pop()
790
807
  if (!lastSegment.includes('.')) {
791
- // For node_modules, ESM resolution above already handles extensionless
792
- // paths via wildcard exports matching (tries subpath + '.js').
808
+ // Try .imba first (compile on the fly), then .js/.mjs
809
+ const imbaPath = '.' + pathname + '.imba'
810
+ if (existsSync(imbaPath)) {
811
+ const out = await compileFile(imbaPath)
812
+ if (!out.errors?.length) return new Response(out.js, { headers: { 'Content-Type': 'application/javascript' } })
813
+ }
793
814
  for (const ext of ['.js', '.mjs']) {
794
815
  const withExt = Bun.file('.' + pathname + ext)
795
816
  if (await withExt.exists()) return new Response(withExt, {