@@ -26,11 +26,12 @@ public class CSTOJS : ILog
26
26
private readonly Stopwatch _Stopwatch = new ( ) ;
27
27
28
28
private Walker ? _Walker = null ;
29
+ private FileSystemWatcher ? _FSWatcher = null ;
29
30
30
31
/// <summary>
31
32
/// New instance of <see cref="CSTOJS"/> with default options, see <see cref="CSTOJSOptions"/>.
32
33
/// </summary>
33
- public CSTOJS ( )
34
+ public CSTOJS ( )
34
35
{
35
36
_Log = ILog . GetILog ( this , _Options ) ;
36
37
@@ -64,7 +65,7 @@ public CSTOJS(CSTOJSOptions options)
64
65
/// <param name="filename">Optional! Filename of a js file if you generating one file!</param>
65
66
/// <returns>empty Task</returns>
66
67
/// <exception cref="DirectoryNotFoundException"></exception>
67
- public async Task GenerateOneAsync ( string path , string ? filename = null )
68
+ public async Task GenerateOneAsync ( string path , string ? filename = null )
68
69
{
69
70
Assembly ? assembly = Assembly . GetEntryAssembly ( ) ;
70
71
List < FileInfo > files = new ( ) ;
@@ -73,7 +74,7 @@ public async Task GenerateOneAsync(string path, string? filename = null)
73
74
{
74
75
files . Add ( new FileInfo ( path ) ) ;
75
76
}
76
- else
77
+ else
77
78
{
78
79
if ( ! Directory . Exists ( path ) )
79
80
throw new DirectoryNotFoundException ( path ) ;
@@ -89,7 +90,7 @@ public async Task GenerateOneAsync(string path, string? filename = null)
89
90
{
90
91
SyntaxTree ? _tree = null ;
91
92
92
- using ( var stream = File . OpenRead ( file . FullName ) )
93
+ using ( var stream = File . Open ( file . FullName , FileMode . Open , FileAccess . Read , FileShare . ReadWrite ) )
93
94
{
94
95
_tree = CSharpSyntaxTree . ParseText ( SourceText . From ( stream ) , path : file . FullName ) ;
95
96
}
@@ -171,15 +172,15 @@ public List<StringBuilder> GenerateOne(string path)
171
172
/// <param name="references">Needed if you don't have access to files. Because Assembly.location is null in Blazor WebAssembly.</param>
172
173
/// <returns>JS <see cref="StringBuilder"/></returns>
173
174
/// <exception cref="ArgumentNullException"></exception>
174
- public StringBuilder GenerateOneFromString ( string csstring , List < MetadataReference > ? references = null )
175
+ public StringBuilder GenerateOneFromString ( string csstring , List < MetadataReference > ? references = null )
175
176
{
176
177
ArgumentNullException . ThrowIfNull ( csstring ) ;
177
178
178
179
Assembly ? assembly = Assembly . GetEntryAssembly ( ) ;
179
180
180
181
SyntaxTree _tree = CSharpSyntaxTree . ParseText ( csstring ) ;
181
-
182
- if ( references != null )
182
+
183
+ if ( references != null )
183
184
Generate ( _tree , assembly , references ) ;
184
185
else
185
186
Generate ( _tree , assembly ) ;
@@ -218,18 +219,100 @@ public async Task GenerateOneFromStringAsync(string csstring, string? filename =
218
219
}
219
220
220
221
string pathCombined = Path . Combine ( _Options . OutPutPath , filename ) ;
221
-
222
+
222
223
await File . WriteAllTextAsync ( pathCombined , _Walker . JSSB . ToString ( ) ) ;
223
224
224
225
_Log . SuccessLine ( $ "--- Done!") ;
225
226
_Log . SuccessLine ( $ "--- Path: { pathCombined } ") ;
226
227
_Log . SuccessLine ( $ "--- --- ---") ;
227
228
}
228
229
230
+ /// <summary>
231
+ /// Method for generating continuously by watching the cs file. Writes a file.
232
+ /// </summary>
233
+ /// <remarks>
234
+ /// <blockquote class="NOTE"><h5>NOTE</h5><para>Note: You must call <see cref="CSTOJS.StopWatching" /> before completing a program.</para></blockquote>
235
+ /// </remarks>
236
+ /// <param name="path">Full path to cs file.</param>
237
+ /// <returns>void</returns>
238
+ /// <exception cref="DirectoryNotFoundException"></exception>
239
+ /// <exception cref="FileNotFoundException"></exception>
240
+ public void GenerateOneContinuously ( string path )
241
+ {
242
+ if ( File . Exists ( path ) )
243
+ {
244
+ FileInfo file = new ( path ) ;
245
+
246
+ if ( file . Directory == null )
247
+ throw new DirectoryNotFoundException ( path ) ;
248
+
249
+ _FSWatcher = new ( file . Directory . FullName ) ;
250
+
251
+ _FSWatcher . NotifyFilter = NotifyFilters . LastWrite ;
252
+
253
+ _FSWatcher . Changed += OnChanged ;
254
+ _FSWatcher . Created += OnCreated ;
255
+ _FSWatcher . Deleted += OnDeleted ;
256
+ _FSWatcher . Renamed += OnRenamed ;
257
+ _FSWatcher . Error += OnError ;
258
+
259
+ _FSWatcher . Filter = file . Name ;
260
+ _FSWatcher . IncludeSubdirectories = true ;
261
+ _FSWatcher . EnableRaisingEvents = true ;
262
+ }
263
+ else
264
+ {
265
+ throw new FileNotFoundException ( path ) ;
266
+ }
267
+ }
268
+ private async void OnChanged ( object sender , FileSystemEventArgs e )
269
+ {
270
+ if ( e . ChangeType != WatcherChangeTypes . Changed )
271
+ return ;
272
+
273
+ _Log . WriteLine ( $ "Changed: { e . FullPath } ") ;
274
+
275
+ await GenerateOneAsync ( e . FullPath ) ;
276
+ }
277
+
278
+ private void OnCreated ( object sender , FileSystemEventArgs e )
279
+ {
280
+ string value = $ "Created: { e . FullPath } ";
281
+ _Log . WriteLine ( value ) ;
282
+ }
283
+
284
+ private void OnDeleted ( object sender , FileSystemEventArgs e )
285
+ {
286
+ _Log . WriteLine ( $ "Deleted: { e . FullPath } ") ;
287
+ }
288
+
289
+ private void OnRenamed ( object sender , RenamedEventArgs e )
290
+ {
291
+ _Log . WriteLine ( $ "Renamed:") ;
292
+ _Log . WriteLine ( $ " Old: { e . OldFullPath } ") ;
293
+ _Log . WriteLine ( $ " New: { e . FullPath } ") ;
294
+ }
295
+
296
+ private void OnError ( object sender , ErrorEventArgs e )
297
+ {
298
+ throw e . GetException ( ) ;
299
+ }
300
+
301
+ /// <summary>
302
+ /// Method for stopping watching cs file.
303
+ /// </summary>
304
+ public void StopWatching ( )
305
+ {
306
+ if ( _FSWatcher != null )
307
+ {
308
+ _FSWatcher . Dispose ( ) ;
309
+ _FSWatcher = null ;
310
+ }
311
+ }
229
312
230
- private void Generate ( SyntaxTree tree , Assembly ? assembly , List < MetadataReference > ? refs = null )
313
+ private void Generate ( SyntaxTree tree , Assembly ? assembly , List < MetadataReference > ? refs = null )
231
314
{
232
- if ( _Options . Debug )
315
+ if ( _Options . Debug )
233
316
{
234
317
_Stopwatch . Restart ( ) ;
235
318
_Log . WriteLine ( "Start stopwatch" ) ;
@@ -262,7 +345,7 @@ private void Generate(SyntaxTree tree, Assembly? assembly, List<MetadataReferenc
262
345
}
263
346
}
264
347
}
265
- else
348
+ else
266
349
{
267
350
references = refs ;
268
351
}
@@ -428,38 +511,23 @@ private void Generate(SyntaxTree tree, Assembly? assembly, List<MetadataReferenc
428
511
429
512
if ( _Options . KeepBraceOnTheSameLine )
430
513
{
431
- //
432
- //
433
- //Overriding root works only once.
434
- //ReplaceTokens? how?
435
- //I'm not sure how to properly fix this...
436
- //Below is a very bad code...
437
- //
438
- //Todo! Delete 'tab' before 'EndOfLineTrivia', if there is any.
439
- //Also cant figure out how to use ReplaceTokens...
440
- //https://learn.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.syntaxnodeextensions.replacetokens?view=roslyn-dotnet-4.9.0
514
+ //TODO! remove whitespace trivia before brace!
441
515
List < SyntaxToken > allBraces = trueRoot . DescendantTokens ( ) . Where ( ( e ) => e . IsKind ( SyntaxKind . OpenBraceToken ) ) . ToList ( ) ;
442
- int i = 0 ;
443
- while ( i < allBraces . Count )
516
+ List < SyntaxTrivia > allTriviaToReplace = new ( ) ;
517
+ for ( int i = 0 ; i < allBraces . Count ; i ++ )
444
518
{
445
- for ( int j = 0 ; j < allBraces . Count ; j ++ )
519
+ SyntaxToken _token = allBraces [ i ] . GetPreviousToken ( ) ;
520
+ if ( _token . HasTrailingTrivia )
446
521
{
447
- SyntaxToken _token = allBraces [ j ] . GetPreviousToken ( ) ;
448
- if ( _token . HasTrailingTrivia )
522
+ SyntaxTrivia _trivia = _token . TrailingTrivia . Where ( ( e ) => e . IsKind ( SyntaxKind . EndOfLineTrivia ) ) . FirstOrDefault ( ) ;
523
+ if ( ! _trivia . IsKind ( SyntaxKind . None ) )
449
524
{
450
- SyntaxTrivia _trivia = _token . TrailingTrivia . Where ( ( e ) => e . IsKind ( SyntaxKind . EndOfLineTrivia ) ) . FirstOrDefault ( ) ;
451
- if ( ! _trivia . IsKind ( SyntaxKind . None ) )
452
- {
453
- SyntaxToken _replacedToken = _token . ReplaceTrivia ( _trivia , SyntaxFactory . Space ) ;
454
- trueRoot = trueRoot . ReplaceToken ( _token , _replacedToken ) ;
455
- break ;
456
- }
525
+ allTriviaToReplace . Add ( _trivia ) ;
457
526
}
458
527
}
459
- allBraces = trueRoot . DescendantTokens ( ) . Where ( ( e ) => e . IsKind ( SyntaxKind . OpenBraceToken ) ) . ToList ( ) ;
460
- i ++ ;
461
528
}
462
-
529
+ trueRoot = trueRoot . ReplaceTrivia ( allTriviaToReplace , ( o , r ) => SyntaxFactory . Space ) ;
530
+
463
531
}
464
532
465
533
if ( rtPath != null && rtPath != string . Empty )
@@ -484,7 +552,7 @@ private void Generate(SyntaxTree tree, Assembly? assembly, List<MetadataReferenc
484
552
485
553
if ( File . Exists ( Path . Combine ( rtPath , "System.Threading.Tasks.dll" ) ) )
486
554
references . Add ( MetadataReference . CreateFromFile ( Path . Combine ( rtPath , "System.Threading.Tasks.dll" ) ) ) ;
487
-
555
+
488
556
if ( File . Exists ( Path . Combine ( rtPath , "System.Console.dll" ) ) )
489
557
references . Add ( MetadataReference . CreateFromFile ( Path . Combine ( rtPath , "System.Console.dll" ) ) ) ;
490
558
@@ -513,7 +581,7 @@ private void Generate(SyntaxTree tree, Assembly? assembly, List<MetadataReferenc
513
581
if ( item . Display == null )
514
582
continue ;
515
583
516
- if ( resultItem . Display == item . Display )
584
+ if ( resultItem . Display == item . Display )
517
585
found = true ;
518
586
}
519
587
@@ -547,7 +615,7 @@ private void Generate(SyntaxTree tree, Assembly? assembly, List<MetadataReferenc
547
615
. AddReferences ( trueReferences . ToArray ( ) )
548
616
. AddSyntaxTrees ( trueST ) ;
549
617
550
-
618
+
551
619
_Walker = new ( _Options , compilation . GetSemanticModel ( trueST ) ) ;
552
620
553
621
_Walker . JSSB . Append ( _Options . AddSBInFront ) ;
0 commit comments