11#!/usr/bin/env node
22
3- import gaze from 'gaze' ;
3+ import chokidar from 'chokidar' ;
4+ import allSettled from 'promise.allsettled' ;
45import fs from 'fs' ;
56import path from 'path' ;
67import minimist from 'minimist' ;
@@ -9,125 +10,92 @@ import { extractMachines } from './extractMachines';
910import { printToFile , printJsFiles } from './printToFile' ;
1011
1112const { _ : arrayArgs , ...objectArgs } = minimist ( process . argv . slice ( 2 ) ) ;
13+ const onlyOnce = objectArgs . once ;
1214
13- const [ , , pattern ] = process . argv ;
15+ const [ , , ... patterns ] = process . argv ;
1416
15- type RecordOfArrays = Record < string , string [ ] > ;
16-
17- const flattenRecords = (
18- filesAsRecord : Record < string , RecordOfArrays | string [ ] > | string [ ] ,
19- ) : string [ ] => {
20- if ( Array . isArray ( filesAsRecord ) ) {
21- return filesAsRecord ;
22- }
23- return Object . values ( filesAsRecord ) . reduce (
24- ( array , paths ) => array . concat ( flattenRecords ( paths ) ) ,
25- [ ] as any ,
26- ) as string [ ] ;
27- } ;
28-
29- if ( ! pattern ) {
30- console . log ( 'You must pass a glob, for instance "**/src/**.machine.ts"' ) ;
17+ if ( patterns . length === 0 ) {
18+ console . log (
19+ 'You must pass at least one glob, for instance "**/src/**.machine.ts"' ,
20+ ) ;
3121 process . exit ( 1 ) ;
3222}
3323
34- const toRelative = ( filePath : string ) => path . relative ( process . cwd ( ) , filePath ) ;
35-
3624const typedSuffix = / \. t y p e d \. ( j s | t s | t s x | j s x ) $ / ;
37-
3825const tsExtension = / \. ( t s | t s x | j s | j s x ) $ / ;
26+ function isValidFile ( filePath : string ) {
27+ return ! typedSuffix . test ( filePath ) && tsExtension . test ( filePath ) ;
28+ }
3929
40- let fileCache : Record <
30+ const fileCache : Record <
4131 string ,
4232 ReturnType < typeof introspectMachine > & { id : string }
4333> = { } ;
4434
45- gaze ( pattern , { } , async function ( err , watcher ) {
46- if ( err ) {
47- console . log ( err ) ;
48- process . exit ( 1 ) ;
49- }
35+ printJsFiles();
36+ console.clear();
5037
51- const filesAsRecord : Record < string , string [ ] > = watcher . watched ( ) as any ;
38+ const watcher = chokidar.watch(patterns, {
39+ persistent : ! onlyOnce ,
40+ } );
5241
53- const files = flattenRecords ( filesAsRecord ) ;
42+ watcher.on('error', (err) => {
43+ console . error ( err ) ;
44+ process . exit ( 1 ) ;
45+ } );
5446
55- const filteredFiles = files . filter ( ( filePath ) => {
56- return ! typedSuffix . test ( filePath ) && tsExtension . test ( filePath ) ;
57- } ) ;
47+ const toRelative = (filePath: string) => path . relative ( process . cwd ( ) , filePath ) ;
5848
59- if ( filteredFiles . length === 0 ) {
60- console . log ( 'No files found from that glob' ) ;
61- process . exit ( 1 ) ;
49+ watcher . on ( 'all' , async ( eventName , filePath ) => {
50+ if ( ! isValidFile ( filePath ) ) {
51+ return ;
6252 }
63-
64- printJsFiles ( ) ;
65- console . clear ( ) ;
66-
67- const addToCache = async ( filePath : string ) => {
68- let code : string = '' ;
69- try {
70- code = fs . readFileSync ( filePath , 'utf8' ) ;
71- } catch ( e ) { }
72- if ( ! code ) {
73- console . log ( `Could not read from path ${ filePath } ` ) ;
74- return ;
75- }
76- if ( ! code . includes ( '@xstate/compiled' ) ) {
77- return ;
78- }
79- const machines = await extractMachines ( filePath ) ;
80- if ( machines . length === 0 ) {
81- return ;
82- }
83- const { machine, id } = machines [ 0 ] ;
84- fileCache [ filePath ] = { ...introspectMachine ( machine ) , id } ;
85- } ;
86-
87- await filteredFiles . reduce ( async ( promise , filePath ) => {
88- await promise ;
89- try {
90- console . log ( `Scanning File: ` . cyan . bold + toRelative ( filePath ) . gray ) ;
91- await addToCache ( filePath ) ;
92- } catch ( e ) {
93- console . log ( e ) ;
94- if ( objectArgs . once ) {
95- console . log ( 'Could not complete due to errors' . red . bold ) ;
96- // @ts -ignore
97- this . close ( ) ;
98- process . exit ( 1 ) ;
99- }
100- }
101- } , Promise . resolve ( ) ) ;
102-
103- printToFile ( fileCache , objectArgs . outDir ) ;
104-
105- if ( objectArgs . once ) {
106- console . log ( 'Completed!' . green . bold ) ;
107- // @ts -ignore
108- this . close ( ) ;
109- process . exit ( 0 ) ;
53+ if ( eventName === 'add' ) {
54+ console . log ( `Scanning File: ` . cyan . bold + toRelative ( filePath ) . gray ) ;
55+ await addToCache ( filePath ) ;
11056 }
111-
112- // @ts -ignore
113- this . on ( 'changed' , async ( filePath ) => {
57+ if ( eventName === 'change' ) {
11458 console . log ( `File Changed: ` . cyan . bold + toRelative ( filePath ) . gray ) ;
11559 await addToCache ( filePath ) ;
116- printToFile ( fileCache , objectArgs . outDir ) ;
117- } ) ;
118- // @ts -ignore
119- this . on ( 'added' , async ( filePath ) => {
120- console . log ( `File Added: ` . green . bold + toRelative ( filePath ) . gray ) ;
121- await addToCache ( filePath ) ;
122- printToFile ( fileCache , objectArgs . outDir ) ;
123- } ) ;
124-
125- // @ts -ignore
126- this . on ( 'deleted' , async ( filePath ) => {
60+ }
61+ if ( eventName === 'unlink' ) {
12762 console . log ( `File Deleted: ` . red . bold + toRelative ( filePath ) . gray ) ;
128- delete fileCache [ filePath ] ;
129- printToFile ( fileCache , objectArgs . outDir ) ;
130- } ) ;
63+ removeFromCache ( filePath ) ;
64+ }
65+ printToFile ( fileCache , objectArgs . outDir ) ;
66+ } ) ;
67+
68+ process . on ( 'exit' , ( ) => {
69+ console . log ( 'Completed!' . green . bold ) ;
70+ } ) ;
13171
132- console . log ( `Watching for file changes in: ` . cyan . bold + pattern . gray ) ;
72+ watcher . on ( 'ready' , async ( ) => {
73+ if ( ! onlyOnce ) {
74+ patterns . forEach ( ( pattern ) => {
75+ console . log ( `Watching for file changes in: ` . cyan . bold + pattern ) ;
76+ } ) ;
77+ }
13378} ) ;
79+
80+ async function addToCache ( filePath : string ) {
81+ let code : string = '' ;
82+ try {
83+ code = fs . readFileSync ( filePath , 'utf8' ) ;
84+ } catch ( e ) { }
85+ if ( ! code ) {
86+ throw new Error ( `Could not read from path ${ filePath } ` ) ;
87+ }
88+ if ( ! code . includes ( '@xstate/compiled' ) ) {
89+ return ;
90+ }
91+ const machines = await extractMachines ( filePath ) ;
92+ if ( machines . length === 0 ) {
93+ return ;
94+ }
95+ const { machine, id } = machines [ 0 ] ;
96+ fileCache [ filePath ] = { ...introspectMachine ( machine ) , id } ;
97+ }
98+
99+ function removeFromCache ( filePath : string ) {
100+ delete fileCache [ filePath ] ;
101+ }
0 commit comments