1
- import * as chalk from 'chalk' ;
2
- import * as fs from 'fs' ;
3
- import * as os from 'os' ;
4
- import * as path from 'path' ;
1
+ import { cyan , yellow } from 'chalk' ;
2
+ const stringUtils = require ( 'ember-cli-string-utils' ) ;
5
3
import { oneLine } from 'common-tags' ;
6
4
import { CliConfig } from '../models/config' ;
7
5
6
+ import 'rxjs/add/observable/of' ;
7
+ import 'rxjs/add/operator/ignoreElements' ;
8
+ import {
9
+ getCollection ,
10
+ getEngineHost
11
+ } from '../utilities/schematics' ;
12
+ import { DynamicPathOptions , dynamicPathParser } from '../utilities/dynamic-path-parser' ;
13
+ import { getAppFromConfig } from '../utilities/app-utils' ;
14
+ import * as path from 'path' ;
15
+ import { SchematicAvailableOptions } from '../tasks/schematic-get-options' ;
16
+
8
17
const Command = require ( '../ember-cli/lib/models/command' ) ;
9
- const Blueprint = require ( '../ember-cli/lib/models/blueprint' ) ;
10
- const parseOptions = require ( '../ember-cli/lib/utilities/parse-options' ) ;
11
18
const SilentError = require ( 'silent-error' ) ;
12
19
13
- function loadBlueprints ( ) : Array < any > {
14
- const blueprintList = fs . readdirSync ( path . join ( __dirname , '..' , 'blueprints' ) ) ;
15
- const blueprints = blueprintList
16
- . filter ( bp => bp . indexOf ( '-test' ) === - 1 )
17
- . filter ( bp => bp !== 'ng' )
18
- . map ( bp => Blueprint . load ( path . join ( __dirname , '..' , 'blueprints' , bp ) ) ) ;
20
+ const separatorRegEx = / [ \/ \\ ] / g;
19
21
20
- return blueprints ;
21
- }
22
22
23
23
export default Command . extend ( {
24
24
name : 'generate' ,
25
- description : 'Generates and/or modifies files based on a blueprint .' ,
25
+ description : 'Generates and/or modifies files based on a schematic .' ,
26
26
aliases : [ 'g' ] ,
27
27
28
28
availableOptions : [
@@ -34,117 +34,145 @@ export default Command.extend({
34
34
description : 'Run through without making any changes.'
35
35
} ,
36
36
{
37
- name : 'lint-fix ' ,
37
+ name : 'force ' ,
38
38
type : Boolean ,
39
- aliases : [ 'lf' ] ,
40
- description : 'Use lint to fix files after generation.'
39
+ default : false ,
40
+ aliases : [ 'f' ] ,
41
+ description : 'Forces overwriting of files.'
41
42
} ,
42
43
{
43
- name : 'verbose' ,
44
+ name : 'app' ,
45
+ type : String ,
46
+ aliases : [ 'a' ] ,
47
+ description : 'Specifies app name to use.'
48
+ } ,
49
+ {
50
+ name : 'collection' ,
51
+ type : String ,
52
+ aliases : [ 'c' ] ,
53
+ description : 'Schematics collection to use.'
54
+ } ,
55
+ {
56
+ name : 'lint-fix' ,
44
57
type : Boolean ,
45
- default : false ,
46
- aliases : [ 'v' ] ,
47
- description : 'Adds more details to output logging.'
58
+ aliases : [ 'lf' ] ,
59
+ description : 'Use lint to fix files after generation.'
48
60
}
49
61
] ,
50
62
51
63
anonymousOptions : [
52
- '<blueprint >'
64
+ '<schematic >'
53
65
] ,
54
66
55
- beforeRun : function ( rawArgs : string [ ] ) {
56
- if ( ! rawArgs . length ) {
57
- return ;
67
+ getCollectionName ( rawArgs : string [ ] ) {
68
+ let collectionName = CliConfig . getValue ( 'defaults.schematics.collection' ) ;
69
+ if ( rawArgs ) {
70
+ const parsedArgs = this . parseArgs ( rawArgs , false ) ;
71
+ if ( parsedArgs . options . collection ) {
72
+ collectionName = parsedArgs . options . collection ;
73
+ }
58
74
}
75
+ return collectionName ;
76
+ } ,
77
+
78
+ beforeRun : function ( rawArgs : string [ ] ) {
59
79
60
80
const isHelp = [ '--help' , '-h' ] . includes ( rawArgs [ 0 ] ) ;
61
81
if ( isHelp ) {
62
82
return ;
63
83
}
64
84
65
- this . blueprints = loadBlueprints ( ) ;
66
-
67
- const name = rawArgs [ 0 ] ;
68
- const blueprint = this . blueprints . find ( ( bp : any ) => bp . name === name
69
- || ( bp . aliases && bp . aliases . includes ( name ) ) ) ;
70
-
71
- if ( ! blueprint ) {
72
- SilentError . debugOrThrow ( '@angular/cli/commands/generate' ,
73
- `Invalid blueprint: ${ name } ` ) ;
74
- }
75
-
76
- if ( ! rawArgs [ 1 ] ) {
77
- SilentError . debugOrThrow ( '@angular/cli/commands/generate' ,
78
- `The \`ng generate ${ name } \` command requires a name to be specified.` ) ;
85
+ const schematicName = rawArgs [ 0 ] ;
86
+ if ( ! schematicName ) {
87
+ return Promise . reject ( new SilentError ( oneLine `
88
+ The "ng generate" command requires a
89
+ schematic name to be specified.
90
+ For more details, use "ng help".
91
+ ` ) ) ;
79
92
}
80
93
81
94
if ( / ^ \d / . test ( rawArgs [ 1 ] ) ) {
82
95
SilentError . debugOrThrow ( '@angular/cli/commands/generate' ,
83
- `The \`ng generate ${ name } ${ rawArgs [ 1 ] } \` file name cannot begin with a digit.` ) ;
96
+ `The \`ng generate ${ schematicName } ${ rawArgs [ 1 ] } \` file name cannot begin with a digit.` ) ;
84
97
}
85
98
86
- rawArgs [ 0 ] = blueprint . name ;
87
- this . registerOptions ( blueprint ) ;
88
- } ,
99
+ const SchematicGetOptionsTask = require ( '../tasks/schematic-get-options' ) . default ;
89
100
90
- printDetailedHelp : function ( ) {
91
- if ( ! this . blueprints ) {
92
- this . blueprints = loadBlueprints ( ) ;
93
- }
94
- this . ui . writeLine ( chalk . cyan ( ' Available blueprints' ) ) ;
95
- this . ui . writeLine ( this . blueprints . map ( ( bp : any ) => bp . printBasicHelp ( false ) ) . join ( os . EOL ) ) ;
101
+ const getOptionsTask = new SchematicGetOptionsTask ( {
102
+ ui : this . ui ,
103
+ project : this . project
104
+ } ) ;
105
+ const collectionName = this . getCollectionName ( rawArgs ) ;
106
+
107
+ return getOptionsTask . run ( {
108
+ schematicName,
109
+ collectionName
110
+ } )
111
+ . then ( ( availableOptions : SchematicAvailableOptions ) => {
112
+ let anonymousOptions : string [ ] = [ ] ;
113
+ if ( collectionName === '@schematics/angular' && schematicName === 'interface' ) {
114
+ anonymousOptions = [ '<type>' ] ;
115
+ }
116
+
117
+ this . registerOptions ( {
118
+ anonymousOptions : anonymousOptions ,
119
+ availableOptions : availableOptions
120
+ } ) ;
121
+ } ) ;
96
122
} ,
97
123
98
124
run : function ( commandOptions : any , rawArgs : string [ ] ) {
99
- const name = rawArgs [ 0 ] ;
100
- if ( ! name ) {
101
- return Promise . reject ( new SilentError ( oneLine `
102
- The "ng generate" command requires a
103
- blueprint name to be specified.
104
- For more details, use "ng help".
105
- ` ) ) ;
125
+ if ( rawArgs [ 0 ] === 'module' && ! rawArgs [ 1 ] ) {
126
+ throw 'The `ng generate module` command requires a name to be specified.' ;
106
127
}
107
128
108
- const blueprint = this . blueprints . find ( ( bp : any ) => bp . name === name
109
- || ( bp . aliases && bp . aliases . includes ( name ) ) ) ;
110
-
111
- const projectName = CliConfig . getValue ( 'project.name' ) ;
112
- const blueprintOptions = {
113
- target : this . project . root ,
114
- entity : {
115
- name : rawArgs [ 1 ] ,
116
- options : parseOptions ( rawArgs . slice ( 2 ) )
117
- } ,
118
- projectName,
119
- ui : this . ui ,
129
+ const entityName = rawArgs [ 1 ] ;
130
+ commandOptions . name = stringUtils . dasherize ( entityName . split ( separatorRegEx ) . pop ( ) ) ;
131
+
132
+ const appConfig = getAppFromConfig ( commandOptions . app ) ;
133
+ const dynamicPathOptions : DynamicPathOptions = {
120
134
project : this . project ,
121
- settings : this . settings ,
122
- testing : this . testing ,
123
- args : rawArgs ,
124
- ...commandOptions
135
+ entityName : entityName ,
136
+ appConfig : appConfig ,
137
+ dryRun : commandOptions . dryRun
125
138
} ;
139
+ const parsedPath = dynamicPathParser ( dynamicPathOptions ) ;
140
+ commandOptions . sourceDir = appConfig . root ;
141
+ commandOptions . path = parsedPath . dir
142
+ . replace ( appConfig . root + path . sep , '' )
143
+ . replace ( separatorRegEx , '/' ) ;
126
144
127
- return blueprint . install ( blueprintOptions )
128
- . then ( ( ) => {
129
- const lintFix = commandOptions . lintFix !== undefined ?
130
- commandOptions . lintFix : CliConfig . getValue ( 'defaults.lintFix' ) ;
131
-
132
- if ( lintFix && blueprint . modifiedFiles ) {
133
- const LintTask = require ( '../tasks/lint' ) . default ;
134
- const lintTask = new LintTask ( {
135
- ui : this . ui ,
136
- project : this . project
137
- } ) ;
138
-
139
- return lintTask . run ( {
140
- fix : true ,
141
- force : true ,
142
- silent : true ,
143
- configs : [ {
144
- files : blueprint . modifiedFiles . filter ( ( file : string ) => / .t s $ / . test ( file ) )
145
- } ]
146
- } ) ;
147
- }
145
+ const cwd = this . project . root ;
146
+ const schematicName = rawArgs [ 0 ] ;
147
+
148
+ const SchematicRunTask = require ( '../tasks/schematic-run' ) . default ;
149
+ const schematicRunTask = new SchematicRunTask ( {
150
+ ui : this . ui ,
151
+ project : this . project
152
+ } ) ;
153
+ const collectionName = this . getCollectionName ( rawArgs ) ;
154
+
155
+ if ( collectionName === '@schematics/angular' && schematicName === 'interface' && rawArgs [ 2 ] ) {
156
+ commandOptions . type = rawArgs [ 2 ] ;
157
+ }
158
+
159
+ return schematicRunTask . run ( {
160
+ taskOptions : commandOptions ,
161
+ workingDir : cwd ,
162
+ collectionName,
163
+ schematicName
148
164
} ) ;
165
+ } ,
166
+
167
+ printDetailedHelp : function ( ) {
168
+ const engineHost = getEngineHost ( ) ;
169
+ const collectionName = this . getCollectionName ( ) ;
170
+ const collection = getCollection ( collectionName ) ;
171
+ const schematicNames : string [ ] = engineHost . listSchematics ( collection ) ;
172
+ this . ui . writeLine ( cyan ( 'Available schematics:' ) ) ;
173
+ schematicNames . forEach ( schematicName => {
174
+ this . ui . writeLine ( yellow ( ` ${ schematicName } ` ) ) ;
175
+ } ) ;
176
+ this . ui . writeLine ( '' ) ;
149
177
}
150
178
} ) ;
0 commit comments