diff options
Diffstat (limited to 'op_crates/web')
-rw-r--r-- | op_crates/web/00_webidl.js | 810 | ||||
-rw-r--r-- | op_crates/web/01_dom_exception.js | 1 | ||||
-rw-r--r-- | op_crates/web/11_url.js | 406 | ||||
-rw-r--r-- | op_crates/web/Cargo.toml | 1 | ||||
-rw-r--r-- | op_crates/web/abort_controller_test.js | 140 | ||||
-rw-r--r-- | op_crates/web/event_target_test.js | 245 | ||||
-rw-r--r-- | op_crates/web/event_test.js | 142 | ||||
-rw-r--r-- | op_crates/web/internal.d.ts | 287 | ||||
-rw-r--r-- | op_crates/web/lib.deno_web.d.ts | 169 | ||||
-rw-r--r-- | op_crates/web/lib.rs | 226 |
10 files changed, 1 insertions, 2426 deletions
diff --git a/op_crates/web/00_webidl.js b/op_crates/web/00_webidl.js deleted file mode 100644 index c00c605e8..000000000 --- a/op_crates/web/00_webidl.js +++ /dev/null @@ -1,810 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -// Adapted from https://github.com/jsdom/webidl-conversions. -// Copyright Domenic Denicola. Licensed under BSD-2-Clause License. -// Original license at https://github.com/jsdom/webidl-conversions/blob/master/LICENSE.md. - -"use strict"; - -((window) => { - function makeException(ErrorType, message, opts = {}) { - if (opts.globals) { - ErrorType = opts.globals[ErrorType.name]; - } - return new ErrorType( - `${opts.prefix ? opts.prefix + ": " : ""}${ - opts.context ? opts.context : "Value" - } ${message}`, - ); - } - - function toNumber(value, opts = {}) { - if (!opts.globals) { - return +value; - } - if (typeof value === "bigint") { - throw opts.globals.TypeError("Cannot convert a BigInt value to a number"); - } - return opts.globals.Number(value); - } - - function type(V) { - if (V === null) { - return "Null"; - } - switch (typeof V) { - case "undefined": - return "Undefined"; - case "boolean": - return "Boolean"; - case "number": - return "Number"; - case "string": - return "String"; - case "symbol": - return "Symbol"; - case "bigint": - return "BigInt"; - case "object": - // Falls through - case "function": - // Falls through - default: - // Per ES spec, typeof returns an implemention-defined value that is not any of the existing ones for - // uncallable non-standard exotic objects. Yet Type() which the Web IDL spec depends on returns Object for - // such cases. So treat the default case as an object. - return "Object"; - } - } - - // Round x to the nearest integer, choosing the even integer if it lies halfway between two. - function evenRound(x) { - // There are four cases for numbers with fractional part being .5: - // - // case | x | floor(x) | round(x) | expected | x <> 0 | x % 1 | x & 1 | example - // 1 | 2n + 0.5 | 2n | 2n + 1 | 2n | > | 0.5 | 0 | 0.5 -> 0 - // 2 | 2n + 1.5 | 2n + 1 | 2n + 2 | 2n + 2 | > | 0.5 | 1 | 1.5 -> 2 - // 3 | -2n - 0.5 | -2n - 1 | -2n | -2n | < | -0.5 | 0 | -0.5 -> 0 - // 4 | -2n - 1.5 | -2n - 2 | -2n - 1 | -2n - 2 | < | -0.5 | 1 | -1.5 -> -2 - // (where n is a non-negative integer) - // - // Branch here for cases 1 and 4 - if ( - (x > 0 && x % 1 === +0.5 && (x & 1) === 0) || - (x < 0 && x % 1 === -0.5 && (x & 1) === 1) - ) { - return censorNegativeZero(Math.floor(x)); - } - - return censorNegativeZero(Math.round(x)); - } - - function integerPart(n) { - return censorNegativeZero(Math.trunc(n)); - } - - function sign(x) { - return x < 0 ? -1 : 1; - } - - function modulo(x, y) { - // https://tc39.github.io/ecma262/#eqn-modulo - // Note that http://stackoverflow.com/a/4467559/3191 does NOT work for large modulos - const signMightNotMatch = x % y; - if (sign(y) !== sign(signMightNotMatch)) { - return signMightNotMatch + y; - } - return signMightNotMatch; - } - - function censorNegativeZero(x) { - return x === 0 ? 0 : x; - } - - function createIntegerConversion(bitLength, typeOpts) { - const isSigned = !typeOpts.unsigned; - - let lowerBound; - let upperBound; - if (bitLength === 64) { - upperBound = Number.MAX_SAFE_INTEGER; - lowerBound = !isSigned ? 0 : Number.MIN_SAFE_INTEGER; - } else if (!isSigned) { - lowerBound = 0; - upperBound = Math.pow(2, bitLength) - 1; - } else { - lowerBound = -Math.pow(2, bitLength - 1); - upperBound = Math.pow(2, bitLength - 1) - 1; - } - - const twoToTheBitLength = Math.pow(2, bitLength); - const twoToOneLessThanTheBitLength = Math.pow(2, bitLength - 1); - - return (V, opts = {}) => { - let x = toNumber(V, opts); - x = censorNegativeZero(x); - - if (opts.enforceRange) { - if (!Number.isFinite(x)) { - throw makeException(TypeError, "is not a finite number", opts); - } - - x = integerPart(x); - - if (x < lowerBound || x > upperBound) { - throw makeException( - TypeError, - `is outside the accepted range of ${lowerBound} to ${upperBound}, inclusive`, - opts, - ); - } - - return x; - } - - if (!Number.isNaN(x) && opts.clamp) { - x = Math.min(Math.max(x, lowerBound), upperBound); - x = evenRound(x); - return x; - } - - if (!Number.isFinite(x) || x === 0) { - return 0; - } - x = integerPart(x); - - // Math.pow(2, 64) is not accurately representable in JavaScript, so try to avoid these per-spec operations if - // possible. Hopefully it's an optimization for the non-64-bitLength cases too. - if (x >= lowerBound && x <= upperBound) { - return x; - } - - // These will not work great for bitLength of 64, but oh well. See the README for more details. - x = modulo(x, twoToTheBitLength); - if (isSigned && x >= twoToOneLessThanTheBitLength) { - return x - twoToTheBitLength; - } - return x; - }; - } - - function createLongLongConversion(bitLength, { unsigned }) { - const upperBound = Number.MAX_SAFE_INTEGER; - const lowerBound = unsigned ? 0 : Number.MIN_SAFE_INTEGER; - const asBigIntN = unsigned ? BigInt.asUintN : BigInt.asIntN; - - return (V, opts = {}) => { - let x = toNumber(V, opts); - x = censorNegativeZero(x); - - if (opts.enforceRange) { - if (!Number.isFinite(x)) { - throw makeException(TypeError, "is not a finite number", opts); - } - - x = integerPart(x); - - if (x < lowerBound || x > upperBound) { - throw makeException( - TypeError, - `is outside the accepted range of ${lowerBound} to ${upperBound}, inclusive`, - opts, - ); - } - - return x; - } - - if (!Number.isNaN(x) && opts.clamp) { - x = Math.min(Math.max(x, lowerBound), upperBound); - x = evenRound(x); - return x; - } - - if (!Number.isFinite(x) || x === 0) { - return 0; - } - - let xBigInt = BigInt(integerPart(x)); - xBigInt = asBigIntN(bitLength, xBigInt); - return Number(xBigInt); - }; - } - - const converters = []; - - converters.any = (V) => { - return V; - }; - - converters.boolean = function (val) { - return !!val; - }; - - converters.byte = createIntegerConversion(8, { unsigned: false }); - converters.octet = createIntegerConversion(8, { unsigned: true }); - - converters.short = createIntegerConversion(16, { unsigned: false }); - converters["unsigned short"] = createIntegerConversion(16, { - unsigned: true, - }); - - converters.long = createIntegerConversion(32, { unsigned: false }); - converters["unsigned long"] = createIntegerConversion(32, { unsigned: true }); - - converters["long long"] = createLongLongConversion(64, { unsigned: false }); - converters["unsigned long long"] = createLongLongConversion(64, { - unsigned: true, - }); - - converters.float = (V, opts) => { - const x = toNumber(V, opts); - - if (!Number.isFinite(x)) { - throw makeException( - TypeError, - "is not a finite floating-point value", - opts, - ); - } - - if (Object.is(x, -0)) { - return x; - } - - const y = Math.fround(x); - - if (!Number.isFinite(y)) { - throw makeException( - TypeError, - "is outside the range of a single-precision floating-point value", - opts, - ); - } - - return y; - }; - - converters["unrestricted float"] = (V, opts) => { - const x = toNumber(V, opts); - - if (isNaN(x)) { - return x; - } - - if (Object.is(x, -0)) { - return x; - } - - return Math.fround(x); - }; - - converters.double = (V, opts) => { - const x = toNumber(V, opts); - - if (!Number.isFinite(x)) { - throw makeException( - TypeError, - "is not a finite floating-point value", - opts, - ); - } - - return x; - }; - - converters["unrestricted double"] = (V, opts) => { - const x = toNumber(V, opts); - - return x; - }; - - converters.DOMString = function (V, opts = {}) { - if (opts.treatNullAsEmptyString && V === null) { - return ""; - } - - if (typeof V === "symbol") { - throw makeException( - TypeError, - "is a symbol, which cannot be converted to a string", - opts, - ); - } - - const StringCtor = opts.globals ? opts.globals.String : String; - return StringCtor(V); - }; - - converters.ByteString = (V, opts) => { - const x = converters.DOMString(V, opts); - let c; - for (let i = 0; (c = x.codePointAt(i)) !== undefined; ++i) { - if (c > 255) { - throw makeException(TypeError, "is not a valid ByteString", opts); - } - } - - return x; - }; - - converters.USVString = (V, opts) => { - const S = converters.DOMString(V, opts); - const n = S.length; - const U = []; - for (let i = 0; i < n; ++i) { - const c = S.charCodeAt(i); - if (c < 0xd800 || c > 0xdfff) { - U.push(String.fromCodePoint(c)); - } else if (0xdc00 <= c && c <= 0xdfff) { - U.push(String.fromCodePoint(0xfffd)); - } else if (i === n - 1) { - U.push(String.fromCodePoint(0xfffd)); - } else { - const d = S.charCodeAt(i + 1); - if (0xdc00 <= d && d <= 0xdfff) { - const a = c & 0x3ff; - const b = d & 0x3ff; - U.push(String.fromCodePoint((2 << 15) + (2 << 9) * a + b)); - ++i; - } else { - U.push(String.fromCodePoint(0xfffd)); - } - } - } - - return U.join(""); - }; - - converters.object = (V, opts) => { - if (type(V) !== "Object") { - throw makeException(TypeError, "is not an object", opts); - } - - return V; - }; - - // Not exported, but used in Function and VoidFunction. - - // Neither Function nor VoidFunction is defined with [TreatNonObjectAsNull], so - // handling for that is omitted. - function convertCallbackFunction(V, opts) { - if (typeof V !== "function") { - throw makeException(TypeError, "is not a function", opts); - } - return V; - } - - const abByteLengthGetter = Object.getOwnPropertyDescriptor( - ArrayBuffer.prototype, - "byteLength", - ).get; - - function isNonSharedArrayBuffer(V) { - try { - // This will throw on SharedArrayBuffers, but not detached ArrayBuffers. - // (The spec says it should throw, but the spec conflicts with implementations: https://github.com/tc39/ecma262/issues/678) - abByteLengthGetter.call(V); - - return true; - } catch { - return false; - } - } - - let sabByteLengthGetter; - - function isSharedArrayBuffer(V) { - // TODO(lucacasonato): vulnerable to prototype pollution. Needs to happen - // here because SharedArrayBuffer is not available during snapshotting. - if (!sabByteLengthGetter) { - sabByteLengthGetter = Object.getOwnPropertyDescriptor( - SharedArrayBuffer.prototype, - "byteLength", - ).get; - } - try { - sabByteLengthGetter.call(V); - return true; - } catch { - return false; - } - } - - function isArrayBufferDetached(V) { - try { - // eslint-disable-next-line no-new - new Uint8Array(V); - return false; - } catch { - return true; - } - } - - converters.ArrayBuffer = (V, opts = {}) => { - if (!isNonSharedArrayBuffer(V)) { - if (opts.allowShared && !isSharedArrayBuffer(V)) { - throw makeException( - TypeError, - "is not an ArrayBuffer or SharedArrayBuffer", - opts, - ); - } - throw makeException(TypeError, "is not an ArrayBuffer", opts); - } - if (isArrayBufferDetached(V)) { - throw makeException(TypeError, "is a detached ArrayBuffer", opts); - } - - return V; - }; - - const dvByteLengthGetter = Object.getOwnPropertyDescriptor( - DataView.prototype, - "byteLength", - ).get; - converters.DataView = (V, opts = {}) => { - try { - dvByteLengthGetter.call(V); - } catch (e) { - throw makeException(TypeError, "is not a DataView", opts); - } - - if (!opts.allowShared && isSharedArrayBuffer(V.buffer)) { - throw makeException( - TypeError, - "is backed by a SharedArrayBuffer, which is not allowed", - opts, - ); - } - if (isArrayBufferDetached(V.buffer)) { - throw makeException( - TypeError, - "is backed by a detached ArrayBuffer", - opts, - ); - } - - return V; - }; - - // Returns the unforgeable `TypedArray` constructor name or `undefined`, - // if the `this` value isn't a valid `TypedArray` object. - // - // https://tc39.es/ecma262/#sec-get-%typedarray%.prototype-@@tostringtag - const typedArrayNameGetter = Object.getOwnPropertyDescriptor( - Object.getPrototypeOf(Uint8Array).prototype, - Symbol.toStringTag, - ).get; - [ - Int8Array, - Int16Array, - Int32Array, - Uint8Array, - Uint16Array, - Uint32Array, - Uint8ClampedArray, - Float32Array, - Float64Array, - ].forEach((func) => { - const name = func.name; - const article = /^[AEIOU]/.test(name) ? "an" : "a"; - converters[name] = (V, opts = {}) => { - if (!ArrayBuffer.isView(V) || typedArrayNameGetter.call(V) !== name) { - throw makeException( - TypeError, - `is not ${article} ${name} object`, - opts, - ); - } - if (!opts.allowShared && isSharedArrayBuffer(V.buffer)) { - throw makeException( - TypeError, - "is a view on a SharedArrayBuffer, which is not allowed", - opts, - ); - } - if (isArrayBufferDetached(V.buffer)) { - throw makeException( - TypeError, - "is a view on a detached ArrayBuffer", - opts, - ); - } - - return V; - }; - }); - - // Common definitions - - converters.ArrayBufferView = (V, opts = {}) => { - if (!ArrayBuffer.isView(V)) { - throw makeException( - TypeError, - "is not a view on an ArrayBuffer or SharedArrayBuffer", - opts, - ); - } - - if (!opts.allowShared && isSharedArrayBuffer(V.buffer)) { - throw makeException( - TypeError, - "is a view on a SharedArrayBuffer, which is not allowed", - opts, - ); - } - - if (isArrayBufferDetached(V.buffer)) { - throw makeException( - TypeError, - "is a view on a detached ArrayBuffer", - opts, - ); - } - return V; - }; - - converters.BufferSource = (V, opts = {}) => { - if (ArrayBuffer.isView(V)) { - if (!opts.allowShared && isSharedArrayBuffer(V.buffer)) { - throw makeException( - TypeError, - "is a view on a SharedArrayBuffer, which is not allowed", - opts, - ); - } - - if (isArrayBufferDetached(V.buffer)) { - throw makeException( - TypeError, - "is a view on a detached ArrayBuffer", - opts, - ); - } - return V; - } - - if (!opts.allowShared && !isNonSharedArrayBuffer(V)) { - throw makeException( - TypeError, - "is not an ArrayBuffer or a view on one", - opts, - ); - } - if ( - opts.allowShared && - !isSharedArrayBuffer(V) && - !isNonSharedArrayBuffer(V) - ) { - throw makeException( - TypeError, - "is not an ArrayBuffer, SharedArrayBuffer, or a view on one", - opts, - ); - } - if (isArrayBufferDetached(V)) { - throw makeException(TypeError, "is a detached ArrayBuffer", opts); - } - - return V; - }; - - converters.DOMTimeStamp = converters["unsigned long long"]; - - converters.Function = convertCallbackFunction; - - converters.VoidFunction = convertCallbackFunction; - - converters["UVString?"] = createNullableConverter( - converters.USVString, - ); - converters["sequence<double>"] = createSequenceConverter( - converters["double"], - ); - - function requiredArguments(length, required, opts = {}) { - if (length < required) { - const errMsg = `${ - opts.prefix ? opts.prefix + ": " : "" - }${required} argument${ - required === 1 ? "" : "s" - } required, but only ${length} present.`; - throw new TypeError(errMsg); - } - } - - function createDictionaryConverter(name, ...dictionaries) { - return function (V, opts = {}) { - const typeV = type(V); - switch (typeV) { - case "Undefined": - case "Null": - case "Object": - break; - default: - throw makeException( - TypeError, - "can not be converted to a dictionary", - opts, - ); - } - const esDict = V; - - const idlDict = {}; - - for (const members of dictionaries) { - for (const member of members) { - const key = member.key; - - let esMemberValue; - if (typeV === "Undefined" || typeV === "Null") { - esMemberValue = undefined; - } else { - esMemberValue = esDict[key]; - } - - const context = `'${key}' of '${name}'${ - opts.context ? ` (${opts.context})` : "" - }`; - - if (esMemberValue !== undefined) { - const converter = member.converter; - const idlMemberValue = converter(esMemberValue, { - ...opts, - context, - }); - idlDict[key] = idlMemberValue; - } else if ("defaultValue" in member) { - const defaultValue = member.defaultValue; - const idlMemberValue = defaultValue; - idlDict[key] = idlMemberValue; - } else if (member.required) { - throw makeException( - TypeError, - `can not be converted to '${name}' because '${key}' is required in '${name}'.`, - { ...opts }, - ); - } - } - } - - return idlDict; - }; - } - - // https://heycam.github.io/webidl/#es-enumeration - function createEnumConverter(name, values) { - const E = new Set(values); - - return function (V, opts = {}) { - const S = String(V); - - if (!E.has(S)) { - throw new TypeError( - `${ - opts.prefix ? opts.prefix + ": " : "" - }The provided value '${S}' is not a valid enum value of type ${name}.`, - ); - } - - return S; - }; - } - - function createNullableConverter(converter) { - return (V, opts = {}) => { - // FIXME: If Type(V) is not Object, and the conversion to an IDL value is - // being performed due to V being assigned to an attribute whose type is a - // nullable callback function that is annotated with - // [LegacyTreatNonObjectAsNull], then return the IDL nullable type T? - // value null. - - if (V === null || V === undefined) return null; - return converter(V, opts); - }; - } - - // https://heycam.github.io/webidl/#es-sequence - function createSequenceConverter(converter) { - return function (V, opts = {}) { - if (typeof V !== "object") { - throw makeException( - TypeError, - "can not be converted to sequence.", - opts, - ); - } - const iter = V?.[Symbol.iterator]?.(); - if (iter === undefined) { - throw makeException( - TypeError, - "can not be converted to sequence.", - opts, - ); - } - const array = []; - while (true) { - const res = iter?.next?.(); - if (res === undefined) { - throw makeException( - TypeError, - "can not be converted to sequence.", - opts, - ); - } - if (res.done === true) break; - const val = converter(res.value, { - ...opts, - context: `${opts.context}, index ${array.length}`, - }); - array.push(val); - } - return array; - }; - } - - function createRecordConverter(keyConverter, valueConverter) { - return (V, opts) => { - if (typeof V !== "object") { - throw makeException( - TypeError, - "can not be converted to dictionary.", - opts, - ); - } - const result = {}; - for (const key of V) { - const typedKey = keyConverter(key, opts); - const value = V[key]; - const typedValue = valueConverter(value, opts); - result[typedKey] = typedValue; - } - return result; - }; - } - - const brand = Symbol("[[webidl.brand]]"); - - function createInterfaceConverter(name, prototype) { - return (V, opts) => { - if (!(V instanceof prototype) || V[brand] !== brand) { - throw makeException(TypeError, `is not of type ${name}.`, opts); - } - return V; - }; - } - - function createBranded(Type) { - const t = Object.create(Type.prototype); - t[brand] = brand; - return t; - } - - function assertBranded(self, prototype) { - if (!(self instanceof prototype) || self[brand] !== brand) { - throw new TypeError("Illegal invocation"); - } - } - - function illegalConstructor() { - throw new TypeError("Illegal constructor"); - } - - window.__bootstrap ??= {}; - window.__bootstrap.webidl = { - makeException, - converters, - requiredArguments, - createDictionaryConverter, - createEnumConverter, - createNullableConverter, - createSequenceConverter, - createRecordConverter, - createInterfaceConverter, - brand, - createBranded, - assertBranded, - illegalConstructor, - }; -})(this); diff --git a/op_crates/web/01_dom_exception.js b/op_crates/web/01_dom_exception.js index 14f4ca8e9..f5bd3289b 100644 --- a/op_crates/web/01_dom_exception.js +++ b/op_crates/web/01_dom_exception.js @@ -2,6 +2,7 @@ // @ts-check /// <reference path="../../core/lib.deno_core.d.ts" /> +/// <reference path="../webidl/internal.d.ts" /> /// <reference path="../web/internal.d.ts" /> /// <reference path="../web/lib.deno_web.d.ts" /> diff --git a/op_crates/web/11_url.js b/op_crates/web/11_url.js deleted file mode 100644 index d8f5bd5f7..000000000 --- a/op_crates/web/11_url.js +++ /dev/null @@ -1,406 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -"use strict"; - -((window) => { - const core = window.Deno.core; - - function requiredArguments(name, length, required) { - if (length < required) { - const errMsg = `${name} requires at least ${required} argument${ - required === 1 ? "" : "s" - }, but only ${length} present`; - throw new TypeError(errMsg); - } - } - - const paramLists = new WeakMap(); - const urls = new WeakMap(); - - class URLSearchParams { - #params = []; - - constructor(init = "") { - if (typeof init === "string") { - // Overload: USVString - // If init is a string and starts with U+003F (?), - // remove the first code point from init. - if (init[0] == "?") { - init = init.slice(1); - } - - this.#params = core.jsonOpSync("op_parse_url_search_params", init); - } else if ( - Array.isArray(init) || - typeof init?.[Symbol.iterator] == "function" - ) { - // Overload: sequence<sequence<USVString>> - for (const pair of init) { - // If pair does not contain exactly two items, then throw a TypeError. - if (pair.length !== 2) { - throw new TypeError( - "URLSearchParams.constructor sequence argument must only contain pair elements", - ); - } - this.#params.push([String(pair[0]), String(pair[1])]); - } - } else if (Object(init) !== init) { - // pass - } else if (init instanceof URLSearchParams) { - this.#params = [...init.#params]; - } else { - // Overload: record<USVString, USVString> - for (const key of Object.keys(init)) { - this.#params.push([key, String(init[key])]); - } - } - - paramLists.set(this, this.#params); - urls.set(this, null); - } - - #updateUrlSearch = () => { - const url = urls.get(this); - if (url == null) { - return; - } - const parseArgs = { href: url.href, setSearch: this.toString() }; - parts.set(url, core.jsonOpSync("op_parse_url", parseArgs)); - }; - - append(name, value) { - requiredArguments("URLSearchParams.append", arguments.length, 2); - this.#params.push([String(name), String(value)]); - this.#updateUrlSearch(); - } - - delete(name) { - requiredArguments("URLSearchParams.delete", arguments.length, 1); - name = String(name); - let i = 0; - while (i < this.#params.length) { - if (this.#params[i][0] === name) { - this.#params.splice(i, 1); - } else { - i++; - } - } - this.#updateUrlSearch(); - } - - getAll(name) { - requiredArguments("URLSearchParams.getAll", arguments.length, 1); - name = String(name); - const values = []; - for (const entry of this.#params) { - if (entry[0] === name) { - values.push(entry[1]); - } - } - - return values; - } - - get(name) { - requiredArguments("URLSearchParams.get", arguments.length, 1); - name = String(name); - for (const entry of this.#params) { - if (entry[0] === name) { - return entry[1]; - } - } - - return null; - } - - has(name) { - requiredArguments("URLSearchParams.has", arguments.length, 1); - name = String(name); - return this.#params.some((entry) => entry[0] === name); - } - - set(name, value) { - requiredArguments("URLSearchParams.set", arguments.length, 2); - - // If there are any name-value pairs whose name is name, in list, - // set the value of the first such name-value pair to value - // and remove the others. - name = String(name); - value = String(value); - let found = false; - let i = 0; - while (i < this.#params.length) { - if (this.#params[i][0] === name) { - if (!found) { - this.#params[i][1] = value; - found = true; - i++; - } else { - this.#params.splice(i, 1); - } - } else { - i++; - } - } - - // Otherwise, append a new name-value pair whose name is name - // and value is value, to list. - if (!found) { - this.#params.push([String(name), String(value)]); - } - - this.#updateUrlSearch(); - } - - sort() { - this.#params.sort((a, b) => (a[0] === b[0] ? 0 : a[0] > b[0] ? 1 : -1)); - this.#updateUrlSearch(); - } - - forEach(callbackfn, thisArg) { - requiredArguments("URLSearchParams.forEach", arguments.length, 1); - - if (typeof thisArg !== "undefined") { - callbackfn = callbackfn.bind(thisArg); - } - - for (const [key, value] of this.#params) { - callbackfn(value, key, this); - } - } - - *keys() { - for (const [key] of this.#params) { - yield key; - } - } - - *values() { - for (const [, value] of this.#params) { - yield value; - } - } - - *entries() { - yield* this.#params; - } - - *[Symbol.iterator]() { - yield* this.#params; - } - - toString() { - return core.jsonOpSync("op_stringify_url_search_params", this.#params); - } - } - - const parts = new WeakMap(); - - class URL { - #searchParams = null; - - constructor(url, base) { - new.target; - - if (url instanceof URL && base === undefined) { - parts.set(this, parts.get(url)); - } else { - base = base !== undefined ? String(base) : base; - const parseArgs = { href: String(url), baseHref: base }; - parts.set(this, core.jsonOpSync("op_parse_url", parseArgs)); - } - } - - [Symbol.for("Deno.customInspect")](inspect) { - const object = { - href: this.href, - origin: this.origin, - protocol: this.protocol, - username: this.username, - password: this.password, - host: this.host, - hostname: this.hostname, - port: this.port, - pathname: this.pathname, - hash: this.hash, - search: this.search, - }; - return `${this.constructor.name} ${inspect(object)}`; - } - - #updateSearchParams = () => { - if (this.#searchParams != null) { - const params = paramLists.get(this.#searchParams); - const newParams = core.jsonOpSync( - "op_parse_url_search_params", - this.search.slice(1), - ); - params.splice(0, params.length, ...newParams); - } - }; - - get hash() { - return parts.get(this).hash; - } - - set hash(value) { - try { - const parseArgs = { href: this.href, setHash: String(value) }; - parts.set(this, core.jsonOpSync("op_parse_url", parseArgs)); - } catch { - /* pass */ - } - } - - get host() { - return parts.get(this).host; - } - - set host(value) { - try { - const parseArgs = { href: this.href, setHost: String(value) }; - parts.set(this, core.jsonOpSync("op_parse_url", parseArgs)); - } catch { - /* pass */ - } - } - - get hostname() { - return parts.get(this).hostname; - } - - set hostname(value) { - try { - const parseArgs = { href: this.href, setHostname: String(value) }; - parts.set(this, core.jsonOpSync("op_parse_url", parseArgs)); - } catch { - /* pass */ - } - } - - get href() { - return parts.get(this).href; - } - - set href(value) { - try { - const parseArgs = { href: String(value) }; - parts.set(this, core.jsonOpSync("op_parse_url", parseArgs)); - } catch { - throw new TypeError("Invalid URL"); - } - this.#updateSearchParams(); - } - - get origin() { - return parts.get(this).origin; - } - - get password() { - return parts.get(this).password; - } - - set password(value) { - try { - const parseArgs = { href: this.href, setPassword: String(value) }; - parts.set(this, core.jsonOpSync("op_parse_url", parseArgs)); - } catch { - /* pass */ - } - } - - get pathname() { - return parts.get(this).pathname; - } - - set pathname(value) { - try { - const parseArgs = { href: this.href, setPathname: String(value) }; - parts.set(this, core.jsonOpSync("op_parse_url", parseArgs)); - } catch { - /* pass */ - } - } - - get port() { - return parts.get(this).port; - } - - set port(value) { - try { - const parseArgs = { href: this.href, setPort: String(value) }; - parts.set(this, core.jsonOpSync("op_parse_url", parseArgs)); - } catch { - /* pass */ - } - } - - get protocol() { - return parts.get(this).protocol; - } - - set protocol(value) { - try { - const parseArgs = { href: this.href, setProtocol: String(value) }; - parts.set(this, core.jsonOpSync("op_parse_url", parseArgs)); - } catch { - /* pass */ - } - } - - get search() { - return parts.get(this).search; - } - - set search(value) { - try { - const parseArgs = { href: this.href, setSearch: String(value) }; - parts.set(this, core.jsonOpSync("op_parse_url", parseArgs)); - this.#updateSearchParams(); - } catch { - /* pass */ - } - } - - get username() { - return parts.get(this).username; - } - - set username(value) { - try { - const parseArgs = { href: this.href, setUsername: String(value) }; - parts.set(this, core.jsonOpSync("op_parse_url", parseArgs)); - } catch { - /* pass */ - } - } - - get searchParams() { - if (this.#searchParams == null) { - this.#searchParams = new URLSearchParams(this.search); - urls.set(this.#searchParams, this); - } - return this.#searchParams; - } - - toString() { - return this.href; - } - - toJSON() { - return this.href; - } - - static createObjectURL() { - throw new Error("Not implemented"); - } - - static revokeObjectURL() { - throw new Error("Not implemented"); - } - } - - window.__bootstrap.url = { - URL, - URLSearchParams, - }; -})(this); diff --git a/op_crates/web/Cargo.toml b/op_crates/web/Cargo.toml index d1d37c216..e86207881 100644 --- a/op_crates/web/Cargo.toml +++ b/op_crates/web/Cargo.toml @@ -15,7 +15,6 @@ path = "lib.rs" [dependencies] deno_core = { version = "0.80.2", path = "../../core" } -serde = { version = "1.0.123", features = ["derive"] } [dev-dependencies] futures = "0.3.12" diff --git a/op_crates/web/abort_controller_test.js b/op_crates/web/abort_controller_test.js deleted file mode 100644 index 26f58dccb..000000000 --- a/op_crates/web/abort_controller_test.js +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -"use strict"; -function assert(cond) { - if (!cond) { - throw Error("assert"); - } -} - -function assertEquals(left, right) { - assert(left === right); -} - -function assertThrows(fn) { - let error = null; - try { - fn(); - } catch (error_) { - error = error_; - } - if (error == null) { - throw new Error("Didn't throw."); - } - return error; -} - -function basicAbortController() { - const controller = new AbortController(); - assert(controller); - const { signal } = controller; - assert(signal); - assertEquals(signal.aborted, false); - controller.abort(); - assertEquals(signal.aborted, true); -} - -function signalCallsOnabort() { - const controller = new AbortController(); - const { signal } = controller; - let called = false; - signal.onabort = (evt) => { - assert(evt); - assertEquals(evt.type, "abort"); - called = true; - }; - controller.abort(); - assert(called); -} - -function signalEventListener() { - const controller = new AbortController(); - const { signal } = controller; - let called = false; - signal.addEventListener("abort", function (ev) { - assert(this === signal); - assertEquals(ev.type, "abort"); - called = true; - }); - controller.abort(); - assert(called); -} - -function onlyAbortsOnce() { - const controller = new AbortController(); - const { signal } = controller; - let called = 0; - signal.addEventListener("abort", () => called++); - signal.onabort = () => { - called++; - }; - controller.abort(); - assertEquals(called, 2); - controller.abort(); - assertEquals(called, 2); -} - -function controllerHasProperToString() { - const actual = Object.prototype.toString.call(new AbortController()); - assertEquals(actual, "[object AbortController]"); -} - -function abortSignalIllegalConstructor() { - const error = assertThrows(() => new AbortSignal()); - assert(error instanceof TypeError); - assertEquals(error.message, "Illegal constructor."); -} - -function abortSignalEventOrder() { - const arr = []; - const controller = new AbortController(); - const { signal } = controller; - signal.addEventListener("abort", () => arr.push(1)); - signal.onabort = () => arr.push(2); - signal.addEventListener("abort", () => arr.push(3)); - controller.abort(); - assertEquals(arr[0], 1); - assertEquals(arr[1], 2); - assertEquals(arr[2], 3); -} - -function abortSignalEventOrderComplex() { - const arr = []; - const controller = new AbortController(); - const { signal } = controller; - signal.addEventListener("abort", () => arr.push(1)); - signal.onabort = () => { - throw new Error(); - }; - signal.addEventListener("abort", () => arr.push(3)); - signal.onabort = () => arr.push(2); - controller.abort(); - assertEquals(arr[0], 1); - assertEquals(arr[1], 2); - assertEquals(arr[2], 3); -} - -function abortSignalHandlerLocation() { - const controller = new AbortController(); - const { signal } = controller; - const abortHandler = Object.getOwnPropertyDescriptor(signal, "onabort"); - assertEquals(abortHandler, undefined); -} -function abortSignalLength() { - const controller = new AbortController(); - const { signal } = controller; - assertEquals(signal.constructor.length, 0); -} -function main() { - basicAbortController(); - signalCallsOnabort(); - signalEventListener(); - onlyAbortsOnce(); - controllerHasProperToString(); - abortSignalIllegalConstructor(); - abortSignalEventOrder(); - abortSignalEventOrderComplex(); - abortSignalHandlerLocation(); - abortSignalLength(); -} - -main(); diff --git a/op_crates/web/event_target_test.js b/op_crates/web/event_target_test.js deleted file mode 100644 index acb75cc19..000000000 --- a/op_crates/web/event_target_test.js +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -"use strict"; -function assert(cond) { - if (!cond) { - throw Error("assert"); - } -} - -function addEventListenerTest() { - const document = new EventTarget(); - - assert(document.addEventListener("x", null, false) === undefined); - assert(document.addEventListener("x", null, true) === undefined); - assert(document.addEventListener("x", null) === undefined); -} - -function constructedEventTargetCanBeUsedAsExpected() { - const target = new EventTarget(); - const event = new Event("foo", { bubbles: true, cancelable: false }); - let callCount = 0; - - const listener = (e) => { - assert(e === event); - ++callCount; - }; - - target.addEventListener("foo", listener); - - target.dispatchEvent(event); - assert(callCount === 1); - - target.dispatchEvent(event); - assert(callCount === 2); - - target.removeEventListener("foo", listener); - target.dispatchEvent(event); - assert(callCount === 2); -} - -function anEventTargetCanBeSubclassed() { - class NicerEventTarget extends EventTarget { - on( - type, - callback, - options, - ) { - this.addEventListener(type, callback, options); - } - - off( - type, - callback, - options, - ) { - this.removeEventListener(type, callback, options); - } - } - - const target = new NicerEventTarget(); - new Event("foo", { bubbles: true, cancelable: false }); - let callCount = 0; - - const listener = () => { - ++callCount; - }; - - target.on("foo", listener); - assert(callCount === 0); - - target.off("foo", listener); - assert(callCount === 0); -} - -function removingNullEventListenerShouldSucceed() { - const document = new EventTarget(); - assert(document.removeEventListener("x", null, false) === undefined); - assert(document.removeEventListener("x", null, true) === undefined); - assert(document.removeEventListener("x", null) === undefined); -} - -function constructedEventTargetUseObjectPrototype() { - const target = new EventTarget(); - const event = new Event("toString", { bubbles: true, cancelable: false }); - let callCount = 0; - - const listener = (e) => { - assert(e === event); - ++callCount; - }; - - target.addEventListener("toString", listener); - - target.dispatchEvent(event); - assert(callCount === 1); - - target.dispatchEvent(event); - assert(callCount === 2); - - target.removeEventListener("toString", listener); - target.dispatchEvent(event); - assert(callCount === 2); -} - -function toStringShouldBeWebCompatible() { - const target = new EventTarget(); - assert(target.toString() === "[object EventTarget]"); -} - -function dispatchEventShouldNotThrowError() { - let hasThrown = false; - - try { - const target = new EventTarget(); - const event = new Event("hasOwnProperty", { - bubbles: true, - cancelable: false, - }); - const listener = () => {}; - target.addEventListener("hasOwnProperty", listener); - target.dispatchEvent(event); - } catch { - hasThrown = true; - } - - assert(hasThrown === false); -} - -function eventTargetThisShouldDefaultToWindow() { - const { - addEventListener, - dispatchEvent, - removeEventListener, - } = EventTarget.prototype; - let n = 1; - const event = new Event("hello"); - const listener = () => { - n = 2; - }; - - addEventListener("hello", listener); - globalThis.dispatchEvent(event); - assert(n === 2); - n = 1; - removeEventListener("hello", listener); - globalThis.dispatchEvent(event); - assert(n === 1); - - globalThis.addEventListener("hello", listener); - dispatchEvent(event); - assert(n === 2); - n = 1; - globalThis.removeEventListener("hello", listener); - dispatchEvent(event); - assert(n === 1); -} - -function eventTargetShouldAcceptEventListenerObject() { - const target = new EventTarget(); - const event = new Event("foo", { bubbles: true, cancelable: false }); - let callCount = 0; - - const listener = { - handleEvent(e) { - assert(e === event); - ++callCount; - }, - }; - - target.addEventListener("foo", listener); - - target.dispatchEvent(event); - assert(callCount === 1); - - target.dispatchEvent(event); - assert(callCount === 2); - - target.removeEventListener("foo", listener); - target.dispatchEvent(event); - assert(callCount === 2); -} - -function eventTargetShouldAcceptAsyncFunction() { - const target = new EventTarget(); - const event = new Event("foo", { bubbles: true, cancelable: false }); - let callCount = 0; - - const listener = (e) => { - assert(e === event); - ++callCount; - }; - - target.addEventListener("foo", listener); - - target.dispatchEvent(event); - assert(callCount === 1); - - target.dispatchEvent(event); - assert(callCount === 2); - - target.removeEventListener("foo", listener); - target.dispatchEvent(event); - assert(callCount === 2); -} - -function eventTargetShouldAcceptAsyncFunctionForEventListenerObject() { - const target = new EventTarget(); - const event = new Event("foo", { bubbles: true, cancelable: false }); - let callCount = 0; - - const listener = { - handleEvent(e) { - assert(e === event); - ++callCount; - }, - }; - - target.addEventListener("foo", listener); - - target.dispatchEvent(event); - assert(callCount === 1); - - target.dispatchEvent(event); - assert(callCount === 2); - - target.removeEventListener("foo", listener); - target.dispatchEvent(event); - assert(callCount === 2); -} - -function main() { - globalThis.__bootstrap.eventTarget.setEventTargetData(globalThis); - addEventListenerTest(); - constructedEventTargetCanBeUsedAsExpected(); - anEventTargetCanBeSubclassed(); - removingNullEventListenerShouldSucceed(); - constructedEventTargetUseObjectPrototype(); - toStringShouldBeWebCompatible(); - dispatchEventShouldNotThrowError(); - eventTargetThisShouldDefaultToWindow(); - eventTargetShouldAcceptEventListenerObject(); - eventTargetShouldAcceptAsyncFunction(); - eventTargetShouldAcceptAsyncFunctionForEventListenerObject(); -} - -main(); diff --git a/op_crates/web/event_test.js b/op_crates/web/event_test.js deleted file mode 100644 index fa92a3e07..000000000 --- a/op_crates/web/event_test.js +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -"use strict"; -function assert(cond) { - if (!cond) { - throw Error("assert"); - } -} - -function eventInitializedWithType() { - const type = "click"; - const event = new Event(type); - - assert(event.isTrusted === false); - assert(event.target === null); - assert(event.currentTarget === null); - assert(event.type === "click"); - assert(event.bubbles === false); - assert(event.cancelable === false); -} - -function eventInitializedWithTypeAndDict() { - const init = "submit"; - const eventInit = { bubbles: true, cancelable: true }; - const event = new Event(init, eventInit); - - assert(event.isTrusted === false); - assert(event.target === null); - assert(event.currentTarget === null); - assert(event.type === "submit"); - assert(event.bubbles === true); - assert(event.cancelable === true); -} - -function eventComposedPathSuccess() { - const type = "click"; - const event = new Event(type); - const composedPath = event.composedPath(); - - assert(composedPath.length === 0); -} - -function eventStopPropagationSuccess() { - const type = "click"; - const event = new Event(type); - - assert(event.cancelBubble === false); - event.stopPropagation(); - assert(event.cancelBubble === true); -} - -function eventStopImmediatePropagationSuccess() { - const type = "click"; - const event = new Event(type); - - assert(event.cancelBubble === false); - event.stopImmediatePropagation(); - assert(event.cancelBubble === true); -} - -function eventPreventDefaultSuccess() { - const type = "click"; - const event = new Event(type); - - assert(event.defaultPrevented === false); - event.preventDefault(); - assert(event.defaultPrevented === false); - - const eventInit = { bubbles: true, cancelable: true }; - const cancelableEvent = new Event(type, eventInit); - assert(cancelableEvent.defaultPrevented === false); - cancelableEvent.preventDefault(); - assert(cancelableEvent.defaultPrevented === true); -} - -function eventInitializedWithNonStringType() { - const type = undefined; - const event = new Event(type); - - assert(event.isTrusted === false); - assert(event.target === null); - assert(event.currentTarget === null); - assert(event.type === "undefined"); - assert(event.bubbles === false); - assert(event.cancelable === false); -} - -// ref https://github.com/web-platform-tests/wpt/blob/master/dom/events/Event-isTrusted.any.js -function eventIsTrusted() { - const desc1 = Object.getOwnPropertyDescriptor(new Event("x"), "isTrusted"); - assert(desc1); - assert(typeof desc1.get === "function"); - - const desc2 = Object.getOwnPropertyDescriptor(new Event("x"), "isTrusted"); - assert(desc2); - assert(typeof desc2.get === "function"); - - assert(desc1.get === desc2.get); -} - -function eventIsTrustedGetterName() { - const { get } = Object.getOwnPropertyDescriptor(new Event("x"), "isTrusted"); - assert(get.name === "get isTrusted"); - try { - Reflect.construct(get); - throw new Error("Should not have reached here"); - } catch (e) { - assert(e.message.includes("not a constructor")); - } -} -function eventAbortSignal() { - let count = 0; - function handler() { - count++; - } - const et = new EventTarget(); - const controller = new AbortController(); - et.addEventListener("test", handler, { signal: controller.signal }); - et.dispatchEvent(new Event("test")); - assert(count === 1); - et.dispatchEvent(new Event("test")); - assert(count === 2); - controller.abort(); - et.dispatchEvent(new Event("test")); - assert(count === 2); - et.addEventListener("test", handler, { signal: controller.signal }); - et.dispatchEvent(new Event("test")); - assert(count === 2); -} -function main() { - eventInitializedWithType(); - eventInitializedWithTypeAndDict(); - eventComposedPathSuccess(); - eventStopPropagationSuccess(); - eventStopImmediatePropagationSuccess(); - eventPreventDefaultSuccess(); - eventInitializedWithNonStringType(); - eventIsTrusted(); - eventIsTrustedGetterName(); - eventAbortSignal(); -} - -main(); diff --git a/op_crates/web/internal.d.ts b/op_crates/web/internal.d.ts index efafee26c..458f4a173 100644 --- a/op_crates/web/internal.d.ts +++ b/op_crates/web/internal.d.ts @@ -1,301 +1,14 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -// deno-lint-ignore-file no-explicit-any ban-types /// <reference no-default-lib="true" /> /// <reference lib="esnext" /> declare namespace globalThis { declare namespace __bootstrap { - declare namespace webidl { - declare interface ConverterOpts { - /** - * The prefix for error messages created by this converter. - * Examples: - * - `Failed to construct 'Event'` - * - `Failed to execute 'removeEventListener' on 'EventTarget'` - */ - prefix: string; - } - declare interface ValueConverterOpts extends ConverterOpts { - /** - * The context of this value error messages created by this converter. - * Examples: - * - `Argument 1` - * - `Argument 3` - */ - context: string; - } - declare function makeException( - ErrorType: any, - message: string, - opts: ValueConverterOpts, - ): any; - declare interface IntConverterOpts extends ValueConverterOpts { - /** - * Wether to throw if the number is outside of the acceptable values for - * this type. - */ - enforceRange?: boolean; - /** - * Wether to clamp this number to the acceptable values for this type. - */ - clamp?: boolean; - } - declare interface StringConverterOpts extends ValueConverterOpts { - /** - * Wether to treat `null` value as an empty string. - */ - treatNullAsEmptyString?: boolean; - } - declare interface BufferConverterOpts extends ValueConverterOpts { - /** - * Wether to allow `SharedArrayBuffer` (not just `ArrayBuffer`). - */ - allowShared?: boolean; - } - declare const converters: { - any(v: any): any; - /** - * Convert a value into a `boolean` (bool). - */ - boolean(v: any, opts?: IntConverterOpts): boolean; - /** - * Convert a value into a `byte` (int8). - */ - byte(v: any, opts?: IntConverterOpts): number; - /** - * Convert a value into a `octet` (uint8). - */ - octet(v: any, opts?: IntConverterOpts): number; - /** - * Convert a value into a `short` (int16). - */ - short(v: any, opts?: IntConverterOpts): number; - /** - * Convert a value into a `unsigned short` (uint16). - */ - ["unsigned short"](v: any, opts?: IntConverterOpts): number; - /** - * Convert a value into a `long` (int32). - */ - long(v: any, opts?: IntConverterOpts): number; - /** - * Convert a value into a `unsigned long` (uint32). - */ - ["unsigned long"](v: any, opts?: IntConverterOpts): number; - /** - * Convert a value into a `long long` (int64). - * **Note this is truncated to a JS number (53 bit precision).** - */ - ["long long"](v: any, opts?: IntConverterOpts): number; - /** - * Convert a value into a `unsigned long long` (uint64). - * **Note this is truncated to a JS number (53 bit precision).** - */ - ["unsigned long long"](v: any, opts?: IntConverterOpts): number; - /** - * Convert a value into a `float` (f32). - */ - float(v: any, opts?: ValueConverterOpts): number; - /** - * Convert a value into a `unrestricted float` (f32, infinity, or NaN). - */ - ["unrestricted float"](v: any, opts?: ValueConverterOpts): number; - /** - * Convert a value into a `double` (f64). - */ - double(v: any, opts?: ValueConverterOpts): number; - /** - * Convert a value into a `unrestricted double` (f64, infinity, or NaN). - */ - ["unrestricted double"](v: any, opts?: ValueConverterOpts): number; - /** - * Convert a value into a `DOMString` (string). - */ - DOMString(v: any, opts?: StringConverterOpts): string; - /** - * Convert a value into a `ByteString` (string with only u8 codepoints). - */ - ByteString(v: any, opts?: StringConverterOpts): string; - /** - * Convert a value into a `USVString` (string with only valid non - * surrogate Unicode code points). - */ - USVString(v: any, opts?: StringConverterOpts): string; - /** - * Convert a value into an `object` (object). - */ - object(v: any, opts?: ValueConverterOpts): object; - /** - * Convert a value into an `ArrayBuffer` (ArrayBuffer). - */ - ArrayBuffer(v: any, opts?: BufferConverterOpts): ArrayBuffer; - /** - * Convert a value into a `DataView` (ArrayBuffer). - */ - DataView(v: any, opts?: BufferConverterOpts): DataView; - /** - * Convert a value into a `Int8Array` (Int8Array). - */ - Int8Array(v: any, opts?: BufferConverterOpts): Int8Array; - /** - * Convert a value into a `Int16Array` (Int16Array). - */ - Int16Array(v: any, opts?: BufferConverterOpts): Int16Array; - /** - * Convert a value into a `Int32Array` (Int32Array). - */ - Int32Array(v: any, opts?: BufferConverterOpts): Int32Array; - /** - * Convert a value into a `Uint8Array` (Uint8Array). - */ - Uint8Array(v: any, opts?: BufferConverterOpts): Uint8Array; - /** - * Convert a value into a `Uint16Array` (Uint16Array). - */ - Uint16Array(v: any, opts?: BufferConverterOpts): Uint16Array; - /** - * Convert a value into a `Uint32Array` (Uint32Array). - */ - Uint32Array(v: any, opts?: BufferConverterOpts): Uint32Array; - /** - * Convert a value into a `Uint8ClampedArray` (Uint8ClampedArray). - */ - Uint8ClampedArray( - v: any, - opts?: BufferConverterOpts, - ): Uint8ClampedArray; - /** - * Convert a value into a `Float32Array` (Float32Array). - */ - Float32Array(v: any, opts?: BufferConverterOpts): Float32Array; - /** - * Convert a value into a `Float64Array` (Float64Array). - */ - Float64Array(v: any, opts?: BufferConverterOpts): Float64Array; - /** - * Convert a value into an `ArrayBufferView` (ArrayBufferView). - */ - ArrayBufferView(v: any, opts?: BufferConverterOpts): ArrayBufferView; - /** - * Convert a value into a `BufferSource` (ArrayBuffer or ArrayBufferView). - */ - BufferSource( - v: any, - opts?: BufferConverterOpts, - ): ArrayBuffer | ArrayBufferView; - /** - * Convert a value into a `DOMTimeStamp` (u64). Alias for unsigned long long - */ - DOMTimeStamp(v: any, opts?: IntConverterOpts): number; - /** - * Convert a value into a `Function` ((...args: any[]) => any). - */ - Function(v: any, opts?: ValueConverterOpts): (...args: any) => any; - /** - * Convert a value into a `VoidFunction` (() => void). - */ - VoidFunction(v: any, opts?: ValueConverterOpts): () => void; - ["UVString?"](v: any, opts?: ValueConverterOpts): string | null; - ["sequence<double>"](v: any, opts?: ValueConverterOpts): number[]; - - [type: string]: (v: any, opts: ValueConverterOpts) => any; - }; - - /** - * Assert that the a function has at least a required amount of arguments. - */ - declare function requiredArguments( - length: number, - required: number, - opts: ConverterOpts, - ): void; - declare type Dictionary = DictionaryMember[]; - declare interface DictionaryMember { - key: string; - converter: (v: any, opts: ValueConverterOpts) => any; - defaultValue?: any; - required?: boolean; - } - - /** - * Create a converter for dictionaries. - */ - declare function createDictionaryConverter<T>( - name: string, - ...dictionaries: Dictionary[] - ): (v: any, opts: ValueConverterOpts) => T; - - /** - * Create a converter for enums. - */ - declare function createEnumConverter( - name: string, - values: string[], - ): (v: any, opts: ValueConverterOpts) => string; - - /** - * Create a converter that makes the contained type nullable. - */ - declare function createNullableConverter<T>( - converter: (v: any, opts: ValueConverterOpts) => T, - ): (v: any, opts: ValueConverterOpts) => T | null; - - /** - * Create a converter that converts a sequence of the inner type. - */ - declare function createSequenceConverter<T>( - converter: (v: any, opts: ValueConverterOpts) => T, - ): (v: any, opts: ValueConverterOpts) => T[]; - - /** - * Throw an illegal constructor error. - */ - declare function illegalConstructor(): never; - - /** - * The branding symbol. - */ - declare const brand: unique symbol; - - /** - * Create a branded instance of an interface. - */ - declare function createBranded(self: any): any; - - /** - * Assert that self is branded. - */ - declare function assertBranded(self: any, type: any): void; - - /** - * Create a converter for interfaces. - */ - declare function createInterfaceConverter( - name: string, - prototype: any, - ): (v: any, opts: ValueConverterOpts) => any; - - declare function createRecordConverter< - K extends string | number | symbol, - V, - >( - keyConverter: (v: any, opts: ValueConverterOpts) => K, - valueConverter: (v: any, opts: ValueConverterOpts) => V, - ): ( - v: Record<K, V>, - opts: ValueConverterOpts, - ) => any; - } - declare var eventTarget: { EventTarget: typeof EventTarget; }; - declare var url: { - URLSearchParams: typeof URLSearchParams; - }; - declare var location: { getLocationHref(): string | undefined; }; diff --git a/op_crates/web/lib.deno_web.d.ts b/op_crates/web/lib.deno_web.d.ts index 24a8f929d..79b56f68e 100644 --- a/op_crates/web/lib.deno_web.d.ts +++ b/op_crates/web/lib.deno_web.d.ts @@ -313,172 +313,3 @@ declare var FileReader: { readonly EMPTY: number; readonly LOADING: number; }; - -declare class URLSearchParams { - constructor( - init?: string[][] | Record<string, string> | string | URLSearchParams, - ); - static toString(): string; - - /** Appends a specified key/value pair as a new search parameter. - * - * ```ts - * let searchParams = new URLSearchParams(); - * searchParams.append('name', 'first'); - * searchParams.append('name', 'second'); - * ``` - */ - append(name: string, value: string): void; - - /** Deletes the given search parameter and its associated value, - * from the list of all search parameters. - * - * ```ts - * let searchParams = new URLSearchParams([['name', 'value']]); - * searchParams.delete('name'); - * ``` - */ - delete(name: string): void; - - /** Returns all the values associated with a given search parameter - * as an array. - * - * ```ts - * searchParams.getAll('name'); - * ``` - */ - getAll(name: string): string[]; - - /** Returns the first value associated to the given search parameter. - * - * ```ts - * searchParams.get('name'); - * ``` - */ - get(name: string): string | null; - - /** Returns a Boolean that indicates whether a parameter with the - * specified name exists. - * - * ```ts - * searchParams.has('name'); - * ``` - */ - has(name: string): boolean; - - /** Sets the value associated with a given search parameter to the - * given value. If there were several matching values, this method - * deletes the others. If the search parameter doesn't exist, this - * method creates it. - * - * ```ts - * searchParams.set('name', 'value'); - * ``` - */ - set(name: string, value: string): void; - - /** Sort all key/value pairs contained in this object in place and - * return undefined. The sort order is according to Unicode code - * points of the keys. - * - * ```ts - * searchParams.sort(); - * ``` - */ - sort(): void; - - /** Calls a function for each element contained in this object in - * place and return undefined. Optionally accepts an object to use - * as this when executing callback as second argument. - * - * ```ts - * const params = new URLSearchParams([["a", "b"], ["c", "d"]]); - * params.forEach((value, key, parent) => { - * console.log(value, key, parent); - * }); - * ``` - * - */ - forEach( - callbackfn: (value: string, key: string, parent: this) => void, - thisArg?: any, - ): void; - - /** Returns an iterator allowing to go through all keys contained - * in this object. - * - * ```ts - * const params = new URLSearchParams([["a", "b"], ["c", "d"]]); - * for (const key of params.keys()) { - * console.log(key); - * } - * ``` - */ - keys(): IterableIterator<string>; - - /** Returns an iterator allowing to go through all values contained - * in this object. - * - * ```ts - * const params = new URLSearchParams([["a", "b"], ["c", "d"]]); - * for (const value of params.values()) { - * console.log(value); - * } - * ``` - */ - values(): IterableIterator<string>; - - /** Returns an iterator allowing to go through all key/value - * pairs contained in this object. - * - * ```ts - * const params = new URLSearchParams([["a", "b"], ["c", "d"]]); - * for (const [key, value] of params.entries()) { - * console.log(key, value); - * } - * ``` - */ - entries(): IterableIterator<[string, string]>; - - /** Returns an iterator allowing to go through all key/value - * pairs contained in this object. - * - * ```ts - * const params = new URLSearchParams([["a", "b"], ["c", "d"]]); - * for (const [key, value] of params) { - * console.log(key, value); - * } - * ``` - */ - [Symbol.iterator](): IterableIterator<[string, string]>; - - /** Returns a query string suitable for use in a URL. - * - * ```ts - * searchParams.toString(); - * ``` - */ - toString(): string; -} - -/** The URL interface represents an object providing static methods used for creating object URLs. */ -declare class URL { - constructor(url: string, base?: string | URL); - createObjectURL(object: any): string; - revokeObjectURL(url: string): void; - - hash: string; - host: string; - hostname: string; - href: string; - toString(): string; - readonly origin: string; - password: string; - pathname: string; - port: string; - protocol: string; - search: string; - readonly searchParams: URLSearchParams; - username: string; - toJSON(): string; -} diff --git a/op_crates/web/lib.rs b/op_crates/web/lib.rs index f67fd81a1..af7a7cebc 100644 --- a/op_crates/web/lib.rs +++ b/op_crates/web/lib.rs @@ -1,30 +1,12 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use deno_core::error::generic_error; -use deno_core::error::type_error; -use deno_core::error::uri_error; -use deno_core::error::AnyError; -use deno_core::serde_json; -use deno_core::serde_json::json; -use deno_core::serde_json::Value; -use deno_core::url::form_urlencoded; -use deno_core::url::quirks; -use deno_core::url::Url; use deno_core::JsRuntime; -use deno_core::ZeroCopyBuf; -use serde::Deserialize; -use serde::Serialize; -use std::panic::catch_unwind; use std::path::PathBuf; /// Load and execute the javascript code. pub fn init(isolate: &mut JsRuntime) { let files = vec![ ( - "deno:op_crates/web/00_webidl.js", - include_str!("00_webidl.js"), - ), - ( "deno:op_crates/web/01_dom_exception.js", include_str!("01_dom_exception.js"), ), @@ -44,7 +26,6 @@ pub fn init(isolate: &mut JsRuntime) { "deno:op_crates/web/08_text_encoding.js", include_str!("08_text_encoding.js"), ), - ("deno:op_crates/web/11_url.js", include_str!("11_url.js")), ( "deno:op_crates/web/12_location.js", include_str!("12_location.js"), @@ -59,213 +40,6 @@ pub fn init(isolate: &mut JsRuntime) { } } -/// Parse `UrlParseArgs::href` with an optional `UrlParseArgs::base_href`, or an -/// optional part to "set" after parsing. Return `UrlParts`. -pub fn op_parse_url( - _state: &mut deno_core::OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase")] - struct UrlParseArgs { - href: String, - base_href: Option<String>, - // If one of the following are present, this is a setter call. Apply the - // proper `Url::set_*()` method after (re)parsing `href`. - set_hash: Option<String>, - set_host: Option<String>, - set_hostname: Option<String>, - set_password: Option<String>, - set_pathname: Option<String>, - set_port: Option<String>, - set_protocol: Option<String>, - set_search: Option<String>, - set_username: Option<String>, - } - let args: UrlParseArgs = serde_json::from_value(args)?; - let base_url = args - .base_href - .as_ref() - .map(|b| Url::parse(b).map_err(|_| type_error("Invalid base URL"))) - .transpose()?; - let mut url = Url::options() - .base_url(base_url.as_ref()) - .parse(&args.href) - .map_err(|_| type_error("Invalid URL"))?; - - if let Some(hash) = args.set_hash.as_ref() { - quirks::set_hash(&mut url, hash); - } else if let Some(host) = args.set_host.as_ref() { - quirks::set_host(&mut url, host).map_err(|_| uri_error("Invalid host"))?; - } else if let Some(hostname) = args.set_hostname.as_ref() { - quirks::set_hostname(&mut url, hostname) - .map_err(|_| uri_error("Invalid hostname"))?; - } else if let Some(password) = args.set_password.as_ref() { - quirks::set_password(&mut url, password) - .map_err(|_| uri_error("Invalid password"))?; - } else if let Some(pathname) = args.set_pathname.as_ref() { - quirks::set_pathname(&mut url, pathname); - } else if let Some(port) = args.set_port.as_ref() { - quirks::set_port(&mut url, port).map_err(|_| uri_error("Invalid port"))?; - } else if let Some(protocol) = args.set_protocol.as_ref() { - quirks::set_protocol(&mut url, protocol) - .map_err(|_| uri_error("Invalid protocol"))?; - } else if let Some(search) = args.set_search.as_ref() { - quirks::set_search(&mut url, search); - } else if let Some(username) = args.set_username.as_ref() { - quirks::set_username(&mut url, username) - .map_err(|_| uri_error("Invalid username"))?; - } - - #[derive(Serialize)] - struct UrlParts<'a> { - href: &'a str, - hash: &'a str, - host: &'a str, - hostname: &'a str, - origin: &'a str, - password: &'a str, - pathname: &'a str, - port: &'a str, - protocol: &'a str, - search: &'a str, - username: &'a str, - } - // TODO(nayeemrmn): Panic that occurs in rust-url for the `non-spec:` - // url-constructor wpt tests: https://github.com/servo/rust-url/issues/670. - let username = catch_unwind(|| quirks::username(&url)).map_err(|_| { - generic_error(format!( - "Internal error while parsing \"{}\"{}, \ - see https://github.com/servo/rust-url/issues/670", - args.href, - args - .base_href - .map(|b| format!(" against \"{}\"", b)) - .unwrap_or_default() - )) - })?; - Ok(json!(UrlParts { - href: quirks::href(&url), - hash: quirks::hash(&url), - host: quirks::host(&url), - hostname: quirks::hostname(&url), - origin: &quirks::origin(&url), - password: quirks::password(&url), - pathname: quirks::pathname(&url), - port: quirks::port(&url), - protocol: quirks::protocol(&url), - search: quirks::search(&url), - username, - })) -} - -pub fn op_parse_url_search_params( - _state: &mut deno_core::OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - let search: String = serde_json::from_value(args)?; - let search_params: Vec<_> = form_urlencoded::parse(search.as_bytes()) - .into_iter() - .collect(); - Ok(json!(search_params)) -} - -pub fn op_stringify_url_search_params( - _state: &mut deno_core::OpState, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<Value, AnyError> { - let search_params: Vec<(String, String)> = serde_json::from_value(args)?; - let search = form_urlencoded::Serializer::new(String::new()) - .extend_pairs(search_params) - .finish(); - Ok(json!(search)) -} - pub fn get_declaration() -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_web.d.ts") } - -#[cfg(test)] -mod tests { - use deno_core::JsRuntime; - use futures::future::lazy; - use futures::task::Context; - use futures::task::Poll; - - fn run_in_task<F>(f: F) - where - F: FnOnce(&mut Context) + Send + 'static, - { - futures::executor::block_on(lazy(move |cx| f(cx))); - } - - fn setup() -> JsRuntime { - let mut isolate = JsRuntime::new(Default::default()); - crate::init(&mut isolate); - isolate - } - - #[test] - fn test_abort_controller() { - run_in_task(|mut cx| { - let mut isolate = setup(); - isolate - .execute( - "abort_controller_test.js", - include_str!("abort_controller_test.js"), - ) - .unwrap(); - if let Poll::Ready(Err(_)) = isolate.poll_event_loop(&mut cx) { - unreachable!(); - } - }); - } - - #[test] - fn test_event() { - run_in_task(|mut cx| { - let mut isolate = setup(); - isolate - .execute("event_test.js", include_str!("event_test.js")) - .unwrap(); - if let Poll::Ready(Err(_)) = isolate.poll_event_loop(&mut cx) { - unreachable!(); - } - }); - } - - #[test] - fn test_event_error() { - run_in_task(|mut cx| { - let mut isolate = setup(); - let result = isolate.execute("foo.js", "new Event()"); - if let Err(error) = result { - let error_string = error.to_string(); - // Test that the script specifier is a URL: `deno:<repo-relative path>`. - assert!(error_string.contains("deno:op_crates/web/02_event.js")); - assert!(error_string.contains("TypeError")); - } else { - unreachable!(); - } - if let Poll::Ready(Err(_)) = isolate.poll_event_loop(&mut cx) { - unreachable!(); - } - }); - } - - #[test] - fn test_event_target() { - run_in_task(|mut cx| { - let mut isolate = setup(); - isolate - .execute("event_target_test.js", include_str!("event_target_test.js")) - .unwrap(); - if let Poll::Ready(Err(_)) = isolate.poll_event_loop(&mut cx) { - unreachable!(); - } - }); - } -} |