7
7
*/
8
8
9
9
// 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' ;
12
21
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' ;
15
40
import { take } from 'rxjs/operators' ;
16
41
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' ;
21
48
22
49
export interface CoreSchematicOptions {
23
50
dryRun : boolean ;
@@ -44,15 +71,35 @@ export interface GetOptionsResult {
44
71
arguments : Option [ ] ;
45
72
}
46
73
74
+ export class UnknownCollectionError extends Error {
75
+ constructor ( collectionName : string ) {
76
+ super ( `Invalid collection (${ collectionName } ).` ) ;
77
+ }
78
+ }
79
+
47
80
export abstract class SchematicCommand extends Command {
48
81
readonly options : Option [ ] = [ ] ;
49
82
readonly allowPrivateSchematics : boolean = false ;
50
83
private _host = new NodeJsSyncHost ( ) ;
51
84
private _workspace : experimental . workspace . Workspace ;
52
85
private _deAliasedName : string ;
53
86
private _originalOptions : Option [ ] ;
87
+ private _engineHost : FileSystemEngineHostBase ;
88
+ private _engine : Engine < FileSystemCollectionDesc , FileSystemSchematicDesc > ;
89
+ private _workFlow : workflow . BaseWorkflow ;
54
90
argStrategy = ArgumentStrategy . Nothing ;
55
91
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
+
56
103
protected readonly coreOptions : Option [ ] = [
57
104
{
58
105
name : 'dryRun' ,
@@ -75,6 +122,31 @@ export abstract class SchematicCommand extends Command {
75
122
this . _loadWorkspace ( ) ;
76
123
}
77
124
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
+
78
150
protected setPathOptions ( options : any , workingDir : string ) : any {
79
151
if ( workingDir === '' ) {
80
152
return { } ;
@@ -91,22 +163,40 @@ export abstract class SchematicCommand extends Command {
91
163
} , { } ) ;
92
164
}
93
165
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
+
94
193
protected runSchematic ( options : RunSchematicOptions ) {
95
- const { collectionName, schematicName, debug, force , dryRun } = options ;
194
+ const { collectionName, schematicName, debug, dryRun} = options ;
96
195
let schematicOptions = this . removeCoreOptions ( options . schematicOptions ) ;
97
196
let nothingDone = true ;
98
197
let loggingQueue : string [ ] = [ ] ;
99
198
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 ) ;
110
200
111
201
const workingDir = process . cwd ( ) . replace ( this . project . root , '' ) . replace ( / \\ / g, '/' ) ;
112
202
const pathOptions = this . setPathOptions ( schematicOptions , workingDir ) ;
@@ -249,9 +339,10 @@ export abstract class SchematicCommand extends Command {
249
339
250
340
const collectionName = options . collectionName || getDefaultSchematicCollection ( ) ;
251
341
252
- const collection = getCollection ( collectionName ) ;
342
+ const collection = this . getCollection ( collectionName ) ;
253
343
254
- const schematic = getSchematic ( collection , options . schematicName , this . allowPrivateSchematics ) ;
344
+ const schematic = this . getSchematic ( collection , options . schematicName ,
345
+ this . allowPrivateSchematics ) ;
255
346
this . _deAliasedName = schematic . description . name ;
256
347
257
348
if ( ! schematic . description . schemaJson ) {
0 commit comments