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

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