1
+ import * as fs from 'fs' ;
1
2
import * as path from 'path' ;
2
3
import * as yeoman from 'yeoman-generator' ;
3
4
import * as uuid from 'node-uuid' ;
@@ -9,15 +10,35 @@ const yosay = require('yosay');
9
10
const toPascalCase = require ( 'to-pascal-case' ) ;
10
11
const isWindows = / ^ w i n / . test ( process . platform ) ;
11
12
13
+ // Paths matching these regexes will only be included if the user wants tests
14
+ const testSpecificPaths = [
15
+ / \. s p e c .t s $ / , // Files ending '.spec.ts'
16
+ / ( ^ | \/ | \\ ) t e s t ( $ | \/ | \\ ) / // Files under any directory called 'test'
17
+ ] ;
18
+
19
+ // These NPM dependencies will only be included if the user wants tests
20
+ const testSpecificNpmPackages = [
21
+ "@types/chai" ,
22
+ "@types/jasmine" ,
23
+ "chai" ,
24
+ "jasmine-core" ,
25
+ "karma" ,
26
+ "karma-chai" ,
27
+ "karma-chrome-launcher" ,
28
+ "karma-cli" ,
29
+ "karma-jasmine" ,
30
+ "karma-webpack"
31
+ ] ;
32
+
12
33
type YeomanPrompt = ( opt : yeoman . IPromptOptions | yeoman . IPromptOptions [ ] , callback : ( answers : any ) => void ) => void ;
13
34
const optionOrPrompt : YeomanPrompt = require ( 'yeoman-option-or-prompt' ) ;
14
35
15
36
const templates = [
16
- { value : 'angular-2' , name : 'Angular 2' } ,
17
- { value : 'aurelia' , name : 'Aurelia' } ,
18
- { value : 'knockout' , name : 'Knockout' } ,
19
- { value : 'react' , name : 'React' } ,
20
- { value : 'react-redux' , name : 'React with Redux' }
37
+ { value : 'angular-2' , name : 'Angular 2' , tests : true } ,
38
+ { value : 'aurelia' , name : 'Aurelia' , tests : false } ,
39
+ { value : 'knockout' , name : 'Knockout' , tests : false } ,
40
+ { value : 'react' , name : 'React' , tests : false } ,
41
+ { value : 'react-redux' , name : 'React with Redux' , tests : false }
21
42
] ;
22
43
23
44
class MyGenerator extends yeoman . Base {
@@ -35,24 +56,40 @@ class MyGenerator extends yeoman.Base {
35
56
}
36
57
37
58
prompting ( ) {
38
- const done = this . async ( ) ;
39
-
40
59
this . option ( 'projectguid' ) ;
60
+
61
+ const done = this . async ( ) ;
41
62
this . _optionOrPrompt ( [ {
42
63
type : 'list' ,
43
64
name : 'framework' ,
44
65
message : 'Framework' ,
45
66
choices : templates
46
- } , {
47
- type : 'input' ,
48
- name : 'name' ,
49
- message : 'Your project name' ,
50
- default : this . appname
51
- } ] , answers => {
52
- this . _answers = answers ;
53
- this . _answers . namePascalCase = toPascalCase ( answers . name ) ;
54
- this . _answers . projectGuid = this . options [ 'projectguid' ] || uuid . v4 ( ) ;
55
- done ( ) ;
67
+ } ] , frameworkAnswer => {
68
+ const frameworkChoice = templates . filter ( t => t . value === frameworkAnswer . framework ) [ 0 ] ;
69
+ const furtherQuestions = [ {
70
+ type : 'input' ,
71
+ name : 'name' ,
72
+ message : 'Your project name' ,
73
+ default : this . appname
74
+ } ] ;
75
+
76
+ if ( frameworkChoice . tests ) {
77
+ furtherQuestions . unshift ( {
78
+ type : 'confirm' ,
79
+ name : 'tests' ,
80
+ message : 'Do you want to include unit tests?' ,
81
+ default : true as any
82
+ } ) ;
83
+ }
84
+
85
+ this . _optionOrPrompt ( furtherQuestions , answers => {
86
+ answers . framework = frameworkAnswer . framework ;
87
+ this . _answers = answers ;
88
+ this . _answers . framework = frameworkAnswer . framework ;
89
+ this . _answers . namePascalCase = toPascalCase ( answers . name ) ;
90
+ this . _answers . projectGuid = this . options [ 'projectguid' ] || uuid . v4 ( ) ;
91
+ done ( ) ;
92
+ } ) ;
56
93
} ) ;
57
94
}
58
95
@@ -79,11 +116,27 @@ class MyGenerator extends yeoman.Base {
79
116
outputFn = path . join ( path . dirname ( fn ) , 'node_modules' , '_placeholder.txt' ) ;
80
117
}
81
118
82
- this . fs . copyTpl (
83
- path . join ( templateRoot , fn ) ,
84
- this . destinationPath ( outputFn ) ,
85
- this . _answers
86
- ) ;
119
+ // Exclude test-specific files (unless the user has said they want tests)
120
+ const isTestSpecificFile = testSpecificPaths . some ( regex => regex . test ( outputFn ) ) ;
121
+ if ( this . _answers . tests || ! isTestSpecificFile ) {
122
+ const inputFullPath = path . join ( templateRoot , fn ) ;
123
+ if ( path . basename ( fn ) === 'package.json' ) {
124
+ // Special handling for package.json, because we rewrite it dynamically
125
+ this . fs . writeJSON (
126
+ this . destinationPath ( outputFn ) ,
127
+ rewritePackageJson ( JSON . parse ( fs . readFileSync ( inputFullPath , 'utf8' ) ) , this . _answers . tests ) ,
128
+ /* replacer */ null ,
129
+ /* space */ 2
130
+ ) ;
131
+ } else {
132
+ // Regular file - copy as template
133
+ this . fs . copyTpl (
134
+ inputFullPath ,
135
+ this . destinationPath ( outputFn ) ,
136
+ this . _answers
137
+ ) ;
138
+ }
139
+ }
87
140
} ) ;
88
141
}
89
142
@@ -125,5 +178,34 @@ function assertNpmVersionIsAtLeast(minVersion: string) {
125
178
}
126
179
}
127
180
181
+ function rewritePackageJson ( contents , includeTests ) {
182
+ if ( ! includeTests ) {
183
+ // Delete any test-specific packages from dependencies and devDependencies
184
+ [ 'dependencies' , 'devDependencies' ] . forEach ( dependencyListName => {
185
+ var packageList = contents [ dependencyListName ] ;
186
+ if ( packageList ) {
187
+ testSpecificNpmPackages . forEach ( packageToRemove => {
188
+ delete packageList [ packageToRemove ] ;
189
+ } ) ;
190
+
191
+ if ( Object . getOwnPropertyNames ( packageList ) . length === 0 ) {
192
+ delete contents [ dependencyListName ] ;
193
+ }
194
+ }
195
+ } ) ;
196
+
197
+ // Delete any script called 'test'
198
+ const scripts = contents . scripts ;
199
+ if ( scripts . test ) {
200
+ delete scripts . test ;
201
+ if ( Object . getOwnPropertyNames ( scripts ) . length === 0 ) {
202
+ delete contents . scripts ;
203
+ }
204
+ }
205
+ }
206
+
207
+ return contents ;
208
+ }
209
+
128
210
declare var module : any ;
129
211
( module ) . exports = MyGenerator ;
0 commit comments