1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | const core_1 = require("@angular-devkit/core");
|
11 | const schematics_1 = require("@angular-devkit/schematics");
|
12 | const tasks_1 = require("@angular-devkit/schematics/tasks");
|
13 | const dependencies_1 = require("../utility/dependencies");
|
14 | const json_utils_1 = require("../utility/json-utils");
|
15 | const latest_versions_1 = require("../utility/latest-versions");
|
16 | const lint_fix_1 = require("../utility/lint-fix");
|
17 | const paths_1 = require("../utility/paths");
|
18 | const tsconfig_1 = require("../utility/tsconfig");
|
19 | const validation_1 = require("../utility/validation");
|
20 | const workspace_1 = require("../utility/workspace");
|
21 | const workspace_models_1 = require("../utility/workspace-models");
|
22 | const schema_1 = require("./schema");
|
23 | function addDependenciesToPackageJson(options) {
|
24 | return (host, context) => {
|
25 | [
|
26 | {
|
27 | type: dependencies_1.NodeDependencyType.Dev,
|
28 | name: '@angular/compiler-cli',
|
29 | version: latest_versions_1.latestVersions.Angular,
|
30 | },
|
31 | {
|
32 | type: dependencies_1.NodeDependencyType.Dev,
|
33 | name: '@angular-devkit/build-angular',
|
34 | version: latest_versions_1.latestVersions.DevkitBuildAngular,
|
35 | },
|
36 | {
|
37 | type: dependencies_1.NodeDependencyType.Dev,
|
38 | name: 'typescript',
|
39 | version: latest_versions_1.latestVersions.TypeScript,
|
40 | },
|
41 | ].forEach(dependency => dependencies_1.addPackageJsonDependency(host, dependency));
|
42 | if (!options.skipInstall) {
|
43 | context.addTask(new tasks_1.NodePackageInstallTask());
|
44 | }
|
45 | return host;
|
46 | };
|
47 | }
|
48 | function readTsLintConfig(host, path) {
|
49 | const buffer = host.read(path);
|
50 | if (!buffer) {
|
51 | throw new schematics_1.SchematicsException(`Could not read ${path}.`);
|
52 | }
|
53 | const config = core_1.parseJsonAst(buffer.toString(), core_1.JsonParseMode.Loose);
|
54 | if (config.kind !== 'object') {
|
55 | throw new schematics_1.SchematicsException(`Invalid ${path}. Was expecting an object.`);
|
56 | }
|
57 | return config;
|
58 | }
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 | function mergeWithRootTsLint(parentHost) {
|
66 | return (host) => {
|
67 | const tsLintPath = '/tslint.json';
|
68 | if (!host.exists(tsLintPath)) {
|
69 | return;
|
70 | }
|
71 | const rootTslintConfig = readTsLintConfig(parentHost, tsLintPath);
|
72 | const appTslintConfig = readTsLintConfig(host, tsLintPath);
|
73 | const recorder = host.beginUpdate(tsLintPath);
|
74 | rootTslintConfig.properties.forEach(prop => {
|
75 | if (json_utils_1.findPropertyInAstObject(appTslintConfig, prop.key.value)) {
|
76 |
|
77 | return;
|
78 | }
|
79 | json_utils_1.insertPropertyInAstObjectInOrder(recorder, appTslintConfig, prop.key.value, prop.value.value, 2);
|
80 | });
|
81 | const rootRules = json_utils_1.findPropertyInAstObject(rootTslintConfig, 'rules');
|
82 | const appRules = json_utils_1.findPropertyInAstObject(appTslintConfig, 'rules');
|
83 | if (!appRules || appRules.kind !== 'object' || !rootRules || rootRules.kind !== 'object') {
|
84 |
|
85 | return;
|
86 | }
|
87 | rootRules.properties.forEach(prop => {
|
88 | json_utils_1.insertPropertyInAstObjectInOrder(recorder, appRules, prop.key.value, prop.value.value, 4);
|
89 | });
|
90 | host.commitUpdate(recorder);
|
91 |
|
92 | const content = readTsLintConfig(host, tsLintPath);
|
93 | host.overwrite(tsLintPath, JSON.stringify(content.value, undefined, 2));
|
94 | };
|
95 | }
|
96 | function addAppToWorkspaceFile(options, appDir) {
|
97 | let projectRoot = appDir;
|
98 | if (projectRoot) {
|
99 | projectRoot += '/';
|
100 | }
|
101 | const schematics = {};
|
102 | if (options.inlineTemplate
|
103 | || options.inlineStyle
|
104 | || options.minimal
|
105 | || options.style !== schema_1.Style.Css) {
|
106 | const componentSchematicsOptions = {};
|
107 | if (options.inlineTemplate || options.minimal) {
|
108 | componentSchematicsOptions.inlineTemplate = true;
|
109 | }
|
110 | if (options.inlineStyle || options.minimal) {
|
111 | componentSchematicsOptions.inlineStyle = true;
|
112 | }
|
113 | if (options.style && options.style !== schema_1.Style.Css) {
|
114 | componentSchematicsOptions.style = options.style;
|
115 | }
|
116 | schematics['@schematics/angular:component'] = componentSchematicsOptions;
|
117 | }
|
118 | if (options.skipTests || options.minimal) {
|
119 | ['class', 'component', 'directive', 'guard', 'interceptor', 'module', 'pipe', 'service'].forEach((type) => {
|
120 | if (!(`@schematics/angular:${type}` in schematics)) {
|
121 | schematics[`@schematics/angular:${type}`] = {};
|
122 | }
|
123 | schematics[`@schematics/angular:${type}`].skipTests = true;
|
124 | });
|
125 | }
|
126 | if (options.strict) {
|
127 | if (!('@schematics/angular:application' in schematics)) {
|
128 | schematics['@schematics/angular:application'] = {};
|
129 | }
|
130 | schematics['@schematics/angular:application'].strict = true;
|
131 | }
|
132 | const sourceRoot = core_1.join(core_1.normalize(projectRoot), 'src');
|
133 | let budgets = [];
|
134 | if (options.strict) {
|
135 | budgets = [
|
136 | {
|
137 | type: 'initial',
|
138 | maximumWarning: '500kb',
|
139 | maximumError: '1mb',
|
140 | },
|
141 | {
|
142 | type: 'anyComponentStyle',
|
143 | maximumWarning: '2kb',
|
144 | maximumError: '4kb',
|
145 | },
|
146 | ];
|
147 | }
|
148 | else {
|
149 | budgets = [
|
150 | {
|
151 | type: 'initial',
|
152 | maximumWarning: '2mb',
|
153 | maximumError: '5mb',
|
154 | },
|
155 | {
|
156 | type: 'anyComponentStyle',
|
157 | maximumWarning: '6kb',
|
158 | maximumError: '10kb',
|
159 | },
|
160 | ];
|
161 | }
|
162 | const project = {
|
163 | root: core_1.normalize(projectRoot),
|
164 | sourceRoot,
|
165 | projectType: workspace_models_1.ProjectType.Application,
|
166 | prefix: options.prefix || 'app',
|
167 | schematics,
|
168 | targets: {
|
169 | build: {
|
170 | builder: workspace_models_1.Builders.Browser,
|
171 | options: {
|
172 | outputPath: `dist/${options.name}`,
|
173 | index: `${sourceRoot}/index.html`,
|
174 | main: `${sourceRoot}/main.ts`,
|
175 | polyfills: `${sourceRoot}/polyfills.ts`,
|
176 | tsConfig: `${projectRoot}tsconfig.app.json`,
|
177 | aot: true,
|
178 | assets: [
|
179 | `${sourceRoot}/favicon.ico`,
|
180 | `${sourceRoot}/assets`,
|
181 | ],
|
182 | styles: [
|
183 | `${sourceRoot}/styles.${options.style}`,
|
184 | ],
|
185 | scripts: [],
|
186 | },
|
187 | configurations: {
|
188 | production: {
|
189 | fileReplacements: [{
|
190 | replace: `${sourceRoot}/environments/environment.ts`,
|
191 | with: `${sourceRoot}/environments/environment.prod.ts`,
|
192 | }],
|
193 | optimization: true,
|
194 | outputHashing: 'all',
|
195 | sourceMap: false,
|
196 | extractCss: true,
|
197 | namedChunks: false,
|
198 | extractLicenses: true,
|
199 | vendorChunk: false,
|
200 | buildOptimizer: true,
|
201 | budgets,
|
202 | },
|
203 | },
|
204 | },
|
205 | serve: {
|
206 | builder: workspace_models_1.Builders.DevServer,
|
207 | options: {
|
208 | browserTarget: `${options.name}:build`,
|
209 | },
|
210 | configurations: {
|
211 | production: {
|
212 | browserTarget: `${options.name}:build:production`,
|
213 | },
|
214 | },
|
215 | },
|
216 | 'extract-i18n': {
|
217 | builder: workspace_models_1.Builders.ExtractI18n,
|
218 | options: {
|
219 | browserTarget: `${options.name}:build`,
|
220 | },
|
221 | },
|
222 | test: options.minimal ? undefined : {
|
223 | builder: workspace_models_1.Builders.Karma,
|
224 | options: {
|
225 | main: `${sourceRoot}/test.ts`,
|
226 | polyfills: `${sourceRoot}/polyfills.ts`,
|
227 | tsConfig: `${projectRoot}tsconfig.spec.json`,
|
228 | karmaConfig: `${projectRoot}karma.conf.js`,
|
229 | assets: [
|
230 | `${sourceRoot}/favicon.ico`,
|
231 | `${sourceRoot}/assets`,
|
232 | ],
|
233 | styles: [
|
234 | `${sourceRoot}/styles.${options.style}`,
|
235 | ],
|
236 | scripts: [],
|
237 | },
|
238 | },
|
239 | lint: options.minimal ? undefined : {
|
240 | builder: workspace_models_1.Builders.TsLint,
|
241 | options: {
|
242 | tsConfig: [
|
243 | `${projectRoot}tsconfig.app.json`,
|
244 | `${projectRoot}tsconfig.spec.json`,
|
245 | ],
|
246 | exclude: [
|
247 | '**/node_modules/**',
|
248 | ],
|
249 | },
|
250 | },
|
251 | },
|
252 | };
|
253 | return workspace_1.updateWorkspace(workspace => {
|
254 | if (workspace.projects.size === 0) {
|
255 | workspace.extensions.defaultProject = options.name;
|
256 | }
|
257 | workspace.projects.add({
|
258 | name: options.name,
|
259 | ...project,
|
260 | });
|
261 | });
|
262 | }
|
263 | function minimalPathFilter(path) {
|
264 | const toRemoveList = /(test.ts|tsconfig.spec.json|karma.conf.js|tslint.json).template$/;
|
265 | return !toRemoveList.test(path);
|
266 | }
|
267 | function default_1(options) {
|
268 | return async (host) => {
|
269 | if (!options.name) {
|
270 | throw new schematics_1.SchematicsException(`Invalid options, "name" is required.`);
|
271 | }
|
272 | validation_1.validateProjectName(options.name);
|
273 | tsconfig_1.verifyBaseTsConfigExists(host);
|
274 | const appRootSelector = `${options.prefix}-root`;
|
275 | const componentOptions = !options.minimal ?
|
276 | {
|
277 | inlineStyle: options.inlineStyle,
|
278 | inlineTemplate: options.inlineTemplate,
|
279 | skipTests: options.skipTests,
|
280 | style: options.style,
|
281 | viewEncapsulation: options.viewEncapsulation,
|
282 | } :
|
283 | {
|
284 | inlineStyle: true,
|
285 | inlineTemplate: true,
|
286 | skipTests: true,
|
287 | style: options.style,
|
288 | };
|
289 | const workspace = await workspace_1.getWorkspace(host);
|
290 | const newProjectRoot = workspace.extensions.newProjectRoot || '';
|
291 | const isRootApp = options.projectRoot !== undefined;
|
292 | const appDir = isRootApp
|
293 | ? core_1.normalize(options.projectRoot || '')
|
294 | : core_1.join(core_1.normalize(newProjectRoot), options.name);
|
295 | const sourceDir = `${appDir}/src/app`;
|
296 | const e2eOptions = {
|
297 | relatedAppName: options.name,
|
298 | rootSelector: appRootSelector,
|
299 | };
|
300 | return schematics_1.chain([
|
301 | addAppToWorkspaceFile(options, appDir),
|
302 | schematics_1.mergeWith(schematics_1.apply(schematics_1.url('./files'), [
|
303 | options.minimal ? schematics_1.filter(minimalPathFilter) : schematics_1.noop(),
|
304 | schematics_1.applyTemplates({
|
305 | utils: core_1.strings,
|
306 | ...options,
|
307 | relativePathToWorkspaceRoot: paths_1.relativePathToWorkspaceRoot(appDir),
|
308 | appName: options.name,
|
309 | isRootApp,
|
310 | }),
|
311 | isRootApp ? mergeWithRootTsLint(host) : schematics_1.noop(),
|
312 | schematics_1.move(appDir),
|
313 | ]), schematics_1.MergeStrategy.Overwrite),
|
314 | schematics_1.schematic('module', {
|
315 | name: 'app',
|
316 | commonModule: false,
|
317 | flat: true,
|
318 | routing: options.routing,
|
319 | routingScope: 'Root',
|
320 | path: sourceDir,
|
321 | project: options.name,
|
322 | }),
|
323 | schematics_1.schematic('component', {
|
324 | name: 'app',
|
325 | selector: appRootSelector,
|
326 | flat: true,
|
327 | path: sourceDir,
|
328 | skipImport: true,
|
329 | project: options.name,
|
330 | ...componentOptions,
|
331 | }),
|
332 | schematics_1.mergeWith(schematics_1.apply(schematics_1.url('./other-files'), [
|
333 | options.strict
|
334 | ? schematics_1.noop()
|
335 | : schematics_1.filter(path => path !== '/package.json.template'),
|
336 | componentOptions.inlineTemplate
|
337 | ? schematics_1.filter(path => !path.endsWith('.html.template'))
|
338 | : schematics_1.noop(),
|
339 | componentOptions.skipTests
|
340 | ? schematics_1.filter(path => !path.endsWith('.spec.ts.template'))
|
341 | : schematics_1.noop(),
|
342 | schematics_1.applyTemplates({
|
343 | utils: core_1.strings,
|
344 | ...options,
|
345 | selector: appRootSelector,
|
346 | ...componentOptions,
|
347 | }),
|
348 | schematics_1.move(sourceDir),
|
349 | ]), schematics_1.MergeStrategy.Overwrite),
|
350 | tsconfig_1.addTsConfigProjectReferences([
|
351 | core_1.join(appDir, 'tsconfig.app.json'),
|
352 | core_1.join(appDir, 'tsconfig.spec.json'),
|
353 | ]),
|
354 | options.minimal ? schematics_1.noop() : schematics_1.schematic('e2e', e2eOptions),
|
355 | options.skipPackageJson ? schematics_1.noop() : addDependenciesToPackageJson(options),
|
356 | options.lintFix ? lint_fix_1.applyLintFix(appDir) : schematics_1.noop(),
|
357 | ]);
|
358 | };
|
359 | }
|
360 | exports.default = default_1;
|