@bb-labs/bldr 0.0.3 → 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 +136 -9
  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,14 +349,16 @@ 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();
228
355
  // Close file watcher
229
356
  try {
230
357
  await srcWatcher.close();
231
- console.log("[bldr] src watcher closed");
358
+ logToBldr("[bldr] src watcher closed");
232
359
  }
233
360
  catch (error) {
234
- console.error(`[bldr] error closing src watcher: ${error}`);
361
+ logToBldr(`[bldr] error closing src watcher: ${error}`);
235
362
  }
236
363
  // Kill child processes
237
364
  const killPromises = [];
@@ -247,7 +374,7 @@ async function main() {
247
374
  resolve();
248
375
  }, 5000);
249
376
  }));
250
- console.log("[bldr] killing tsc watcher...");
377
+ logToBldr("[bldr] killing tsc watcher...");
251
378
  }
252
379
  if (!aliasWatch.killed) {
253
380
  killPromises.push(new Promise((resolve) => {
@@ -261,11 +388,11 @@ async function main() {
261
388
  resolve();
262
389
  }, 5000);
263
390
  }));
264
- console.log("[bldr] killing tsc-alias watcher...");
391
+ logToBldr("[bldr] killing tsc-alias watcher...");
265
392
  }
266
393
  // Wait for all child processes to exit
267
394
  await Promise.all(killPromises);
268
- console.log("[bldr] all processes cleaned up");
395
+ logToBldr("[bldr] all processes cleaned up");
269
396
  process.exit(0);
270
397
  };
271
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.3",
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
  }