4
4
5
5
const QueryString = exports ;
6
6
7
- // If obj.hasOwnProperty has been overridden, then calling
8
- // obj.hasOwnProperty(prop) will break.
9
- // See: https://github.com/joyent/node/issues/1707
10
- function hasOwnProperty ( obj , prop ) {
11
- return Object . prototype . hasOwnProperty . call ( obj , prop ) ;
12
- }
13
-
14
7
15
8
function charCode ( c ) {
16
9
return c . charCodeAt ( 0 ) ;
@@ -93,19 +86,68 @@ QueryString.unescape = function(s, decodeSpaces) {
93
86
} ;
94
87
95
88
89
+ var hexTable = new Array ( 256 ) ;
90
+ for ( var i = 0 ; i < 256 ; ++ i )
91
+ hexTable [ i ] = '%' + ( ( i < 16 ? '0' : '' ) + i . toString ( 16 ) ) . toUpperCase ( ) ;
96
92
QueryString . escape = function ( str ) {
97
- return encodeURIComponent ( str ) ;
93
+ var len = str . length ;
94
+ var out = '' ;
95
+ var i , c ;
96
+
97
+ if ( len === 0 )
98
+ return str ;
99
+
100
+ for ( i = 0 ; i < len ; ++ i ) {
101
+ c = str . charCodeAt ( i ) ;
102
+
103
+ // These characters do not need escaping (in order):
104
+ // ! - . _ ~
105
+ // ' ( ) *
106
+ // digits
107
+ // alpha (uppercase)
108
+ // alpha (lowercase)
109
+ if ( c === 0x21 || c === 0x2D || c === 0x2E || c === 0x5F || c === 0x7E ||
110
+ ( c >= 0x27 && c <= 0x2A ) ||
111
+ ( c >= 0x30 && c <= 0x39 ) ||
112
+ ( c >= 0x41 && c <= 0x5A ) ||
113
+ ( c >= 0x61 && c <= 0x7A ) ) {
114
+ out += str [ i ] ;
115
+ continue ;
116
+ }
117
+
118
+ // Other ASCII characters
119
+ if ( c < 0x80 ) {
120
+ out += hexTable [ c ] ;
121
+ continue ;
122
+ }
123
+
124
+ // Multi-byte characters ...
125
+ if ( c < 0x800 ) {
126
+ out += hexTable [ 0xC0 | ( c >> 6 ) ] + hexTable [ 0x80 | ( c & 0x3F ) ] ;
127
+ continue ;
128
+ }
129
+ if ( c < 0xD800 || c >= 0xE000 ) {
130
+ out += hexTable [ 0xE0 | ( c >> 12 ) ] +
131
+ hexTable [ 0x80 | ( ( c >> 6 ) & 0x3F ) ] +
132
+ hexTable [ 0x80 | ( c & 0x3F ) ] ;
133
+ continue ;
134
+ }
135
+ // Surrogate pair
136
+ ++ i ;
137
+ c = 0x10000 + ( ( ( c & 0x3FF ) << 10 ) | ( str . charCodeAt ( i ) & 0x3FF ) ) ;
138
+ out += hexTable [ 0xF0 | ( c >> 18 ) ] +
139
+ hexTable [ 0x80 | ( ( c >> 12 ) & 0x3F ) ] +
140
+ hexTable [ 0x80 | ( ( c >> 6 ) & 0x3F ) ] +
141
+ hexTable [ 0x80 | ( c & 0x3F ) ] ;
142
+ }
143
+ return out ;
98
144
} ;
99
145
100
146
var stringifyPrimitive = function ( v ) {
101
- let type = typeof v ;
102
-
103
- if ( type === 'string' )
147
+ if ( typeof v === 'string' || ( typeof v === 'number' && isFinite ( v ) ) )
104
148
return v ;
105
- if ( type === 'boolean' )
149
+ if ( typeof v === 'boolean' )
106
150
return v ? 'true' : 'false' ;
107
- if ( type === 'number' )
108
- return isFinite ( v ) ? v : '' ;
109
151
return '' ;
110
152
} ;
111
153
@@ -121,21 +163,31 @@ QueryString.stringify = QueryString.encode = function(obj, sep, eq, options) {
121
163
122
164
if ( obj !== null && typeof obj === 'object' ) {
123
165
var keys = Object . keys ( obj ) ;
124
- var fields = [ ] ;
125
-
126
- for ( var i = 0 ; i < keys . length ; i ++ ) {
166
+ var len = keys . length ;
167
+ var flast = len - 1 ;
168
+ var fields = '' ;
169
+ for ( var i = 0 ; i < len ; ++ i ) {
127
170
var k = keys [ i ] ;
128
171
var v = obj [ k ] ;
129
172
var ks = encode ( stringifyPrimitive ( k ) ) + eq ;
130
173
131
174
if ( Array . isArray ( v ) ) {
132
- for ( var j = 0 ; j < v . length ; j ++ )
133
- fields . push ( ks + encode ( stringifyPrimitive ( v [ j ] ) ) ) ;
175
+ var vlen = v . length ;
176
+ var vlast = vlen - 1 ;
177
+ for ( var j = 0 ; j < vlen ; ++ j ) {
178
+ fields += ks + encode ( stringifyPrimitive ( v [ j ] ) ) ;
179
+ if ( j < vlast )
180
+ fields += sep ;
181
+ }
182
+ if ( vlen && i < flast )
183
+ fields += sep ;
134
184
} else {
135
- fields . push ( ks + encode ( stringifyPrimitive ( v ) ) ) ;
185
+ fields += ks + encode ( stringifyPrimitive ( v ) ) ;
186
+ if ( i < flast )
187
+ fields += sep ;
136
188
}
137
189
}
138
- return fields . join ( sep ) ;
190
+ return fields ;
139
191
}
140
192
return '' ;
141
193
} ;
@@ -169,29 +221,23 @@ QueryString.parse = QueryString.decode = function(qs, sep, eq, options) {
169
221
decode = options . decodeURIComponent ;
170
222
}
171
223
224
+ var keys = [ ] ;
172
225
for ( var i = 0 ; i < len ; ++ i ) {
173
226
var x = qs [ i ] . replace ( regexp , '%20' ) ,
174
227
idx = x . indexOf ( eq ) ,
175
- kstr , vstr , k , v ;
228
+ k , v ;
176
229
177
230
if ( idx >= 0 ) {
178
- kstr = x . substr ( 0 , idx ) ;
179
- vstr = x . substr ( idx + 1 ) ;
231
+ k = decodeStr ( x . substring ( 0 , idx ) , decode ) ;
232
+ v = decodeStr ( x . substring ( idx + 1 ) , decode ) ;
180
233
} else {
181
- kstr = x ;
182
- vstr = '' ;
234
+ k = decodeStr ( x , decode ) ;
235
+ v = '' ;
183
236
}
184
237
185
- try {
186
- k = decode ( kstr ) ;
187
- v = decode ( vstr ) ;
188
- } catch ( e ) {
189
- k = QueryString . unescape ( kstr , true ) ;
190
- v = QueryString . unescape ( vstr , true ) ;
191
- }
192
-
193
- if ( ! hasOwnProperty ( obj , k ) ) {
238
+ if ( keys . indexOf ( k ) === - 1 ) {
194
239
obj [ k ] = v ;
240
+ keys . push ( k ) ;
195
241
} else if ( Array . isArray ( obj [ k ] ) ) {
196
242
obj [ k ] . push ( v ) ;
197
243
} else {
@@ -201,3 +247,12 @@ QueryString.parse = QueryString.decode = function(qs, sep, eq, options) {
201
247
202
248
return obj ;
203
249
} ;
250
+
251
+
252
+ function decodeStr ( s , decoder ) {
253
+ try {
254
+ return decoder ( s ) ;
255
+ } catch ( e ) {
256
+ return QueryString . unescape ( s , true ) ;
257
+ }
258
+ }
0 commit comments