Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 82f2bda

Browse files
alan-agius4Keen Yee Liau
authored and
Keen Yee Liau
committed
refactor(@schematics/angular): make interaction with architect targets type safe
1 parent a5bb3ce commit 82f2bda

File tree

21 files changed

+357
-283
lines changed

21 files changed

+357
-283
lines changed

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

+25-57
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, experimental, join, normalize } from '@angular-devkit/core';
8+
import { dirname, experimental, join, normalize } from '@angular-devkit/core';
99
import {
1010
Rule,
1111
SchematicContext,
@@ -26,19 +26,13 @@ import {
2626
isImported,
2727
} from '../utility/ast-utils';
2828
import { Change, InsertChange } from '../utility/change';
29-
import { getWorkspace, getWorkspacePath } from '../utility/config';
29+
import { getWorkspace, updateWorkspace } from '../utility/config';
3030
import { getAppModulePath } from '../utility/ng-ast-utils';
31-
import { getProjectTargets } from '../utility/project-targets';
31+
import { getProject } from '../utility/project';
32+
import { getProjectTargets, targetBuildNotFoundError } from '../utility/project-targets';
33+
import { Builders, WorkspaceProject } from '../utility/workspace-models';
3234
import { Schema as AppShellOptions } from './schema';
3335

34-
35-
// Helper functions. (possible refactors to utils)
36-
function formatMissingAppMsg(label: string, nameOrIndex: string | undefined): string {
37-
const nameOrIndexText = nameOrIndex ? ` (${nameOrIndex})` : '';
38-
39-
return `${label} app ${nameOrIndexText} not found.`;
40-
}
41-
4236
function getSourceFile(host: Tree, path: string): ts.SourceFile {
4337
const buffer = host.read(path);
4438
if (!buffer) {
@@ -103,9 +97,13 @@ function getComponentTemplate(host: Tree, compPath: string, tmplInfo: TemplateIn
10397

10498
function getBootstrapComponentPath(
10599
host: Tree,
106-
project: experimental.workspace.WorkspaceProject,
100+
project: WorkspaceProject,
107101
): string {
108102
const projectTargets = getProjectTargets(project);
103+
if (!projectTargets.build) {
104+
throw targetBuildNotFoundError();
105+
}
106+
109107
const mainPath = projectTargets.build.options.main;
110108
const modulePath = getAppModulePath(host, mainPath);
111109
const moduleSource = getSourceFile(host, modulePath);
@@ -137,7 +135,7 @@ function validateProject(options: AppShellOptions): Rule {
137135
return (host: Tree, context: SchematicContext) => {
138136
const routerOutletCheckRegex = /<router\-outlet.*?>([\s\S]*?)<\/router\-outlet>/;
139137

140-
const clientProject = getClientProject(host, options);
138+
const clientProject = getProject(host, options.clientProject);
141139
if (clientProject.projectType !== 'application') {
142140
throw new SchematicsException(`App shell requires a project type of "application".`);
143141
}
@@ -155,11 +153,9 @@ function validateProject(options: AppShellOptions): Rule {
155153

156154
function addUniversalTarget(options: AppShellOptions): Rule {
157155
return (host: Tree, context: SchematicContext) => {
158-
const architect = getClientArchitect(host, options);
159-
if (architect !== null) {
160-
if (architect.server !== undefined) {
161-
return host;
162-
}
156+
const architect = getProjectTargets(host, options.clientProject);
157+
if (architect.server) {
158+
return host;
163159
}
164160

165161
// Copy options.
@@ -187,10 +183,9 @@ function addAppShellConfigToWorkspace(options: AppShellOptions): Rule {
187183
}
188184

189185
const workspace = getWorkspace(host);
190-
const workspacePath = getWorkspacePath(host);
191-
192-
const appShellTarget: JsonObject = {
193-
builder: '@angular-devkit/build-angular:app-shell',
186+
const projectTargets = getProjectTargets(workspace, options.clientProject);
187+
projectTargets['app-shell'] = {
188+
builder: Builders.AppShell,
194189
options: {
195190
browserTarget: `${options.clientProject}:build`,
196191
serverTarget: `${options.clientProject}:server`,
@@ -203,23 +198,17 @@ function addAppShellConfigToWorkspace(options: AppShellOptions): Rule {
203198
},
204199
};
205200

206-
if (!workspace.projects[options.clientProject]) {
207-
throw new SchematicsException(`Client app ${options.clientProject} not found.`);
208-
}
209-
const clientProject = workspace.projects[options.clientProject];
210-
const projectTargets = getProjectTargets(clientProject);
211-
projectTargets['app-shell'] = appShellTarget;
212-
213-
host.overwrite(workspacePath, JSON.stringify(workspace, null, 2));
214-
215-
return host;
201+
return updateWorkspace(workspace);
216202
};
217203
}
218204

219205
function addRouterModule(options: AppShellOptions): Rule {
220206
return (host: Tree) => {
221-
const clientArchitect = getClientArchitect(host, options);
222-
const mainPath = clientArchitect.build.options.main;
207+
const projectTargets = getProjectTargets(host, options.clientProject);
208+
if (!projectTargets.build) {
209+
throw targetBuildNotFoundError();
210+
}
211+
const mainPath = projectTargets.build.options.main;
223212
const modulePath = getAppModulePath(host, mainPath);
224213
const moduleSource = getSourceFile(host, modulePath);
225214
const changes = addImportToModule(moduleSource, modulePath, 'RouterModule', '@angular/router');
@@ -256,8 +245,8 @@ function getMetadataProperty(metadata: ts.Node, propertyName: string): ts.Proper
256245

257246
function addServerRoutes(options: AppShellOptions): Rule {
258247
return (host: Tree) => {
259-
const clientProject = getClientProject(host, options);
260-
const architect = getClientArchitect(host, options);
248+
const clientProject = getProject(host, options.clientProject);
249+
const architect = getProjectTargets(clientProject);
261250
// const mainPath = universalArchitect.build.options.main;
262251
const modulePath = getServerModulePath(host, clientProject, architect);
263252
if (modulePath === null) {
@@ -322,27 +311,6 @@ function addShellComponent(options: AppShellOptions): Rule {
322311
return schematic('component', componentOptions);
323312
}
324313

325-
function getClientProject(
326-
host: Tree, options: AppShellOptions,
327-
): experimental.workspace.WorkspaceProject {
328-
const workspace = getWorkspace(host);
329-
const clientProject = workspace.projects[options.clientProject];
330-
if (!clientProject) {
331-
throw new SchematicsException(formatMissingAppMsg('Client', options.clientProject));
332-
}
333-
334-
return clientProject;
335-
}
336-
337-
function getClientArchitect(
338-
host: Tree, options: AppShellOptions,
339-
): experimental.workspace.WorkspaceTool {
340-
const clientProject = getClientProject(host, options);
341-
const projectTargets = getProjectTargets(clientProject);
342-
343-
return projectTargets;
344-
}
345-
346314
export default function (options: AppShellOptions): Rule {
347315
return chain([
348316
validateProject(options),

packages/schematics/angular/application/index.ts

+12-8
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,18 @@ import {
2424
} from '@angular-devkit/schematics';
2525
import { Schema as E2eOptions } from '../e2e/schema';
2626
import {
27-
WorkspaceProject,
28-
WorkspaceSchema,
2927
addProjectToWorkspace,
3028
getWorkspace,
3129
} from '../utility/config';
3230
import { NodeDependencyType, addPackageJsonDependency } from '../utility/dependencies';
3331
import { latestVersions } from '../utility/latest-versions';
3432
import { validateProjectName } from '../utility/validation';
33+
import {
34+
Builders,
35+
ProjectType,
36+
WorkspaceProject,
37+
WorkspaceSchema,
38+
} from '../utility/workspace-models';
3539
import { Schema as ApplicationOptions } from './schema';
3640

3741

@@ -133,12 +137,12 @@ function addAppToWorkspaceFile(options: ApplicationOptions, workspace: Workspace
133137
const project: WorkspaceProject = {
134138
root: projectRoot,
135139
sourceRoot: join(normalize(projectRoot), 'src'),
136-
projectType: 'application',
140+
projectType: ProjectType.Application,
137141
prefix: options.prefix || 'app',
138142
schematics,
139143
targets: {
140144
build: {
141-
builder: '@angular-devkit/build-angular:browser',
145+
builder: Builders.Browser,
142146
options: {
143147
outputPath: `dist/${options.name}`,
144148
index: `${projectRoot}src/index.html`,
@@ -173,7 +177,7 @@ function addAppToWorkspaceFile(options: ApplicationOptions, workspace: Workspace
173177
},
174178
},
175179
serve: {
176-
builder: '@angular-devkit/build-angular:dev-server',
180+
builder: Builders.DevServer,
177181
options: {
178182
browserTarget: `${options.name}:build`,
179183
},
@@ -184,13 +188,13 @@ function addAppToWorkspaceFile(options: ApplicationOptions, workspace: Workspace
184188
},
185189
},
186190
'extract-i18n': {
187-
builder: '@angular-devkit/build-angular:extract-i18n',
191+
builder: Builders.ExtractI18n,
188192
options: {
189193
browserTarget: `${options.name}:build`,
190194
},
191195
},
192196
test: {
193-
builder: '@angular-devkit/build-angular:karma',
197+
builder: Builders.Karma,
194198
options: {
195199
main: `${projectRoot}src/test.ts`,
196200
polyfills: `${projectRoot}src/polyfills.ts`,
@@ -207,7 +211,7 @@ function addAppToWorkspaceFile(options: ApplicationOptions, workspace: Workspace
207211
},
208212
},
209213
lint: {
210-
builder: '@angular-devkit/build-angular:tslint',
214+
builder: Builders.TsLint,
211215
options: {
212216
tsConfig: [
213217
`${rootFilesRoot}tsconfig.app.json`,

packages/schematics/angular/class/index.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,17 @@ import {
2020
template,
2121
url,
2222
} from '@angular-devkit/schematics';
23-
import { getWorkspace } from '../utility/config';
2423
import { parseName } from '../utility/parse-name';
25-
import { buildDefaultPath } from '../utility/project';
24+
import { buildDefaultPath, getProject } from '../utility/project';
2625
import { Schema as ClassOptions } from './schema';
2726

2827
export default function (options: ClassOptions): Rule {
2928
return (host: Tree, context: SchematicContext) => {
30-
const workspace = getWorkspace(host);
3129
if (!options.project) {
3230
throw new SchematicsException('Option (project) is required.');
3331
}
34-
const project = workspace.projects[options.project];
32+
33+
const project = getProject(host, options.project);
3534

3635
if (options.path === undefined) {
3736
options.path = buildDefaultPath(project);

packages/schematics/angular/component/index.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,10 @@ import {
2727
addExportToModule,
2828
} from '../utility/ast-utils';
2929
import { InsertChange } from '../utility/change';
30-
import { getWorkspace } from '../utility/config';
3130
import { buildRelativePath, findModuleFromOptions } from '../utility/find-module';
3231
import { applyLintFix } from '../utility/lint-fix';
3332
import { parseName } from '../utility/parse-name';
34-
import { buildDefaultPath } from '../utility/project';
33+
import { buildDefaultPath, getProject } from '../utility/project';
3534
import { validateHtmlSelector, validateName } from '../utility/validation';
3635
import { Schema as ComponentOptions } from './schema';
3736

@@ -128,11 +127,10 @@ function buildSelector(options: ComponentOptions, projectPrefix: string) {
128127

129128
export default function(options: ComponentOptions): Rule {
130129
return (host: Tree) => {
131-
const workspace = getWorkspace(host);
132130
if (!options.project) {
133131
throw new SchematicsException('Option (project) is required.');
134132
}
135-
const project = workspace.projects[options.project];
133+
const project = getProject(host, options.project);
136134

137135
if (options.path === undefined) {
138136
options.path = buildDefaultPath(project);

packages/schematics/angular/directive/index.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,10 @@ import {
2323
import * as ts from 'typescript';
2424
import { addDeclarationToModule, addExportToModule } from '../utility/ast-utils';
2525
import { InsertChange } from '../utility/change';
26-
import { getWorkspace } from '../utility/config';
2726
import { buildRelativePath, findModuleFromOptions } from '../utility/find-module';
2827
import { applyLintFix } from '../utility/lint-fix';
2928
import { parseName } from '../utility/parse-name';
30-
import { buildDefaultPath } from '../utility/project';
29+
import { buildDefaultPath, getProject } from '../utility/project';
3130
import { validateHtmlSelector } from '../utility/validation';
3231
import { Schema as DirectiveOptions } from './schema';
3332

@@ -104,11 +103,10 @@ function buildSelector(options: DirectiveOptions, projectPrefix: string) {
104103

105104
export default function (options: DirectiveOptions): Rule {
106105
return (host: Tree) => {
107-
const workspace = getWorkspace(host);
108106
if (!options.project) {
109107
throw new SchematicsException('Option (project) is required.');
110108
}
111-
const project = workspace.projects[options.project];
109+
const project = getProject(host, options.project);
112110

113111
if (options.path === undefined) {
114112
options.path = buildDefaultPath(project);

0 commit comments

Comments
 (0)