1
- ' use strict' ;
1
+ " use strict" ;
2
2
3
- const validateProjectName = require ( 'validate-npm-package-name' ) ;
4
- const chalk = require ( 'chalk' ) ;
5
- const commander = require ( 'commander' ) ;
6
- const path = require ( 'path' ) ;
3
+ const validateProjectName = require ( "validate-npm-package-name" ) ;
4
+ const chalk = require ( "chalk" ) ;
5
+ const semver = require ( "semver" ) ;
6
+ const spawn = require ( 'cross-spawn' ) ;
7
+ const commander = require ( "commander" ) ;
8
+ const fs = require ( "fs-extra" ) ;
9
+ const path = require ( "path" ) ;
7
10
8
- const packageJson = require ( ' ./package.json' ) ;
11
+ const packageJson = require ( " ./package.json" ) ;
9
12
10
13
let projectName ;
11
14
12
15
const program = new commander . Command ( packageJson . name )
13
16
. version ( packageJson . version )
14
- . arguments ( ' <project-directory>' )
15
- . usage ( `${ chalk . green ( ' <project-directory>' ) } ` )
17
+ . arguments ( " <project-directory>" )
18
+ . usage ( `${ chalk . green ( " <project-directory>" ) } ` )
16
19
. action ( name => {
17
20
projectName = name ;
18
21
} )
19
- . on ( ' --help' , ( ) => {
20
- console . log ( ` Only ${ chalk . green ( ' <project-directory>' ) } is required.` ) ;
22
+ . on ( " --help" , ( ) => {
23
+ console . log ( ` Only ${ chalk . green ( " <project-directory>" ) } is required.` ) ;
21
24
console . log ( ) ;
22
25
} )
23
- . parse ( process . argv ) ;
26
+ . parse ( process . argv ) ;
27
+
28
+ if ( typeof projectName === "undefined" ) {
29
+ console . error ( "Please specify the project directory:" ) ;
30
+ console . log (
31
+ ` ${ chalk . cyan ( program . name ( ) ) } ${ chalk . green ( "<project-directory>" ) } `
32
+ ) ;
33
+ console . log ( ) ;
34
+ console . log ( "For example:" ) ;
35
+ console . log (
36
+ ` ${ chalk . cyan ( program . name ( ) ) } ${ chalk . green ( "my-typescript-lib" ) } `
37
+ ) ;
38
+ console . log ( ) ;
39
+ console . log (
40
+ `Run ${ chalk . cyan ( `${ program . name ( ) } --help` ) } to see all options.`
41
+ ) ;
42
+ process . exit ( 1 ) ;
43
+ }
44
+
45
+ createApp ( projectName ) ;
46
+
47
+ function createApp ( name ) {
48
+ const root = path . resolve ( name ) ;
49
+ const appName = path . basename ( root ) ;
50
+
51
+ checkAppName ( appName ) ;
52
+ fs . ensureDirSync ( name ) ;
53
+ if ( ! isSafeToCreateProjectIn ( root , name ) ) {
54
+ process . exit ( 1 ) ;
55
+ }
56
+
57
+ console . log ( `Creating a new TypeScript library in ${ chalk . green ( root ) } .` ) ;
58
+ console . log ( ) ;
59
+
60
+ const originalDirectory = process . cwd ( ) ;
61
+ process . chdir ( root ) ;
62
+
63
+ if ( ! semver . satisfies ( process . version , ">=6.0.0" ) ) {
64
+ console . log (
65
+ chalk . yellow (
66
+ `You are using Node ${ process . version } so the project will be bootstrapped with an old unsupported version of tools.\n\n` +
67
+ `Please update to Node 6 or higher for a better, fully supported experience.\n`
68
+ )
69
+ ) ;
70
+ }
71
+
72
+ const npmInfo = checkNpmVersion ( ) ;
73
+ if ( ! npmInfo . hasMinNpm ) {
74
+ if ( npmInfo . npmVersion ) {
75
+ console . log (
76
+ chalk . yellow (
77
+ `You are using npm ${ npmInfo . npmVersion } so the project will be boostrapped with an old unsupported version of tools.\n\n` +
78
+ `Please update to npm 3 or higher for a better, fully supported experience.\n`
79
+ )
80
+ ) ;
81
+ }
82
+ }
83
+ run ( root , appName , originalDirectory ) ;
84
+ }
85
+
86
+ function run ( root , appName , originalDirectory ) {
87
+ console . log ( "debug creating library " , root , appName , originalDirectory ) ;
88
+ const templatePath = path . resolve ( __dirname , "template" ) ;
89
+ if ( fs . existsSync ( templatePath ) ) {
90
+ fs . copySync ( templatePath , root ) ;
91
+ let packageJsonPath = path . join ( root , "package.json" ) ;
92
+ let packageJson = require ( packageJsonPath ) ;
93
+ packageJson . name = appName ;
94
+ packageJson . version = "0.0.1" ;
95
+
96
+ fs . writeFileSync (
97
+ packageJsonPath ,
98
+ JSON . stringify ( packageJson , null , 2 )
99
+ ) ;
100
+ console . log ( 'Installing packages. This might take a couple of minutes.' ) ;
101
+ return install ( ) ;
102
+ } else {
103
+ console . error (
104
+ `Could not locate supplied template: ${ chalk . green ( templatePath ) } `
105
+ ) ;
106
+ return ;
107
+ }
108
+ }
109
+
110
+ function install ( ) {
111
+ return new Promise ( ( resolve , reject ) => {
112
+ let command ;
113
+ let args ;
114
+
115
+ command = 'npm' ;
116
+ args = [
117
+ 'install' ,
118
+ '--save' ,
119
+ '--save-exact' ,
120
+ '--loglevel' ,
121
+ 'error' ,
122
+ ] ;
123
+
124
+ const child = spawn ( command , args , { stdio : 'inherit' } ) ;
125
+ child . on ( 'close' , code => {
126
+ if ( code !== 0 ) {
127
+ reject ( {
128
+ command : `${ command } ${ args . join ( ' ' ) } ` ,
129
+ } ) ;
130
+ return ;
131
+ }
132
+ resolve ( ) ;
133
+ } ) ;
134
+ } ) ;
135
+ }
136
+
137
+ function getInstallPackage ( version ) {
138
+ let packageToInstall = "react-scripts" ;
139
+ const validSemver = semver . valid ( version ) ;
140
+ if ( validSemver ) {
141
+ packageToInstall += `@${ validSemver } ` ;
142
+ } else if ( version ) {
143
+ // for tar.gz or alternative paths
144
+ packageToInstall = version ;
145
+ }
146
+ return packageToInstall ;
147
+ }
148
+
149
+ function checkAppName ( appName ) {
150
+ const validationResult = validateProjectName ( appName ) ;
151
+ if ( ! validationResult . validForNewPackages ) {
152
+ console . error (
153
+ `Could not create a project called ${ chalk . red (
154
+ `"${ appName } "`
155
+ ) } because of npm naming restrictions:`
156
+ ) ;
157
+ printValidationResults ( validationResult . errors ) ;
158
+ printValidationResults ( validationResult . warnings ) ;
159
+ process . exit ( 1 ) ;
160
+ }
161
+ }
162
+
163
+ function printValidationResults ( results ) {
164
+ if ( typeof results !== "undefined" ) {
165
+ results . forEach ( error => {
166
+ console . error ( chalk . red ( ` * ${ error } ` ) ) ;
167
+ } ) ;
168
+ }
169
+ }
170
+
171
+ function isSafeToCreateProjectIn ( root , name ) {
172
+ const validFiles = [
173
+ ".DS_Store" ,
174
+ "Thumbs.db" ,
175
+ ".git" ,
176
+ ".gitignore" ,
177
+ ".idea" ,
178
+ "README.md" ,
179
+ "LICENSE" ,
180
+ "web.iml" ,
181
+ ".hg" ,
182
+ ".hgignore" ,
183
+ ".hgcheck"
184
+ ] ;
185
+ console . log ( ) ;
186
+
187
+ const conflicts = fs
188
+ . readdirSync ( root )
189
+ . filter ( file => ! validFiles . includes ( file ) ) ;
190
+ if ( conflicts . length < 1 ) {
191
+ return true ;
192
+ }
193
+
194
+ console . log (
195
+ `The directory ${ chalk . green ( name ) } contains files that could conflict:`
196
+ ) ;
197
+ console . log ( ) ;
198
+ for ( const file of conflicts ) {
199
+ console . log ( ` ${ file } ` ) ;
200
+ }
201
+ console . log ( ) ;
202
+ console . log (
203
+ "Either try using a new directory name, or remove the files listed above."
204
+ ) ;
205
+
206
+ return false ;
207
+ }
208
+
209
+ function checkNpmVersion ( ) {
210
+ let hasMinNpm = false ;
211
+ let npmVersion = null ;
212
+ try {
213
+ npmVersion = execSync ( "npm --version" ) . toString ( ) . trim ( ) ;
214
+ hasMinNpm = semver . gte ( npmVersion , "3.0.0" ) ;
215
+ } catch ( err ) {
216
+ // ignore
217
+ }
218
+ return {
219
+ hasMinNpm : hasMinNpm ,
220
+ npmVersion : npmVersion
221
+ } ;
222
+ }
0 commit comments