-
Notifications
You must be signed in to change notification settings - Fork 6.8k
/
Copy pathsetup-project.ts
134 lines (118 loc) · 5.17 KB
/
setup-project.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {chain, Rule, SchematicContext, Tree} from '@angular-devkit/schematics';
import {
addModuleImportToRootModule,
getAppModulePath,
getProjectFromWorkspace,
getProjectMainFile,
getProjectStyleFile,
hasNgModuleImport,
} from '@angular/cdk/schematics';
import {getWorkspace} from '@schematics/angular/utility/workspace';
import {ProjectType} from '@schematics/angular/utility/workspace-models';
import {addFontsToIndex} from './fonts/material-fonts';
import {Schema} from './schema';
import {addThemeToAppStyles, addTypographyClass} from './theming/theming';
/** Name of the Angular module that enables Angular browser animations. */
const browserAnimationsModuleName = 'BrowserAnimationsModule';
/** Name of the module that switches Angular animations to a noop implementation. */
const noopAnimationsModuleName = 'NoopAnimationsModule';
/**
* Scaffolds the basics of a Angular Material application, this includes:
* - Add Packages to package.json
* - Adds pre-built themes to styles.ext
* - Adds Browser Animation to app.module
*/
export default function(options: Schema): Rule {
return async (host: Tree, context: SchematicContext) => {
const workspace = await getWorkspace(host);
const project = getProjectFromWorkspace(workspace, options.project);
if (project.extensions.projectType === ProjectType.Application) {
return chain([
addAnimationsModule(options),
addThemeToAppStyles(options),
addFontsToIndex(options),
addMaterialAppStyles(options),
addTypographyClass(options),
]);
}
context.logger.warn(
'Angular Material has been set up in your workspace. There is no additional setup ' +
'required for consuming Angular Material in your library project.\n\n' +
'If you intended to run the schematic on a different project, pass the `--project` ' +
'option.');
return;
};
}
/**
* Adds an animation module to the root module of the specified project. In case the "animations"
* option is set to false, we still add the `NoopAnimationsModule` because otherwise various
* components of Angular Material will throw an exception.
*/
function addAnimationsModule(options: Schema) {
return async (host: Tree, context: SchematicContext) => {
const workspace = await getWorkspace(host);
const project = getProjectFromWorkspace(workspace, options.project);
const appModulePath = getAppModulePath(host, getProjectMainFile(project));
if (options.animations) {
// In case the project explicitly uses the NoopAnimationsModule, we should print a warning
// message that makes the user aware of the fact that we won't automatically set up
// animations. If we would add the BrowserAnimationsModule while the NoopAnimationsModule
// is already configured, we would cause unexpected behavior and runtime exceptions.
if (hasNgModuleImport(host, appModulePath, noopAnimationsModuleName)) {
context.logger.error(
`Could not set up "${browserAnimationsModuleName}" ` +
`because "${noopAnimationsModuleName}" is already imported.`);
context.logger.info(`Please manually set up browser animations.`);
return;
}
addModuleImportToRootModule(host, browserAnimationsModuleName,
'@angular/platform-browser/animations', project);
} else if (!hasNgModuleImport(host, appModulePath, browserAnimationsModuleName)) {
// Do not add the NoopAnimationsModule module if the project already explicitly uses
// the BrowserAnimationsModule.
addModuleImportToRootModule(host, noopAnimationsModuleName,
'@angular/platform-browser/animations', project);
}
};
}
/**
* Adds custom Material styles to the project style file. The custom CSS sets up the Roboto font
* and reset the default browser body margin.
*/
function addMaterialAppStyles(options: Schema) {
return async (host: Tree, context: SchematicContext) => {
const workspace = await getWorkspace(host);
const project = getProjectFromWorkspace(workspace, options.project);
const styleFilePath = getProjectStyleFile(project);
const logger = context.logger;
if (!styleFilePath) {
logger.error(`Could not find the default style file for this project.`);
logger.info(`Please consider manually setting up the Roboto font in your CSS.`);
return;
}
const buffer = host.read(styleFilePath);
if (!buffer) {
logger.error(`Could not read the default style file within the project ` +
`(${styleFilePath})`);
logger.info(`Please consider manually setting up the Robot font.`);
return;
}
const htmlContent = buffer.toString();
const insertion = '\n' +
`html, body { height: 100%; }\n` +
`body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }\n`;
if (htmlContent.includes(insertion)) {
return;
}
const recorder = host.beginUpdate(styleFilePath);
recorder.insertLeft(htmlContent.length, insertion);
host.commitUpdate(recorder);
};
}