Skip to content

Commit 38fda3e

Browse files
committed
fix(@schematics/angular): support updating projects that use the targets property
1 parent 3071608 commit 38fda3e

File tree

7 files changed

+76
-64
lines changed

7 files changed

+76
-64
lines changed

packages/schematics/angular/app-shell/index.ts

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
import { JsonObject, dirname, join, normalize } from '@angular-devkit/core';
8+
import { JsonObject, dirname, experimental, join, normalize } from '@angular-devkit/core';
99
import {
1010
Rule,
1111
SchematicContext,
@@ -15,10 +15,6 @@ import {
1515
schematic,
1616
} from '@angular-devkit/schematics';
1717
import * as ts from 'typescript';
18-
import {
19-
WorkspaceProject,
20-
WorkspaceTool,
21-
} from '../../../angular_devkit/core/src/workspace/workspace-schema';
2218
import { Schema as ComponentOptions } from '../component/schema';
2319
import {
2420
addImportToModule,
@@ -32,6 +28,7 @@ import {
3228
import { InsertChange } from '../utility/change';
3329
import { getWorkspace, getWorkspacePath } from '../utility/config';
3430
import { getAppModulePath } from '../utility/ng-ast-utils';
31+
import { getProjectTargets } from '../utility/project-targets';
3532
import { Schema as AppShellOptions } from './schema';
3633

3734

@@ -54,7 +51,9 @@ function getSourceFile(host: Tree, path: string): ts.SourceFile {
5451
}
5552

5653
function getServerModulePath(
57-
host: Tree, project: WorkspaceProject, architect: WorkspaceTool,
54+
host: Tree,
55+
project: experimental.workspace.WorkspaceProject,
56+
architect: experimental.workspace.WorkspaceTool,
5857
): string | null {
5958
const mainPath = architect.server.options.main;
6059
const mainSource = getSourceFile(host, mainPath);
@@ -102,11 +101,12 @@ function getComponentTemplate(host: Tree, compPath: string, tmplInfo: TemplateIn
102101
return template;
103102
}
104103

105-
function getBootstrapComponentPath(host: Tree, project: WorkspaceProject): string {
106-
if (!project.architect) {
107-
throw new Error('Project architect not found.');
108-
}
109-
const mainPath = project.architect.build.options.main;
104+
function getBootstrapComponentPath(
105+
host: Tree,
106+
project: experimental.workspace.WorkspaceProject,
107+
): string {
108+
const projectTargets = getProjectTargets(project);
109+
const mainPath = projectTargets.build.options.main;
110110
const modulePath = getAppModulePath(host, mainPath);
111111
const moduleSource = getSourceFile(host, modulePath);
112112

@@ -202,10 +202,8 @@ function addAppShellConfigToWorkspace(options: AppShellOptions): Rule {
202202
throw new SchematicsException(`Client app ${options.clientProject} not found.`);
203203
}
204204
const clientProject = workspace.projects[options.clientProject];
205-
if (!clientProject.architect) {
206-
throw new Error('Client project architect not found.');
207-
}
208-
clientProject.architect['app-shell'] = appShellTarget;
205+
const projectTargets = getProjectTargets(clientProject);
206+
projectTargets['app-shell'] = appShellTarget;
209207

210208
host.overwrite(workspacePath, JSON.stringify(workspace, null, 2));
211209

@@ -317,7 +315,9 @@ function addShellComponent(options: AppShellOptions): Rule {
317315
return schematic('component', componentOptions);
318316
}
319317

320-
function getClientProject(host: Tree, options: AppShellOptions): WorkspaceProject {
318+
function getClientProject(
319+
host: Tree, options: AppShellOptions,
320+
): experimental.workspace.WorkspaceProject {
321321
const workspace = getWorkspace(host);
322322
const clientProject = workspace.projects[options.clientProject];
323323
if (!clientProject) {
@@ -327,14 +327,13 @@ function getClientProject(host: Tree, options: AppShellOptions): WorkspaceProjec
327327
return clientProject;
328328
}
329329

330-
function getClientArchitect(host: Tree, options: AppShellOptions): WorkspaceTool {
331-
const clientArchitect = getClientProject(host, options).architect;
332-
333-
if (!clientArchitect) {
334-
throw new Error('Client project architect not found.');
335-
}
330+
function getClientArchitect(
331+
host: Tree, options: AppShellOptions,
332+
): experimental.workspace.WorkspaceTool {
333+
const clientProject = getClientProject(host, options);
334+
const projectTargets = getProjectTargets(clientProject);
336335

337-
return clientArchitect;
336+
return projectTargets;
338337
}
339338

340339
export default function (options: AppShellOptions): Rule {

packages/schematics/angular/app-shell/index_spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ describe('App Shell Schematic', () => {
6565
const filePath = '/angular.json';
6666
const content = tree.readContent(filePath);
6767
const workspace = JSON.parse(content);
68-
const target = workspace.projects.bar.architect['app-shell'];
68+
const target = workspace.projects.bar.targets['app-shell'];
6969
expect(target.options.browserTarget).toEqual('bar:build');
7070
expect(target.options.serverTarget).toEqual('bar:server');
7171
expect(target.options.route).toEqual('shell');

packages/schematics/angular/service-worker/index.ts

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
} from '../utility/config';
2929
import { addPackageJsonDependency, getPackageJsonDependency } from '../utility/dependencies';
3030
import { getAppModulePath } from '../utility/ng-ast-utils';
31+
import { getProjectTargets } from '../utility/project-targets';
3132
import { Schema as ServiceWorkerOptions } from './schema';
3233

3334
function updateConfigFile(options: ServiceWorkerOptions): Rule {
@@ -43,20 +44,18 @@ function updateConfigFile(options: ServiceWorkerOptions): Rule {
4344
throw new Error(`Project is not defined in this workspace.`);
4445
}
4546

46-
if (!project.architect) {
47-
throw new Error(`Architect is not defined for this project.`);
48-
}
47+
const projectTargets = getProjectTargets(project);
4948

50-
if (!project.architect[options.target]) {
49+
if (!projectTargets[options.target]) {
5150
throw new Error(`Target is not defined for this project.`);
5251
}
5352

54-
let applyTo = project.architect[options.target].options;
53+
let applyTo = projectTargets[options.target].options;
5554

5655
if (options.configuration &&
57-
project.architect[options.target].configurations &&
58-
project.architect[options.target].configurations[options.configuration]) {
59-
applyTo = project.architect[options.target].configurations[options.configuration];
56+
projectTargets[options.target].configurations &&
57+
projectTargets[options.target].configurations[options.configuration]) {
58+
applyTo = projectTargets[options.target].configurations[options.configuration];
6059
}
6160

6261
applyTo.serviceWorker = true;
@@ -92,10 +91,8 @@ function updateAppModule(options: ServiceWorkerOptions): Rule {
9291
// find app module
9392
const workspace = getWorkspace(host);
9493
const project = workspace.projects[options.project as string];
95-
if (!project.architect) {
96-
throw new Error('Project architect not found.');
97-
}
98-
const mainPath = project.architect.build.options.main;
94+
const projectTargets = getProjectTargets(project);
95+
const mainPath = projectTargets.build.options.main;
9996
const modulePath = getAppModulePath(host, mainPath);
10097
context.logger.debug(`module path: ${modulePath}`);
10198

packages/schematics/angular/service-worker/index_spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ describe('Service Worker Schematic', () => {
5050
const tree = schematicRunner.runSchematic('service-worker', defaultOptions, appTree);
5151
const configText = tree.readContent('/angular.json');
5252
const config = JSON.parse(configText);
53-
const swFlag = config.projects.bar.architect.build.configurations.production.serviceWorker;
53+
const swFlag = config.projects.bar.targets.build.configurations.production.serviceWorker;
5454
expect(swFlag).toEqual(true);
5555
});
5656

@@ -59,7 +59,7 @@ describe('Service Worker Schematic', () => {
5959
const tree = schematicRunner.runSchematic('service-worker', options, appTree);
6060
const configText = tree.readContent('/angular.json');
6161
const config = JSON.parse(configText);
62-
const swFlag = config.projects.bar.architect.build.options.serviceWorker;
62+
const swFlag = config.projects.bar.targets.build.options.serviceWorker;
6363
expect(swFlag).toEqual(true);
6464
});
6565

packages/schematics/angular/universal/index.ts

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import { InsertChange } from '../utility/change';
3636
import { getWorkspace } from '../utility/config';
3737
import { addPackageJsonDependency, getPackageJsonDependency } from '../utility/dependencies';
3838
import { findBootstrapModuleCall, findBootstrapModulePath } from '../utility/ng-ast-utils';
39+
import { getProjectTargets } from '../utility/project-targets';
3940
import { Schema as UniversalOptions } from './schema';
4041

4142

@@ -57,17 +58,14 @@ function getClientProject(
5758
return clientProject;
5859
}
5960

60-
function getClientArchitect(
61+
function getClientTargets(
6162
host: Tree,
6263
options: UniversalOptions,
6364
): experimental.workspace.WorkspaceTool {
64-
const clientArchitect = getClientProject(host, options).architect;
65+
const clientProject = getClientProject(host, options);
66+
const projectTargets = getProjectTargets(clientProject);
6567

66-
if (!clientArchitect) {
67-
throw new Error('Client project architect not found.');
68-
}
69-
70-
return clientArchitect;
68+
return projectTargets;
7169
}
7270

7371
function updateConfigFile(options: UniversalOptions, tsConfigDirectory: Path): Rule {
@@ -78,9 +76,7 @@ function updateConfigFile(options: UniversalOptions, tsConfigDirectory: Path): R
7876
}
7977

8078
const clientProject = workspace.projects[options.clientProject];
81-
if (!clientProject.architect) {
82-
throw new Error('Client project architect not found.');
83-
}
79+
const projectTargets = getProjectTargets(clientProject);
8480

8581
const builderOptions: JsonObject = {
8682
outputPath: `dist/${options.clientProject}-server`,
@@ -91,7 +87,7 @@ function updateConfigFile(options: UniversalOptions, tsConfigDirectory: Path): R
9187
builder: '@angular-devkit/build-angular:server',
9288
options: builderOptions,
9389
};
94-
clientProject.architect.server = serverTarget;
90+
projectTargets.server = serverTarget;
9591

9692
const workspacePath = getWorkspacePath(host);
9793

@@ -122,8 +118,8 @@ function findBrowserModuleImport(host: Tree, modulePath: string): ts.Node {
122118

123119
function wrapBootstrapCall(options: UniversalOptions): Rule {
124120
return (host: Tree) => {
125-
const clientArchitect = getClientArchitect(host, options);
126-
const mainPath = normalize('/' + clientArchitect.build.options.main);
121+
const clientTargets = getClientTargets(host, options);
122+
const mainPath = normalize('/' + clientTargets.build.options.main);
127123
let bootstrapCall: ts.Node | null = findBootstrapModuleCall(host, mainPath);
128124
if (bootstrapCall === null) {
129125
throw new SchematicsException('Bootstrap module not found.');
@@ -151,8 +147,8 @@ function wrapBootstrapCall(options: UniversalOptions): Rule {
151147
function addServerTransition(options: UniversalOptions): Rule {
152148
return (host: Tree) => {
153149
const clientProject = getClientProject(host, options);
154-
const clientArchitect = getClientArchitect(host, options);
155-
const mainPath = normalize('/' + clientArchitect.build.options.main);
150+
const clientTargets = getClientTargets(host, options);
151+
const mainPath = normalize('/' + clientTargets.build.options.main);
156152

157153
const bootstrapModuleRelativePath = findBootstrapModulePath(host, mainPath);
158154
const bootstrapModulePath = normalize(
@@ -187,8 +183,8 @@ function addDependencies(): Rule {
187183
};
188184
}
189185

190-
function getTsConfigOutDir(host: Tree, architect: experimental.workspace.WorkspaceTool): string {
191-
const tsConfigPath = architect.build.options.tsConfig;
186+
function getTsConfigOutDir(host: Tree, targets: experimental.workspace.WorkspaceTool): string {
187+
const tsConfigPath = targets.build.options.tsConfig;
192188
const tsConfigBuffer = host.read(tsConfigPath);
193189
if (!tsConfigBuffer) {
194190
throw new SchematicsException(`Could not read ${tsConfigPath}`);
@@ -211,9 +207,9 @@ export default function (options: UniversalOptions): Rule {
211207
if (clientProject.projectType !== 'application') {
212208
throw new SchematicsException(`Universal requires a project type of "application".`);
213209
}
214-
const clientArchitect = getClientArchitect(host, options);
215-
const outDir = getTsConfigOutDir(host, clientArchitect);
216-
const tsConfigExtends = basename(clientArchitect.build.options.tsConfig);
210+
const clientTargets = getClientTargets(host, options);
211+
const outDir = getTsConfigOutDir(host, clientTargets);
212+
const tsConfigExtends = basename(clientTargets.build.options.tsConfig);
217213
const rootInSrc = clientProject.root === '';
218214
const tsConfigDirectory = join(normalize(clientProject.root), rootInSrc ? 'src' : '');
219215

packages/schematics/angular/universal/index_spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ describe('Universal Schematic', () => {
8888
},
8989
});
9090
const angularConfig = JSON.parse(tree.readContent('angular.json'));
91-
expect(angularConfig.projects.workspace.architect.server.options.tsConfig)
91+
expect(angularConfig.projects.workspace.targets.server.options.tsConfig)
9292
.toEqual('src/tsconfig.server.json');
9393
});
9494

@@ -108,7 +108,7 @@ describe('Universal Schematic', () => {
108108
},
109109
});
110110
const angularConfig = JSON.parse(tree.readContent('angular.json'));
111-
expect(angularConfig.projects.bar.architect.server.options.tsConfig)
111+
expect(angularConfig.projects.bar.targets.server.options.tsConfig)
112112
.toEqual('projects/bar/tsconfig.server.json');
113113
});
114114

@@ -124,10 +124,10 @@ describe('Universal Schematic', () => {
124124
const filePath = '/angular.json';
125125
const contents = tree.readContent(filePath);
126126
const config = JSON.parse(contents.toString());
127-
const arch = config.projects.bar.architect;
128-
expect(arch.server).toBeDefined();
129-
expect(arch.server.builder).toBeDefined();
130-
const opts = arch.server.options;
127+
const targets = config.projects.bar.targets;
128+
expect(targets.server).toBeDefined();
129+
expect(targets.server.builder).toBeDefined();
130+
const opts = targets.server.options;
131131
expect(opts.outputPath).toEqual('dist/bar-server');
132132
expect(opts.main).toEqual('projects/bar/src/main.server.ts');
133133
expect(opts.tsConfig).toEqual('projects/bar/tsconfig.server.json');
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. 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 { experimental } from '@angular-devkit/core';
10+
11+
export function getProjectTargets(
12+
project: experimental.workspace.WorkspaceProject,
13+
): experimental.workspace.WorkspaceTool {
14+
const projectTargets = project.targets || project.architect;
15+
if (!projectTargets) {
16+
throw new Error('Project architect not found.');
17+
}
18+
19+
return projectTargets;
20+
}

0 commit comments

Comments
 (0)