diff options
Diffstat (limited to 'op_crates/webidl')
-rw-r--r-- | op_crates/webidl/00_webidl.js | 810 | ||||
-rw-r--r-- | op_crates/webidl/Cargo.toml | 17 | ||||
-rw-r--r-- | op_crates/webidl/README.md | 6 | ||||
-rw-r--r-- | op_crates/webidl/internal.d.ts | 291 | ||||
-rw-r--r-- | op_crates/webidl/lib.rs | 14 |
5 files changed, 1138 insertions, 0 deletions
diff --git a/op_crates/webidl/00_webidl.js b/op_crates/webidl/00_webidl.js new file mode 100644 index 000000000..c00c605e8 --- /dev/null +++ b/op_crates/webidl/00_webidl.js @@ -0,0 +1,810 @@ +// 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/webidl/Cargo.toml b/op_crates/webidl/Cargo.toml new file mode 100644 index 000000000..5d2b17999 --- /dev/null +++ b/op_crates/webidl/Cargo.toml @@ -0,0 +1,17 @@ +# Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + +[package] +name = "deno_webidl" +version = "0.1.0" +edition = "2018" +description = "WebIDL implementation for Deno" +authors = ["the Deno authors"] +license = "MIT" +readme = "README.md" +repository = "https://github.com/denoland/deno" + +[lib] +path = "lib.rs" + +[dependencies] +deno_core = { version = "0.80.2", path = "../../core" } diff --git a/op_crates/webidl/README.md b/op_crates/webidl/README.md new file mode 100644 index 000000000..ce2d661e3 --- /dev/null +++ b/op_crates/webidl/README.md @@ -0,0 +1,6 @@ +# deno_webidl + +This crate implements WebIDL for Deno. It consists of infrastructure to do ECMA +-> WebIDL conversions. + +Spec: https://heycam.github.io/webidl/ diff --git a/op_crates/webidl/internal.d.ts b/op_crates/webidl/internal.d.ts new file mode 100644 index 000000000..425ee674e --- /dev/null +++ b/op_crates/webidl/internal.d.ts @@ -0,0 +1,291 @@ +// 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; + } + } +} diff --git a/op_crates/webidl/lib.rs b/op_crates/webidl/lib.rs new file mode 100644 index 000000000..7e617c7a7 --- /dev/null +++ b/op_crates/webidl/lib.rs @@ -0,0 +1,14 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +use deno_core::JsRuntime; + +/// Load and execute the javascript code. +pub fn init(isolate: &mut JsRuntime) { + let files = vec![( + "deno:op_crates/webidl/00_webidl.js", + include_str!("00_webidl.js"), + )]; + for (url, source_code) in files { + isolate.execute(url, source_code).unwrap(); + } +} |