@@ -4,16 +4,12 @@ exports.quote = function (xs) {
4
4
return xs . map ( function ( s ) {
5
5
if ( s && typeof s === 'object' ) {
6
6
return s . op . replace ( / ( .) / g, '\\$1' ) ;
7
- }
8
- else if ( / [ " \s ] / . test ( s ) && ! / ' / . test ( s ) ) {
7
+ } else if ( ( / [ " \s ] / ) . test ( s ) && ! ( / ' / ) . test ( s ) ) {
9
8
return "'" + s . replace ( / ( [ ' \\ ] ) / g, '\\$1' ) + "'" ;
10
- }
11
- else if ( / [ " ' \s ] / . test ( s ) ) {
9
+ } else if ( ( / [ " ' \s ] / ) . test ( s ) ) {
12
10
return '"' + s . replace ( / ( [ " \\ $ ` ! ] ) / g, '\\$1' ) + '"' ;
13
11
}
14
- else {
15
- return String ( s ) . replace ( / ( [ A - Z a - z ] : ) ? ( [ # ! " $ & ' ( ) * , : ; < = > ? @ \[ \\ \] ^ ` { | } ] ) / g, '$1\\$2' ) ;
16
- }
12
+ return String ( s ) . replace ( / ( [ A - Z a - z ] : ) ? ( [ # ! " $ & ' ( ) * , : ; < = > ? @ [ \\ \] ^ ` { | } ] ) / g, '$1\\$2' ) ;
17
13
} ) . join ( ' ' ) ;
18
14
} ;
19
15
@@ -32,50 +28,56 @@ for (var i = 0; i < 4; i++) {
32
28
TOKEN += ( Math . pow ( 16 , 8 ) * Math . random ( ) ) . toString ( 16 ) ;
33
29
}
34
30
35
- exports . parse = function ( s , env , opts ) {
36
- var mapped = parse ( s , env , opts ) ;
37
- if ( typeof env !== 'function' ) return mapped ;
38
- return mapped . reduce ( function ( acc , s ) {
39
- if ( typeof s === 'object' ) return acc . concat ( s ) ;
40
- var xs = s . split ( RegExp ( '(' + TOKEN + '.*?' + TOKEN + ')' , 'g' ) ) ;
41
- if ( xs . length === 1 ) return acc . concat ( xs [ 0 ] ) ;
42
- return acc . concat ( xs . filter ( Boolean ) . map ( function ( x ) {
43
- if ( RegExp ( '^' + TOKEN ) . test ( x ) ) {
44
- return JSON . parse ( x . split ( TOKEN ) [ 1 ] ) ;
45
- }
46
- else return x ;
47
- } ) ) ;
48
- } , [ ] ) ;
49
- } ;
50
-
51
31
function parse ( s , env , opts ) {
52
32
var chunker = new RegExp ( [
53
33
'(' + CONTROL + ')' , // control chars
54
34
'(' + BAREWORD + '|' + SINGLE_QUOTE + '|' + DOUBLE_QUOTE + ')*'
55
35
] . join ( '|' ) , 'g' ) ;
56
36
var match = s . match ( chunker ) . filter ( Boolean ) ;
37
+
38
+ if ( ! match ) {
39
+ return [ ] ;
40
+ }
41
+ if ( ! env ) {
42
+ env = { } ;
43
+ }
44
+ if ( ! opts ) {
45
+ opts = { } ;
46
+ }
47
+
57
48
var commented = false ;
58
49
59
- if ( ! match ) return [ ] ;
60
- if ( ! env ) env = { } ;
61
- if ( ! opts ) opts = { } ;
50
+ function getVar ( _ , pre , key ) {
51
+ var r = typeof env === 'function' ? env ( key ) : env [ key ] ;
52
+ if ( r === undefined && key != '' ) {
53
+ r = '' ;
54
+ } else if ( r === undefined ) {
55
+ r = '$' ;
56
+ }
57
+
58
+ if ( typeof r === 'object' ) {
59
+ return pre + TOKEN + JSON . stringify ( r ) + TOKEN ;
60
+ }
61
+ return pre + r ;
62
+ }
63
+
62
64
return match . map ( function ( s , j ) {
63
65
if ( commented ) {
64
- return ;
66
+ return void undefined ;
65
67
}
66
68
if ( RegExp ( '^' + CONTROL + '$' ) . test ( s ) ) {
67
69
return { op : s } ;
68
70
}
69
71
70
72
// Hand-written scanner/parser for Bash quoting rules:
71
73
//
72
- // 1. inside single quotes, all characters are printed literally.
73
- // 2. inside double quotes, all characters are printed literally
74
- // except variables prefixed by '$' and backslashes followed by
75
- // either a double quote or another backslash.
76
- // 3. outside of any quotes, backslashes are treated as escape
77
- // characters and not printed (unless they are themselves escaped)
78
- // 4. quote context can switch mid-token if there is no whitespace
74
+ // 1. inside single quotes, all characters are printed literally.
75
+ // 2. inside double quotes, all characters are printed literally
76
+ // except variables prefixed by '$' and backslashes followed by
77
+ // either a double quote or another backslash.
78
+ // 3. outside of any quotes, backslashes are treated as escape
79
+ // characters and not printed (unless they are themselves escaped)
80
+ // 4. quote context can switch mid-token if there is no whitespace
79
81
// between the two quote contexts (e.g. all'one'"token" parses as
80
82
// "allonetoken")
81
83
var SQ = "'" ;
@@ -86,22 +88,52 @@ function parse(s, env, opts) {
86
88
var esc = false ;
87
89
var out = '' ;
88
90
var isGlob = false ;
91
+ var i ;
89
92
90
- for ( var i = 0 , len = s . length ; i < len ; i ++ ) {
93
+ function parseEnvVar ( ) {
94
+ i += 1 ;
95
+ var varend ;
96
+ var varname ;
97
+ // debugger
98
+ if ( s . charAt ( i ) === '{' ) {
99
+ i += 1 ;
100
+ if ( s . charAt ( i ) === '}' ) {
101
+ throw new Error ( 'Bad substitution: ' + s . substr ( i - 2 , 3 ) ) ;
102
+ }
103
+ varend = s . indexOf ( '}' , i ) ;
104
+ if ( varend < 0 ) {
105
+ throw new Error ( 'Bad substitution: ' + s . substr ( i ) ) ;
106
+ }
107
+ varname = s . substr ( i , varend - i ) ;
108
+ i = varend ;
109
+ } else if ( ( / [ * @ # ? $ ! _ - ] / ) . test ( s . charAt ( i ) ) ) {
110
+ varname = s . charAt ( i ) ;
111
+ i += 1 ;
112
+ } else {
113
+ varend = s . substr ( i ) . match ( / [ ^ \w \d _ ] / ) ;
114
+ if ( ! varend ) {
115
+ varname = s . substr ( i ) ;
116
+ i = s . length ;
117
+ } else {
118
+ varname = s . substr ( i , varend . index ) ;
119
+ i += varend . index - 1 ;
120
+ }
121
+ }
122
+ return getVar ( null , '' , varname ) ;
123
+ }
124
+
125
+ for ( i = 0 ; i < s . length ; i ++ ) {
91
126
var c = s . charAt ( i ) ;
92
127
isGlob = isGlob || ( ! quote && ( c === '*' || c === '?' ) ) ;
93
128
if ( esc ) {
94
129
out += c ;
95
130
esc = false ;
96
- }
97
- else if ( quote ) {
131
+ } else if ( quote ) {
98
132
if ( c === quote ) {
99
133
quote = false ;
100
- }
101
- else if ( quote == SQ ) {
134
+ } else if ( quote == SQ ) {
102
135
out += c ;
103
- }
104
- else { // Double quote
136
+ } else { // Double quote
105
137
if ( c === BS ) {
106
138
i += 1 ;
107
139
c = s . charAt ( i ) ;
@@ -110,92 +142,62 @@ function parse(s, env, opts) {
110
142
} else {
111
143
out += BS + c ;
112
144
}
113
- }
114
- else if ( c === DS ) {
145
+ } else if ( c === DS ) {
115
146
out += parseEnvVar ( ) ;
116
- }
117
- else {
147
+ } else {
118
148
out += c ;
119
149
}
120
150
}
121
- }
122
- else if ( c === DQ || c === SQ ) {
151
+ } else if ( c === DQ || c === SQ ) {
123
152
quote = c ;
124
- }
125
- else if ( RegExp ( '^' + CONTROL + '$' ) . test ( c ) ) {
153
+ } else if ( RegExp ( '^' + CONTROL + '$' ) . test ( c ) ) {
126
154
return { op : s } ;
127
- }
128
- else if ( RegExp ( '^#$' ) . test ( c ) ) {
155
+ } else if ( ( / ^ # $ / ) . test ( c ) ) {
129
156
commented = true ;
130
157
if ( out . length ) {
131
158
return [ out , { comment : s . slice ( i + 1 ) + match . slice ( j + 1 ) . join ( ' ' ) } ] ;
132
159
}
133
160
return [ { comment : s . slice ( i + 1 ) + match . slice ( j + 1 ) . join ( ' ' ) } ] ;
134
- }
135
- else if ( c === BS ) {
161
+ } else if ( c === BS ) {
136
162
esc = true ;
137
- }
138
- else if ( c === DS ) {
163
+ } else if ( c === DS ) {
139
164
out += parseEnvVar ( ) ;
165
+ } else {
166
+ out += c ;
140
167
}
141
- else out += c ;
142
168
}
143
169
144
- if ( isGlob ) return { op : 'glob' , pattern : out } ;
170
+ if ( isGlob ) {
171
+ return { op : 'glob' , pattern : out } ;
172
+ }
145
173
146
174
return out ;
147
-
148
- function parseEnvVar ( ) {
149
- i += 1 ;
150
- var varend , varname ;
151
- // debugger
152
- if ( s . charAt ( i ) === '{' ) {
153
- i += 1 ;
154
- if ( s . charAt ( i ) === '}' ) {
155
- throw new Error ( "Bad substitution: " + s . substr ( i - 2 , 3 ) ) ;
156
- }
157
- varend = s . indexOf ( '}' , i ) ;
158
- if ( varend < 0 ) {
159
- throw new Error ( "Bad substitution: " + s . substr ( i ) ) ;
160
- }
161
- varname = s . substr ( i , varend - i ) ;
162
- i = varend ;
163
- }
164
- else if ( / [ * @ # ? $ ! _ \- ] / . test ( s . charAt ( i ) ) ) {
165
- varname = s . charAt ( i ) ;
166
- i += 1 ;
167
- }
168
- else {
169
- varend = s . substr ( i ) . match ( / [ ^ \w \d _ ] / ) ;
170
- if ( ! varend ) {
171
- varname = s . substr ( i ) ;
172
- i = s . length ;
173
- } else {
174
- varname = s . substr ( i , varend . index ) ;
175
- i += varend . index - 1 ;
176
- }
177
- }
178
- return getVar ( null , '' , varname ) ;
175
+ } ) . reduce ( function ( prev , arg ) { // finalize parsed aruments
176
+ if ( arg === undefined ) {
177
+ return prev ;
179
178
}
180
- } )
181
- // finalize parsed aruments
182
- . reduce ( function ( prev , arg ) {
183
- if ( arg === undefined ) {
184
- return prev ;
185
- }
186
- return prev . concat ( arg ) ;
187
- } , [ ] ) ;
188
-
189
- function getVar ( _ , pre , key ) {
190
- var r = typeof env === 'function' ? env ( key ) : env [ key ] ;
191
- if ( r === undefined && key != '' )
192
- r = '' ;
193
- else if ( r === undefined )
194
- r = '$' ;
179
+ return prev . concat ( arg ) ;
180
+ } , [ ] ) ;
181
+ }
195
182
196
- if ( typeof r === 'object' ) {
197
- return pre + TOKEN + JSON . stringify ( r ) + TOKEN ;
198
- }
199
- else return pre + r ;
183
+ exports . parse = function ( s , env , opts ) {
184
+ var mapped = parse ( s , env , opts ) ;
185
+ if ( typeof env !== 'function' ) {
186
+ return mapped ;
200
187
}
201
- }
188
+ return mapped . reduce ( function ( acc , s ) {
189
+ if ( typeof s === 'object' ) {
190
+ return acc . concat ( s ) ;
191
+ }
192
+ var xs = s . split ( RegExp ( '(' + TOKEN + '.*?' + TOKEN + ')' , 'g' ) ) ;
193
+ if ( xs . length === 1 ) {
194
+ return acc . concat ( xs [ 0 ] ) ;
195
+ }
196
+ return acc . concat ( xs . filter ( Boolean ) . map ( function ( x ) {
197
+ if ( RegExp ( '^' + TOKEN ) . test ( x ) ) {
198
+ return JSON . parse ( x . split ( TOKEN ) [ 1 ] ) ;
199
+ }
200
+ return x ;
201
+ } ) ) ;
202
+ } , [ ] ) ;
203
+ } ;
0 commit comments