@bb-labs/bldr 0.0.2 → 0.0.4

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/README.md +20 -3
  2. package/dist/index.js +166 -19
  3. package/package.json +6 -2
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # @bb-labs/builder
1
+ # bldr
2
2
 
3
- A TypeScript build tool with watch mode and automatic dist synchronization.
3
+ A TypeScript build tool with watch mode, automatic dist synchronization, and split-terminal UI.
4
4
 
5
5
  ## Installation
6
6
 
@@ -21,5 +21,22 @@ bun add -d @bb-labs/builder typescript tsc-alias
21
21
 
22
22
  ## Options
23
23
 
24
- - `--watch`, `-w`: Watch mode
24
+ - `--watch`, `-w`: Watch mode with split-terminal UI showing tsc, tsc-alias, and bldr outputs side by side
25
25
  - `--project`, `-p <path>`: Custom tsconfig.json path
26
+
27
+ ## Testing
28
+
29
+ Run `bun run test:dev` to test the build tool with the included test files in `test-src/`. This will:
30
+
31
+ - Build files from `test-src/` to `test-dist/`
32
+ - Show the split-terminal UI with real-time updates
33
+ - Watch for changes and rebuild automatically
34
+
35
+ Add or modify files in `test-src/` to see the build tool in action!
36
+
37
+ ## Features
38
+
39
+ - **Split Terminal UI**: In watch mode, displays three panels side by side showing output from TypeScript compiler, tsc-alias, and bldr itself
40
+ - **Clean Builds**: Always cleans output directory before building
41
+ - **Path Alias Support**: Integrates with tsc-alias for path mapping
42
+ - **Process Management**: Properly handles child process cleanup on exit
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { spawn } from "node:child_process";
3
3
  import path from "node:path";
4
4
  import fs from "node:fs";
5
5
  import chokidar from "chokidar";
6
+ import blessed from "blessed";
6
7
  // We use the TypeScript API to correctly resolve tsconfig + "extends".
7
8
  import ts from "typescript";
