77 */
88
99import {
10- DirEntry ,
1110 Rule ,
1211 SchematicContext ,
1312 SchematicsException ,
1413 Tree ,
1514 chain ,
1615 externalSchematic ,
1716} from '@angular-devkit/schematics' ;
18- import { basename , dirname , extname , join } from 'node:path/posix' ;
17+ import { dirname , join } from 'node:path/posix' ;
1918import { removePackageJsonDependency } from '../../utility/dependencies' ;
2019import {
2120 DependencyType ,
@@ -27,13 +26,16 @@ import { JSONFile } from '../../utility/json-file';
2726import { latestVersions } from '../../utility/latest-versions' ;
2827import {
2928 TargetDefinition ,
30- WorkspaceDefinition ,
3129 allTargetOptions ,
3230 allWorkspaceTargets ,
3331 updateWorkspace ,
3432} from '../../utility/workspace' ;
3533import { 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' ;
3739
3840function * updateBuildTarget (
3941 projectName : string ,
@@ -334,168 +336,6 @@ function updateProjects(tree: Tree, context: SchematicContext) {
334336 } ) ;
335337}
336338
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-
499339function deleteFile ( path : string ) : Rule {
500340 return ( tree ) => {
501341 tree . delete ( path ) ;
0 commit comments