web.url-search-params.js 12 KB

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