8
9
  function parseArgs(argv) {
@@ -79,7 +80,7 @@ function run(cmd, args, cwd) {
79
80
  function spawnLongRunning(cmd, args, cwd) {
80
81
  const p = spawn(cmd, args, {
81
82
  cwd,
82
- stdio: "inherit",
83
+ stdio: ["inherit", "pipe", "pipe"], // pipe stdout and stderr
83
84
  shell: process.platform === "win32",
84
85
  });
85
86
  return p;
@@ -133,6 +134,79 @@ async function main() {
133
134
  }
134
135
  const rootDirAbs = path.isAbsolute(cfg.rootDir) ? cfg.rootDir : path.resolve(cfg.configDir, cfg.rootDir);
135
136
  const outDirAbs = path.isAbsolute(cfg.outDir) ? cfg.outDir : path.resolve(cfg.configDir, cfg.outDir);
137
+ // Create terminal UI only in watch mode
138
+ let screen, bldrBox, tscBox, aliasBox, logToBldr;
139
+ if (args.watch) {
140
+ screen = blessed.screen({
141
+ smartCSR: true,
142
+ title: "bldr - TypeScript Build Tool",
143
+ });
144
+ bldrBox = blessed.box({
145
+ top: 0,
146
+ left: 0,
147
+ width: "33%",
148
+ height: "100%",
149
+ label: " bldr ",
150
+ border: { type: "line" },
151
+ scrollable: true,
152
+ alwaysScroll: true,
153
+ scrollbar: { ch: " " },
154
+ });
155
+ tscBox = blessed.box({
156
+ top: 0,
157
+ left: "33%",
158
+ width: "34%",
159
+ height: "100%",
160
+ label: " tsc ",
161
+ border: { type: "line" },
162
+ scrollable: true,
163
+ alwaysScroll: true,
164
+ scrollbar: { ch: " " },
165
+ });
166
+ aliasBox = blessed.box({
167
+ top: 0,
168
+ left: "67%",
169
+ width: "33%",
170
+ height: "100%",
171
+ label: " tsc-alias ",
172
+ border: { type: "line" },
173
+ scrollable: true,
174
+ alwaysScroll: true,
175
+ scrollbar: { ch: " " },
176
+ });
177
+ screen.append(bldrBox);
178
+ screen.append(tscBox);
179
+ screen.append(aliasBox);
180
+ // Handle screen events
181
+ screen.key(["escape", "q", "C-c"], () => {
182
+ shutdown();
183
+ });
184
+ screen.key(["C-l"], () => {
185
+ bldrBox.setScrollPerc(100);
186
+ tscBox.setScrollPerc(100);
187
+ aliasBox.setScrollPerc(100);
188
+ screen.render();
189
+ });
190
+ // Create a function to log to the bldr box
191
+ logToBldr = (text) => {
192
+ bldrBox.insertBottom(text);
193
+ bldrBox.setScrollPerc(100);
194
+ screen.render();
195
+ };
196
+ // Override console.log and console.error for bldr messages
197
+ const originalLog = console.log;
198
+ const originalError = console.error;
199
+ console.log = (...args) => {
200
+ logToBldr(args.join(" "));
201
+ // Don't call originalLog to avoid double output
202
+ };
203
+ console.error = (...args) => {
204
+ logToBldr(args.join(" "));
205
+ // Don't call originalError to avoid double output
206
+ };
207
+ screen.render();
208
+ }
209
+ // Initial messages will now go to the bldr box via overridden console.log
136
210
  console.log([
137
211
  `\n[bldr] project: ${rel(cwd, tsconfigPath)}`,
138
212
  `[bldr] rootDir : ${rel(cwd, rootDirAbs)}`,
@@ -156,10 +230,11 @@ async function main() {
156
230
  await rmIfExists(outDirAbs);
157
231
  throw error;
158
232
  }
233
+ console.log(`[bldr] build completed successfully!`);
159
234
  return;
160
235
  }
161
236
  // Watch mode:
162
- // 1) Do a clean initial pass so dist is correct immediately.
237
+ // 2) Do a clean initial pass so dist is correct immediately.
163
238
  try {
164
239
  await run("tsc", tscArgs, cwd);
165
240
  await run("tsc-alias", aliasArgs, cwd);
@@ -169,9 +244,59 @@ async function main() {
169
244
  // Continue in watch mode even if initial build fails
170
245
  console.log(`[bldr] continuing in watch mode...`);
171
246
  }
172
- // 2) Start watchers
247
+ // 3) Start watchers
173
248
  const tscWatch = spawnLongRunning("tsc", [...tscArgs, "-w"], cwd);
174
249
  const aliasWatch = spawnLongRunning("tsc-alias", [...aliasArgs, "-w"], cwd);
250
+ // Pipe output to boxes
251
+ if (tscWatch.stdout) {
252
+ tscWatch.stdout.on("data", (data) => {
253
+ const text = data.toString().trim();
254
+ if (text) {
255
+ tscBox.insertBottom(text);
256
+ tscBox.setScrollPerc(100);
257
+ screen.render();
258
+ }
259
+ });
260
+ }
261
+ if (tscWatch.stderr) {
262
+ tscWatch.stderr.on("data", (data) => {
263
+ const text = data.toString().trim();
264
+ if (text) {
265
+ tscBox.insertBottom(text);
266
+ tscBox.setScrollPerc(100);
267
+ screen.render();
268
+ }
269
+ });
270
+ }
271
+ if (aliasWatch.stdout) {
272
+ aliasWatch.stdout.on("data", (data) => {
273
+ const text = data.toString().trim();
274
+ if (text) {
275
+ aliasBox.insertBottom(text);
276
+ aliasBox.setScrollPerc(100);
277
+ screen.render();
278
+ }
279
+ });
280
+ }
281
+ if (aliasWatch.stderr) {
282
+ aliasWatch.stderr.on("data", (data) => {
283
+ const text = data.toString().trim();
284
+ if (text) {
285
+ aliasBox.insertBottom(text);
286
+ aliasBox.setScrollPerc(100);
287
+ screen.render();
288
+ }
289
+ });
290
+ }
291
+ // If any child process errors or exits, shut down all processes
292
+ tscWatch.on("error", (error) => {
293
+ console.error(`[bldr] tsc watcher error: ${error}`);
294
+ shutdown();
295
+ });
296
+ aliasWatch.on("error", (error) => {
297
+ console.error(`[bldr] tsc-alias watcher error: ${error}`);
298
+ shutdown();
299
+ });
175
300
  // 3) dist sync watcher: remove stale outputs on deletes/dir deletes
176
301
  const cleaner = makeDistCleaner(rootDirAbs, outDirAbs);
177
302
  const srcWatcher = chokidar.watch(rootDirAbs, {
@@ -224,28 +349,50 @@ async function main() {
224
349
  });
225
350
  // TypeScript compiler handles additions and changes automatically
226
351
  const shutdown = async () => {
227
- console.log("\n[bldr] shutting down...");
352
+ logToBldr("\n[bldr] shutting down...");
353
+ // Destroy screen
354
+ screen.destroy();
355
+ // Close file watcher
228
356
  try {
229
- srcWatcher.close();
230
- console.log("[bldr] src watcher closed");
357
+ await srcWatcher.close();
358
+ logToBldr("[bldr] src watcher closed");
231
359
  }
232
360
  catch (error) {
233
- console.error(`[bldr] error closing src watcher: ${error}`);
361
+ logToBldr(`[bldr] error closing src watcher: ${error}`);
234
362
  }
235
- try {
236
- tscWatch.kill();
237
- console.log("[bldr] tsc watcher killed");
363
+ // Kill child processes
364
+ const killPromises = [];
365
+ if (!tscWatch.killed) {
366
+ killPromises.push(new Promise((resolve) => {
367
+ tscWatch.on("exit", () => resolve());
368
+ tscWatch.kill();
369
+ // Force kill after 5 seconds
370
+ setTimeout(() => {
371
+ if (!tscWatch.killed) {
372
+ tscWatch.kill("SIGKILL");
373
+ }
374
+ resolve();
375
+ }, 5000);
376
+ }));
377
+ logToBldr("[bldr] killing tsc watcher...");
238
378
  }
239
- catch (error) {
240
- console.error(`[bldr] error killing tsc watcher: ${error}`);
241
- }
242
- try {
243
- aliasWatch.kill();
244
- console.log("[bldr] tsc-alias watcher killed");
245
- }
246
- catch (error) {
247
- console.error(`[bldr] error killing tsc-alias watcher: ${error}`);
379
+ if (!aliasWatch.killed) {
380
+ killPromises.push(new Promise((resolve) => {
381
+ aliasWatch.on("exit", () => resolve());
382
+ aliasWatch.kill();
383
+ // Force kill after 5 seconds
384
+ setTimeout(() => {
385
+ if (!aliasWatch.killed) {
386
+ aliasWatch.kill("SIGKILL");
387
+ }
388
+ resolve();
389
+ }, 5000);
390
+ }));
391
+ logToBldr("[bldr] killing tsc-alias watcher...");
248
392
  }
393
+ // Wait for all child processes to exit
394
+ await Promise.all(killPromises);
395
+ logToBldr("[bldr] all processes cleaned up");
249
396
  process.exit(0);
250
397
  };
251
398
  process.on("SIGINT", shutdown);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bb-labs/bldr",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "bin": {
5
5
  "bldr": "./dist/index.js"
6
6
  },
@@ -9,9 +9,12 @@
9
9
  ],
10
10
  "scripts": {
11
11
  "build": "tsc",
12
- "postbuild": "chmod +x dist/index.js"
12
+ "postbuild": "chmod +x dist/index.js",
13
+ "test:build": "bun run src/index.ts --project test-src/tsconfig.json",
14
+ "test:watch": "bun run src/index.ts --watch --project test-src/tsconfig.json"
13
15
  },
14
16
  "devDependencies": {
17
+ "@types/blessed": "^0.1.27",
15
18
  "@types/bun": "latest",
16
19
  "@types/node": "latest"
17
20
  },
@@ -20,6 +23,7 @@
20
23
  },
21
24
  "dependencies": {
22
25
  "@bb-labs/tsconfigs": "^0.0.1",
26
+ "blessed": "^0.1.81",
23
27
  "chokidar": "^5.0.0",
24
28
  "tsc-alias": "^1.8.8"
25
29
  }