bimba-cli 0.7.17 → 0.7.19

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 (3) hide show
  1. package/index.js +17 -2
  2. package/package.json +1 -1
  3. package/serve.js +42 -7
package/index.js CHANGED
@@ -90,6 +90,8 @@ if(flags.help) {
90
90
 
91
91
 
92
92
  let bundling = false;
93
+ let rebuildQueued = false;
94
+ let watchTimer = null;
93
95
 
94
96
  // typecheck mode
95
97
  if (flags.typecheck || flags.tscheck) {
@@ -131,7 +133,13 @@ else {
131
133
 
132
134
  function watch(callback) {
133
135
  if (flags.watch) {
134
- const watcher = fs.watch(path.dirname(entrypoint), {recursive: true}, async (event, filename) => ( callback() ));
136
+ const watcher = fs.watch(path.dirname(entrypoint), {recursive: true}, () => {
137
+ if (watchTimer) clearTimeout(watchTimer);
138
+ watchTimer = setTimeout(() => {
139
+ watchTimer = null;
140
+ callback();
141
+ }, 150);
142
+ });
135
143
 
136
144
  process.on("SIGINT", () => {
137
145
  if(flags.clearcache) rmSync(cache, { recursive: true, force: true });
@@ -146,7 +154,10 @@ function watch(callback) {
146
154
 
147
155
 
148
156
  async function bundle() {
149
- if (bundling) return;
157
+ if (bundling) {
158
+ rebuildQueued = true;
159
+ return false;
160
+ }
150
161
  bundling = true;
151
162
 
152
163
  if (!fs.existsSync(entrypoint)) {
@@ -220,5 +231,9 @@ async function bundle() {
220
231
  }
221
232
  finally {
222
233
  bundling = false;
234
+ if (rebuildQueued) {
235
+ rebuildQueued = false;
236
+ queueMicrotask(bundle);
237
+ }
223
238
  };
224
239
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bimba-cli",
3
- "version": "0.7.17",
3
+ "version": "0.7.19",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/HeapVoid/bimba.git"
package/serve.js CHANGED
@@ -216,7 +216,15 @@ const hmrClient = `
216
216
 
217
217
  // ── Error overlay ──────────────────────────────────────────────────────────
218
218
 
219
+ function normalizeFile(file) {
220
+ let value = String(file || '').split(String.fromCharCode(92)).join('/');
221
+ while (value.startsWith('./')) value = value.slice(2);
222
+ while (value.startsWith('/')) value = value.slice(1);
223
+ return value;
224
+ }
225
+
219
226
  function showError(file, errors) {
227
+ const displayFile = normalizeFile(file);
220
228
  let overlay = document.getElementById('__bimba_error__');
221
229
  if (!overlay) {
222
230
  overlay = document.createElement('div');
@@ -225,11 +233,11 @@ const hmrClient = `
225
233
  overlay.addEventListener('click', e => { if (e.target === overlay) overlay.remove(); });
226
234
  document.body.appendChild(overlay);
227
235
  }
228
- overlay.dataset.file = file;
236
+ overlay.dataset.file = displayFile;
229
237
  overlay.innerHTML = \`
230
238
  <div style="background:#1a1a1a;border:1px solid #ff4444;border-radius:8px;max-width:860px;width:100%;max-height:90vh;overflow:auto;box-shadow:0 0 40px rgba(255,68,68,.3)">
231
239
  <div style="background:#ff4444;color:#fff;padding:10px 16px;font-size:13px;font-weight:600;display:flex;justify-content:space-between;align-items:center">
232
- <span>Compile error — \${file}</span>
240
+ <span>Compile error — \${displayFile}</span>
233
241
  <span onclick="document.getElementById('__bimba_error__').remove()" style="cursor:pointer;opacity:.7;font-size:16px">✕</span>
234
242
  </div>
235
243
  \${errors.map(err => \`
@@ -244,7 +252,10 @@ const hmrClient = `
244
252
 
245
253
  function clearError(file) {
246
254
  const overlay = document.getElementById('__bimba_error__');
247
- if (overlay && (!file || overlay.dataset.file === file)) overlay.remove();
255
+ if (!overlay) return;
256
+
257
+ const activeFile = overlay.dataset.file;
258
+ if (!file || !activeFile || activeFile === normalizeFile(file)) overlay.remove();
248
259
  }
249
260
 
250
261
  connect();
@@ -609,17 +620,35 @@ export function serve(entrypoint, flags) {
609
620
  }
610
621
 
611
622
  const _debounce = new Map()
623
+ const _watchVersion = new Map()
612
624
 
613
- watch(srcDir, { recursive: true }, async (_event, filename) => {
625
+ function scheduleCompile(filename) {
626
+ filename = filename && String(filename)
614
627
  if (!filename || !filename.endsWith('.imba')) return
615
- if (_debounce.has(filename)) return
616
- _debounce.set(filename, setTimeout(() => _debounce.delete(filename), 150))
617
628
 
629
+ const version = (_watchVersion.get(filename) || 0) + 1
630
+ _watchVersion.set(filename, version)
631
+
632
+ const pending = _debounce.get(filename)
633
+ if (pending) clearTimeout(pending)
634
+
635
+ _debounce.set(filename, setTimeout(() => {
636
+ _debounce.delete(filename)
637
+ compileChangedFile(filename, version)
638
+ }, 150))
639
+ }
640
+
641
+ function isCurrentChange(filename, version) {
642
+ return _watchVersion.get(filename) === version
643
+ }
644
+
645
+ async function compileChangedFile(filename, version) {
618
646
  const filepath = path.join(srcDir, filename)
619
647
  const rel = path.join(path.relative('.', srcDir), filename).replaceAll('\\', '/')
620
648
 
621
649
  try {
622
650
  if (!existsSync(filepath)) {
651
+ if (!isCurrentChange(filename, version)) return
623
652
  dropFileState(filepath)
624
653
  clearError(rel)
625
654
  return
@@ -627,6 +656,7 @@ export function serve(entrypoint, flags) {
627
656
 
628
657
  const out = await compileFile(filepath)
629
658
 
659
+ if (!isCurrentChange(filename, version)) return
630
660
 
631
661
  if (out.errors?.length) {
632
662
  printStatus(rel, 'fail', out.errors)
@@ -638,7 +668,7 @@ export function serve(entrypoint, flags) {
638
668
  return
639
669
  }
640
670
 
641
- clearError()
671
+ clearError(rel)
642
672
 
643
673
  // No change at all — skip
644
674
  if (out.changeType === 'none' || out.changeType === 'cached') return
@@ -646,9 +676,14 @@ export function serve(entrypoint, flags) {
646
676
  printStatus(rel, 'ok')
647
677
  broadcast({ type: 'update', file: rel, slots: out.slots || 'shifted' })
648
678
  } catch(e) {
679
+ if (!isCurrentChange(filename, version)) return
649
680
  printStatus(rel, 'fail', [{ message: e.message }])
650
681
  broadcast({ type: 'error', file: rel, errors: [{ message: e.message, snippet: e.stack || e.message }] })
651
682
  }
683
+ }
684
+
685
+ watch(srcDir, { recursive: true }, (_event, filename) => {
686
+ scheduleCompile(filename)
652
687
  })
653
688
 
654
689
  // ── HTTP + WebSocket server ────────────────────────────────────────────────