UNPKG

14.8 kBJavaScriptView Raw
1'use strict';
2// TODO: in core-js@4, move /modules/ dependencies to public entries for better optimization by tools like `preset-env`
3require('../modules/es.array.iterator');
4var $ = require('../internals/export');
5var global = require('../internals/global');
6var safeGetBuiltIn = require('../internals/safe-get-built-in');
7var call = require('../internals/function-call');
8var uncurryThis = require('../internals/function-uncurry-this');
9var DESCRIPTORS = require('../internals/descriptors');
10var USE_NATIVE_URL = require('../internals/url-constructor-detection');
11var defineBuiltIn = require('../internals/define-built-in');
12var defineBuiltInAccessor = require('../internals/define-built-in-accessor');
13var defineBuiltIns = require('../internals/define-built-ins');
14var setToStringTag = require('../internals/set-to-string-tag');
15var createIteratorConstructor = require('../internals/iterator-create-constructor');
16var InternalStateModule = require('../internals/internal-state');
17var anInstance = require('../internals/an-instance');
18var isCallable = require('../internals/is-callable');
19var hasOwn = require('../internals/has-own-property');
20var bind = require('../internals/function-bind-context');
21var classof = require('../internals/classof');
22var anObject = require('../internals/an-object');
23var isObject = require('../internals/is-object');
24var $toString = require('../internals/to-string');
25var create = require('../internals/object-create');
26var createPropertyDescriptor = require('../internals/create-property-descriptor');
27var getIterator = require('../internals/get-iterator');
28var getIteratorMethod = require('../internals/get-iterator-method');
29var createIterResultObject = require('../internals/create-iter-result-object');
30var validateArgumentsLength = require('../internals/validate-arguments-length');
31var wellKnownSymbol = require('../internals/well-known-symbol');
32var arraySort = require('../internals/array-sort');
33
34var ITERATOR = wellKnownSymbol('iterator');
35var URL_SEARCH_PARAMS = 'URLSearchParams';
36var URL_SEARCH_PARAMS_ITERATOR = URL_SEARCH_PARAMS + 'Iterator';
37var setInternalState = InternalStateModule.set;
38var getInternalParamsState = InternalStateModule.getterFor(URL_SEARCH_PARAMS);
39var getInternalIteratorState = InternalStateModule.getterFor(URL_SEARCH_PARAMS_ITERATOR);
40
41var nativeFetch = safeGetBuiltIn('fetch');
42var NativeRequest = safeGetBuiltIn('Request');
43var Headers = safeGetBuiltIn('Headers');
44var RequestPrototype = NativeRequest && NativeRequest.prototype;
45var HeadersPrototype = Headers && Headers.prototype;
46var RegExp = global.RegExp;
47var TypeError = global.TypeError;
48var decodeURIComponent = global.decodeURIComponent;
49var encodeURIComponent = global.encodeURIComponent;
50var charAt = uncurryThis(''.charAt);
51var join = uncurryThis([].join);
52var push = uncurryThis([].push);
53var replace = uncurryThis(''.replace);
54var shift = uncurryThis([].shift);
55var splice = uncurryThis([].splice);
56var split = uncurryThis(''.split);
57var stringSlice = uncurryThis(''.slice);
58
59var plus = /\+/g;
60var sequences = Array(4);
61
62var percentSequence = function (bytes) {
63 return sequences[bytes - 1] || (sequences[bytes - 1] = RegExp('((?:%[\\da-f]{2}){' + bytes + '})', 'gi'));
64};
65
66var percentDecode = function (sequence) {
67 try {
68 return decodeURIComponent(sequence);
69 } catch (error) {
70 return sequence;
71 }
72};
73
74var deserialize = function (it) {
75 var result = replace(it, plus, ' ');
76 var bytes = 4;
77 try {
78 return decodeURIComponent(result);
79 } catch (error) {
80 while (bytes) {
81 result = replace(result, percentSequence(bytes--), percentDecode);
82 }
83 return result;
84 }
85};
86
87var find = /[!'()~]|%20/g;
88
89var replacements = {
90 '!': '%21',
91 "'": '%27',
92 '(': '%28',
93 ')': '%29',
94 '~': '%7E',
95 '%20': '+'
96};
97
98var replacer = function (match) {
99 return replacements[match];
100};
101
102var serialize = function (it) {
103 return replace(encodeURIComponent(it), find, replacer);
104};
105
106var URLSearchParamsIterator = createIteratorConstructor(function Iterator(params, kind) {
107 setInternalState(this, {
108 type: URL_SEARCH_PARAMS_ITERATOR,
109 target: getInternalParamsState(params).entries,
110 index: 0,
111 kind: kind
112 });
113}, URL_SEARCH_PARAMS, function next() {
114 var state = getInternalIteratorState(this);
115 var target = state.target;
116 var index = state.index++;
117 if (!target || index >= target.length) {
118 state.target = undefined;
119 return createIterResultObject(undefined, true);
120 }
121 var entry = target[index];
122 switch (state.kind) {
123 case 'keys': return createIterResultObject(entry.key, false);
124 case 'values': return createIterResultObject(entry.value, false);
125 } return createIterResultObject([entry.key, entry.value], false);
126}, true);
127
128var URLSearchParamsState = function (init) {
129 this.entries = [];
130 this.url = null;
131
132 if (init !== undefined) {
133 if (isObject(init)) this.parseObject(init);
134 else this.parseQuery(typeof init == 'string' ? charAt(init, 0) === '?' ? stringSlice(init, 1) : init : $toString(init));
135 }
136};
137
138URLSearchParamsState.prototype = {
139 type: URL_SEARCH_PARAMS,
140 bindURL: function (url) {
141 this.url = url;
142 this.update();
143 },
144 parseObject: function (object) {
145 var entries = this.entries;
146 var iteratorMethod = getIteratorMethod(object);
147 var iterator, next, step, entryIterator, entryNext, first, second;
148
149 if (iteratorMethod) {
150 iterator = getIterator(object, iteratorMethod);
151 next = iterator.next;
152 while (!(step = call(next, iterator)).done) {
153 entryIterator = getIterator(anObject(step.value));
154 entryNext = entryIterator.next;
155 if (
156 (first = call(entryNext, entryIterator)).done ||
157 (second = call(entryNext, entryIterator)).done ||
158 !call(entryNext, entryIterator).done
159 ) throw new TypeError('Expected sequence with length 2');
160 push(entries, { key: $toString(first.value), value: $toString(second.value) });
161 }
162 } else for (var key in object) if (hasOwn(object, key)) {
163 push(entries, { key: key, value: $toString(object[key]) });
164 }
165 },
166 parseQuery: function (query) {
167 if (query) {
168 var entries = this.entries;
169 var attributes = split(query, '&');
170 var index = 0;
171 var attribute, entry;
172 while (index < attributes.length) {
173 attribute = attributes[index++];
174 if (attribute.length) {
175 entry = split(attribute, '=');
176 push(entries, {
177 key: deserialize(shift(entry)),
178 value: deserialize(join(entry, '='))
179 });
180 }
181 }
182 }
183 },
184 serialize: function () {
185 var entries = this.entries;
186 var result = [];
187 var index = 0;
188 var entry;
189 while (index < entries.length) {
190 entry = entries[index++];
191 push(result, serialize(entry.key) + '=' + serialize(entry.value));
192 } return join(result, '&');
193 },
194 update: function () {
195 this.entries.length = 0;
196 this.parseQuery(this.url.query);
197 },
198 updateURL: function () {
199 if (this.url) this.url.update();
200 }
201};
202
203// `URLSearchParams` constructor
204// https://url.spec.whatwg.org/#interface-urlsearchparams
205var URLSearchParamsConstructor = function URLSearchParams(/* init */) {
206 anInstance(this, URLSearchParamsPrototype);
207 var init = arguments.length > 0 ? arguments[0] : undefined;
208 var state = setInternalState(this, new URLSearchParamsState(init));
209 if (!DESCRIPTORS) this.size = state.entries.length;
210};
211
212var URLSearchParamsPrototype = URLSearchParamsConstructor.prototype;
213
214defineBuiltIns(URLSearchParamsPrototype, {
215 // `URLSearchParams.prototype.append` method
216 // https://url.spec.whatwg.org/#dom-urlsearchparams-append
217 append: function append(name, value) {
218 var state = getInternalParamsState(this);
219 validateArgumentsLength(arguments.length, 2);
220 push(state.entries, { key: $toString(name), value: $toString(value) });
221 if (!DESCRIPTORS) this.length++;
222 state.updateURL();
223 },
224 // `URLSearchParams.prototype.delete` method
225 // https://url.spec.whatwg.org/#dom-urlsearchparams-delete
226 'delete': function (name /* , value */) {
227 var state = getInternalParamsState(this);
228 var length = validateArgumentsLength(arguments.length, 1);
229 var entries = state.entries;
230 var key = $toString(name);
231 var $value = length < 2 ? undefined : arguments[1];
232 var value = $value === undefined ? $value : $toString($value);
233 var index = 0;
234 while (index < entries.length) {
235 var entry = entries[index];
236 if (entry.key === key && (value === undefined || entry.value === value)) {
237 splice(entries, index, 1);
238 if (value !== undefined) break;
239 } else index++;
240 }
241 if (!DESCRIPTORS) this.size = entries.length;
242 state.updateURL();
243 },
244 // `URLSearchParams.prototype.get` method
245 // https://url.spec.whatwg.org/#dom-urlsearchparams-get
246 get: function get(name) {
247 var entries = getInternalParamsState(this).entries;
248 validateArgumentsLength(arguments.length, 1);
249 var key = $toString(name);
250 var index = 0;
251 for (; index < entries.length; index++) {
252 if (entries[index].key === key) return entries[index].value;
253 }
254 return null;
255 },
256 // `URLSearchParams.prototype.getAll` method
257 // https://url.spec.whatwg.org/#dom-urlsearchparams-getall
258 getAll: function getAll(name) {
259 var entries = getInternalParamsState(this).entries;
260 validateArgumentsLength(arguments.length, 1);
261 var key = $toString(name);
262 var result = [];
263 var index = 0;
264 for (; index < entries.length; index++) {
265 if (entries[index].key === key) push(result, entries[index].value);
266 }
267 return result;
268 },
269 // `URLSearchParams.prototype.has` method
270 // https://url.spec.whatwg.org/#dom-urlsearchparams-has
271 has: function has(name /* , value */) {
272 var entries = getInternalParamsState(this).entries;
273 var length = validateArgumentsLength(arguments.length, 1);
274 var key = $toString(name);
275 var $value = length < 2 ? undefined : arguments[1];
276 var value = $value === undefined ? $value : $toString($value);
277 var index = 0;
278 while (index < entries.length) {
279 var entry = entries[index++];
280 if (entry.key === key && (value === undefined || entry.value === value)) return true;
281 }
282 return false;
283 },
284 // `URLSearchParams.prototype.set` method
285 // https://url.spec.whatwg.org/#dom-urlsearchparams-set
286 set: function set(name, value) {
287 var state = getInternalParamsState(this);
288 validateArgumentsLength(arguments.length, 1);
289 var entries = state.entries;
290 var found = false;
291 var key = $toString(name);
292 var val = $toString(value);
293 var index = 0;
294 var entry;
295 for (; index < entries.length; index++) {
296 entry = entries[index];
297 if (entry.key === key) {
298 if (found) splice(entries, index--, 1);
299 else {
300 found = true;
301 entry.value = val;
302 }
303 }
304 }
305 if (!found) push(entries, { key: key, value: val });
306 if (!DESCRIPTORS) this.size = entries.length;
307 state.updateURL();
308 },
309 // `URLSearchParams.prototype.sort` method
310 // https://url.spec.whatwg.org/#dom-urlsearchparams-sort
311 sort: function sort() {
312 var state = getInternalParamsState(this);
313 arraySort(state.entries, function (a, b) {
314 return a.key > b.key ? 1 : -1;
315 });
316 state.updateURL();
317 },
318 // `URLSearchParams.prototype.forEach` method
319 forEach: function forEach(callback /* , thisArg */) {
320 var entries = getInternalParamsState(this).entries;
321 var boundFunction = bind(callback, arguments.length > 1 ? arguments[1] : undefined);
322 var index = 0;
323 var entry;
324 while (index < entries.length) {
325 entry = entries[index++];
326 boundFunction(entry.value, entry.key, this);
327 }
328 },
329 // `URLSearchParams.prototype.keys` method
330 keys: function keys() {
331 return new URLSearchParamsIterator(this, 'keys');
332 },
333 // `URLSearchParams.prototype.values` method
334 values: function values() {
335 return new URLSearchParamsIterator(this, 'values');
336 },
337 // `URLSearchParams.prototype.entries` method
338 entries: function entries() {
339 return new URLSearchParamsIterator(this, 'entries');
340 }
341}, { enumerable: true });
342
343// `URLSearchParams.prototype[@@iterator]` method
344defineBuiltIn(URLSearchParamsPrototype, ITERATOR, URLSearchParamsPrototype.entries, { name: 'entries' });
345
346// `URLSearchParams.prototype.toString` method
347// https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior
348defineBuiltIn(URLSearchParamsPrototype, 'toString', function toString() {
349 return getInternalParamsState(this).serialize();
350}, { enumerable: true });
351
352// `URLSearchParams.prototype.size` getter
353// https://github.com/whatwg/url/pull/734
354if (DESCRIPTORS) defineBuiltInAccessor(URLSearchParamsPrototype, 'size', {
355 get: function size() {
356 return getInternalParamsState(this).entries.length;
357 },
358 configurable: true,
359 enumerable: true
360});
361
362setToStringTag(URLSearchParamsConstructor, URL_SEARCH_PARAMS);
363
364$({ global: true, constructor: true, forced: !USE_NATIVE_URL }, {
365 URLSearchParams: URLSearchParamsConstructor
366});
367
368// Wrap `fetch` and `Request` for correct work with polyfilled `URLSearchParams`
369if (!USE_NATIVE_URL && isCallable(Headers)) {
370 var headersHas = uncurryThis(HeadersPrototype.has);
371 var headersSet = uncurryThis(HeadersPrototype.set);
372
373 var wrapRequestOptions = function (init) {
374 if (isObject(init)) {
375 var body = init.body;
376 var headers;
377 if (classof(body) === URL_SEARCH_PARAMS) {
378 headers = init.headers ? new Headers(init.headers) : new Headers();
379 if (!headersHas(headers, 'content-type')) {
380 headersSet(headers, 'content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
381 }
382 return create(init, {
383 body: createPropertyDescriptor(0, $toString(body)),
384 headers: createPropertyDescriptor(0, headers)
385 });
386 }
387 } return init;
388 };
389
390 if (isCallable(nativeFetch)) {
391 $({ global: true, enumerable: true, dontCallGetSet: true, forced: true }, {
392 fetch: function fetch(input /* , init */) {
393 return nativeFetch(input, arguments.length > 1 ? wrapRequestOptions(arguments[1]) : {});
394 }
395 });
396 }
397
398 if (isCallable(NativeRequest)) {
399 var RequestConstructor = function Request(input /* , init */) {
400 anInstance(this, RequestPrototype);
401 return new NativeRequest(input, arguments.length > 1 ? wrapRequestOptions(arguments[1]) : {});
402 };
403
404 RequestPrototype.constructor = RequestConstructor;
405 RequestConstructor.prototype = RequestPrototype;
406
407 $({ global: true, constructor: true, dontCallGetSet: true, forced: true }, {
408 Request: RequestConstructor
409 });
410 }
411}
412
413module.exports = {
414 URLSearchParams: URLSearchParamsConstructor,
415 getState: getInternalParamsState
416};