NamedNodeMap.js 16 KB

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