Skip to content

Commit 714c205

Browse files
devversionjelbourn
authored andcommitted
feat(schematics): compatibility with Angular CLI 6.2.0 (#13078)
* Upgrades the devkit dependencies to the latest versions. * Adds support for the newly introduced and published `project.targets` instead of `project.architect` (see: angular/angular-cli@3071608) * Compatibility behavior for a published but non-announced breaking change within the schematic context (see: https://github.com/angular/angular-cli/commit/9720077a4b5ae628ddfaf5f1a26bac3b04bdf637#diff-e73df838d6700d187eff76a50c7e1c53R233`) * Supports the new `project.targets` schema within the update schematics (in order to properly determine `tsconfig` files) * Due to the fact that the @angular-devkit/schematics now handles Bazel better, the template files will be resolved through NodeJS. This means that the template files need to be referenced in the @//:node_modules label. Fixes #11438
1 parent 6b2f008 commit 714c205

15 files changed

+163
-149
lines changed

BUILD.bazel

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ filegroup(
3838
"*.d.ts",
3939
]] + [
4040
"node_modules/http-server/**",
41+
# Reference all files of the "@schematics/angular" package because the schematic
42+
# tests depend on the template files of the angular schematics.
43+
"node_modules/@schematics/angular/**",
4144
]),
4245
)
4346

package-lock.json

