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' ) ;
53import { oneLine } from 'common-tags' ;
64import { CliConfig } from '../models/config' ;
75
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+
817const 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' ) ;
1118const SilentError = require ( 'silent-error' ) ;
1219
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;
1921
20- return blueprints ;
21- }
2222
2323export default Command . extend ( {
2424 name : 'generate' ,
25- description : 'Generates and/or modifies files based on a blueprint .' ,
25+ description : 'Generates and/or modifies files based on a schematic .' ,
2626 aliases : [ 'g' ] ,
2727
2828 availableOptions : [
@@ -34,117 +34,145 @@ export default Command.extend({
3434 description : 'Run through without making any changes.'
3535 } ,
3636 {
37- name : 'lint-fix ' ,
37+ name : 'force ' ,
3838 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.'
4142 } ,
4243 {
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' ,
4457 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.'
4860 }
4961 ] ,
5062
5163 anonymousOptions : [
52- '<blueprint >'
64+ '<schematic >'
5365 ] ,
5466
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+ }
5874 }
75+ return collectionName ;
76+ } ,
77+
78+ beforeRun : function ( rawArgs : string [ ] ) {
5979
6080 const isHelp = [ '--help' , '-h' ] . includes ( rawArgs [ 0 ] ) ;
6181 if ( isHelp ) {
6282 return ;
6383 }
6484
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+ ` ) ) ;
7992 }
8093
8194 if ( / ^ \d / . test ( rawArgs [ 1 ] ) ) {
8295 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.` ) ;
8497 }
8598
86- rawArgs [ 0 ] = blueprint . name ;
87- this . registerOptions ( blueprint ) ;
88- } ,
99+ const SchematicGetOptionsTask = require ( '../tasks/schematic-get-options' ) . default ;
89100
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+ } ) ;
96122 } ,
97123
98124 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.' ;
106127 }
107128
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 = {
120134 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
125138 } ;
139+ const parsedPath = dynamicPathParser ( dynamicPathOptions ) ;
140+ commandOptions . sourceDir = appConfig . root ;
141+ commandOptions . path = parsedPath . dir
142+ . replace ( appConfig . root + path . sep , '' )
143+ . replace ( separatorRegEx , '/' ) ;
126144
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
148164 } ) ;
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 ( '' ) ;
149177 }
150178} ) ;
0 commit comments