1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node --harmony
2
2
'use-strict' ;
3
3
4
+ const path = require ( 'path' ) ;
5
+ const fs = require ( 'fs' ) ;
4
6
const program = require ( 'commander' ) ;
7
+ const co = require ( 'co' ) ;
8
+ const prompt = require ( 'co-prompt' ) ;
9
+ const nodegit = require ( 'nodegit' ) ;
10
+ const del = require ( 'del' ) ;
11
+ const ncp = require ( 'ncp' ) . ncp ;
12
+ const fetch = require ( 'node-fetch' ) ;
13
+ const pkg = require ( './package.json' ) ;
5
14
6
15
const defaultArgs = {
7
- themename : 'WP Theme' ,
8
- themeuri : 'https://github.com/dreamsicle-io/create-wp-theme' ,
9
- themeversion : '0.0.1' ,
10
- themedescription : 'This theme was generated using "create-wp-theme".' ,
11
- author : 'Dreamsicle' ,
12
- authoruri : 'https://www.dreamsicle.io' ,
13
- license : 'GPL-3.0' ,
14
- textdomain : 'wp-theme' ,
15
- tags : 'accessibility-ready, translation-ready' ,
16
+ themeName : 'WP Theme' ,
17
+ themeTextDomain : 'wp-theme' ,
18
+ themeVersion : '0.0.1' ,
19
+ themeTemplate : '' ,
20
+ themeURI : 'https://github.com/dreamsicle-io/create-wp-theme' ,
21
+ themeBugsURI : 'https://github.com/dreamsicle-io/create-wp-theme/issues' ,
22
+ themeRepoURI : 'https://github.com/dreamsicle-io/create-wp-theme.git' ,
23
+ themeRepoType : 'git' ,
24
+ themeDescription : 'This theme was generated using create-wp-theme.' ,
25
+ themeAuthor : 'Dreamsicle' ,
26
+ themeAuthorEmail : 'hello@dreamsicle.io' ,
27
+ themeAuthorURI : 'https://www.dreamsicle.io' ,
28
+ themeLicense : 'GPL-3.0' ,
29
+ themeTags : 'accessibility-ready, translation-ready' ,
30
+ wpVersionRequired : '4.9.8' ,
31
+ wpVersionTested : '4.9.8' ,
32
+ } ;
33
+
34
+ const argTypes = {
35
+ themeName : 'name' ,
36
+ themeTextDomain : 'textdomain' ,
37
+ themeVersion : 'version' ,
38
+ themeTemplate : 'theme' ,
39
+ themeURI : 'uri' ,
40
+ themeBugsURI : 'uri' ,
41
+ themeRepoURI : 'uri' ,
42
+ themeRepoType : 'type' ,
43
+ themeDescription : 'description' ,
44
+ themeAuthor : 'name' ,
45
+ themeAuthorEmail : 'email' ,
46
+ themeAuthorURI : 'uri' ,
47
+ themeLicense : 'spdx' ,
48
+ themeTags : 'tags' ,
49
+ wpVersionRequired : 'version' ,
50
+ wpVersionTested : 'version' ,
51
+ } ;
52
+
53
+ const argTitles = {
54
+ themeName : 'Theme Name' ,
55
+ themeTextDomain : 'Text Domain' ,
56
+ themeVersion : 'Version' ,
57
+ themeTemplate : 'Template' ,
58
+ themeURI : 'Theme URI' ,
59
+ themeBugsURI : 'Theme Bugs URI' ,
60
+ themeRepoURI : 'Theme Repository URI' ,
61
+ themeRepoType : 'Theme Repository Type' ,
62
+ themeDescription : 'Description' ,
63
+ themeAuthor : 'Author' ,
64
+ themeAuthorEmail : 'Author Email' ,
65
+ themeAuthorURI : 'Author URI' ,
66
+ themeLicense : 'License' ,
67
+ themeTags : 'Tags' ,
68
+ wpVersionRequired : 'WP Version Required' ,
69
+ wpVersionTested : 'WP Version Tested' ,
16
70
} ;
17
71
18
72
const argDescriptions = {
19
- themename : 'The theme name.' ,
20
- themeuri : 'The theme URI.' ,
21
- themeversion : 'The theme version.' ,
22
- themedescription : 'The theme description' ,
23
- author : 'The theme author.' ,
24
- authoruri : 'The theme author URI.' ,
25
- license : 'The theme license as a valid SPDX expression.' ,
26
- textdomain : 'The theme text domain.' ,
27
- tags : 'A comma separated list of valid WordPress theme repository tags.' ,
73
+ themeName : 'The theme name' ,
74
+ themeTextDomain : 'The theme text domain' ,
75
+ themeVersion : 'The theme version' ,
76
+ themeTemplate : 'The parent theme if this is a child theme' ,
77
+ themeURI : 'The theme URI' ,
78
+ themeBugsURI : 'The theme bugs URI' ,
79
+ themeRepoURI : 'The theme repository URI' ,
80
+ themeRepoType : 'The theme repository type' ,
81
+ themeDescription : 'The theme description' ,
82
+ themeAuthor : 'The theme author' ,
83
+ themeAuthorEmail : 'The theme author email' ,
84
+ themeAuthorURI : 'The theme author URI' ,
85
+ themeLicense : 'The theme license as a valid SPDX expression' ,
86
+ themeTags : 'A CSV of WordPress theme tags' ,
87
+ wpVersionRequired : 'The version of WordPress the theme requires' ,
88
+ wpVersionTested : 'The version of WordPress the theme has been tested up to' ,
28
89
} ;
29
90
30
91
const argAliases = {
31
- themename : 'tn' ,
32
- themeuri : 'tu' ,
33
- themeversion : 'tv' ,
34
- themedescription : 'td' ,
35
- author : 'a' ,
36
- authoruri : 'au' ,
37
- license : 'l' ,
38
- textdomain : 'td' ,
39
- tags : 't' ,
92
+ themeName : 'N' ,
93
+ themeTextDomain : 'D' ,
94
+ themeVersion : 'X' ,
95
+ themeTemplate : 'T' ,
96
+ themeURI : 'U' ,
97
+ themeBugsURI : 'B' ,
98
+ themeRepoURI : 'R' ,
99
+ themeRepoType : 'r' ,
100
+ themeDescription : 'd' ,
101
+ themeAuthor : 'A' ,
102
+ themeAuthorEmail : 'E' ,
103
+ themeAuthorURI : 'u' ,
104
+ themeLicense : 'L' ,
105
+ themeTags : 't' ,
106
+ wpVersionRequired : 'W' ,
107
+ wpVersionTested : 'w' ,
40
108
} ;
41
109
42
110
const requiredArgs = [
43
- 'themename ' ,
44
- 'textdomain ' ,
111
+ 'themeName ' ,
112
+ 'themeTextDomain ' ,
45
113
] ;
46
114
115
+ program . name ( getCommandName ( ) ) ;
116
+ program . version ( pkg . version ) ;
47
117
program . arguments ( '<file>' ) ;
48
118
49
119
for ( var key in defaultArgs ) {
50
120
const defaultValue = defaultArgs [ key ] ;
51
121
const alias = argAliases [ key ] ;
52
122
const description = argDescriptions [ key ] ;
53
123
const isRequired = ( requiredArgs . indexOf ( key ) !== - 1 ) ;
54
- program . option ( '-' + alias + ', --' + key + ' <' + key + '>' , description ) ;
124
+ const argType = argTypes [ key ] ;
125
+ const type = isRequired ? '<' + argType + '>' : '[' + argType + ']' ;
126
+ program . option ( '-' + alias + ', --' + key + ' ' + type , description , defaultValue ) ;
55
127
}
56
128
57
129
program . parse ( process . argv ) ;
58
130
59
- const args = defaultArgs ;
60
- for ( var key in defaultArgs ) {
61
- if ( program [ key ] ) {
62
- args [ key ] = program [ key ] ;
131
+ const repoPath = 'https://github.com/dreamsicle-io/wp-theme-assets.git' ;
132
+ const tmpPath = path . join ( __dirname , 'tmp' ) ;
133
+ const tmpThemePath = path . join ( tmpPath , 'package' ) ;
134
+ const tmpThemePkgPath = path . join ( tmpThemePath , 'package.json' ) ;
135
+ const tmpThemePkgLockPath = path . join ( tmpThemePath , 'package-lock.json' ) ;
136
+ const tmpThemeLicPath = path . join ( tmpThemePath , 'LICENSE' ) ;
137
+ const themeDirName = program . args [ 0 ] ;
138
+ const themePath = path . join ( process . cwd ( ) , themeDirName ) ;
139
+ const cloneOptions = {
140
+ fetchOpts : {
141
+ callbacks : {
142
+ // This is a required callback for OS X machines. There is a known issue
143
+ // with libgit2 being able to verify certificates from GitHub.
144
+ certificateCheck : function ( ) { return 1 ; }
145
+ }
146
+ }
147
+ } ;
148
+
149
+ function pathExists ( path = '' ) {
150
+ var exists = true ;
151
+ try {
152
+ fs . statSync ( path ) ;
153
+ } catch ( error ) {
154
+ exists = false ;
155
+ }
156
+ return exists ;
157
+ }
158
+
159
+ function getCommandName ( ) {
160
+ var cmd = pkg . name ;
161
+ if ( pkg . bin ) {
162
+ for ( var key in pkg . bin ) {
163
+ cmd = key ;
164
+ break ;
165
+ }
63
166
}
167
+ return cmd ;
64
168
}
65
169
66
- console . log ( args ) ;
170
+ function putPackage ( args = null ) {
171
+ ncp ( tmpThemePath , themePath , function ( error ) {
172
+ if ( error ) {
173
+ console . error ( error ) ;
174
+ process . exit ( ) ;
175
+ } else {
176
+ console . info ( 'Theme copied: ' + themePath ) ;
177
+ del ( [ tmpPath ] , { force : true } )
178
+ . then ( function ( paths ) {
179
+ if ( paths . length > 0 ) {
180
+ console . info ( 'Repo cleaned: ' + paths . join ( ', ' ) ) ;
181
+ }
182
+ console . info ( '\nTheme created: ' + args . themeName + ' in ' + themePath ) ;
183
+ process . exit ( ) ;
184
+ } ) . catch ( function ( error ) {
185
+ console . error ( error ) ;
186
+ process . exit ( ) ;
187
+ } ) ;
188
+ }
189
+ } ) ;
190
+ }
191
+
192
+ function writeLicense ( args = null ) {
193
+ fetch ( 'https://api.github.com/licenses/' + encodeURIComponent ( args . themeLicense . toLowerCase ( ) ) )
194
+ . then ( function ( response ) {
195
+ if ( response . status === 200 ) {
196
+ return response . json ( ) ;
197
+ } else {
198
+ throw new Error ( 'License not found: ' + args . themeLicense ) ;
199
+ }
200
+ } ) . then ( function ( data ) {
201
+ console . info ( 'License fetched: ' + data . name ) ;
202
+ fs . writeFile ( tmpThemeLicPath , data . body , function ( error ) {
203
+ if ( error ) {
204
+ console . error ( error ) ;
205
+ process . exit ( ) ;
206
+ } else {
207
+ console . info ( 'License written: ' + tmpThemeLicPath ) ;
208
+ putPackage ( args ) ;
209
+ }
210
+ } ) ;
211
+ } ) . catch ( function ( error ) {
212
+ console . info ( error . message ) ;
213
+ putPackage ( args ) ;
214
+ } ) ;
215
+ }
216
+
217
+ function writePackage ( args = null ) {
218
+ del ( [ tmpThemePkgLockPath ] , { force : true } )
219
+ . then ( function ( paths ) {
220
+ if ( paths . length > 0 ) {
221
+ console . info ( 'package-lock.json cleaned: ' + paths . join ( ', ' ) ) ;
222
+ }
223
+ fs . readFile ( tmpThemePkgPath , function ( error , data ) {
224
+ if ( error ) {
225
+ console . error ( error ) ;
226
+ process . exit ( ) ;
227
+ } else {
228
+ themePkg = JSON . parse ( data ) ;
229
+ themePkg . name = themeDirName ;
230
+ themePkg . version = args . themeVersion ;
231
+ themePkg . description = args . themeDescription ;
232
+ themePkg . keywords = args . themeTags ? args . themeTags . split ( ',' ) . map ( function ( tag ) { return tag . trim ( ) ; } ) : [ ] ;
233
+ themePkg . author = {
234
+ name : args . themeAuthor ,
235
+ email : args . themeAuthorEmail ,
236
+ url : args . themeAuthorURI ,
237
+ } ;
238
+ themePkg . license = args . themeLicense ;
239
+ themePkg . wordpress = {
240
+ versionRequired : args . wpVersionRequired ,
241
+ versionTested : args . wpVersionTested ,
242
+ } ;
243
+ themePkg . bugs = {
244
+ url : args . themeBugsURI ,
245
+ } ;
246
+ themePkg . homepage = args . themeURI ;
247
+ themePkg . repository = {
248
+ type : args . themeRepoType ,
249
+ url : args . themeRepoURI ,
250
+ } ;
251
+ fs . writeFile ( tmpThemePkgPath , JSON . stringify ( themePkg , null , '\t' ) , function ( error ) {
252
+ if ( error ) {
253
+ console . error ( error ) ;
254
+ process . exit ( ) ;
255
+ } else {
256
+ console . info ( 'package.json written: ' + tmpThemePkgPath ) ;
257
+ writeLicense ( args ) ;
258
+ }
259
+ } ) ;
260
+ }
261
+ } ) ;
262
+ } ) . catch ( function ( error ) {
263
+ console . error ( error ) ;
264
+ process . exit ( ) ;
265
+ } ) ;
266
+ }
267
+
268
+ function clonePackage ( args = null ) {
269
+ del ( [ tmpPath ] , { force : true } )
270
+ . then ( function ( paths ) {
271
+ if ( paths . length > 0 ) {
272
+ console . info ( 'Repo cleaned: ' + paths . join ( ', ' ) ) ;
273
+ }
274
+ nodegit . Clone ( repoPath , tmpPath , cloneOptions )
275
+ . then ( function ( repo ) {
276
+ console . info ( 'Repo cloned: ' + repoPath + ' --> ' + tmpPath ) ;
277
+ writePackage ( args ) ;
278
+ } ) . catch ( function ( error ) {
279
+ console . error ( error ) ;
280
+ process . exit ( ) ;
281
+ } ) ;
282
+ } )
283
+ . catch ( function ( error ) {
284
+ console . error ( error ) ;
285
+ process . exit ( ) ;
286
+ } ) ;
287
+ }
288
+
289
+ co ( function * ( ) {
290
+ if ( pathExists ( themePath ) ) {
291
+ console . log ( '\nPath already exists: ' + themePath ) ;
292
+ process . exit ( ) ;
293
+ }
294
+ console . info ( '\nThe following tool will help you configure your new theme.\nFor each setting, set a value and hit "Enter" to continue.\n' ) ;
295
+ var values = defaultArgs ;
296
+ for ( var key in defaultArgs ) {
297
+ const promptValue = yield prompt ( argTitles [ key ] + ': (' + program [ key ] + ') ' ) ;
298
+ if ( promptValue || program [ key ] ) {
299
+ values [ key ] = promptValue || program [ key ] ;
300
+ }
301
+ }
302
+ return values ;
303
+ } ) . then ( function ( args ) {
304
+ console . info ( '\nCreating theme: ' + args . themeName + ' in ' + themePath + '\n' ) ;
305
+ clonePackage ( args ) ;
306
+ } , function ( error ) {
307
+ console . error ( error ) ;
308
+ process . exit ( ) ;
309
+ } ) ;
0 commit comments