1+ import * as fs from 'fs' ;
12import * as path from 'path' ;
23import * as yeoman from 'yeoman-generator' ;
34import * as uuid from 'node-uuid' ;
@@ -9,15 +10,35 @@ const yosay = require('yosay');
910const toPascalCase = require ( 'to-pascal-case' ) ;
1011const isWindows = / ^ w i n / . test ( process . platform ) ;
1112
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+
1233type YeomanPrompt = ( opt : yeoman . IPromptOptions | yeoman . IPromptOptions [ ] , callback : ( answers : any ) => void ) => void ;
1334const optionOrPrompt : YeomanPrompt = require ( 'yeoman-option-or-prompt' ) ;
1435
1536const 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 }
2142] ;
2243
2344class MyGenerator extends yeoman . Base {
@@ -35,24 +56,40 @@ class MyGenerator extends yeoman.Base {
3556 }
3657
3758 prompting ( ) {
38- const done = this . async ( ) ;
39-
4059 this . option ( 'projectguid' ) ;
60+
61+ const done = this . async ( ) ;
4162 this . _optionOrPrompt ( [ {
4263 type : 'list' ,
4364 name : 'framework' ,
4465 message : 'Framework' ,
4566 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+ } ) ;
5693 } ) ;
5794 }
5895
@@ -79,11 +116,27 @@ class MyGenerator extends yeoman.Base {
79116 outputFn = path . join ( path . dirname ( fn ) , 'node_modules' , '_placeholder.txt' ) ;
80117 }
81118
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+ }
87140 } ) ;
88141 }
89142
@@ -125,5 +178,34 @@ function assertNpmVersionIsAtLeast(minVersion: string) {
125178 }
126179}
127180
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+
128210declare var module : any ;
129211( module ) . exports = MyGenerator ;
0 commit comments