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 { getCollection , getEngineHost , getSchematic , runSchematic } from '../utilities/schematics' ;
9
+ import { DynamicPathOptions , dynamicPathParser } from '../utilities/dynamic-path-parser' ;
10
+ import { getAppFromConfig } from '../utilities/app-utils' ;
11
+ import * as path from 'path' ;
12
+
8
13
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
14
const SilentError = require ( 'silent-error' ) ;
12
15
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 ) ) ) ;
19
-
20
- return blueprints ;
16
+ function mapSchematicOptions ( schematic : any ) : any [ ] {
17
+ const properties = schematic . description . schemaJson . properties ;
18
+ const keys = Object . keys ( properties ) ;
19
+ const options = keys
20
+ . map ( key => ( { ...properties [ key ] , ...{ name : stringUtils . dasherize ( key ) } } ) )
21
+ . map ( opt => {
22
+ let type ;
23
+ switch ( opt . type ) {
24
+ case 'string' :
25
+ type = String ;
26
+ break ;
27
+ case 'boolean' :
28
+ type = Boolean ;
29
+ break ;
30
+ }
31
+ let aliases : string [ ] = [ ] ;
32
+ if ( opt . alias ) {
33
+ aliases = [ ...aliases , opt . alias ] ;
34
+ }
35
+ if ( opt . aliases ) {
36
+ aliases = [ ...aliases , ...opt . aliases ] ;
37
+ }
38
+
39
+ return {
40
+ ...opt ,
41
+ aliases,
42
+ type
43
+ } ;
44
+ } ) ;
45
+
46
+ return options ;
21
47
}
22
48
23
49
export default Command . extend ( {
24
50
name : 'generate' ,
25
- description : 'Generates and/or modifies files based on a blueprint .' ,
51
+ description : 'Generates and/or modifies files based on a schematic .' ,
26
52
aliases : [ 'g' ] ,
27
53
28
54
availableOptions : [
@@ -34,117 +60,109 @@ export default Command.extend({
34
60
description : 'Run through without making any changes.'
35
61
} ,
36
62
{
37
- name : 'lint-fix ' ,
63
+ name : 'force ' ,
38
64
type : Boolean ,
39
- aliases : [ 'lf' ] ,
40
- description : 'Use lint to fix files after generation.'
65
+ default : false ,
66
+ aliases : [ 'f' ] ,
67
+ description : 'Forces overwriting of files.'
41
68
} ,
42
69
{
43
- name : 'verbose' ,
44
- type : Boolean ,
45
- default : false ,
46
- aliases : [ 'v' ] ,
47
- description : 'Adds more details to output logging.'
70
+ name : 'app' ,
71
+ type : String ,
72
+ aliases : [ 'a' ] ,
73
+ description : 'Specifies app name to use.'
74
+ } ,
75
+ {
76
+ name : 'collection' ,
77
+ type : String ,
78
+ aliases : [ 'c' ] ,
79
+ description : 'Schematics collection to use.'
48
80
}
49
81
] ,
50
82
51
83
anonymousOptions : [
52
- '<blueprint >'
84
+ '<schemtatic >'
53
85
] ,
54
86
55
- beforeRun : function ( rawArgs : string [ ] ) {
56
- if ( ! rawArgs . length ) {
57
- return ;
87
+ getCollectionName ( rawArgs : string [ ] ) {
88
+ let collectionName = CliConfig . getValue ( 'defaults.schematics.collection' ) ;
89
+ if ( rawArgs ) {
90
+ const parsedArgs = this . parseArgs ( rawArgs , false ) ;
91
+ if ( parsedArgs . options . collection ) {
92
+ collectionName = parsedArgs . options . collection ;
93
+ }
58
94
}
95
+ return collectionName ;
96
+ } ,
97
+
98
+ beforeRun : function ( rawArgs : string [ ] ) {
99
+ const collection = getCollection ( this . getCollectionName ( rawArgs ) ) ;
59
100
60
101
const isHelp = [ '--help' , '-h' ] . includes ( rawArgs [ 0 ] ) ;
61
102
if ( isHelp ) {
62
103
return ;
63
104
}
64
105
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.` ) ;
106
+ const schematicName = rawArgs [ 0 ] ;
107
+ if ( ! schematicName ) {
108
+ return Promise . reject ( new SilentError ( oneLine `
109
+ The "ng generate" command requires a
110
+ schematic name to be specified.
111
+ For more details, use "ng help".
112
+ ` ) ) ;
79
113
}
80
114
81
- if ( / ^ \d / . test ( rawArgs [ 1 ] ) ) {
82
- SilentError . debugOrThrow ( '@angular/cli/commands/generate' ,
83
- `The \`ng generate ${ name } ${ rawArgs [ 1 ] } \` file name cannot begin with a digit.` ) ;
84
- }
115
+ this . schematic = getSchematic ( collection , schematicName ) ;
85
116
86
- rawArgs [ 0 ] = blueprint . name ;
87
- this . registerOptions ( blueprint ) ;
88
- } ,
117
+ const schematicOptions = mapSchematicOptions ( this . schematic ) ;
89
118
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 ) ) ;
119
+ this . registerOptions ( { availableOptions : schematicOptions } ) ;
96
120
} ,
97
121
98
122
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
- ` ) ) ;
106
- }
123
+ const entityName = rawArgs [ 1 ] ;
124
+ commandOptions . name = stringUtils . dasherize ( entityName . split ( path . sep ) . pop ( ) ) ;
107
125
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 ,
126
+ const appConfig = getAppFromConfig ( commandOptions . app ) ;
127
+ const dynamicPathOptions : DynamicPathOptions = {
120
128
project : this . project ,
121
- settings : this . settings ,
122
- testing : this . testing ,
123
- args : rawArgs ,
124
- ...commandOptions
129
+ entityName : entityName ,
130
+ appConfig : appConfig ,
131
+ dryRun : commandOptions . dryRun
125
132
} ;
133
+ const parsedPath = dynamicPathParser ( dynamicPathOptions ) ;
134
+ commandOptions . sourceDir = appConfig . root ;
135
+ commandOptions . path = parsedPath . dir . replace ( appConfig . root + path . sep , '' ) ;
136
+
137
+ const cwd = process . cwd ( ) ;
138
+ let dir = cwd ;
139
+ const sourceRoot = path . join ( this . project . root , appConfig . root ) ;
140
+ const appRoot = path . join ( sourceRoot , 'app' ) ;
141
+ if ( cwd . indexOf ( appRoot ) === 0 ) {
142
+ dir = cwd ;
143
+ } else if ( cwd . indexOf ( sourceRoot ) === 0 ) {
144
+ dir = path . join ( sourceRoot , 'app' ) ;
145
+ } else {
146
+ dir = path . join ( this . project . root , appConfig . root , 'app' ) ;
147
+ }
126
148
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
- }
148
- } ) ;
149
+ const collectionName = this . getCollectionName ( rawArgs ) ;
150
+ const collection = getCollection ( collectionName ) ;
151
+ const schematicName = rawArgs [ 0 ] ;
152
+ const schematic = getSchematic ( collection , schematicName ) ;
153
+ return runSchematic ( schematic , cwd , dir , commandOptions , this . project . root ) ;
154
+
155
+ } ,
156
+
157
+ printDetailedHelp : function ( ) {
158
+ const engineHost = getEngineHost ( ) ;
159
+ const collectionName = this . getCollectionName ( ) ;
160
+ const collection = getCollection ( collectionName ) ;
161
+ const schematicNames : string [ ] = engineHost . listSchematics ( collection )
162
+ this . ui . writeLine ( cyan ( 'Available schematics:' ) ) ;
163
+ schematicNames . forEach ( schematicName => {
164
+ this . ui . writeLine ( yellow ( ` ${ schematicName } ` ) ) ;
165
+ } )
166
+ this . ui . writeLine ( '' ) ;
149
167
}
150
168
} ) ;
0 commit comments