@@ -24,15 +24,12 @@ function encoderForArrayFormat(options) {
2424 }
2525
2626 if ( value === null ) {
27- return [
28- ...result , [ encode ( key , options ) , '[' , index , ']' ] . join ( '' ) ,
29- ] ;
27+ result . push ( [ encode ( key , options ) , '[' , index , ']' ] . join ( '' ) ) ;
28+ return result ;
3029 }
3130
32- return [
33- ...result ,
34- [ encode ( key , options ) , '[' , encode ( index , options ) , ']=' , encode ( value , options ) ] . join ( '' ) ,
35- ] ;
31+ result . push ( [ encode ( key , options ) , '[' , encode ( index , options ) , ']=' , encode ( value , options ) ] . join ( '' ) ) ;
32+ return result ;
3633 } ;
3734 }
3835
@@ -47,16 +44,12 @@ function encoderForArrayFormat(options) {
4744 }
4845
4946 if ( value === null ) {
50- return [
51- ...result ,
52- [ encode ( key , options ) , '[]' ] . join ( '' ) ,
53- ] ;
47+ result . push ( [ encode ( key , options ) , '[]' ] . join ( '' ) ) ;
48+ return result ;
5449 }
5550
56- return [
57- ...result ,
58- [ encode ( key , options ) , '[]=' , encode ( value , options ) ] . join ( '' ) ,
59- ] ;
51+ result . push ( [ encode ( key , options ) , '[]=' , encode ( value , options ) ] . join ( '' ) ) ;
52+ return result ;
6053 } ;
6154 }
6255
@@ -71,16 +64,12 @@ function encoderForArrayFormat(options) {
7164 }
7265
7366 if ( value === null ) {
74- return [
75- ...result ,
76- [ encode ( key , options ) , ':list=' ] . join ( '' ) ,
77- ] ;
67+ result . push ( [ encode ( key , options ) , ':list=' ] . join ( '' ) ) ;
68+ return result ;
7869 }
7970
80- return [
81- ...result ,
82- [ encode ( key , options ) , ':list=' , encode ( value , options ) ] . join ( '' ) ,
83- ] ;
71+ result . push ( [ encode ( key , options ) , ':list=' , encode ( value , options ) ] . join ( '' ) ) ;
72+ return result ;
8473 } ;
8574 }
8675
@@ -104,10 +93,12 @@ function encoderForArrayFormat(options) {
10493 value = value === null ? '' : value ;
10594
10695 if ( result . length === 0 ) {
107- return [ [ encode ( key , options ) , keyValueSeparator , encode ( value , options ) ] . join ( '' ) ] ;
96+ result . push ( [ encode ( key , options ) , keyValueSeparator , encode ( value , options ) ] . join ( '' ) ) ;
97+ return result ;
10898 }
10999
110- return [ [ result , encode ( value , options ) ] . join ( options . arrayFormatSeparator ) ] ;
100+ result . push ( encode ( value , options ) ) ;
101+ return result ;
111102 } ;
112103 }
113104
@@ -122,16 +113,12 @@ function encoderForArrayFormat(options) {
122113 }
123114
124115 if ( value === null ) {
125- return [
126- ...result ,
127- encode ( key , options ) ,
128- ] ;
116+ result . push ( encode ( key , options ) ) ;
117+ return result ;
129118 }
130119
131- return [
132- ...result ,
133- [ encode ( key , options ) , '=' , encode ( value , options ) ] . join ( '' ) ,
134- ] ;
120+ result . push ( [ encode ( key , options ) , '=' , encode ( value , options ) ] . join ( '' ) ) ;
121+ return result ;
135122 } ;
136123 }
137124 }
@@ -175,7 +162,12 @@ function parserForArrayFormat(options) {
175162 return ;
176163 }
177164
178- accumulator [ key ] = [ ...accumulator [ key ] , value ] ;
165+ if ( ! Array . isArray ( accumulator [ key ] ) ) {
166+ accumulator [ key ] = [ accumulator [ key ] , value ] ;
167+ return ;
168+ }
169+
170+ accumulator [ key ] . push ( value ) ;
179171 } ;
180172 }
181173
@@ -194,7 +186,12 @@ function parserForArrayFormat(options) {
194186 return ;
195187 }
196188
197- accumulator [ key ] = [ ...accumulator [ key ] , value ] ;
189+ if ( ! Array . isArray ( accumulator [ key ] ) ) {
190+ accumulator [ key ] = [ accumulator [ key ] , value ] ;
191+ return ;
192+ }
193+
194+ accumulator [ key ] . push ( value ) ;
198195 } ;
199196 }
200197
@@ -226,7 +223,13 @@ function parserForArrayFormat(options) {
226223 return ;
227224 }
228225
229- accumulator [ key ] = [ ...accumulator [ key ] , ...arrayValue ] ;
226+ if ( ! Array . isArray ( accumulator [ key ] ) ) {
227+ accumulator [ key ] = [ accumulator [ key ] ] ;
228+ }
229+
230+ for ( const item of arrayValue ) {
231+ accumulator [ key ] . push ( item ) ;
232+ }
230233 } ;
231234 }
232235
@@ -237,7 +240,12 @@ function parserForArrayFormat(options) {
237240 return ;
238241 }
239242
240- accumulator [ key ] = [ ...[ accumulator [ key ] ] . flat ( ) , value ] ;
243+ if ( Array . isArray ( accumulator [ key ] ) ) {
244+ accumulator [ key ] . push ( value ) ;
245+ return ;
246+ }
247+
248+ accumulator [ key ] = [ accumulator [ key ] , value ] ;
241249 } ;
242250 }
243251 }
@@ -298,6 +306,12 @@ function getHash(url) {
298306 return hash ;
299307}
300308
309+ function getUrlWithoutQuery ( url ) {
310+ // Avoid `split('?')` so query-heavy URLs don't allocate large arrays.
311+ const queryStart = url . indexOf ( '?' ) ;
312+ return queryStart === - 1 ? url : url . slice ( 0 , queryStart ) ;
313+ }
314+
301315function parseValue ( value , options , type ) {
302316 if ( type === 'string' && typeof value === 'string' ) {
303317 return value ;
@@ -381,11 +395,21 @@ export function parse(query, options) {
381395 return returnValue ;
382396 }
383397
384- for ( const parameter of query . split ( '&' ) ) {
385- if ( parameter === '' ) {
398+ // Avoid `split('&')` so separator-heavy inputs don't allocate large arrays of empty strings.
399+ let parameterStart = 0 ;
400+
401+ for ( let index = 0 ; index <= query . length ; index ++ ) {
402+ if ( index < query . length && query [ index ] !== '&' ) {
403+ continue ;
404+ }
405+
406+ if ( index === parameterStart ) {
407+ parameterStart = index + 1 ;
386408 continue ;
387409 }
388410
411+ const parameter = query . slice ( parameterStart , index ) ;
412+ parameterStart = index + 1 ;
389413 const parameter_ = options . decode ? parameter . replaceAll ( '+' , ' ' ) : parameter ;
390414
391415 let [ key , value ] = splitOnFirst ( parameter_ , '=' ) ;
@@ -498,9 +522,9 @@ export function stringify(object, options) {
498522 ) . filter ( item => item !== undefined ) ;
499523 }
500524
501- return processedArray
502- . reduce ( formatter ( key ) , [ ] )
503- . join ( '&' ) ;
525+ const result = processedArray . reduce ( formatter ( key ) , [ ] ) ;
526+ const arrayFormatSeparator = [ 'comma' , 'separator' , 'bracket-separator' ] . includes ( options . arrayFormat ) ? options . arrayFormatSeparator : '&' ;
527+ return result . join ( arrayFormatSeparator ) ;
504528 }
505529
506530 return encode ( key , options ) + '=' + encode ( value , options ) ;
@@ -520,7 +544,7 @@ export function parseUrl(url, options) {
520544 }
521545
522546 return {
523- url : url_ ?. split ( '?' ) ?. [ 0 ] ?? '' ,
547+ url : getUrlWithoutQuery ( url_ ?? '' ) ,
524548 query : parse ( extract ( url ) , options ) ,
525549 ...( options && options . parseFragmentIdentifier && hash ? { fragmentIdentifier : decode ( hash , options ) } : { } ) ,
526550 } ;
@@ -534,7 +558,7 @@ export function stringifyUrl(object, options) {
534558 ...options ,
535559 } ;
536560
537- const url = removeHash ( object . url ) . split ( '?' ) [ 0 ] || '' ;
561+ const url = getUrlWithoutQuery ( removeHash ( object . url ) ) || '' ;
538562 const queryFromUrl = extract ( object . url ) ;
539563
540564 const query = {
@@ -572,7 +596,10 @@ export function pick(input, filter, options) {
572596}
573597
574598export function exclude ( input , filter , options ) {
575- const exclusionFilter = Array . isArray ( filter ) ? key => ! filter . includes ( key ) : ( key , value ) => ! filter ( key , value ) ;
599+ if ( Array . isArray ( filter ) ) {
600+ const filterSet = new Set ( filter ) ;
601+ return pick ( input , key => ! filterSet . has ( key ) , options ) ;
602+ }
576603
577- return pick ( input , exclusionFilter , options ) ;
604+ return pick ( input , ( key , value ) => ! filter ( key , value ) , options ) ;
578605}
0 commit comments