URLSearchParams.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. "use strict";
  2. const conversions = require("webidl-conversions");
  3. const utils = require("./utils.js");
  4. const Function = require("./Function.js");
  5. const newObjectInRealm = utils.newObjectInRealm;
  6. const implSymbol = utils.implSymbol;
  7. const ctorRegistrySymbol = utils.ctorRegistrySymbol;
  8. const interfaceName = "URLSearchParams";
  9. exports.is = value => {
  10. return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
  11. };
  12. exports.isImpl = value => {
  13. return utils.isObject(value) && value instanceof Impl.implementation;
  14. };
  15. exports.convert = (globalObject, value, { context = "The provided value" } = {}) => {
  16. if (exports.is(value)) {
  17. return utils.implForWrapper(value);
  18. }
  19. throw new globalObject.TypeError(`${context} is not of type 'URLSearchParams'.`);
  20. };
  21. exports.createDefaultIterator = (globalObject, target, kind) => {
  22. const ctorRegistry = globalObject[ctorRegistrySymbol];
  23. const iteratorPrototype = ctorRegistry["URLSearchParams Iterator"];
  24. const iterator = Object.create(iteratorPrototype);
  25. Object.defineProperty(iterator, utils.iterInternalSymbol, {
  26. value: { target, kind, index: 0 },
  27. configurable: true
  28. });
  29. return iterator;
  30. };
  31. function makeWrapper(globalObject, newTarget) {
  32. let proto;
  33. if (newTarget !== undefined) {
  34. proto = newTarget.prototype;
  35. }
  36. if (!utils.isObject(proto)) {
  37. proto = globalObject[ctorRegistrySymbol]["URLSearchParams"].prototype;
  38. }
  39. return Object.create(proto);
  40. }
  41. exports.create = (globalObject, constructorArgs, privateData) => {
  42. const wrapper = makeWrapper(globalObject);
  43. return exports.setup(wrapper, globalObject, constructorArgs, privateData);
  44. };
  45. exports.createImpl = (globalObject, constructorArgs, privateData) => {
  46. const wrapper = exports.create(globalObject, constructorArgs, privateData);
  47. return utils.implForWrapper(wrapper);
  48. };
  49. exports._internalSetup = (wrapper, globalObject) => {};
  50. exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
  51. privateData.wrapper = wrapper;
  52. exports._internalSetup(wrapper, globalObject);
  53. Object.defineProperty(wrapper, implSymbol, {
  54. value: new Impl.implementation(globalObject, constructorArgs, privateData),
  55. configurable: true
  56. });
  57. wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
  58. if (Impl.init) {
  59. Impl.init(wrapper[implSymbol]);
  60. }
  61. return wrapper;
  62. };
  63. exports.new = (globalObject, newTarget) => {
  64. const wrapper = makeWrapper(globalObject, newTarget);
  65. exports._internalSetup(wrapper, globalObject);
  66. Object.defineProperty(wrapper, implSymbol, {
  67. value: Object.create(Impl.implementation.prototype),
  68. configurable: true
  69. });
  70. wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
  71. if (Impl.init) {
  72. Impl.init(wrapper[implSymbol]);
  73. }
  74. return wrapper[implSymbol];
  75. };
  76. const exposed = new Set(["Window", "Worker"]);
  77. exports.install = (globalObject, globalNames) => {
  78. if (!globalNames.some(globalName => exposed.has(globalName))) {
  79. return;
  80. }
  81. const ctorRegistry = utils.initCtorRegistry(globalObject);
  82. class URLSearchParams {
  83. constructor() {
  84. const args = [];
  85. {
  86. let curArg = arguments[0];
  87. if (curArg !== undefined) {
  88. if (utils.isObject(curArg)) {
  89. if (curArg[Symbol.iterator] !== undefined) {
  90. if (!utils.isObject(curArg)) {
  91. throw new globalObject.TypeError(
  92. "Failed to construct 'URLSearchParams': parameter 1" + " sequence" + " is not an iterable object."
  93. );
  94. } else {
  95. const V = [];
  96. const tmp = curArg;
  97. for (let nextItem of tmp) {
  98. if (!utils.isObject(nextItem)) {
  99. throw new globalObject.TypeError(
  100. "Failed to construct 'URLSearchParams': parameter 1" +
  101. " sequence" +
  102. "'s element" +
  103. " is not an iterable object."
  104. );
  105. } else {
  106. const V = [];
  107. const tmp = nextItem;
  108. for (let nextItem of tmp) {
  109. nextItem = conversions["USVString"](nextItem, {
  110. context:
  111. "Failed to construct 'URLSearchParams': parameter 1" +
  112. " sequence" +
  113. "'s element" +
  114. "'s element",
  115. globals: globalObject
  116. });
  117. V.push(nextItem);
  118. }
  119. nextItem = V;
  120. }
  121. V.push(nextItem);
  122. }
  123. curArg = V;
  124. }
  125. } else {
  126. if (!utils.isObject(curArg)) {
  127. throw new globalObject.TypeError(
  128. "Failed to construct 'URLSearchParams': parameter 1" + " record" + " is not an object."
  129. );
  130. } else {
  131. const result = Object.create(null);
  132. for (const key of Reflect.ownKeys(curArg)) {
  133. const desc = Object.getOwnPropertyDescriptor(curArg, key);
  134. if (desc && desc.enumerable) {
  135. let typedKey = key;
  136. typedKey = conversions["USVString"](typedKey, {
  137. context: "Failed to construct 'URLSearchParams': parameter 1" + " record" + "'s key",
  138. globals: globalObject
  139. });
  140. let typedValue = curArg[key];
  141. typedValue = conversions["USVString"](typedValue, {
  142. context: "Failed to construct 'URLSearchParams': parameter 1" + " record" + "'s value",
  143. globals: globalObject
  144. });
  145. result[typedKey] = typedValue;
  146. }
  147. }
  148. curArg = result;
  149. }
  150. }
  151. } else {
  152. curArg = conversions["USVString"](curArg, {
  153. context: "Failed to construct 'URLSearchParams': parameter 1",
  154. globals: globalObject
  155. });
  156. }
  157. } else {
  158. curArg = "";
  159. }
  160. args.push(curArg);
  161. }
  162. return exports.setup(Object.create(new.target.prototype), globalObject, args);
  163. }
  164. append(name, value) {
  165. const esValue = this !== null && this !== undefined ? this : globalObject;
  166. if (!exports.is(esValue)) {
  167. throw new globalObject.TypeError(
  168. "'append' called on an object that is not a valid instance of URLSearchParams."
  169. );
  170. }
  171. if (arguments.length < 2) {
  172. throw new globalObject.TypeError(
  173. `Failed to execute 'append' on 'URLSearchParams': 2 arguments required, but only ${arguments.length} present.`
  174. );
  175. }
  176. const args = [];
  177. {
  178. let curArg = arguments[0];
  179. curArg = conversions["USVString"](curArg, {
  180. context: "Failed to execute 'append' on 'URLSearchParams': parameter 1",
  181. globals: globalObject
  182. });
  183. args.push(curArg);
  184. }
  185. {
  186. let curArg = arguments[1];
  187. curArg = conversions["USVString"](curArg, {
  188. context: "Failed to execute 'append' on 'URLSearchParams': parameter 2",
  189. globals: globalObject
  190. });
  191. args.push(curArg);
  192. }
  193. return utils.tryWrapperForImpl(esValue[implSymbol].append(...args));
  194. }
  195. delete(name) {
  196. const esValue = this !== null && this !== undefined ? this : globalObject;
  197. if (!exports.is(esValue)) {
  198. throw new globalObject.TypeError(
  199. "'delete' called on an object that is not a valid instance of URLSearchParams."
  200. );
  201. }
  202. if (arguments.length < 1) {
  203. throw new globalObject.TypeError(
  204. `Failed to execute 'delete' on 'URLSearchParams': 1 argument required, but only ${arguments.length} present.`
  205. );
  206. }
  207. const args = [];
  208. {
  209. let curArg = arguments[0];
  210. curArg = conversions["USVString"](curArg, {
  211. context: "Failed to execute 'delete' on 'URLSearchParams': parameter 1",
  212. globals: globalObject
  213. });
  214. args.push(curArg);
  215. }
  216. {
  217. let curArg = arguments[1];
  218. if (curArg !== undefined) {
  219. curArg = conversions["USVString"](curArg, {
  220. context: "Failed to execute 'delete' on 'URLSearchParams': parameter 2",
  221. globals: globalObject
  222. });
  223. }
  224. args.push(curArg);
  225. }
  226. return utils.tryWrapperForImpl(esValue[implSymbol].delete(...args));
  227. }
  228. get(name) {
  229. const esValue = this !== null && this !== undefined ? this : globalObject;
  230. if (!exports.is(esValue)) {
  231. throw new globalObject.TypeError("'get' called on an object that is not a valid instance of URLSearchParams.");
  232. }
  233. if (arguments.length < 1) {
  234. throw new globalObject.TypeError(
  235. `Failed to execute 'get' on 'URLSearchParams': 1 argument required, but only ${arguments.length} present.`
  236. );
  237. }
  238. const args = [];
  239. {
  240. let curArg = arguments[0];
  241. curArg = conversions["USVString"](curArg, {
  242. context: "Failed to execute 'get' on 'URLSearchParams': parameter 1",
  243. globals: globalObject
  244. });
  245. args.push(curArg);
  246. }
  247. return esValue[implSymbol].get(...args);
  248. }
  249. getAll(name) {
  250. const esValue = this !== null && this !== undefined ? this : globalObject;
  251. if (!exports.is(esValue)) {
  252. throw new globalObject.TypeError(
  253. "'getAll' called on an object that is not a valid instance of URLSearchParams."
  254. );
  255. }
  256. if (arguments.length < 1) {
  257. throw new globalObject.TypeError(
  258. `Failed to execute 'getAll' on 'URLSearchParams': 1 argument required, but only ${arguments.length} present.`
  259. );
  260. }
  261. const args = [];
  262. {
  263. let curArg = arguments[0];
  264. curArg = conversions["USVString"](curArg, {
  265. context: "Failed to execute 'getAll' on 'URLSearchParams': parameter 1",
  266. globals: globalObject
  267. });
  268. args.push(curArg);
  269. }
  270. return utils.tryWrapperForImpl(esValue[implSymbol].getAll(...args));
  271. }
  272. has(name) {
  273. const esValue = this !== null && this !== undefined ? this : globalObject;
  274. if (!exports.is(esValue)) {
  275. throw new globalObject.TypeError("'has' called on an object that is not a valid instance of URLSearchParams.");
  276. }
  277. if (arguments.length < 1) {
  278. throw new globalObject.TypeError(
  279. `Failed to execute 'has' on 'URLSearchParams': 1 argument required, but only ${arguments.length} present.`
  280. );
  281. }
  282. const args = [];
  283. {
  284. let curArg = arguments[0];
  285. curArg = conversions["USVString"](curArg, {
  286. context: "Failed to execute 'has' on 'URLSearchParams': parameter 1",
  287. globals: globalObject
  288. });
  289. args.push(curArg);
  290. }
  291. {
  292. let curArg = arguments[1];
  293. if (curArg !== undefined) {
  294. curArg = conversions["USVString"](curArg, {
  295. context: "Failed to execute 'has' on 'URLSearchParams': parameter 2",
  296. globals: globalObject
  297. });
  298. }
  299. args.push(curArg);
  300. }
  301. return esValue[implSymbol].has(...args);
  302. }
  303. set(name, value) {
  304. const esValue = this !== null && this !== undefined ? this : globalObject;
  305. if (!exports.is(esValue)) {
  306. throw new globalObject.TypeError("'set' called on an object that is not a valid instance of URLSearchParams.");
  307. }
  308. if (arguments.length < 2) {
  309. throw new globalObject.TypeError(
  310. `Failed to execute 'set' on 'URLSearchParams': 2 arguments required, but only ${arguments.length} present.`
  311. );
  312. }
  313. const args = [];
  314. {
  315. let curArg = arguments[0];
  316. curArg = conversions["USVString"](curArg, {
  317. context: "Failed to execute 'set' on 'URLSearchParams': parameter 1",
  318. globals: globalObject
  319. });
  320. args.push(curArg);
  321. }
  322. {
  323. let curArg = arguments[1];
  324. curArg = conversions["USVString"](curArg, {
  325. context: "Failed to execute 'set' on 'URLSearchParams': parameter 2",
  326. globals: globalObject
  327. });
  328. args.push(curArg);
  329. }
  330. return utils.tryWrapperForImpl(esValue[implSymbol].set(...args));
  331. }
  332. sort() {
  333. const esValue = this !== null && this !== undefined ? this : globalObject;
  334. if (!exports.is(esValue)) {
  335. throw new globalObject.TypeError("'sort' called on an object that is not a valid instance of URLSearchParams.");
  336. }
  337. return utils.tryWrapperForImpl(esValue[implSymbol].sort());
  338. }
  339. toString() {
  340. const esValue = this !== null && this !== undefined ? this : globalObject;
  341. if (!exports.is(esValue)) {
  342. throw new globalObject.TypeError(
  343. "'toString' called on an object that is not a valid instance of URLSearchParams."
  344. );
  345. }
  346. return esValue[implSymbol].toString();
  347. }
  348. keys() {
  349. if (!exports.is(this)) {
  350. throw new globalObject.TypeError("'keys' called on an object that is not a valid instance of URLSearchParams.");
  351. }
  352. return exports.createDefaultIterator(globalObject, this, "key");
  353. }
  354. values() {
  355. if (!exports.is(this)) {
  356. throw new globalObject.TypeError(
  357. "'values' called on an object that is not a valid instance of URLSearchParams."
  358. );
  359. }
  360. return exports.createDefaultIterator(globalObject, this, "value");
  361. }
  362. entries() {
  363. if (!exports.is(this)) {
  364. throw new globalObject.TypeError(
  365. "'entries' called on an object that is not a valid instance of URLSearchParams."
  366. );
  367. }
  368. return exports.createDefaultIterator(globalObject, this, "key+value");
  369. }
  370. forEach(callback) {
  371. if (!exports.is(this)) {
  372. throw new globalObject.TypeError(
  373. "'forEach' called on an object that is not a valid instance of URLSearchParams."
  374. );
  375. }
  376. if (arguments.length < 1) {
  377. throw new globalObject.TypeError(
  378. "Failed to execute 'forEach' on 'iterable': 1 argument required, but only 0 present."
  379. );
  380. }
  381. callback = Function.convert(globalObject, callback, {
  382. context: "Failed to execute 'forEach' on 'iterable': The callback provided as parameter 1"
  383. });
  384. const thisArg = arguments[1];
  385. let pairs = Array.from(this[implSymbol]);
  386. let i = 0;
  387. while (i < pairs.length) {
  388. const [key, value] = pairs[i].map(utils.tryWrapperForImpl);
  389. callback.call(thisArg, value, key, this);
  390. pairs = Array.from(this[implSymbol]);
  391. i++;
  392. }
  393. }
  394. get size() {
  395. const esValue = this !== null && this !== undefined ? this : globalObject;
  396. if (!exports.is(esValue)) {
  397. throw new globalObject.TypeError(
  398. "'get size' called on an object that is not a valid instance of URLSearchParams."
  399. );
  400. }
  401. return esValue[implSymbol]["size"];
  402. }
  403. }
  404. Object.defineProperties(URLSearchParams.prototype, {
  405. append: { enumerable: true },
  406. delete: { enumerable: true },
  407. get: { enumerable: true },
  408. getAll: { enumerable: true },
  409. has: { enumerable: true },
  410. set: { enumerable: true },
  411. sort: { enumerable: true },
  412. toString: { enumerable: true },
  413. keys: { enumerable: true },
  414. values: { enumerable: true },
  415. entries: { enumerable: true },
  416. forEach: { enumerable: true },
  417. size: { enumerable: true },
  418. [Symbol.toStringTag]: { value: "URLSearchParams", configurable: true },
  419. [Symbol.iterator]: { value: URLSearchParams.prototype.entries, configurable: true, writable: true }
  420. });
  421. ctorRegistry[interfaceName] = URLSearchParams;
  422. ctorRegistry["URLSearchParams Iterator"] = Object.create(ctorRegistry["%IteratorPrototype%"], {
  423. [Symbol.toStringTag]: {
  424. configurable: true,
  425. value: "URLSearchParams Iterator"
  426. }
  427. });
  428. utils.define(ctorRegistry["URLSearchParams Iterator"], {
  429. next() {
  430. const internal = this && this[utils.iterInternalSymbol];
  431. if (!internal) {
  432. throw new globalObject.TypeError("next() called on a value that is not a URLSearchParams iterator object");
  433. }
  434. const { target, kind, index } = internal;
  435. const values = Array.from(target[implSymbol]);
  436. const len = values.length;
  437. if (index >= len) {
  438. return newObjectInRealm(globalObject, { value: undefined, done: true });
  439. }
  440. const pair = values[index];
  441. internal.index = index + 1;
  442. return newObjectInRealm(globalObject, utils.iteratorResult(pair.map(utils.tryWrapperForImpl), kind));
  443. }
  444. });
  445. Object.defineProperty(globalObject, interfaceName, {
  446. configurable: true,
  447. writable: true,
  448. value: URLSearchParams
  449. });
  450. };
  451. const Impl = require("./URLSearchParams-impl.js");