@@ -19,7 +19,13 @@ import {getWorkspace} from '@schematics/angular/utility/config';
19
19
import { join } from 'path' ;
20
20
import { Schema } from '../schema' ;
21
21
import { createCustomTheme } from './custom-theme' ;
22
+ import { red , bold } from 'chalk' ;
22
23
24
+ /** Path segment that can be found in paths that refer to a prebuilt theme. */
25
+ const prebuiltThemePathSegment = '@angular/material/prebuilt-themes' ;
26
+
27
+ /** Default file name of the custom theme that can be generated. */
28
+ const defaultCustomThemeFilename = 'custom-theme.scss' ;
23
29
24
30
/** Add pre-built styles to the main project style file. */
25
31
export function addThemeToAppStyles ( options : Schema ) : ( host : Tree ) => Tree {
@@ -60,11 +66,17 @@ function insertCustomTheme(project: WorkspaceProject, projectName: string, host:
60
66
61
67
// Normalize the path through the devkit utilities because we want to avoid having
62
68
// unnecessary path segments and windows backslash delimiters.
63
- const customThemePath = normalize ( join ( project . sourceRoot , 'custom-theme.scss' ) ) ;
69
+ const customThemePath = normalize ( join ( project . sourceRoot , defaultCustomThemeFilename ) ) ;
64
70
65
- host . create ( customThemePath , themeContent ) ;
71
+ if ( host . exists ( customThemePath ) ) {
72
+ console . warn ( red ( `Cannot create a custom Angular Material theme because
73
+ "${ customThemePath } " already exists. Skipping custom theme generation.` ) ) ;
74
+ return ;
75
+ }
66
76
67
- return addStyleToTarget ( project , 'build' , host , customThemePath , workspace ) ;
77
+ host . create ( customThemePath , themeContent ) ;
78
+ addThemeStyleToTarget ( project , 'build' , host , customThemePath , workspace ) ;
79
+ return ;
68
80
}
69
81
70
82
const insertion = new InsertChange ( stylesPath , 0 , themeContent ) ;
@@ -81,25 +93,42 @@ function insertPrebuiltTheme(project: WorkspaceProject, host: Tree, theme: strin
81
93
// Path needs to be always relative to the `package.json` or workspace root.
82
94
const themePath = `./node_modules/@angular/material/prebuilt-themes/${ theme } .css` ;
83
95
84
- addStyleToTarget ( project , 'build' , host , themePath , workspace ) ;
85
- addStyleToTarget ( project , 'test' , host , themePath , workspace ) ;
96
+ addThemeStyleToTarget ( project , 'build' , host , themePath , workspace ) ;
97
+ addThemeStyleToTarget ( project , 'test' , host , themePath , workspace ) ;
86
98
}
87
99
88
- /** Adds a style entry to the given project target. */
89
- function addStyleToTarget ( project : WorkspaceProject , targetName : string , host : Tree ,
100
+ /** Adds a theming style entry to the given project target options . */
101
+ function addThemeStyleToTarget ( project : WorkspaceProject , targetName : string , host : Tree ,
90
102
assetPath : string , workspace : WorkspaceSchema ) {
103
+
91
104
const targetOptions = getProjectTargetOptions ( project , targetName ) ;
92
105
93
106
if ( ! targetOptions . styles ) {
94
107
targetOptions . styles = [ assetPath ] ;
95
108
} else {
96
109
const existingStyles = targetOptions . styles . map ( s => typeof s === 'string' ? s : s . input ) ;
97
- const hasGivenTheme = existingStyles . find ( s => s . includes ( assetPath ) ) ;
98
- const hasOtherTheme = existingStyles . find ( s => s . includes ( 'material/prebuilt' ) ) ;
99
110
100
- if ( ! hasGivenTheme && ! hasOtherTheme ) {
101
- targetOptions . styles . unshift ( assetPath ) ;
111
+ for ( let [ index , stylePath ] of existingStyles . entries ( ) ) {
112
+ // If the given asset is already specified in the styles, we don't need to do anything.
113
+ if ( stylePath === assetPath ) {
114
+ return ;
115
+ }
116
+
117
+ // In case a prebuilt theme is already set up, we can safely replace the theme with the new
118
+ // theme file. If a custom theme is set up, we are not able to safely replace the custom
119
+ // theme because these files can contain custom styles, while prebuilt themes are
120
+ // always packaged and considered replaceable.
121
+ if ( stylePath . includes ( defaultCustomThemeFilename ) ) {
122
+ console . warn ( red ( `Cannot add "${ bold ( assetPath ) } to the CLI project configuration ` +
123
+ `because there is already a custom theme file referenced. Please manually add ` +
124
+ `the "${ bold ( assetPath ) } " style file to your configuration.` ) ) ;
125
+ return ;
126
+ } else if ( stylePath . includes ( prebuiltThemePathSegment ) ) {
127
+ targetOptions . styles . splice ( index , 1 ) ;
128
+ }
102
129
}
130
+
131
+ targetOptions . styles . unshift ( assetPath ) ;
103
132
}
104
133
105
134
host . overwrite ( 'angular.json' , JSON . stringify ( workspace , null , 2 ) ) ;
0 commit comments