web.url-search-params.constructor.js 18 KB

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