7
7
*/
8
8
9
9
import {
10
- DirEntry ,
11
10
Rule ,
12
11
SchematicContext ,
13
12
SchematicsException ,
14
13
Tree ,
15
14
chain ,
16
15
externalSchematic ,
17
16
} from '@angular-devkit/schematics' ;
18
- import { basename , dirname , extname , join } from 'node:path/posix' ;
17
+ import { dirname , join } from 'node:path/posix' ;
19
18
import { removePackageJsonDependency } from '../../utility/dependencies' ;
20
19
import {
21
20
DependencyType ,
@@ -27,13 +26,16 @@ import { JSONFile } from '../../utility/json-file';
27
26
import { latestVersions } from '../../utility/latest-versions' ;
28
27
import {
29
28
TargetDefinition ,
30
- WorkspaceDefinition ,
31
29
allTargetOptions ,
32
30
allWorkspaceTargets ,
33
31
updateWorkspace ,
34
32
} from '../../utility/workspace' ;
35
33
import { Builders , ProjectType } from '../../utility/workspace-models' ;
36
- import { findImports } from './css-import-lexer' ;
34
+ import {
35
+ hasLessStylesheets ,
36
+ hasPostcssConfiguration ,
37
+ updateStyleImports ,
38
+ } from './stylesheet-updates' ;
37
39
38
40
function * updateBuildTarget (
39
41
projectName : string ,
@@ -334,168 +336,6 @@ function updateProjects(tree: Tree, context: SchematicContext) {
334
336
} ) ;
335
337
}
336
338
337
- /**
338
- * Searches the schematic tree for files that have a `.less` extension.
339
- *
340
- * @param tree A Schematics tree instance to search
341
- * @returns true if Less stylesheet files are found; otherwise, false
342
- */
343
- function hasLessStylesheets ( tree : Tree ) {
344
- const directories = [ tree . getDir ( '/' ) ] ;
345
-
346
- let current ;
347
- while ( ( current = directories . pop ( ) ) ) {
348
- for ( const path of current . subfiles ) {
349
- if ( path . endsWith ( '.less' ) ) {
350
- return true ;
351
- }
352
- }
353
-
354
- for ( const path of current . subdirs ) {
355
- if ( path === 'node_modules' || path . startsWith ( '.' ) ) {
356
- continue ;
357
- }
358
- directories . push ( current . dir ( path ) ) ;
359
- }
360
- }
361
- }
362
-
363
- /**
364
- * Searches for a Postcss configuration file within the workspace root
365
- * or any of the project roots.
366
- *
367
- * @param tree A Schematics tree instance to search
368
- * @param workspace A Workspace to check for projects
369
- * @returns true, if a Postcss configuration file is found; otherwise, false
370
- */
371
- function hasPostcssConfiguration ( tree : Tree , workspace : WorkspaceDefinition ) {
372
- // Add workspace root
373
- const searchDirectories = [ '' ] ;
374
-
375
- // Add each project root
376
- for ( const { root } of workspace . projects . values ( ) ) {
377
- if ( root ) {
378
- searchDirectories . push ( root ) ;
379
- }
380
- }
381
-
382
- return searchDirectories . some (
383
- ( dir ) =>
384
- tree . exists ( join ( dir , 'postcss.config.json' ) ) || tree . exists ( join ( dir , '.postcssrc.json' ) ) ,
385
- ) ;
386
- }
387
-
388
- function * visit (
389
- directory : DirEntry ,
390
- ) : IterableIterator < [ fileName : string , contents : string , sass : boolean ] > {
391
- for ( const path of directory . subfiles ) {
392
- const sass = path . endsWith ( '.scss' ) ;
393
- if ( path . endsWith ( '.css' ) || sass ) {
394
- const entry = directory . file ( path ) ;
395
- if ( entry ) {
396
- const content = entry . content ;
397
-
398
- yield [ entry . path , content . toString ( ) , sass ] ;
399
- }
400
- }
401
- }
402
-
403
- for ( const path of directory . subdirs ) {
404
- if ( path === 'node_modules' || path . startsWith ( '.' ) ) {
405
- continue ;
406
- }
407
-
408
- yield * visit ( directory . dir ( path ) ) ;
409
- }
410
- }
411
-
412
- // Based on https://github.com/sass/dart-sass/blob/44d6bb6ac72fe6b93f5bfec371a1fffb18e6b76d/lib/src/importer/utils.dart
413
- function * potentialSassImports (
414
- specifier : string ,
415
- base : string ,
416
- fromImport : boolean ,
417
- ) : Iterable < string > {
418
- const directory = join ( base , dirname ( specifier ) ) ;
419
- const extension = extname ( specifier ) ;
420
- const hasStyleExtension = extension === '.scss' || extension === '.sass' || extension === '.css' ;
421
- // Remove the style extension if present to allow adding the `.import` suffix
422
- const filename = basename ( specifier , hasStyleExtension ? extension : undefined ) ;
423
-
424
- if ( hasStyleExtension ) {
425
- if ( fromImport ) {
426
- yield join ( directory , filename + '.import' + extension ) ;
427
- yield join ( directory , '_' + filename + '.import' + extension ) ;
428
- }
429
- yield join ( directory , filename + extension ) ;
430
- yield join ( directory , '_' + filename + extension ) ;
431
- } else {
432
- if ( fromImport ) {
433
- yield join ( directory , filename + '.import.scss' ) ;
434
- yield join ( directory , filename + '.import.sass' ) ;
435
- yield join ( directory , filename + '.import.css' ) ;
436
- yield join ( directory , '_' + filename + '.import.scss' ) ;
437
- yield join ( directory , '_' + filename + '.import.sass' ) ;
438
- yield join ( directory , '_' + filename + '.import.css' ) ;
439
- }
440
- yield join ( directory , filename + '.scss' ) ;
441
- yield join ( directory , filename + '.sass' ) ;
442
- yield join ( directory , filename + '.css' ) ;
443
- yield join ( directory , '_' + filename + '.scss' ) ;
444
- yield join ( directory , '_' + filename + '.sass' ) ;
445
- yield join ( directory , '_' + filename + '.css' ) ;
446
- }
447
- }
448
-
449
- function updateStyleImports ( tree : Tree , projectSourceRoot : string , buildTarget : TargetDefinition ) {
450
- const external = new Set < string > ( ) ;
451
- let needWorkspaceIncludePath = false ;
452
- for ( const file of visit ( tree . getDir ( projectSourceRoot ) ) ) {
453
- const [ path , content , sass ] = file ;
454
- const relativeBase = dirname ( path ) ;
455
-
456
- let updater ;
457
- for ( const { start, specifier, fromUse } of findImports ( content , sass ) ) {
458
- if ( specifier [ 0 ] === '~' ) {
459
- updater ??= tree . beginUpdate ( path ) ;
460
- // start position includes the opening quote
461
- updater . remove ( start + 1 , 1 ) ;
462
- } else if ( specifier [ 0 ] === '^' ) {
463
- updater ??= tree . beginUpdate ( path ) ;
464
- // start position includes the opening quote
465
- updater . remove ( start + 1 , 1 ) ;
466
- // Add to externalDependencies
467
- external . add ( specifier . slice ( 1 ) ) ;
468
- } else if (
469
- sass &&
470
- [ ...potentialSassImports ( specifier , relativeBase , ! fromUse ) ] . every (
471
- ( v ) => ! tree . exists ( v ) ,
472
- ) &&
473
- [ ...potentialSassImports ( specifier , '/' , ! fromUse ) ] . some ( ( v ) => tree . exists ( v ) )
474
- ) {
475
- needWorkspaceIncludePath = true ;
476
- }
477
- }
478
- if ( updater ) {
479
- tree . commitUpdate ( updater ) ;
480
- }
481
- }
482
-
483
- if ( needWorkspaceIncludePath ) {
484
- buildTarget . options ??= { } ;
485
- buildTarget . options [ 'stylePreprocessorOptions' ] ??= { } ;
486
- ( ( buildTarget . options [ 'stylePreprocessorOptions' ] as { includePaths ?: string [ ] } ) [
487
- 'includePaths'
488
- ] ??= [ ] ) . push ( '.' ) ;
489
- }
490
-
491
- if ( external . size > 0 ) {
492
- buildTarget . options ??= { } ;
493
- ( ( buildTarget . options [ 'externalDependencies' ] as string [ ] | undefined ) ??= [ ] ) . push (
494
- ...external ,
495
- ) ;
496
- }
497
- }
498
-
499
339
function deleteFile ( path : string ) : Rule {
500
340
return ( tree ) => {
501
341
tree . delete ( path ) ;
0 commit comments