Skip to content

Commit 569acc4

Browse files
qiyigghansl
authored andcommitted
feat(@angular/cli): allow specifying workflow and engineHost for schematic commands.
1 parent 64cf05b commit 569acc4

File tree

3 files changed

+114
-89
lines changed

3 files changed

+114
-89
lines changed

packages/angular/cli/commands/generate.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@ import { tags, terminal } from '@angular-devkit/core';
1111
import { CommandScope, Option } from '../models/command';
1212
import { SchematicCommand } from '../models/schematic-command';
1313
import { getDefaultSchematicCollection } from '../utilities/config';
14-
import {
15-
getCollection,
16-
getEngineHost,
17-
} from '../utilities/schematics';
1814

1915

2016
export class GenerateCommand extends SchematicCommand {
@@ -103,9 +99,9 @@ export class GenerateCommand extends SchematicCommand {
10399
this.printHelpOptions(options);
104100
} else {
105101
this.printHelpUsage(this.name, this.arguments, this.options);
106-
const engineHost = getEngineHost();
102+
const engineHost = this.getEngineHost();
107103
const [collectionName] = this.parseSchematicInfo(options);
108-
const collection = getCollection(collectionName);
104+
const collection = this.getCollection(collectionName);
109105
const schematicNames: string[] = engineHost.listSchematics(collection);
110106
this.logger.info('Available schematics:');
111107
schematicNames.forEach(schematicName => {

packages/angular/cli/models/schematic-command.ts

Lines changed: 112 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,44 @@
77
*/
88

99
// tslint:disable:no-global-tslint-disable no-any
10-
import { JsonObject, experimental } from '@angular-devkit/core';
11-
import { normalize, strings, tags, terminal, virtualFs } from '@angular-devkit/core';
10+
import {
11+
JsonObject,
12+
experimental,
13+
logging,
14+
normalize,
15+
schema,
16+
strings,
17+
tags,
18+
terminal,
19+
virtualFs,
20+
} from '@angular-devkit/core';
1221
import { NodeJsSyncHost } from '@angular-devkit/core/node';
13-
import { DryRunEvent, UnsuccessfulWorkflowExecution } from '@angular-devkit/schematics';
14-
import { NodeWorkflow } from '@angular-devkit/schematics/tools';
22+
import {
23+
Collection,
24+
DryRunEvent,
25+
Engine,
26+
Schematic,
27+
SchematicEngine,
28+
UnsuccessfulWorkflowExecution,
29+
formats,
30+
workflow,
31+
} from '@angular-devkit/schematics';
32+
import {
33+
FileSystemCollectionDesc,
34+
FileSystemEngineHostBase,
35+
FileSystemSchematicDesc,
36+
NodeModulesEngineHost,
37+
NodeWorkflow,
38+
validateOptionsWithSchema,
39+
} from '@angular-devkit/schematics/tools';
1540
import { take } from 'rxjs/operators';
1641
import { WorkspaceLoader } from '../models/workspace-loader';
17-
import { getDefaultSchematicCollection, getPackageManager } from '../utilities/config';
18-
import { getSchematicDefaults } from '../utilities/config';
19-
import { getCollection, getSchematic } from '../utilities/schematics';
20-
import { ArgumentStrategy, Command, Option } from './command';
42+
import {
43+
getDefaultSchematicCollection,
44+
getPackageManager,
45+
getSchematicDefaults,
46+
} from '../utilities/config';
47+
import { ArgumentStrategy, Command, CommandContext, Option } from './command';
2148

2249
export interface CoreSchematicOptions {
2350
dryRun: boolean;
@@ -44,15 +71,35 @@ export interface GetOptionsResult {
4471
arguments: Option[];
4572
}
4673

74+
export class UnknownCollectionError extends Error {
75+
constructor(collectionName: string) {
76+
super(`Invalid collection (${collectionName}).`);
77+
}
78+
}
79+
4780
export abstract class SchematicCommand extends Command {
4881
readonly options: Option[] = [];
4982
readonly allowPrivateSchematics: boolean = false;
5083
private _host = new NodeJsSyncHost();
5184
private _workspace: experimental.workspace.Workspace;
5285
private _deAliasedName: string;
5386
private _originalOptions: Option[];
87+
private _engineHost: FileSystemEngineHostBase;
88+
private _engine: Engine<FileSystemCollectionDesc, FileSystemSchematicDesc>;
89+
private _workFlow: workflow.BaseWorkflow;
5490
argStrategy = ArgumentStrategy.Nothing;
5591

92+
constructor(
93+
context: CommandContext, logger: logging.Logger,
94+
engineHost: FileSystemEngineHostBase = new NodeModulesEngineHost()) {
95+
super(context, logger);
96+
this._engineHost = engineHost;
97+
this._engine = new SchematicEngine(this._engineHost);
98+
const registry = new schema.CoreSchemaRegistry(formats.standardFormats);
99+
this._engineHost.registerOptionsTransform(
100+
validateOptionsWithSchema(registry));
101+
}
102+
56103
protected readonly coreOptions: Option[] = [
57104
{
58105
name: 'dryRun',
@@ -75,6 +122,31 @@ export abstract class SchematicCommand extends Command {
75122
this._loadWorkspace();
76123
}
77124

125+
protected getEngineHost() {
126+
return this._engineHost;
127+
}
128+
protected getEngine():
129+
Engine<FileSystemCollectionDesc, FileSystemSchematicDesc> {
130+
return this._engine;
131+
}
132+
133+
protected getCollection(collectionName: string): Collection<any, any> {
134+
const engine = this.getEngine();
135+
const collection = engine.createCollection(collectionName);
136+
137+
if (collection === null) {
138+
throw new UnknownCollectionError(collectionName);
139+
}
140+
141+
return collection;
142+
}
143+
144+
protected getSchematic(
145+
collection: Collection<any, any>, schematicName: string,
146+
allowPrivate?: boolean): Schematic<any, any> {
147+
return collection.createSchematic(schematicName, allowPrivate);
148+
}
149+
78150
protected setPathOptions(options: any, workingDir: string): any {
79151
if (workingDir === '') {
80152
return {};
@@ -91,22 +163,40 @@ export abstract class SchematicCommand extends Command {
91163
}, {});
92164
}
93165

166+
/*
167+
* Runtime hook to allow specifying customized workflow
168+
*/
169+
protected getWorkFlow(options: RunSchematicOptions): workflow.BaseWorkflow {
170+
const {force, dryRun} = options;
171+
const fsHost = new virtualFs.ScopedHost(
172+
new NodeJsSyncHost(), normalize(this.project.root));
173+
174+
return new NodeWorkflow(
175+
fsHost as any,
176+
{
177+
force,
178+
dryRun,
179+
packageManager: getPackageManager(),
180+
root: this.project.root,
181+
},
182+
);
183+
}
184+
185+
private _getWorkFlow(options: RunSchematicOptions): workflow.BaseWorkflow {
186+
if (!this._workFlow) {
187+
this._workFlow = this.getWorkFlow(options);
188+
}
189+
190+
return this._workFlow;
191+
}
192+
94193
protected runSchematic(options: RunSchematicOptions) {
95-
const { collectionName, schematicName, debug, force, dryRun } = options;
194+
const {collectionName, schematicName, debug, dryRun} = options;
96195
let schematicOptions = this.removeCoreOptions(options.schematicOptions);
97196
let nothingDone = true;
98197
let loggingQueue: string[] = [];
99198
let error = false;
100-
const fsHost = new virtualFs.ScopedHost(new NodeJsSyncHost(), normalize(this.project.root));
101-
const workflow = new NodeWorkflow(
102-
fsHost as any,
103-
{
104-
force,
105-
dryRun,
106-
packageManager: getPackageManager(),
107-
root: this.project.root,
108-
},
109-
);
199+
const workflow = this._getWorkFlow(options);
110200

111201
const workingDir = process.cwd().replace(this.project.root, '').replace(/\\/g, '/');
112202
const pathOptions = this.setPathOptions(schematicOptions, workingDir);
@@ -249,9 +339,10 @@ export abstract class SchematicCommand extends Command {
249339

250340
const collectionName = options.collectionName || getDefaultSchematicCollection();
251341

252-
const collection = getCollection(collectionName);
342+
const collection = this.getCollection(collectionName);
253343

254-
const schematic = getSchematic(collection, options.schematicName, this.allowPrivateSchematics);
344+
const schematic = this.getSchematic(collection, options.schematicName,
345+
this.allowPrivateSchematics);
255346
this._deAliasedName = schematic.description.name;
256347

257348
if (!schematic.description.schemaJson) {

packages/angular/cli/utilities/schematics.ts

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

0 commit comments

Comments
 (0)