55 * Workflow:
66 * 1. Listens to `stdin` for lines matching the pattern "transpiled [file].ts".
77 * 2. When a match is found, it identifies the corresponding generated ".js" file.
8- * 3. Checks if the ".js" file exists on the filesystem.
9- * 4. If it exists, it triggers `prettier` to format the generated JavaScript file
10- * using the project's configuration (prettier.config.cjs).
11- * 5. Logs the original stdin line (prefixed with "stdin: ") and reports successful
12- * formatting (prefixed with "frmtd: ") or any errors encountered.
8+ * 3. Checks if the ".js" file exists on the filesystem and adds it to a buffer.
9+ * 4. Buffering & Batching:
10+ * - Groups up to BATCH_SIZE (3) files to format them in a single Prettier command.
11+ * - Uses a DEBOUNCE_MS (100ms) timer to flush the buffer if it doesn't fill up.
12+ * 5. Formatting:
13+ * - Uses `spawn` to run Prettier safely, passing files as an array of arguments
14+ * (avoids issues with spaces in paths).
15+ * 6. Logs:
16+ * - Original stdin lines (prefixed with "stdin: ").
17+ * - Successful formatting (prefixed with "frmtd: ").
18+ * - Any errors or stderr output from Prettier.
1319 *
1420 * Usage example:
1521 * node transpile.ts --watch | node transpile_pipe.ts
1622 */
1723import readline from "readline" ;
18- import { exec } from "child_process" ;
24+ import { spawn } from "child_process" ;
1925import fs from "fs" ;
2026
2127if ( process . stdin . isTTY ) {
@@ -32,6 +38,43 @@ Description:
3238 process . exit ( 0 ) ;
3339}
3440
41+ const BATCH_SIZE = 3 ;
42+ const DEBOUNCE_MS = 100 ;
43+
44+ let buffer : string [ ] = [ ] ;
45+ let timeout : NodeJS . Timeout | null = null ;
46+
47+ function flush ( ) {
48+ if ( timeout ) {
49+ clearTimeout ( timeout ) ;
50+ timeout = null ;
51+ }
52+ if ( buffer . length === 0 ) return ;
53+
54+ const files = [ ...buffer ] ;
55+ buffer = [ ] ;
56+
57+ const args = [ "--config" , "prettier.config.cjs" , "--write" , ...files ] ;
58+ const proc = spawn ( "node_modules/.bin/prettier" , args ) ;
59+
60+ let stderr = "" ;
61+ proc . stderr . on ( "data" , ( data ) => {
62+ stderr += data . toString ( ) ;
63+ } ) ;
64+
65+ proc . on ( "error" , ( error ) => {
66+ console . error ( `error: ${ error . message } ` ) ;
67+ } ) ;
68+
69+ proc . on ( "close" , ( code ) => {
70+ if ( code !== 0 ) {
71+ console . error ( `stderr: ${ stderr } ` ) ;
72+ return ;
73+ }
74+ files . forEach ( ( f ) => console . log ( `frmtd: ${ f } ` ) ) ;
75+ } ) ;
76+ }
77+
3578const rl = readline . createInterface ( {
3679 input : process . stdin ,
3780 terminal : false ,
@@ -46,18 +89,16 @@ rl.on("line", (line) => {
4689 const jsFile = tsFile . replace ( / \. t s $ / , ".js" ) ;
4790
4891 if ( fs . existsSync ( jsFile ) ) {
49- const cmd = `/bin/bash node_modules/.bin/prettier --config prettier.config.cjs --write ${ jsFile } ` ;
50- exec ( cmd , ( error , stdout , stderr ) => {
51- if ( error ) {
52- console . error ( `error: ${ error . message } ` ) ;
53- return ;
54- }
55- if ( stderr ) {
56- console . error ( `stderr: ${ stderr } ` ) ;
57- return ;
92+ buffer . push ( jsFile ) ;
93+
94+ if ( buffer . length >= BATCH_SIZE ) {
95+ flush ( ) ;
96+ } else {
97+ if ( timeout ) {
98+ clearTimeout ( timeout ) ;
5899 }
59- console . log ( `frmtd: ${ jsFile } ` ) ;
60- } ) ;
100+ timeout = setTimeout ( flush , DEBOUNCE_MS ) ;
101+ }
61102 }
62103 }
63104} ) ;
0 commit comments