1
1
import * as path from "path" ;
2
- import { HtmlGenerator } from "../html" ;
2
+ import { HtmlGenerator , WebAppName } from "../html" ;
3
3
import { Answers } from "yeoman-generator" ;
4
4
5
+ /**
6
+ * Interface the contains the address of a registry and the corresponding available channels
7
+ */
8
+ interface RegistryChannels {
9
+ /**
10
+ * Address of the registry
11
+ */
12
+ registry : string ,
13
+ /**
14
+ * Available channels
15
+ */
16
+ channels : string [ ] | null ;
17
+ }
18
+
5
19
export = class extends HtmlGenerator {
6
20
7
21
packagePrefix : string ;
@@ -24,29 +38,31 @@ export = class extends HtmlGenerator {
24
38
{
25
39
type : "input" ,
26
40
name : "packagePrefix" ,
27
- message : "Please specify the client's prefix (example: cmf ) " ,
41
+ message : "Please specify the client's prefix (example: customization ) " ,
28
42
default : null ,
29
43
validate : ( input : string , answers : Answers ) : boolean => {
30
44
return typeof input === "string" && ! ! input && input !== "cmf" ;
31
45
} ,
32
46
store : true
33
- } ,
34
- {
35
- type : "input" ,
36
- name : "registry" ,
37
- message : "What is your npm registry endpoint? " ,
38
- store : true
39
- } ,
40
- {
41
- type : "input" ,
42
- name : "channel" ,
43
- message : "What is the channel you want to use?" ,
44
- store : true
45
47
}
46
- ] ) . then ( ( answers ) => {
47
- this . packagePrefix = answers . packagePrefix ;
48
- this . registry = answers . registry ;
49
- this . channel = answers . channel ;
48
+ ] ) . then ( ( prefixAnswers ) => {
49
+ this . packagePrefix = prefixAnswers . packagePrefix ;
50
+ // Get the registry endpoint
51
+ return this . _promptForRegistry ( )
52
+ . then ( ( registryChannels ) => {
53
+ this . registry = registryChannels . registry ;
54
+ let options : string [ ] | null = null ;
55
+ // If there are channels, use them on the prompt for channel
56
+ if ( registryChannels != null && registryChannels . channels != null ) {
57
+ options = registryChannels . channels ;
58
+ options . push ( "other" ) ;
59
+ }
60
+ // Get the channel
61
+ return this . _promptForChannel ( options )
62
+ . then ( ( channel ) => {
63
+ this . channel = channel ;
64
+ } ) ;
65
+ } )
50
66
} ) ;
51
67
}
52
68
@@ -68,4 +84,164 @@ export = class extends HtmlGenerator {
68
84
this . config . set ( "isRoot" , true ) ;
69
85
this . config . save ( ) ;
70
86
}
87
+
88
+ /**
89
+ * Utility method to prompt the user for channel
90
+ * @param options Available channels from the user to choose from
91
+ * @returns String containing the chosen channel
92
+ */
93
+ private _promptForChannel ( options : string [ ] | null ) : Promise < string > {
94
+ // Prompt for the user to select a channel from the list
95
+ if ( options != null && options . length > 0 ) {
96
+ return this . prompt ( [
97
+ {
98
+ type : "list" ,
99
+ name : "channel" ,
100
+ message : "What channel from the available channels do you want to use?" ,
101
+ choices : options
102
+ } ,
103
+ ] ) . then ( ( listAnswers ) => {
104
+ if ( listAnswers . channel === "other" ) {
105
+ return this . _promptForChannel ( null ) ;
106
+ } else {
107
+ return listAnswers . channel ;
108
+ }
109
+ } )
110
+ } else {
111
+ // Prompt for the user to input a channel
112
+ return this . prompt ( [
113
+ {
114
+ type : "input" ,
115
+ name : "channel" ,
116
+ message : "What is the channel you want to use?" ,
117
+ validate : ( input : string , answers : Answers ) : boolean => {
118
+ return typeof input === "string" && ! ! input ;
119
+ } ,
120
+ store : true
121
+ }
122
+ ] ) . then ( ( channelAnswer ) => {
123
+ return channelAnswer . channel ;
124
+ } ) ;
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Utility method to ask the user to supply a channel
130
+ * @returns Registry and channel, if any
131
+ */
132
+ _promptForRegistry ( ) : Promise < RegistryChannels > {
133
+ return this . prompt ( [
134
+ {
135
+ type : "input" ,
136
+ name : "registry" ,
137
+ message : "What is your npm registry endpoint? " ,
138
+ validate : ( input : string , answers : Answers ) : boolean => {
139
+ return typeof input === "string" && ! ! input ;
140
+ } ,
141
+ store : true
142
+ } ,
143
+ ] ) . then ( ( answers ) => {
144
+ // Get the available channels and check that we can connect
145
+ const registryChannels = this . _getChannelsFromRegistry ( answers . registry ) ;
146
+ if ( registryChannels != null && registryChannels . channels != null && registryChannels . channels . length > 0 ) {
147
+ return registryChannels ;
148
+ } else {
149
+ return this . prompt ( {
150
+ type : "input" ,
151
+ name : "confirmSkip" ,
152
+ message : "Registry was not found, do you wish to continue anyway? (y/n)" ,
153
+ validate : ( input : string , answers : Answers ) : boolean => {
154
+ return typeof input === "string" && ! ! input ;
155
+ } ,
156
+ store : false
157
+ } ) . then ( ( confirmAnswers ) => {
158
+ if ( confirmAnswers . confirmSkip === "y" || confirmAnswers . confirmSkip === "yes" || confirmAnswers . confirmSkip === "Y" || confirmAnswers . confirmSkip === "YES" ) {
159
+ return < RegistryChannels > {
160
+ registry : answers . registry ,
161
+ channels : null
162
+ }
163
+ } else {
164
+ return this . _promptForRegistry ( ) ;
165
+ }
166
+ } )
167
+ }
168
+ } ) ;
169
+ }
170
+
171
+ /**
172
+ * Retrieves the available channel by calling npm info for the given registry
173
+ * @param registry registry endpoint
174
+ * @returns Registry and available channels, if any
175
+ */
176
+ private _getChannelsFromRegistry ( registry : string ) : RegistryChannels {
177
+ try {
178
+ const result = this . spawnCommandSync ( "npm" , [ "info" , WebAppName . MES , `--registry=${ registry } ` , `--fetch-retry-maxtimeout=10` , `--fetch-retry-mintimeout=5` , "--json" ] , { stdio : 'pipe' } ) ;
179
+ if ( result != null && result . stdout != null ) {
180
+ const json = this . _Utf8ArrayToStr ( result . stdout )
181
+ if ( json != null ) {
182
+ const packageJson = JSON . parse ( json ) ;
183
+ if ( packageJson != null && packageJson [ "dist-tags" ] != null ) {
184
+ const channels = Object . keys ( packageJson [ "dist-tags" ] ) ;
185
+ return < RegistryChannels > {
186
+ registry : registry ,
187
+ channels : channels
188
+ }
189
+ }
190
+ }
191
+ }
192
+ } catch ( e ) {
193
+ return < RegistryChannels > {
194
+ registry : registry ,
195
+ channels : null
196
+ }
197
+ }
198
+
199
+ return < RegistryChannels > {
200
+ registry : registry ,
201
+ channels : null
202
+ }
203
+ }
204
+
205
+
206
+ /* utf.js - UTF-8 <=> UTF-16 conversion
207
+ *
208
+ * http://www.onicos.com/staff/iz/amuse/javascript/expert/utf.txt
209
+ * Copyright (C) 1999 Masanao Izumo <[email protected] >
210
+ * Version: 1.0
211
+ * LastModified: Dec 25 1999
212
+ * This library is free. You can redistribute it and/or modify it.
213
+ */
214
+ private _Utf8ArrayToStr ( array ) {
215
+ var out , i , len , c ;
216
+ var char2 , char3 ;
217
+
218
+ out = "" ;
219
+ len = array . length ;
220
+ i = 0 ;
221
+ while ( i < len ) {
222
+ c = array [ i ++ ] ;
223
+ switch ( c >> 4 )
224
+ {
225
+ case 0 : case 1 : case 2 : case 3 : case 4 : case 5 : case 6 : case 7 :
226
+ // 0xxxxxxx
227
+ out += String . fromCharCode ( c ) ;
228
+ break ;
229
+ case 12 : case 13 :
230
+ // 110x xxxx 10xx xxxx
231
+ char2 = array [ i ++ ] ;
232
+ out += String . fromCharCode ( ( ( c & 0x1F ) << 6 ) | ( char2 & 0x3F ) ) ;
233
+ break ;
234
+ case 14 :
235
+ // 1110 xxxx 10xx xxxx 10xx xxxx
236
+ char2 = array [ i ++ ] ;
237
+ char3 = array [ i ++ ] ;
238
+ out += String . fromCharCode ( ( ( c & 0x0F ) << 12 ) |
239
+ ( ( char2 & 0x3F ) << 6 ) |
240
+ ( ( char3 & 0x3F ) << 0 ) ) ;
241
+ break ;
242
+ }
243
+ }
244
+
245
+ return out ;
246
+ }
71
247
}
0 commit comments