bimba-cli 0.7.15 → 0.7.17

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/package.json +1 -1
  2. package/serve.js +40 -5
  3. package/typecheck.js +17 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bimba-cli",
3
- "version": "0.7.15",
3
+ "version": "0.7.17",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/HeapVoid/bimba.git"
package/serve.js CHANGED
@@ -208,7 +208,7 @@ const hmrClient = `
208
208
  if (msg.type === 'update') _applyUpdate(msg.file, msg.slots);
209
209
  else if (msg.type === 'reload') location.reload();
210
210
  else if (msg.type === 'error') showError(msg.file, msg.errors);
211
- else if (msg.type === 'clear-error') clearError();
211
+ else if (msg.type === 'clear-error') clearError(msg.file);
212
212
  };
213
213
 
214
214
  ws.onclose = () => setTimeout(connect, 1000);
@@ -225,6 +225,7 @@ const hmrClient = `
225
225
  overlay.addEventListener('click', e => { if (e.target === overlay) overlay.remove(); });
226
226
  document.body.appendChild(overlay);
227
227
  }
228
+ overlay.dataset.file = file;
228
229
  overlay.innerHTML = \`
229
230
  <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)">
230
231
  <div style="background:#ff4444;color:#fff;padding:10px 16px;font-size:13px;font-weight:600;display:flex;justify-content:space-between;align-items:center">
@@ -241,9 +242,9 @@ const hmrClient = `
241
242
  \`;
242
243
  }
243
244
 
244
- function clearError() {
245
+ function clearError(file) {
245
246
  const overlay = document.getElementById('__bimba_error__');
246
- if (overlay) overlay.remove();
247
+ if (overlay && (!file || overlay.dataset.file === file)) overlay.remove();
247
248
  }
248
249
 
249
250
  connect();
@@ -257,6 +258,13 @@ const _prevJs = new Map() // filepath → compiled js — for change detection
257
258
  const _prevSlots = new Map() // filepath → previous symbol slot count
258
259
  const _importScanner = new Bun.Transpiler({ loader: 'js' })
259
260
 
261
+ function dropFileState(filepath) {
262
+ const abs = path.resolve(filepath)
263
+ _compileCache.delete(abs)
264
+ _prevJs.delete(abs)
265
+ _prevSlots.delete(abs)
266
+ }
267
+
260
268
  // Imba compiles tag render-cache slots as anonymous local Symbols at module top
261
269
  // level: `var $4 = Symbol(), $11 = Symbol(), ...; let c$0 = Symbol();`. Each
262
270
  // re-import of the file creates fresh Symbol objects, so old slot data on live
@@ -517,6 +525,7 @@ export function serve(entrypoint, flags) {
517
525
 
518
526
  let _fadeTimers = []
519
527
  let _fadeId = 0
528
+ let _statusFile = null
520
529
  let _statusSaved = false
521
530
  const _isTTY = process.stdout.isTTY
522
531
 
@@ -525,6 +534,16 @@ export function serve(entrypoint, flags) {
525
534
  _fadeTimers = []
526
535
  }
527
536
 
537
+ function clearStatus(file) {
538
+ if (file && _statusFile && _statusFile !== file) return
539
+ cancelFade()
540
+ if (_statusSaved) {
541
+ process.stdout.write('\x1b[u\x1b[J')
542
+ _statusSaved = false
543
+ }
544
+ _statusFile = null
545
+ }
546
+
528
547
  function printStatus(file, state, errors) {
529
548
  // non-TTY (pipes, Claude Code bash, CI): plain newline-terminated output,
530
549
  // no ANSI cursor tricks, no fade-out — so logs stay readable.
@@ -552,6 +571,7 @@ export function serve(entrypoint, flags) {
552
571
 
553
572
  process.stdout.write('\x1b[s')
554
573
  _statusSaved = true
574
+ _statusFile = file
555
575
 
556
576
  if (errors?.length) {
557
577
  process.stdout.write(` ${theme.folder(now)} ${theme.filename(file)} ${status}\n`)
@@ -567,7 +587,10 @@ export function serve(entrypoint, flags) {
567
587
  _fadeTimers.push(setTimeout(() => {
568
588
  if (_fadeId !== myId) return
569
589
  process.stdout.write('\x1b[1D \x1b[1D')
570
- if (i === total) _statusSaved = false
590
+ if (i === total) {
591
+ _statusSaved = false
592
+ _statusFile = null
593
+ }
571
594
  }, 5000 + i * 22))
572
595
  }
573
596
  }
@@ -580,6 +603,11 @@ export function serve(entrypoint, flags) {
580
603
  for (const socket of sockets) socket.send(msg)
581
604
  }
582
605
 
606
+ function clearError(file) {
607
+ clearStatus(file)
608
+ broadcast({ type: 'clear-error', file })
609
+ }
610
+
583
611
  const _debounce = new Map()
584
612
 
585
613
  watch(srcDir, { recursive: true }, async (_event, filename) => {
@@ -591,6 +619,12 @@ export function serve(entrypoint, flags) {
591
619
  const rel = path.join(path.relative('.', srcDir), filename).replaceAll('\\', '/')
592
620
 
593
621
  try {
622
+ if (!existsSync(filepath)) {
623
+ dropFileState(filepath)
624
+ clearError(rel)
625
+ return
626
+ }
627
+
594
628
  const out = await compileFile(filepath)
595
629
 
596
630
 
@@ -604,11 +638,12 @@ export function serve(entrypoint, flags) {
604
638
  return
605
639
  }
606
640
 
641
+ clearError()
642
+
607
643
  // No change at all — skip
608
644
  if (out.changeType === 'none' || out.changeType === 'cached') return
609
645
 
610
646
  printStatus(rel, 'ok')
611
- broadcast({ type: 'clear-error' })
612
647
  broadcast({ type: 'update', file: rel, slots: out.slots || 'shifted' })
613
648
  } catch(e) {
614
649
  printStatus(rel, 'fail', [{ message: e.message }])
package/typecheck.js CHANGED
@@ -157,7 +157,7 @@ function send(server, seq, command, args) {
157
157
 
158
158
  export async function checkImbaTypes(entrypoint, options = {}) {
159
159
  const cwd = options.cwd || process.cwd();
160
- const timeout = Number(options.timeout || process.env.BIMBA_TYPECHECK_TIMEOUT || process.env.IMBA_TS_CHECK_TIMEOUT || 12000);
160
+ const timeout = Number(options.timeout || process.env.BIMBA_TYPECHECK_TIMEOUT || process.env.IMBA_TS_CHECK_TIMEOUT || 30000);
161
161
  const scanRoot = getScanRoot(entrypoint, cwd);
162
162
  const files = collectImbaFiles(scanRoot);
163
163
 
@@ -178,6 +178,7 @@ export async function checkImbaTypes(entrypoint, options = {}) {
178
178
  let buffer = Buffer.alloc(0);
179
179
  const seq = { value: 1 };
180
180
  const diagnostics = [];
181
+ let geterrSeq = null;
181
182
 
182
183
  const server = spawn(runner, [
183
184
  tsserver,
@@ -195,7 +196,7 @@ export async function checkImbaTypes(entrypoint, options = {}) {
195
196
  resolve(success);
196
197
  }
197
198
 
198
- const timer = setTimeout(() => {
199
+ function finishWithDiagnostics() {
199
200
  const unique = uniqueDiagnostics(diagnostics);
200
201
 
201
202
  if (!unique.length) {
@@ -207,6 +208,11 @@ export async function checkImbaTypes(entrypoint, options = {}) {
207
208
  printDiagnostics(cwd, unique);
208
209
  console.log(theme.failure(' Failure ') + ` TypeScript found ${theme.count(unique.length)} diagnostic${unique.length > 1 ? 's' : ''}`);
209
210
  finish(false);
211
+ }
212
+
213
+ const timer = setTimeout(() => {
214
+ console.log(theme.failure(' Failure ') + ` Timed out waiting for TypeScript diagnostics after ${theme.time(timeout)} ms`);
215
+ finish(false);
210
216
  }, timeout);
211
217
 
212
218
  server.on('error', (error) => {
@@ -219,7 +225,14 @@ export async function checkImbaTypes(entrypoint, options = {}) {
219
225
  server.stdout.on('data', chunk => {
220
226
  buffer = Buffer.concat([buffer, chunk]);
221
227
  buffer = parseMessages(buffer, msg => {
222
- if (msg.type != 'event' || !/Diag$/.test(msg.event)) return;
228
+ if (msg.type != 'event') return;
229
+
230
+ if (msg.event == 'requestCompleted' && msg.body?.request_seq == geterrSeq) {
231
+ finishWithDiagnostics();
232
+ return;
233
+ }
234
+
235
+ if (!/Diag$/.test(msg.event)) return;
223
236
  if (!msg.body?.diagnostics?.length) return;
224
237
 
225
238
  for (const diagnostic of msg.body.diagnostics) {
@@ -246,6 +259,7 @@ export async function checkImbaTypes(entrypoint, options = {}) {
246
259
  if (settled) return;
247
260
  send(server, seq, 'configure', { preferences: {}, hostInfo: 'bimba-typecheck' });
248
261
  for (const file of files) send(server, seq, 'open', { file, projectRootPath: cwd });
262
+ geterrSeq = seq.value;
249
263
  send(server, seq, 'geterr', { files, delay: 0 });
250
264
  }, 100);
251
265
  });