'use strict'; const { Error, ErrorPrototype, ObjectDefineProperties, ObjectDefineProperty, ObjectSetPrototypeOf, SafeMap, SafeSet, SafeWeakMap, SymbolToStringTag, TypeError, } = primordials; const { transfer_mode_private_symbol, } = privateSymbols; const { messaging_clone_symbol, messaging_deserialize_symbol, } = perIsolateSymbols; /** * Maps to BaseObject::TransferMode::kCloneable */ const kCloneable = 2; function throwInvalidThisError(Base, type) { const err = new Base(); const key = 'ERR_INVALID_THIS'; ObjectDefineProperties(err, { message: { __proto__: null, value: `Value of "this" must be of ${type}`, enumerable: false, writable: true, configurable: true, }, toString: { __proto__: null, value() { return `${this.name} [${key}]: ${this.message}`; }, enumerable: false, writable: true, configurable: true, }, }); err.code = key; throw err; } const internalsMap = new SafeWeakMap(); const nameToCodeMap = new SafeMap(); // These were removed from the error names table. // See https://github.com/heycam/webidl/pull/946. const disusedNamesSet = new SafeSet() .add('DOMStringSizeError') .add('NoDataAllowedError') .add('ValidationError'); // The DOMException WebIDL interface defines that: // - ObjectGetPrototypeOf(DOMException) === Function. // - ObjectGetPrototypeOf(DOMException.prototype) === Error.prototype. // Thus, we can not simply use the pattern of `class DOMException extends Error` and call // `super()` to construct an object. The `super` in `super()` call in the constructor will // be resolved to `Function`, instead of `Error`. Use the trick of return overriding to // create an object with the `[[ErrorData]]` internal slot. // Ref: https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-getsuperconstructor class DOMException { constructor(message = '', options = 'Error') { // Invokes the Error constructor to create an object with the [[ErrorData]] // internal slot. // eslint-disable-next-line no-restricted-syntax const self = new Error(); // Use `new.target.prototype` to support DOMException subclasses. ObjectSetPrototypeOf(self, new.target.prototype); self[transfer_mode_private_symbol] = kCloneable; if (options && typeof options === 'object') { const { name } = options; internalsMap.set(self, { message: `${message}`, name: `${name}`, }); if ('cause' in options) { ObjectDefineProperty(self, 'cause', { __proto__: null, value: options.cause, configurable: true, writable: true, enumerable: false, }); } } else { internalsMap.set(self, { message: `${message}`, name: `${options}`, }); } // Return the error object as the return overriding of the constructor. // eslint-disable-next-line no-constructor-return return self; } [messaging_clone_symbol]() { // See serialization steps in https://webidl.spec.whatwg.org/#dom-domexception-domexception const internals = internalsMap.get(this); return { data: { message: internals.message, name: internals.name, stack: this.stack, }, deserializeInfo: 'internal/worker/clone_dom_exception:DOMException', }; } [messaging_deserialize_symbol](data) { // See deserialization steps in https://webidl.spec.whatwg.org/#dom-domexception-domexception internalsMap.set(this, { message: data.message, name: data.name, }); this.stack = data.stack; } get name() { const internals = internalsMap.get(this); if (internals === undefined) { throwInvalidThisError(TypeError, 'DOMException'); } return internals.name; } get message() { const internals = internalsMap.get(this); if (internals === undefined) { throwInvalidThisError(TypeError, 'DOMException'); } return internals.message; } get code() { const internals = internalsMap.get(this); if (internals === undefined) { throwInvalidThisError(TypeError, 'DOMException'); } if (disusedNamesSet.has(internals.name)) { return 0; } const code = nameToCodeMap.get(internals.name); return code === undefined ? 0 : code; } } const DOMExceptionPrototype = DOMException.prototype; ObjectSetPrototypeOf(DOMExceptionPrototype, ErrorPrototype); ObjectDefineProperties(DOMExceptionPrototype, { [SymbolToStringTag]: { __proto__: null, configurable: true, value: 'DOMException' }, name: { __proto__: null, enumerable: true, configurable: true }, message: { __proto__: null, enumerable: true, configurable: true }, code: { __proto__: null, enumerable: true, configurable: true }, }); for (const { 0: name, 1: codeName, 2: value } of [ ['IndexSizeError', 'INDEX_SIZE_ERR', 1], ['DOMStringSizeError', 'DOMSTRING_SIZE_ERR', 2], ['HierarchyRequestError', 'HIERARCHY_REQUEST_ERR', 3], ['WrongDocumentError', 'WRONG_DOCUMENT_ERR', 4], ['InvalidCharacterError', 'INVALID_CHARACTER_ERR', 5], ['NoDataAllowedError', 'NO_DATA_ALLOWED_ERR', 6], ['NoModificationAllowedError', 'NO_MODIFICATION_ALLOWED_ERR', 7], ['NotFoundError', 'NOT_FOUND_ERR', 8], ['NotSupportedError', 'NOT_SUPPORTED_ERR', 9], ['InUseAttributeError', 'INUSE_ATTRIBUTE_ERR', 10], ['InvalidStateError', 'INVALID_STATE_ERR', 11], ['SyntaxError', 'SYNTAX_ERR', 12], ['InvalidModificationError', 'INVALID_MODIFICATION_ERR', 13], ['NamespaceError', 'NAMESPACE_ERR', 14], ['InvalidAccessError', 'INVALID_ACCESS_ERR', 15], ['ValidationError', 'VALIDATION_ERR', 16], ['TypeMismatchError', 'TYPE_MISMATCH_ERR', 17], ['SecurityError', 'SECURITY_ERR', 18], ['NetworkError', 'NETWORK_ERR', 19], ['AbortError', 'ABORT_ERR', 20], ['URLMismatchError', 'URL_MISMATCH_ERR', 21], ['QuotaExceededError', 'QUOTA_EXCEEDED_ERR', 22], ['TimeoutError', 'TIMEOUT_ERR', 23], ['InvalidNodeTypeError', 'INVALID_NODE_TYPE_ERR', 24], ['DataCloneError', 'DATA_CLONE_ERR', 25], // There are some more error names, but since they don't have codes assigned, // we don't need to care about them. ]) { const desc = { enumerable: true, value }; ObjectDefineProperty(DOMException, codeName, desc); ObjectDefineProperty(DOMExceptionPrototype, codeName, desc); nameToCodeMap.set(name, value); } exports.DOMException = DOMException;