fix(@schematics/angular): support updating projects that use the targets property

This commit is contained in:
Filipe Silva 2018-07-25 19:13:48 +01:00
parent 307160806c
commit 38fda3ea60
7 changed files with 76 additions and 64 deletions

View File

@ -5,7 +5,7 @@
* 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 { JsonObject, dirname, join, normalize } from '@angular-devkit/core';
import { JsonObject, dirname, experimental, join, normalize } from '@angular-devkit/core';
import {
Rule,
SchematicContext,
@ -15,10 +15,6 @@ import {
schematic,
} from '@angular-devkit/schematics';
import * as ts from 'typescript';
import {
WorkspaceProject,
WorkspaceTool,
} from '../../../angular_devkit/core/src/workspace/workspace-schema';
import { Schema as ComponentOptions } from '../component/schema';
import {
addImportToModule,
@ -32,6 +28,7 @@ import {
import { InsertChange } from '../utility/change';
import { getWorkspace, getWorkspacePath } from '../utility/config';
import { getAppModulePath } from '../utility/ng-ast-utils';
import { getProjectTargets } from '../utility/project-targets';
import { Schema as AppShellOptions } from './schema';
@ -54,7 +51,9 @@ function getSourceFile(host: Tree, path: string): ts.SourceFile {
}
function getServerModulePath(
host: Tree, project: WorkspaceProject, architect: WorkspaceTool,
host: Tree,
project: experimental.workspace.WorkspaceProject,
architect: experimental.workspace.WorkspaceTool,
): string | null {
const mainPath = architect.server.options.main;
const mainSource = getSourceFile(host, mainPath);
@ -102,11 +101,12 @@ function getComponentTemplate(host: Tree, compPath: string, tmplInfo: TemplateIn
return template;
}
function getBootstrapComponentPath(host: Tree, project: WorkspaceProject): string {
if (!project.architect) {
throw new Error('Project architect not found.');
}
const mainPath = project.architect.build.options.main;
function getBootstrapComponentPath(
host: Tree,
project: experimental.workspace.WorkspaceProject,
): string {
const projectTargets = getProjectTargets(project);
const mainPath = projectTargets.build.options.main;
const modulePath = getAppModulePath(host, mainPath);
const moduleSource = getSourceFile(host, modulePath);
@ -202,10 +202,8 @@ function addAppShellConfigToWorkspace(options: AppShellOptions): Rule {
throw new SchematicsException(`Client app ${options.clientProject} not found.`);
}
const clientProject = workspace.projects[options.clientProject];
if (!clientProject.architect) {
throw new Error('Client project architect not found.');
}
clientProject.architect['app-shell'] = appShellTarget;
const projectTargets = getProjectTargets(clientProject);
projectTargets['app-shell'] = appShellTarget;
host.overwrite(workspacePath, JSON.stringify(workspace, null, 2));
@ -317,7 +315,9 @@ function addShellComponent(options: AppShellOptions): Rule {
return schematic('component', componentOptions);
}
function getClientProject(host: Tree, options: AppShellOptions): WorkspaceProject {
function getClientProject(
host: Tree, options: AppShellOptions,
): experimental.workspace.WorkspaceProject {
const workspace = getWorkspace(host);
const clientProject = workspace.projects[options.clientProject];
if (!clientProject) {
@ -327,14 +327,13 @@ function getClientProject(host: Tree, options: AppShellOptions): WorkspaceProjec
return clientProject;
}
function getClientArchitect(host: Tree, options: AppShellOptions): WorkspaceTool {
const clientArchitect = getClientProject(host, options).architect;
function getClientArchitect(
host: Tree, options: AppShellOptions,
): experimental.workspace.WorkspaceTool {
const clientProject = getClientProject(host, options);
const projectTargets = getProjectTargets(clientProject);
if (!clientArchitect) {
throw new Error('Client project architect not found.');
}
return clientArchitect;
return projectTargets;
}
export default function (options: AppShellOptions): Rule {

View File

@ -65,7 +65,7 @@ describe('App Shell Schematic', () => {
const filePath = '/angular.json';
const content = tree.readContent(filePath);
const workspace = JSON.parse(content);
const target = workspace.projects.bar.architect['app-shell'];
const target = workspace.projects.bar.targets['app-shell'];
expect(target.options.browserTarget).toEqual('bar:build');
expect(target.options.serverTarget).toEqual('bar:server');
expect(target.options.route).toEqual('shell');

View File

@ -28,6 +28,7 @@ import {
} from '../utility/config';
import { addPackageJsonDependency, getPackageJsonDependency } from '../utility/dependencies';
import { getAppModulePath } from '../utility/ng-ast-utils';
import { getProjectTargets } from '../utility/project-targets';
import { Schema as ServiceWorkerOptions } from './schema';
function updateConfigFile(options: ServiceWorkerOptions): Rule {
@ -43,20 +44,18 @@ function updateConfigFile(options: ServiceWorkerOptions): Rule {
throw new Error(`Project is not defined in this workspace.`);
}
if (!project.architect) {
throw new Error(`Architect is not defined for this project.`);
}
const projectTargets = getProjectTargets(project);
if (!project.architect[options.target]) {
if (!projectTargets[options.target]) {
throw new Error(`Target is not defined for this project.`);
}
let applyTo = project.architect[options.target].options;
let applyTo = projectTargets[options.target].options;
if (options.configuration &&
project.architect[options.target].configurations &&
project.architect[options.target].configurations[options.configuration]) {
applyTo = project.architect[options.target].configurations[options.configuration];
projectTargets[options.target].configurations &&
projectTargets[options.target].configurations[options.configuration]) {
applyTo = projectTargets[options.target].configurations[options.configuration];
}
applyTo.serviceWorker = true;
@ -92,10 +91,8 @@ function updateAppModule(options: ServiceWorkerOptions): Rule {
// find app module
const workspace = getWorkspace(host);
const project = workspace.projects[options.project as string];
if (!project.architect) {
throw new Error('Project architect not found.');
}
const mainPath = project.architect.build.options.main;
const projectTargets = getProjectTargets(project);
const mainPath = projectTargets.build.options.main;
const modulePath = getAppModulePath(host, mainPath);
context.logger.debug(`module path: ${modulePath}`);

View File

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

View File

@ -36,6 +36,7 @@ import { InsertChange } from '../utility/change';
import { getWorkspace } from '../utility/config';
import { addPackageJsonDependency, getPackageJsonDependency } from '../utility/dependencies';
import { findBootstrapModuleCall, findBootstrapModulePath } from '../utility/ng-ast-utils';
import { getProjectTargets } from '../utility/project-targets';
import { Schema as UniversalOptions } from './schema';
@ -57,17 +58,14 @@ function getClientProject(
return clientProject;
}
function getClientArchitect(
function getClientTargets(
host: Tree,
options: UniversalOptions,
): experimental.workspace.WorkspaceTool {
const clientArchitect = getClientProject(host, options).architect;
const clientProject = getClientProject(host, options);
const projectTargets = getProjectTargets(clientProject);
if (!clientArchitect) {
throw new Error('Client project architect not found.');
}
return clientArchitect;
return projectTargets;
}
function updateConfigFile(options: UniversalOptions, tsConfigDirectory: Path): Rule {
@ -78,9 +76,7 @@ function updateConfigFile(options: UniversalOptions, tsConfigDirectory: Path): R
}
const clientProject = workspace.projects[options.clientProject];
if (!clientProject.architect) {
throw new Error('Client project architect not found.');
}
const projectTargets = getProjectTargets(clientProject);
const builderOptions: JsonObject = {
outputPath: `dist/${options.clientProject}-server`,
@ -91,7 +87,7 @@ function updateConfigFile(options: UniversalOptions, tsConfigDirectory: Path): R
builder: '@angular-devkit/build-angular:server',
options: builderOptions,
};
clientProject.architect.server = serverTarget;
projectTargets.server = serverTarget;
const workspacePath = getWorkspacePath(host);
@ -122,8 +118,8 @@ function findBrowserModuleImport(host: Tree, modulePath: string): ts.Node {
function wrapBootstrapCall(options: UniversalOptions): Rule {
return (host: Tree) => {
const clientArchitect = getClientArchitect(host, options);
const mainPath = normalize('/' + clientArchitect.build.options.main);
const clientTargets = getClientTargets(host, options);
const mainPath = normalize('/' + clientTargets.build.options.main);
let bootstrapCall: ts.Node | null = findBootstrapModuleCall(host, mainPath);
if (bootstrapCall === null) {
throw new SchematicsException('Bootstrap module not found.');
@ -151,8 +147,8 @@ function wrapBootstrapCall(options: UniversalOptions): Rule {
function addServerTransition(options: UniversalOptions): Rule {
return (host: Tree) => {
const clientProject = getClientProject(host, options);
const clientArchitect = getClientArchitect(host, options);
const mainPath = normalize('/' + clientArchitect.build.options.main);
const clientTargets = getClientTargets(host, options);
const mainPath = normalize('/' + clientTargets.build.options.main);
const bootstrapModuleRelativePath = findBootstrapModulePath(host, mainPath);
const bootstrapModulePath = normalize(
@ -187,8 +183,8 @@ function addDependencies(): Rule {
};
}
function getTsConfigOutDir(host: Tree, architect: experimental.workspace.WorkspaceTool): string {
const tsConfigPath = architect.build.options.tsConfig;
function getTsConfigOutDir(host: Tree, targets: experimental.workspace.WorkspaceTool): string {
const tsConfigPath = targets.build.options.tsConfig;
const tsConfigBuffer = host.read(tsConfigPath);
if (!tsConfigBuffer) {
throw new SchematicsException(`Could not read ${tsConfigPath}`);
@ -211,9 +207,9 @@ export default function (options: UniversalOptions): Rule {
if (clientProject.projectType !== 'application') {
throw new SchematicsException(`Universal requires a project type of "application".`);
}
const clientArchitect = getClientArchitect(host, options);
const outDir = getTsConfigOutDir(host, clientArchitect);
const tsConfigExtends = basename(clientArchitect.build.options.tsConfig);
const clientTargets = getClientTargets(host, options);
const outDir = getTsConfigOutDir(host, clientTargets);
const tsConfigExtends = basename(clientTargets.build.options.tsConfig);
const rootInSrc = clientProject.root === '';
const tsConfigDirectory = join(normalize(clientProject.root), rootInSrc ? 'src' : '');

View File

@ -88,7 +88,7 @@ describe('Universal Schematic', () => {
},
});
const angularConfig = JSON.parse(tree.readContent('angular.json'));
expect(angularConfig.projects.workspace.architect.server.options.tsConfig)
expect(angularConfig.projects.workspace.targets.server.options.tsConfig)
.toEqual('src/tsconfig.server.json');
});
@ -108,7 +108,7 @@ describe('Universal Schematic', () => {
},
});
const angularConfig = JSON.parse(tree.readContent('angular.json'));
expect(angularConfig.projects.bar.architect.server.options.tsConfig)
expect(angularConfig.projects.bar.targets.server.options.tsConfig)
.toEqual('projects/bar/tsconfig.server.json');
});
@ -124,10 +124,10 @@ describe('Universal Schematic', () => {
const filePath = '/angular.json';
const contents = tree.readContent(filePath);
const config = JSON.parse(contents.toString());
const arch = config.projects.bar.architect;
expect(arch.server).toBeDefined();
expect(arch.server.builder).toBeDefined();
const opts = arch.server.options;
const targets = config.projects.bar.targets;
expect(targets.server).toBeDefined();
expect(targets.server.builder).toBeDefined();
const opts = targets.server.options;
expect(opts.outputPath).toEqual('dist/bar-server');
expect(opts.main).toEqual('projects/bar/src/main.server.ts');
expect(opts.tsConfig).toEqual('projects/bar/tsconfig.server.json');

View File

@ -0,0 +1,20 @@
/**
* @license
* Copyright Google Inc. 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 { experimental } from '@angular-devkit/core';
export function getProjectTargets(
project: experimental.workspace.WorkspaceProject,
): experimental.workspace.WorkspaceTool {
const projectTargets = project.targets || project.architect;
if (!projectTargets) {
throw new Error('Project architect not found.');
}
return projectTargets;
}