@@ -20,6 +20,11 @@ function debug() {
20
20
const INCREMENTAL_FOLDER_NAME = "___incremental" ;
21
21
const INCREMENTAL_FILE_FOLDER_LOCATION = `lib/bs/${ INCREMENTAL_FOLDER_NAME } ` ;
22
22
23
+ type RewatchCompilerArgs = {
24
+ compiler_args : Array < string > ;
25
+ parser_args : Array < string > ;
26
+ } ;
27
+
23
28
type IncrementallyCompiledFileInfo = {
24
29
file : {
25
30
/** File type. */
@@ -44,6 +49,11 @@ type IncrementallyCompiledFileInfo = {
44
49
/** The raw, extracted needed info from build.ninja. Needs processing. */
45
50
rawExtracted : Array < string > ;
46
51
} | null ;
52
+ /** Cache for rewatch compiler args. */
53
+ buildRewatch : {
54
+ lastFile : string ;
55
+ compilerArgs : RewatchCompilerArgs ;
56
+ } | null ;
47
57
/** Info of the currently active incremental compilation. `null` if no incremental compilation is active. */
48
58
compilation : {
49
59
/** The timeout of the currently active compilation for this incremental file. */
@@ -57,6 +67,8 @@ type IncrementallyCompiledFileInfo = {
57
67
project : {
58
68
/** The root path of the project. */
59
69
rootPath : string ;
70
+ /** The root path of the workspace (if a monorepo) */
71
+ workspaceRootPath : string ;
60
72
/** Computed location of bsc. */
61
73
bscBinaryLocation : string ;
62
74
/** The arguments needed for bsc, derived from the project configuration/build.ninja. */
@@ -176,96 +188,139 @@ export function cleanUpIncrementalFiles(
176
188
}
177
189
function getBscArgs (
178
190
entry : IncrementallyCompiledFileInfo
179
- ) : Promise < Array < string > | null > {
191
+ ) : Promise < Array < string > | RewatchCompilerArgs | null > {
180
192
const buildNinjaPath = path . resolve (
181
193
entry . project . rootPath ,
182
194
"lib/bs/build.ninja"
183
195
) ;
196
+ const rewatchLockfile = path . resolve (
197
+ entry . project . workspaceRootPath ,
198
+ "lib/rewatch.lock"
199
+ ) ;
200
+ let buildSystem : "bsb" | "rewatch" | null = null ;
201
+
184
202
let stat : fs . Stats | null = null ;
185
203
try {
186
204
stat = fs . statSync ( buildNinjaPath ) ;
187
- } catch {
188
- if ( debug ( ) ) {
189
- console . log ( "Did not find build.ninja, cannot proceed.." ) ;
190
- }
205
+ buildSystem = "bsb" ;
206
+ } catch { }
207
+ try {
208
+ stat = fs . statSync ( rewatchLockfile ) ;
209
+ buildSystem = "rewatch" ;
210
+ } catch { }
211
+ if ( buildSystem == null ) {
212
+ console . log ( "Did not find build.ninja or rewatch.lock, cannot proceed.." ) ;
191
213
return Promise . resolve ( null ) ;
192
214
}
193
- const cacheEntry = entry . buildNinja ;
215
+ const bsbCacheEntry = entry . buildNinja ;
216
+ const rewatchCacheEntry = entry . buildRewatch ;
217
+
194
218
if (
195
- cacheEntry != null &&
219
+ buildSystem === "bsb" &&
220
+ bsbCacheEntry != null &&
196
221
stat != null &&
197
- cacheEntry . fileMtime >= stat . mtimeMs
222
+ bsbCacheEntry . fileMtime >= stat . mtimeMs
223
+ ) {
224
+ return Promise . resolve ( bsbCacheEntry . rawExtracted ) ;
225
+ }
226
+ if (
227
+ buildSystem === "rewatch" &&
228
+ rewatchCacheEntry != null &&
229
+ rewatchCacheEntry . lastFile === entry . file . sourceFilePath
198
230
) {
199
- return Promise . resolve ( cacheEntry . rawExtracted ) ;
231
+ return Promise . resolve ( rewatchCacheEntry . compilerArgs ) ;
200
232
}
201
233
return new Promise ( ( resolve , _reject ) => {
202
- function resolveResult ( result : Array < string > ) {
203
- if ( stat != null ) {
234
+ function resolveResult ( result : Array < string > | RewatchCompilerArgs ) {
235
+ if ( stat != null && Array . isArray ( result ) ) {
204
236
entry . buildNinja = {
205
237
fileMtime : stat . mtimeMs ,
206
238
rawExtracted : result ,
207
239
} ;
240
+ } else if ( ! Array . isArray ( result ) ) {
241
+ entry . buildRewatch = {
242
+ lastFile : entry . file . sourceFilePath ,
243
+ compilerArgs : result ,
244
+ } ;
208
245
}
209
246
resolve ( result ) ;
210
247
}
211
- const fileStream = fs . createReadStream ( buildNinjaPath ) ;
212
- const rl = readline . createInterface ( {
213
- input : fileStream ,
214
- crlfDelay : Infinity ,
215
- } ) ;
216
- let captureNextLine = false ;
217
- let done = false ;
218
- let stopped = false ;
219
- const captured : Array < string > = [ ] ;
220
- rl . on ( "line" , ( line ) => {
221
- if ( stopped ) {
222
- return ;
223
- }
224
- if ( captureNextLine ) {
225
- captured . push ( line ) ;
226
- captureNextLine = false ;
227
- }
228
- if ( done ) {
229
- fileStream . destroy ( ) ;
230
- rl . close ( ) ;
248
+
249
+ if ( buildSystem === "bsb" ) {
250
+ const fileStream = fs . createReadStream ( buildNinjaPath ) ;
251
+ const rl = readline . createInterface ( {
252
+ input : fileStream ,
253
+ crlfDelay : Infinity ,
254
+ } ) ;
255
+ let captureNextLine = false ;
256
+ let done = false ;
257
+ let stopped = false ;
258
+ const captured : Array < string > = [ ] ;
259
+ rl . on ( "line" , ( line ) => {
260
+ if ( stopped ) {
261
+ return ;
262
+ }
263
+ if ( captureNextLine ) {
264
+ captured . push ( line ) ;
265
+ captureNextLine = false ;
266
+ }
267
+ if ( done ) {
268
+ fileStream . destroy ( ) ;
269
+ rl . close ( ) ;
270
+ resolveResult ( captured ) ;
271
+ stopped = true ;
272
+ return ;
273
+ }
274
+ if ( line . startsWith ( "rule astj" ) ) {
275
+ captureNextLine = true ;
276
+ }
277
+ if ( line . startsWith ( "rule mij" ) ) {
278
+ captureNextLine = true ;
279
+ done = true ;
280
+ }
281
+ } ) ;
282
+ rl . on ( "close" , ( ) => {
231
283
resolveResult ( captured ) ;
232
- stopped = true ;
233
- return ;
234
- }
235
- if ( line . startsWith ( "rule astj" ) ) {
236
- captureNextLine = true ;
237
- }
238
- if ( line . startsWith ( "rule mij" ) ) {
239
- captureNextLine = true ;
240
- done = true ;
284
+ } ) ;
285
+ } else if ( buildSystem === "rewatch" ) {
286
+ try {
287
+ let rewatchPath = path . resolve (
288
+ entry . project . workspaceRootPath ,
289
+ "node_modules/@rolandpeelen/rewatch/rewatch"
290
+ ) ;
291
+ const compilerArgs = JSON . parse (
292
+ cp
293
+ . execFileSync ( rewatchPath , [
294
+ "--rescript-version" ,
295
+ entry . project . rescriptVersion ,
296
+ "--compiler-args" ,
297
+ entry . file . sourceFilePath ,
298
+ ] )
299
+ . toString ( )
300
+ . trim ( )
301
+ ) as RewatchCompilerArgs ;
302
+ resolveResult ( compilerArgs ) ;
303
+ } catch ( e ) {
304
+ console . error ( e ) ;
241
305
}
242
- } ) ;
243
- rl . on ( "close" , ( ) => {
244
- resolveResult ( captured ) ;
245
- } ) ;
306
+ }
246
307
} ) ;
247
308
}
248
- function argsFromCommandString ( cmdString : string ) : Array < Array < string > > {
249
- const s = cmdString
250
- . trim ( )
251
- . split ( "command = " ) [ 1 ]
252
- . split ( " " )
253
- . map ( ( v ) => v . trim ( ) )
254
- . filter ( ( v ) => v !== "" ) ;
255
- const args : Array < Array < string > > = [ ] ;
256
309
257
- for ( let i = 0 ; i <= s . length - 1 ; i ++ ) {
258
- const item = s [ i ] ;
310
+ function argCouples ( argList : string [ ] ) : string [ ] [ ] {
311
+ let args : string [ ] [ ] = [ ] ;
312
+ for ( let i = 0 ; i <= argList . length - 1 ; i ++ ) {
313
+ const item = argList [ i ] ;
259
314
const nextIndex = i + 1 ;
260
- const nextItem = s [ nextIndex ] ?? "" ;
315
+ const nextItem = argList [ nextIndex ] ?? "" ;
261
316
if ( item . startsWith ( "-" ) && nextItem . startsWith ( "-" ) ) {
262
317
// Single entry arg
263
318
args . push ( [ item ] ) ;
264
319
} else if ( item . startsWith ( "-" ) && nextItem . startsWith ( "'" ) ) {
265
320
// Quoted arg, take until ending '
266
321
const arg = [ nextItem . slice ( 1 ) ] ;
267
- for ( let x = nextIndex + 1 ; x <= s . length - 1 ; x ++ ) {
268
- let subItem = s [ x ] ;
322
+ for ( let x = nextIndex + 1 ; x <= argList . length - 1 ; x ++ ) {
323
+ let subItem = argList [ x ] ;
269
324
let break_ = false ;
270
325
if ( subItem . endsWith ( "'" ) ) {
271
326
subItem = subItem . slice ( 0 , subItem . length - 1 ) ;
@@ -284,6 +339,17 @@ function argsFromCommandString(cmdString: string): Array<Array<string>> {
284
339
}
285
340
return args ;
286
341
}
342
+
343
+ function argsFromCommandString ( cmdString : string ) : Array < Array < string > > {
344
+ const argList = cmdString
345
+ . trim ( )
346
+ . split ( "command = " ) [ 1 ]
347
+ . split ( " " )
348
+ . map ( ( v ) => v . trim ( ) )
349
+ . filter ( ( v ) => v !== "" ) ;
350
+
351
+ return argCouples ( argList ) ;
352
+ }
287
353
function removeAnsiCodes ( s : string ) : string {
288
354
const ansiEscape = / \x1B [ @ - _ ] [ 0 - ? ] * [ - / ] * [ @ - ~ ] / g;
289
355
return s . replace ( ansiEscape , "" ) ;
@@ -298,6 +364,9 @@ function triggerIncrementalCompilationOfFile(
298
364
if ( incrementalFileCacheEntry == null ) {
299
365
// New file
300
366
const projectRootPath = utils . findProjectRootOfFile ( filePath ) ;
367
+ const workspaceRootPath = projectRootPath
368
+ ? utils . findProjectRootOfFile ( projectRootPath )
369
+ : null ;
301
370
if ( projectRootPath == null ) {
302
371
if ( debug ( ) )
303
372
console . log ( "Did not find project root path for " + filePath ) ;
@@ -362,12 +431,14 @@ function triggerIncrementalCompilationOfFile(
362
431
incrementalFilePath : path . join ( incrementalFolderPath , moduleName + ext ) ,
363
432
} ,
364
433
project : {
434
+ workspaceRootPath : workspaceRootPath ?? projectRootPath ,
365
435
rootPath : projectRootPath ,
366
436
callArgs : Promise . resolve ( [ ] ) ,
367
437
bscBinaryLocation,
368
438
incrementalFolderPath,
369
439
rescriptVersion,
370
440
} ,
441
+ buildRewatch : null ,
371
442
buildNinja : null ,
372
443
compilation : null ,
373
444
killCompilationListeners : [ ] ,
@@ -419,11 +490,17 @@ function verifyTriggerToken(filePath: string, triggerToken: number): boolean {
419
490
async function figureOutBscArgs ( entry : IncrementallyCompiledFileInfo ) {
420
491
const res = await getBscArgs ( entry ) ;
421
492
if ( res == null ) return null ;
422
- const [ astBuildCommand , fullBuildCommand ] = res ;
423
-
424
- const astArgs = argsFromCommandString ( astBuildCommand ) ;
425
- const buildArgs = argsFromCommandString ( fullBuildCommand ) ;
426
-
493
+ let astArgs : Array < Array < string > > = [ ] ;
494
+ let buildArgs : Array < Array < string > > = [ ] ;
495
+ let isBsb = Array . isArray ( res ) ;
496
+ if ( Array . isArray ( res ) ) {
497
+ const [ astBuildCommand , fullBuildCommand ] = res ;
498
+ astArgs = argsFromCommandString ( astBuildCommand ) ;
499
+ buildArgs = argsFromCommandString ( fullBuildCommand ) ;
500
+ } else {
501
+ astArgs = argCouples ( res . parser_args ) ;
502
+ buildArgs = argCouples ( res . compiler_args ) ;
503
+ }
427
504
let callArgs : Array < string > = [ ] ;
428
505
429
506
if ( config . extensionConfiguration . incrementalTypechecking ?. acrossFiles ) {
@@ -435,10 +512,21 @@ async function figureOutBscArgs(entry: IncrementallyCompiledFileInfo) {
435
512
436
513
buildArgs . forEach ( ( [ key , value ] : Array < string > ) => {
437
514
if ( key === "-I" ) {
438
- callArgs . push (
439
- "-I" ,
440
- path . resolve ( entry . project . rootPath , "lib/bs" , value )
441
- ) ;
515
+ if ( isBsb ) {
516
+ callArgs . push (
517
+ "-I" ,
518
+ path . resolve ( entry . project . rootPath , "lib/bs" , value )
519
+ ) ;
520
+ } else {
521
+ if ( value === "." ) {
522
+ callArgs . push (
523
+ "-I" ,
524
+ path . resolve ( entry . project . rootPath , "lib/ocaml" )
525
+ ) ;
526
+ } else {
527
+ callArgs . push ( "-I" , value ) ;
528
+ }
529
+ }
442
530
} else if ( key === "-bs-v" ) {
443
531
callArgs . push ( "-bs-v" , Date . now ( ) . toString ( ) ) ;
444
532
} else if ( key === "-bs-package-output" ) {
0 commit comments