Lines changed: 16 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@
4444
"zone.js": "^0.8.26"
4545
},
4646
"devDependencies": {
47-
"@angular-devkit/core": "0.7.4",
48-
"@angular-devkit/schematics": "0.7.4",
47+
"@angular-devkit/core": "^0.9.0-beta.2",
48+
"@angular-devkit/schematics": "^0.9.0-beta.2",
4949
"@angular/bazel": "7.0.0-beta.4",
5050
"@angular/compiler-cli": "7.0.0-beta.4",
5151
"@angular/http": "7.0.0-beta.4",
@@ -56,7 +56,7 @@
5656
"@bazel/ibazel": "0.3.1",
5757
"@google-cloud/storage": "^1.1.1",
5858
"@octokit/rest": "^15.9.4",
59-
"@schematics/angular": "0.7.4",
59+
"@schematics/angular": "^0.9.0-beta.2",
6060
"@types/chalk": "^0.4.31",
6161
"@types/fs-extra": "^4.0.3",
6262
"@types/glob": "^5.0.33",

src/lib/schematics/install/fonts/project-index-html.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88

99
import {SchematicsException} from '@angular-devkit/schematics';
1010
import {WorkspaceProject} from '@schematics/angular/utility/config';
11-
import {getArchitectOptions} from '../../utils/architect-options';
11+
import {getProjectTargetOptions} from '../../utils/project-targets';
1212

1313
/** Looks for the index HTML file in the given project and returns its path. */
1414
export function getIndexHtmlPath(project: WorkspaceProject): string {
15-
const buildOptions = getArchitectOptions(project, 'build');
15+
const buildOptions = getProjectTargetOptions(project, 'build');
1616

1717
if (!buildOptions.index) {
1818
throw new SchematicsException('No project "index.html" file could be found.');

src/lib/schematics/install/index.spec.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {Tree} from '@angular-devkit/schematics';
22
import {SchematicTestRunner} from '@angular-devkit/schematics/testing';
3+
import {getProjectTargetOptions} from '@angular/material/schematics/utils/project-targets';
34
import {getProjectStyleFile} from '../utils/project-style-file';
45
import {getIndexHtmlPath} from './fonts/project-index-html';
56
import {getProjectFromWorkspace} from '../utils/get-project';
@@ -19,11 +20,7 @@ describe('material-install-schematic', () => {
1920

2021
/** Expects the given file to be in the styles of the specified workspace project. */
2122
function expectProjectStyleFile(project: WorkspaceProject, filePath: string) {
22-
const architect = project.architect!;
23-
24-
expect(architect!['build']).toBeTruthy();
25-
expect(architect!['build']['options']).toBeTruthy();
26-
expect(architect!['build']['options']['styles']).toContain(filePath,
23+
expect(getProjectTargetOptions(project, 'build').styles).toContain(filePath,
2724
`Expected "${filePath}" to be added to the project styles in the workspace.`);
2825
}
2926

src/lib/schematics/install/theming/theming.ts

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {getWorkspace, WorkspaceProject, WorkspaceSchema} from '@schematics/angul
1313
import {join} from 'path';
1414
import {getProjectFromWorkspace} from '../../utils/get-project';
1515
import {getProjectStyleFile} from '../../utils/project-style-file';
16+
import {getProjectTargetOptions} from '../../utils/project-targets';
1617
import {Schema} from '../schema';
1718
import {createCustomTheme} from './custom-theme';
1819

@@ -60,9 +61,7 @@ function insertCustomTheme(project: WorkspaceProject, projectName: string, host:
6061

6162
host.create(customThemePath, themeContent);
6263

63-
// Architect is always defined because we initially asserted if the default builder
64-
// configuration is set up or not.
65-
return addStyleToTarget(project.architect!['build'], host, customThemePath, workspace);
64+
return addStyleToTarget(project, 'build', host, customThemePath, workspace);
6665
}
6766

6867
const insertion = new InsertChange(stylesPath, 0, themeContent);
@@ -79,27 +78,24 @@ function insertPrebuiltTheme(project: WorkspaceProject, host: Tree, theme: strin
7978
// Path needs to be always relative to the `package.json` or workspace root.
8079
const themePath = `./node_modules/@angular/material/prebuilt-themes/${theme}.css`;
8180

82-
// Architect is always defined because we initially asserted if the default builder
83-
// configuration is set up or not.
84-
addStyleToTarget(project.architect!['build'], host, themePath, workspace);
85-
addStyleToTarget(project.architect!['test'], host, themePath, workspace);
81+
addStyleToTarget(project, 'build', host, themePath, workspace);
82+
addStyleToTarget(project, 'test', host, themePath, workspace);
8683
}
8784

88-
/** Adds a style entry to the given target. */
89-
function addStyleToTarget(target: any, host: Tree, asset: string, workspace: WorkspaceSchema) {
90-
// We can't assume that any of these properties are defined, so safely add them as we go
91-
// if necessary.
92-
if (!target.options) {
93-
target.options = {styles: [asset]};
94-
} else if (!target.options.styles) {
95-
target.options.styles = [asset];
85+
/** Adds a style entry to the given project target. */
86+
function addStyleToTarget(project: WorkspaceProject, targetName: string, host: Tree,
87+
assetPath: string, workspace: WorkspaceSchema) {
88+
const targetOptions = getProjectTargetOptions(project, targetName);
89+
90+
if (!targetOptions.styles) {
91+
targetOptions.styles = [assetPath];
9692
} else {
97-
const existingStyles = target.options.styles.map(s => typeof s === 'string' ? s : s.input);
98-
const hasGivenTheme = existingStyles.find(s => s.includes(asset));
93+
const existingStyles = targetOptions.styles.map(s => typeof s === 'string' ? s : s.input);
94+
const hasGivenTheme = existingStyles.find(s => s.includes(assetPath));
9995
const hasOtherTheme = existingStyles.find(s => s.includes('material/prebuilt'));
10096

10197
if (!hasGivenTheme && !hasOtherTheme) {
102-
target.options.styles.unshift(asset);
98+
targetOptions.styles.unshift(assetPath);
10399
}
104100
}
105101

@@ -108,18 +104,23 @@ function addStyleToTarget(target: any, host: Tree, asset: string, workspace: Wor
108104

109105
/** Throws if the project is not using the default Angular devkit builders. */
110106
function assertDefaultBuildersConfigured(project: WorkspaceProject) {
111-
const defaultBuilder = '@angular-devkit/build-angular:browser';
112-
const defaultTestBuilder = '@angular-devkit/build-angular:karma';
107+
checkProjectTargetBuilder(project, 'build', '@angular-devkit/build-angular:browser');
108+
checkProjectTargetBuilder(project, 'test', '@angular-devkit/build-angular:karma');
109+
}
110+
111+
/**
112+
* Checks if the specified project target is configured with the default builders which are
113+
* provided by the Angular CLI.
114+
*/
115+
function checkProjectTargetBuilder(project: WorkspaceProject, targetName: string,
116+
defaultBuilder: string) {
113117

114-
const hasDefaultBuilders = project.architect &&
115-
project.architect['build'] &&
116-
project.architect['build']['builder'] === defaultBuilder &&
117-
project.architect['test'] &&
118-
project.architect['test']['builder'] === defaultTestBuilder;
118+
const targetConfig = project.architect && project.architect[targetName] ||
119+
project.targets && project.targets[targetName];
119120

120-
if (!hasDefaultBuilders) {
121+
if (!targetConfig || targetConfig['builder'] !== defaultBuilder) {
121122
throw new SchematicsException(
122-
'Your project is not using the default builders for build and test. The Angular Material ' +
123+
`Your project is not using the default builders for "${targetName}". The Angular Material ` +
123124
'schematics can only be used if the original builders from the Angular CLI are configured.');
124125
}
125126
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Tree} from '@angular-devkit/schematics';
10+
import {getWorkspace} from '@schematics/angular/utility/config';
11+
12+
/**
13+
* Gets all tsconfig paths from a CLI project by reading the workspace configuration
14+
* and looking for common tsconfig locations.
15+
*/
16+
export function getProjectTsConfigPaths(tree: Tree): string[] {
17+
// Start with some tsconfig paths that are generally used within CLI projects.
18+
const tsconfigPaths = new Set<string>([
19+
'./tsconfig.json',
20+
'./src/tsconfig.json',
21+
'./src/tsconfig.app.json',
22+
]);
23+
24+
// Add any tsconfig directly referenced in a build or test task of the angular.json workspace.
25+
const workspace = getWorkspace(tree);
26+
27+
for (const project of Object.values(workspace.projects)) {
28+
['build', 'test'].forEach(targetName => {
29+
if (project.targets &&
30+
project.targets[targetName] &&
31+
project.targets[targetName].options &&
32+
project.targets[targetName].options.tsConfig) {
33+
tsconfigPaths.add(project.targets[targetName].options.tsConfig);
34+
}
35+
36+
if (project.architect &&
37+
project.architect[targetName] &&
38+
project.architect[targetName].options &&
39+
project.architect[targetName].options.tsConfig) {
40+
tsconfigPaths.add(project.architect[targetName].options.tsConfig);
41+
}
42+
});
43+
}
44+
45+
// Filter out tsconfig files that don't exist in the CLI project.
46+
return Array.from(tsconfigPaths).filter(p => tree.exists(p));
47+
}

src/lib/schematics/update/update.ts

Lines changed: 4 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,25 @@
88

99
import {Rule, SchematicContext, TaskId, Tree} from '@angular-devkit/schematics';
1010
import {RunSchematicTask, TslintFixTask} from '@angular-devkit/schematics/tasks';
11-
import {getWorkspace} from '@schematics/angular/utility/config';
1211
import {TargetVersion} from './index';
12+
import {getProjectTsConfigPaths} from './project-tsconfig-paths';
1313
import {createTslintConfig} from './tslint-update';
1414

1515
/** Entry point for `ng update` from Angular CLI. */
1616
export function createUpdateRule(targetVersion: TargetVersion): Rule {
1717
return (tree: Tree, context: SchematicContext) => {
1818

19-
const allTsConfigPaths = getTsConfigPaths(tree);
19+
const projectTsConfigPaths = getProjectTsConfigPaths(tree);
2020
const tslintFixTasks: TaskId[] = [];
2121

22-
if (!allTsConfigPaths.length) {
22+
if (!projectTsConfigPaths.length) {
2323
throw new Error('Could not find any tsconfig file. Please submit an issue on the Angular ' +
2424
'Material repository that includes the name of your TypeScript configuration.');
2525
}
2626

2727
const tslintConfig = createTslintConfig(targetVersion);
2828

29-
for (const tsconfig of allTsConfigPaths) {
29+
for (const tsconfig of projectTsConfigPaths) {
3030
// Run the update tslint rules.
3131
tslintFixTasks.push(context.addTask(new TslintFixTask(tslintConfig, {
3232
silent: false,
@@ -39,40 +39,3 @@ export function createUpdateRule(targetVersion: TargetVersion): Rule {
3939
context.addTask(new RunSchematicTask('ng-post-update', {}), tslintFixTasks);
4040
};
4141
}
42-
43-
/**
44-
* Gets all tsconfig paths from a CLI project by reading the workspace configuration
45-
* and looking for common tsconfig locations.
46-
*/
47-
function getTsConfigPaths(tree: Tree): string[] {
48-
// Start with some tsconfig paths that are generally used.
49-
const tsconfigPaths = [
50-
'./tsconfig.json',
51-
'./src/tsconfig.json',
52-
'./src/tsconfig.app.json',
53-
];
54-
55-
// Add any tsconfig directly referenced in a build or test task of the angular.json workspace.
56-
const workspace = getWorkspace(tree);
57-
58-
for (const project of Object.values(workspace.projects)) {
59-
if (project && project.architect) {
60-
for (const taskName of ['build', 'test']) {
61-
const task = project.architect[taskName];
62-
if (task && task.options && task.options.tsConfig) {
63-
const tsConfigOption = task.options.tsConfig;
64-
if (typeof tsConfigOption === 'string') {
65-
tsconfigPaths.push(tsConfigOption);
66-
} else if (Array.isArray(tsConfigOption)) {
67-
tsconfigPaths.push(...tsConfigOption);
68-
}
69-
}
70-
}
71-
}
72-
}
73-
74-
// Filter out tsconfig files that don't exist and remove any duplicates.
75-
return tsconfigPaths
76-
.filter(p => tree.exists(p))
77-
.filter((value, index, self) => self.indexOf(value) === index);
78-
}

src/lib/schematics/utils/architect-options.ts

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/lib/schematics/utils/ast.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,7 @@ export function addModuleImportToModule(host: Tree, modulePath: string, moduleNa
4949
throw new SchematicsException(`Module not found: ${modulePath}`);
5050
}
5151

52-
// TODO(devversion): Cast to any because the Bazel typescript rules seem to incorrectly resolve
53-
// the the required TypeScript version for the @schematics/angular utility functions. Meaning
54-
// that is a type signature mismatch at compilation which is not valid.
55-
const changes = addImportToModule(moduleSource as any, modulePath, moduleName, src);
52+
const changes = addImportToModule(moduleSource, modulePath, moduleName, src);
5653
const recorder = host.beginUpdate(modulePath);
5754

5855
changes.forEach((change) => {

0 commit comments

Comments
 (0)