@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.
- package/README.md +20 -3
- package/dist/index.js +166 -19
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# bldr
|
|
2
2
|
|
|
3
|
-
A TypeScript build tool with watch mode
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
|
|
352
|
+
logToBldr("\n[bldr] shutting down...");
|
|
353
|
+
// Destroy screen
|
|
354
|
+
screen.destroy();
|
|
355
|
+
// Close file watcher
|
|
228
356
|
try {
|
|
229
|
-
srcWatcher.close();
|
|
230
|
-
|
|
357
|
+
await srcWatcher.close();
|
|
358
|
+
logToBldr("[bldr] src watcher closed");
|
|
231
359
|
}
|
|
232
360
|
catch (error) {
|
|
233
|
-
|
|
361
|
+
logToBldr(`[bldr] error closing src watcher: ${error}`);
|
|
234
362
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
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.
|
|
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
|
}
|