From 0399f84dc5f8c69367d64312d2947455dbfa6ace Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Fri, 21 Feb 2020 07:59:50 +0000 Subject: [PATCH 001/254] --- compile.js | 81 + htmlparser2.js | 6199 ++++++++++++++++++++++++++++++++++++++++++++++++ index.html | 60 + 3 files changed, 6340 insertions(+) create mode 100644 compile.js create mode 100644 htmlparser2.js create mode 100644 index.html diff --git a/compile.js b/compile.js new file mode 100644 index 0000000..472779e --- /dev/null +++ b/compile.js @@ -0,0 +1,81 @@ +"use strict"; +const htmlparser = window.htmlparser2; + +const html2hyperscript = (input, stream) => { + let indentLevel = 0; + let attrOpen = false; + let justClosed = false; + let size = 0; + const streamWrite = stream.write; + stream.write = (...chunk) => ((size += chunk.length), streamWrite(...chunk)); + + const parser = new htmlparser.Parser( + { + onopentag(name, attr) { + if (justClosed) { + justClosed = false; + } + stream.write("\n" + "\t".repeat(indentLevel++) + `${name}`); + let attrKeys = Object.keys(attr); + if (attrKeys.length) { + let selector = ""; + if (attr.id) selector += "#" + attr.id.split(" ").join("#"); + if (attr.class) selector += "." + attr.class.split(" ").join("."); + if (selector) stream.write(`["${selector}"]`); + stream.write("("); + + attrKeys = attrKeys.filter(name => !["class", "id"].includes(name)); + if (attrKeys.length) { + stream.write(JSON.stringify(attr), ", "); + attrOpen = true; + } + } else { + stream.write("("); + } + }, + + oncomment(comments) { + justClosed = false; + (comments = comments.trim()) && + comments.split("\n").forEach(comment => + stream.write( + "\n// " + "\t".repeat(indentLevel) + comment.trim(), + // Strip whitespace and prepend ; to every line of comment + ), + ); + }, + + ontext(text) { + if (!text.trim()) return; + if (attrOpen) attrOpen = false; + justClosed = false; + stream.write(`\`${text.replace(/`/g, String.raw`\``)}\``); + }, + + onclosetag() { + if (justClosed) stream.pop(); + if (attrOpen) { + stream.pop(); + stream.pop(); + attrOpen = false; + } + justClosed = true; + stream.write("),"); + indentLevel--; + }, + + onend() { + if (justClosed) stream.pop(); + if (size) stream.write(";\n"); + stream.end(); + }, + }, + { decodeEntities: true }, + ); + + parser.write(input); + parser.end(); + return stream; +}; + +window.compile = html2hyperscript; diff --git a/htmlparser2.js b/htmlparser2.js new file mode 100644 index 0000000..d41e302 --- /dev/null +++ b/htmlparser2.js @@ -0,0 +1,6199 @@ +(function(f) { + if (typeof exports === "object" && typeof module !== "undefined") { + module.exports = f(); + } else if (typeof define === "function" && define.amd) { + define([], f); + } else { + var g; + if (typeof window !== "undefined") { + g = window; + } else if (typeof global !== "undefined") { + g = global; + } else if (typeof self !== "undefined") { + g = self; + } else { + g = this; + } + g.htmlparser2 = f(); + } +})(function() { + var define, module, exports; + return (function() { + function r(e, n, t) { + function o(i, f) { + if (!n[i]) { + if (!e[i]) { + var c = "function" == typeof require && require; + if (!f && c) return c(i, !0); + if (u) return u(i, !0); + var a = new Error("Cannot find module '" + i + "'"); + throw ((a.code = "MODULE_NOT_FOUND"), a); + } + var p = (n[i] = { exports: {} }); + e[i][0].call( + p.exports, + function(r) { + var n = e[i][1][r]; + return o(n || r); + }, + p, + p.exports, + r, + e, + n, + t, + ); + } + return n[i].exports; + } + for ( + var u = "function" == typeof require && require, i = 0; + i < t.length; + i++ + ) + o(t[i]); + return o; + } + return r; + })()( + { + 1: [function(require, module, exports) {}, {}], + 2: [ + function(require, module, exports) { + // Copyright Joyent, Inc. and other Node contributors. + // + // Permission is hereby granted, free of charge, to any person obtaining a + // copy of this software and associated documentation files (the + // "Software"), to deal in the Software without restriction, including + // without limitation the rights to use, copy, modify, merge, publish, + // distribute, sublicense, and/or sell copies of the Software, and to permit + // persons to whom the Software is furnished to do so, subject to the + // following conditions: + // + // The above copyright notice and this permission notice shall be included + // in all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + // USE OR OTHER DEALINGS IN THE SOFTWARE. + + var objectCreate = Object.create || objectCreatePolyfill; + var objectKeys = Object.keys || objectKeysPolyfill; + var bind = Function.prototype.bind || functionBindPolyfill; + + function EventEmitter() { + if ( + !this._events || + !Object.prototype.hasOwnProperty.call(this, "_events") + ) { + this._events = objectCreate(null); + this._eventsCount = 0; + } + + this._maxListeners = this._maxListeners || undefined; + } + module.exports = EventEmitter; + + // Backwards-compat with node 0.10.x + EventEmitter.EventEmitter = EventEmitter; + + EventEmitter.prototype._events = undefined; + EventEmitter.prototype._maxListeners = undefined; + + // By default EventEmitters will print a warning if more than 10 listeners are + // added to it. This is a useful default which helps finding memory leaks. + var defaultMaxListeners = 10; + + var hasDefineProperty; + try { + var o = {}; + if (Object.defineProperty) + Object.defineProperty(o, "x", { value: 0 }); + hasDefineProperty = o.x === 0; + } catch (err) { + hasDefineProperty = false; + } + if (hasDefineProperty) { + Object.defineProperty(EventEmitter, "defaultMaxListeners", { + enumerable: true, + get: function() { + return defaultMaxListeners; + }, + set: function(arg) { + // check whether the input is a positive number (whose value is zero or + // greater and not a NaN). + if (typeof arg !== "number" || arg < 0 || arg !== arg) + throw new TypeError( + '"defaultMaxListeners" must be a positive number', + ); + defaultMaxListeners = arg; + }, + }); + } else { + EventEmitter.defaultMaxListeners = defaultMaxListeners; + } + + // Obviously not all Emitters should be limited to 10. This function allows + // that to be increased. Set to zero for unlimited. + EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { + if (typeof n !== "number" || n < 0 || isNaN(n)) + throw new TypeError('"n" argument must be a positive number'); + this._maxListeners = n; + return this; + }; + + function $getMaxListeners(that) { + if (that._maxListeners === undefined) + return EventEmitter.defaultMaxListeners; + return that._maxListeners; + } + + EventEmitter.prototype.getMaxListeners = function getMaxListeners() { + return $getMaxListeners(this); + }; + + // These standalone emit* functions are used to optimize calling of event + // handlers for fast cases because emit() itself often has a variable number of + // arguments and can be deoptimized because of that. These functions always have + // the same number of arguments and thus do not get deoptimized, so the code + // inside them can execute faster. + function emitNone(handler, isFn, self) { + if (isFn) handler.call(self); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) listeners[i].call(self); + } + } + function emitOne(handler, isFn, self, arg1) { + if (isFn) handler.call(self, arg1); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) listeners[i].call(self, arg1); + } + } + function emitTwo(handler, isFn, self, arg1, arg2) { + if (isFn) handler.call(self, arg1, arg2); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) listeners[i].call(self, arg1, arg2); + } + } + function emitThree(handler, isFn, self, arg1, arg2, arg3) { + if (isFn) handler.call(self, arg1, arg2, arg3); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].call(self, arg1, arg2, arg3); + } + } + + function emitMany(handler, isFn, self, args) { + if (isFn) handler.apply(self, args); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) listeners[i].apply(self, args); + } + } + + EventEmitter.prototype.emit = function emit(type) { + var er, handler, len, args, i, events; + var doError = type === "error"; + + events = this._events; + if (events) doError = doError && events.error == null; + else if (!doError) return false; + + // If there is no 'error' event listener then throw. + if (doError) { + if (arguments.length > 1) er = arguments[1]; + if (er instanceof Error) { + throw er; // Unhandled 'error' event + } else { + // At least give some kind of context to the user + var err = new Error('Unhandled "error" event. (' + er + ")"); + err.context = er; + throw err; + } + return false; + } + + handler = events[type]; + + if (!handler) return false; + + var isFn = typeof handler === "function"; + len = arguments.length; + switch (len) { + // fast cases + case 1: + emitNone(handler, isFn, this); + break; + case 2: + emitOne(handler, isFn, this, arguments[1]); + break; + case 3: + emitTwo(handler, isFn, this, arguments[1], arguments[2]); + break; + case 4: + emitThree( + handler, + isFn, + this, + arguments[1], + arguments[2], + arguments[3], + ); + break; + // slower + default: + args = new Array(len - 1); + for (i = 1; i < len; i++) args[i - 1] = arguments[i]; + emitMany(handler, isFn, this, args); + } + + return true; + }; + + function _addListener(target, type, listener, prepend) { + var m; + var events; + var existing; + + if (typeof listener !== "function") + throw new TypeError('"listener" argument must be a function'); + + events = target._events; + if (!events) { + events = target._events = objectCreate(null); + target._eventsCount = 0; + } else { + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (events.newListener) { + target.emit( + "newListener", + type, + listener.listener ? listener.listener : listener, + ); + + // Re-assign `events` because a newListener handler could have caused the + // this._events to be assigned to a new object + events = target._events; + } + existing = events[type]; + } + + if (!existing) { + // Optimize the case of one listener. Don't need the extra array object. + existing = events[type] = listener; + ++target._eventsCount; + } else { + if (typeof existing === "function") { + // Adding the second element, need to change to array. + existing = events[type] = prepend + ? [listener, existing] + : [existing, listener]; + } else { + // If we've already got an array, just append. + if (prepend) { + existing.unshift(listener); + } else { + existing.push(listener); + } + } + + // Check for listener leak + if (!existing.warned) { + m = $getMaxListeners(target); + if (m && m > 0 && existing.length > m) { + existing.warned = true; + var w = new Error( + "Possible EventEmitter memory leak detected. " + + existing.length + + ' "' + + String(type) + + '" listeners ' + + "added. Use emitter.setMaxListeners() to " + + "increase limit.", + ); + w.name = "MaxListenersExceededWarning"; + w.emitter = target; + w.type = type; + w.count = existing.length; + if (typeof console === "object" && console.warn) { + console.warn("%s: %s", w.name, w.message); + } + } + } + } + + return target; + } + + EventEmitter.prototype.addListener = function addListener( + type, + listener, + ) { + return _addListener(this, type, listener, false); + }; + + EventEmitter.prototype.on = EventEmitter.prototype.addListener; + + EventEmitter.prototype.prependListener = function prependListener( + type, + listener, + ) { + return _addListener(this, type, listener, true); + }; + + function onceWrapper() { + if (!this.fired) { + this.target.removeListener(this.type, this.wrapFn); + this.fired = true; + switch (arguments.length) { + case 0: + return this.listener.call(this.target); + case 1: + return this.listener.call(this.target, arguments[0]); + case 2: + return this.listener.call( + this.target, + arguments[0], + arguments[1], + ); + case 3: + return this.listener.call( + this.target, + arguments[0], + arguments[1], + arguments[2], + ); + default: + var args = new Array(arguments.length); + for (var i = 0; i < args.length; ++i) args[i] = arguments[i]; + this.listener.apply(this.target, args); + } + } + } + + function _onceWrap(target, type, listener) { + var state = { + fired: false, + wrapFn: undefined, + target: target, + type: type, + listener: listener, + }; + var wrapped = bind.call(onceWrapper, state); + wrapped.listener = listener; + state.wrapFn = wrapped; + return wrapped; + } + + EventEmitter.prototype.once = function once(type, listener) { + if (typeof listener !== "function") + throw new TypeError('"listener" argument must be a function'); + this.on(type, _onceWrap(this, type, listener)); + return this; + }; + + EventEmitter.prototype.prependOnceListener = function prependOnceListener( + type, + listener, + ) { + if (typeof listener !== "function") + throw new TypeError('"listener" argument must be a function'); + this.prependListener(type, _onceWrap(this, type, listener)); + return this; + }; + + // Emits a 'removeListener' event if and only if the listener was removed. + EventEmitter.prototype.removeListener = function removeListener( + type, + listener, + ) { + var list, events, position, i, originalListener; + + if (typeof listener !== "function") + throw new TypeError('"listener" argument must be a function'); + + events = this._events; + if (!events) return this; + + list = events[type]; + if (!list) return this; + + if (list === listener || list.listener === listener) { + if (--this._eventsCount === 0) this._events = objectCreate(null); + else { + delete events[type]; + if (events.removeListener) + this.emit("removeListener", type, list.listener || listener); + } + } else if (typeof list !== "function") { + position = -1; + + for (i = list.length - 1; i >= 0; i--) { + if (list[i] === listener || list[i].listener === listener) { + originalListener = list[i].listener; + position = i; + break; + } + } + + if (position < 0) return this; + + if (position === 0) list.shift(); + else spliceOne(list, position); + + if (list.length === 1) events[type] = list[0]; + + if (events.removeListener) + this.emit("removeListener", type, originalListener || listener); + } + + return this; + }; + + EventEmitter.prototype.removeAllListeners = function removeAllListeners( + type, + ) { + var listeners, events, i; + + events = this._events; + if (!events) return this; + + // not listening for removeListener, no need to emit + if (!events.removeListener) { + if (arguments.length === 0) { + this._events = objectCreate(null); + this._eventsCount = 0; + } else if (events[type]) { + if (--this._eventsCount === 0) + this._events = objectCreate(null); + else delete events[type]; + } + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + var keys = objectKeys(events); + var key; + for (i = 0; i < keys.length; ++i) { + key = keys[i]; + if (key === "removeListener") continue; + this.removeAllListeners(key); + } + this.removeAllListeners("removeListener"); + this._events = objectCreate(null); + this._eventsCount = 0; + return this; + } + + listeners = events[type]; + + if (typeof listeners === "function") { + this.removeListener(type, listeners); + } else if (listeners) { + // LIFO order + for (i = listeners.length - 1; i >= 0; i--) { + this.removeListener(type, listeners[i]); + } + } + + return this; + }; + + function _listeners(target, type, unwrap) { + var events = target._events; + + if (!events) return []; + + var evlistener = events[type]; + if (!evlistener) return []; + + if (typeof evlistener === "function") + return unwrap + ? [evlistener.listener || evlistener] + : [evlistener]; + + return unwrap + ? unwrapListeners(evlistener) + : arrayClone(evlistener, evlistener.length); + } + + EventEmitter.prototype.listeners = function listeners(type) { + return _listeners(this, type, true); + }; + + EventEmitter.prototype.rawListeners = function rawListeners(type) { + return _listeners(this, type, false); + }; + + EventEmitter.listenerCount = function(emitter, type) { + if (typeof emitter.listenerCount === "function") { + return emitter.listenerCount(type); + } else { + return listenerCount.call(emitter, type); + } + }; + + EventEmitter.prototype.listenerCount = listenerCount; + function listenerCount(type) { + var events = this._events; + + if (events) { + var evlistener = events[type]; + + if (typeof evlistener === "function") { + return 1; + } else if (evlistener) { + return evlistener.length; + } + } + + return 0; + } + + EventEmitter.prototype.eventNames = function eventNames() { + return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : []; + }; + + // About 1.5x faster than the two-arg version of Array#splice(). + function spliceOne(list, index) { + for ( + var i = index, k = i + 1, n = list.length; + k < n; + i += 1, k += 1 + ) + list[i] = list[k]; + list.pop(); + } + + function arrayClone(arr, n) { + var copy = new Array(n); + for (var i = 0; i < n; ++i) copy[i] = arr[i]; + return copy; + } + + function unwrapListeners(arr) { + var ret = new Array(arr.length); + for (var i = 0; i < ret.length; ++i) { + ret[i] = arr[i].listener || arr[i]; + } + return ret; + } + + function objectCreatePolyfill(proto) { + var F = function() {}; + F.prototype = proto; + return new F(); + } + function objectKeysPolyfill(obj) { + var keys = []; + for (var k in obj) + if (Object.prototype.hasOwnProperty.call(obj, k)) { + keys.push(k); + } + return k; + } + function functionBindPolyfill(context) { + var fn = this; + return function() { + return fn.apply(context, arguments); + }; + } + }, + {}, + ], + 3: [ + function(require, module, exports) { + "use strict"; + var __extends = + (this && this.__extends) || + (function() { + var extendStatics = function(d, b) { + extendStatics = + Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && + function(d, b) { + d.__proto__ = b; + }) || + function(d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + }; + return extendStatics(d, b); + }; + return function(d, b) { + extendStatics(d, b); + function __() { + this.constructor = d; + } + d.prototype = + b === null + ? Object.create(b) + : ((__.prototype = b.prototype), new __()); + }; + })(); + var __spreadArrays = + (this && this.__spreadArrays) || + function() { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) + s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for ( + var a = arguments[i], j = 0, jl = a.length; + j < jl; + j++, k++ + ) + r[k] = a[j]; + return r; + }; + var __importDefault = + (this && this.__importDefault) || + function(mod) { + return mod && mod.__esModule ? mod : { default: mod }; + }; + Object.defineProperty(exports, "__esModule", { value: true }); + var MultiplexHandler_1 = __importDefault( + require("./MultiplexHandler"), + ); + var CollectingHandler = /** @class */ (function(_super) { + __extends(CollectingHandler, _super); + function CollectingHandler(cbs) { + if (cbs === void 0) { + cbs = {}; + } + var _this = + _super.call(this, function(name) { + var _a; + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + _this.events.push(__spreadArrays([name], args)); + // @ts-ignore + if (_this._cbs[name]) (_a = _this._cbs)[name].apply(_a, args); + }) || this; + _this._cbs = cbs; + _this.events = []; + return _this; + } + CollectingHandler.prototype.onreset = function() { + this.events = []; + if (this._cbs.onreset) this._cbs.onreset(); + }; + CollectingHandler.prototype.restart = function() { + var _a; + if (this._cbs.onreset) this._cbs.onreset(); + for (var i = 0; i < this.events.length; i++) { + var _b = this.events[i], + name_1 = _b[0], + args = _b.slice(1); + if (!this._cbs[name_1]) { + continue; + } + // @ts-ignore + (_a = this._cbs)[name_1].apply(_a, args); + } + }; + return CollectingHandler; + })(MultiplexHandler_1.default); + exports.CollectingHandler = CollectingHandler; + }, + { "./MultiplexHandler": 5 }, + ], + 4: [ + function(require, module, exports) { + "use strict"; + var __extends = + (this && this.__extends) || + (function() { + var extendStatics = function(d, b) { + extendStatics = + Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && + function(d, b) { + d.__proto__ = b; + }) || + function(d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + }; + return extendStatics(d, b); + }; + return function(d, b) { + extendStatics(d, b); + function __() { + this.constructor = d; + } + d.prototype = + b === null + ? Object.create(b) + : ((__.prototype = b.prototype), new __()); + }; + })(); + var __importDefault = + (this && this.__importDefault) || + function(mod) { + return mod && mod.__esModule ? mod : { default: mod }; + }; + var __importStar = + (this && this.__importStar) || + function(mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; + }; + Object.defineProperty(exports, "__esModule", { value: true }); + var domhandler_1 = __importDefault(require("domhandler")); + var DomUtils = __importStar(require("domutils")); + var Parser_1 = require("./Parser"); + //TODO: Consume data as it is coming in + var FeedHandler = /** @class */ (function(_super) { + __extends(FeedHandler, _super); + /** + * + * @param callback + * @param options + */ + function FeedHandler(callback, options) { + var _this = this; + if (typeof callback === "object" && callback !== null) { + callback = undefined; + options = callback; + } + _this = _super.call(this, callback, options) || this; + return _this; + } + FeedHandler.prototype.onend = function() { + var feed = {}; + var feedRoot = getOneElement(isValidFeed, this.dom); + if (feedRoot) { + if (feedRoot.name === "feed") { + var childs = feedRoot.children; + feed.type = "atom"; + addConditionally(feed, "id", "id", childs); + addConditionally(feed, "title", "title", childs); + var href = getAttribute( + "href", + getOneElement("link", childs), + ); + if (href) { + feed.link = href; + } + addConditionally(feed, "description", "subtitle", childs); + var updated = fetch("updated", childs); + if (updated) { + feed.updated = new Date(updated); + } + addConditionally(feed, "author", "email", childs, true); + feed.items = getElements("entry", childs).map(function(item) { + var entry = {}; + var children = item.children; + addConditionally(entry, "id", "id", children); + addConditionally(entry, "title", "title", children); + var href = getAttribute( + "href", + getOneElement("link", children), + ); + if (href) { + entry.link = href; + } + var description = + fetch("summary", children) || fetch("content", children); + if (description) { + entry.description = description; + } + var pubDate = fetch("updated", children); + if (pubDate) { + entry.pubDate = new Date(pubDate); + } + return entry; + }); + } else { + var childs = getOneElement("channel", feedRoot.children) + .children; + feed.type = feedRoot.name.substr(0, 3); + feed.id = ""; + addConditionally(feed, "title", "title", childs); + addConditionally(feed, "link", "link", childs); + addConditionally(feed, "description", "description", childs); + var updated = fetch("lastBuildDate", childs); + if (updated) { + feed.updated = new Date(updated); + } + addConditionally( + feed, + "author", + "managingEditor", + childs, + true, + ); + feed.items = getElements("item", feedRoot.children).map( + function(item) { + var entry = {}; + var children = item.children; + addConditionally(entry, "id", "guid", children); + addConditionally(entry, "title", "title", children); + addConditionally(entry, "link", "link", children); + addConditionally( + entry, + "description", + "description", + children, + ); + var pubDate = fetch("pubDate", children); + if (pubDate) entry.pubDate = new Date(pubDate); + return entry; + }, + ); + } + } + this.feed = feed; + this.handleCallback( + feedRoot ? null : Error("couldn't find root of feed"), + ); + }; + return FeedHandler; + })(domhandler_1.default); + exports.FeedHandler = FeedHandler; + function getElements(what, where) { + return DomUtils.getElementsByTagName(what, where, true); + } + function getOneElement(what, where) { + return DomUtils.getElementsByTagName(what, where, true, 1)[0]; + } + function fetch(what, where, recurse) { + if (recurse === void 0) { + recurse = false; + } + return DomUtils.getText( + DomUtils.getElementsByTagName(what, where, recurse, 1), + ).trim(); + } + function getAttribute(name, elem) { + if (!elem) { + return null; + } + var attribs = elem.attribs; + return attribs[name]; + } + function addConditionally(obj, prop, what, where, recurse) { + if (recurse === void 0) { + recurse = false; + } + var tmp = fetch(what, where, recurse); + // @ts-ignore + if (tmp) obj[prop] = tmp; + } + function isValidFeed(value) { + return value === "rss" || value === "feed" || value === "rdf:RDF"; + } + var defaultOptions = { xmlMode: true }; + /** + * Parse a feed. + * + * @param feed The feed that should be parsed, as a string. + * @param options Optionally, options for parsing. When using this option, you probably want to set `xmlMode` to `true`. + */ + function parseFeed(feed, options) { + if (options === void 0) { + options = defaultOptions; + } + var handler = new FeedHandler(options); + new Parser_1.Parser(handler, options).end(feed); + return handler.feed; + } + exports.parseFeed = parseFeed; + }, + { "./Parser": 6, "domhandler": 12, "domutils": 15 }, + ], + 5: [ + function(require, module, exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + /** + * Calls a specific handler function for all events that are encountered. + * + * @param func — The function to multiplex all events to. + */ + var MultiplexHandler = /** @class */ (function() { + function MultiplexHandler(func) { + this._func = func; + } + /* Format: eventname: number of arguments */ + MultiplexHandler.prototype.onattribute = function(name, value) { + this._func("onattribute", name, value); + }; + MultiplexHandler.prototype.oncdatastart = function() { + this._func("oncdatastart"); + }; + MultiplexHandler.prototype.oncdataend = function() { + this._func("oncdataend"); + }; + MultiplexHandler.prototype.ontext = function(text) { + this._func("ontext", text); + }; + MultiplexHandler.prototype.onprocessinginstruction = function( + name, + value, + ) { + this._func("onprocessinginstruction", name, value); + }; + MultiplexHandler.prototype.oncomment = function(comment) { + this._func("oncomment", comment); + }; + MultiplexHandler.prototype.oncommentend = function() { + this._func("oncommentend"); + }; + MultiplexHandler.prototype.onclosetag = function(name) { + this._func("onclosetag", name); + }; + MultiplexHandler.prototype.onopentag = function(name, attribs) { + this._func("onopentag", name, attribs); + }; + MultiplexHandler.prototype.onopentagname = function(name) { + this._func("onopentagname", name); + }; + MultiplexHandler.prototype.onerror = function(error) { + this._func("onerror", error); + }; + MultiplexHandler.prototype.onend = function() { + this._func("onend"); + }; + MultiplexHandler.prototype.onparserinit = function(parser) { + this._func("onparserinit", parser); + }; + MultiplexHandler.prototype.onreset = function() { + this._func("onreset"); + }; + return MultiplexHandler; + })(); + exports.default = MultiplexHandler; + }, + {}, + ], + 6: [ + function(require, module, exports) { + "use strict"; + var __extends = + (this && this.__extends) || + (function() { + var extendStatics = function(d, b) { + extendStatics = + Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && + function(d, b) { + d.__proto__ = b; + }) || + function(d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + }; + return extendStatics(d, b); + }; + return function(d, b) { + extendStatics(d, b); + function __() { + this.constructor = d; + } + d.prototype = + b === null + ? Object.create(b) + : ((__.prototype = b.prototype), new __()); + }; + })(); + var __importDefault = + (this && this.__importDefault) || + function(mod) { + return mod && mod.__esModule ? mod : { default: mod }; + }; + Object.defineProperty(exports, "__esModule", { value: true }); + var Tokenizer_1 = __importDefault(require("./Tokenizer")); + var events_1 = require("events"); + var formTags = new Set([ + "input", + "option", + "optgroup", + "select", + "button", + "datalist", + "textarea", + ]); + var pTag = new Set(["p"]); + var openImpliesClose = { + tr: new Set(["tr", "th", "td"]), + th: new Set(["th"]), + td: new Set(["thead", "th", "td"]), + body: new Set(["head", "link", "script"]), + li: new Set(["li"]), + p: pTag, + h1: pTag, + h2: pTag, + h3: pTag, + h4: pTag, + h5: pTag, + h6: pTag, + select: formTags, + input: formTags, + output: formTags, + button: formTags, + datalist: formTags, + textarea: formTags, + option: new Set(["option"]), + optgroup: new Set(["optgroup", "option"]), + dd: new Set(["dt", "dd"]), + dt: new Set(["dt", "dd"]), + address: pTag, + article: pTag, + aside: pTag, + blockquote: pTag, + details: pTag, + div: pTag, + dl: pTag, + fieldset: pTag, + figcaption: pTag, + figure: pTag, + footer: pTag, + form: pTag, + header: pTag, + hr: pTag, + main: pTag, + nav: pTag, + ol: pTag, + pre: pTag, + section: pTag, + table: pTag, + ul: pTag, + rt: new Set(["rt", "rp"]), + rp: new Set(["rt", "rp"]), + tbody: new Set(["thead", "tbody"]), + tfoot: new Set(["thead", "tbody"]), + }; + var voidElements = new Set([ + "area", + "base", + "basefont", + "br", + "col", + "command", + "embed", + "frame", + "hr", + "img", + "input", + "isindex", + "keygen", + "link", + "meta", + "param", + "source", + "track", + "wbr", + ]); + var foreignContextElements = new Set(["math", "svg"]); + var htmlIntegrationElements = new Set([ + "mi", + "mo", + "mn", + "ms", + "mtext", + "annotation-xml", + "foreignObject", + "desc", + "title", + ]); + var reNameEnd = /\s|\//; + var Parser = /** @class */ (function(_super) { + __extends(Parser, _super); + function Parser(cbs, options) { + var _this = _super.call(this) || this; + _this._tagname = ""; + _this._attribname = ""; + _this._attribvalue = ""; + _this._attribs = null; + _this._stack = []; + _this._foreignContext = []; + _this.startIndex = 0; + _this.endIndex = null; + // Aliases for backwards compatibility + _this.parseChunk = Parser.prototype.write; + _this.done = Parser.prototype.end; + _this._options = options || {}; + _this._cbs = cbs || {}; + _this._tagname = ""; + _this._attribname = ""; + _this._attribvalue = ""; + _this._attribs = null; + _this._stack = []; + _this._foreignContext = []; + _this.startIndex = 0; + _this.endIndex = null; + _this._lowerCaseTagNames = + "lowerCaseTags" in _this._options + ? !!_this._options.lowerCaseTags + : !_this._options.xmlMode; + _this._lowerCaseAttributeNames = + "lowerCaseAttributeNames" in _this._options + ? !!_this._options.lowerCaseAttributeNames + : !_this._options.xmlMode; + _this._tokenizer = new (_this._options.Tokenizer || + Tokenizer_1.default)(_this._options, _this); + if (_this._cbs.onparserinit) _this._cbs.onparserinit(_this); + return _this; + } + Parser.prototype._updatePosition = function(initialOffset) { + if (this.endIndex === null) { + if (this._tokenizer._sectionStart <= initialOffset) { + this.startIndex = 0; + } else { + this.startIndex = + this._tokenizer._sectionStart - initialOffset; + } + } else this.startIndex = this.endIndex + 1; + this.endIndex = this._tokenizer.getAbsoluteIndex(); + }; + //Tokenizer event handlers + Parser.prototype.ontext = function(data) { + this._updatePosition(1); + // @ts-ignore + this.endIndex--; + if (this._cbs.ontext) this._cbs.ontext(data); + }; + Parser.prototype.onopentagname = function(name) { + if (this._lowerCaseTagNames) { + name = name.toLowerCase(); + } + this._tagname = name; + if (!this._options.xmlMode && name in openImpliesClose) { + for ( + var el = void 0; + // @ts-ignore + openImpliesClose[name].has( + (el = this._stack[this._stack.length - 1]), + ); + this.onclosetag(el) + ); + } + if (this._options.xmlMode || !voidElements.has(name)) { + this._stack.push(name); + if (foreignContextElements.has(name)) { + this._foreignContext.push(true); + } else if (htmlIntegrationElements.has(name)) { + this._foreignContext.push(false); + } + } + if (this._cbs.onopentagname) this._cbs.onopentagname(name); + if (this._cbs.onopentag) this._attribs = {}; + }; + Parser.prototype.onopentagend = function() { + this._updatePosition(1); + if (this._attribs) { + if (this._cbs.onopentag) { + this._cbs.onopentag(this._tagname, this._attribs); + } + this._attribs = null; + } + if ( + !this._options.xmlMode && + this._cbs.onclosetag && + voidElements.has(this._tagname) + ) { + this._cbs.onclosetag(this._tagname); + } + this._tagname = ""; + }; + Parser.prototype.onclosetag = function(name) { + this._updatePosition(1); + if (this._lowerCaseTagNames) { + name = name.toLowerCase(); + } + if ( + foreignContextElements.has(name) || + htmlIntegrationElements.has(name) + ) { + this._foreignContext.pop(); + } + if ( + this._stack.length && + (this._options.xmlMode || !voidElements.has(name)) + ) { + var pos = this._stack.lastIndexOf(name); + if (pos !== -1) { + if (this._cbs.onclosetag) { + pos = this._stack.length - pos; + // @ts-ignore + while (pos--) this._cbs.onclosetag(this._stack.pop()); + } else this._stack.length = pos; + } else if (name === "p" && !this._options.xmlMode) { + this.onopentagname(name); + this._closeCurrentTag(); + } + } else if ( + !this._options.xmlMode && + (name === "br" || name === "p") + ) { + this.onopentagname(name); + this._closeCurrentTag(); + } + }; + Parser.prototype.onselfclosingtag = function() { + if ( + this._options.xmlMode || + this._options.recognizeSelfClosing || + this._foreignContext[this._foreignContext.length - 1] + ) { + this._closeCurrentTag(); + } else { + this.onopentagend(); + } + }; + Parser.prototype._closeCurrentTag = function() { + var name = this._tagname; + this.onopentagend(); + //self-closing tags will be on the top of the stack + //(cheaper check than in onclosetag) + if (this._stack[this._stack.length - 1] === name) { + if (this._cbs.onclosetag) { + this._cbs.onclosetag(name); + } + this._stack.pop(); + } + }; + Parser.prototype.onattribname = function(name) { + if (this._lowerCaseAttributeNames) { + name = name.toLowerCase(); + } + this._attribname = name; + }; + Parser.prototype.onattribdata = function(value) { + this._attribvalue += value; + }; + Parser.prototype.onattribend = function() { + if (this._cbs.onattribute) + this._cbs.onattribute(this._attribname, this._attribvalue); + if ( + this._attribs && + !Object.prototype.hasOwnProperty.call( + this._attribs, + this._attribname, + ) + ) { + this._attribs[this._attribname] = this._attribvalue; + } + this._attribname = ""; + this._attribvalue = ""; + }; + Parser.prototype._getInstructionName = function(value) { + var idx = value.search(reNameEnd); + var name = idx < 0 ? value : value.substr(0, idx); + if (this._lowerCaseTagNames) { + name = name.toLowerCase(); + } + return name; + }; + Parser.prototype.ondeclaration = function(value) { + if (this._cbs.onprocessinginstruction) { + var name_1 = this._getInstructionName(value); + this._cbs.onprocessinginstruction("!" + name_1, "!" + value); + } + }; + Parser.prototype.onprocessinginstruction = function(value) { + if (this._cbs.onprocessinginstruction) { + var name_2 = this._getInstructionName(value); + this._cbs.onprocessinginstruction("?" + name_2, "?" + value); + } + }; + Parser.prototype.oncomment = function(value) { + this._updatePosition(4); + if (this._cbs.oncomment) this._cbs.oncomment(value); + if (this._cbs.oncommentend) this._cbs.oncommentend(); + }; + Parser.prototype.oncdata = function(value) { + this._updatePosition(1); + if (this._options.xmlMode || this._options.recognizeCDATA) { + if (this._cbs.oncdatastart) this._cbs.oncdatastart(); + if (this._cbs.ontext) this._cbs.ontext(value); + if (this._cbs.oncdataend) this._cbs.oncdataend(); + } else { + this.oncomment("[CDATA[" + value + "]]"); + } + }; + Parser.prototype.onerror = function(err) { + if (this._cbs.onerror) this._cbs.onerror(err); + }; + Parser.prototype.onend = function() { + if (this._cbs.onclosetag) { + for ( + var i = this._stack.length; + i > 0; + this._cbs.onclosetag(this._stack[--i]) + ); + } + if (this._cbs.onend) this._cbs.onend(); + }; + //Resets the parser to a blank state, ready to parse a new HTML document + Parser.prototype.reset = function() { + if (this._cbs.onreset) this._cbs.onreset(); + this._tokenizer.reset(); + this._tagname = ""; + this._attribname = ""; + this._attribs = null; + this._stack = []; + if (this._cbs.onparserinit) this._cbs.onparserinit(this); + }; + //Parses a complete HTML document and pushes it to the handler + Parser.prototype.parseComplete = function(data) { + this.reset(); + this.end(data); + }; + Parser.prototype.write = function(chunk) { + this._tokenizer.write(chunk); + }; + Parser.prototype.end = function(chunk) { + this._tokenizer.end(chunk); + }; + Parser.prototype.pause = function() { + this._tokenizer.pause(); + }; + Parser.prototype.resume = function() { + this._tokenizer.resume(); + }; + return Parser; + })(events_1.EventEmitter); + exports.Parser = Parser; + }, + { "./Tokenizer": 7, "events": 2 }, + ], + 7: [ + function(require, module, exports) { + "use strict"; + var __importDefault = + (this && this.__importDefault) || + function(mod) { + return mod && mod.__esModule ? mod : { default: mod }; + }; + Object.defineProperty(exports, "__esModule", { value: true }); + var decode_codepoint_1 = __importDefault( + require("entities/lib/decode_codepoint"), + ); + var entities_json_1 = __importDefault( + require("entities/lib/maps/entities.json"), + ); + var legacy_json_1 = __importDefault( + require("entities/lib/maps/legacy.json"), + ); + var xml_json_1 = __importDefault( + require("entities/lib/maps/xml.json"), + ); + function whitespace(c) { + return ( + c === " " || c === "\n" || c === "\t" || c === "\f" || c === "\r" + ); + } + function ifElseState(upper, SUCCESS, FAILURE) { + var lower = upper.toLowerCase(); + if (upper === lower) { + return function(t, c) { + if (c === lower) { + t._state = SUCCESS; + } else { + t._state = FAILURE; + t._index--; + } + }; + } else { + return function(t, c) { + if (c === lower || c === upper) { + t._state = SUCCESS; + } else { + t._state = FAILURE; + t._index--; + } + }; + } + } + function consumeSpecialNameChar(upper, NEXT_STATE) { + var lower = upper.toLowerCase(); + return function(t, c) { + if (c === lower || c === upper) { + t._state = NEXT_STATE; + } else { + t._state = 3 /* InTagName */; + t._index--; //consume the token again + } + }; + } + var stateBeforeCdata1 = ifElseState( + "C", + 23 /* BeforeCdata2 */, + 16 /* InDeclaration */, + ); + var stateBeforeCdata2 = ifElseState( + "D", + 24 /* BeforeCdata3 */, + 16 /* InDeclaration */, + ); + var stateBeforeCdata3 = ifElseState( + "A", + 25 /* BeforeCdata4 */, + 16 /* InDeclaration */, + ); + var stateBeforeCdata4 = ifElseState( + "T", + 26 /* BeforeCdata5 */, + 16 /* InDeclaration */, + ); + var stateBeforeCdata5 = ifElseState( + "A", + 27 /* BeforeCdata6 */, + 16 /* InDeclaration */, + ); + var stateBeforeScript1 = consumeSpecialNameChar( + "R", + 34 /* BeforeScript2 */, + ); + var stateBeforeScript2 = consumeSpecialNameChar( + "I", + 35 /* BeforeScript3 */, + ); + var stateBeforeScript3 = consumeSpecialNameChar( + "P", + 36 /* BeforeScript4 */, + ); + var stateBeforeScript4 = consumeSpecialNameChar( + "T", + 37 /* BeforeScript5 */, + ); + var stateAfterScript1 = ifElseState( + "R", + 39 /* AfterScript2 */, + 1 /* Text */, + ); + var stateAfterScript2 = ifElseState( + "I", + 40 /* AfterScript3 */, + 1 /* Text */, + ); + var stateAfterScript3 = ifElseState( + "P", + 41 /* AfterScript4 */, + 1 /* Text */, + ); + var stateAfterScript4 = ifElseState( + "T", + 42 /* AfterScript5 */, + 1 /* Text */, + ); + var stateBeforeStyle1 = consumeSpecialNameChar( + "Y", + 44 /* BeforeStyle2 */, + ); + var stateBeforeStyle2 = consumeSpecialNameChar( + "L", + 45 /* BeforeStyle3 */, + ); + var stateBeforeStyle3 = consumeSpecialNameChar( + "E", + 46 /* BeforeStyle4 */, + ); + var stateAfterStyle1 = ifElseState( + "Y", + 48 /* AfterStyle2 */, + 1 /* Text */, + ); + var stateAfterStyle2 = ifElseState( + "L", + 49 /* AfterStyle3 */, + 1 /* Text */, + ); + var stateAfterStyle3 = ifElseState( + "E", + 50 /* AfterStyle4 */, + 1 /* Text */, + ); + var stateBeforeEntity = ifElseState( + "#", + 52 /* BeforeNumericEntity */, + 53 /* InNamedEntity */, + ); + var stateBeforeNumericEntity = ifElseState( + "X", + 55 /* InHexEntity */, + 54 /* InNumericEntity */, + ); + var Tokenizer = /** @class */ (function() { + function Tokenizer(options, cbs) { + /** The current state the tokenizer is in. */ + this._state = 1 /* Text */; + /** The read buffer. */ + this._buffer = ""; + /** The beginning of the section that is currently being read. */ + this._sectionStart = 0; + /** The index within the buffer that we are currently looking at. */ + this._index = 0; + /** + * Data that has already been processed will be removed from the buffer occasionally. + * `_bufferOffset` keeps track of how many characters have been removed, to make sure position information is accurate. + */ + this._bufferOffset = 0; + /** Some behavior, eg. when decoding entities, is done while we are in another state. This keeps track of the other state type. */ + this._baseState = 1 /* Text */; + /** For special parsing behavior inside of script and style tags. */ + this._special = 1 /* None */; + /** Indicates whether the tokenizer has been paused. */ + this._running = true; + /** Indicates whether the tokenizer has finished running / `.end` has been called. */ + this._ended = false; + this._cbs = cbs; + this._xmlMode = !!(options && options.xmlMode); + this._decodeEntities = !!(options && options.decodeEntities); + } + Tokenizer.prototype.reset = function() { + this._state = 1 /* Text */; + this._buffer = ""; + this._sectionStart = 0; + this._index = 0; + this._bufferOffset = 0; + this._baseState = 1 /* Text */; + this._special = 1 /* None */; + this._running = true; + this._ended = false; + }; + Tokenizer.prototype._stateText = function(c) { + if (c === "<") { + if (this._index > this._sectionStart) { + this._cbs.ontext(this._getSection()); + } + this._state = 2 /* BeforeTagName */; + this._sectionStart = this._index; + } else if ( + this._decodeEntities && + this._special === 1 /* None */ && + c === "&" + ) { + if (this._index > this._sectionStart) { + this._cbs.ontext(this._getSection()); + } + this._baseState = 1 /* Text */; + this._state = 51 /* BeforeEntity */; + this._sectionStart = this._index; + } + }; + Tokenizer.prototype._stateBeforeTagName = function(c) { + if (c === "/") { + this._state = 5 /* BeforeClosingTagName */; + } else if (c === "<") { + this._cbs.ontext(this._getSection()); + this._sectionStart = this._index; + } else if ( + c === ">" || + this._special !== 1 /* None */ || + whitespace(c) + ) { + this._state = 1 /* Text */; + } else if (c === "!") { + this._state = 15 /* BeforeDeclaration */; + this._sectionStart = this._index + 1; + } else if (c === "?") { + this._state = 17 /* InProcessingInstruction */; + this._sectionStart = this._index + 1; + } else { + this._state = + !this._xmlMode && (c === "s" || c === "S") + ? 31 /* BeforeSpecial */ + : 3 /* InTagName */; + this._sectionStart = this._index; + } + }; + Tokenizer.prototype._stateInTagName = function(c) { + if (c === "/" || c === ">" || whitespace(c)) { + this._emitToken("onopentagname"); + this._state = 8 /* BeforeAttributeName */; + this._index--; + } + }; + Tokenizer.prototype._stateBeforeCloseingTagName = function(c) { + if (whitespace(c)) { + // ignore + } else if (c === ">") { + this._state = 1 /* Text */; + } else if (this._special !== 1 /* None */) { + if (c === "s" || c === "S") { + this._state = 32 /* BeforeSpecialEnd */; + } else { + this._state = 1 /* Text */; + this._index--; + } + } else { + this._state = 6 /* InClosingTagName */; + this._sectionStart = this._index; + } + }; + Tokenizer.prototype._stateInCloseingTagName = function(c) { + if (c === ">" || whitespace(c)) { + this._emitToken("onclosetag"); + this._state = 7 /* AfterClosingTagName */; + this._index--; + } + }; + Tokenizer.prototype._stateAfterCloseingTagName = function(c) { + //skip everything until ">" + if (c === ">") { + this._state = 1 /* Text */; + this._sectionStart = this._index + 1; + } + }; + Tokenizer.prototype._stateBeforeAttributeName = function(c) { + if (c === ">") { + this._cbs.onopentagend(); + this._state = 1 /* Text */; + this._sectionStart = this._index + 1; + } else if (c === "/") { + this._state = 4 /* InSelfClosingTag */; + } else if (!whitespace(c)) { + this._state = 9 /* InAttributeName */; + this._sectionStart = this._index; + } + }; + Tokenizer.prototype._stateInSelfClosingTag = function(c) { + if (c === ">") { + this._cbs.onselfclosingtag(); + this._state = 1 /* Text */; + this._sectionStart = this._index + 1; + } else if (!whitespace(c)) { + this._state = 8 /* BeforeAttributeName */; + this._index--; + } + }; + Tokenizer.prototype._stateInAttributeName = function(c) { + if (c === "=" || c === "/" || c === ">" || whitespace(c)) { + this._cbs.onattribname(this._getSection()); + this._sectionStart = -1; + this._state = 10 /* AfterAttributeName */; + this._index--; + } + }; + Tokenizer.prototype._stateAfterAttributeName = function(c) { + if (c === "=") { + this._state = 11 /* BeforeAttributeValue */; + } else if (c === "/" || c === ">") { + this._cbs.onattribend(); + this._state = 8 /* BeforeAttributeName */; + this._index--; + } else if (!whitespace(c)) { + this._cbs.onattribend(); + this._state = 9 /* InAttributeName */; + this._sectionStart = this._index; + } + }; + Tokenizer.prototype._stateBeforeAttributeValue = function(c) { + if (c === '"') { + this._state = 12 /* InAttributeValueDq */; + this._sectionStart = this._index + 1; + } else if (c === "'") { + this._state = 13 /* InAttributeValueSq */; + this._sectionStart = this._index + 1; + } else if (!whitespace(c)) { + this._state = 14 /* InAttributeValueNq */; + this._sectionStart = this._index; + this._index--; //reconsume token + } + }; + Tokenizer.prototype._stateInAttributeValueDoubleQuotes = function( + c, + ) { + if (c === '"') { + this._emitToken("onattribdata"); + this._cbs.onattribend(); + this._state = 8 /* BeforeAttributeName */; + } else if (this._decodeEntities && c === "&") { + this._emitToken("onattribdata"); + this._baseState = this._state; + this._state = 51 /* BeforeEntity */; + this._sectionStart = this._index; + } + }; + Tokenizer.prototype._stateInAttributeValueSingleQuotes = function( + c, + ) { + if (c === "'") { + this._emitToken("onattribdata"); + this._cbs.onattribend(); + this._state = 8 /* BeforeAttributeName */; + } else if (this._decodeEntities && c === "&") { + this._emitToken("onattribdata"); + this._baseState = this._state; + this._state = 51 /* BeforeEntity */; + this._sectionStart = this._index; + } + }; + Tokenizer.prototype._stateInAttributeValueNoQuotes = function(c) { + if (whitespace(c) || c === ">") { + this._emitToken("onattribdata"); + this._cbs.onattribend(); + this._state = 8 /* BeforeAttributeName */; + this._index--; + } else if (this._decodeEntities && c === "&") { + this._emitToken("onattribdata"); + this._baseState = this._state; + this._state = 51 /* BeforeEntity */; + this._sectionStart = this._index; + } + }; + Tokenizer.prototype._stateBeforeDeclaration = function(c) { + this._state = + c === "[" + ? 22 /* BeforeCdata1 */ + : c === "-" + ? 18 /* BeforeComment */ + : 16 /* InDeclaration */; + }; + Tokenizer.prototype._stateInDeclaration = function(c) { + if (c === ">") { + this._cbs.ondeclaration(this._getSection()); + this._state = 1 /* Text */; + this._sectionStart = this._index + 1; + } + }; + Tokenizer.prototype._stateInProcessingInstruction = function(c) { + if (c === ">") { + this._cbs.onprocessinginstruction(this._getSection()); + this._state = 1 /* Text */; + this._sectionStart = this._index + 1; + } + }; + Tokenizer.prototype._stateBeforeComment = function(c) { + if (c === "-") { + this._state = 19 /* InComment */; + this._sectionStart = this._index + 1; + } else { + this._state = 16 /* InDeclaration */; + } + }; + Tokenizer.prototype._stateInComment = function(c) { + if (c === "-") this._state = 20 /* AfterComment1 */; + }; + Tokenizer.prototype._stateAfterComment1 = function(c) { + if (c === "-") { + this._state = 21 /* AfterComment2 */; + } else { + this._state = 19 /* InComment */; + } + }; + Tokenizer.prototype._stateAfterComment2 = function(c) { + if (c === ">") { + //remove 2 trailing chars + this._cbs.oncomment( + this._buffer.substring(this._sectionStart, this._index - 2), + ); + this._state = 1 /* Text */; + this._sectionStart = this._index + 1; + } else if (c !== "-") { + this._state = 19 /* InComment */; + } + // else: stay in AFTER_COMMENT_2 (`--->`) + }; + Tokenizer.prototype._stateBeforeCdata6 = function(c) { + if (c === "[") { + this._state = 28 /* InCdata */; + this._sectionStart = this._index + 1; + } else { + this._state = 16 /* InDeclaration */; + this._index--; + } + }; + Tokenizer.prototype._stateInCdata = function(c) { + if (c === "]") this._state = 29 /* AfterCdata1 */; + }; + Tokenizer.prototype._stateAfterCdata1 = function(c) { + if (c === "]") this._state = 30 /* AfterCdata2 */; + else this._state = 28 /* InCdata */; + }; + Tokenizer.prototype._stateAfterCdata2 = function(c) { + if (c === ">") { + //remove 2 trailing chars + this._cbs.oncdata( + this._buffer.substring(this._sectionStart, this._index - 2), + ); + this._state = 1 /* Text */; + this._sectionStart = this._index + 1; + } else if (c !== "]") { + this._state = 28 /* InCdata */; + } + //else: stay in AFTER_CDATA_2 (`]]]>`) + }; + Tokenizer.prototype._stateBeforeSpecial = function(c) { + if (c === "c" || c === "C") { + this._state = 33 /* BeforeScript1 */; + } else if (c === "t" || c === "T") { + this._state = 43 /* BeforeStyle1 */; + } else { + this._state = 3 /* InTagName */; + this._index--; //consume the token again + } + }; + Tokenizer.prototype._stateBeforeSpecialEnd = function(c) { + if ( + this._special === 2 /* Script */ && + (c === "c" || c === "C") + ) { + this._state = 38 /* AfterScript1 */; + } else if ( + this._special === 3 /* Style */ && + (c === "t" || c === "T") + ) { + this._state = 47 /* AfterStyle1 */; + } else this._state = 1 /* Text */; + }; + Tokenizer.prototype._stateBeforeScript5 = function(c) { + if (c === "/" || c === ">" || whitespace(c)) { + this._special = 2 /* Script */; + } + this._state = 3 /* InTagName */; + this._index--; //consume the token again + }; + Tokenizer.prototype._stateAfterScript5 = function(c) { + if (c === ">" || whitespace(c)) { + this._special = 1 /* None */; + this._state = 6 /* InClosingTagName */; + this._sectionStart = this._index - 6; + this._index--; //reconsume the token + } else this._state = 1 /* Text */; + }; + Tokenizer.prototype._stateBeforeStyle4 = function(c) { + if (c === "/" || c === ">" || whitespace(c)) { + this._special = 3 /* Style */; + } + this._state = 3 /* InTagName */; + this._index--; //consume the token again + }; + Tokenizer.prototype._stateAfterStyle4 = function(c) { + if (c === ">" || whitespace(c)) { + this._special = 1 /* None */; + this._state = 6 /* InClosingTagName */; + this._sectionStart = this._index - 5; + this._index--; //reconsume the token + } else this._state = 1 /* Text */; + }; + //for entities terminated with a semicolon + Tokenizer.prototype._parseNamedEntityStrict = function() { + //offset = 1 + if (this._sectionStart + 1 < this._index) { + var entity = this._buffer.substring( + this._sectionStart + 1, + this._index, + ), + map = this._xmlMode + ? xml_json_1.default + : entities_json_1.default; + if (Object.prototype.hasOwnProperty.call(map, entity)) { + // @ts-ignore + this._emitPartial(map[entity]); + this._sectionStart = this._index + 1; + } + } + }; + //parses legacy entities (without trailing semicolon) + Tokenizer.prototype._parseLegacyEntity = function() { + var start = this._sectionStart + 1; + var limit = this._index - start; + if (limit > 6) limit = 6; // The max length of legacy entities is 6 + while (limit >= 2) { + // The min length of legacy entities is 2 + var entity = this._buffer.substr(start, limit); + if ( + Object.prototype.hasOwnProperty.call( + legacy_json_1.default, + entity, + ) + ) { + // @ts-ignore + this._emitPartial(legacy_json_1.default[entity]); + this._sectionStart += limit + 1; + return; + } else { + limit--; + } + } + }; + Tokenizer.prototype._stateInNamedEntity = function(c) { + if (c === ";") { + this._parseNamedEntityStrict(); + if (this._sectionStart + 1 < this._index && !this._xmlMode) { + this._parseLegacyEntity(); + } + this._state = this._baseState; + } else if ( + (c < "a" || c > "z") && + (c < "A" || c > "Z") && + (c < "0" || c > "9") + ) { + if (this._xmlMode || this._sectionStart + 1 === this._index) { + // ignore + } else if (this._baseState !== 1 /* Text */) { + if (c !== "=") { + this._parseNamedEntityStrict(); + } + } else { + this._parseLegacyEntity(); + } + this._state = this._baseState; + this._index--; + } + }; + Tokenizer.prototype._decodeNumericEntity = function(offset, base) { + var sectionStart = this._sectionStart + offset; + if (sectionStart !== this._index) { + //parse entity + var entity = this._buffer.substring(sectionStart, this._index); + var parsed = parseInt(entity, base); + this._emitPartial(decode_codepoint_1.default(parsed)); + this._sectionStart = this._index; + } else { + this._sectionStart--; + } + this._state = this._baseState; + }; + Tokenizer.prototype._stateInNumericEntity = function(c) { + if (c === ";") { + this._decodeNumericEntity(2, 10); + this._sectionStart++; + } else if (c < "0" || c > "9") { + if (!this._xmlMode) { + this._decodeNumericEntity(2, 10); + } else { + this._state = this._baseState; + } + this._index--; + } + }; + Tokenizer.prototype._stateInHexEntity = function(c) { + if (c === ";") { + this._decodeNumericEntity(3, 16); + this._sectionStart++; + } else if ( + (c < "a" || c > "f") && + (c < "A" || c > "F") && + (c < "0" || c > "9") + ) { + if (!this._xmlMode) { + this._decodeNumericEntity(3, 16); + } else { + this._state = this._baseState; + } + this._index--; + } + }; + Tokenizer.prototype._cleanup = function() { + if (this._sectionStart < 0) { + this._buffer = ""; + this._bufferOffset += this._index; + this._index = 0; + } else if (this._running) { + if (this._state === 1 /* Text */) { + if (this._sectionStart !== this._index) { + this._cbs.ontext(this._buffer.substr(this._sectionStart)); + } + this._buffer = ""; + this._bufferOffset += this._index; + this._index = 0; + } else if (this._sectionStart === this._index) { + //the section just started + this._buffer = ""; + this._bufferOffset += this._index; + this._index = 0; + } else { + //remove everything unnecessary + this._buffer = this._buffer.substr(this._sectionStart); + this._index -= this._sectionStart; + this._bufferOffset += this._sectionStart; + } + this._sectionStart = 0; + } + }; + //TODO make events conditional + Tokenizer.prototype.write = function(chunk) { + if (this._ended) this._cbs.onerror(Error(".write() after done!")); + this._buffer += chunk; + this._parse(); + }; + // Iterates through the buffer, calling the function corresponding to the current state. + // States that are more likely to be hit are higher up, as a performance improvement. + Tokenizer.prototype._parse = function() { + while (this._index < this._buffer.length && this._running) { + var c = this._buffer.charAt(this._index); + if (this._state === 1 /* Text */) { + this._stateText(c); + } else if (this._state === 12 /* InAttributeValueDq */) { + this._stateInAttributeValueDoubleQuotes(c); + } else if (this._state === 9 /* InAttributeName */) { + this._stateInAttributeName(c); + } else if (this._state === 19 /* InComment */) { + this._stateInComment(c); + } else if (this._state === 8 /* BeforeAttributeName */) { + this._stateBeforeAttributeName(c); + } else if (this._state === 3 /* InTagName */) { + this._stateInTagName(c); + } else if (this._state === 6 /* InClosingTagName */) { + this._stateInCloseingTagName(c); + } else if (this._state === 2 /* BeforeTagName */) { + this._stateBeforeTagName(c); + } else if (this._state === 10 /* AfterAttributeName */) { + this._stateAfterAttributeName(c); + } else if (this._state === 13 /* InAttributeValueSq */) { + this._stateInAttributeValueSingleQuotes(c); + } else if (this._state === 11 /* BeforeAttributeValue */) { + this._stateBeforeAttributeValue(c); + } else if (this._state === 5 /* BeforeClosingTagName */) { + this._stateBeforeCloseingTagName(c); + } else if (this._state === 7 /* AfterClosingTagName */) { + this._stateAfterCloseingTagName(c); + } else if (this._state === 31 /* BeforeSpecial */) { + this._stateBeforeSpecial(c); + } else if (this._state === 20 /* AfterComment1 */) { + this._stateAfterComment1(c); + } else if (this._state === 14 /* InAttributeValueNq */) { + this._stateInAttributeValueNoQuotes(c); + } else if (this._state === 4 /* InSelfClosingTag */) { + this._stateInSelfClosingTag(c); + } else if (this._state === 16 /* InDeclaration */) { + this._stateInDeclaration(c); + } else if (this._state === 15 /* BeforeDeclaration */) { + this._stateBeforeDeclaration(c); + } else if (this._state === 21 /* AfterComment2 */) { + this._stateAfterComment2(c); + } else if (this._state === 18 /* BeforeComment */) { + this._stateBeforeComment(c); + } else if (this._state === 32 /* BeforeSpecialEnd */) { + this._stateBeforeSpecialEnd(c); + } else if (this._state === 38 /* AfterScript1 */) { + stateAfterScript1(this, c); + } else if (this._state === 39 /* AfterScript2 */) { + stateAfterScript2(this, c); + } else if (this._state === 40 /* AfterScript3 */) { + stateAfterScript3(this, c); + } else if (this._state === 33 /* BeforeScript1 */) { + stateBeforeScript1(this, c); + } else if (this._state === 34 /* BeforeScript2 */) { + stateBeforeScript2(this, c); + } else if (this._state === 35 /* BeforeScript3 */) { + stateBeforeScript3(this, c); + } else if (this._state === 36 /* BeforeScript4 */) { + stateBeforeScript4(this, c); + } else if (this._state === 37 /* BeforeScript5 */) { + this._stateBeforeScript5(c); + } else if (this._state === 41 /* AfterScript4 */) { + stateAfterScript4(this, c); + } else if (this._state === 42 /* AfterScript5 */) { + this._stateAfterScript5(c); + } else if (this._state === 43 /* BeforeStyle1 */) { + stateBeforeStyle1(this, c); + } else if (this._state === 28 /* InCdata */) { + this._stateInCdata(c); + } else if (this._state === 44 /* BeforeStyle2 */) { + stateBeforeStyle2(this, c); + } else if (this._state === 45 /* BeforeStyle3 */) { + stateBeforeStyle3(this, c); + } else if (this._state === 46 /* BeforeStyle4 */) { + this._stateBeforeStyle4(c); + } else if (this._state === 47 /* AfterStyle1 */) { + stateAfterStyle1(this, c); + } else if (this._state === 48 /* AfterStyle2 */) { + stateAfterStyle2(this, c); + } else if (this._state === 49 /* AfterStyle3 */) { + stateAfterStyle3(this, c); + } else if (this._state === 50 /* AfterStyle4 */) { + this._stateAfterStyle4(c); + } else if (this._state === 17 /* InProcessingInstruction */) { + this._stateInProcessingInstruction(c); + } else if (this._state === 53 /* InNamedEntity */) { + this._stateInNamedEntity(c); + } else if (this._state === 22 /* BeforeCdata1 */) { + stateBeforeCdata1(this, c); + } else if (this._state === 51 /* BeforeEntity */) { + stateBeforeEntity(this, c); + } else if (this._state === 23 /* BeforeCdata2 */) { + stateBeforeCdata2(this, c); + } else if (this._state === 24 /* BeforeCdata3 */) { + stateBeforeCdata3(this, c); + } else if (this._state === 29 /* AfterCdata1 */) { + this._stateAfterCdata1(c); + } else if (this._state === 30 /* AfterCdata2 */) { + this._stateAfterCdata2(c); + } else if (this._state === 25 /* BeforeCdata4 */) { + stateBeforeCdata4(this, c); + } else if (this._state === 26 /* BeforeCdata5 */) { + stateBeforeCdata5(this, c); + } else if (this._state === 27 /* BeforeCdata6 */) { + this._stateBeforeCdata6(c); + } else if (this._state === 55 /* InHexEntity */) { + this._stateInHexEntity(c); + } else if (this._state === 54 /* InNumericEntity */) { + this._stateInNumericEntity(c); + } else if (this._state === 52 /* BeforeNumericEntity */) { + stateBeforeNumericEntity(this, c); + } else { + this._cbs.onerror(Error("unknown _state"), this._state); + } + this._index++; + } + this._cleanup(); + }; + Tokenizer.prototype.pause = function() { + this._running = false; + }; + Tokenizer.prototype.resume = function() { + this._running = true; + if (this._index < this._buffer.length) { + this._parse(); + } + if (this._ended) { + this._finish(); + } + }; + Tokenizer.prototype.end = function(chunk) { + if (this._ended) this._cbs.onerror(Error(".end() after done!")); + if (chunk) this.write(chunk); + this._ended = true; + if (this._running) this._finish(); + }; + Tokenizer.prototype._finish = function() { + //if there is remaining data, emit it in a reasonable way + if (this._sectionStart < this._index) { + this._handleTrailingData(); + } + this._cbs.onend(); + }; + Tokenizer.prototype._handleTrailingData = function() { + var data = this._buffer.substr(this._sectionStart); + if ( + this._state === 28 /* InCdata */ || + this._state === 29 /* AfterCdata1 */ || + this._state === 30 /* AfterCdata2 */ + ) { + this._cbs.oncdata(data); + } else if ( + this._state === 19 /* InComment */ || + this._state === 20 /* AfterComment1 */ || + this._state === 21 /* AfterComment2 */ + ) { + this._cbs.oncomment(data); + } else if ( + this._state === 53 /* InNamedEntity */ && + !this._xmlMode + ) { + this._parseLegacyEntity(); + if (this._sectionStart < this._index) { + this._state = this._baseState; + this._handleTrailingData(); + } + } else if ( + this._state === 54 /* InNumericEntity */ && + !this._xmlMode + ) { + this._decodeNumericEntity(2, 10); + if (this._sectionStart < this._index) { + this._state = this._baseState; + this._handleTrailingData(); + } + } else if ( + this._state === 55 /* InHexEntity */ && + !this._xmlMode + ) { + this._decodeNumericEntity(3, 16); + if (this._sectionStart < this._index) { + this._state = this._baseState; + this._handleTrailingData(); + } + } else if ( + this._state !== 3 /* InTagName */ && + this._state !== 8 /* BeforeAttributeName */ && + this._state !== 11 /* BeforeAttributeValue */ && + this._state !== 10 /* AfterAttributeName */ && + this._state !== 9 /* InAttributeName */ && + this._state !== 13 /* InAttributeValueSq */ && + this._state !== 12 /* InAttributeValueDq */ && + this._state !== 14 /* InAttributeValueNq */ && + this._state !== 6 /* InClosingTagName */ + ) { + this._cbs.ontext(data); + } + //else, ignore remaining data + //TODO add a way to remove current tag + }; + Tokenizer.prototype.getAbsoluteIndex = function() { + return this._bufferOffset + this._index; + }; + Tokenizer.prototype._getSection = function() { + return this._buffer.substring(this._sectionStart, this._index); + }; + Tokenizer.prototype._emitToken = function(name) { + this._cbs[name](this._getSection()); + this._sectionStart = -1; + }; + Tokenizer.prototype._emitPartial = function(value) { + if (this._baseState !== 1 /* Text */) { + this._cbs.onattribdata(value); //TODO implement the new event + } else { + this._cbs.ontext(value); + } + }; + return Tokenizer; + })(); + exports.default = Tokenizer; + }, + { + "entities/lib/decode_codepoint": 23, + "entities/lib/maps/entities.json": 27, + "entities/lib/maps/legacy.json": 28, + "entities/lib/maps/xml.json": 29, + }, + ], + 8: [ + function(require, module, exports) { + "use strict"; + function __export(m) { + for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; + } + var __importStar = + (this && this.__importStar) || + function(mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; + }; + Object.defineProperty(exports, "__esModule", { value: true }); + var Parser_1 = require("./Parser"); + exports.Parser = Parser_1.Parser; + var domhandler_1 = require("domhandler"); + exports.DomHandler = domhandler_1.DomHandler; + exports.DefaultHandler = domhandler_1.DomHandler; + // Helper methods + /** + * Parses data, returns the resulting DOM. + * + * @param data The data that should be parsed. + * @param options Optional options for the parser and DOM builder. + */ + function parseDOM(data, options) { + var handler = new domhandler_1.DomHandler(void 0, options); + new Parser_1.Parser(handler, options).end(data); + return handler.dom; + } + exports.parseDOM = parseDOM; + /** + * Creates a parser instance, with an attached DOM handler. + * + * @param cb A callback that will be called once parsing has been completed. + * @param options Optional options for the parser and DOM builder. + * @param elementCb An optional callback that will be called every time a tag has been completed inside of the DOM. + */ + function createDomStream(cb, options, elementCb) { + var handler = new domhandler_1.DomHandler(cb, options, elementCb); + return new Parser_1.Parser(handler, options); + } + exports.createDomStream = createDomStream; + var Tokenizer_1 = require("./Tokenizer"); + exports.Tokenizer = Tokenizer_1.default; + var ElementType = __importStar(require("domelementtype")); + exports.ElementType = ElementType; + /** + * List of all events that the parser emits. + * + * Format: eventname: number of arguments. + */ + exports.EVENTS = { + attribute: 2, + cdatastart: 0, + cdataend: 0, + text: 1, + processinginstruction: 2, + comment: 1, + commentend: 0, + closetag: 1, + opentag: 2, + opentagname: 1, + error: 1, + end: 0, + }; + /* + All of the following exports exist for backwards-compatibility. + They should probably be removed eventually. +*/ + __export(require("./FeedHandler")); + __export(require("./WritableStream")); + __export(require("./CollectingHandler")); + var DomUtils = __importStar(require("domutils")); + exports.DomUtils = DomUtils; + var FeedHandler_1 = require("./FeedHandler"); + exports.RssHandler = FeedHandler_1.FeedHandler; + }, + { + "./CollectingHandler": 3, + "./FeedHandler": 4, + "./Parser": 6, + "./Tokenizer": 7, + "./WritableStream": 1, + "domelementtype": 11, + "domhandler": 12, + "domutils": 15, + }, + ], + 9: [ + function(require, module, exports) { + module.exports = { + elementNames: { + altglyph: "altGlyph", + altglyphdef: "altGlyphDef", + altglyphitem: "altGlyphItem", + animatecolor: "animateColor", + animatemotion: "animateMotion", + animatetransform: "animateTransform", + clippath: "clipPath", + feblend: "feBlend", + fecolormatrix: "feColorMatrix", + fecomponenttransfer: "feComponentTransfer", + fecomposite: "feComposite", + feconvolvematrix: "feConvolveMatrix", + fediffuselighting: "feDiffuseLighting", + fedisplacementmap: "feDisplacementMap", + fedistantlight: "feDistantLight", + fedropshadow: "feDropShadow", + feflood: "feFlood", + fefunca: "feFuncA", + fefuncb: "feFuncB", + fefuncg: "feFuncG", + fefuncr: "feFuncR", + fegaussianblur: "feGaussianBlur", + feimage: "feImage", + femerge: "feMerge", + femergenode: "feMergeNode", + femorphology: "feMorphology", + feoffset: "feOffset", + fepointlight: "fePointLight", + fespecularlighting: "feSpecularLighting", + fespotlight: "feSpotLight", + fetile: "feTile", + feturbulence: "feTurbulence", + foreignobject: "foreignObject", + glyphref: "glyphRef", + lineargradient: "linearGradient", + radialgradient: "radialGradient", + textpath: "textPath", + }, + attributeNames: { + definitionurl: "definitionURL", + attributename: "attributeName", + attributetype: "attributeType", + basefrequency: "baseFrequency", + baseprofile: "baseProfile", + calcmode: "calcMode", + clippathunits: "clipPathUnits", + diffuseconstant: "diffuseConstant", + edgemode: "edgeMode", + filterunits: "filterUnits", + glyphref: "glyphRef", + gradienttransform: "gradientTransform", + gradientunits: "gradientUnits", + kernelmatrix: "kernelMatrix", + kernelunitlength: "kernelUnitLength", + keypoints: "keyPoints", + keysplines: "keySplines", + keytimes: "keyTimes", + lengthadjust: "lengthAdjust", + limitingconeangle: "limitingConeAngle", + markerheight: "markerHeight", + markerunits: "markerUnits", + markerwidth: "markerWidth", + maskcontentunits: "maskContentUnits", + maskunits: "maskUnits", + numoctaves: "numOctaves", + pathlength: "pathLength", + patterncontentunits: "patternContentUnits", + patterntransform: "patternTransform", + patternunits: "patternUnits", + pointsatx: "pointsAtX", + pointsaty: "pointsAtY", + pointsatz: "pointsAtZ", + preservealpha: "preserveAlpha", + preserveaspectratio: "preserveAspectRatio", + primitiveunits: "primitiveUnits", + refx: "refX", + refy: "refY", + repeatcount: "repeatCount", + repeatdur: "repeatDur", + requiredextensions: "requiredExtensions", + requiredfeatures: "requiredFeatures", + specularconstant: "specularConstant", + specularexponent: "specularExponent", + spreadmethod: "spreadMethod", + startoffset: "startOffset", + stddeviation: "stdDeviation", + stitchtiles: "stitchTiles", + surfacescale: "surfaceScale", + systemlanguage: "systemLanguage", + tablevalues: "tableValues", + targetx: "targetX", + targety: "targetY", + textlength: "textLength", + viewbox: "viewBox", + viewtarget: "viewTarget", + xchannelselector: "xChannelSelector", + ychannelselector: "yChannelSelector", + zoomandpan: "zoomAndPan", + }, + }; + }, + {}, + ], + 10: [ + function(require, module, exports) { + /* + Module dependencies +*/ + var ElementType = require("domelementtype"); + var entities = require("entities"); + + /* mixed-case SVG and MathML tags & attributes + recognized by the HTML parser, see + https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inforeign +*/ + var foreignNames = require("./foreignNames.json"); + foreignNames.elementNames.__proto__ = null; /* use as a simple dictionary */ + foreignNames.attributeNames.__proto__ = null; + + var unencodedElements = { + __proto__: null, + style: true, + script: true, + xmp: true, + iframe: true, + noembed: true, + noframes: true, + plaintext: true, + noscript: true, + }; + + /* + Format attributes +*/ + function formatAttrs(attributes, opts) { + if (!attributes) return; + + var output = ""; + var value; + + // Loop through the attributes + for (var key in attributes) { + value = attributes[key]; + if (output) { + output += " "; + } + + if (opts.xmlMode === "foreign") { + /* fix up mixed-case attribute names */ + key = foreignNames.attributeNames[key] || key; + } + output += key; + if ((value !== null && value !== "") || opts.xmlMode) { + output += + '="' + + (opts.decodeEntities + ? entities.encodeXML(value) + : value.replace(/\"/g, """)) + + '"'; + } + } + + return output; + } + + /* + Self-enclosing tags (stolen from node-htmlparser) +*/ + var singleTag = { + __proto__: null, + area: true, + base: true, + basefont: true, + br: true, + col: true, + command: true, + embed: true, + frame: true, + hr: true, + img: true, + input: true, + isindex: true, + keygen: true, + link: true, + meta: true, + param: true, + source: true, + track: true, + wbr: true, + }; + + var render = (module.exports = function(dom, opts) { + if (!Array.isArray(dom) && !dom.cheerio) dom = [dom]; + opts = opts || {}; + + var output = ""; + + for (var i = 0; i < dom.length; i++) { + var elem = dom[i]; + + if (elem.type === "root") output += render(elem.children, opts); + else if (ElementType.isTag(elem)) output += renderTag(elem, opts); + else if (elem.type === ElementType.Directive) + output += renderDirective(elem); + else if (elem.type === ElementType.Comment) + output += renderComment(elem); + else if (elem.type === ElementType.CDATA) + output += renderCdata(elem); + else output += renderText(elem, opts); + } + + return output; + }); + + var foreignModeIntegrationPoints = [ + "mi", + "mo", + "mn", + "ms", + "mtext", + "annotation-xml", + "foreignObject", + "desc", + "title", + ]; + + function renderTag(elem, opts) { + // Handle SVG / MathML in HTML + if (opts.xmlMode === "foreign") { + /* fix up mixed-case element names */ + elem.name = foreignNames.elementNames[elem.name] || elem.name; + /* exit foreign mode at integration points */ + if ( + elem.parent && + foreignModeIntegrationPoints.indexOf(elem.parent.name) >= 0 + ) + opts = Object.assign({}, opts, { xmlMode: false }); + } + if (!opts.xmlMode && ["svg", "math"].indexOf(elem.name) >= 0) { + opts = Object.assign({}, opts, { xmlMode: "foreign" }); + } + + var tag = "<" + elem.name; + var attribs = formatAttrs(elem.attribs, opts); + + if (attribs) { + tag += " " + attribs; + } + + if ( + opts.xmlMode && + (!elem.children || elem.children.length === 0) + ) { + tag += "/>"; + } else { + tag += ">"; + if (elem.children) { + tag += render(elem.children, opts); + } + + if (!singleTag[elem.name] || opts.xmlMode) { + tag += ""; + } + } + + return tag; + } + + function renderDirective(elem) { + return "<" + elem.data + ">"; + } + + function renderText(elem, opts) { + var data = elem.data || ""; + + // if entities weren't decoded, no need to encode them back + if ( + opts.decodeEntities && + !(elem.parent && elem.parent.name in unencodedElements) + ) { + data = entities.encodeXML(data); + } + + return data; + } + + function renderCdata(elem) { + return ""; + } + + function renderComment(elem) { + return ""; + } + }, + { "./foreignNames.json": 9, "domelementtype": 11, "entities": 25 }, + ], + 11: [ + function(require, module, exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + /** + * Tests whether an element is a tag or not. + * + * @param elem Element to test + */ + function isTag(elem) { + return ( + elem.type === "tag" /* Tag */ || + elem.type === "script" /* Script */ || + elem.type === "style" /* Style */ + ); + } + exports.isTag = isTag; + // Exports for backwards compatibility + exports.Text = "text" /* Text */; //Text + exports.Directive = "directive" /* Directive */; // + exports.Comment = "comment" /* Comment */; // + exports.Script = "script" /* Script */; // + + + From 3886cbf3d179d4bfe34bde464e494c9861636d75 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Fri, 21 Feb 2020 08:07:45 +0000 Subject: [PATCH 002/254] --- compile.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/compile.js b/compile.js index 472779e..bab5cb8 100644 --- a/compile.js +++ b/compile.js @@ -4,6 +4,7 @@ const htmlparser = window.htmlparser2; const html2hyperscript = (input, stream) => { let indentLevel = 0; let attrOpen = false; + let textWritten = false; let justClosed = false; let size = 0; const streamWrite = stream.write; @@ -15,6 +16,10 @@ const html2hyperscript = (input, stream) => { if (justClosed) { justClosed = false; } + if (textWritten) { + stream.write(", "); + textWritten = false; + } stream.write("\n" + "\t".repeat(indentLevel++) + `${name}`); let attrKeys = Object.keys(attr); if (attrKeys.length) { @@ -47,6 +52,10 @@ const html2hyperscript = (input, stream) => { ontext(text) { if (!text.trim()) return; + if (textWritten) { + stream.write(", "); + textWritten = false; + } if (attrOpen) attrOpen = false; justClosed = false; stream.write(`\`${text.replace(/`/g, String.raw`\``)}\``); From f0813113de837301524ee01d1428098c4c9bbfea Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Fri, 21 Feb 2020 10:49:04 +0000 Subject: [PATCH 003/254] --- compile.js | 29 +++++++++----- index.html | 115 +++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 123 insertions(+), 21 deletions(-) diff --git a/compile.js b/compile.js index bab5cb8..8f1e97b 100644 --- a/compile.js +++ b/compile.js @@ -2,6 +2,7 @@ const htmlparser = window.htmlparser2; const html2hyperscript = (input, stream) => { + const elements = new Set(); let indentLevel = 0; let attrOpen = false; let textWritten = false; @@ -13,6 +14,7 @@ const html2hyperscript = (input, stream) => { const parser = new htmlparser.Parser( { onopentag(name, attr) { + elements.add(name); if (justClosed) { justClosed = false; } @@ -20,6 +22,7 @@ const html2hyperscript = (input, stream) => { stream.write(", "); textWritten = false; } + if (attrOpen) attrOpen = false; stream.write("\n" + "\t".repeat(indentLevel++) + `${name}`); let attrKeys = Object.keys(attr); if (attrKeys.length) { @@ -29,7 +32,10 @@ const html2hyperscript = (input, stream) => { if (selector) stream.write(`["${selector}"]`); stream.write("("); - attrKeys = attrKeys.filter(name => !["class", "id"].includes(name)); + delete attr.class; + delete attr.id; + + attrKeys = Object.keys(attr); if (attrKeys.length) { stream.write(JSON.stringify(attr), ", "); attrOpen = true; @@ -42,12 +48,11 @@ const html2hyperscript = (input, stream) => { oncomment(comments) { justClosed = false; (comments = comments.trim()) && - comments.split("\n").forEach(comment => - stream.write( - "\n// " + "\t".repeat(indentLevel) + comment.trim(), - // Strip whitespace and prepend ; to every line of comment - ), - ); + comments + .split("\n") + .forEach(comment => + stream.write("\n// " + "\t".repeat(indentLevel) + comment.trim()), + ); }, ontext(text) { @@ -58,11 +63,17 @@ const html2hyperscript = (input, stream) => { } if (attrOpen) attrOpen = false; justClosed = false; - stream.write(`\`${text.replace(/`/g, String.raw`\``)}\``); + const escapedTick = String.raw`\``; + text = text.replace(/`/g, escapedTick); + stream.write(`m.trust(String.raw\`${text}\`)`); + textWritten = true; }, onclosetag() { if (justClosed) stream.pop(); + if (textWritten) { + textWritten = false; + } if (attrOpen) { stream.pop(); stream.pop(); @@ -84,7 +95,7 @@ const html2hyperscript = (input, stream) => { parser.write(input); parser.end(); - return stream; + return { elements, stream }; }; window.compile = html2hyperscript; diff --git a/index.html b/index.html index e9ca307..63c63b8 100644 --- a/index.html +++ b/index.html @@ -1,51 +1,137 @@ + +

HTML to Hyperscript (mithril-toolset compatible)

+ +
- - + + + + + + + +
- + \ No newline at end of file From ac625c1fd8617429e96a0b2a256b7040d2398e9d Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Mon, 21 Jun 2021 02:41:57 +0530 Subject: [PATCH 004/254] (feat) rewrite for deno Signed-off-by: Muthu Kumar --- .eslintrc | 25 ------ .gitignore | 2 - .npmrc | 1 - .pnpm-workspace.yaml | 6 -- .prettierrc | 12 --- .vscode/settings.json | 5 ++ mod.ts | 3 + node/index.ts | 110 ------------------------- node/package.json | 10 --- node/types.ts | 4 - node/util.ts | 22 ----- package.json | 13 --- pnpm-lock.yaml | 10 --- src/Node.ts | 83 +++++++++++++++++++ src/elements.ts | 113 ++++++++++++++++++++++++++ node/parseSelector.ts => src/parse.ts | 32 ++++++-- src/util.ts | 1 + tsconfig.json | 15 ---- 18 files changed, 231 insertions(+), 236 deletions(-) delete mode 100644 .eslintrc delete mode 100644 .gitignore delete mode 100644 .npmrc delete mode 100644 .pnpm-workspace.yaml delete mode 100644 .prettierrc create mode 100644 .vscode/settings.json create mode 100644 mod.ts delete mode 100644 node/index.ts delete mode 100644 node/package.json delete mode 100644 node/types.ts delete mode 100644 node/util.ts delete mode 100644 package.json delete mode 100644 pnpm-lock.yaml create mode 100644 src/Node.ts create mode 100644 src/elements.ts rename node/parseSelector.ts => src/parse.ts (73%) create mode 100644 src/util.ts delete mode 100644 tsconfig.json diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 3e995d5..0000000 --- a/.eslintrc +++ /dev/null @@ -1,25 +0,0 @@ -{ - "env": { - "es6": true, - "node": true - }, - "parserOptions": { - "ecmaVersion": 2020, - "sourceType": "module", - "project": "./tsconfig.json" - }, - "extends": ["eslint:recommended"], - "rules": { - "indent": ["error", "tab"], - "camelcase": ["error", {"properties": "never"}], - "linebreak-style": ["error", "unix"], - "no-constant-condition": "error", - "quotes": ["error", "double"], - "semi": "error", - "no-extra-semi": "error", - "prefer-const": "error", - "eol-last": "error", - "no-unused-vars": 0, - "no-console": 0 - } -} \ No newline at end of file diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 867a84a..0000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -**/node_modules -**/pnpm-debug.log \ No newline at end of file diff --git a/.npmrc b/.npmrc deleted file mode 100644 index c02dd08..0000000 --- a/.npmrc +++ /dev/null @@ -1 +0,0 @@ -link-workspace-packages = true \ No newline at end of file diff --git a/.pnpm-workspace.yaml b/.pnpm-workspace.yaml deleted file mode 100644 index 0f2abf0..0000000 --- a/.pnpm-workspace.yaml +++ /dev/null @@ -1,6 +0,0 @@ -{ - packages: [ - ".", - "packages/**" - ] -} \ No newline at end of file diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 90509d3..0000000 --- a/.prettierrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "trailingComma": "all", - "useTabs": true, - "semi": true, - "singleQuote": false, - "quoteProps": "consistent", - "jsxSingleQuote": false, - "bracketSpacing": true, - "jsxBracketSameLine": true, - "arrowParens": "avoid", - "printWidth": 100 -} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d76b357 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "deno.enable": true, + "deno.lint": true, + "deno.unstable": true +} \ No newline at end of file diff --git a/mod.ts b/mod.ts new file mode 100644 index 0000000..8e6a574 --- /dev/null +++ b/mod.ts @@ -0,0 +1,3 @@ +export type { Element } from "./src/elements.ts"; +export { elements } from "./src/Node.ts"; +export { parseSelector } from "./src/parse.ts"; diff --git a/node/index.ts b/node/index.ts deleted file mode 100644 index c6f8882..0000000 --- a/node/index.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { Attrs } from "./types"; -import { parseSelector } from "./parseSelector"; -import { flatCat, isIterable, collect, map, isObject } from "./util"; - -interface Node { - tag: string; - key?: string; - attrs: Attrs; - children: Iterable; -} - -type Nodes = Node | Iterable; - -interface h { - (element: string, selector: string, attr: Attrs, ...children: Nodes[]): Node; - (element: string, selector: string, ...children: Nodes[]): Node; - (selector: string, attr: Attrs, ...children: Nodes[]): Node; - (selector: string, ...children: Nodes[]): Node; - (attr: Attrs, ...children: Nodes[]): Node; - (...children: Nodes[]): Node; -} - -const composeAttributes = (a: Attrs, b: Attrs) => { - if (a.id && b.id) { - throw new Error(`Multiple IDs are not allowed: ${a.id}, ${b.id}`); - } - - return Object.assign(a, b, { class: [...(a.class || []), ...(b.class || [])] }); -}; - -const resolveChildren = (a: Nodes[], b: T | Nodes): Iterable => { - if (b instanceof Node) { - return flatCat(...a, [b]); - } else if (isIterable(b)) { - return flatCat(...a, b); - } else return flatCat(...a); -}; - -export const isNode = (x: any): x is Node => x instanceof Node; - -export const isAttr = (x: any): x is Attrs => isObject(x) && !isIterable(x) && !isNode(x); - -class Node implements Node { - constructor(a?: unknown, b?: unknown, c?: unknown, ...otherChildren: Nodes[]) { - if (typeof b === "string") { - // (string, string, ...) -> Node; - - // if c is an object, but not an instance of Node or Array, it's attrs - const attrs: Attrs = isAttr(c) ? c : {}; - // if c is an instance of Node or Array, it joins otherChildren - const children = resolveChildren(otherChildren, c); - const { tag, ...classID } = parseSelector(b); - Object.assign(this, { - tag: a, - attrs: composeAttributes(classID, attrs), - children, - }); - } else if (typeof a === "string") { - // at least a is defined - // if b is an object, but not an instance of Node or Array, it's attrs - const attrs: Attrs = isAttr(b) ? b : {}; - // if c or b are instances of Node or Array, it joins otherChildren - const children = resolveChildren(otherChildren, [c, b]); - const { tag, ...classID } = parseSelector(a, { tagMode: true }); - if (Array.isArray(c)) { - Object.assign(this, { - tag, - attrs: composeAttributes(classID, attrs), - children, - }); - } else if (c instanceof Node) { - } - } - } - - toJSON(): any { - return Object.assign({}, this, { - children: collect(this.children ? map(child => child.toJSON(), this.children) : []), - }); - } -} - -// export function h(a: string, b: string, c: Attrs, ...otherChildren: Nodes[]): Node { -// let node: Node = Object.create(Node); - -// if (typeof b === "string") { -// return Object.assign(node, { -// tag: a, -// attrs: Object.assign(parseSelector(b), c), -// children: otherChildren, -// NODE, -// }); -// } else if (typeof a === "string") { -// const { tag, ...attrs } = parseSelector(a, { tagMode: true }); -// if () -// return { tag, attrs, NODE }; -// } - -// return node; -// } - -console.log( - new Node( - "div", - "#main.container", - { "data-attr": "0" }, - new Node(".child", { "data-attr": "1" }), - ).toJSON(), - new Node(".child", { "data-attr": "1" }), -); diff --git a/node/package.json b/node/package.json deleted file mode 100644 index 0e84ca3..0000000 --- a/node/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "@hyperactive/node", - "version": "0.0.1", - "description": "Node utility for hyperactive", - "author": "Muthu Kumar <@MKRhere> (https://mkr.pw)", - "license": "MIT", - "scripts": { - "preinstall": "node -e \"!process.env.npm_config_user_agent.startsWith('pnpm/') && !console.log('Use \\`npm i -g pnpm\\` and \\`pnpm install\\` to install dependencies in this package\\n') && process.exit(1)\"" - } -} diff --git a/node/types.ts b/node/types.ts deleted file mode 100644 index 0b9b9aa..0000000 --- a/node/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type Attrs = Partial<{ - id: string; - class: string[]; -}>; diff --git a/node/util.ts b/node/util.ts deleted file mode 100644 index 1928b3a..0000000 --- a/node/util.ts +++ /dev/null @@ -1,22 +0,0 @@ -export const isObject = (x: any): x is object => x && typeof x === "object"; - -export const isIterable = (x: any): x is Iterable => - x && typeof x === "object" && typeof (x[Symbol.iterator] as any) === "function"; - -export function* flatCat(...xs: (T | Iterable)[]): Iterable { - for (const x of xs) { - if (isIterable(x)) { - yield* flatCat(...x); - } else yield x; - } -} - -export function* map(f: (x: T) => U, xs: Iterable) { - for (const x of xs) { - yield f(x); - } -} - -export function collect(iter: Iterable) { - return [...iter]; -} diff --git a/package.json b/package.json deleted file mode 100644 index fbce62c..0000000 --- a/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "hyperactive", - "version": "0.0.0", - "description": "The hyperactive suite of web application development tools", - "author": "Muthu Kumar <@MKRhere> (https://mkr.pw)", - "license": "MIT", - "scripts": { - "preinstall": "node -e \"!process.env.npm_config_user_agent.startsWith('pnpm/') && !console.log('Use \\`npm i -g pnpm\\` and \\`pnpm --recursive install\\` to install dependencies in this repository\\n') && process.exit(1)\"" - }, - "devDependencies": { - "@types/node": "^13.7.6" - } -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index 8797efa..0000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,10 +0,0 @@ -devDependencies: - '@types/node': 13.7.6 -lockfileVersion: 5.1 -packages: - /@types/node/13.7.6: - dev: true - resolution: - integrity: sha512-eyK7MWD0R1HqVTp+PtwRgFeIsemzuj4gBFSQxfPHY5iMjS7474e5wq+VFgTcdpyHeNxyKSaetYAjdMLJlKoWqA== -specifiers: - '@types/node': ^13.7.6 diff --git a/src/Node.ts b/src/Node.ts new file mode 100644 index 0000000..e25dbd9 --- /dev/null +++ b/src/Node.ts @@ -0,0 +1,83 @@ +import { Element } from "./elements.ts"; + +type Falsy = false | "" | 0 | 0n | undefined | null; + +const Falsy = new Set([false, "", 0, 0n, undefined, null]); +// deno-lint-ignore no-explicit-any +const isFalsy = (n: any): n is Falsy => Falsy.has(n); + +type Attr = Record; + +class Node { + constructor( + public tag: Tag, + public attrs: Attrs, + public children: Node[], + ) {} +} + +// deno-lint-ignore no-explicit-any +const isNode = (n: any): n is Node => n instanceof Node; + +function h( + elem: Tag, + props?: Attrs | Falsy, +): Node; + +function h( + elem: Tag, + ...children: (Node | Falsy)[] +): Node; + +function h( + elem: Tag, + props: Attr, + ...children: Node[] +): Node; + +function h( + elem: Tag, + props?: Attrs | Node | Falsy, + ...children: (Node | Falsy)[] +): Node; + +function h( + elem: Element, + props?: Attr | Node | Falsy, + ...childNodes: (Node | Falsy)[] +): Node { + const [attrs, children] = + isNode(props) || isFalsy(props) + ? [{}, [props, ...childNodes]] + : [props || {}, childNodes || []]; + + return new Node( + elem, + attrs, + children + // filter falsy nodes + .filter((child): child is Node => (child ? true : false)), + ); +} + +type hElement = + // + ((props?: Node["attrs"]) => Node) & + ((childNode: Nodeish) => Node) & + ((props: Node["attrs"], ...childNodes: (Node | Falsy)[]) => Node); + +export const elements = (...elems: Elems) => { + return elems.map( + (elem): hElement => + ( + props?: Node["attrs"] | Node | Falsy, + ...childNodes: (Node | Falsy)[] + ) => + h(elem, props, ...childNodes), + ) as { + [Index in keyof Elems]: hElement< + // @ts-ignore TypeScript pls + Elems[Index] + >; + }; +}; diff --git a/src/elements.ts b/src/elements.ts new file mode 100644 index 0000000..57a5e70 --- /dev/null +++ b/src/elements.ts @@ -0,0 +1,113 @@ +export type Element = + | "a" + | "abbr" + | "address" + | "area" + | "article" + | "aside" + | "audio" + | "b" + | "base" + | "bdi" + | "bdo" + | "blockquote" + | "body" + | "br" + | "button" + | "canvas" + | "caption" + | "cite" + | "code" + | "col" + | "colgroup" + | "data" + | "datalist" + | "dd" + | "del" + | "details" + | "dfn" + | "dialog" + | "div" + | "dl" + | "dt" + | "em" + | "embed" + | "fieldset" + | "figcaption" + | "figure" + | "footer" + | "form" + | "h1" + | "h2" + | "h3" + | "h4" + | "h5" + | "h6" + | "head" + | "header" + | "hr" + | "html" + | "i" + | "iframe" + | "img" + | "input" + | "ins" + | "kbd" + | "label" + | "legend" + | "li" + | "link" + | "main" + | "map" + | "mark" + | "meta" + | "meter" + | "nav" + | "noscript" + | "object" + | "ol" + | "optgroup" + | "option" + | "output" + | "p" + | "param" + | "picture" + | "pre" + | "progress" + | "q" + | "rb" + | "rp" + | "rt" + | "rtc" + | "ruby" + | "s" + | "samp" + | "script" + | "section" + | "select" + | "slot" + | "small" + | "source" + | "span" + | "strong" + | "style" + | "sub" + | "summary" + | "sup" + | "table" + | "tbody" + | "td" + | "template" + | "textarea" + | "tfoot" + | "th" + | "thead" + | "time" + | "title" + | "tr" + | "track" + | "u" + | "ul" + | "var" + | "video" + | "wbr"; diff --git a/node/parseSelector.ts b/src/parse.ts similarity index 73% rename from node/parseSelector.ts rename to src/parse.ts index e643902..107e286 100644 --- a/node/parseSelector.ts +++ b/src/parse.ts @@ -1,11 +1,26 @@ -import { Attrs } from "./types"; +export type Attrs = { + tag: string; + id: string; + class: string[]; +}; -const digits = new Set(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]); +const digits = new Set([ + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", +]); export const parseSelector = (selector: string, { tagMode = false } = {}) => { selector = selector.trim(); - const attrs: Attrs & { tag?: string } = { tag: undefined, id: undefined }; + const attrs: Partial = { tag: undefined, id: undefined }; const classlist = new Set(); let started = false, @@ -17,8 +32,11 @@ export const parseSelector = (selector: string, { tagMode = false } = {}) => { buffer = buffer.trim(); if (bufferType) { if (bufferType === "id" && attrs.id) - throw new Error(`Cannot declare multiple IDs: ${attrs.id} ${buffer}`); - if (bufferType === "tag" || bufferType == "id") attrs[bufferType] = buffer; + throw new Error( + `Cannot declare multiple IDs: ${attrs.id} ${buffer}`, + ); + if (bufferType === "tag" || bufferType == "id") + attrs[bufferType] = buffer; else classlist.add(buffer); } } @@ -31,7 +49,9 @@ export const parseSelector = (selector: string, { tagMode = false } = {}) => { if (!buffer) if (char === "-" || char === "_" || digits.has(char)) // if match starts with -_0-9, error - throw new Error(`${bufferType || type} cannot start with char: ${char}`); + throw new Error( + `${bufferType || type} cannot start with char: ${char}`, + ); buffer += char; if (type) bufferType = type; }; diff --git a/src/util.ts b/src/util.ts new file mode 100644 index 0000000..fe96f5d --- /dev/null +++ b/src/util.ts @@ -0,0 +1 @@ +export type Falsy = false | "" | 0 | 0n | undefined | null; diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index a88a178..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "es2020", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ - "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ - "lib": [ "es2020" ], /* Specify library files to be included in the compilation. */ - "allowJs": true, /* Allow javascript files to be compiled. */ - "checkJs": true, /* Report errors in .js files. */ - "declaration": true, /* Generates corresponding '.d.ts' file. */ - "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - "sourceMap": true, /* Generates corresponding '.map' file. */ - "strict": true, /* Enable all strict type-checking options. */ - "resolveJsonModule": true, /* Resolves JSON imports */ - "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ - } -} \ No newline at end of file From 6dbd2acef939f5cac25aa798bddb8120ed3ab4b3 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Mon, 21 Jun 2021 02:43:31 +0530 Subject: [PATCH 005/254] (feat) expose Node and h Signed-off-by: Muthu Kumar --- mod.ts | 2 +- src/Node.ts | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mod.ts b/mod.ts index 8e6a574..614a1b5 100644 --- a/mod.ts +++ b/mod.ts @@ -1,3 +1,3 @@ export type { Element } from "./src/elements.ts"; -export { elements } from "./src/Node.ts"; +export { Node, h, elements } from "./src/Node.ts"; export { parseSelector } from "./src/parse.ts"; diff --git a/src/Node.ts b/src/Node.ts index e25dbd9..eae978a 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -8,7 +8,7 @@ const isFalsy = (n: any): n is Falsy => Falsy.has(n); type Attr = Record; -class Node { +export class Node { constructor( public tag: Tag, public attrs: Attrs, @@ -19,29 +19,29 @@ class Node { // deno-lint-ignore no-explicit-any const isNode = (n: any): n is Node => n instanceof Node; -function h( +export function h( elem: Tag, props?: Attrs | Falsy, ): Node; -function h( +export function h( elem: Tag, ...children: (Node | Falsy)[] ): Node; -function h( +export function h( elem: Tag, props: Attr, ...children: Node[] ): Node; -function h( +export function h( elem: Tag, props?: Attrs | Node | Falsy, ...children: (Node | Falsy)[] ): Node; -function h( +export function h( elem: Element, props?: Attr | Node | Falsy, ...childNodes: (Node | Falsy)[] From 6d280137f2e40df37b4af1a2b7c97f64cb4c28f6 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Mon, 21 Jun 2021 03:24:36 +0530 Subject: [PATCH 006/254] (feat) support TextNode Signed-off-by: Muthu Kumar --- src/Node.ts | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/Node.ts b/src/Node.ts index eae978a..4d56661 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -1,23 +1,31 @@ import { Element } from "./elements.ts"; -type Falsy = false | "" | 0 | 0n | undefined | null; +export type Falsy = false | "" | 0 | 0n | undefined | null; -const Falsy = new Set([false, "", 0, 0n, undefined, null]); +export const Falsy = new Set([false, "", 0, 0n, undefined, null]); // deno-lint-ignore no-explicit-any -const isFalsy = (n: any): n is Falsy => Falsy.has(n); +export const isFalsy = (n: any): n is Falsy => Falsy.has(n); -type Attr = Record; +export type Attr = Record; + +export type TextNode = string; + +export type Nodeish = + | Node + | TextNode + | Falsy; export class Node { constructor( public tag: Tag, public attrs: Attrs, - public children: Node[], + public children: (Node | TextNode)[], ) {} } // deno-lint-ignore no-explicit-any -const isNode = (n: any): n is Node => n instanceof Node; +export const isNode = (n: any): n is Node | TextNode => + n instanceof Node || typeof n === "string"; export function h( elem: Tag, @@ -26,25 +34,25 @@ export function h( export function h( elem: Tag, - ...children: (Node | Falsy)[] + ...children: Nodeish[] ): Node; export function h( elem: Tag, props: Attr, - ...children: Node[] + ...children: Nodeish[] ): Node; export function h( elem: Tag, - props?: Attrs | Node | Falsy, - ...children: (Node | Falsy)[] + props?: Attrs | Nodeish | Falsy, + ...children: Nodeish[] ): Node; export function h( elem: Element, - props?: Attr | Node | Falsy, - ...childNodes: (Node | Falsy)[] + props?: Attr | Nodeish, + ...childNodes: Nodeish[] ): Node { const [attrs, children] = isNode(props) || isFalsy(props) @@ -60,19 +68,16 @@ export function h( ); } -type hElement = +export type hElement = // - ((props?: Node["attrs"]) => Node) & - ((childNode: Nodeish) => Node) & - ((props: Node["attrs"], ...childNodes: (Node | Falsy)[]) => Node); + ((props?: Attr) => Node) & + ((childNode: TNodeish) => Node) & + ((props: Attr, ...childNodes: Nodeish[]) => Node); export const elements = (...elems: Elems) => { return elems.map( (elem): hElement => - ( - props?: Node["attrs"] | Node | Falsy, - ...childNodes: (Node | Falsy)[] - ) => + (props?: Attr | Nodeish, ...childNodes: Nodeish[]) => h(elem, props, ...childNodes), ) as { [Index in keyof Elems]: hElement< From fdb104a40e76f8564adef55419ac1bc9bd452358 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Mon, 21 Jun 2021 03:24:47 +0530 Subject: [PATCH 007/254] (feat) export everything Signed-off-by: Muthu Kumar --- mod.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mod.ts b/mod.ts index 614a1b5..31037b1 100644 --- a/mod.ts +++ b/mod.ts @@ -1,3 +1,4 @@ -export type { Element } from "./src/elements.ts"; -export { Node, h, elements } from "./src/Node.ts"; -export { parseSelector } from "./src/parse.ts"; +export * from "./src/elements.ts"; +export * from "./src/Node.ts"; +export * from "./src/parse.ts"; +export * from "./src/render.ts"; From adb598774ab0bc6ab4495851643b98b1b5d70eb6 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Mon, 21 Jun 2021 03:25:56 +0530 Subject: [PATCH 008/254] (feat) renderHTML Signed-off-by: Muthu Kumar --- src/render.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/render.ts diff --git a/src/render.ts b/src/render.ts new file mode 100644 index 0000000..a70b141 --- /dev/null +++ b/src/render.ts @@ -0,0 +1,21 @@ +import { Nodeish, isFalsy } from "./Node.ts"; + +export function renderHTML(node: Nodeish) { + if (typeof node === "string") return node; + if (isFalsy(node)) return ""; + + let stringified = "<" + node.tag; + + const attr = Object.entries(node.attrs) + .map(([attr, val]) => (val ? `${attr}="${val}"` : attr)) + .join(" "); + + if (attr) stringified += " " + attr; + + if (node.children.length) + stringified += + ">" + node.children.map(renderHTML).join("") + ``; + else stringified += " />"; + + return stringified; +} From dd33ec4c079cd456cd0a366558ca02519fab3724 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Mon, 21 Jun 2021 03:26:04 +0530 Subject: [PATCH 009/254] (feat) add tests Signed-off-by: Muthu Kumar --- .vscode/settings.json | 5 ++++- test.ts | 30 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 test.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index d76b357..542c65d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,8 @@ { "deno.enable": true, "deno.lint": true, - "deno.unstable": true + "deno.unstable": true, + "deno.suggest.imports.hosts": { + "https://deno.land": true + } } \ No newline at end of file diff --git a/test.ts b/test.ts new file mode 100644 index 0000000..c2358af --- /dev/null +++ b/test.ts @@ -0,0 +1,30 @@ +import { assertEquals } from "https://deno.land/std@0.99.0/testing/asserts.ts"; + +import { elements, renderHTML } from "./mod.ts"; + +const [div, p, h1, br] = elements("div", "p", "h1", "br"); + +Deno.test({ + name: "renderHTML simple", + fn: () => { + assertEquals( + renderHTML(div({ id: "hello", class: "world" }, "Hello world")), + `
Hello world
`, + ); + }, +}); + +Deno.test({ + name: "renderHTML complex", + fn: () => { + assertEquals( + renderHTML( + div( + { id: "hello", class: "world" }, + p(h1({ class: "hello" }, "hello world", br())), + ), + ), + `

hello world

`, + ); + }, +}); From 19c1ddebb4e3cc3f8f32735e8b95dc8978f56cbc Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Mon, 21 Jun 2021 03:40:31 +0530 Subject: [PATCH 010/254] (doc) update README Signed-off-by: Muthu Kumar --- README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c4a875..c99911a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,19 @@ # hyperactive -Hyperactive is a suite of tools for webapps. It's still in development, so check back later. +Hyperactive is a suite of tools to build smart webapps. As of 1.0, only server-side render is supported. + +## Usage example + +```TypeScript +import { elements, renderHTML } from "https://deno.land/x/hyperactive/mod.ts"; + +assertEquals( + renderHTML( + div( + { id: "hello", class: "world" }, + p(h1({ class: "hello" }, "hello world", br())), + ), + ), + `

hello world

`, +); +``` From 6e85f46f0756379ddb4ce5554b1a6cc914dbd629 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Tue, 22 Jun 2021 03:46:47 +0530 Subject: [PATCH 011/254] (feat) escape HTML by default, use trust() for raw Signed-off-by: Muthu Kumar --- README.md | 2 ++ src/Node.ts | 30 +++++++++++++++++------------- src/render.ts | 6 ++++-- src/util.ts | 15 +++++++++++++++ test.ts | 16 +++++++++++++++- 5 files changed, 53 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index c99911a..393850f 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ Hyperactive is a suite of tools to build smart webapps. As of 1.0, only server-s ```TypeScript import { elements, renderHTML } from "https://deno.land/x/hyperactive/mod.ts"; +const [ div, p, h1 ] = elements("div", "p", "h1"); + assertEquals( renderHTML( div( diff --git a/src/Node.ts b/src/Node.ts index 4d56661..6e12954 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -1,19 +1,13 @@ import { Element } from "./elements.ts"; - -export type Falsy = false | "" | 0 | 0n | undefined | null; - -export const Falsy = new Set([false, "", 0, 0n, undefined, null]); -// deno-lint-ignore no-explicit-any -export const isFalsy = (n: any): n is Falsy => Falsy.has(n); +import { Falsy, isFalsy } from "./util.ts"; export type Attr = Record; export type TextNode = string; -export type Nodeish = - | Node - | TextNode - | Falsy; +export class HTMLNode { + constructor(public htmlString: string) {} +} export class Node { constructor( @@ -23,9 +17,15 @@ export class Node { ) {} } +export type Nodeish = + | Node + | TextNode + | HTMLNode + | Falsy; + // deno-lint-ignore no-explicit-any -export const isNode = (n: any): n is Node | TextNode => - n instanceof Node || typeof n === "string"; +export const isNode = (n: any): n is Node | HTMLNode | TextNode => + n instanceof Node || n instanceof HTMLNode || typeof n === "string"; export function h( elem: Tag, @@ -71,7 +71,7 @@ export function h( export type hElement = // ((props?: Attr) => Node) & - ((childNode: TNodeish) => Node) & + ((...childNodes: Nodeish[]) => Node) & ((props: Attr, ...childNodes: Nodeish[]) => Node); export const elements = (...elems: Elems) => { @@ -86,3 +86,7 @@ export const elements = (...elems: Elems) => { >; }; }; + +export function trust(html: string) { + return new HTMLNode(html); +} diff --git a/src/render.ts b/src/render.ts index a70b141..106cf23 100644 --- a/src/render.ts +++ b/src/render.ts @@ -1,8 +1,10 @@ -import { Nodeish, isFalsy } from "./Node.ts"; +import { Nodeish, HTMLNode } from "./Node.ts"; +import { isFalsy, escapeHTML } from "./util.ts"; export function renderHTML(node: Nodeish) { - if (typeof node === "string") return node; if (isFalsy(node)) return ""; + if (typeof node === "string") return escapeHTML(node); + if (node instanceof HTMLNode) return node.htmlString; let stringified = "<" + node.tag; diff --git a/src/util.ts b/src/util.ts index fe96f5d..59386f6 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1 +1,16 @@ +const escapables = { + "<": "<", + ">": ">", + "&": "&", + "'": "'", + '"': """, +}; + +export const escapeHTML = (s: string) => + s.replace(/<|>|&|"|'/g, r => escapables[r as keyof typeof escapables] || r); + export type Falsy = false | "" | 0 | 0n | undefined | null; + +export const Falsy = new Set([false, "", 0, 0n, undefined, null]); +// deno-lint-ignore no-explicit-any +export const isFalsy = (n: any): n is Falsy => Falsy.has(n); diff --git a/test.ts b/test.ts index c2358af..ba86625 100644 --- a/test.ts +++ b/test.ts @@ -1,6 +1,6 @@ import { assertEquals } from "https://deno.land/std@0.99.0/testing/asserts.ts"; -import { elements, renderHTML } from "./mod.ts"; +import { elements, trust, renderHTML } from "./mod.ts"; const [div, p, h1, br] = elements("div", "p", "h1", "br"); @@ -28,3 +28,17 @@ Deno.test({ ); }, }); + +Deno.test({ + name: "renderHTML with HTML characters", + fn: () => { + assertEquals(renderHTML(p("")), `

<test />

`); + }, +}); + +Deno.test({ + name: "renderHTML with trusted HTML", + fn: () => { + assertEquals(renderHTML(p(trust(""))), `

`); + }, +}); From eeb77e736eb23d15f89b225bd0105c22bd2d9295 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Tue, 22 Jun 2021 22:08:16 +0530 Subject: [PATCH 012/254] (feat) support custom-tags Signed-off-by: Muthu Kumar --- src/Node.ts | 11 +++++++++-- src/elements.ts | 3 +++ test.ts | 22 +++++++++++++++++++++- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/Node.ts b/src/Node.ts index 6e12954..c78625f 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -1,4 +1,4 @@ -import { Element } from "./elements.ts"; +import { Element, CustomTag } from "./elements.ts"; import { Falsy, isFalsy } from "./util.ts"; export type Attr = Record; @@ -74,7 +74,7 @@ export type hElement = ((...childNodes: Nodeish[]) => Node) & ((props: Attr, ...childNodes: Nodeish[]) => Node); -export const elements = (...elems: Elems) => { +const _elements = (...elems: Elems) => { return elems.map( (elem): hElement => (props?: Attr | Nodeish, ...childNodes: Nodeish[]) => @@ -87,6 +87,13 @@ export const elements = (...elems: Elems) => { }; }; +export const elements = new Proxy(_elements, { + get(_: unknown, elem: E): hElement { + return (props?: Attr | Nodeish, ...childNodes: Nodeish[]) => + h(elem, props, ...childNodes); + }, +}) as typeof _elements & { [k in Exclude]: hElement }; + export function trust(html: string) { return new HTMLNode(html); } diff --git a/src/elements.ts b/src/elements.ts index 57a5e70..1700cb1 100644 --- a/src/elements.ts +++ b/src/elements.ts @@ -1,4 +1,7 @@ +export type CustomTag = `${string}-${string}`; + export type Element = + | CustomTag | "a" | "abbr" | "address" diff --git a/test.ts b/test.ts index ba86625..e0bd123 100644 --- a/test.ts +++ b/test.ts @@ -2,7 +2,7 @@ import { assertEquals } from "https://deno.land/std@0.99.0/testing/asserts.ts"; import { elements, trust, renderHTML } from "./mod.ts"; -const [div, p, h1, br] = elements("div", "p", "h1", "br"); +const { div, p, h1, br } = elements; Deno.test({ name: "renderHTML simple", @@ -42,3 +42,23 @@ Deno.test({ assertEquals(renderHTML(p(trust(""))), `

`); }, }); + +Deno.test({ + name: "elements() - elements[] equivalence", + fn: () => { + const { div, p } = elements; + const [div2, p2] = elements("div", "p"); + assertEquals( + renderHTML(div(p("Hello"))), + renderHTML(div2(p2("Hello"))), + ); + }, +}); + +Deno.test({ + name: "renderHTML with custom element", + fn: () => { + const [el] = elements("custom-element"); + assertEquals(renderHTML(el()), ``); + }, +}); From 8faf80477383a4c0166279264ef79c82a89b45ab Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Wed, 23 Jun 2021 08:51:02 +0530 Subject: [PATCH 013/254] (feat) refactor and deduplication Signed-off-by: Muthu Kumar --- src/Node.ts | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/Node.ts b/src/Node.ts index c78625f..4b207b5 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -74,25 +74,28 @@ export type hElement = ((...childNodes: Nodeish[]) => Node) & ((props: Attr, ...childNodes: Nodeish[]) => Node); -const _elements = (...elems: Elems) => { - return elems.map( - (elem): hElement => - (props?: Attr | Nodeish, ...childNodes: Nodeish[]) => - h(elem, props, ...childNodes), - ) as { - [Index in keyof Elems]: hElement< - // @ts-ignore TypeScript pls - Elems[Index] - >; +function getHElement(elem: Elem): hElement { + return function hElement(props?: Attr | Nodeish, ...childNodes: Nodeish[]) { + return h(elem, props, ...childNodes); }; -}; +} + +export type ElementsToHElements = { + [Index in keyof Elements]: hElement< + // @ts-ignore TypeScript pls + Elements[Index] + >; +} & { length: Elements["length"] }; + +function mapElements(...elements: Elements) { + return elements.map(getHElement) as ElementsToHElements; +} -export const elements = new Proxy(_elements, { - get(_: unknown, elem: E): hElement { - return (props?: Attr | Nodeish, ...childNodes: Nodeish[]) => - h(elem, props, ...childNodes); +export const elements = new Proxy(mapElements, { + get(_: unknown, element: E): hElement { + return getHElement(element); }, -}) as typeof _elements & { [k in Exclude]: hElement }; +}) as typeof mapElements & { [k in Exclude]: hElement }; export function trust(html: string) { return new HTMLNode(html); From 1393e0b23350cbecf6c2e6f6f405bac777b22419 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Wed, 23 Jun 2021 09:02:45 +0530 Subject: [PATCH 014/254] (feat) cache hElement to prevent a memory leak Signed-off-by: Muthu Kumar --- src/Node.ts | 16 ++++++++++++---- test.ts | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/Node.ts b/src/Node.ts index 4b207b5..9f50db2 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -74,10 +74,18 @@ export type hElement = ((...childNodes: Nodeish[]) => Node) & ((props: Attr, ...childNodes: Nodeish[]) => Node); -function getHElement(elem: Elem): hElement { - return function hElement(props?: Attr | Nodeish, ...childNodes: Nodeish[]) { - return h(elem, props, ...childNodes); - }; +const hElementCache = new Map(); + +function getHElement(element: Elem): hElement { + const fromCache = hElementCache.get(element); + if (fromCache) return fromCache as hElement; + + function hElement(props?: Attr | Nodeish, ...childNodes: Nodeish[]) { + return h(element, props, ...childNodes); + } + + hElementCache.set(element, hElement); + return hElement; } export type ElementsToHElements = { diff --git a/test.ts b/test.ts index e0bd123..a72fe6f 100644 --- a/test.ts +++ b/test.ts @@ -55,6 +55,26 @@ Deno.test({ }, }); +Deno.test({ + name: "elements() - elements[] equality", + fn: () => { + const { div, p } = elements; + const { div: div2, p: p2 } = elements; + + const [div3, p3] = elements("div", "p"); + const [div4, p4] = elements("div", "p"); + + assertEquals(div, div2); + assertEquals(p, p2); + + assertEquals(div, div3); + assertEquals(p, p3); + + assertEquals(div, div4); + assertEquals(p, p4); + }, +}); + Deno.test({ name: "renderHTML with custom element", fn: () => { From fbc4ed5478827bc1c5c8225c6ba82cf219897b1b Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Wed, 23 Jun 2021 09:09:28 +0530 Subject: [PATCH 015/254] (refactor) hElement -> hElement.ts Signed-off-by: Muthu Kumar --- mod.ts | 1 + src/Node.ts | 39 +-------------------------------------- src/hElement.ts | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 38 deletions(-) create mode 100644 src/hElement.ts diff --git a/mod.ts b/mod.ts index 31037b1..a52e05c 100644 --- a/mod.ts +++ b/mod.ts @@ -1,4 +1,5 @@ export * from "./src/elements.ts"; export * from "./src/Node.ts"; +export * from "./src/hElement.ts"; export * from "./src/parse.ts"; export * from "./src/render.ts"; diff --git a/src/Node.ts b/src/Node.ts index 9f50db2..160b2df 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -1,4 +1,4 @@ -import { Element, CustomTag } from "./elements.ts"; +import { Element } from "./elements.ts"; import { Falsy, isFalsy } from "./util.ts"; export type Attr = Record; @@ -68,43 +68,6 @@ export function h( ); } -export type hElement = - // - ((props?: Attr) => Node) & - ((...childNodes: Nodeish[]) => Node) & - ((props: Attr, ...childNodes: Nodeish[]) => Node); - -const hElementCache = new Map(); - -function getHElement(element: Elem): hElement { - const fromCache = hElementCache.get(element); - if (fromCache) return fromCache as hElement; - - function hElement(props?: Attr | Nodeish, ...childNodes: Nodeish[]) { - return h(element, props, ...childNodes); - } - - hElementCache.set(element, hElement); - return hElement; -} - -export type ElementsToHElements = { - [Index in keyof Elements]: hElement< - // @ts-ignore TypeScript pls - Elements[Index] - >; -} & { length: Elements["length"] }; - -function mapElements(...elements: Elements) { - return elements.map(getHElement) as ElementsToHElements; -} - -export const elements = new Proxy(mapElements, { - get(_: unknown, element: E): hElement { - return getHElement(element); - }, -}) as typeof mapElements & { [k in Exclude]: hElement }; - export function trust(html: string) { return new HTMLNode(html); } diff --git a/src/hElement.ts b/src/hElement.ts new file mode 100644 index 0000000..b5985b2 --- /dev/null +++ b/src/hElement.ts @@ -0,0 +1,39 @@ +import { Element, CustomTag } from "./elements.ts"; +import { Nodeish, Attr, Node, h } from "./Node.ts"; + +export type hElement = + // + ((props?: Attr) => Node) & + ((...childNodes: Nodeish[]) => Node) & + ((props: Attr, ...childNodes: Nodeish[]) => Node); + +const hElementCache = new Map(); + +function getHElement(element: Elem): hElement { + const fromCache = hElementCache.get(element); + if (fromCache) return fromCache as hElement; + + function hElement(props?: Attr | Nodeish, ...childNodes: Nodeish[]) { + return h(element, props, ...childNodes); + } + + hElementCache.set(element, hElement); + return hElement; +} + +export type ElementsToHElements = { + [Index in keyof Elements]: hElement< + // @ts-ignore TypeScript pls + Elements[Index] + >; +} & { length: Elements["length"] }; + +function mapElements(...elements: Elements) { + return elements.map(getHElement) as ElementsToHElements; +} + +export const elements = new Proxy(mapElements, { + get(_: unknown, element: E): hElement { + return getHElement(element); + }, +}) as typeof mapElements & { [k in Exclude]: hElement }; From 610193580f041310636a309a6f3de02a26ab777a Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Wed, 23 Jun 2021 14:37:10 +0530 Subject: [PATCH 016/254] (doc) fix example Signed-off-by: Muthu Kumar --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 393850f..5a7ab92 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Hyperactive is a suite of tools to build smart webapps. As of 1.0, only server-s ```TypeScript import { elements, renderHTML } from "https://deno.land/x/hyperactive/mod.ts"; -const [ div, p, h1 ] = elements("div", "p", "h1"); +const { div, p, h1 } = elements; assertEquals( renderHTML( From ac2ea83b60f0a8d1dbd90aceecc2dae4622fd7c7 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Thu, 24 Jun 2021 01:41:59 +0530 Subject: [PATCH 017/254] (feat) simple renderDOM implementation Signed-off-by: Muthu Kumar --- .gitignore | 1 + browser-test/index.html | 14 +++++++++++ src/render.ts | 51 +++++++++++++++++++++++++++++++++++++++-- src/util.ts | 9 ++++++++ test.browser.ts | 11 +++++++++ 5 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 browser-test/index.html create mode 100644 test.browser.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4bb0cfb --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +browser-test/test.browser.js \ No newline at end of file diff --git a/browser-test/index.html b/browser-test/index.html new file mode 100644 index 0000000..0c6fbd0 --- /dev/null +++ b/browser-test/index.html @@ -0,0 +1,14 @@ + + + + + Hyperactive! + + + + + +
+ + + diff --git a/src/render.ts b/src/render.ts index 106cf23..7d65f4c 100644 --- a/src/render.ts +++ b/src/render.ts @@ -1,5 +1,8 @@ -import { Nodeish, HTMLNode } from "./Node.ts"; -import { isFalsy, escapeHTML } from "./util.ts"; +/// +/// + +import { Node, Nodeish, HTMLNode } from "./Node.ts"; +import { Falsy, isFalsy, escapeHTML, guessEnv } from "./util.ts"; export function renderHTML(node: Nodeish) { if (isFalsy(node)) return ""; @@ -21,3 +24,47 @@ export function renderHTML(node: Nodeish) { return stringified; } + +type NodeishtoDOM = N extends Falsy + ? "" + : N extends string + ? string + : N extends HTMLNode + ? { innerHTML: string } + : HTMLElement; + +const toDOM = function toDOM(node: N) { + if (isFalsy(node)) return ""; + if (typeof node === "string") return escapeHTML(node); + if (node instanceof HTMLNode) return { innerHTML: node.htmlString }; + + const el = document.createElement(node.tag); + + for (const attr in node.attrs) { + el.setAttribute(attr, node.attrs[attr]); + } + + for (const child of node.children) { + const childNode = toDOM(child); + if (typeof childNode !== "string" && "innerHTML" in childNode) + el.insertAdjacentHTML("beforeend", childNode.innerHTML); + else el.append(childNode); + } + + return el; +} as (node: N) => NodeishtoDOM; + +export function renderDOM< + HyNode extends Node | string, + RootNode extends HTMLElement, +>(rootNode: RootNode, hyNode: HyNode) { + const env = guessEnv(); + if (env !== "browser") + throw new Error( + `renderDOM is meant to be used in the browser.` + + ` Found: '${env || "unknown"}'`, + ); + + const domNode = toDOM(hyNode); + return rootNode.append(domNode); +} diff --git a/src/util.ts b/src/util.ts index 59386f6..c330f12 100644 --- a/src/util.ts +++ b/src/util.ts @@ -14,3 +14,12 @@ export type Falsy = false | "" | 0 | 0n | undefined | null; export const Falsy = new Set([false, "", 0, 0n, undefined, null]); // deno-lint-ignore no-explicit-any export const isFalsy = (n: any): n is Falsy => Falsy.has(n); + +export const guessEnv = () => { + if (typeof window === "undefined") { + // @ts-ignore process is a node global API + if (typeof process === "undefined") return "node"; + else return undefined; + } else if (typeof window.Deno !== "undefined") return "deno"; + else return "browser"; +}; diff --git a/test.browser.ts b/test.browser.ts new file mode 100644 index 0000000..6b39d92 --- /dev/null +++ b/test.browser.ts @@ -0,0 +1,11 @@ +/// +/// + +import { elements, renderDOM } from "./mod.ts"; + +const { div, p } = elements; + +renderDOM( + document.getElementById("root")!, + div({ class: "container" }, p("Hello world")), +); From b8d6823075eabebf2a7480b39caed90ab9cd1dae Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Thu, 24 Jun 2021 03:32:22 +0530 Subject: [PATCH 018/254] (feat) experimental State.simple implementation Signed-off-by: Muthu Kumar --- mod.ts | 1 + src/Node.ts | 9 +++++--- src/State.ts | 51 +++++++++++++++++++++++++++++++++++++++++++ src/render.ts | 57 ++++++++++++++++++++++++++++++++++++++----------- test.browser.ts | 18 +++++++++++++--- 5 files changed, 117 insertions(+), 19 deletions(-) create mode 100644 src/State.ts diff --git a/mod.ts b/mod.ts index a52e05c..58206ee 100644 --- a/mod.ts +++ b/mod.ts @@ -1,5 +1,6 @@ export * from "./src/elements.ts"; export * from "./src/Node.ts"; +export * from "./src/State.ts"; export * from "./src/hElement.ts"; export * from "./src/parse.ts"; export * from "./src/render.ts"; diff --git a/src/Node.ts b/src/Node.ts index 160b2df..b0ff5c6 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -1,5 +1,6 @@ import { Element } from "./elements.ts"; import { Falsy, isFalsy } from "./util.ts"; +import { SimpleState, SimpleStateRO, isState } from "./State.ts"; export type Attr = Record; @@ -21,7 +22,9 @@ export type Nodeish = | Node | TextNode | HTMLNode - | Falsy; + | Falsy + | SimpleState | TextNode | HTMLNode | Falsy> + | SimpleStateRO | TextNode | HTMLNode | Falsy>; // deno-lint-ignore no-explicit-any export const isNode = (n: any): n is Node | HTMLNode | TextNode => @@ -55,7 +58,7 @@ export function h( ...childNodes: Nodeish[] ): Node { const [attrs, children] = - isNode(props) || isFalsy(props) + isNode(props) || isFalsy(props) || isState(props) ? [{}, [props, ...childNodes]] : [props || {}, childNodes || []]; @@ -64,7 +67,7 @@ export function h( attrs, children // filter falsy nodes - .filter((child): child is Node => (child ? true : false)), + .filter((child): child is Node => Boolean(child)), ); } diff --git a/src/State.ts b/src/State.ts new file mode 100644 index 0000000..338416c --- /dev/null +++ b/src/State.ts @@ -0,0 +1,51 @@ +export const STATE = Symbol("@hyperactive/state"); + +export type Subscriber = (val: T) => void; + +export type SimpleStateRO = { + init: T; + subscribe: (f: Subscriber) => void; + map: U>( + f: Mapper, + ) => ReturnType["readonly"]>; + [STATE]: true; +}; + +export type SimpleState = SimpleStateRO & { + publish: (next: T) => void; + readonly: () => SimpleStateRO; +}; + +// deno-lint-ignore no-explicit-any +export const isState = (n: any): n is SimpleState | SimpleStateRO => + Boolean(n[STATE]); + +const SimpleState = (init: T): SimpleState => { + const subscribers: Subscriber[] = []; + + const publish: SimpleState["publish"] = next => + Promise.resolve(next).then(val => + subscribers.forEach(subscriber => subscriber(val)), + ); + + const subscribe: SimpleState["subscribe"] = f => subscribers.push(f); + + const map: SimpleState["map"] = f => { + const s = SimpleState>( + f(init) as ReturnType, + ); + subscribe(value => s.publish(f(value) as ReturnType)); + return s.readonly(); + }; + + const readonly: SimpleState["readonly"] = () => ({ + init, + subscribe, + map, + [STATE]: true, + }); + + return { init, publish, subscribe, map, readonly, [STATE]: true }; +}; + +export const State = { simple: SimpleState }; diff --git a/src/render.ts b/src/render.ts index 7d65f4c..0ff25cc 100644 --- a/src/render.ts +++ b/src/render.ts @@ -2,12 +2,14 @@ /// import { Node, Nodeish, HTMLNode } from "./Node.ts"; +import { isState } from "./State.ts"; import { Falsy, isFalsy, escapeHTML, guessEnv } from "./util.ts"; -export function renderHTML(node: Nodeish) { +export function renderHTML(node: Nodeish): string { if (isFalsy(node)) return ""; if (typeof node === "string") return escapeHTML(node); if (node instanceof HTMLNode) return node.htmlString; + if (isState(node)) return renderHTML(node.init); let stringified = "<" + node.tag; @@ -28,15 +30,45 @@ export function renderHTML(node: Nodeish) { type NodeishtoDOM = N extends Falsy ? "" : N extends string - ? string + ? ChildNode | "" : N extends HTMLNode - ? { innerHTML: string } + ? ChildNode | "" : HTMLElement; -const toDOM = function toDOM(node: N) { +function htmlStringToElement(html: string) { + var template = document.createElement("template"); + html = html.trim(); // Never return a text node of whitespace as the result + template.innerHTML = html; + + return template.content.firstChild || ""; +} + +const toDOM = function toDOM( + node: N, + parent: HTMLElement, + opts: { emptyTextNodes?: boolean } = {}, +): "" | ChildNode | HTMLElement { + if (typeof node === "string" && (node !== "" || opts.emptyTextNodes)) + return document.createTextNode(escapeHTML(node)); if (isFalsy(node)) return ""; - if (typeof node === "string") return escapeHTML(node); - if (node instanceof HTMLNode) return { innerHTML: node.htmlString }; + if (node instanceof HTMLNode) return htmlStringToElement(node.htmlString); + if (isState(node)) { + let stateNode = toDOM(node.init, parent, { emptyTextNodes: true }); + + node.subscribe(val => { + const newStateNode = toDOM(val, parent, { emptyTextNodes: true }); + + if (newStateNode === "" || stateNode === "") { + // + } else { + parent.replaceChild(newStateNode, stateNode); + stateNode = newStateNode; + } + return newStateNode; + }); + + return stateNode; + } const el = document.createElement(node.tag); @@ -45,14 +77,14 @@ const toDOM = function toDOM(node: N) { } for (const child of node.children) { - const childNode = toDOM(child); - if (typeof childNode !== "string" && "innerHTML" in childNode) - el.insertAdjacentHTML("beforeend", childNode.innerHTML); - else el.append(childNode); + const childNode = toDOM(child, el); + if (childNode === "") { + // + } else el.append(childNode); } return el; -} as (node: N) => NodeishtoDOM; +} as (node: N, parent: HTMLElement) => NodeishtoDOM; export function renderDOM< HyNode extends Node | string, @@ -65,6 +97,5 @@ export function renderDOM< ` Found: '${env || "unknown"}'`, ); - const domNode = toDOM(hyNode); - return rootNode.append(domNode); + return rootNode.append(toDOM(hyNode, rootNode)); } diff --git a/test.browser.ts b/test.browser.ts index 6b39d92..59da0b0 100644 --- a/test.browser.ts +++ b/test.browser.ts @@ -1,11 +1,23 @@ /// /// -import { elements, renderDOM } from "./mod.ts"; +import { elements, renderDOM, State } from "./mod.ts"; -const { div, p } = elements; +const { div, input, p } = elements; + +const state = State.simple("hello"); + +setTimeout(() => { + document.querySelector("#input-el")?.addEventListener("input", e => { + state.publish((e.target as unknown as { value: string }).value); + }); +}, 1000); renderDOM( document.getElementById("root")!, - div({ class: "container" }, p("Hello world")), + div( + { class: "container" }, + input({ id: "input-el", value: state.init }), + p(state), + ), ); From 8a259d2b46d03abda8f06af0e8fc1a3fe8dafd6d Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Thu, 24 Jun 2021 03:57:00 +0530 Subject: [PATCH 019/254] (misc) test with state.map() Signed-off-by: Muthu Kumar --- src/hElement.ts | 2 +- test.browser.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/hElement.ts b/src/hElement.ts index b5985b2..a50d4f2 100644 --- a/src/hElement.ts +++ b/src/hElement.ts @@ -3,7 +3,7 @@ import { Nodeish, Attr, Node, h } from "./Node.ts"; export type hElement = // - ((props?: Attr) => Node) & + ((props?: Attr | Nodeish) => Node) & ((...childNodes: Nodeish[]) => Node) & ((props: Attr, ...childNodes: Nodeish[]) => Node); diff --git a/test.browser.ts b/test.browser.ts index 59da0b0..ba0d156 100644 --- a/test.browser.ts +++ b/test.browser.ts @@ -3,9 +3,9 @@ import { elements, renderDOM, State } from "./mod.ts"; -const { div, input, p } = elements; +const { div, input, h3, p } = elements; -const state = State.simple("hello"); +const state = State.simple("1"); setTimeout(() => { document.querySelector("#input-el")?.addEventListener("input", e => { @@ -17,7 +17,8 @@ renderDOM( document.getElementById("root")!, div( { class: "container" }, + h3("Enter a number, it should double below"), input({ id: "input-el", value: state.init }), - p(state), + p(state.map(v => String(parseFloat(v) * 2))), ), ); From 25bda2e234eeacc2cac416aed3ad5698714971b8 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Sat, 26 Jun 2021 21:24:35 +0530 Subject: [PATCH 020/254] (feat) generate elements.ts from MDN Signed-off-by: Muthu Kumar --- scripts/generateElements.ts | 85 +++++++++++++++++++++++++++++++++++++ src/Node.ts | 6 ++- src/elements.deprecated.ts | 32 ++++++++++++++ src/elements.ts | 6 ++- src/hElement.ts | 3 +- 5 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 scripts/generateElements.ts create mode 100644 src/elements.deprecated.ts diff --git a/scripts/generateElements.ts b/scripts/generateElements.ts new file mode 100644 index 0000000..35587c0 --- /dev/null +++ b/scripts/generateElements.ts @@ -0,0 +1,85 @@ +import config from "./config.ts"; + +const rootUrl = "https://api.github.com/repos/mdn/content/contents/"; + +const elementsUrl = rootUrl + "files/en-us/web/html/element"; + +const opts = { + headers: new Headers({ + Accept: "application/vnd.github.v3+json", + Authorization: `Token ${config.apiToken}`, + }), +}; + +const baseType = + "export type CustomTag = `${string}-${string}`;\n\n" + + `export type Element = + | CustomTag`; + +const constructTypes = (elements: { title: string }[]) => { + return ( + baseType + + "\n\t| " + + elements + .sort((a, b) => a.title.localeCompare(b.title)) + .map(({ title }) => `"${title}"`) + .join("\n\t| ") + + ";\n" + ); +}; + +fetch(elementsUrl, opts) + .then(res => res.json()) + .then((elements: { name: string; path: string }[]) => + Promise.all( + elements + .filter(e => e.name !== "index.html") + .map(element => + fetch(rootUrl + element.path + "/index.html", opts) + .then(res => res.json()) + .then((file: { content: string }) => atob(file.content)) + .then((html: string) => { + const [line1, ...rest] = html + .split("\n") + .reduce( + (acc, curr, i) => { + if (!acc.seen) acc.arr.push(curr); + if (i !== 0 && curr === "---") + acc.seen = true; + + return acc; + }, + { seen: false, arr: [] as string[] }, + ) + .arr.slice(1, -1); + + const title = line1 + .replace(/^title: '?.*$/, ""); + + const deprecated = rest.some(line => + line.includes("Deprecated"), + ); + + return { title, deprecated }; + }), + ), + ), + ) + .then(elements => { + const active = elements + .filter(e => !e.deprecated) + .concat( + ["h2", "h3", "h4", "h5", "h6", "svg", "math"].map(title => ({ + title, + deprecated: false, + })), + ); + const deprecated = elements.filter(e => e.deprecated); + + Deno.writeTextFileSync("./src/elements.ts", constructTypes(active)); + Deno.writeTextFileSync( + "./src/elements.deprecated.ts", + constructTypes(deprecated), + ); + }); diff --git a/src/Node.ts b/src/Node.ts index b0ff5c6..bbcaf7c 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -1,7 +1,11 @@ -import { Element } from "./elements.ts"; +import { Element as Active } from "./elements.ts"; +import { Element as Deprecated } from "./elements.deprecated.ts"; import { Falsy, isFalsy } from "./util.ts"; import { SimpleState, SimpleStateRO, isState } from "./State.ts"; +export type Element = Active | Deprecated; +export type { CustomTag } from "./elements.ts"; + export type Attr = Record; export type TextNode = string; diff --git a/src/elements.deprecated.ts b/src/elements.deprecated.ts new file mode 100644 index 0000000..928f9c3 --- /dev/null +++ b/src/elements.deprecated.ts @@ -0,0 +1,32 @@ +export type CustomTag = `${string}-${string}`; + +export type Element = + | CustomTag + | "acronym" + | "applet" + | "basefont" + | "bgsound" + | "big" + | "blink" + | "center" + | "content" + | "dir" + | "font" + | "frame" + | "frameset" + | "hgroup" + | "image" + | "keygen" + | "marquee" + | "menuitem" + | "nobr" + | "noembed" + | "noframes" + | "plaintext" + | "rb" + | "rtc" + | "shadow" + | "spacer" + | "strike" + | "tt" + | "xmp"; diff --git a/src/elements.ts b/src/elements.ts index 1700cb1..8f0f85b 100644 --- a/src/elements.ts +++ b/src/elements.ts @@ -63,6 +63,8 @@ export type Element = | "main" | "map" | "mark" + | "math" + | "menu" | "meta" | "meter" | "nav" @@ -75,13 +77,12 @@ export type Element = | "p" | "param" | "picture" + | "portal" | "pre" | "progress" | "q" - | "rb" | "rp" | "rt" - | "rtc" | "ruby" | "s" | "samp" @@ -97,6 +98,7 @@ export type Element = | "sub" | "summary" | "sup" + | "svg" | "table" | "tbody" | "td" diff --git a/src/hElement.ts b/src/hElement.ts index a50d4f2..6435626 100644 --- a/src/hElement.ts +++ b/src/hElement.ts @@ -1,5 +1,4 @@ -import { Element, CustomTag } from "./elements.ts"; -import { Nodeish, Attr, Node, h } from "./Node.ts"; +import { Element, CustomTag, Nodeish, Attr, Node, h } from "./Node.ts"; export type hElement = // From 63ba8317d193621e51331fe0509772f4c3a7831b Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Tue, 29 Jun 2021 00:43:52 +0530 Subject: [PATCH 021/254] (feat) generate attribute autocompletion Signed-off-by: Muthu Kumar --- scripts/generateAttributes.ts | 36 +++++++++ src/Node.ts | 3 +- src/attrs.ts | 136 ++++++++++++++++++++++++++++++++++ src/hElement.ts | 6 +- 4 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 scripts/generateAttributes.ts create mode 100644 src/attrs.ts diff --git a/scripts/generateAttributes.ts b/scripts/generateAttributes.ts new file mode 100644 index 0000000..b1ab89e --- /dev/null +++ b/scripts/generateAttributes.ts @@ -0,0 +1,36 @@ +import { DOMParser } from "https://deno.land/x/deno_dom@v0.1.12-alpha/deno-dom-wasm.ts"; + +const html = await fetch( + "https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes", +).then(res => res.text()); + +const document = new DOMParser().parseFromString(html, "text/html"); + +const attrs = [ + ...document?.querySelector("article table.standard-table tbody") + ?.childNodes!, +] + .filter(tr => tr.nodeName === "TR") + // .filter((_, i) => i <= 2) // limit to 3 elements + .map(tr => [...tr.childNodes!].map(each => each.textContent)) + .map(([, attr, , elements]) => ({ + attr: attr.trim(), + elements: elements.replaceAll(/<|>/g, "").split(/,\s+/), + })) + .filter(each => each.attr !== "data-*"); + +const prelude = "type DataAttr = `data-${string}`;\n\n"; + +const prologue = ` +export type Attr = { [data in DataAttr]?: string } & Partial>; +`; + +// TODO(mkr): group by element +Deno.writeTextFileSync( + "./src/attrs.ts", + prelude + + "type AttrKeys =\n\t| " + + attrs.map(each => `"${each.attr}"`).join("\n\t| ") + + ";\n" + + prologue, +); diff --git a/src/Node.ts b/src/Node.ts index bbcaf7c..ba25aca 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -1,12 +1,13 @@ import { Element as Active } from "./elements.ts"; import { Element as Deprecated } from "./elements.deprecated.ts"; +import { Attr } from "./attrs.ts"; import { Falsy, isFalsy } from "./util.ts"; import { SimpleState, SimpleStateRO, isState } from "./State.ts"; export type Element = Active | Deprecated; export type { CustomTag } from "./elements.ts"; -export type Attr = Record; +export type { Attr }; export type TextNode = string; diff --git a/src/attrs.ts b/src/attrs.ts new file mode 100644 index 0000000..c534a97 --- /dev/null +++ b/src/attrs.ts @@ -0,0 +1,136 @@ +type DataAttr = `data-${string}`; + +type AttrKeys = + | "accept" + | "accept-charset" + | "accesskey" + | "action" + | "align" + | "allow" + | "alt" + | "async" + | "autocapitalize" + | "autocomplete" + | "autofocus" + | "autoplay" + | "background" + | "bgcolor" + | "border" + | "buffered" + | "capture" + | "challenge" + | "charset" + | "checked" + | "cite" + | "class" + | "code" + | "codebase" + | "color" + | "cols" + | "colspan" + | "content" + | "contenteditable" + | "contextmenu" + | "controls" + | "coords" + | "crossorigin" + | "csp" + | "data" + | "datetime" + | "decoding" + | "default" + | "defer" + | "dir" + | "dirname" + | "disabled" + | "download" + | "draggable" + | "enctype" + | "enterkeyhint" + | "for" + | "form" + | "formaction" + | "formenctype" + | "formmethod" + | "formnovalidate" + | "formtarget" + | "headers" + | "height" + | "hidden" + | "high" + | "href" + | "hreflang" + | "http-equiv" + | "icon" + | "id" + | "importance" + | "integrity" + | "intrinsicsize" + | "inputmode" + | "ismap" + | "itemprop" + | "keytype" + | "kind" + | "label" + | "lang" + | "language" + | "loading" + | "list" + | "loop" + | "low" + | "manifest" + | "max" + | "maxlength" + | "minlength" + | "media" + | "method" + | "min" + | "multiple" + | "muted" + | "name" + | "novalidate" + | "open" + | "optimum" + | "pattern" + | "ping" + | "placeholder" + | "poster" + | "preload" + | "radiogroup" + | "readonly" + | "referrerpolicy" + | "rel" + | "required" + | "reversed" + | "rows" + | "rowspan" + | "sandbox" + | "scope" + | "scoped" + | "selected" + | "shape" + | "size" + | "sizes" + | "slot" + | "span" + | "spellcheck" + | "src" + | "srcdoc" + | "srclang" + | "srcset" + | "start" + | "step" + | "style" + | "summary" + | "tabindex" + | "target" + | "title" + | "translate" + | "type" + | "usemap" + | "value" + | "width" + | "wrap"; + +export type Attr = { [data in DataAttr]?: string } & + Partial>; diff --git a/src/hElement.ts b/src/hElement.ts index 6435626..0064ff0 100644 --- a/src/hElement.ts +++ b/src/hElement.ts @@ -1,10 +1,10 @@ import { Element, CustomTag, Nodeish, Attr, Node, h } from "./Node.ts"; -export type hElement = +export type hElement = // - ((props?: Attr | Nodeish) => Node) & + ((props?: Attrs | Nodeish) => Node) & ((...childNodes: Nodeish[]) => Node) & - ((props: Attr, ...childNodes: Nodeish[]) => Node); + ((props: Attrs, ...childNodes: Nodeish[]) => Node); const hElementCache = new Map(); From 678a7e592a52c0f6e1cb69a03e2d28fd103c5095 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Tue, 29 Jun 2021 00:44:28 +0530 Subject: [PATCH 022/254] (fix) minor Signed-off-by: Muthu Kumar --- src/State.ts | 8 ++++---- test.browser.ts | 14 ++++++-------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/State.ts b/src/State.ts index 338416c..9f35409 100644 --- a/src/State.ts +++ b/src/State.ts @@ -5,7 +5,7 @@ export type Subscriber = (val: T) => void; export type SimpleStateRO = { init: T; subscribe: (f: Subscriber) => void; - map: U>( + transform: U>( f: Mapper, ) => ReturnType["readonly"]>; [STATE]: true; @@ -30,7 +30,7 @@ const SimpleState = (init: T): SimpleState => { const subscribe: SimpleState["subscribe"] = f => subscribers.push(f); - const map: SimpleState["map"] = f => { + const transform: SimpleState["transform"] = f => { const s = SimpleState>( f(init) as ReturnType, ); @@ -41,11 +41,11 @@ const SimpleState = (init: T): SimpleState => { const readonly: SimpleState["readonly"] = () => ({ init, subscribe, - map, + transform, [STATE]: true, }); - return { init, publish, subscribe, map, readonly, [STATE]: true }; + return { init, publish, subscribe, transform, readonly, [STATE]: true }; }; export const State = { simple: SimpleState }; diff --git a/test.browser.ts b/test.browser.ts index ba0d156..f30b7ea 100644 --- a/test.browser.ts +++ b/test.browser.ts @@ -3,22 +3,20 @@ import { elements, renderDOM, State } from "./mod.ts"; -const { div, input, h3, p } = elements; +const { div, input, h3, p, span } = elements; const state = State.simple("1"); -setTimeout(() => { - document.querySelector("#input-el")?.addEventListener("input", e => { - state.publish((e.target as unknown as { value: string }).value); - }); -}, 1000); - renderDOM( document.getElementById("root")!, div( { class: "container" }, h3("Enter a number, it should double below"), input({ id: "input-el", value: state.init }), - p(state.map(v => String(parseFloat(v) * 2))), + p(state.transform(v => span(String(parseFloat(v) * 2)))), ), ); + +document.querySelector("#input-el")?.addEventListener("input", e => { + state.publish((e.target as unknown as { value: string }).value); +}); From 9e8fc04353aa42e0f3c90b1e357c1b097df82966 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Tue, 29 Jun 2021 01:18:35 +0530 Subject: [PATCH 023/254] (fix) comment data-* attributes awaiting TS 4.4 Signed-off-by: Muthu Kumar --- scripts/generateAttributes.ts | 5 ++++- src/attrs.ts | 4 +++- src/render.ts | 5 +++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/scripts/generateAttributes.ts b/scripts/generateAttributes.ts index b1ab89e..e22cd8d 100644 --- a/scripts/generateAttributes.ts +++ b/scripts/generateAttributes.ts @@ -22,7 +22,10 @@ const attrs = [ const prelude = "type DataAttr = `data-${string}`;\n\n"; const prologue = ` -export type Attr = { [data in DataAttr]?: string } & Partial>; +export type Attr = + // TODO(mkr): will work in TS 4.4 + // { [data in DataAttr]?: string } & + Partial>; `; // TODO(mkr): group by element diff --git a/src/attrs.ts b/src/attrs.ts index c534a97..6b4cb97 100644 --- a/src/attrs.ts +++ b/src/attrs.ts @@ -132,5 +132,7 @@ type AttrKeys = | "width" | "wrap"; -export type Attr = { [data in DataAttr]?: string } & +export type Attr = + // TODO(mkr): will work in TS 4.4 + // { [data in DataAttr]?: string } & Partial>; diff --git a/src/render.ts b/src/render.ts index 0ff25cc..20942ef 100644 --- a/src/render.ts +++ b/src/render.ts @@ -1,7 +1,7 @@ /// /// -import { Node, Nodeish, HTMLNode } from "./Node.ts"; +import { Node, Nodeish, HTMLNode, Attr } from "./Node.ts"; import { isState } from "./State.ts"; import { Falsy, isFalsy, escapeHTML, guessEnv } from "./util.ts"; @@ -73,7 +73,8 @@ const toDOM = function toDOM( const el = document.createElement(node.tag); for (const attr in node.attrs) { - el.setAttribute(attr, node.attrs[attr]); + const value = node.attrs[attr as keyof Attr]; + if (value) el.setAttribute(attr, value); } for (const child of node.children) { From 2584900694bfab724045192b81099adb248f7867 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Tue, 29 Jun 2021 01:21:59 +0530 Subject: [PATCH 024/254] (fix) duplicate Element export Signed-off-by: Muthu Kumar --- mod.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mod.ts b/mod.ts index 58206ee..be88cf3 100644 --- a/mod.ts +++ b/mod.ts @@ -1,4 +1,5 @@ -export * from "./src/elements.ts"; +export type { Element as SupportedElements } from "./src/elements.ts"; +export type { Element as DeprecatedElements } from "./src/elements.deprecated.ts"; export * from "./src/Node.ts"; export * from "./src/State.ts"; export * from "./src/hElement.ts"; From 537edcc05950bd94b3a1254d4301ff2c08c234cb Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Tue, 29 Jun 2021 04:06:09 +0530 Subject: [PATCH 025/254] (feat) element-sensitive attribute types Signed-off-by: Muthu Kumar --- mod.ts | 10 +- scripts/generateAttributes.ts | 93 +++++++--- scripts/generateElements.ts | 8 - src/attributes.ts | 319 ++++++++++++++++++++++++++++++++++ src/attrs.ts | 138 --------------- src/elements.deprecated.ts | 32 ---- src/hElement.ts | 38 ---- src/h_element.ts | 54 ++++++ src/{Node.ts => node.ts} | 16 +- src/render.ts | 5 +- src/{State.ts => state.ts} | 0 11 files changed, 451 insertions(+), 262 deletions(-) create mode 100644 src/attributes.ts delete mode 100644 src/attrs.ts delete mode 100644 src/elements.deprecated.ts delete mode 100644 src/hElement.ts create mode 100644 src/h_element.ts rename src/{Node.ts => node.ts} (76%) rename src/{State.ts => state.ts} (100%) diff --git a/mod.ts b/mod.ts index be88cf3..6981e2f 100644 --- a/mod.ts +++ b/mod.ts @@ -1,7 +1,7 @@ -export type { Element as SupportedElements } from "./src/elements.ts"; -export type { Element as DeprecatedElements } from "./src/elements.deprecated.ts"; -export * from "./src/Node.ts"; -export * from "./src/State.ts"; -export * from "./src/hElement.ts"; +export * from "./src/elements.ts"; +export * from "./src/attributes.ts"; +export * from "./src/node.ts"; +export * from "./src/state.ts"; +export * from "./src/h_element.ts"; export * from "./src/parse.ts"; export * from "./src/render.ts"; diff --git a/scripts/generateAttributes.ts b/scripts/generateAttributes.ts index e22cd8d..f66c64f 100644 --- a/scripts/generateAttributes.ts +++ b/scripts/generateAttributes.ts @@ -6,34 +6,71 @@ const html = await fetch( const document = new DOMParser().parseFromString(html, "text/html"); -const attrs = [ - ...document?.querySelector("article table.standard-table tbody") - ?.childNodes!, -] - .filter(tr => tr.nodeName === "TR") - // .filter((_, i) => i <= 2) // limit to 3 elements - .map(tr => [...tr.childNodes!].map(each => each.textContent)) - .map(([, attr, , elements]) => ({ - attr: attr.trim(), - elements: elements.replaceAll(/<|>/g, "").split(/,\s+/), - })) - .filter(each => each.attr !== "data-*"); - -const prelude = "type DataAttr = `data-${string}`;\n\n"; - -const prologue = ` -export type Attr = +type Attribute = { attr: string; elements: string[] }; + +const groupByList = (xs: Attribute[]) => + xs.reduce((acc, curr) => { + for (const element of curr.elements) { + (acc[element] || (acc[element] = [])).push({ + attr: curr.attr, + type: "string", + }); + } + + return acc; + }, {} as Record); + +const { "Global attribute": globalAttr, ...elements } = groupByList( + [ + ...document?.querySelector("article table.standard-table tbody") + ?.childNodes!, + ] + .filter(tr => tr.nodeName === "TR") + .map(tr => [...tr.childNodes!].map(each => each.textContent)) + .map(([, attr, , elements]) => ({ + attr: attr.trim(), + elements: elements + .replaceAll(/<|>/g, "") + .split(/,\s+/) + .map(e => e.trim()), + })) + .filter(each => each.attr !== "data-*") + .sort((a, b) => a.attr.localeCompare(b.attr)), +); + +const elementToType = ( + el: string, + attrs: { attr: string; type: string }[], + { root }: { root?: boolean } = {}, +) => + `${el}${root ? " =" : ":"} Record<${attrs + .map(attr => `"${attr.attr}"`) + .join(" | ")}, string>;`; + +const globalTypes = elementToType("GlobalAttrs", globalAttr, { + root: true, +}); + +const elementTypes = Object.keys(elements) + .sort((a, b) => a.localeCompare(b)) + .map(element => elementToType(element, elements[element])) + .join("\n\t"); + +const types = `import { Element } from "./elements.ts"; + +type ${globalTypes} + +type ElementAttrs = { + ${elementTypes} + [k: string]: unknown; +} + +type DataAttr = ${"`data-${string}`"}; + +export type Attr = // TODO(mkr): will work in TS 4.4 - // { [data in DataAttr]?: string } & - Partial>; + // { [data in DataAttr]?: string } + Partial; `; -// TODO(mkr): group by element -Deno.writeTextFileSync( - "./src/attrs.ts", - prelude + - "type AttrKeys =\n\t| " + - attrs.map(each => `"${each.attr}"`).join("\n\t| ") + - ";\n" + - prologue, -); +Deno.writeTextFileSync("./src/attrs.ts", types); diff --git a/scripts/generateElements.ts b/scripts/generateElements.ts index 35587c0..e9f6e0c 100644 --- a/scripts/generateElements.ts +++ b/scripts/generateElements.ts @@ -1,5 +1,3 @@ -import config from "./config.ts"; - const rootUrl = "https://api.github.com/repos/mdn/content/contents/"; const elementsUrl = rootUrl + "files/en-us/web/html/element"; @@ -7,7 +5,6 @@ const elementsUrl = rootUrl + "files/en-us/web/html/element"; const opts = { headers: new Headers({ Accept: "application/vnd.github.v3+json", - Authorization: `Token ${config.apiToken}`, }), }; @@ -75,11 +72,6 @@ fetch(elementsUrl, opts) deprecated: false, })), ); - const deprecated = elements.filter(e => e.deprecated); Deno.writeTextFileSync("./src/elements.ts", constructTypes(active)); - Deno.writeTextFileSync( - "./src/elements.deprecated.ts", - constructTypes(deprecated), - ); }); diff --git a/src/attributes.ts b/src/attributes.ts new file mode 100644 index 0000000..87ba1c7 --- /dev/null +++ b/src/attributes.ts @@ -0,0 +1,319 @@ +import { Element } from "./elements.ts"; + +type Aria = `aria-${string}`; + +type GlobalAttrs = Record< + | "accesskey" + | "autocapitalize" + | "class" + | "contenteditable" + | "contextmenu" + | "dir" + | "draggable" + | "hidden" + | "id" + | "itemprop" + | "lang" + | "slot" + | "spellcheck" + | "style" + | "tabindex" + | "title" + | "translate", + string +>; + +type ElementAttrs = { + a: Record< + | "download" + | "href" + | "hreflang" + | "media" + | "ping" + | "referrerpolicy" + | "rel" + | "shape" + | "target", + string + >; + applet: Record<"align" | "alt" | "code" | "codebase", string>; + area: Record< + | "alt" + | "coords" + | "download" + | "href" + | "hreflang" + | "media" + | "ping" + | "referrerpolicy" + | "rel" + | "shape" + | "target", + string + >; + audio: Record< + | "autoplay" + | "buffered" + | "controls" + | "crossorigin" + | "loop" + | "muted" + | "preload" + | "src", + string + >; + base: Record<"href" | "target", string>; + basefont: Record<"color", string>; + bgsound: Record<"loop", string>; + blockquote: Record<"cite", string>; + body: Record<"background" | "bgcolor", string>; + button: Record< + | "autofocus" + | "disabled" + | "form" + | "formaction" + | "formenctype" + | "formmethod" + | "formnovalidate" + | "formtarget" + | "name" + | "type" + | "value", + string + >; + canvas: Record<"height" | "width", string>; + caption: Record<"align", string>; + col: Record<"align" | "bgcolor" | "span", string>; + colgroup: Record<"align" | "bgcolor" | "span", string>; + command: Record< + "checked" | "disabled" | "icon" | "radiogroup" | "type", + string + >; + contenteditable: Record<"enterkeyhint" | "inputmode", string>; + data: Record<"value", string>; + del: Record<"cite" | "datetime", string>; + details: Record<"open", string>; + embed: Record<"height" | "src" | "type" | "width", string>; + fieldset: Record<"disabled" | "form" | "name", string>; + font: Record<"color", string>; + form: Record< + | "accept" + | "accept-charset" + | "action" + | "autocomplete" + | "enctype" + | "method" + | "name" + | "novalidate" + | "target", + string + >; + hr: Record<"align" | "color", string>; + html: Record<"manifest", string>; + iframe: Record< + | "align" + | "allow" + | "csp" + | "height" + | "importance" + | "loading" + | "name" + | "referrerpolicy" + | "sandbox" + | "src" + | "srcdoc" + | "width", + string + >; + img: Record< + | "align" + | "alt" + | "border" + | "crossorigin" + | "decoding" + | "height" + | "importance" + | "intrinsicsize" + | "ismap" + | "loading" + | "referrerpolicy" + | "sizes" + | "src" + | "srcset" + | "usemap" + | "width", + string + >; + input: Record< + | "accept" + | "alt" + | "autocomplete" + | "autofocus" + | "capture" + | "checked" + | "dirname" + | "disabled" + | "form" + | "formaction" + | "formenctype" + | "formmethod" + | "formnovalidate" + | "formtarget" + | "height" + | "list" + | "max" + | "maxlength" + | "min" + | "minlength" + | "multiple" + | "name" + | "pattern" + | "placeholder" + | "readonly" + | "required" + | "size" + | "src" + | "step" + | "type" + | "usemap" + | "value" + | "width", + string + >; + ins: Record<"cite" | "datetime", string>; + keygen: Record< + "autofocus" | "challenge" | "disabled" | "form" | "keytype" | "name", + string + >; + label: Record<"for" | "form", string>; + li: Record<"value", string>; + link: Record< + | "crossorigin" + | "href" + | "hreflang" + | "importance" + | "integrity" + | "media" + | "referrerpolicy" + | "rel" + | "sizes", + string + >; + map: Record<"name", string>; + marquee: Record<"bgcolor" | "loop", string>; + menu: Record<"type", string>; + meta: Record<"charset" | "content" | "http-equiv" | "name", string>; + meter: Record< + "form" | "high" | "low" | "max" | "min" | "optimum" | "value", + string + >; + object: Record< + | "border" + | "data" + | "form" + | "height" + | "name" + | "type" + | "usemap" + | "width", + string + >; + ol: Record<"reversed" | "start", string>; + optgroup: Record<"disabled" | "label", string>; + option: Record<"disabled" | "label" | "selected" | "value", string>; + output: Record<"for" | "form" | "name", string>; + param: Record<"name" | "value", string>; + progress: Record<"form" | "max" | "value", string>; + q: Record<"cite", string>; + script: Record< + | "async" + | "charset" + | "crossorigin" + | "defer" + | "importance" + | "integrity" + | "language" + | "referrerpolicy" + | "src" + | "type", + string + >; + select: Record< + | "autocomplete" + | "autofocus" + | "disabled" + | "form" + | "multiple" + | "name" + | "required" + | "size", + string + >; + source: Record<"media" | "sizes" | "src" | "srcset" | "type", string>; + style: Record<"media" | "scoped" | "type", string>; + table: Record< + "align" | "background" | "bgcolor" | "border" | "summary", + string + >; + tbody: Record<"align" | "bgcolor", string>; + td: Record< + "align" | "background" | "bgcolor" | "colspan" | "headers" | "rowspan", + string + >; + textarea: Record< + | "autocomplete" + | "autofocus" + | "cols" + | "dirname" + | "disabled" + | "enterkeyhint" + | "form" + | "inputmode" + | "maxlength" + | "minlength" + | "name" + | "placeholder" + | "readonly" + | "required" + | "rows" + | "wrap", + string + >; + tfoot: Record<"align" | "bgcolor", string>; + th: Record< + | "align" + | "background" + | "bgcolor" + | "colspan" + | "headers" + | "rowspan" + | "scope", + string + >; + thead: Record<"align", string>; + time: Record<"datetime", string>; + tr: Record<"align" | "bgcolor", string>; + track: Record<"default" | "kind" | "label" | "src" | "srclang", string>; + video: Record< + | "autoplay" + | "buffered" + | "controls" + | "crossorigin" + | "height" + | "loop" + | "muted" + | "poster" + | "preload" + | "src" + | "width", + string + >; + [k: string]: unknown; +}; + +type DataAttr = `data-${string}`; + +export type Attr = + // TODO(mkr): will work in TS 4.4 + // { [data in DataAttr]?: string } + Partial; diff --git a/src/attrs.ts b/src/attrs.ts deleted file mode 100644 index 6b4cb97..0000000 --- a/src/attrs.ts +++ /dev/null @@ -1,138 +0,0 @@ -type DataAttr = `data-${string}`; - -type AttrKeys = - | "accept" - | "accept-charset" - | "accesskey" - | "action" - | "align" - | "allow" - | "alt" - | "async" - | "autocapitalize" - | "autocomplete" - | "autofocus" - | "autoplay" - | "background" - | "bgcolor" - | "border" - | "buffered" - | "capture" - | "challenge" - | "charset" - | "checked" - | "cite" - | "class" - | "code" - | "codebase" - | "color" - | "cols" - | "colspan" - | "content" - | "contenteditable" - | "contextmenu" - | "controls" - | "coords" - | "crossorigin" - | "csp" - | "data" - | "datetime" - | "decoding" - | "default" - | "defer" - | "dir" - | "dirname" - | "disabled" - | "download" - | "draggable" - | "enctype" - | "enterkeyhint" - | "for" - | "form" - | "formaction" - | "formenctype" - | "formmethod" - | "formnovalidate" - | "formtarget" - | "headers" - | "height" - | "hidden" - | "high" - | "href" - | "hreflang" - | "http-equiv" - | "icon" - | "id" - | "importance" - | "integrity" - | "intrinsicsize" - | "inputmode" - | "ismap" - | "itemprop" - | "keytype" - | "kind" - | "label" - | "lang" - | "language" - | "loading" - | "list" - | "loop" - | "low" - | "manifest" - | "max" - | "maxlength" - | "minlength" - | "media" - | "method" - | "min" - | "multiple" - | "muted" - | "name" - | "novalidate" - | "open" - | "optimum" - | "pattern" - | "ping" - | "placeholder" - | "poster" - | "preload" - | "radiogroup" - | "readonly" - | "referrerpolicy" - | "rel" - | "required" - | "reversed" - | "rows" - | "rowspan" - | "sandbox" - | "scope" - | "scoped" - | "selected" - | "shape" - | "size" - | "sizes" - | "slot" - | "span" - | "spellcheck" - | "src" - | "srcdoc" - | "srclang" - | "srcset" - | "start" - | "step" - | "style" - | "summary" - | "tabindex" - | "target" - | "title" - | "translate" - | "type" - | "usemap" - | "value" - | "width" - | "wrap"; - -export type Attr = - // TODO(mkr): will work in TS 4.4 - // { [data in DataAttr]?: string } & - Partial>; diff --git a/src/elements.deprecated.ts b/src/elements.deprecated.ts deleted file mode 100644 index 928f9c3..0000000 --- a/src/elements.deprecated.ts +++ /dev/null @@ -1,32 +0,0 @@ -export type CustomTag = `${string}-${string}`; - -export type Element = - | CustomTag - | "acronym" - | "applet" - | "basefont" - | "bgsound" - | "big" - | "blink" - | "center" - | "content" - | "dir" - | "font" - | "frame" - | "frameset" - | "hgroup" - | "image" - | "keygen" - | "marquee" - | "menuitem" - | "nobr" - | "noembed" - | "noframes" - | "plaintext" - | "rb" - | "rtc" - | "shadow" - | "spacer" - | "strike" - | "tt" - | "xmp"; diff --git a/src/hElement.ts b/src/hElement.ts deleted file mode 100644 index 0064ff0..0000000 --- a/src/hElement.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Element, CustomTag, Nodeish, Attr, Node, h } from "./Node.ts"; - -export type hElement = - // - ((props?: Attrs | Nodeish) => Node) & - ((...childNodes: Nodeish[]) => Node) & - ((props: Attrs, ...childNodes: Nodeish[]) => Node); - -const hElementCache = new Map(); - -function getHElement(element: Elem): hElement { - const fromCache = hElementCache.get(element); - if (fromCache) return fromCache as hElement; - - function hElement(props?: Attr | Nodeish, ...childNodes: Nodeish[]) { - return h(element, props, ...childNodes); - } - - hElementCache.set(element, hElement); - return hElement; -} - -export type ElementsToHElements = { - [Index in keyof Elements]: hElement< - // @ts-ignore TypeScript pls - Elements[Index] - >; -} & { length: Elements["length"] }; - -function mapElements(...elements: Elements) { - return elements.map(getHElement) as ElementsToHElements; -} - -export const elements = new Proxy(mapElements, { - get(_: unknown, element: E): hElement { - return getHElement(element); - }, -}) as typeof mapElements & { [k in Exclude]: hElement }; diff --git a/src/h_element.ts b/src/h_element.ts new file mode 100644 index 0000000..fdad94d --- /dev/null +++ b/src/h_element.ts @@ -0,0 +1,54 @@ +import { Nodeish, Node, h } from "./node.ts"; +import { Element, CustomTag } from "./elements.ts"; +import { Attr } from "./attributes.ts"; + +export type hElement< + Tag extends Element = Element, + Attrs extends Attr = Attr, +> = + // + (() => Node) & + // is a duplicate type, but gives clean intellisense + ((childNode: Nodeish) => Node) & + // order must be preserved, otherwise TS thinks State -> Node is invalid + ((...childNodes: Nodeish[]) => Node) & + ((props: Attrs) => Node) & + ((props: Attrs, ...childNodes: Nodeish[]) => Node); + +const hElementCache = new Map(); + +function getHElement( + element: Elem, +): hElement> { + type hE = hElement>; + + const fromCache = hElementCache.get(element); + if (fromCache) return fromCache as hE; + + const hElement = function hElement( + props?: Attr | Nodeish, + ...childNodes: Nodeish[] + ) { + return h(element, props, ...childNodes); + } as hE; + + hElementCache.set(element, hElement); + return hElement; +} + +export type ElementsToHElements = { + [Index in keyof Elements]: hElement< + // @ts-ignore TypeScript pls + Elements[Index] + >; +} & { length: Elements["length"] }; + +function mapElements(...elements: Elements) { + return elements.map(getHElement) as ElementsToHElements; +} + +export const elements = new Proxy(mapElements, { + get(_: unknown, element: E): hElement { + return getHElement(element); + }, +}) as typeof mapElements & { [k in Exclude]: hElement }; diff --git a/src/Node.ts b/src/node.ts similarity index 76% rename from src/Node.ts rename to src/node.ts index ba25aca..13bd670 100644 --- a/src/Node.ts +++ b/src/node.ts @@ -1,13 +1,7 @@ -import { Element as Active } from "./elements.ts"; -import { Element as Deprecated } from "./elements.deprecated.ts"; -import { Attr } from "./attrs.ts"; +import { Element } from "./elements.ts"; +import { Attr } from "./attributes.ts"; import { Falsy, isFalsy } from "./util.ts"; -import { SimpleState, SimpleStateRO, isState } from "./State.ts"; - -export type Element = Active | Deprecated; -export type { CustomTag } from "./elements.ts"; - -export type { Attr }; +import { SimpleState, SimpleStateRO, isState } from "./state.ts"; export type TextNode = string; @@ -45,13 +39,13 @@ export function h( ...children: Nodeish[] ): Node; -export function h( +export function h = Attr>( elem: Tag, props: Attr, ...children: Nodeish[] ): Node; -export function h( +export function h = Attr>( elem: Tag, props?: Attrs | Nodeish | Falsy, ...children: Nodeish[] diff --git a/src/render.ts b/src/render.ts index 20942ef..005d194 100644 --- a/src/render.ts +++ b/src/render.ts @@ -1,8 +1,9 @@ /// /// -import { Node, Nodeish, HTMLNode, Attr } from "./Node.ts"; -import { isState } from "./State.ts"; +import { Node, Nodeish, HTMLNode } from "./node.ts"; +import { Attr } from "./attributes.ts"; +import { isState } from "./state.ts"; import { Falsy, isFalsy, escapeHTML, guessEnv } from "./util.ts"; export function renderHTML(node: Nodeish): string { diff --git a/src/State.ts b/src/state.ts similarity index 100% rename from src/State.ts rename to src/state.ts From e4c6cf8dea3d0cc958e43c06b8d12987a8ccee96 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Tue, 29 Jun 2021 04:57:20 +0530 Subject: [PATCH 026/254] (feat) fetch ARIA props Signed-off-by: Muthu Kumar --- scripts/fetchARIA.ts | 45 ++++++++++++++++++++++++++++ src/aria.ts | 71 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 scripts/fetchARIA.ts create mode 100644 src/aria.ts diff --git a/scripts/fetchARIA.ts b/scripts/fetchARIA.ts new file mode 100644 index 0000000..a762d17 --- /dev/null +++ b/scripts/fetchARIA.ts @@ -0,0 +1,45 @@ +import { DOMParser } from "https://deno.land/x/deno_dom@v0.1.12-alpha/deno-dom-wasm.ts"; + +{ + const html = await fetch("https://w3c.github.io/using-aria/") + // + .then(res => res.text()); + + const document = new DOMParser().parseFromString(html, "text/html")!; + + const roles = [ + ...document.querySelector("#html-aria-gaps > section > ol")!.childNodes, + ] + .map(each => each.textContent.trim().replace(/`/g, "")) + .filter(Boolean) + .map(each => `"${each}"`); + + const types = [ + "export type ariaRoles =", + ` | ${roles.join("\n\t| ")};\n\n`, + ].join("\n"); + + Deno.writeTextFileSync("./src/aria.ts", types); +} + +{ + const html = await fetch( + "https://www.w3.org/TR/wai-aria-1.0/states_and_properties", + ).then(res => res.text()); + + const document = new DOMParser().parseFromString(html, "text/html")!; + + const attributes = [...document.querySelectorAll("#index_state_prop code")] + .map(each => each.textContent.trim()) + .filter(Boolean) + .map(each => `"${each}"`); + + const types = [ + "export type ariaAttributes = Record<", + ` | ${attributes.join("\n\t| ")},`, + " string", + ">;\n", + ].join("\n"); + + Deno.writeTextFileSync("./src/aria.ts", types, { append: true }); +} diff --git a/src/aria.ts b/src/aria.ts new file mode 100644 index 0000000..7148de2 --- /dev/null +++ b/src/aria.ts @@ -0,0 +1,71 @@ +export type ariaRoles = + | "alert" + | "alertdialog" + | "application" + | "directory" + | "document" + | "feed" + | "grid" + | "gridcell" + | "group" + | "log" + | "marquee" + | "menu" + | "menubar" + | "menuitemcheckbox" + | "menuitemradio" + | "none" + | "note" + | "presentation" + | "scrollbar" + | "search" + | "status" + | "switch" + | "tab" + | "tablist" + | "tabpanel" + | "timer" + | "toolbar" + | "tooltip" + | "tree" + | "treegrid" + | "treeitem"; + +export type ariaAttributes = Record< + | "aria-activedescendant" + | "aria-atomic" + | "aria-autocomplete" + | "aria-busy" + | "aria-checked" + | "aria-controls" + | "aria-describedby" + | "aria-disabled" + | "aria-dropeffect" + | "aria-expanded" + | "aria-flowto" + | "aria-grabbed" + | "aria-haspopup" + | "aria-hidden" + | "aria-invalid" + | "aria-label" + | "aria-labelledby" + | "aria-level" + | "aria-live" + | "aria-multiline" + | "aria-multiselectable" + | "aria-orientation" + | "aria-owns" + | "aria-posinset" + | "aria-pressed" + | "aria-readonly" + | "aria-relevant" + | "aria-required" + | "aria-selected" + | "aria-setsize" + | "aria-sort" + | "aria-valuemax" + | "aria-valuemin" + | "aria-valuenow" + | "aria-valuetext", + string +>; From 2ea3b48f8fbf2a3d5b37b2a9bce9eaa5d001b1fd Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Tue, 29 Jun 2021 05:37:57 +0530 Subject: [PATCH 027/254] (feat) support ARIA props Signed-off-by: Muthu Kumar --- scripts/fetchARIA.ts | 12 +-- ...nerateAttributes.ts => fetchAttributes.ts} | 16 ++-- src/aria.ts | 78 ++++++++++--------- src/attributes.ts | 12 ++- src/render.ts | 36 +++++++-- test.ts | 32 ++++++++ 6 files changed, 127 insertions(+), 59 deletions(-) rename scripts/{generateAttributes.ts => fetchAttributes.ts} (84%) diff --git a/scripts/fetchARIA.ts b/scripts/fetchARIA.ts index a762d17..2f57ebb 100644 --- a/scripts/fetchARIA.ts +++ b/scripts/fetchARIA.ts @@ -15,7 +15,7 @@ import { DOMParser } from "https://deno.land/x/deno_dom@v0.1.12-alpha/deno-dom-w .map(each => `"${each}"`); const types = [ - "export type ariaRoles =", + "export type AriaRoles =", ` | ${roles.join("\n\t| ")};\n\n`, ].join("\n"); @@ -32,12 +32,14 @@ import { DOMParser } from "https://deno.land/x/deno_dom@v0.1.12-alpha/deno-dom-w const attributes = [...document.querySelectorAll("#index_state_prop code")] .map(each => each.textContent.trim()) .filter(Boolean) - .map(each => `"${each}"`); + .map(each => `"${each.replace("aria-", "")}"`); const types = [ - "export type ariaAttributes = Record<", - ` | ${attributes.join("\n\t| ")},`, - " string", + "export type AriaAttributes = Partial<", + " Record<", + ` | ${attributes.join("\n\t\t| ")},`, + " string", + " >", ">;\n", ].join("\n"); diff --git a/scripts/generateAttributes.ts b/scripts/fetchAttributes.ts similarity index 84% rename from scripts/generateAttributes.ts rename to scripts/fetchAttributes.ts index f66c64f..3583b70 100644 --- a/scripts/generateAttributes.ts +++ b/scripts/fetchAttributes.ts @@ -4,7 +4,7 @@ const html = await fetch( "https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes", ).then(res => res.text()); -const document = new DOMParser().parseFromString(html, "text/html"); +const document = new DOMParser().parseFromString(html, "text/html")!; type Attribute = { attr: string; elements: string[] }; @@ -22,7 +22,7 @@ const groupByList = (xs: Attribute[]) => const { "Global attribute": globalAttr, ...elements } = groupByList( [ - ...document?.querySelector("article table.standard-table tbody") + ...document.querySelector("article table.standard-table tbody") ?.childNodes!, ] .filter(tr => tr.nodeName === "TR") @@ -57,6 +57,7 @@ const elementTypes = Object.keys(elements) .join("\n\t"); const types = `import { Element } from "./elements.ts"; +import { AriaRoles, AriaAttributes } from "./aria.ts"; type ${globalTypes} @@ -65,12 +66,17 @@ type ElementAttrs = { [k: string]: unknown; } -type DataAttr = ${"`data-${string}`"}; +export type DataAttr = ${"`data-${string}`"}; export type Attr = // TODO(mkr): will work in TS 4.4 // { [data in DataAttr]?: string } - Partial; + Partial< + GlobalAttrs & { + role?: AriaRoles; + aria?: AriaAttributes; + } & ElementAttrs[E] + >; `; -Deno.writeTextFileSync("./src/attrs.ts", types); +Deno.writeTextFileSync("./src/attributes.ts", types); diff --git a/src/aria.ts b/src/aria.ts index 7148de2..5939bfd 100644 --- a/src/aria.ts +++ b/src/aria.ts @@ -1,4 +1,4 @@ -export type ariaRoles = +export type AriaRoles = | "alert" | "alertdialog" | "application" @@ -31,41 +31,43 @@ export type ariaRoles = | "treegrid" | "treeitem"; -export type ariaAttributes = Record< - | "aria-activedescendant" - | "aria-atomic" - | "aria-autocomplete" - | "aria-busy" - | "aria-checked" - | "aria-controls" - | "aria-describedby" - | "aria-disabled" - | "aria-dropeffect" - | "aria-expanded" - | "aria-flowto" - | "aria-grabbed" - | "aria-haspopup" - | "aria-hidden" - | "aria-invalid" - | "aria-label" - | "aria-labelledby" - | "aria-level" - | "aria-live" - | "aria-multiline" - | "aria-multiselectable" - | "aria-orientation" - | "aria-owns" - | "aria-posinset" - | "aria-pressed" - | "aria-readonly" - | "aria-relevant" - | "aria-required" - | "aria-selected" - | "aria-setsize" - | "aria-sort" - | "aria-valuemax" - | "aria-valuemin" - | "aria-valuenow" - | "aria-valuetext", - string +export type AriaAttributes = Partial< + Record< + | "activedescendant" + | "atomic" + | "autocomplete" + | "busy" + | "checked" + | "controls" + | "describedby" + | "disabled" + | "dropeffect" + | "expanded" + | "flowto" + | "grabbed" + | "haspopup" + | "hidden" + | "invalid" + | "label" + | "labelledby" + | "level" + | "live" + | "multiline" + | "multiselectable" + | "orientation" + | "owns" + | "posinset" + | "pressed" + | "readonly" + | "relevant" + | "required" + | "selected" + | "setsize" + | "sort" + | "valuemax" + | "valuemin" + | "valuenow" + | "valuetext", + string + > >; diff --git a/src/attributes.ts b/src/attributes.ts index 87ba1c7..534e2f5 100644 --- a/src/attributes.ts +++ b/src/attributes.ts @@ -1,6 +1,5 @@ import { Element } from "./elements.ts"; - -type Aria = `aria-${string}`; +import { AriaRoles, AriaAttributes } from "./aria.ts"; type GlobalAttrs = Record< | "accesskey" @@ -311,9 +310,14 @@ type ElementAttrs = { [k: string]: unknown; }; -type DataAttr = `data-${string}`; +export type DataAttr = `data-${string}`; export type Attr = // TODO(mkr): will work in TS 4.4 // { [data in DataAttr]?: string } - Partial; + Partial< + GlobalAttrs & { + role?: AriaRoles; + aria?: AriaAttributes; + } & ElementAttrs[E] + >; diff --git a/src/render.ts b/src/render.ts index 005d194..d5f916b 100644 --- a/src/render.ts +++ b/src/render.ts @@ -6,6 +6,20 @@ import { Attr } from "./attributes.ts"; import { isState } from "./state.ts"; import { Falsy, isFalsy, escapeHTML, guessEnv } from "./util.ts"; +function attrifyHTML( + attrs: Record>, + prefix = "", +): string { + return Object.entries(attrs) + .map(([attr, value]) => { + if (value === "") return value; + if (typeof value === "object") + return attrifyHTML(value, attr + "-"); + return `${prefix + attr}="${value}"`; + }) + .join(" "); +} + export function renderHTML(node: Nodeish): string { if (isFalsy(node)) return ""; if (typeof node === "string") return escapeHTML(node); @@ -14,9 +28,7 @@ export function renderHTML(node: Nodeish): string { let stringified = "<" + node.tag; - const attr = Object.entries(node.attrs) - .map(([attr, val]) => (val ? `${attr}="${val}"` : attr)) - .join(" "); + const attr = attrifyHTML(node.attrs); if (attr) stringified += " " + attr; @@ -44,6 +56,19 @@ function htmlStringToElement(html: string) { return template.content.firstChild || ""; } +function attrifyDOM( + el: HTMLElement, + attrs: Record>, + prefix = "", +) { + for (const attr in attrs) { + const value = attrs[attr as keyof Attr]; + if (value === "") el.setAttribute(prefix + attr, ""); + else if (typeof value === "object") attrifyDOM(el, value, attr + "-"); + else if (value) el.setAttribute(prefix + attr, value); + } +} + const toDOM = function toDOM( node: N, parent: HTMLElement, @@ -73,10 +98,7 @@ const toDOM = function toDOM( const el = document.createElement(node.tag); - for (const attr in node.attrs) { - const value = node.attrs[attr as keyof Attr]; - if (value) el.setAttribute(attr, value); - } + attrifyDOM(el, node.attrs); for (const child of node.children) { const childNode = toDOM(child, el); diff --git a/test.ts b/test.ts index a72fe6f..384b2e6 100644 --- a/test.ts +++ b/test.ts @@ -14,6 +14,21 @@ Deno.test({ }, }); +assertEquals( + renderHTML( + div( + { + id: "hello", + class: "world", + role: "note", + aria: { disabled: "true" }, + }, + p(h1({ class: "hello" }, "hello world", br())), + ), + ), + `

hello world

`, +); + Deno.test({ name: "renderHTML complex", fn: () => { @@ -29,6 +44,23 @@ Deno.test({ }, }); +Deno.test({ + name: "renderHTML ARIA props", + fn: () => { + assertEquals( + renderHTML( + div({ + id: "hello", + class: "world", + role: "note", + aria: { disabled: "true" }, + }), + ), + `
`, + ); + }, +}); + Deno.test({ name: "renderHTML with HTML characters", fn: () => { From 3ae59e471ca44c42c5e8a1b4bb8939b8f0920ad3 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Tue, 29 Jun 2021 05:49:36 +0530 Subject: [PATCH 028/254] (doc) update README Signed-off-by: Muthu Kumar --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5a7ab92..643bbda 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Hyperactive is a suite of tools to build smart webapps. As of 1.0, only server-side render is supported. +You're on the experimental branch where interesting things are happening! + ## Usage example ```TypeScript From 7d003e46862232bd89d4513b5eaa4a8528ca8858 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Tue, 29 Jun 2021 21:20:01 +0530 Subject: [PATCH 029/254] (feat) rm deprecated attrs Signed-off-by: Muthu Kumar --- scripts/fetchAttributes.ts | 5 +++++ src/attributes.ts | 10 ++-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/scripts/fetchAttributes.ts b/scripts/fetchAttributes.ts index 3583b70..61308fd 100644 --- a/scripts/fetchAttributes.ts +++ b/scripts/fetchAttributes.ts @@ -26,6 +26,11 @@ const { "Global attribute": globalAttr, ...elements } = groupByList( ?.childNodes!, ] .filter(tr => tr.nodeName === "TR") + .filter( + tr => + // @ts-ignore: innerHTML exists, but isn't typed + !(tr.innerHTML as string).includes(`"icon icon-deprecated"`), + ) .map(tr => [...tr.childNodes!].map(each => each.textContent)) .map(([, attr, , elements]) => ({ attr: attr.trim(), diff --git a/src/attributes.ts b/src/attributes.ts index 534e2f5..0553c0a 100644 --- a/src/attributes.ts +++ b/src/attributes.ts @@ -108,7 +108,6 @@ type ElementAttrs = { string >; hr: Record<"align" | "color", string>; - html: Record<"manifest", string>; iframe: Record< | "align" | "allow" @@ -132,7 +131,6 @@ type ElementAttrs = { | "decoding" | "height" | "importance" - | "intrinsicsize" | "ismap" | "loading" | "referrerpolicy" @@ -231,7 +229,6 @@ type ElementAttrs = { | "defer" | "importance" | "integrity" - | "language" | "referrerpolicy" | "src" | "type", @@ -249,11 +246,8 @@ type ElementAttrs = { string >; source: Record<"media" | "sizes" | "src" | "srcset" | "type", string>; - style: Record<"media" | "scoped" | "type", string>; - table: Record< - "align" | "background" | "bgcolor" | "border" | "summary", - string - >; + style: Record<"media" | "type", string>; + table: Record<"align" | "background" | "bgcolor" | "border", string>; tbody: Record<"align" | "bgcolor", string>; td: Record< "align" | "background" | "bgcolor" | "colspan" | "headers" | "rowspan", From 865c6ae95ce5775cbc519b5631b83a16fa8aa373 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Tue, 29 Jun 2021 21:28:56 +0530 Subject: [PATCH 030/254] (feat) switch to object literal over Record<> Signed-off-by: Muthu Kumar --- scripts/fetchAttributes.ts | 19 +- src/attributes.ts | 727 ++++++++++++++++++++++--------------- 2 files changed, 443 insertions(+), 303 deletions(-) diff --git a/scripts/fetchAttributes.ts b/scripts/fetchAttributes.ts index 61308fd..ae8cd32 100644 --- a/scripts/fetchAttributes.ts +++ b/scripts/fetchAttributes.ts @@ -43,14 +43,23 @@ const { "Global attribute": globalAttr, ...elements } = groupByList( .sort((a, b) => a.attr.localeCompare(b.attr)), ); +const getKeyStr = (key: string) => (key.includes("-") ? `["${key}"]` : key); + const elementToType = ( el: string, attrs: { attr: string; type: string }[], { root }: { root?: boolean } = {}, -) => - `${el}${root ? " =" : ":"} Record<${attrs - .map(attr => `"${attr.attr}"`) - .join(" | ")}, string>;`; +) => { + const indent = "\t".repeat(root ? 1 : 2); + return [ + `${el}${root ? " =" : ":"} {`, + indent + + attrs + .map(attr => `${getKeyStr(attr.attr)}: string;`) + .join("\n" + indent), + "\t".repeat(root ? 0 : 1) + "};", + ].join("\n"); +}; const globalTypes = elementToType("GlobalAttrs", globalAttr, { root: true, @@ -69,7 +78,7 @@ type ${globalTypes} type ElementAttrs = { ${elementTypes} [k: string]: unknown; -} +}; export type DataAttr = ${"`data-${string}`"}; diff --git a/src/attributes.ts b/src/attributes.ts index 0553c0a..4b434ff 100644 --- a/src/attributes.ts +++ b/src/attributes.ts @@ -1,306 +1,437 @@ import { Element } from "./elements.ts"; import { AriaRoles, AriaAttributes } from "./aria.ts"; -type GlobalAttrs = Record< - | "accesskey" - | "autocapitalize" - | "class" - | "contenteditable" - | "contextmenu" - | "dir" - | "draggable" - | "hidden" - | "id" - | "itemprop" - | "lang" - | "slot" - | "spellcheck" - | "style" - | "tabindex" - | "title" - | "translate", - string ->; +type GlobalAttrs = { + accesskey: string; + autocapitalize: string; + class: string; + contenteditable: string; + contextmenu: string; + dir: string; + draggable: string; + hidden: string; + id: string; + itemprop: string; + lang: string; + slot: string; + spellcheck: string; + style: string; + tabindex: string; + title: string; + translate: string; +}; type ElementAttrs = { - a: Record< - | "download" - | "href" - | "hreflang" - | "media" - | "ping" - | "referrerpolicy" - | "rel" - | "shape" - | "target", - string - >; - applet: Record<"align" | "alt" | "code" | "codebase", string>; - area: Record< - | "alt" - | "coords" - | "download" - | "href" - | "hreflang" - | "media" - | "ping" - | "referrerpolicy" - | "rel" - | "shape" - | "target", - string - >; - audio: Record< - | "autoplay" - | "buffered" - | "controls" - | "crossorigin" - | "loop" - | "muted" - | "preload" - | "src", - string - >; - base: Record<"href" | "target", string>; - basefont: Record<"color", string>; - bgsound: Record<"loop", string>; - blockquote: Record<"cite", string>; - body: Record<"background" | "bgcolor", string>; - button: Record< - | "autofocus" - | "disabled" - | "form" - | "formaction" - | "formenctype" - | "formmethod" - | "formnovalidate" - | "formtarget" - | "name" - | "type" - | "value", - string - >; - canvas: Record<"height" | "width", string>; - caption: Record<"align", string>; - col: Record<"align" | "bgcolor" | "span", string>; - colgroup: Record<"align" | "bgcolor" | "span", string>; - command: Record< - "checked" | "disabled" | "icon" | "radiogroup" | "type", - string - >; - contenteditable: Record<"enterkeyhint" | "inputmode", string>; - data: Record<"value", string>; - del: Record<"cite" | "datetime", string>; - details: Record<"open", string>; - embed: Record<"height" | "src" | "type" | "width", string>; - fieldset: Record<"disabled" | "form" | "name", string>; - font: Record<"color", string>; - form: Record< - | "accept" - | "accept-charset" - | "action" - | "autocomplete" - | "enctype" - | "method" - | "name" - | "novalidate" - | "target", - string - >; - hr: Record<"align" | "color", string>; - iframe: Record< - | "align" - | "allow" - | "csp" - | "height" - | "importance" - | "loading" - | "name" - | "referrerpolicy" - | "sandbox" - | "src" - | "srcdoc" - | "width", - string - >; - img: Record< - | "align" - | "alt" - | "border" - | "crossorigin" - | "decoding" - | "height" - | "importance" - | "ismap" - | "loading" - | "referrerpolicy" - | "sizes" - | "src" - | "srcset" - | "usemap" - | "width", - string - >; - input: Record< - | "accept" - | "alt" - | "autocomplete" - | "autofocus" - | "capture" - | "checked" - | "dirname" - | "disabled" - | "form" - | "formaction" - | "formenctype" - | "formmethod" - | "formnovalidate" - | "formtarget" - | "height" - | "list" - | "max" - | "maxlength" - | "min" - | "minlength" - | "multiple" - | "name" - | "pattern" - | "placeholder" - | "readonly" - | "required" - | "size" - | "src" - | "step" - | "type" - | "usemap" - | "value" - | "width", - string - >; - ins: Record<"cite" | "datetime", string>; - keygen: Record< - "autofocus" | "challenge" | "disabled" | "form" | "keytype" | "name", - string - >; - label: Record<"for" | "form", string>; - li: Record<"value", string>; - link: Record< - | "crossorigin" - | "href" - | "hreflang" - | "importance" - | "integrity" - | "media" - | "referrerpolicy" - | "rel" - | "sizes", - string - >; - map: Record<"name", string>; - marquee: Record<"bgcolor" | "loop", string>; - menu: Record<"type", string>; - meta: Record<"charset" | "content" | "http-equiv" | "name", string>; - meter: Record< - "form" | "high" | "low" | "max" | "min" | "optimum" | "value", - string - >; - object: Record< - | "border" - | "data" - | "form" - | "height" - | "name" - | "type" - | "usemap" - | "width", - string - >; - ol: Record<"reversed" | "start", string>; - optgroup: Record<"disabled" | "label", string>; - option: Record<"disabled" | "label" | "selected" | "value", string>; - output: Record<"for" | "form" | "name", string>; - param: Record<"name" | "value", string>; - progress: Record<"form" | "max" | "value", string>; - q: Record<"cite", string>; - script: Record< - | "async" - | "charset" - | "crossorigin" - | "defer" - | "importance" - | "integrity" - | "referrerpolicy" - | "src" - | "type", - string - >; - select: Record< - | "autocomplete" - | "autofocus" - | "disabled" - | "form" - | "multiple" - | "name" - | "required" - | "size", - string - >; - source: Record<"media" | "sizes" | "src" | "srcset" | "type", string>; - style: Record<"media" | "type", string>; - table: Record<"align" | "background" | "bgcolor" | "border", string>; - tbody: Record<"align" | "bgcolor", string>; - td: Record< - "align" | "background" | "bgcolor" | "colspan" | "headers" | "rowspan", - string - >; - textarea: Record< - | "autocomplete" - | "autofocus" - | "cols" - | "dirname" - | "disabled" - | "enterkeyhint" - | "form" - | "inputmode" - | "maxlength" - | "minlength" - | "name" - | "placeholder" - | "readonly" - | "required" - | "rows" - | "wrap", - string - >; - tfoot: Record<"align" | "bgcolor", string>; - th: Record< - | "align" - | "background" - | "bgcolor" - | "colspan" - | "headers" - | "rowspan" - | "scope", - string - >; - thead: Record<"align", string>; - time: Record<"datetime", string>; - tr: Record<"align" | "bgcolor", string>; - track: Record<"default" | "kind" | "label" | "src" | "srclang", string>; - video: Record< - | "autoplay" - | "buffered" - | "controls" - | "crossorigin" - | "height" - | "loop" - | "muted" - | "poster" - | "preload" - | "src" - | "width", - string - >; + a: { + download: string; + href: string; + hreflang: string; + media: string; + ping: string; + referrerpolicy: string; + rel: string; + shape: string; + target: string; + }; + applet: { + align: string; + alt: string; + code: string; + codebase: string; + }; + area: { + alt: string; + coords: string; + download: string; + href: string; + hreflang: string; + media: string; + ping: string; + referrerpolicy: string; + rel: string; + shape: string; + target: string; + }; + audio: { + autoplay: string; + buffered: string; + controls: string; + crossorigin: string; + loop: string; + muted: string; + preload: string; + src: string; + }; + base: { + href: string; + target: string; + }; + basefont: { + color: string; + }; + bgsound: { + loop: string; + }; + blockquote: { + cite: string; + }; + body: { + background: string; + bgcolor: string; + }; + button: { + autofocus: string; + disabled: string; + form: string; + formaction: string; + formenctype: string; + formmethod: string; + formnovalidate: string; + formtarget: string; + name: string; + type: string; + value: string; + }; + canvas: { + height: string; + width: string; + }; + caption: { + align: string; + }; + col: { + align: string; + bgcolor: string; + span: string; + }; + colgroup: { + align: string; + bgcolor: string; + span: string; + }; + command: { + checked: string; + disabled: string; + icon: string; + radiogroup: string; + type: string; + }; + contenteditable: { + enterkeyhint: string; + inputmode: string; + }; + data: { + value: string; + }; + del: { + cite: string; + datetime: string; + }; + details: { + open: string; + }; + embed: { + height: string; + src: string; + type: string; + width: string; + }; + fieldset: { + disabled: string; + form: string; + name: string; + }; + font: { + color: string; + }; + form: { + accept: string; + ["accept-charset"]: string; + action: string; + autocomplete: string; + enctype: string; + method: string; + name: string; + novalidate: string; + target: string; + }; + hr: { + align: string; + color: string; + }; + iframe: { + align: string; + allow: string; + csp: string; + height: string; + importance: string; + loading: string; + name: string; + referrerpolicy: string; + sandbox: string; + src: string; + srcdoc: string; + width: string; + }; + img: { + align: string; + alt: string; + border: string; + crossorigin: string; + decoding: string; + height: string; + importance: string; + ismap: string; + loading: string; + referrerpolicy: string; + sizes: string; + src: string; + srcset: string; + usemap: string; + width: string; + }; + input: { + accept: string; + alt: string; + autocomplete: string; + autofocus: string; + capture: string; + checked: string; + dirname: string; + disabled: string; + form: string; + formaction: string; + formenctype: string; + formmethod: string; + formnovalidate: string; + formtarget: string; + height: string; + list: string; + max: string; + maxlength: string; + min: string; + minlength: string; + multiple: string; + name: string; + pattern: string; + placeholder: string; + readonly: string; + required: string; + size: string; + src: string; + step: string; + type: string; + usemap: string; + value: string; + width: string; + }; + ins: { + cite: string; + datetime: string; + }; + keygen: { + autofocus: string; + challenge: string; + disabled: string; + form: string; + keytype: string; + name: string; + }; + label: { + for: string; + form: string; + }; + li: { + value: string; + }; + link: { + crossorigin: string; + href: string; + hreflang: string; + importance: string; + integrity: string; + media: string; + referrerpolicy: string; + rel: string; + sizes: string; + }; + map: { + name: string; + }; + marquee: { + bgcolor: string; + loop: string; + }; + menu: { + type: string; + }; + meta: { + charset: string; + content: string; + ["http-equiv"]: string; + name: string; + }; + meter: { + form: string; + high: string; + low: string; + max: string; + min: string; + optimum: string; + value: string; + }; + object: { + border: string; + data: string; + form: string; + height: string; + name: string; + type: string; + usemap: string; + width: string; + }; + ol: { + reversed: string; + start: string; + }; + optgroup: { + disabled: string; + label: string; + }; + option: { + disabled: string; + label: string; + selected: string; + value: string; + }; + output: { + for: string; + form: string; + name: string; + }; + param: { + name: string; + value: string; + }; + progress: { + form: string; + max: string; + value: string; + }; + q: { + cite: string; + }; + script: { + async: string; + charset: string; + crossorigin: string; + defer: string; + importance: string; + integrity: string; + referrerpolicy: string; + src: string; + type: string; + }; + select: { + autocomplete: string; + autofocus: string; + disabled: string; + form: string; + multiple: string; + name: string; + required: string; + size: string; + }; + source: { + media: string; + sizes: string; + src: string; + srcset: string; + type: string; + }; + style: { + media: string; + type: string; + }; + table: { + align: string; + background: string; + bgcolor: string; + border: string; + }; + tbody: { + align: string; + bgcolor: string; + }; + td: { + align: string; + background: string; + bgcolor: string; + colspan: string; + headers: string; + rowspan: string; + }; + textarea: { + autocomplete: string; + autofocus: string; + cols: string; + dirname: string; + disabled: string; + enterkeyhint: string; + form: string; + inputmode: string; + maxlength: string; + minlength: string; + name: string; + placeholder: string; + readonly: string; + required: string; + rows: string; + wrap: string; + }; + tfoot: { + align: string; + bgcolor: string; + }; + th: { + align: string; + background: string; + bgcolor: string; + colspan: string; + headers: string; + rowspan: string; + scope: string; + }; + thead: { + align: string; + }; + time: { + datetime: string; + }; + tr: { + align: string; + bgcolor: string; + }; + track: { + default: string; + kind: string; + label: string; + src: string; + srclang: string; + }; + video: { + autoplay: string; + buffered: string; + controls: string; + crossorigin: string; + height: string; + loop: string; + muted: string; + poster: string; + preload: string; + src: string; + width: string; + }; [k: string]: unknown; }; From e1fbd4d1e9ba13c505f3dd54687c109f19884a75 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Thu, 1 Jul 2021 23:53:52 +0530 Subject: [PATCH 031/254] (feat) add tsdoc from mdn to attributes Signed-off-by: Muthu Kumar --- scripts/fetchAttributes.ts | 49 +- src/attributes.ts | 1522 ++++++++++++++++++++++++++++++++++++ 2 files changed, 1566 insertions(+), 5 deletions(-) diff --git a/scripts/fetchAttributes.ts b/scripts/fetchAttributes.ts index ae8cd32..5b3a0a0 100644 --- a/scripts/fetchAttributes.ts +++ b/scripts/fetchAttributes.ts @@ -6,19 +6,21 @@ const html = await fetch( const document = new DOMParser().parseFromString(html, "text/html")!; -type Attribute = { attr: string; elements: string[] }; +type Attribute = { attr: string; elements: string[]; desc: string }; const groupByList = (xs: Attribute[]) => xs.reduce((acc, curr) => { for (const element of curr.elements) { (acc[element] || (acc[element] = [])).push({ attr: curr.attr, + elements: curr.elements, type: "string", + desc: curr.desc, }); } return acc; - }, {} as Record); + }, {} as Record); const { "Global attribute": globalAttr, ...elements } = groupByList( [ @@ -32,22 +34,41 @@ const { "Global attribute": globalAttr, ...elements } = groupByList( !(tr.innerHTML as string).includes(`"icon icon-deprecated"`), ) .map(tr => [...tr.childNodes!].map(each => each.textContent)) - .map(([, attr, , elements]) => ({ + .map(([, attr, , elements, , desc]) => ({ attr: attr.trim(), elements: elements .replaceAll(/<|>/g, "") .split(/,\s+/) .map(e => e.trim()), + desc: desc.trim(), })) .filter(each => each.attr !== "data-*") .sort((a, b) => a.attr.localeCompare(b.attr)), ); +console.log({ elements }); + const getKeyStr = (key: string) => (key.includes("-") ? `["${key}"]` : key); +const globalOrElems = (elements: string[]) => + elements.includes("Global attribute") + ? "Global attribute" + : "Applies to " + elements.map(e => "`" + e + "`").join(", "); + +const docLine = (line: string) => { + line = line.trim(); + if (!line) return ""; + line = line.replace( + /<|>/g, + s => ({ "<": "`<", ">": ">`" }[s as "<" | ">"]), + ); + if (line.startsWith("Note")) line = "> " + line; + return " * " + line; +}; + const elementToType = ( el: string, - attrs: { attr: string; type: string }[], + attrs: (Attribute & { type: string })[], { root }: { root?: boolean } = {}, ) => { const indent = "\t".repeat(root ? 1 : 2); @@ -55,7 +76,25 @@ const elementToType = ( `${el}${root ? " =" : ":"} {`, indent + attrs - .map(attr => `${getKeyStr(attr.attr)}: string;`) + .map( + attr => + (attr.desc && + "/**\n" + + indent + + [ + globalOrElems(attr.elements), + ...attr.desc + .replace("\n\n", "\n") + .split("\n"), + ] + .map(docLine) + .filter(Boolean) + .join("\n" + indent + " *\n" + indent) + + "\n" + + indent + + " */\n" + + indent) + `${getKeyStr(attr.attr)}: string;`, + ) .join("\n" + indent), "\t".repeat(root ? 0 : 1) + "};", ].join("\n"); diff --git a/src/attributes.ts b/src/attributes.ts index 4b434ff..ddab516 100644 --- a/src/attributes.ts +++ b/src/attributes.ts @@ -2,434 +2,1956 @@ import { Element } from "./elements.ts"; import { AriaRoles, AriaAttributes } from "./aria.ts"; type GlobalAttrs = { + /** + * Global attribute + * + * Keyboard shortcut to activate or add focus to the element. + */ accesskey: string; + /** + * Global attribute + * + * Sets whether input is automatically capitalized when entered by user + */ autocapitalize: string; + /** + * Global attribute + * + * Often used with CSS to style elements with common properties. + */ class: string; + /** + * Global attribute + * + * Indicates whether the element's content is editable. + */ contenteditable: string; + /** + * Global attribute + * + * Defines the ID of a `` element which will serve as the element's context menu. + */ contextmenu: string; + /** + * Global attribute + * + * Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left) + */ dir: string; + /** + * Global attribute + * + * Defines whether the element can be dragged. + */ draggable: string; + /** + * Global attribute + * + * Prevents rendering of given element, while keeping child elements, e.g. script elements, active. + */ hidden: string; + /** + * Global attribute + * + * Often used with CSS to style a specific element. The value of this attribute must be unique. + */ id: string; itemprop: string; + /** + * Global attribute + * + * Defines the language used in the element. + */ lang: string; + /** + * Global attribute + * + * Assigns a slot in a shadow DOM shadow tree to an element. + */ slot: string; + /** + * Global attribute + * + * Indicates whether spell checking is allowed for the element. + */ spellcheck: string; + /** + * Global attribute + * + * Defines CSS styles which will override styles previously set. + */ style: string; + /** + * Global attribute + * + * Overrides the browser's default tab order and follows the one specified instead. + */ tabindex: string; + /** + * Global attribute + * + * Text to be displayed in a tooltip when hovering over the element. + */ title: string; + /** + * Global attribute + * + * Specify whether an element’s attribute values and the values of its Text node children are to be translated when the page is localized, or whether to leave them unchanged. + */ translate: string; }; type ElementAttrs = { a: { + /** + * Applies to `a`, `area` + * + * Indicates that the hyperlink is to be used for downloading a resource. + */ download: string; + /** + * Applies to `a`, `area`, `base`, `link` + * + * The URL of a linked resource. + */ href: string; + /** + * Applies to `a`, `area`, `link` + * + * Specifies the language of the linked resource. + */ hreflang: string; + /** + * Applies to `a`, `area`, `link`, `source`, `style` + * + * Specifies a hint of the media for which the linked resource was designed. + */ media: string; + /** + * Applies to `a`, `area` + * + * The ping attribute specifies a space-separated list of URLs to be notified if a user follows the hyperlink. + */ ping: string; + /** + * Applies to `a`, `area`, `iframe`, `img`, `link`, `script` + * + * Specifies which referrer is sent when fetching the resource. + */ referrerpolicy: string; + /** + * Applies to `a`, `area`, `link` + * + * Specifies the relationship of the target object to the link object. + */ rel: string; shape: string; + /** + * Applies to `a`, `area`, `base`, `form` + * + * Specifies where to open the linked document (in the case of an `` element) or where to display the response received (in the case of a `
` element) + */ target: string; }; applet: { + /** + * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` + * + * Specifies the horizontal alignment of the element. + */ align: string; + /** + * Applies to `applet`, `area`, `img`, `input` + * + * Alternative text in case an image can't be displayed. + */ alt: string; + /** + * Applies to `applet` + * + * Specifies the URL of the applet's class file to be loaded and executed. + */ code: string; + /** + * Applies to `applet` + * + * This attribute gives the absolute or relative URL of the directory where applets' .class files referenced by the code attribute are stored. + */ codebase: string; }; area: { + /** + * Applies to `applet`, `area`, `img`, `input` + * + * Alternative text in case an image can't be displayed. + */ alt: string; + /** + * Applies to `area` + * + * A set of values specifying the coordinates of the hot-spot region. + */ coords: string; + /** + * Applies to `a`, `area` + * + * Indicates that the hyperlink is to be used for downloading a resource. + */ download: string; + /** + * Applies to `a`, `area`, `base`, `link` + * + * The URL of a linked resource. + */ href: string; + /** + * Applies to `a`, `area`, `link` + * + * Specifies the language of the linked resource. + */ hreflang: string; + /** + * Applies to `a`, `area`, `link`, `source`, `style` + * + * Specifies a hint of the media for which the linked resource was designed. + */ media: string; + /** + * Applies to `a`, `area` + * + * The ping attribute specifies a space-separated list of URLs to be notified if a user follows the hyperlink. + */ ping: string; + /** + * Applies to `a`, `area`, `iframe`, `img`, `link`, `script` + * + * Specifies which referrer is sent when fetching the resource. + */ referrerpolicy: string; + /** + * Applies to `a`, `area`, `link` + * + * Specifies the relationship of the target object to the link object. + */ rel: string; shape: string; + /** + * Applies to `a`, `area`, `base`, `form` + * + * Specifies where to open the linked document (in the case of an `` element) or where to display the response received (in the case of a `` element) + */ target: string; }; audio: { + /** + * Applies to `audio`, `video` + * + * The audio or video should play as soon as possible. + */ autoplay: string; + /** + * Applies to `audio`, `video` + * + * Contains the time range of already buffered media. + */ buffered: string; + /** + * Applies to `audio`, `video` + * + * Indicates whether the browser should show playback controls to the user. + */ controls: string; + /** + * Applies to `audio`, `img`, `link`, `script`, `video` + * + * How the element handles cross-origin requests + */ crossorigin: string; + /** + * Applies to `audio`, `bgsound`, `marquee`, `video` + * + * Indicates whether the media should start playing from the start when it's finished. + */ loop: string; + /** + * Applies to `audio`, `video` + * + * Indicates whether the audio will be initially silenced on page load. + */ muted: string; + /** + * Applies to `audio`, `video` + * + * Indicates whether the whole resource, parts of it or nothing should be preloaded. + */ preload: string; + /** + * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` + * + * The URL of the embeddable content. + */ src: string; }; base: { + /** + * Applies to `a`, `area`, `base`, `link` + * + * The URL of a linked resource. + */ href: string; + /** + * Applies to `a`, `area`, `base`, `form` + * + * Specifies where to open the linked document (in the case of an `` element) or where to display the response received (in the case of a `` element) + */ target: string; }; basefont: { + /** + * Applies to `basefont`, `font`, `hr` + * + * This attribute sets the text color using either a named color or a color specified in the hexadecimal #RRGGBB format. + * + * > Note: This is a legacy attribute. Please use the CSS color property instead. + */ color: string; }; bgsound: { + /** + * Applies to `audio`, `bgsound`, `marquee`, `video` + * + * Indicates whether the media should start playing from the start when it's finished. + */ loop: string; }; blockquote: { + /** + * Applies to `blockquote`, `del`, `ins`, `q` + * + * Contains a URI which points to the source of the quote or change. + */ cite: string; }; body: { + /** + * Applies to `body`, `table`, `td`, `th` + * + * Specifies the URL of an image file. + * + * > Note: Although browsers and email clients may still support this attribute, it is obsolete. Use CSS background-image instead. + */ background: string; + /** + * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` + * + * Background color of the element. + * + * > Note: This is a legacy attribute. Please use the CSS background-color property instead. + */ bgcolor: string; }; button: { + /** + * Applies to `button`, `input`, `keygen`, `select`, `textarea` + * + * The element should be automatically focused after the page loaded. + */ autofocus: string; + /** + * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` + * + * Indicates whether the user can interact with the element. + */ disabled: string; + /** + * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` + * + * Indicates the form that is the owner of the element. + */ form: string; + /** + * Applies to `input`, `button` + * + * Indicates the action of the element, overriding the action defined in the ``. + */ formaction: string; + /** + * Applies to `button`, `input` + * + * If the button/input is a submit button (type="submit"), this attribute sets the encoding type to use during form submission. If this attribute is specified, it overrides the enctype attribute of the button's form owner. + */ formenctype: string; + /** + * Applies to `button`, `input` + * + * If the button/input is a submit button (type="submit"), this attribute sets the submission method to use during form submission (GET, POST, etc.). If this attribute is specified, it overrides the method attribute of the button's form owner. + */ formmethod: string; + /** + * Applies to `button`, `input` + * + * If the button/input is a submit button (type="submit"), this boolean attribute specifies that the form is not to be validated when it is submitted. If this attribute is specified, it overrides the novalidate attribute of the button's form owner. + */ formnovalidate: string; + /** + * Applies to `button`, `input` + * + * If the button/input is a submit button (type="submit"), this attribute specifies the browsing context (for example, tab, window, or inline frame) in which to display the response that is received after submitting the form. If this attribute is specified, it overrides the target attribute of the button's form owner. + */ formtarget: string; + /** + * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` + * + * Name of the element. For example used by the server to identify the fields in form submits. + */ name: string; + /** + * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` + * + * Defines the type of the element. + */ type: string; + /** + * Applies to `button`, `data`, `input`, `li`, `meter`, `option`, `progress`, `param` + * + * Defines a default value which will be displayed in the element on page load. + */ value: string; }; canvas: { + /** + * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` + * + * Specifies the height of elements listed here. For all other elements, use the CSS height property. + * + * > Note: In some instances, such as `
`, this is a legacy attribute, in which case the CSS height property should be used instead. + */ height: string; + /** + * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` + * + * For the elements listed here, this establishes the element's width. + * + * > Note: For all other instances, such as `
`, this is a legacy attribute, in which case the CSS width property should be used instead. + */ width: string; }; caption: { + /** + * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` + * + * Specifies the horizontal alignment of the element. + */ align: string; }; col: { + /** + * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` + * + * Specifies the horizontal alignment of the element. + */ align: string; + /** + * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` + * + * Background color of the element. + * + * > Note: This is a legacy attribute. Please use the CSS background-color property instead. + */ bgcolor: string; span: string; }; colgroup: { + /** + * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` + * + * Specifies the horizontal alignment of the element. + */ align: string; + /** + * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` + * + * Background color of the element. + * + * > Note: This is a legacy attribute. Please use the CSS background-color property instead. + */ bgcolor: string; span: string; }; command: { + /** + * Applies to `command`, `input` + * + * Indicates whether the element should be checked on page load. + */ checked: string; + /** + * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` + * + * Indicates whether the user can interact with the element. + */ disabled: string; + /** + * Applies to `command` + * + * Specifies a picture which represents the command. + */ icon: string; radiogroup: string; + /** + * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` + * + * Defines the type of the element. + */ type: string; }; contenteditable: { + /** + * Applies to `textarea`, `contenteditable` + * + * The enterkeyhint specifies what action label (or icon) to present for the enter key on virtual keyboards. The attribute can be used with form controls (such as the value of textarea elements), or in elements in an editing host (e.g., using contenteditable attribute). + */ enterkeyhint: string; + /** + * Applies to `textarea`, `contenteditable` + * + * Provides a hint as to the type of data that might be entered by the user while editing the element or its contents. The attribute can be used with form controls (such as the value of textarea elements), or in elements in an editing host (e.g., using contenteditable attribute). + */ inputmode: string; }; data: { + /** + * Applies to `button`, `data`, `input`, `li`, `meter`, `option`, `progress`, `param` + * + * Defines a default value which will be displayed in the element on page load. + */ value: string; }; del: { + /** + * Applies to `blockquote`, `del`, `ins`, `q` + * + * Contains a URI which points to the source of the quote or change. + */ cite: string; + /** + * Applies to `del`, `ins`, `time` + * + * Indicates the date and time associated with the element. + */ datetime: string; }; details: { + /** + * Applies to `details` + * + * Indicates whether the details will be shown on page load. + */ open: string; }; embed: { + /** + * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` + * + * Specifies the height of elements listed here. For all other elements, use the CSS height property. + * + * > Note: In some instances, such as `
`, this is a legacy attribute, in which case the CSS height property should be used instead. + */ height: string; + /** + * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` + * + * The URL of the embeddable content. + */ src: string; + /** + * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` + * + * Defines the type of the element. + */ type: string; + /** + * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` + * + * For the elements listed here, this establishes the element's width. + * + * > Note: For all other instances, such as `
`, this is a legacy attribute, in which case the CSS width property should be used instead. + */ width: string; }; fieldset: { + /** + * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` + * + * Indicates whether the user can interact with the element. + */ disabled: string; + /** + * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` + * + * Indicates the form that is the owner of the element. + */ form: string; + /** + * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` + * + * Name of the element. For example used by the server to identify the fields in form submits. + */ name: string; }; font: { + /** + * Applies to `basefont`, `font`, `hr` + * + * This attribute sets the text color using either a named color or a color specified in the hexadecimal #RRGGBB format. + * + * > Note: This is a legacy attribute. Please use the CSS color property instead. + */ color: string; }; form: { + /** + * Applies to `form`, `input` + * + * List of types the server accepts, typically a file type. + */ accept: string; + /** + * Applies to `form` + * + * List of supported charsets. + */ ["accept-charset"]: string; + /** + * Applies to `form` + * + * The URI of a program that processes the information submitted via the form. + */ action: string; + /** + * Applies to `form`, `input`, `select`, `textarea` + * + * Indicates whether controls in this form can by default have their values automatically completed by the browser. + */ autocomplete: string; + /** + * Applies to `form` + * + * Defines the content type of the form data when the method is POST. + */ enctype: string; + /** + * Applies to `form` + * + * Defines which HTTP method to use when submitting the form. Can be GET (default) or POST. + */ method: string; + /** + * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` + * + * Name of the element. For example used by the server to identify the fields in form submits. + */ name: string; + /** + * Applies to `form` + * + * This attribute indicates that the form shouldn't be validated when submitted. + */ novalidate: string; + /** + * Applies to `a`, `area`, `base`, `form` + * + * Specifies where to open the linked document (in the case of an `` element) or where to display the response received (in the case of a `` element) + */ target: string; }; hr: { + /** + * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` + * + * Specifies the horizontal alignment of the element. + */ align: string; + /** + * Applies to `basefont`, `font`, `hr` + * + * This attribute sets the text color using either a named color or a color specified in the hexadecimal #RRGGBB format. + * + * > Note: This is a legacy attribute. Please use the CSS color property instead. + */ color: string; }; iframe: { + /** + * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` + * + * Specifies the horizontal alignment of the element. + */ align: string; + /** + * Applies to `iframe` + * + * Specifies a feature-policy for the iframe. + */ allow: string; + /** + * Applies to `iframe` + * + * Specifies the Content Security Policy that an embedded document must agree to enforce upon itself. + */ csp: string; + /** + * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` + * + * Specifies the height of elements listed here. For all other elements, use the CSS height property. + * + * > Note: In some instances, such as `
`, this is a legacy attribute, in which case the CSS height property should be used instead. + */ height: string; + /** + * Applies to `iframe`, `img`, `link`, `script` + * + * Indicates the relative fetch priority for the resource. + */ importance: string; + /** + * Applies to `img`, `iframe` + * + * Indicates if the element should be loaded lazily (loading="lazy") or loaded immediately (loading="eager"). + * + * WIP: WHATWG PR #3752 + */ loading: string; + /** + * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` + * + * Name of the element. For example used by the server to identify the fields in form submits. + */ name: string; + /** + * Applies to `a`, `area`, `iframe`, `img`, `link`, `script` + * + * Specifies which referrer is sent when fetching the resource. + */ referrerpolicy: string; + /** + * Applies to `iframe` + * + * Stops a document loaded in an iframe from using certain features (such as submitting forms or opening new windows). + */ sandbox: string; + /** + * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` + * + * The URL of the embeddable content. + */ src: string; srcdoc: string; + /** + * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` + * + * For the elements listed here, this establishes the element's width. + * + * > Note: For all other instances, such as `
`, this is a legacy attribute, in which case the CSS width property should be used instead. + */ width: string; }; img: { + /** + * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` + * + * Specifies the horizontal alignment of the element. + */ align: string; + /** + * Applies to `applet`, `area`, `img`, `input` + * + * Alternative text in case an image can't be displayed. + */ alt: string; + /** + * Applies to `img`, `object`, `table` + * + * The border width. + * + * > Note: This is a legacy attribute. Please use the CSS border property instead. + */ border: string; + /** + * Applies to `audio`, `img`, `link`, `script`, `video` + * + * How the element handles cross-origin requests + */ crossorigin: string; + /** + * Applies to `img` + * + * Indicates the preferred method to decode the image. + */ decoding: string; + /** + * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` + * + * Specifies the height of elements listed here. For all other elements, use the CSS height property. + * + * > Note: In some instances, such as `
`, this is a legacy attribute, in which case the CSS height property should be used instead. + */ height: string; + /** + * Applies to `iframe`, `img`, `link`, `script` + * + * Indicates the relative fetch priority for the resource. + */ importance: string; + /** + * Applies to `img` + * + * Indicates that the image is part of a server-side image map. + */ ismap: string; + /** + * Applies to `img`, `iframe` + * + * Indicates if the element should be loaded lazily (loading="lazy") or loaded immediately (loading="eager"). + * + * WIP: WHATWG PR #3752 + */ loading: string; + /** + * Applies to `a`, `area`, `iframe`, `img`, `link`, `script` + * + * Specifies which referrer is sent when fetching the resource. + */ referrerpolicy: string; sizes: string; + /** + * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` + * + * The URL of the embeddable content. + */ src: string; + /** + * Applies to `img`, `source` + * + * One or more responsive image candidates. + */ srcset: string; usemap: string; + /** + * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` + * + * For the elements listed here, this establishes the element's width. + * + * > Note: For all other instances, such as `
`, this is a legacy attribute, in which case the CSS width property should be used instead. + */ width: string; }; input: { + /** + * Applies to `form`, `input` + * + * List of types the server accepts, typically a file type. + */ accept: string; + /** + * Applies to `applet`, `area`, `img`, `input` + * + * Alternative text in case an image can't be displayed. + */ alt: string; + /** + * Applies to `form`, `input`, `select`, `textarea` + * + * Indicates whether controls in this form can by default have their values automatically completed by the browser. + */ autocomplete: string; + /** + * Applies to `button`, `input`, `keygen`, `select`, `textarea` + * + * The element should be automatically focused after the page loaded. + */ autofocus: string; + /** + * Applies to `input` + * + * From the HTML Media CaptureThe definition of 'media capture' in that specification.spec, specifies a new file can be captured. + */ capture: string; + /** + * Applies to `command`, `input` + * + * Indicates whether the element should be checked on page load. + */ checked: string; dirname: string; + /** + * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` + * + * Indicates whether the user can interact with the element. + */ disabled: string; + /** + * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` + * + * Indicates the form that is the owner of the element. + */ form: string; + /** + * Applies to `input`, `button` + * + * Indicates the action of the element, overriding the action defined in the ``. + */ formaction: string; + /** + * Applies to `button`, `input` + * + * If the button/input is a submit button (type="submit"), this attribute sets the encoding type to use during form submission. If this attribute is specified, it overrides the enctype attribute of the button's form owner. + */ formenctype: string; + /** + * Applies to `button`, `input` + * + * If the button/input is a submit button (type="submit"), this attribute sets the submission method to use during form submission (GET, POST, etc.). If this attribute is specified, it overrides the method attribute of the button's form owner. + */ formmethod: string; + /** + * Applies to `button`, `input` + * + * If the button/input is a submit button (type="submit"), this boolean attribute specifies that the form is not to be validated when it is submitted. If this attribute is specified, it overrides the novalidate attribute of the button's form owner. + */ formnovalidate: string; + /** + * Applies to `button`, `input` + * + * If the button/input is a submit button (type="submit"), this attribute specifies the browsing context (for example, tab, window, or inline frame) in which to display the response that is received after submitting the form. If this attribute is specified, it overrides the target attribute of the button's form owner. + */ formtarget: string; + /** + * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` + * + * Specifies the height of elements listed here. For all other elements, use the CSS height property. + * + * > Note: In some instances, such as `
`, this is a legacy attribute, in which case the CSS height property should be used instead. + */ height: string; + /** + * Applies to `input` + * + * Identifies a list of pre-defined options to suggest to the user. + */ list: string; + /** + * Applies to `input`, `meter`, `progress` + * + * Indicates the maximum value allowed. + */ max: string; + /** + * Applies to `input`, `textarea` + * + * Defines the maximum number of characters allowed in the element. + */ maxlength: string; + /** + * Applies to `input`, `meter` + * + * Indicates the minimum value allowed. + */ min: string; + /** + * Applies to `input`, `textarea` + * + * Defines the minimum number of characters allowed in the element. + */ minlength: string; + /** + * Applies to `input`, `select` + * + * Indicates whether multiple values can be entered in an input of the type email or file. + */ multiple: string; + /** + * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` + * + * Name of the element. For example used by the server to identify the fields in form submits. + */ name: string; + /** + * Applies to `input` + * + * Defines a regular expression which the element's value will be validated against. + */ pattern: string; + /** + * Applies to `input`, `textarea` + * + * Provides a hint to the user of what can be entered in the field. + */ placeholder: string; + /** + * Applies to `input`, `textarea` + * + * Indicates whether the element can be edited. + */ readonly: string; + /** + * Applies to `input`, `select`, `textarea` + * + * Indicates whether this element is required to fill out or not. + */ required: string; + /** + * Applies to `input`, `select` + * + * Defines the width of the element (in pixels). If the element's type attribute is text or password then it's the number of characters. + */ size: string; + /** + * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` + * + * The URL of the embeddable content. + */ src: string; step: string; + /** + * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` + * + * Defines the type of the element. + */ type: string; usemap: string; + /** + * Applies to `button`, `data`, `input`, `li`, `meter`, `option`, `progress`, `param` + * + * Defines a default value which will be displayed in the element on page load. + */ value: string; + /** + * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` + * + * For the elements listed here, this establishes the element's width. + * + * > Note: For all other instances, such as `
`, this is a legacy attribute, in which case the CSS width property should be used instead. + */ width: string; }; ins: { + /** + * Applies to `blockquote`, `del`, `ins`, `q` + * + * Contains a URI which points to the source of the quote or change. + */ cite: string; + /** + * Applies to `del`, `ins`, `time` + * + * Indicates the date and time associated with the element. + */ datetime: string; }; keygen: { + /** + * Applies to `button`, `input`, `keygen`, `select`, `textarea` + * + * The element should be automatically focused after the page loaded. + */ autofocus: string; + /** + * Applies to `keygen` + * + * A challenge string that is submitted along with the public key. + */ challenge: string; + /** + * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` + * + * Indicates whether the user can interact with the element. + */ disabled: string; + /** + * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` + * + * Indicates the form that is the owner of the element. + */ form: string; + /** + * Applies to `keygen` + * + * Specifies the type of key generated. + */ keytype: string; + /** + * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` + * + * Name of the element. For example used by the server to identify the fields in form submits. + */ name: string; }; label: { + /** + * Applies to `label`, `output` + * + * Describes elements which belongs to this one. + */ for: string; + /** + * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` + * + * Indicates the form that is the owner of the element. + */ form: string; }; li: { + /** + * Applies to `button`, `data`, `input`, `li`, `meter`, `option`, `progress`, `param` + * + * Defines a default value which will be displayed in the element on page load. + */ value: string; }; link: { + /** + * Applies to `audio`, `img`, `link`, `script`, `video` + * + * How the element handles cross-origin requests + */ crossorigin: string; + /** + * Applies to `a`, `area`, `base`, `link` + * + * The URL of a linked resource. + */ href: string; + /** + * Applies to `a`, `area`, `link` + * + * Specifies the language of the linked resource. + */ hreflang: string; + /** + * Applies to `iframe`, `img`, `link`, `script` + * + * Indicates the relative fetch priority for the resource. + */ importance: string; + /** + * Applies to `link`, `script` + * + * Specifies a Subresource Integrity value that allows browsers to verify what they fetch. + */ integrity: string; + /** + * Applies to `a`, `area`, `link`, `source`, `style` + * + * Specifies a hint of the media for which the linked resource was designed. + */ media: string; + /** + * Applies to `a`, `area`, `iframe`, `img`, `link`, `script` + * + * Specifies which referrer is sent when fetching the resource. + */ referrerpolicy: string; + /** + * Applies to `a`, `area`, `link` + * + * Specifies the relationship of the target object to the link object. + */ rel: string; sizes: string; }; map: { + /** + * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` + * + * Name of the element. For example used by the server to identify the fields in form submits. + */ name: string; }; marquee: { + /** + * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` + * + * Background color of the element. + * + * > Note: This is a legacy attribute. Please use the CSS background-color property instead. + */ bgcolor: string; + /** + * Applies to `audio`, `bgsound`, `marquee`, `video` + * + * Indicates whether the media should start playing from the start when it's finished. + */ loop: string; }; menu: { + /** + * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` + * + * Defines the type of the element. + */ type: string; }; meta: { + /** + * Applies to `meta`, `script` + * + * Declares the character encoding of the page or script. + */ charset: string; + /** + * Applies to `meta` + * + * A value associated with http-equiv or name depending on the context. + */ content: string; + /** + * Applies to `meta` + * + * Defines a pragma directive. + */ ["http-equiv"]: string; + /** + * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` + * + * Name of the element. For example used by the server to identify the fields in form submits. + */ name: string; }; meter: { + /** + * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` + * + * Indicates the form that is the owner of the element. + */ form: string; + /** + * Applies to `meter` + * + * Indicates the lower bound of the upper range. + */ high: string; + /** + * Applies to `meter` + * + * Indicates the upper bound of the lower range. + */ low: string; + /** + * Applies to `input`, `meter`, `progress` + * + * Indicates the maximum value allowed. + */ max: string; + /** + * Applies to `input`, `meter` + * + * Indicates the minimum value allowed. + */ min: string; + /** + * Applies to `meter` + * + * Indicates the optimal numeric value. + */ optimum: string; + /** + * Applies to `button`, `data`, `input`, `li`, `meter`, `option`, `progress`, `param` + * + * Defines a default value which will be displayed in the element on page load. + */ value: string; }; object: { + /** + * Applies to `img`, `object`, `table` + * + * The border width. + * + * > Note: This is a legacy attribute. Please use the CSS border property instead. + */ border: string; + /** + * Applies to `object` + * + * Specifies the URL of the resource. + */ data: string; + /** + * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` + * + * Indicates the form that is the owner of the element. + */ form: string; + /** + * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` + * + * Specifies the height of elements listed here. For all other elements, use the CSS height property. + * + * > Note: In some instances, such as `
`, this is a legacy attribute, in which case the CSS height property should be used instead. + */ height: string; + /** + * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` + * + * Name of the element. For example used by the server to identify the fields in form submits. + */ name: string; + /** + * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` + * + * Defines the type of the element. + */ type: string; usemap: string; + /** + * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` + * + * For the elements listed here, this establishes the element's width. + * + * > Note: For all other instances, such as `
`, this is a legacy attribute, in which case the CSS width property should be used instead. + */ width: string; }; ol: { + /** + * Applies to `ol` + * + * Indicates whether the list should be displayed in a descending order instead of a ascending. + */ reversed: string; + /** + * Applies to `ol` + * + * Defines the first number if other than 1. + */ start: string; }; optgroup: { + /** + * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` + * + * Indicates whether the user can interact with the element. + */ disabled: string; + /** + * Applies to `optgroup`, `option`, `track` + * + * Specifies a user-readable title of the element. + */ label: string; }; option: { + /** + * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` + * + * Indicates whether the user can interact with the element. + */ disabled: string; + /** + * Applies to `optgroup`, `option`, `track` + * + * Specifies a user-readable title of the element. + */ label: string; + /** + * Applies to `option` + * + * Defines a value which will be selected on page load. + */ selected: string; + /** + * Applies to `button`, `data`, `input`, `li`, `meter`, `option`, `progress`, `param` + * + * Defines a default value which will be displayed in the element on page load. + */ value: string; }; output: { + /** + * Applies to `label`, `output` + * + * Describes elements which belongs to this one. + */ for: string; + /** + * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` + * + * Indicates the form that is the owner of the element. + */ form: string; + /** + * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` + * + * Name of the element. For example used by the server to identify the fields in form submits. + */ name: string; }; param: { + /** + * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` + * + * Name of the element. For example used by the server to identify the fields in form submits. + */ name: string; + /** + * Applies to `button`, `data`, `input`, `li`, `meter`, `option`, `progress`, `param` + * + * Defines a default value which will be displayed in the element on page load. + */ value: string; }; progress: { + /** + * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` + * + * Indicates the form that is the owner of the element. + */ form: string; + /** + * Applies to `input`, `meter`, `progress` + * + * Indicates the maximum value allowed. + */ max: string; + /** + * Applies to `button`, `data`, `input`, `li`, `meter`, `option`, `progress`, `param` + * + * Defines a default value which will be displayed in the element on page load. + */ value: string; }; q: { + /** + * Applies to `blockquote`, `del`, `ins`, `q` + * + * Contains a URI which points to the source of the quote or change. + */ cite: string; }; script: { + /** + * Applies to `script` + * + * Executes the script asynchronously. + */ async: string; + /** + * Applies to `meta`, `script` + * + * Declares the character encoding of the page or script. + */ charset: string; + /** + * Applies to `audio`, `img`, `link`, `script`, `video` + * + * How the element handles cross-origin requests + */ crossorigin: string; + /** + * Applies to `script` + * + * Indicates that the script should be executed after the page has been parsed. + */ defer: string; + /** + * Applies to `iframe`, `img`, `link`, `script` + * + * Indicates the relative fetch priority for the resource. + */ importance: string; + /** + * Applies to `link`, `script` + * + * Specifies a Subresource Integrity value that allows browsers to verify what they fetch. + */ integrity: string; + /** + * Applies to `a`, `area`, `iframe`, `img`, `link`, `script` + * + * Specifies which referrer is sent when fetching the resource. + */ referrerpolicy: string; + /** + * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` + * + * The URL of the embeddable content. + */ src: string; + /** + * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` + * + * Defines the type of the element. + */ type: string; }; select: { + /** + * Applies to `form`, `input`, `select`, `textarea` + * + * Indicates whether controls in this form can by default have their values automatically completed by the browser. + */ autocomplete: string; + /** + * Applies to `button`, `input`, `keygen`, `select`, `textarea` + * + * The element should be automatically focused after the page loaded. + */ autofocus: string; + /** + * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` + * + * Indicates whether the user can interact with the element. + */ disabled: string; + /** + * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` + * + * Indicates the form that is the owner of the element. + */ form: string; + /** + * Applies to `input`, `select` + * + * Indicates whether multiple values can be entered in an input of the type email or file. + */ multiple: string; + /** + * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` + * + * Name of the element. For example used by the server to identify the fields in form submits. + */ name: string; + /** + * Applies to `input`, `select`, `textarea` + * + * Indicates whether this element is required to fill out or not. + */ required: string; + /** + * Applies to `input`, `select` + * + * Defines the width of the element (in pixels). If the element's type attribute is text or password then it's the number of characters. + */ size: string; }; source: { + /** + * Applies to `a`, `area`, `link`, `source`, `style` + * + * Specifies a hint of the media for which the linked resource was designed. + */ media: string; sizes: string; + /** + * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` + * + * The URL of the embeddable content. + */ src: string; + /** + * Applies to `img`, `source` + * + * One or more responsive image candidates. + */ srcset: string; + /** + * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` + * + * Defines the type of the element. + */ type: string; }; style: { + /** + * Applies to `a`, `area`, `link`, `source`, `style` + * + * Specifies a hint of the media for which the linked resource was designed. + */ media: string; + /** + * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` + * + * Defines the type of the element. + */ type: string; }; table: { + /** + * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` + * + * Specifies the horizontal alignment of the element. + */ align: string; + /** + * Applies to `body`, `table`, `td`, `th` + * + * Specifies the URL of an image file. + * + * > Note: Although browsers and email clients may still support this attribute, it is obsolete. Use CSS background-image instead. + */ background: string; + /** + * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` + * + * Background color of the element. + * + * > Note: This is a legacy attribute. Please use the CSS background-color property instead. + */ bgcolor: string; + /** + * Applies to `img`, `object`, `table` + * + * The border width. + * + * > Note: This is a legacy attribute. Please use the CSS border property instead. + */ border: string; }; tbody: { + /** + * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` + * + * Specifies the horizontal alignment of the element. + */ align: string; + /** + * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` + * + * Background color of the element. + * + * > Note: This is a legacy attribute. Please use the CSS background-color property instead. + */ bgcolor: string; }; td: { + /** + * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` + * + * Specifies the horizontal alignment of the element. + */ align: string; + /** + * Applies to `body`, `table`, `td`, `th` + * + * Specifies the URL of an image file. + * + * > Note: Although browsers and email clients may still support this attribute, it is obsolete. Use CSS background-image instead. + */ background: string; + /** + * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` + * + * Background color of the element. + * + * > Note: This is a legacy attribute. Please use the CSS background-color property instead. + */ bgcolor: string; + /** + * Applies to `td`, `th` + * + * The colspan attribute defines the number of columns a cell should span. + */ colspan: string; + /** + * Applies to `td`, `th` + * + * IDs of the `` elements which applies to this element. + */ headers: string; + /** + * Applies to `td`, `th` + * + * Defines the number of rows a table cell should span over. + */ rowspan: string; }; textarea: { + /** + * Applies to `form`, `input`, `select`, `textarea` + * + * Indicates whether controls in this form can by default have their values automatically completed by the browser. + */ autocomplete: string; + /** + * Applies to `button`, `input`, `keygen`, `select`, `textarea` + * + * The element should be automatically focused after the page loaded. + */ autofocus: string; + /** + * Applies to `textarea` + * + * Defines the number of columns in a textarea. + */ cols: string; dirname: string; + /** + * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` + * + * Indicates whether the user can interact with the element. + */ disabled: string; + /** + * Applies to `textarea`, `contenteditable` + * + * The enterkeyhint specifies what action label (or icon) to present for the enter key on virtual keyboards. The attribute can be used with form controls (such as the value of textarea elements), or in elements in an editing host (e.g., using contenteditable attribute). + */ enterkeyhint: string; + /** + * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` + * + * Indicates the form that is the owner of the element. + */ form: string; + /** + * Applies to `textarea`, `contenteditable` + * + * Provides a hint as to the type of data that might be entered by the user while editing the element or its contents. The attribute can be used with form controls (such as the value of textarea elements), or in elements in an editing host (e.g., using contenteditable attribute). + */ inputmode: string; + /** + * Applies to `input`, `textarea` + * + * Defines the maximum number of characters allowed in the element. + */ maxlength: string; + /** + * Applies to `input`, `textarea` + * + * Defines the minimum number of characters allowed in the element. + */ minlength: string; + /** + * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` + * + * Name of the element. For example used by the server to identify the fields in form submits. + */ name: string; + /** + * Applies to `input`, `textarea` + * + * Provides a hint to the user of what can be entered in the field. + */ placeholder: string; + /** + * Applies to `input`, `textarea` + * + * Indicates whether the element can be edited. + */ readonly: string; + /** + * Applies to `input`, `select`, `textarea` + * + * Indicates whether this element is required to fill out or not. + */ required: string; + /** + * Applies to `textarea` + * + * Defines the number of rows in a text area. + */ rows: string; + /** + * Applies to `textarea` + * + * Indicates whether the text should be wrapped. + */ wrap: string; }; tfoot: { + /** + * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` + * + * Specifies the horizontal alignment of the element. + */ align: string; + /** + * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` + * + * Background color of the element. + * + * > Note: This is a legacy attribute. Please use the CSS background-color property instead. + */ bgcolor: string; }; th: { + /** + * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` + * + * Specifies the horizontal alignment of the element. + */ align: string; + /** + * Applies to `body`, `table`, `td`, `th` + * + * Specifies the URL of an image file. + * + * > Note: Although browsers and email clients may still support this attribute, it is obsolete. Use CSS background-image instead. + */ background: string; + /** + * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` + * + * Background color of the element. + * + * > Note: This is a legacy attribute. Please use the CSS background-color property instead. + */ bgcolor: string; + /** + * Applies to `td`, `th` + * + * The colspan attribute defines the number of columns a cell should span. + */ colspan: string; + /** + * Applies to `td`, `th` + * + * IDs of the `` elements which applies to this element. + */ headers: string; + /** + * Applies to `td`, `th` + * + * Defines the number of rows a table cell should span over. + */ rowspan: string; + /** + * Applies to `th` + * + * Defines the cells that the header test (defined in the th element) relates to. + */ scope: string; }; thead: { + /** + * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` + * + * Specifies the horizontal alignment of the element. + */ align: string; }; time: { + /** + * Applies to `del`, `ins`, `time` + * + * Indicates the date and time associated with the element. + */ datetime: string; }; tr: { + /** + * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` + * + * Specifies the horizontal alignment of the element. + */ align: string; + /** + * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` + * + * Background color of the element. + * + * > Note: This is a legacy attribute. Please use the CSS background-color property instead. + */ bgcolor: string; }; track: { + /** + * Applies to `track` + * + * Indicates that the track should be enabled unless the user's preferences indicate something different. + */ default: string; + /** + * Applies to `track` + * + * Specifies the kind of text track. + */ kind: string; + /** + * Applies to `optgroup`, `option`, `track` + * + * Specifies a user-readable title of the element. + */ label: string; + /** + * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` + * + * The URL of the embeddable content. + */ src: string; srclang: string; }; video: { + /** + * Applies to `audio`, `video` + * + * The audio or video should play as soon as possible. + */ autoplay: string; + /** + * Applies to `audio`, `video` + * + * Contains the time range of already buffered media. + */ buffered: string; + /** + * Applies to `audio`, `video` + * + * Indicates whether the browser should show playback controls to the user. + */ controls: string; + /** + * Applies to `audio`, `img`, `link`, `script`, `video` + * + * How the element handles cross-origin requests + */ crossorigin: string; + /** + * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` + * + * Specifies the height of elements listed here. For all other elements, use the CSS height property. + * + * > Note: In some instances, such as `
`, this is a legacy attribute, in which case the CSS height property should be used instead. + */ height: string; + /** + * Applies to `audio`, `bgsound`, `marquee`, `video` + * + * Indicates whether the media should start playing from the start when it's finished. + */ loop: string; + /** + * Applies to `audio`, `video` + * + * Indicates whether the audio will be initially silenced on page load. + */ muted: string; + /** + * Applies to `video` + * + * A URL indicating a poster frame to show until the user plays or seeks. + */ poster: string; + /** + * Applies to `audio`, `video` + * + * Indicates whether the whole resource, parts of it or nothing should be preloaded. + */ preload: string; + /** + * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` + * + * The URL of the embeddable content. + */ src: string; + /** + * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` + * + * For the elements listed here, this establishes the element's width. + * + * > Note: For all other instances, such as `
`, this is a legacy attribute, in which case the CSS width property should be used instead. + */ width: string; }; [k: string]: unknown; From b8338fe81a2bb200be0da06147b77fd48136f8b5 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Fri, 2 Jul 2021 00:03:50 +0530 Subject: [PATCH 032/254] (refactor) elementToType Signed-off-by: Muthu Kumar --- scripts/fetchAttributes.ts | 41 ++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/scripts/fetchAttributes.ts b/scripts/fetchAttributes.ts index 5b3a0a0..d4ad630 100644 --- a/scripts/fetchAttributes.ts +++ b/scripts/fetchAttributes.ts @@ -46,8 +46,6 @@ const { "Global attribute": globalAttr, ...elements } = groupByList( .sort((a, b) => a.attr.localeCompare(b.attr)), ); -console.log({ elements }); - const getKeyStr = (key: string) => (key.includes("-") ? `["${key}"]` : key); const globalOrElems = (elements: string[]) => @@ -66,6 +64,22 @@ const docLine = (line: string) => { return " * " + line; }; +const getDesc = (attr: Attribute & { type: string }, indent: string) => + attr.desc && + indent + + "/**\n" + + indent + + [globalOrElems(attr.elements)] + .concat(attr.desc.replace("\n\n", "\n").split("\n")) + .map(docLine) + .filter(Boolean) + .join("\n" + indent + " *\n" + indent) + + ("\n" + indent + " */\n"); + +const transformAttr = + (indent: string) => (attr: Attribute & { type: string }) => + getDesc(attr, indent) + `${indent}${getKeyStr(attr.attr)}: string;`; + const elementToType = ( el: string, attrs: (Attribute & { type: string })[], @@ -74,28 +88,7 @@ const elementToType = ( const indent = "\t".repeat(root ? 1 : 2); return [ `${el}${root ? " =" : ":"} {`, - indent + - attrs - .map( - attr => - (attr.desc && - "/**\n" + - indent + - [ - globalOrElems(attr.elements), - ...attr.desc - .replace("\n\n", "\n") - .split("\n"), - ] - .map(docLine) - .filter(Boolean) - .join("\n" + indent + " *\n" + indent) + - "\n" + - indent + - " */\n" + - indent) + `${getKeyStr(attr.attr)}: string;`, - ) - .join("\n" + indent), + attrs.map(transformAttr(indent)).join("\n"), "\t".repeat(root ? 0 : 1) + "};", ].join("\n"); }; From c5873de7f6ad4b7f75f064bf60ea7c55991eef52 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Fri, 2 Jul 2021 02:05:23 +0530 Subject: [PATCH 033/254] (feat) codegen util Signed-off-by: Muthu Kumar --- scripts/codegen.ts | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 scripts/codegen.ts diff --git a/scripts/codegen.ts b/scripts/codegen.ts new file mode 100644 index 0000000..5f42c06 --- /dev/null +++ b/scripts/codegen.ts @@ -0,0 +1,49 @@ +type Prop = { + prop: string; + desc: string; + type: string; +}; + +const getKeyStr = (key: string) => (key.includes("-") ? `["${key}"]` : key); + +const docLine = (line: string) => { + line = line.trim(); + if (!line) return ""; + line = line.replace( + /<|>/g, + s => ({ "<": "`<", ">": ">`" }[s as "<" | ">"]), + ); + if (line.startsWith("Note")) line = "> " + line; + return " * " + line; +}; + +const getDesc = (prop: Prop, indent: string) => + prop.desc && + indent + + "/**\n" + + indent + + prop.desc + .replace("\n\n", "\n") + .split("\n") + .map(docLine) + .filter(Boolean) + .join("\n" + indent + " *\n" + indent) + + ("\n" + indent + " */\n"); + +const transformProp = (indent: string) => (prop: Prop) => + getDesc(prop, indent) + `${indent}${getKeyStr(prop.prop)}: ${prop.type};`; + +export const propsToType = ( + name: string, + props: Prop[], + { partial, root }: { partial?: boolean; root?: boolean } = {}, +) => { + const indent = "\t".repeat(root ? 1 : 2); + const op = (partial ? "Partial<" : "") + "{"; + const ed = "}" + (partial ? ">" : ""); + return [ + `${name}${root ? " =" : ":"} ${op}`, + props.map(transformProp(indent)).join("\n"), + "\t".repeat(root ? 0 : 1) + ed + ";", + ].join("\n"); +}; From 71b07304b0a3e506f4906d99151ac98370708671 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Fri, 2 Jul 2021 02:06:08 +0530 Subject: [PATCH 034/254] (feat) tsdoc for ARIA attributes Signed-off-by: Muthu Kumar --- scripts/fetchARIA.ts | 37 +++++---- src/aria.ts | 182 +++++++++++++++++++++++++++++++++---------- 2 files changed, 166 insertions(+), 53 deletions(-) diff --git a/scripts/fetchARIA.ts b/scripts/fetchARIA.ts index 2f57ebb..dba799e 100644 --- a/scripts/fetchARIA.ts +++ b/scripts/fetchARIA.ts @@ -1,5 +1,12 @@ import { DOMParser } from "https://deno.land/x/deno_dom@v0.1.12-alpha/deno-dom-wasm.ts"; +import { propsToType } from "./codegen.ts"; + +const chunk = (arr: X[], size: number): X[][] => + Array.from({ length: Math.ceil(arr.length / size) }, (_, i) => + arr.slice(i * size, i * size + size), + ); + { const html = await fetch("https://w3c.github.io/using-aria/") // @@ -29,19 +36,23 @@ import { DOMParser } from "https://deno.land/x/deno_dom@v0.1.12-alpha/deno-dom-w const document = new DOMParser().parseFromString(html, "text/html")!; - const attributes = [...document.querySelectorAll("#index_state_prop code")] - .map(each => each.textContent.trim()) - .filter(Boolean) - .map(each => `"${each.replace("aria-", "")}"`); - - const types = [ - "export type AriaAttributes = Partial<", - " Record<", - ` | ${attributes.join("\n\t\t| ")},`, - " string", - " >", - ">;\n", - ].join("\n"); + const allData = [ + ...document.querySelectorAll( + "#index_state_prop dt, #index_state_prop dd", + ), + ]; + + const attributeTypes = propsToType( + "AriaAttributes", + chunk(allData, 2).map(([dt, dd]) => ({ + prop: dt.textContent.replace(/\(state\)|aria-/g, "").trim(), + desc: dd.textContent.trim(), + type: "string", + })), + { root: true, partial: true }, + ); + + const types = ["export type " + attributeTypes + "\n"].join("\n"); Deno.writeTextFileSync("./src/aria.ts", types, { append: true }); } diff --git a/src/aria.ts b/src/aria.ts index 5939bfd..ea5136a 100644 --- a/src/aria.ts +++ b/src/aria.ts @@ -31,43 +31,145 @@ export type AriaRoles = | "treegrid" | "treeitem"; -export type AriaAttributes = Partial< - Record< - | "activedescendant" - | "atomic" - | "autocomplete" - | "busy" - | "checked" - | "controls" - | "describedby" - | "disabled" - | "dropeffect" - | "expanded" - | "flowto" - | "grabbed" - | "haspopup" - | "hidden" - | "invalid" - | "label" - | "labelledby" - | "level" - | "live" - | "multiline" - | "multiselectable" - | "orientation" - | "owns" - | "posinset" - | "pressed" - | "readonly" - | "relevant" - | "required" - | "selected" - | "setsize" - | "sort" - | "valuemax" - | "valuemin" - | "valuenow" - | "valuetext", - string - > ->; +export type AriaAttributes = Partial<{ + /** + * Identifies the currently active descendant of a composite widget. + */ + activedescendant: string; + /** + * Indicates whether assistive technologies will present all, or only parts of, the changed region based on the change notifications defined by the aria-relevant attribute. See related aria-relevant. + */ + atomic: string; + /** + * Indicates whether user input completion suggestions are provided. + */ + autocomplete: string; + /** + * Indicates whether an element, and its subtree, are currently being updated. + */ + busy: string; + /** + * Indicates the current "checked" state of checkboxes, radio buttons, and other widgets. See related aria-pressed and aria-selected. + */ + checked: string; + /** + * Identifies the element (or elements) whose contents or presence are controlled by the current element. See related aria-owns. + */ + controls: string; + /** + * Identifies the element (or elements) that describes the object. See related aria-labelledby. + */ + describedby: string; + /** + * Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable. See related aria-hidden and aria-readonly. + */ + disabled: string; + /** + * Indicates what functions can be performed when the dragged object is released on the drop target. This allows assistive technologies to convey the possible drag options available to users, including whether a pop-up menu of choices is provided by the application. Typically, drop effect functions can only be provided once an object has been grabbed for a drag operation as the drop effect functions available are dependent on the object being dragged. + */ + dropeffect: string; + /** + * Indicates whether the element, or another grouping element it controls, is currently expanded or collapsed. + */ + expanded: string; + /** + * Identifies the next element (or elements) in an alternate reading order of content which, at the user's discretion, allows assistive technology to override the general default of reading in document source order. + */ + flowto: string; + /** + * Indicates an element's "grabbed" state in a drag-and-drop operation. + */ + grabbed: string; + /** + * Indicates that the element has a popup context menu or sub-level menu. + */ + haspopup: string; + /** + * Indicates that the element and all of its descendants are not visible or perceivable to any user as implemented by the author. See related aria-disabled. + */ + hidden: string; + /** + * Indicates the entered value does not conform to the format expected by the application. + */ + invalid: string; + /** + * Defines a string value that labels the current element. See related aria-labelledby. + */ + label: string; + /** + * Identifies the element (or elements) that labels the current element. See related aria-label and aria-describedby. + */ + labelledby: string; + /** + * Defines the hierarchical level of an element within a structure. + */ + level: string; + /** + * Indicates that an element will be updated, and describes the types of updates the user agents, assistive technologies, and user can expect from the live region. + */ + live: string; + /** + * Indicates whether a text box accepts multiple lines of input or only a single line. + */ + multiline: string; + /** + * Indicates that the user may select more than one item from the current selectable descendants. + */ + multiselectable: string; + /** + * Indicates whether the element and orientation is horizontal or vertical. + */ + orientation: string; + /** + * Identifies an element (or elements) in order to define a visual, functional, or contextual parent/child relationship between DOM elements where the DOM hierarchy cannot be used to represent the relationship. See related aria-controls. + */ + owns: string; + /** + * Defines an element's number or position in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM. See related aria-setsize. + */ + posinset: string; + /** + * Indicates the current "pressed" state of toggle buttons. See related aria-checked and aria-selected. + */ + pressed: string; + /** + * Indicates that the element is not editable, but is otherwise operable. See related aria-disabled. + */ + readonly: string; + /** + * Indicates what user agent change notifications (additions, removals, etc.) assistive technologies will receive within a live region. See related aria-atomic. + */ + relevant: string; + /** + * Indicates that user input is required on the element before a form may be submitted. + */ + required: string; + /** + * Indicates the current "selected" state of various widgets. See related aria-checked and aria-pressed. + */ + selected: string; + /** + * Defines the number of items in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM. See related aria-posinset. + */ + setsize: string; + /** + * Indicates if items in a table or grid are sorted in ascending or descending order. + */ + sort: string; + /** + * Defines the maximum allowed value for a range widget. + */ + valuemax: string; + /** + * Defines the minimum allowed value for a range widget. + */ + valuemin: string; + /** + * Defines the current value for a range widget. See related aria-valuetext. + */ + valuenow: string; + /** + * Defines the human readable text alternative of aria-valuenow for a range widget. + */ + valuetext: string; +}>; From 3a19f9eb5272929e3a74592787480979fb3d0522 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Fri, 2 Jul 2021 02:06:38 +0530 Subject: [PATCH 035/254] (feat) use codegen and add role & aria tsdoc Signed-off-by: Muthu Kumar --- scripts/fetchAttributes.ts | 97 +++++++++++++++----------------------- src/attributes.ts | 66 ++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 59 deletions(-) diff --git a/scripts/fetchAttributes.ts b/scripts/fetchAttributes.ts index d4ad630..0fe84a0 100644 --- a/scripts/fetchAttributes.ts +++ b/scripts/fetchAttributes.ts @@ -1,18 +1,20 @@ import { DOMParser } from "https://deno.land/x/deno_dom@v0.1.12-alpha/deno-dom-wasm.ts"; +import { propsToType } from "./codegen.ts"; + const html = await fetch( "https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes", ).then(res => res.text()); const document = new DOMParser().parseFromString(html, "text/html")!; -type Attribute = { attr: string; elements: string[]; desc: string }; +type Attribute = { prop: string; elements: string[]; desc: string }; const groupByList = (xs: Attribute[]) => xs.reduce((acc, curr) => { for (const element of curr.elements) { (acc[element] || (acc[element] = [])).push({ - attr: curr.attr, + prop: curr.prop, elements: curr.elements, type: "string", desc: curr.desc, @@ -22,6 +24,11 @@ const groupByList = (xs: Attribute[]) => return acc; }, {} as Record); +const globalOrElems = (elements: string[]) => + elements.includes("Global attribute") + ? "Global attribute" + : "Applies to " + elements.map(e => "`" + e + "`").join(", "); + const { "Global attribute": globalAttr, ...elements } = groupByList( [ ...document.querySelector("article table.standard-table tbody") @@ -34,72 +41,29 @@ const { "Global attribute": globalAttr, ...elements } = groupByList( !(tr.innerHTML as string).includes(`"icon icon-deprecated"`), ) .map(tr => [...tr.childNodes!].map(each => each.textContent)) - .map(([, attr, , elements, , desc]) => ({ - attr: attr.trim(), - elements: elements + .map(([, attr, , elems, , desc]) => { + const elements = elems .replaceAll(/<|>/g, "") .split(/,\s+/) - .map(e => e.trim()), - desc: desc.trim(), - })) - .filter(each => each.attr !== "data-*") - .sort((a, b) => a.attr.localeCompare(b.attr)), + .map(e => e.trim()); + + return { + prop: attr.trim(), + elements, + desc: [globalOrElems(elements), desc.trim()].join("\n"), + }; + }) + .filter(each => each.prop !== "data-*") + .sort((a, b) => a.prop.localeCompare(b.prop)), ); -const getKeyStr = (key: string) => (key.includes("-") ? `["${key}"]` : key); - -const globalOrElems = (elements: string[]) => - elements.includes("Global attribute") - ? "Global attribute" - : "Applies to " + elements.map(e => "`" + e + "`").join(", "); - -const docLine = (line: string) => { - line = line.trim(); - if (!line) return ""; - line = line.replace( - /<|>/g, - s => ({ "<": "`<", ">": ">`" }[s as "<" | ">"]), - ); - if (line.startsWith("Note")) line = "> " + line; - return " * " + line; -}; - -const getDesc = (attr: Attribute & { type: string }, indent: string) => - attr.desc && - indent + - "/**\n" + - indent + - [globalOrElems(attr.elements)] - .concat(attr.desc.replace("\n\n", "\n").split("\n")) - .map(docLine) - .filter(Boolean) - .join("\n" + indent + " *\n" + indent) + - ("\n" + indent + " */\n"); - -const transformAttr = - (indent: string) => (attr: Attribute & { type: string }) => - getDesc(attr, indent) + `${indent}${getKeyStr(attr.attr)}: string;`; - -const elementToType = ( - el: string, - attrs: (Attribute & { type: string })[], - { root }: { root?: boolean } = {}, -) => { - const indent = "\t".repeat(root ? 1 : 2); - return [ - `${el}${root ? " =" : ":"} {`, - attrs.map(transformAttr(indent)).join("\n"), - "\t".repeat(root ? 0 : 1) + "};", - ].join("\n"); -}; - -const globalTypes = elementToType("GlobalAttrs", globalAttr, { +const globalTypes = propsToType("GlobalAttrs", globalAttr, { root: true, }); const elementTypes = Object.keys(elements) .sort((a, b) => a.localeCompare(b)) - .map(element => elementToType(element, elements[element])) + .map(element => propsToType(element, elements[element])) .join("\n\t"); const types = `import { Element } from "./elements.ts"; @@ -119,7 +83,22 @@ export type Attr = // { [data in DataAttr]?: string } Partial< GlobalAttrs & { + /** + * When the element lacks suitable ARIA-semantics, authors must + * assign an ARIA-role. Addition of ARIA semantics only exposes + * extra information to a browser's accessibility API, and does + * not affect a page's DOM. + * + * @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques + */ role?: AriaRoles; + /** + * ARIA is a set of attributes that define ways to make web content + * and web applications (especially those developed with JavaScript) + * more accessible to people with disabilities. + * + * @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA + */ aria?: AriaAttributes; } & ElementAttrs[E] >; diff --git a/src/attributes.ts b/src/attributes.ts index ddab516..eac81c8 100644 --- a/src/attributes.ts +++ b/src/attributes.ts @@ -56,6 +56,9 @@ type GlobalAttrs = { * Often used with CSS to style a specific element. The value of this attribute must be unique. */ id: string; + /** + * Global attribute + */ itemprop: string; /** * Global attribute @@ -145,6 +148,9 @@ type ElementAttrs = { * Specifies the relationship of the target object to the link object. */ rel: string; + /** + * Applies to `a`, `area` + */ shape: string; /** * Applies to `a`, `area`, `base`, `form` @@ -234,6 +240,9 @@ type ElementAttrs = { * Specifies the relationship of the target object to the link object. */ rel: string; + /** + * Applies to `a`, `area` + */ shape: string; /** * Applies to `a`, `area`, `base`, `form` @@ -459,6 +468,9 @@ type ElementAttrs = { * > Note: This is a legacy attribute. Please use the CSS background-color property instead. */ bgcolor: string; + /** + * Applies to `col`, `colgroup` + */ span: string; }; colgroup: { @@ -476,6 +488,9 @@ type ElementAttrs = { * > Note: This is a legacy attribute. Please use the CSS background-color property instead. */ bgcolor: string; + /** + * Applies to `col`, `colgroup` + */ span: string; }; command: { @@ -497,6 +512,9 @@ type ElementAttrs = { * Specifies a picture which represents the command. */ icon: string; + /** + * Applies to `command` + */ radiogroup: string; /** * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` @@ -746,6 +764,9 @@ type ElementAttrs = { * The URL of the embeddable content. */ src: string; + /** + * Applies to `iframe` + */ srcdoc: string; /** * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` @@ -823,6 +844,9 @@ type ElementAttrs = { * Specifies which referrer is sent when fetching the resource. */ referrerpolicy: string; + /** + * Applies to `link`, `img`, `source` + */ sizes: string; /** * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` @@ -836,6 +860,9 @@ type ElementAttrs = { * One or more responsive image candidates. */ srcset: string; + /** + * Applies to `img`, `input`, `object` + */ usemap: string; /** * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` @@ -883,6 +910,9 @@ type ElementAttrs = { * Indicates whether the element should be checked on page load. */ checked: string; + /** + * Applies to `input`, `textarea` + */ dirname: string; /** * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` @@ -1012,6 +1042,9 @@ type ElementAttrs = { * The URL of the embeddable content. */ src: string; + /** + * Applies to `input` + */ step: string; /** * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` @@ -1019,6 +1052,9 @@ type ElementAttrs = { * Defines the type of the element. */ type: string; + /** + * Applies to `img`, `input`, `object` + */ usemap: string; /** * Applies to `button`, `data`, `input`, `li`, `meter`, `option`, `progress`, `param` @@ -1158,6 +1194,9 @@ type ElementAttrs = { * Specifies the relationship of the target object to the link object. */ rel: string; + /** + * Applies to `link`, `img`, `source` + */ sizes: string; }; map: { @@ -1303,6 +1342,9 @@ type ElementAttrs = { * Defines the type of the element. */ type: string; + /** + * Applies to `img`, `input`, `object` + */ usemap: string; /** * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` @@ -1542,6 +1584,9 @@ type ElementAttrs = { * Specifies a hint of the media for which the linked resource was designed. */ media: string; + /** + * Applies to `link`, `img`, `source` + */ sizes: string; /** * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` @@ -1685,6 +1730,9 @@ type ElementAttrs = { * Defines the number of columns in a textarea. */ cols: string; + /** + * Applies to `input`, `textarea` + */ dirname: string; /** * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` @@ -1880,6 +1928,9 @@ type ElementAttrs = { * The URL of the embeddable content. */ src: string; + /** + * Applies to `track` + */ srclang: string; }; video: { @@ -1964,7 +2015,22 @@ export type Attr = // { [data in DataAttr]?: string } Partial< GlobalAttrs & { + /** + * When the element lacks suitable ARIA-semantics, authors must + * assign an ARIA-role. Addition of ARIA semantics only exposes + * extra information to a browser's accessibility API, and does + * not affect a page's DOM. + * + * @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques + */ role?: AriaRoles; + /** + * ARIA is a set of attributes that define ways to make web content + * and web applications (especially those developed with JavaScript) + * more accessible to people with disabilities. + * + * @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA + */ aria?: AriaAttributes; } & ElementAttrs[E] >; From 0776f79d72c9e3f0c2a44d2955680fab6680acbd Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Fri, 2 Jul 2021 04:28:06 +0530 Subject: [PATCH 036/254] (feat) get special types for attributes Signed-off-by: Muthu Kumar --- scripts/getSplType.ts | 100 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 scripts/getSplType.ts diff --git a/scripts/getSplType.ts b/scripts/getSplType.ts new file mode 100644 index 0000000..ce78886 --- /dev/null +++ b/scripts/getSplType.ts @@ -0,0 +1,100 @@ +import { DOMParser } from "https://deno.land/x/deno_dom@v0.1.12-alpha/deno-dom-wasm.ts"; + +const html = await fetch( + "https://html.spec.whatwg.org/multipage/indices.html", +).then(res => res.text()); + +const document = new DOMParser().parseFromString(html, "text/html")!; + +const rows = [...document.querySelectorAll("#attributes-1 tbody tr")] + .map(row => [...row.children]) + .map(([name, , , value]) => ({ + name: name.textContent.trim(), + value: value.textContent.trim(), + })); + +type Entry = [string, (el: string) => string | null]; + +const boolean: Entry[] = [ + ...new Set( + rows + .filter(row => row.value === "Boolean attribute") + .map(row => row.name), + ), +].map(name => [name, () => "boolean"]); + +const isEnum = /(".+";\s*)*(".+"\s*)/; + +const union = (...parts: string[]) => + parts.map(part => `"${part}"`).join(" | "); + +const mime = "`${string}/${string}`"; + +const manual: Entry[] = [ + ["as", () => `string`], + ["step", () => `number | "any"`], + [ + "dir", + (el: string) => + el === "bdo" ? union("ltr", "rtl") : union("ltr", "rtl", "auto"), + ], + [ + "type", + (el: string) => + ({ + a: mime, + link: mime, + embed: mime, + object: mime, + source: mime, + button: union("submit", "reset", "button"), + ol: union("1", "a", "A", "i", "I"), + script: union("module", mime), + input: union( + "hidden", + "text", + "search", + "tel", + "url", + "email", + "password", + "date", + "month", + "week", + "time", + "datetime", + "number", + "range", + "color", + "checkbox", + "radio", + "file", + "submit", + "image", + "reset", + "button", + ), + }[el] || null), + ], +]; + +const parseEnum = (str: string) => + [...str.matchAll(/"\S+"/g)].flat().map(each => each.replaceAll('"', "")); + +const enums = rows + .filter(row => isEnum.test(row.value.trim())) + .filter(row => !manual.map(each => each[0]).includes(row.name)) + .map(row => [row.name, union(...(parseEnum(row.value) || []))]) + .map(([name, union]): Entry => [name, () => union]); + +const def = () => null; + +const specialTypes = Object.fromEntries( + ([] as Entry[]).concat(boolean, enums, manual), +); + +const specialKeys = new Set(Object.keys(specialTypes)); + +export const isSpecial = (attr: string) => specialKeys.has(attr); + +export const getSplType = (attr: string) => specialTypes[attr] || def; From 8eb7da40be77ba946730450d7d42f9d8d9501467 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Fri, 2 Jul 2021 04:29:00 +0530 Subject: [PATCH 037/254] (feat) update special attributes, render supports the change, and tests Signed-off-by: Muthu Kumar --- scripts/fetchAttributes.ts | 50 ++- src/attributes.ts | 885 +++++-------------------------------- src/render.ts | 27 +- test.ts | 21 +- 4 files changed, 189 insertions(+), 794 deletions(-) diff --git a/scripts/fetchAttributes.ts b/scripts/fetchAttributes.ts index 0fe84a0..0653a89 100644 --- a/scripts/fetchAttributes.ts +++ b/scripts/fetchAttributes.ts @@ -1,6 +1,7 @@ import { DOMParser } from "https://deno.land/x/deno_dom@v0.1.12-alpha/deno-dom-wasm.ts"; import { propsToType } from "./codegen.ts"; +import { getSplType } from "./getSplType.ts"; const html = await fetch( "https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes", @@ -24,11 +25,6 @@ const groupByList = (xs: Attribute[]) => return acc; }, {} as Record); -const globalOrElems = (elements: string[]) => - elements.includes("Global attribute") - ? "Global attribute" - : "Applies to " + elements.map(e => "`" + e + "`").join(", "); - const { "Global attribute": globalAttr, ...elements } = groupByList( [ ...document.querySelector("article table.standard-table tbody") @@ -50,20 +46,38 @@ const { "Global attribute": globalAttr, ...elements } = groupByList( return { prop: attr.trim(), elements, - desc: [globalOrElems(elements), desc.trim()].join("\n"), + desc: desc.trim(), }; }) .filter(each => each.prop !== "data-*") .sort((a, b) => a.prop.localeCompare(b.prop)), ); -const globalTypes = propsToType("GlobalAttrs", globalAttr, { - root: true, -}); +const customDesc: Record = { + height: "Specifies the height of the element.", + width: "Specifies the width of the element.", +}; + +const composeCustom = (attr: Attribute & { type: string }, element?: string) => + Object.assign(attr, { + desc: customDesc[attr.prop] || attr.desc, + type: getSplType(attr.prop)(element || "global") || "string", + }); + +const globalTypes = propsToType( + "GlobalAttrs", + globalAttr.map(attr => composeCustom(attr)), + { root: true }, +); const elementTypes = Object.keys(elements) .sort((a, b) => a.localeCompare(b)) - .map(element => propsToType(element, elements[element])) + .map(element => + propsToType( + element, + elements[element].map(attr => composeCustom(attr, element)), + ), + ) .join("\n\t"); const types = `import { Element } from "./elements.ts"; @@ -73,9 +87,17 @@ type ${globalTypes} type ElementAttrs = { ${elementTypes} - [k: string]: unknown; }; +type PropOr = + T extends Record ? V : D; + +type Deunionize = + | ([undefined] extends [T] ? undefined : never) + | { [K in T extends unknown ? keyof T : never]: PropOr, K, undefined>; }; + +export type AllAttrs = Partial>; + export type DataAttr = ${"`data-${string}`"}; export type Attr = @@ -91,7 +113,7 @@ export type Attr = * * @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques */ - role?: AriaRoles; + role: AriaRoles; /** * ARIA is a set of attributes that define ways to make web content * and web applications (especially those developed with JavaScript) @@ -99,8 +121,8 @@ export type Attr = * * @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA */ - aria?: AriaAttributes; - } & ElementAttrs[E] + aria: AriaAttributes; + } & (ElementAttrs & { [k: string]: unknown })[E] >; `; diff --git a/src/attributes.ts b/src/attributes.ts index eac81c8..ebd575c 100644 --- a/src/attributes.ts +++ b/src/attributes.ts @@ -3,322 +3,215 @@ import { AriaRoles, AriaAttributes } from "./aria.ts"; type GlobalAttrs = { /** - * Global attribute - * * Keyboard shortcut to activate or add focus to the element. */ accesskey: string; /** - * Global attribute - * * Sets whether input is automatically capitalized when entered by user */ - autocapitalize: string; + autocapitalize: "on" | "off" | "none" | "sentences" | "words" | "characters"; /** - * Global attribute - * * Often used with CSS to style elements with common properties. */ class: string; /** - * Global attribute - * * Indicates whether the element's content is editable. */ - contenteditable: string; + contenteditable: "true" | "false"; /** - * Global attribute - * * Defines the ID of a `` element which will serve as the element's context menu. */ contextmenu: string; /** - * Global attribute - * * Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left) */ - dir: string; + dir: "ltr" | "rtl" | "auto"; /** - * Global attribute - * * Defines whether the element can be dragged. */ - draggable: string; + draggable: "true" | "false"; /** - * Global attribute - * * Prevents rendering of given element, while keeping child elements, e.g. script elements, active. */ - hidden: string; + hidden: boolean; /** - * Global attribute - * * Often used with CSS to style a specific element. The value of this attribute must be unique. */ id: string; - /** - * Global attribute - */ itemprop: string; /** - * Global attribute - * * Defines the language used in the element. */ lang: string; /** - * Global attribute - * * Assigns a slot in a shadow DOM shadow tree to an element. */ slot: string; /** - * Global attribute - * * Indicates whether spell checking is allowed for the element. */ - spellcheck: string; + spellcheck: "true" | "false"; /** - * Global attribute - * * Defines CSS styles which will override styles previously set. */ style: string; /** - * Global attribute - * * Overrides the browser's default tab order and follows the one specified instead. */ tabindex: string; /** - * Global attribute - * * Text to be displayed in a tooltip when hovering over the element. */ title: string; /** - * Global attribute - * * Specify whether an element’s attribute values and the values of its Text node children are to be translated when the page is localized, or whether to leave them unchanged. */ - translate: string; + translate: "yes" | "no"; }; type ElementAttrs = { a: { /** - * Applies to `a`, `area` - * * Indicates that the hyperlink is to be used for downloading a resource. */ download: string; /** - * Applies to `a`, `area`, `base`, `link` - * * The URL of a linked resource. */ href: string; /** - * Applies to `a`, `area`, `link` - * * Specifies the language of the linked resource. */ hreflang: string; /** - * Applies to `a`, `area`, `link`, `source`, `style` - * * Specifies a hint of the media for which the linked resource was designed. */ media: string; /** - * Applies to `a`, `area` - * * The ping attribute specifies a space-separated list of URLs to be notified if a user follows the hyperlink. */ ping: string; /** - * Applies to `a`, `area`, `iframe`, `img`, `link`, `script` - * * Specifies which referrer is sent when fetching the resource. */ referrerpolicy: string; /** - * Applies to `a`, `area`, `link` - * * Specifies the relationship of the target object to the link object. */ rel: string; + shape: "circle" | "default" | "poly" | "rect"; /** - * Applies to `a`, `area` - */ - shape: string; - /** - * Applies to `a`, `area`, `base`, `form` - * * Specifies where to open the linked document (in the case of an `` element) or where to display the response received (in the case of a `` element) */ target: string; }; applet: { /** - * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` - * * Specifies the horizontal alignment of the element. */ align: string; /** - * Applies to `applet`, `area`, `img`, `input` - * * Alternative text in case an image can't be displayed. */ alt: string; /** - * Applies to `applet` - * * Specifies the URL of the applet's class file to be loaded and executed. */ code: string; /** - * Applies to `applet` - * * This attribute gives the absolute or relative URL of the directory where applets' .class files referenced by the code attribute are stored. */ codebase: string; }; area: { /** - * Applies to `applet`, `area`, `img`, `input` - * * Alternative text in case an image can't be displayed. */ alt: string; /** - * Applies to `area` - * * A set of values specifying the coordinates of the hot-spot region. */ coords: string; /** - * Applies to `a`, `area` - * * Indicates that the hyperlink is to be used for downloading a resource. */ download: string; /** - * Applies to `a`, `area`, `base`, `link` - * * The URL of a linked resource. */ href: string; /** - * Applies to `a`, `area`, `link` - * * Specifies the language of the linked resource. */ hreflang: string; /** - * Applies to `a`, `area`, `link`, `source`, `style` - * * Specifies a hint of the media for which the linked resource was designed. */ media: string; /** - * Applies to `a`, `area` - * * The ping attribute specifies a space-separated list of URLs to be notified if a user follows the hyperlink. */ ping: string; /** - * Applies to `a`, `area`, `iframe`, `img`, `link`, `script` - * * Specifies which referrer is sent when fetching the resource. */ referrerpolicy: string; /** - * Applies to `a`, `area`, `link` - * * Specifies the relationship of the target object to the link object. */ rel: string; + shape: "circle" | "default" | "poly" | "rect"; /** - * Applies to `a`, `area` - */ - shape: string; - /** - * Applies to `a`, `area`, `base`, `form` - * * Specifies where to open the linked document (in the case of an `` element) or where to display the response received (in the case of a `` element) */ target: string; }; audio: { /** - * Applies to `audio`, `video` - * * The audio or video should play as soon as possible. */ - autoplay: string; + autoplay: boolean; /** - * Applies to `audio`, `video` - * * Contains the time range of already buffered media. */ buffered: string; /** - * Applies to `audio`, `video` - * * Indicates whether the browser should show playback controls to the user. */ - controls: string; + controls: boolean; /** - * Applies to `audio`, `img`, `link`, `script`, `video` - * * How the element handles cross-origin requests */ - crossorigin: string; + crossorigin: "anonymous" | "use-credentials"; /** - * Applies to `audio`, `bgsound`, `marquee`, `video` - * * Indicates whether the media should start playing from the start when it's finished. */ - loop: string; + loop: boolean; /** - * Applies to `audio`, `video` - * * Indicates whether the audio will be initially silenced on page load. */ - muted: string; + muted: boolean; /** - * Applies to `audio`, `video` - * * Indicates whether the whole resource, parts of it or nothing should be preloaded. */ - preload: string; + preload: "none" | "metadata" | "auto"; /** - * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` - * * The URL of the embeddable content. */ src: string; }; base: { /** - * Applies to `a`, `area`, `base`, `link` - * * The URL of a linked resource. */ href: string; /** - * Applies to `a`, `area`, `base`, `form` - * * Specifies where to open the linked document (in the case of an `` element) or where to display the response received (in the case of a `` element) */ target: string; }; basefont: { /** - * Applies to `basefont`, `font`, `hr` - * * This attribute sets the text color using either a named color or a color specified in the hexadecimal #RRGGBB format. * * > Note: This is a legacy attribute. Please use the CSS color property instead. @@ -327,32 +220,24 @@ type ElementAttrs = { }; bgsound: { /** - * Applies to `audio`, `bgsound`, `marquee`, `video` - * * Indicates whether the media should start playing from the start when it's finished. */ - loop: string; + loop: boolean; }; blockquote: { /** - * Applies to `blockquote`, `del`, `ins`, `q` - * * Contains a URI which points to the source of the quote or change. */ cite: string; }; body: { /** - * Applies to `body`, `table`, `td`, `th` - * * Specifies the URL of an image file. * * > Note: Although browsers and email clients may still support this attribute, it is obsolete. Use CSS background-image instead. */ background: string; /** - * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` - * * Background color of the element. * * > Note: This is a legacy attribute. Please use the CSS background-color property instead. @@ -361,266 +246,177 @@ type ElementAttrs = { }; button: { /** - * Applies to `button`, `input`, `keygen`, `select`, `textarea` - * * The element should be automatically focused after the page loaded. */ - autofocus: string; + autofocus: boolean; /** - * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` - * * Indicates whether the user can interact with the element. */ - disabled: string; + disabled: boolean; /** - * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` - * * Indicates the form that is the owner of the element. */ form: string; /** - * Applies to `input`, `button` - * * Indicates the action of the element, overriding the action defined in the ``. */ formaction: string; /** - * Applies to `button`, `input` - * * If the button/input is a submit button (type="submit"), this attribute sets the encoding type to use during form submission. If this attribute is specified, it overrides the enctype attribute of the button's form owner. */ - formenctype: string; + formenctype: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain"; /** - * Applies to `button`, `input` - * * If the button/input is a submit button (type="submit"), this attribute sets the submission method to use during form submission (GET, POST, etc.). If this attribute is specified, it overrides the method attribute of the button's form owner. */ - formmethod: string; + formmethod: "GET" | "POST" | "dialog"; /** - * Applies to `button`, `input` - * * If the button/input is a submit button (type="submit"), this boolean attribute specifies that the form is not to be validated when it is submitted. If this attribute is specified, it overrides the novalidate attribute of the button's form owner. */ - formnovalidate: string; + formnovalidate: boolean; /** - * Applies to `button`, `input` - * * If the button/input is a submit button (type="submit"), this attribute specifies the browsing context (for example, tab, window, or inline frame) in which to display the response that is received after submitting the form. If this attribute is specified, it overrides the target attribute of the button's form owner. */ formtarget: string; /** - * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` - * * Name of the element. For example used by the server to identify the fields in form submits. */ name: string; /** - * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` - * * Defines the type of the element. */ - type: string; + type: "submit" | "reset" | "button"; /** - * Applies to `button`, `data`, `input`, `li`, `meter`, `option`, `progress`, `param` - * * Defines a default value which will be displayed in the element on page load. */ value: string; }; canvas: { /** - * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` - * - * Specifies the height of elements listed here. For all other elements, use the CSS height property. - * - * > Note: In some instances, such as `
`, this is a legacy attribute, in which case the CSS height property should be used instead. + * Specifies the height of the element. */ height: string; /** - * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` - * - * For the elements listed here, this establishes the element's width. - * - * > Note: For all other instances, such as `
`, this is a legacy attribute, in which case the CSS width property should be used instead. + * Specifies the width of the element. */ width: string; }; caption: { /** - * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` - * * Specifies the horizontal alignment of the element. */ align: string; }; col: { /** - * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` - * * Specifies the horizontal alignment of the element. */ align: string; /** - * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` - * * Background color of the element. * * > Note: This is a legacy attribute. Please use the CSS background-color property instead. */ bgcolor: string; - /** - * Applies to `col`, `colgroup` - */ span: string; }; colgroup: { /** - * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` - * * Specifies the horizontal alignment of the element. */ align: string; /** - * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` - * * Background color of the element. * * > Note: This is a legacy attribute. Please use the CSS background-color property instead. */ bgcolor: string; - /** - * Applies to `col`, `colgroup` - */ span: string; }; command: { /** - * Applies to `command`, `input` - * * Indicates whether the element should be checked on page load. */ - checked: string; + checked: boolean; /** - * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` - * * Indicates whether the user can interact with the element. */ - disabled: string; + disabled: boolean; /** - * Applies to `command` - * * Specifies a picture which represents the command. */ icon: string; - /** - * Applies to `command` - */ radiogroup: string; /** - * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` - * * Defines the type of the element. */ type: string; }; contenteditable: { /** - * Applies to `textarea`, `contenteditable` - * * The enterkeyhint specifies what action label (or icon) to present for the enter key on virtual keyboards. The attribute can be used with form controls (such as the value of textarea elements), or in elements in an editing host (e.g., using contenteditable attribute). */ - enterkeyhint: string; + enterkeyhint: "enter" | "done" | "go" | "next" | "previous" | "search" | "send"; /** - * Applies to `textarea`, `contenteditable` - * * Provides a hint as to the type of data that might be entered by the user while editing the element or its contents. The attribute can be used with form controls (such as the value of textarea elements), or in elements in an editing host (e.g., using contenteditable attribute). */ - inputmode: string; + inputmode: "none" | "text" | "tel" | "email" | "url" | "numeric" | "decimal" | "search"; }; data: { /** - * Applies to `button`, `data`, `input`, `li`, `meter`, `option`, `progress`, `param` - * * Defines a default value which will be displayed in the element on page load. */ value: string; }; del: { /** - * Applies to `blockquote`, `del`, `ins`, `q` - * * Contains a URI which points to the source of the quote or change. */ cite: string; /** - * Applies to `del`, `ins`, `time` - * * Indicates the date and time associated with the element. */ datetime: string; }; details: { /** - * Applies to `details` - * * Indicates whether the details will be shown on page load. */ - open: string; + open: boolean; }; embed: { /** - * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` - * - * Specifies the height of elements listed here. For all other elements, use the CSS height property. - * - * > Note: In some instances, such as `
`, this is a legacy attribute, in which case the CSS height property should be used instead. + * Specifies the height of the element. */ height: string; /** - * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` - * * The URL of the embeddable content. */ src: string; /** - * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` - * * Defines the type of the element. */ - type: string; + type: `${string}/${string}`; /** - * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` - * - * For the elements listed here, this establishes the element's width. - * - * > Note: For all other instances, such as `
`, this is a legacy attribute, in which case the CSS width property should be used instead. + * Specifies the width of the element. */ width: string; }; fieldset: { /** - * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` - * * Indicates whether the user can interact with the element. */ - disabled: string; + disabled: boolean; /** - * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` - * * Indicates the form that is the owner of the element. */ form: string; /** - * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` - * * Name of the element. For example used by the server to identify the fields in form submits. */ name: string; }; font: { /** - * Applies to `basefont`, `font`, `hr` - * * This attribute sets the text color using either a named color or a color specified in the hexadecimal #RRGGBB format. * * > Note: This is a legacy attribute. Please use the CSS color property instead. @@ -629,70 +425,48 @@ type ElementAttrs = { }; form: { /** - * Applies to `form`, `input` - * * List of types the server accepts, typically a file type. */ accept: string; /** - * Applies to `form` - * * List of supported charsets. */ - ["accept-charset"]: string; + ["accept-charset"]: "UTF-8"; /** - * Applies to `form` - * * The URI of a program that processes the information submitted via the form. */ action: string; /** - * Applies to `form`, `input`, `select`, `textarea` - * * Indicates whether controls in this form can by default have their values automatically completed by the browser. */ - autocomplete: string; + autocomplete: "on" | "off"; /** - * Applies to `form` - * * Defines the content type of the form data when the method is POST. */ - enctype: string; + enctype: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain"; /** - * Applies to `form` - * * Defines which HTTP method to use when submitting the form. Can be GET (default) or POST. */ - method: string; + method: "GET" | "POST" | "dialog"; /** - * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` - * * Name of the element. For example used by the server to identify the fields in form submits. */ name: string; /** - * Applies to `form` - * * This attribute indicates that the form shouldn't be validated when submitted. */ - novalidate: string; + novalidate: boolean; /** - * Applies to `a`, `area`, `base`, `form` - * * Specifies where to open the linked document (in the case of an `` element) or where to display the response received (in the case of a `` element) */ target: string; }; hr: { /** - * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` - * * Specifies the horizontal alignment of the element. */ align: string; /** - * Applies to `basefont`, `font`, `hr` - * * This attribute sets the text color using either a named color or a color specified in the hexadecimal #RRGGBB format. * * > Note: This is a legacy attribute. Please use the CSS color property instead. @@ -701,952 +475,631 @@ type ElementAttrs = { }; iframe: { /** - * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` - * * Specifies the horizontal alignment of the element. */ align: string; /** - * Applies to `iframe` - * * Specifies a feature-policy for the iframe. */ allow: string; /** - * Applies to `iframe` - * * Specifies the Content Security Policy that an embedded document must agree to enforce upon itself. */ csp: string; /** - * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` - * - * Specifies the height of elements listed here. For all other elements, use the CSS height property. - * - * > Note: In some instances, such as `
`, this is a legacy attribute, in which case the CSS height property should be used instead. + * Specifies the height of the element. */ height: string; /** - * Applies to `iframe`, `img`, `link`, `script` - * * Indicates the relative fetch priority for the resource. */ importance: string; /** - * Applies to `img`, `iframe` - * * Indicates if the element should be loaded lazily (loading="lazy") or loaded immediately (loading="eager"). * * WIP: WHATWG PR #3752 */ - loading: string; + loading: "lazy" | "eager"; /** - * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` - * * Name of the element. For example used by the server to identify the fields in form submits. */ name: string; /** - * Applies to `a`, `area`, `iframe`, `img`, `link`, `script` - * * Specifies which referrer is sent when fetching the resource. */ referrerpolicy: string; /** - * Applies to `iframe` - * * Stops a document loaded in an iframe from using certain features (such as submitting forms or opening new windows). */ - sandbox: string; + sandbox: "allow-forms" | "allow-modals" | "allow-orientation-lock" | "allow-pointer-lock" | "allow-popups" | "allow-popups-to-escape-sandbox" | "allow-presentation" | "allow-same-origin" | "allow-scripts" | "allow-top-navigation"; /** - * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` - * * The URL of the embeddable content. */ src: string; - /** - * Applies to `iframe` - */ srcdoc: string; /** - * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` - * - * For the elements listed here, this establishes the element's width. - * - * > Note: For all other instances, such as `
`, this is a legacy attribute, in which case the CSS width property should be used instead. + * Specifies the width of the element. */ width: string; }; img: { /** - * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` - * * Specifies the horizontal alignment of the element. */ align: string; /** - * Applies to `applet`, `area`, `img`, `input` - * * Alternative text in case an image can't be displayed. */ alt: string; /** - * Applies to `img`, `object`, `table` - * * The border width. * * > Note: This is a legacy attribute. Please use the CSS border property instead. */ border: string; /** - * Applies to `audio`, `img`, `link`, `script`, `video` - * * How the element handles cross-origin requests */ - crossorigin: string; + crossorigin: "anonymous" | "use-credentials"; /** - * Applies to `img` - * * Indicates the preferred method to decode the image. */ - decoding: string; + decoding: "sync" | "async" | "auto"; /** - * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` - * - * Specifies the height of elements listed here. For all other elements, use the CSS height property. - * - * > Note: In some instances, such as `
`, this is a legacy attribute, in which case the CSS height property should be used instead. + * Specifies the height of the element. */ height: string; /** - * Applies to `iframe`, `img`, `link`, `script` - * * Indicates the relative fetch priority for the resource. */ importance: string; /** - * Applies to `img` - * * Indicates that the image is part of a server-side image map. */ - ismap: string; + ismap: boolean; /** - * Applies to `img`, `iframe` - * * Indicates if the element should be loaded lazily (loading="lazy") or loaded immediately (loading="eager"). * * WIP: WHATWG PR #3752 */ - loading: string; + loading: "lazy" | "eager"; /** - * Applies to `a`, `area`, `iframe`, `img`, `link`, `script` - * * Specifies which referrer is sent when fetching the resource. */ referrerpolicy: string; - /** - * Applies to `link`, `img`, `source` - */ sizes: string; /** - * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` - * * The URL of the embeddable content. */ src: string; /** - * Applies to `img`, `source` - * * One or more responsive image candidates. */ srcset: string; - /** - * Applies to `img`, `input`, `object` - */ usemap: string; /** - * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` - * - * For the elements listed here, this establishes the element's width. - * - * > Note: For all other instances, such as `
`, this is a legacy attribute, in which case the CSS width property should be used instead. + * Specifies the width of the element. */ width: string; }; input: { /** - * Applies to `form`, `input` - * * List of types the server accepts, typically a file type. */ accept: string; /** - * Applies to `applet`, `area`, `img`, `input` - * * Alternative text in case an image can't be displayed. */ alt: string; /** - * Applies to `form`, `input`, `select`, `textarea` - * * Indicates whether controls in this form can by default have their values automatically completed by the browser. */ - autocomplete: string; + autocomplete: "on" | "off"; /** - * Applies to `button`, `input`, `keygen`, `select`, `textarea` - * * The element should be automatically focused after the page loaded. */ - autofocus: string; + autofocus: boolean; /** - * Applies to `input` - * * From the HTML Media CaptureThe definition of 'media capture' in that specification.spec, specifies a new file can be captured. */ capture: string; /** - * Applies to `command`, `input` - * * Indicates whether the element should be checked on page load. */ - checked: string; - /** - * Applies to `input`, `textarea` - */ + checked: boolean; dirname: string; /** - * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` - * * Indicates whether the user can interact with the element. */ - disabled: string; + disabled: boolean; /** - * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` - * * Indicates the form that is the owner of the element. */ form: string; /** - * Applies to `input`, `button` - * * Indicates the action of the element, overriding the action defined in the ``. */ formaction: string; /** - * Applies to `button`, `input` - * * If the button/input is a submit button (type="submit"), this attribute sets the encoding type to use during form submission. If this attribute is specified, it overrides the enctype attribute of the button's form owner. */ - formenctype: string; + formenctype: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain"; /** - * Applies to `button`, `input` - * * If the button/input is a submit button (type="submit"), this attribute sets the submission method to use during form submission (GET, POST, etc.). If this attribute is specified, it overrides the method attribute of the button's form owner. */ - formmethod: string; + formmethod: "GET" | "POST" | "dialog"; /** - * Applies to `button`, `input` - * * If the button/input is a submit button (type="submit"), this boolean attribute specifies that the form is not to be validated when it is submitted. If this attribute is specified, it overrides the novalidate attribute of the button's form owner. */ - formnovalidate: string; + formnovalidate: boolean; /** - * Applies to `button`, `input` - * * If the button/input is a submit button (type="submit"), this attribute specifies the browsing context (for example, tab, window, or inline frame) in which to display the response that is received after submitting the form. If this attribute is specified, it overrides the target attribute of the button's form owner. */ formtarget: string; /** - * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` - * - * Specifies the height of elements listed here. For all other elements, use the CSS height property. - * - * > Note: In some instances, such as `
`, this is a legacy attribute, in which case the CSS height property should be used instead. + * Specifies the height of the element. */ height: string; /** - * Applies to `input` - * * Identifies a list of pre-defined options to suggest to the user. */ list: string; /** - * Applies to `input`, `meter`, `progress` - * * Indicates the maximum value allowed. */ max: string; /** - * Applies to `input`, `textarea` - * * Defines the maximum number of characters allowed in the element. */ maxlength: string; /** - * Applies to `input`, `meter` - * * Indicates the minimum value allowed. */ min: string; /** - * Applies to `input`, `textarea` - * * Defines the minimum number of characters allowed in the element. */ minlength: string; /** - * Applies to `input`, `select` - * * Indicates whether multiple values can be entered in an input of the type email or file. */ - multiple: string; + multiple: boolean; /** - * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` - * * Name of the element. For example used by the server to identify the fields in form submits. */ name: string; /** - * Applies to `input` - * * Defines a regular expression which the element's value will be validated against. */ pattern: string; /** - * Applies to `input`, `textarea` - * * Provides a hint to the user of what can be entered in the field. */ placeholder: string; /** - * Applies to `input`, `textarea` - * * Indicates whether the element can be edited. */ - readonly: string; + readonly: boolean; /** - * Applies to `input`, `select`, `textarea` - * * Indicates whether this element is required to fill out or not. */ - required: string; + required: boolean; /** - * Applies to `input`, `select` - * * Defines the width of the element (in pixels). If the element's type attribute is text or password then it's the number of characters. */ size: string; /** - * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` - * * The URL of the embeddable content. */ src: string; + step: number | "any"; /** - * Applies to `input` - */ - step: string; - /** - * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` - * * Defines the type of the element. */ - type: string; - /** - * Applies to `img`, `input`, `object` - */ + type: "hidden" | "text" | "search" | "tel" | "url" | "email" | "password" | "date" | "month" | "week" | "time" | "datetime" | "number" | "range" | "color" | "checkbox" | "radio" | "file" | "submit" | "image" | "reset" | "button"; usemap: string; /** - * Applies to `button`, `data`, `input`, `li`, `meter`, `option`, `progress`, `param` - * * Defines a default value which will be displayed in the element on page load. */ value: string; /** - * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` - * - * For the elements listed here, this establishes the element's width. - * - * > Note: For all other instances, such as `
`, this is a legacy attribute, in which case the CSS width property should be used instead. + * Specifies the width of the element. */ width: string; }; ins: { /** - * Applies to `blockquote`, `del`, `ins`, `q` - * * Contains a URI which points to the source of the quote or change. */ cite: string; /** - * Applies to `del`, `ins`, `time` - * * Indicates the date and time associated with the element. */ datetime: string; }; keygen: { /** - * Applies to `button`, `input`, `keygen`, `select`, `textarea` - * * The element should be automatically focused after the page loaded. */ - autofocus: string; + autofocus: boolean; /** - * Applies to `keygen` - * * A challenge string that is submitted along with the public key. */ challenge: string; /** - * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` - * * Indicates whether the user can interact with the element. */ - disabled: string; + disabled: boolean; /** - * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` - * * Indicates the form that is the owner of the element. */ form: string; /** - * Applies to `keygen` - * * Specifies the type of key generated. */ keytype: string; /** - * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` - * * Name of the element. For example used by the server to identify the fields in form submits. */ name: string; }; label: { /** - * Applies to `label`, `output` - * * Describes elements which belongs to this one. */ for: string; /** - * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` - * * Indicates the form that is the owner of the element. */ form: string; }; li: { /** - * Applies to `button`, `data`, `input`, `li`, `meter`, `option`, `progress`, `param` - * * Defines a default value which will be displayed in the element on page load. */ value: string; }; link: { /** - * Applies to `audio`, `img`, `link`, `script`, `video` - * * How the element handles cross-origin requests */ - crossorigin: string; + crossorigin: "anonymous" | "use-credentials"; /** - * Applies to `a`, `area`, `base`, `link` - * * The URL of a linked resource. */ href: string; /** - * Applies to `a`, `area`, `link` - * * Specifies the language of the linked resource. */ hreflang: string; /** - * Applies to `iframe`, `img`, `link`, `script` - * * Indicates the relative fetch priority for the resource. */ importance: string; /** - * Applies to `link`, `script` - * * Specifies a Subresource Integrity value that allows browsers to verify what they fetch. */ integrity: string; /** - * Applies to `a`, `area`, `link`, `source`, `style` - * * Specifies a hint of the media for which the linked resource was designed. */ media: string; /** - * Applies to `a`, `area`, `iframe`, `img`, `link`, `script` - * * Specifies which referrer is sent when fetching the resource. */ referrerpolicy: string; /** - * Applies to `a`, `area`, `link` - * * Specifies the relationship of the target object to the link object. */ rel: string; - /** - * Applies to `link`, `img`, `source` - */ sizes: string; }; map: { /** - * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` - * * Name of the element. For example used by the server to identify the fields in form submits. */ name: string; }; marquee: { /** - * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` - * * Background color of the element. * * > Note: This is a legacy attribute. Please use the CSS background-color property instead. */ bgcolor: string; /** - * Applies to `audio`, `bgsound`, `marquee`, `video` - * * Indicates whether the media should start playing from the start when it's finished. */ - loop: string; + loop: boolean; }; menu: { /** - * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` - * * Defines the type of the element. */ type: string; }; meta: { /** - * Applies to `meta`, `script` - * * Declares the character encoding of the page or script. */ - charset: string; + charset: "utf-8"; /** - * Applies to `meta` - * * A value associated with http-equiv or name depending on the context. */ content: string; /** - * Applies to `meta` - * * Defines a pragma directive. */ - ["http-equiv"]: string; + ["http-equiv"]: "content-type" | "default-style" | "refresh" | "x-ua-compatible" | "content-security-policy"; /** - * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` - * * Name of the element. For example used by the server to identify the fields in form submits. */ name: string; }; meter: { /** - * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` - * * Indicates the form that is the owner of the element. */ form: string; /** - * Applies to `meter` - * * Indicates the lower bound of the upper range. */ high: string; /** - * Applies to `meter` - * * Indicates the upper bound of the lower range. */ low: string; /** - * Applies to `input`, `meter`, `progress` - * * Indicates the maximum value allowed. */ max: string; /** - * Applies to `input`, `meter` - * * Indicates the minimum value allowed. */ min: string; /** - * Applies to `meter` - * * Indicates the optimal numeric value. */ optimum: string; /** - * Applies to `button`, `data`, `input`, `li`, `meter`, `option`, `progress`, `param` - * * Defines a default value which will be displayed in the element on page load. */ value: string; }; object: { /** - * Applies to `img`, `object`, `table` - * * The border width. * * > Note: This is a legacy attribute. Please use the CSS border property instead. */ border: string; /** - * Applies to `object` - * * Specifies the URL of the resource. */ data: string; /** - * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` - * * Indicates the form that is the owner of the element. */ form: string; /** - * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` - * - * Specifies the height of elements listed here. For all other elements, use the CSS height property. - * - * > Note: In some instances, such as `
`, this is a legacy attribute, in which case the CSS height property should be used instead. + * Specifies the height of the element. */ height: string; /** - * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` - * * Name of the element. For example used by the server to identify the fields in form submits. */ name: string; /** - * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` - * * Defines the type of the element. */ - type: string; - /** - * Applies to `img`, `input`, `object` - */ + type: `${string}/${string}`; usemap: string; /** - * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` - * - * For the elements listed here, this establishes the element's width. - * - * > Note: For all other instances, such as `
`, this is a legacy attribute, in which case the CSS width property should be used instead. + * Specifies the width of the element. */ width: string; }; ol: { /** - * Applies to `ol` - * * Indicates whether the list should be displayed in a descending order instead of a ascending. */ - reversed: string; + reversed: boolean; /** - * Applies to `ol` - * * Defines the first number if other than 1. */ start: string; }; optgroup: { /** - * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` - * * Indicates whether the user can interact with the element. */ - disabled: string; + disabled: boolean; /** - * Applies to `optgroup`, `option`, `track` - * * Specifies a user-readable title of the element. */ label: string; }; option: { /** - * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` - * * Indicates whether the user can interact with the element. */ - disabled: string; + disabled: boolean; /** - * Applies to `optgroup`, `option`, `track` - * * Specifies a user-readable title of the element. */ label: string; /** - * Applies to `option` - * * Defines a value which will be selected on page load. */ - selected: string; + selected: boolean; /** - * Applies to `button`, `data`, `input`, `li`, `meter`, `option`, `progress`, `param` - * * Defines a default value which will be displayed in the element on page load. */ value: string; }; output: { /** - * Applies to `label`, `output` - * * Describes elements which belongs to this one. */ for: string; /** - * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` - * * Indicates the form that is the owner of the element. */ form: string; /** - * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` - * * Name of the element. For example used by the server to identify the fields in form submits. */ name: string; }; param: { /** - * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` - * * Name of the element. For example used by the server to identify the fields in form submits. */ name: string; /** - * Applies to `button`, `data`, `input`, `li`, `meter`, `option`, `progress`, `param` - * * Defines a default value which will be displayed in the element on page load. */ value: string; }; progress: { /** - * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` - * * Indicates the form that is the owner of the element. */ form: string; /** - * Applies to `input`, `meter`, `progress` - * * Indicates the maximum value allowed. */ max: string; /** - * Applies to `button`, `data`, `input`, `li`, `meter`, `option`, `progress`, `param` - * * Defines a default value which will be displayed in the element on page load. */ value: string; }; q: { /** - * Applies to `blockquote`, `del`, `ins`, `q` - * * Contains a URI which points to the source of the quote or change. */ cite: string; }; script: { /** - * Applies to `script` - * * Executes the script asynchronously. */ - async: string; + async: boolean; /** - * Applies to `meta`, `script` - * * Declares the character encoding of the page or script. */ - charset: string; + charset: "utf-8"; /** - * Applies to `audio`, `img`, `link`, `script`, `video` - * * How the element handles cross-origin requests */ - crossorigin: string; + crossorigin: "anonymous" | "use-credentials"; /** - * Applies to `script` - * * Indicates that the script should be executed after the page has been parsed. */ - defer: string; + defer: boolean; /** - * Applies to `iframe`, `img`, `link`, `script` - * * Indicates the relative fetch priority for the resource. */ importance: string; /** - * Applies to `link`, `script` - * * Specifies a Subresource Integrity value that allows browsers to verify what they fetch. */ integrity: string; /** - * Applies to `a`, `area`, `iframe`, `img`, `link`, `script` - * * Specifies which referrer is sent when fetching the resource. */ referrerpolicy: string; /** - * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` - * * The URL of the embeddable content. */ src: string; /** - * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` - * * Defines the type of the element. */ - type: string; + type: "module" | "`${string}/${string}`"; }; select: { /** - * Applies to `form`, `input`, `select`, `textarea` - * * Indicates whether controls in this form can by default have their values automatically completed by the browser. */ - autocomplete: string; + autocomplete: "on" | "off"; /** - * Applies to `button`, `input`, `keygen`, `select`, `textarea` - * * The element should be automatically focused after the page loaded. */ - autofocus: string; + autofocus: boolean; /** - * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` - * * Indicates whether the user can interact with the element. */ - disabled: string; + disabled: boolean; /** - * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` - * * Indicates the form that is the owner of the element. */ form: string; /** - * Applies to `input`, `select` - * * Indicates whether multiple values can be entered in an input of the type email or file. */ - multiple: string; + multiple: boolean; /** - * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` - * * Name of the element. For example used by the server to identify the fields in form submits. */ name: string; /** - * Applies to `input`, `select`, `textarea` - * * Indicates whether this element is required to fill out or not. */ - required: string; + required: boolean; /** - * Applies to `input`, `select` - * * Defines the width of the element (in pixels). If the element's type attribute is text or password then it's the number of characters. */ size: string; }; source: { /** - * Applies to `a`, `area`, `link`, `source`, `style` - * * Specifies a hint of the media for which the linked resource was designed. */ media: string; - /** - * Applies to `link`, `img`, `source` - */ sizes: string; /** - * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` - * * The URL of the embeddable content. */ src: string; /** - * Applies to `img`, `source` - * * One or more responsive image candidates. */ srcset: string; /** - * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` - * * Defines the type of the element. */ - type: string; + type: `${string}/${string}`; }; style: { /** - * Applies to `a`, `area`, `link`, `source`, `style` - * * Specifies a hint of the media for which the linked resource was designed. */ media: string; /** - * Applies to `button`, `input`, `command`, `embed`, `object`, `script`, `source`, `style`, `menu` - * * Defines the type of the element. */ type: string; }; table: { /** - * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` - * * Specifies the horizontal alignment of the element. */ align: string; /** - * Applies to `body`, `table`, `td`, `th` - * * Specifies the URL of an image file. * * > Note: Although browsers and email clients may still support this attribute, it is obsolete. Use CSS background-image instead. */ background: string; /** - * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` - * * Background color of the element. * * > Note: This is a legacy attribute. Please use the CSS background-color property instead. */ bgcolor: string; /** - * Applies to `img`, `object`, `table` - * * The border width. * * > Note: This is a legacy attribute. Please use the CSS border property instead. @@ -1655,14 +1108,10 @@ type ElementAttrs = { }; tbody: { /** - * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` - * * Specifies the horizontal alignment of the element. */ align: string; /** - * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` - * * Background color of the element. * * > Note: This is a legacy attribute. Please use the CSS background-color property instead. @@ -1671,152 +1120,103 @@ type ElementAttrs = { }; td: { /** - * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` - * * Specifies the horizontal alignment of the element. */ align: string; /** - * Applies to `body`, `table`, `td`, `th` - * * Specifies the URL of an image file. * * > Note: Although browsers and email clients may still support this attribute, it is obsolete. Use CSS background-image instead. */ background: string; /** - * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` - * * Background color of the element. * * > Note: This is a legacy attribute. Please use the CSS background-color property instead. */ bgcolor: string; /** - * Applies to `td`, `th` - * * The colspan attribute defines the number of columns a cell should span. */ colspan: string; /** - * Applies to `td`, `th` - * * IDs of the `` elements which applies to this element. */ headers: string; /** - * Applies to `td`, `th` - * * Defines the number of rows a table cell should span over. */ rowspan: string; }; textarea: { /** - * Applies to `form`, `input`, `select`, `textarea` - * * Indicates whether controls in this form can by default have their values automatically completed by the browser. */ - autocomplete: string; + autocomplete: "on" | "off"; /** - * Applies to `button`, `input`, `keygen`, `select`, `textarea` - * * The element should be automatically focused after the page loaded. */ - autofocus: string; + autofocus: boolean; /** - * Applies to `textarea` - * * Defines the number of columns in a textarea. */ cols: string; - /** - * Applies to `input`, `textarea` - */ dirname: string; /** - * Applies to `button`, `command`, `fieldset`, `input`, `keygen`, `optgroup`, `option`, `select`, `textarea` - * * Indicates whether the user can interact with the element. */ - disabled: string; + disabled: boolean; /** - * Applies to `textarea`, `contenteditable` - * * The enterkeyhint specifies what action label (or icon) to present for the enter key on virtual keyboards. The attribute can be used with form controls (such as the value of textarea elements), or in elements in an editing host (e.g., using contenteditable attribute). */ - enterkeyhint: string; + enterkeyhint: "enter" | "done" | "go" | "next" | "previous" | "search" | "send"; /** - * Applies to `button`, `fieldset`, `input`, `keygen`, `label`, `meter`, `object`, `output`, `progress`, `select`, `textarea` - * * Indicates the form that is the owner of the element. */ form: string; /** - * Applies to `textarea`, `contenteditable` - * * Provides a hint as to the type of data that might be entered by the user while editing the element or its contents. The attribute can be used with form controls (such as the value of textarea elements), or in elements in an editing host (e.g., using contenteditable attribute). */ - inputmode: string; + inputmode: "none" | "text" | "tel" | "email" | "url" | "numeric" | "decimal" | "search"; /** - * Applies to `input`, `textarea` - * * Defines the maximum number of characters allowed in the element. */ maxlength: string; /** - * Applies to `input`, `textarea` - * * Defines the minimum number of characters allowed in the element. */ minlength: string; /** - * Applies to `button`, `form`, `fieldset`, `iframe`, `input`, `keygen`, `object`, `output`, `select`, `textarea`, `map`, `meta`, `param` - * * Name of the element. For example used by the server to identify the fields in form submits. */ name: string; /** - * Applies to `input`, `textarea` - * * Provides a hint to the user of what can be entered in the field. */ placeholder: string; /** - * Applies to `input`, `textarea` - * * Indicates whether the element can be edited. */ - readonly: string; + readonly: boolean; /** - * Applies to `input`, `select`, `textarea` - * * Indicates whether this element is required to fill out or not. */ - required: string; + required: boolean; /** - * Applies to `textarea` - * * Defines the number of rows in a text area. */ rows: string; /** - * Applies to `textarea` - * * Indicates whether the text should be wrapped. */ - wrap: string; + wrap: "soft" | "hard"; }; tfoot: { /** - * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` - * * Specifies the horizontal alignment of the element. */ align: string; /** - * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` - * * Background color of the element. * * > Note: This is a legacy attribute. Please use the CSS background-color property instead. @@ -1825,78 +1225,56 @@ type ElementAttrs = { }; th: { /** - * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` - * * Specifies the horizontal alignment of the element. */ align: string; /** - * Applies to `body`, `table`, `td`, `th` - * * Specifies the URL of an image file. * * > Note: Although browsers and email clients may still support this attribute, it is obsolete. Use CSS background-image instead. */ background: string; /** - * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` - * * Background color of the element. * * > Note: This is a legacy attribute. Please use the CSS background-color property instead. */ bgcolor: string; /** - * Applies to `td`, `th` - * * The colspan attribute defines the number of columns a cell should span. */ colspan: string; /** - * Applies to `td`, `th` - * * IDs of the `` elements which applies to this element. */ headers: string; /** - * Applies to `td`, `th` - * * Defines the number of rows a table cell should span over. */ rowspan: string; /** - * Applies to `th` - * * Defines the cells that the header test (defined in the th element) relates to. */ - scope: string; + scope: "row" | "col" | "rowgroup" | "colgroup"; }; thead: { /** - * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` - * * Specifies the horizontal alignment of the element. */ align: string; }; time: { /** - * Applies to `del`, `ins`, `time` - * * Indicates the date and time associated with the element. */ datetime: string; }; tr: { /** - * Applies to `applet`, `caption`, `col`, `colgroup`, `hr`, `iframe`, `img`, `table`, `tbody`, `td`, `tfoot`, `th`, `thead`, `tr` - * * Specifies the horizontal alignment of the element. */ align: string; /** - * Applies to `body`, `col`, `colgroup`, `marquee`, `table`, `tbody`, `tfoot`, `td`, `th`, `tr` - * * Background color of the element. * * > Note: This is a legacy attribute. Please use the CSS background-color property instead. @@ -1905,109 +1283,80 @@ type ElementAttrs = { }; track: { /** - * Applies to `track` - * * Indicates that the track should be enabled unless the user's preferences indicate something different. */ - default: string; + default: boolean; /** - * Applies to `track` - * * Specifies the kind of text track. */ - kind: string; + kind: "subtitles" | "captions" | "descriptions" | "chapters" | "metadata"; /** - * Applies to `optgroup`, `option`, `track` - * * Specifies a user-readable title of the element. */ label: string; /** - * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` - * * The URL of the embeddable content. */ src: string; - /** - * Applies to `track` - */ srclang: string; }; video: { /** - * Applies to `audio`, `video` - * * The audio or video should play as soon as possible. */ - autoplay: string; + autoplay: boolean; /** - * Applies to `audio`, `video` - * * Contains the time range of already buffered media. */ buffered: string; /** - * Applies to `audio`, `video` - * * Indicates whether the browser should show playback controls to the user. */ - controls: string; + controls: boolean; /** - * Applies to `audio`, `img`, `link`, `script`, `video` - * * How the element handles cross-origin requests */ - crossorigin: string; + crossorigin: "anonymous" | "use-credentials"; /** - * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` - * - * Specifies the height of elements listed here. For all other elements, use the CSS height property. - * - * > Note: In some instances, such as `
`, this is a legacy attribute, in which case the CSS height property should be used instead. + * Specifies the height of the element. */ height: string; /** - * Applies to `audio`, `bgsound`, `marquee`, `video` - * * Indicates whether the media should start playing from the start when it's finished. */ - loop: string; + loop: boolean; /** - * Applies to `audio`, `video` - * * Indicates whether the audio will be initially silenced on page load. */ - muted: string; + muted: boolean; /** - * Applies to `video` - * * A URL indicating a poster frame to show until the user plays or seeks. */ poster: string; /** - * Applies to `audio`, `video` - * * Indicates whether the whole resource, parts of it or nothing should be preloaded. */ - preload: string; + preload: "none" | "metadata" | "auto"; /** - * Applies to `audio`, `embed`, `iframe`, `img`, `input`, `script`, `source`, `track`, `video` - * * The URL of the embeddable content. */ src: string; /** - * Applies to `canvas`, `embed`, `iframe`, `img`, `input`, `object`, `video` - * - * For the elements listed here, this establishes the element's width. - * - * > Note: For all other instances, such as `
`, this is a legacy attribute, in which case the CSS width property should be used instead. + * Specifies the width of the element. */ width: string; }; - [k: string]: unknown; }; +type PropOr = + T extends Record ? V : D; + +type Deunionize = + | ([undefined] extends [T] ? undefined : never) + | { [K in T extends unknown ? keyof T : never]: PropOr, K, undefined>; }; + +export type AllAttrs = Partial>; + export type DataAttr = `data-${string}`; export type Attr = @@ -2023,7 +1372,7 @@ export type Attr = * * @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques */ - role?: AriaRoles; + role: AriaRoles; /** * ARIA is a set of attributes that define ways to make web content * and web applications (especially those developed with JavaScript) @@ -2031,6 +1380,6 @@ export type Attr = * * @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA */ - aria?: AriaAttributes; - } & ElementAttrs[E] + aria: AriaAttributes; + } & (ElementAttrs & { [k: string]: unknown })[E] >; diff --git a/src/render.ts b/src/render.ts index d5f916b..9271f1b 100644 --- a/src/render.ts +++ b/src/render.ts @@ -6,16 +6,21 @@ import { Attr } from "./attributes.ts"; import { isState } from "./state.ts"; import { Falsy, isFalsy, escapeHTML, guessEnv } from "./util.ts"; -function attrifyHTML( - attrs: Record>, - prefix = "", -): string { +type AttributeObject = Record< + string, + string | number | boolean | Record +>; + +function attrifyHTML(attrs: AttributeObject, prefix = ""): string { return Object.entries(attrs) .map(([attr, value]) => { if (value === "") return value; if (typeof value === "object") return attrifyHTML(value, attr + "-"); - return `${prefix + attr}="${value}"`; + if (typeof value === "boolean") + if (value) return `${prefix + attr}`; + else return ""; + if (value) return `${prefix + attr}="${value}"`; }) .join(" "); } @@ -56,16 +61,16 @@ function htmlStringToElement(html: string) { return template.content.firstChild || ""; } -function attrifyDOM( - el: HTMLElement, - attrs: Record>, - prefix = "", -) { +function attrifyDOM(el: HTMLElement, attrs: AttributeObject, prefix = "") { for (const attr in attrs) { const value = attrs[attr as keyof Attr]; if (value === "") el.setAttribute(prefix + attr, ""); else if (typeof value === "object") attrifyDOM(el, value, attr + "-"); - else if (value) el.setAttribute(prefix + attr, value); + else if (typeof value === "boolean") + if (value) el.setAttribute(prefix + attr, ""); + // no-op + else null; + else if (value) el.setAttribute(prefix + attr, String(value)); } } diff --git a/test.ts b/test.ts index 384b2e6..baae234 100644 --- a/test.ts +++ b/test.ts @@ -2,7 +2,7 @@ import { assertEquals } from "https://deno.land/std@0.99.0/testing/asserts.ts"; import { elements, trust, renderHTML } from "./mod.ts"; -const { div, p, h1, br } = elements; +const { div, p, h1, br, input } = elements; Deno.test({ name: "renderHTML simple", @@ -114,3 +114,22 @@ Deno.test({ assertEquals(renderHTML(el()), ``); }, }); + +Deno.test({ + name: "renderHTML with boolean attributes", + fn: () => { + assertEquals( + renderHTML(input({ disabled: true })), + ``, + ); + + assertEquals(renderHTML(input({ disabled: false })), ``); + }, +}); + +Deno.test({ + name: "renderHTML with numeric attributes", + fn: () => { + assertEquals(renderHTML(input({ step: 5 })), ``); + }, +}); From 80d6e5d44e0125c53ea4c840df3dcf36e7fcca2d Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Fri, 2 Jul 2021 04:35:19 +0530 Subject: [PATCH 038/254] (fix) unquote mimetype string Signed-off-by: Muthu Kumar --- scripts/getSplType.ts | 2 +- src/attributes.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/getSplType.ts b/scripts/getSplType.ts index ce78886..d13ac7f 100644 --- a/scripts/getSplType.ts +++ b/scripts/getSplType.ts @@ -49,7 +49,7 @@ const manual: Entry[] = [ source: mime, button: union("submit", "reset", "button"), ol: union("1", "a", "A", "i", "I"), - script: union("module", mime), + script: `"module" | ${mime}`, input: union( "hidden", "text", diff --git a/src/attributes.ts b/src/attributes.ts index ebd575c..d7acbaa 100644 --- a/src/attributes.ts +++ b/src/attributes.ts @@ -1017,7 +1017,7 @@ type ElementAttrs = { /** * Defines the type of the element. */ - type: "module" | "`${string}/${string}`"; + type: "module" | `${string}/${string}`; }; select: { /** From 43158d4bcaa7be0a00f39f0bba463ef0bd63d307 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Fri, 2 Jul 2021 04:47:04 +0530 Subject: [PATCH 039/254] (feat) add more number attributes Signed-off-by: Muthu Kumar --- scripts/getSplType.ts | 36 ++++++++++++++++++- src/attributes.ts | 80 +++++++++++++++++++++---------------------- 2 files changed, 75 insertions(+), 41 deletions(-) diff --git a/scripts/getSplType.ts b/scripts/getSplType.ts index d13ac7f..e9cf538 100644 --- a/scripts/getSplType.ts +++ b/scripts/getSplType.ts @@ -32,6 +32,7 @@ const mime = "`${string}/${string}`"; const manual: Entry[] = [ ["as", () => `string`], + ["sandbox", () => `string`], ["step", () => `number | "any"`], [ "dir", @@ -76,6 +77,20 @@ const manual: Entry[] = [ ), }[el] || null), ], + [ + "value", + (el: string) => + ({ + button: `string`, + option: `string`, + data: `string`, + input: `string`, + param: `string`, + li: `number`, + meter: `number`, + progress: `number`, + }[el] || null), + ], ]; const parseEnum = (str: string) => @@ -87,10 +102,29 @@ const enums = rows .map(row => [row.name, union(...(parseEnum(row.value) || []))]) .map(([name, union]): Entry => [name, () => union]); +const numeric = [ + "cols", + "colspan", + "height", + "width", + "high", + "low", + "max", + "maxlength", + "min", + "minlength", + "optimum", + "rows", + "rowspan", + "size", + "start", + "tabindex", +].map((name): Entry => [name, () => "number"]); + const def = () => null; const specialTypes = Object.fromEntries( - ([] as Entry[]).concat(boolean, enums, manual), + ([] as Entry[]).concat(boolean, enums, numeric, manual), ); const specialKeys = new Set(Object.keys(specialTypes)); diff --git a/src/attributes.ts b/src/attributes.ts index d7acbaa..ed20cb4 100644 --- a/src/attributes.ts +++ b/src/attributes.ts @@ -58,7 +58,7 @@ type GlobalAttrs = { /** * Overrides the browser's default tab order and follows the one specified instead. */ - tabindex: string; + tabindex: number; /** * Text to be displayed in a tooltip when hovering over the element. */ @@ -294,11 +294,11 @@ type ElementAttrs = { /** * Specifies the height of the element. */ - height: string; + height: number; /** * Specifies the width of the element. */ - width: string; + width: number; }; caption: { /** @@ -387,7 +387,7 @@ type ElementAttrs = { /** * Specifies the height of the element. */ - height: string; + height: number; /** * The URL of the embeddable content. */ @@ -399,7 +399,7 @@ type ElementAttrs = { /** * Specifies the width of the element. */ - width: string; + width: number; }; fieldset: { /** @@ -489,7 +489,7 @@ type ElementAttrs = { /** * Specifies the height of the element. */ - height: string; + height: number; /** * Indicates the relative fetch priority for the resource. */ @@ -511,7 +511,7 @@ type ElementAttrs = { /** * Stops a document loaded in an iframe from using certain features (such as submitting forms or opening new windows). */ - sandbox: "allow-forms" | "allow-modals" | "allow-orientation-lock" | "allow-pointer-lock" | "allow-popups" | "allow-popups-to-escape-sandbox" | "allow-presentation" | "allow-same-origin" | "allow-scripts" | "allow-top-navigation"; + sandbox: string; /** * The URL of the embeddable content. */ @@ -520,7 +520,7 @@ type ElementAttrs = { /** * Specifies the width of the element. */ - width: string; + width: number; }; img: { /** @@ -548,7 +548,7 @@ type ElementAttrs = { /** * Specifies the height of the element. */ - height: string; + height: number; /** * Indicates the relative fetch priority for the resource. */ @@ -580,7 +580,7 @@ type ElementAttrs = { /** * Specifies the width of the element. */ - width: string; + width: number; }; input: { /** @@ -639,7 +639,7 @@ type ElementAttrs = { /** * Specifies the height of the element. */ - height: string; + height: number; /** * Identifies a list of pre-defined options to suggest to the user. */ @@ -647,19 +647,19 @@ type ElementAttrs = { /** * Indicates the maximum value allowed. */ - max: string; + max: number; /** * Defines the maximum number of characters allowed in the element. */ - maxlength: string; + maxlength: number; /** * Indicates the minimum value allowed. */ - min: string; + min: number; /** * Defines the minimum number of characters allowed in the element. */ - minlength: string; + minlength: number; /** * Indicates whether multiple values can be entered in an input of the type email or file. */ @@ -687,7 +687,7 @@ type ElementAttrs = { /** * Defines the width of the element (in pixels). If the element's type attribute is text or password then it's the number of characters. */ - size: string; + size: number; /** * The URL of the embeddable content. */ @@ -705,7 +705,7 @@ type ElementAttrs = { /** * Specifies the width of the element. */ - width: string; + width: number; }; ins: { /** @@ -757,7 +757,7 @@ type ElementAttrs = { /** * Defines a default value which will be displayed in the element on page load. */ - value: string; + value: number; }; link: { /** @@ -844,27 +844,27 @@ type ElementAttrs = { /** * Indicates the lower bound of the upper range. */ - high: string; + high: number; /** * Indicates the upper bound of the lower range. */ - low: string; + low: number; /** * Indicates the maximum value allowed. */ - max: string; + max: number; /** * Indicates the minimum value allowed. */ - min: string; + min: number; /** * Indicates the optimal numeric value. */ - optimum: string; + optimum: number; /** * Defines a default value which will be displayed in the element on page load. */ - value: string; + value: number; }; object: { /** @@ -884,7 +884,7 @@ type ElementAttrs = { /** * Specifies the height of the element. */ - height: string; + height: number; /** * Name of the element. For example used by the server to identify the fields in form submits. */ @@ -897,7 +897,7 @@ type ElementAttrs = { /** * Specifies the width of the element. */ - width: string; + width: number; }; ol: { /** @@ -907,7 +907,7 @@ type ElementAttrs = { /** * Defines the first number if other than 1. */ - start: string; + start: number; }; optgroup: { /** @@ -969,11 +969,11 @@ type ElementAttrs = { /** * Indicates the maximum value allowed. */ - max: string; + max: number; /** * Defines a default value which will be displayed in the element on page load. */ - value: string; + value: number; }; q: { /** @@ -1051,7 +1051,7 @@ type ElementAttrs = { /** * Defines the width of the element (in pixels). If the element's type attribute is text or password then it's the number of characters. */ - size: string; + size: number; }; source: { /** @@ -1138,7 +1138,7 @@ type ElementAttrs = { /** * The colspan attribute defines the number of columns a cell should span. */ - colspan: string; + colspan: number; /** * IDs of the `` elements which applies to this element. */ @@ -1146,7 +1146,7 @@ type ElementAttrs = { /** * Defines the number of rows a table cell should span over. */ - rowspan: string; + rowspan: number; }; textarea: { /** @@ -1160,7 +1160,7 @@ type ElementAttrs = { /** * Defines the number of columns in a textarea. */ - cols: string; + cols: number; dirname: string; /** * Indicates whether the user can interact with the element. @@ -1181,11 +1181,11 @@ type ElementAttrs = { /** * Defines the maximum number of characters allowed in the element. */ - maxlength: string; + maxlength: number; /** * Defines the minimum number of characters allowed in the element. */ - minlength: string; + minlength: number; /** * Name of the element. For example used by the server to identify the fields in form submits. */ @@ -1205,7 +1205,7 @@ type ElementAttrs = { /** * Defines the number of rows in a text area. */ - rows: string; + rows: number; /** * Indicates whether the text should be wrapped. */ @@ -1243,7 +1243,7 @@ type ElementAttrs = { /** * The colspan attribute defines the number of columns a cell should span. */ - colspan: string; + colspan: number; /** * IDs of the `` elements which applies to this element. */ @@ -1251,7 +1251,7 @@ type ElementAttrs = { /** * Defines the number of rows a table cell should span over. */ - rowspan: string; + rowspan: number; /** * Defines the cells that the header test (defined in the th element) relates to. */ @@ -1320,7 +1320,7 @@ type ElementAttrs = { /** * Specifies the height of the element. */ - height: string; + height: number; /** * Indicates whether the media should start playing from the start when it's finished. */ @@ -1344,7 +1344,7 @@ type ElementAttrs = { /** * Specifies the width of the element. */ - width: string; + width: number; }; }; From a806ade37d5dd311fd2596ff419d96f89c91afb0 Mon Sep 17 00:00:00 2001 From: Darvesh Date: Fri, 2 Jul 2021 21:58:45 +0530 Subject: [PATCH 040/254] fix: guessEnv --- src/util.ts | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/util.ts b/src/util.ts index c330f12..6d6f73e 100644 --- a/src/util.ts +++ b/src/util.ts @@ -16,10 +16,22 @@ export const Falsy = new Set([false, "", 0, 0n, undefined, null]); export const isFalsy = (n: any): n is Falsy => Falsy.has(n); export const guessEnv = () => { - if (typeof window === "undefined") { - // @ts-ignore process is a node global API - if (typeof process === "undefined") return "node"; - else return undefined; - } else if (typeof window.Deno !== "undefined") return "deno"; - else return "browser"; + if ( + //@ts-ignore global + typeof process !== "undefined" && + //@ts-ignore global + process.versions && + //@ts-ignore global + process.versions.node + ) + return "node"; + //@ts-ignore global + if (typeof window !== "undefined") { + //@ts-ignore global + if (window.Deno && window.Deno.version && window.Deno.version.deno) + return "deno"; + //@ts-ignore global + if (window.document) return "browser"; + } + return undefined; }; From fbc0bb61232b5d0cb743c22bcb2e1a51081426a0 Mon Sep 17 00:00:00 2001 From: Darvesh Date: Fri, 2 Jul 2021 23:48:13 +0530 Subject: [PATCH 041/254] fix: move guessEnv out of util.ts with some simplification --- src/guessEnv.ts | 14 ++++++++++++++ src/render.ts | 3 ++- src/util.ts | 21 --------------------- 3 files changed, 16 insertions(+), 22 deletions(-) create mode 100644 src/guessEnv.ts diff --git a/src/guessEnv.ts b/src/guessEnv.ts new file mode 100644 index 0000000..83e5d4c --- /dev/null +++ b/src/guessEnv.ts @@ -0,0 +1,14 @@ +//declare is used to avoid ts-ignoring in multiple places +declare const process: { version: unknown }; +declare const window: { Deno: unknown; document: unknown }; + +export const guessEnv = () => { + if (typeof process !== "undefined" && process.version) return "node"; + if (typeof window !== "undefined") { + if (window.Deno) return "deno"; + if (window.document) return "browser"; + } + return undefined; +}; + +console.log(guessEnv()); diff --git a/src/render.ts b/src/render.ts index 9271f1b..ffb17da 100644 --- a/src/render.ts +++ b/src/render.ts @@ -4,7 +4,8 @@ import { Node, Nodeish, HTMLNode } from "./node.ts"; import { Attr } from "./attributes.ts"; import { isState } from "./state.ts"; -import { Falsy, isFalsy, escapeHTML, guessEnv } from "./util.ts"; +import { Falsy, isFalsy, escapeHTML } from "./util.ts"; +import { guessEnv } from "./guessEnv.ts"; type AttributeObject = Record< string, diff --git a/src/util.ts b/src/util.ts index 6d6f73e..59386f6 100644 --- a/src/util.ts +++ b/src/util.ts @@ -14,24 +14,3 @@ export type Falsy = false | "" | 0 | 0n | undefined | null; export const Falsy = new Set([false, "", 0, 0n, undefined, null]); // deno-lint-ignore no-explicit-any export const isFalsy = (n: any): n is Falsy => Falsy.has(n); - -export const guessEnv = () => { - if ( - //@ts-ignore global - typeof process !== "undefined" && - //@ts-ignore global - process.versions && - //@ts-ignore global - process.versions.node - ) - return "node"; - //@ts-ignore global - if (typeof window !== "undefined") { - //@ts-ignore global - if (window.Deno && window.Deno.version && window.Deno.version.deno) - return "deno"; - //@ts-ignore global - if (window.document) return "browser"; - } - return undefined; -}; From 0b1e6b5c9f20a7f51db9574b4b421c162efcc47d Mon Sep 17 00:00:00 2001 From: Darvesh Date: Fri, 2 Jul 2021 23:52:22 +0530 Subject: [PATCH 042/254] rm: console.log --- src/guessEnv.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/guessEnv.ts b/src/guessEnv.ts index 83e5d4c..08d642c 100644 --- a/src/guessEnv.ts +++ b/src/guessEnv.ts @@ -10,5 +10,3 @@ export const guessEnv = () => { } return undefined; }; - -console.log(guessEnv()); From a4144364a0fc408f854bfa9ec4037816253492fa Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Sat, 3 Jul 2021 00:15:54 +0530 Subject: [PATCH 043/254] (refactor) move things around Signed-off-by: Muthu Kumar --- scripts/fetchARIA.ts | 2 +- scripts/fetchAttributes.ts | 4 ++-- scripts/{ => util}/codegen.ts | 0 scripts/{ => util}/getSplType.ts | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename scripts/{ => util}/codegen.ts (100%) rename scripts/{ => util}/getSplType.ts (100%) diff --git a/scripts/fetchARIA.ts b/scripts/fetchARIA.ts index dba799e..dd08ae2 100644 --- a/scripts/fetchARIA.ts +++ b/scripts/fetchARIA.ts @@ -1,6 +1,6 @@ import { DOMParser } from "https://deno.land/x/deno_dom@v0.1.12-alpha/deno-dom-wasm.ts"; -import { propsToType } from "./codegen.ts"; +import { propsToType } from "./util/codegen.ts"; const chunk = (arr: X[], size: number): X[][] => Array.from({ length: Math.ceil(arr.length / size) }, (_, i) => diff --git a/scripts/fetchAttributes.ts b/scripts/fetchAttributes.ts index 0653a89..57be20d 100644 --- a/scripts/fetchAttributes.ts +++ b/scripts/fetchAttributes.ts @@ -1,7 +1,7 @@ import { DOMParser } from "https://deno.land/x/deno_dom@v0.1.12-alpha/deno-dom-wasm.ts"; -import { propsToType } from "./codegen.ts"; -import { getSplType } from "./getSplType.ts"; +import { propsToType } from "./util/codegen.ts"; +import { getSplType } from "./util/getSplType.ts"; const html = await fetch( "https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes", diff --git a/scripts/codegen.ts b/scripts/util/codegen.ts similarity index 100% rename from scripts/codegen.ts rename to scripts/util/codegen.ts diff --git a/scripts/getSplType.ts b/scripts/util/getSplType.ts similarity index 100% rename from scripts/getSplType.ts rename to scripts/util/getSplType.ts From 875456b55a920a9c8f6d095a7ad478123e74a0a7 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Sat, 3 Jul 2021 00:28:21 +0530 Subject: [PATCH 044/254] (fix) tempfix for upstream Deno and TS breaking our types Signed-off-by: Muthu Kumar --- src/render.ts | 14 ++++++++++++-- test.browser.ts | 3 +-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/render.ts b/src/render.ts index 9271f1b..ff3c013 100644 --- a/src/render.ts +++ b/src/render.ts @@ -1,5 +1,15 @@ -/// -/// +/// + +// LKG upstream DOM lib +/// + +// Some day, one of these will work. We wait for some day. + +// conflicts with Deno types +// + +// Incorrect Element.append type, does not allow ChildNode +// import { Node, Nodeish, HTMLNode } from "./node.ts"; import { Attr } from "./attributes.ts"; diff --git a/test.browser.ts b/test.browser.ts index f30b7ea..818eb22 100644 --- a/test.browser.ts +++ b/test.browser.ts @@ -1,5 +1,4 @@ -/// -/// +/// import { elements, renderDOM, State } from "./mod.ts"; From 3f46d81c48f1dc2b61b7d10aa1369502319b5052 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Sat, 3 Jul 2021 00:54:02 +0530 Subject: [PATCH 045/254] (fix) comment --- src/guessEnv.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/guessEnv.ts b/src/guessEnv.ts index 08d642c..5937d8b 100644 --- a/src/guessEnv.ts +++ b/src/guessEnv.ts @@ -1,4 +1,4 @@ -//declare is used to avoid ts-ignoring in multiple places +// declare expected globals to avoid multiple ts-ignore declare const process: { version: unknown }; declare const window: { Deno: unknown; document: unknown }; From 70f30d810fa2f8f5985ab5c6950df219dae5b72b Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Sun, 4 Jul 2021 23:05:55 +0530 Subject: [PATCH 046/254] (feat) only empty elements self-close Signed-off-by: Muthu Kumar --- src/emptyElements.ts | 20 ++++++++++++++++++++ src/h_element.ts | 24 ++++++++++++------------ src/node.ts | 32 +++++++++++++++++++++----------- src/render.ts | 6 ++++-- src/util.ts | 2 ++ test.ts | 11 +++++++++-- 6 files changed, 68 insertions(+), 27 deletions(-) create mode 100644 src/emptyElements.ts diff --git a/src/emptyElements.ts b/src/emptyElements.ts new file mode 100644 index 0000000..f526a5b --- /dev/null +++ b/src/emptyElements.ts @@ -0,0 +1,20 @@ +import { unionFromSet } from "./util.ts"; + +export const EmptyElements = new Set([ + "area", + "base", + "br", + "col", + "embed", + "hr", + "img", + "input", + "link", + "meta", + "param", + "source", + "track", + "wbr", +] as const); + +export type EmptyElements = unionFromSet; diff --git a/src/h_element.ts b/src/h_element.ts index fdad94d..cfc28f8 100644 --- a/src/h_element.ts +++ b/src/h_element.ts @@ -1,19 +1,19 @@ -import { Nodeish, Node, h } from "./node.ts"; +import { Nodeish, Node, NonEmptyElement, h } from "./node.ts"; import { Element, CustomTag } from "./elements.ts"; +import { EmptyElements } from "./emptyElements.ts"; import { Attr } from "./attributes.ts"; export type hElement< Tag extends Element = Element, Attrs extends Attr = Attr, -> = - // - (() => Node) & - // is a duplicate type, but gives clean intellisense - ((childNode: Nodeish) => Node) & - // order must be preserved, otherwise TS thinks State -> Node is invalid - ((...childNodes: Nodeish[]) => Node) & - ((props: Attrs) => Node) & - ((props: Attrs, ...childNodes: Nodeish[]) => Node); +> = (() => Node) & + (Tag extends EmptyElements + ? (props: Attrs) => Node + : ((childNode: Nodeish) => Node) & + // order must be preserved, otherwise TS thinks State -> Node is invalid + ((...childNodes: Nodeish[]) => Node) & + ((props: Attrs) => Node) & + ((props: Attrs, ...childNodes: Nodeish[]) => Node)); const hElementCache = new Map(); @@ -29,10 +29,10 @@ function getHElement( props?: Attr | Nodeish, ...childNodes: Nodeish[] ) { - return h(element, props, ...childNodes); + return h(element as NonEmptyElement, props, ...childNodes); } as hE; - hElementCache.set(element, hElement); + hElementCache.set(element, hElement as hElement); return hElement; } diff --git a/src/node.ts b/src/node.ts index 13bd670..c4c1f7e 100644 --- a/src/node.ts +++ b/src/node.ts @@ -1,8 +1,11 @@ import { Element } from "./elements.ts"; +import { EmptyElements } from "./emptyElements.ts"; import { Attr } from "./attributes.ts"; import { Falsy, isFalsy } from "./util.ts"; import { SimpleState, SimpleStateRO, isState } from "./state.ts"; +export type NonEmptyElement = Exclude; + export type TextNode = string; export class HTMLNode { @@ -29,28 +32,35 @@ export type Nodeish = export const isNode = (n: any): n is Node | HTMLNode | TextNode => n instanceof Node || n instanceof HTMLNode || typeof n === "string"; -export function h( - elem: Tag, - props?: Attrs | Falsy, -): Node; +export function h< + Tag extends NonEmptyElement = NonEmptyElement, + Attrs extends Attr = Attr, +>(elem: Tag, props?: Attrs | Falsy): Node; -export function h( +export function h( elem: Tag, ...children: Nodeish[] ): Node; -export function h = Attr>( - elem: Tag, - props: Attr, - ...children: Nodeish[] -): Node; +export function h< + Tag extends NonEmptyElement, + Attrs extends Attr = Attr, +>(elem: Tag, props: Attr, ...children: Nodeish[]): Node; -export function h = Attr>( +export function h< + Tag extends NonEmptyElement, + Attrs extends Attr = Attr, +>( elem: Tag, props?: Attrs | Nodeish | Falsy, ...children: Nodeish[] ): Node; +export function h< + Tag extends EmptyElements, + Attrs extends Attr = Attr, +>(elem: Tag, props?: Attrs | Nodeish | Falsy): Node; + export function h( elem: Element, props?: Attr | Nodeish, diff --git a/src/render.ts b/src/render.ts index 62211ac..50e1c5a 100644 --- a/src/render.ts +++ b/src/render.ts @@ -12,6 +12,7 @@ // import { Node, Nodeish, HTMLNode } from "./node.ts"; +import { EmptyElements } from "./emptyElements.ts"; import { Attr } from "./attributes.ts"; import { isState } from "./state.ts"; import { Falsy, isFalsy, escapeHTML } from "./util.ts"; @@ -48,10 +49,11 @@ export function renderHTML(node: Nodeish): string { if (attr) stringified += " " + attr; - if (node.children.length) + if (EmptyElements.has(node.tag as EmptyElements)) stringified += " />"; + else if (node.children.length) stringified += ">" + node.children.map(renderHTML).join("") + ``; - else stringified += " />"; + else stringified += `>`; return stringified; } diff --git a/src/util.ts b/src/util.ts index 59386f6..bdf9100 100644 --- a/src/util.ts +++ b/src/util.ts @@ -14,3 +14,5 @@ export type Falsy = false | "" | 0 | 0n | undefined | null; export const Falsy = new Set([false, "", 0, 0n, undefined, null]); // deno-lint-ignore no-explicit-any export const isFalsy = (n: any): n is Falsy => Falsy.has(n); + +export type unionFromSet = T extends Set ? U : never; diff --git a/test.ts b/test.ts index baae234..2d2185d 100644 --- a/test.ts +++ b/test.ts @@ -56,7 +56,7 @@ Deno.test({ aria: { disabled: "true" }, }), ), - `
`, + `
`, ); }, }); @@ -111,7 +111,7 @@ Deno.test({ name: "renderHTML with custom element", fn: () => { const [el] = elements("custom-element"); - assertEquals(renderHTML(el()), ``); + assertEquals(renderHTML(el()), ``); }, }); @@ -133,3 +133,10 @@ Deno.test({ assertEquals(renderHTML(input({ step: 5 })), ``); }, }); + +Deno.test({ + name: "renderHTML with emptyElements", + fn: () => { + assertEquals(renderHTML(br()), `
`); + }, +}); From 0973dd970b7359de3e582b3289fd1323dc1c55a4 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Sun, 4 Jul 2021 23:50:25 +0530 Subject: [PATCH 047/254] (feat) add events support Signed-off-by: Muthu Kumar --- scripts/fetchAttributes.ts | 7 ++++++- src/attributes.ts | 7 ++++++- src/domTypes.ts | 20 +++++++++++++++++++ src/render.ts | 39 +++++++++++++++++++------------------- test.browser.ts | 20 ++++++++++++++----- test.ts | 20 +++++++++++++++++++ 6 files changed, 86 insertions(+), 27 deletions(-) create mode 100644 src/domTypes.ts diff --git a/scripts/fetchAttributes.ts b/scripts/fetchAttributes.ts index 57be20d..4d07905 100644 --- a/scripts/fetchAttributes.ts +++ b/scripts/fetchAttributes.ts @@ -82,6 +82,7 @@ const elementTypes = Object.keys(elements) const types = `import { Element } from "./elements.ts"; import { AriaRoles, AriaAttributes } from "./aria.ts"; +import { DOMEvents } from "./domTypes.ts"; type ${globalTypes} @@ -105,6 +106,10 @@ export type Attr = // { [data in DataAttr]?: string } Partial< GlobalAttrs & { + /** + * ref callback is called on mount of element with the DOM element. + */ + ref: (el: HTMLElement) => void, /** * When the element lacks suitable ARIA-semantics, authors must * assign an ARIA-role. Addition of ARIA semantics only exposes @@ -122,7 +127,7 @@ export type Attr = * @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA */ aria: AriaAttributes; - } & (ElementAttrs & { [k: string]: unknown })[E] + } & (ElementAttrs & { [k: string]: unknown })[E] & DOMEvents >; `; diff --git a/src/attributes.ts b/src/attributes.ts index ed20cb4..1b34c77 100644 --- a/src/attributes.ts +++ b/src/attributes.ts @@ -1,5 +1,6 @@ import { Element } from "./elements.ts"; import { AriaRoles, AriaAttributes } from "./aria.ts"; +import { DOMEvents } from "./domTypes.ts"; type GlobalAttrs = { /** @@ -1364,6 +1365,10 @@ export type Attr = // { [data in DataAttr]?: string } Partial< GlobalAttrs & { + /** + * ref callback is called on mount of element with the DOM element. + */ + ref: (el: HTMLElement) => void, /** * When the element lacks suitable ARIA-semantics, authors must * assign an ARIA-role. Addition of ARIA semantics only exposes @@ -1381,5 +1386,5 @@ export type Attr = * @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA */ aria: AriaAttributes; - } & (ElementAttrs & { [k: string]: unknown })[E] + } & (ElementAttrs & { [k: string]: unknown })[E] & DOMEvents >; diff --git a/src/domTypes.ts b/src/domTypes.ts new file mode 100644 index 0000000..b647721 --- /dev/null +++ b/src/domTypes.ts @@ -0,0 +1,20 @@ +/// + +// LKG upstream DOM lib +/// + +// Some day, one of these will work. We wait for some day. + +// conflicts with Deno types +// + +// Incorrect Element.append type, does not allow ChildNode +// + +export type HtmlElement = HTMLElement; + +type EMap = GlobalEventHandlersEventMap; + +export type DOMEvents = { + on: Partial<{ [Event in keyof EMap]: (e: EMap[Event]) => void }>; +}; diff --git a/src/render.ts b/src/render.ts index 50e1c5a..7335261 100644 --- a/src/render.ts +++ b/src/render.ts @@ -1,31 +1,27 @@ -/// - -// LKG upstream DOM lib -/// - -// Some day, one of these will work. We wait for some day. - -// conflicts with Deno types -// - -// Incorrect Element.append type, does not allow ChildNode -// - import { Node, Nodeish, HTMLNode } from "./node.ts"; import { EmptyElements } from "./emptyElements.ts"; import { Attr } from "./attributes.ts"; import { isState } from "./state.ts"; import { Falsy, isFalsy, escapeHTML } from "./util.ts"; import { guessEnv } from "./guessEnv.ts"; +import { HtmlElement } from "./domTypes.ts"; + +// deno-lint-ignore no-explicit-any +type AnyFunction = (...props: any[]) => void; type AttributeObject = Record< string, - string | number | boolean | Record + | string + | number + | boolean + | AnyFunction + | Record >; function attrifyHTML(attrs: AttributeObject, prefix = ""): string { return Object.entries(attrs) .map(([attr, value]) => { + if (attr === "on" || typeof value === "function") return ""; if (value === "") return value; if (typeof value === "object") return attrifyHTML(value, attr + "-"); @@ -64,7 +60,7 @@ type NodeishtoDOM = N extends Falsy ? ChildNode | "" : N extends HTMLNode ? ChildNode | "" - : HTMLElement; + : HtmlElement; function htmlStringToElement(html: string) { var template = document.createElement("template"); @@ -74,24 +70,27 @@ function htmlStringToElement(html: string) { return template.content.firstChild || ""; } -function attrifyDOM(el: HTMLElement, attrs: AttributeObject, prefix = "") { +function attrifyDOM(el: HtmlElement, attrs: AttributeObject, prefix = "") { for (const attr in attrs) { const value = attrs[attr as keyof Attr]; if (value === "") el.setAttribute(prefix + attr, ""); + else if (attr === "ref" && typeof value === "function") value(el); else if (typeof value === "object") attrifyDOM(el, value, attr + "-"); else if (typeof value === "boolean") if (value) el.setAttribute(prefix + attr, ""); // no-op else null; + else if (prefix === "on-" && typeof value === "function") + el.addEventListener(attr, value); else if (value) el.setAttribute(prefix + attr, String(value)); } } const toDOM = function toDOM( node: N, - parent: HTMLElement, + parent: HtmlElement, opts: { emptyTextNodes?: boolean } = {}, -): "" | ChildNode | HTMLElement { +): "" | ChildNode | HtmlElement { if (typeof node === "string" && (node !== "" || opts.emptyTextNodes)) return document.createTextNode(escapeHTML(node)); if (isFalsy(node)) return ""; @@ -126,11 +125,11 @@ const toDOM = function toDOM( } return el; -} as (node: N, parent: HTMLElement) => NodeishtoDOM; +} as (node: N, parent: HtmlElement) => NodeishtoDOM; export function renderDOM< HyNode extends Node | string, - RootNode extends HTMLElement, + RootNode extends HtmlElement, >(rootNode: RootNode, hyNode: HyNode) { const env = guessEnv(); if (env !== "browser") diff --git a/test.browser.ts b/test.browser.ts index 818eb22..a82614a 100644 --- a/test.browser.ts +++ b/test.browser.ts @@ -1,6 +1,6 @@ /// -import { elements, renderDOM, State } from "./mod.ts"; +import { elements, renderDOM, State, bindInput } from "./mod.ts"; const { div, input, h3, p, span } = elements; @@ -11,11 +11,21 @@ renderDOM( div( { class: "container" }, h3("Enter a number, it should double below"), - input({ id: "input-el", value: state.init }), + input({ + id: "input-el", + value: state.init, + on: { + input: e => { + state.publish( + (e.target as unknown as { value: string }).value, + ); + }, + }, + }), p(state.transform(v => span(String(parseFloat(v) * 2)))), ), ); -document.querySelector("#input-el")?.addEventListener("input", e => { - state.publish((e.target as unknown as { value: string }).value); -}); +// document.querySelector("#input-el")?.addEventListener("input", e => { +// state.publish((e.target as unknown as { value: string }).value); +// }); diff --git a/test.ts b/test.ts index 2d2185d..19be201 100644 --- a/test.ts +++ b/test.ts @@ -140,3 +140,23 @@ Deno.test({ assertEquals(renderHTML(br()), `
`); }, }); + +Deno.test({ + name: "renderHTML with event listener", + fn: () => { + assertEquals( + renderHTML( + input({ + on: { + input: e => + console.log( + (e?.target as unknown as { value: string }) + .value, + ), + }, + }), + ), + ``, + ); + }, +}); From 5ba3899d07d7517851a354cd158f39bf63146537 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Sun, 4 Jul 2021 23:52:16 +0530 Subject: [PATCH 048/254] (feat) add domutils - bindInput Signed-off-by: Muthu Kumar --- mod.ts | 1 + src/domutils.ts | 8 ++++++++ src/state.ts | 6 ++++-- test.browser.ts | 8 +------- 4 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 src/domutils.ts diff --git a/mod.ts b/mod.ts index 6981e2f..a1092d9 100644 --- a/mod.ts +++ b/mod.ts @@ -5,3 +5,4 @@ export * from "./src/state.ts"; export * from "./src/h_element.ts"; export * from "./src/parse.ts"; export * from "./src/render.ts"; +export * from "./src/domutils.ts"; diff --git a/src/domutils.ts b/src/domutils.ts new file mode 100644 index 0000000..33480f0 --- /dev/null +++ b/src/domutils.ts @@ -0,0 +1,8 @@ +import { SimpleState } from "./state.ts"; + +export const bindInput = + (state: State) => + (el: HTMLElement) => + el.addEventListener("input", e => + state.publish((e?.target as unknown as { value: string }).value), + ); diff --git a/src/state.ts b/src/state.ts index 9f35409..607f943 100644 --- a/src/state.ts +++ b/src/state.ts @@ -2,7 +2,8 @@ export const STATE = Symbol("@hyperactive/state"); export type Subscriber = (val: T) => void; -export type SimpleStateRO = { +// deno-lint-ignore no-explicit-any +export type SimpleStateRO = { init: T; subscribe: (f: Subscriber) => void; transform: U>( @@ -11,7 +12,8 @@ export type SimpleStateRO = { [STATE]: true; }; -export type SimpleState = SimpleStateRO & { +// deno-lint-ignore no-explicit-any +export type SimpleState = SimpleStateRO & { publish: (next: T) => void; readonly: () => SimpleStateRO; }; diff --git a/test.browser.ts b/test.browser.ts index a82614a..9ab5088 100644 --- a/test.browser.ts +++ b/test.browser.ts @@ -12,15 +12,9 @@ renderDOM( { class: "container" }, h3("Enter a number, it should double below"), input({ + ref: bindInput(state), id: "input-el", value: state.init, - on: { - input: e => { - state.publish( - (e.target as unknown as { value: string }).value, - ); - }, - }, }), p(state.transform(v => span(String(parseFloat(v) * 2)))), ), From 68df0dc4921b271746eb26c57846564afa39944d Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Wed, 25 Aug 2021 09:37:25 +0530 Subject: [PATCH 049/254] fix: renderHTML must escape textnodes differently from attributes Signed-off-by: Muthu Kumar --- src/render.ts | 8 ++++---- src/util.ts | 5 ++++- test.ts | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/render.ts b/src/render.ts index 7335261..3ff3130 100644 --- a/src/render.ts +++ b/src/render.ts @@ -2,7 +2,7 @@ import { Node, Nodeish, HTMLNode } from "./node.ts"; import { EmptyElements } from "./emptyElements.ts"; import { Attr } from "./attributes.ts"; import { isState } from "./state.ts"; -import { Falsy, isFalsy, escapeHTML } from "./util.ts"; +import { Falsy, isFalsy, escapeAttr, escapeTextNode } from "./util.ts"; import { guessEnv } from "./guessEnv.ts"; import { HtmlElement } from "./domTypes.ts"; @@ -28,14 +28,14 @@ function attrifyHTML(attrs: AttributeObject, prefix = ""): string { if (typeof value === "boolean") if (value) return `${prefix + attr}`; else return ""; - if (value) return `${prefix + attr}="${value}"`; + if (value) return `${prefix + attr}="${escapeAttr(String(value))}"`; }) .join(" "); } export function renderHTML(node: Nodeish): string { if (isFalsy(node)) return ""; - if (typeof node === "string") return escapeHTML(node); + if (typeof node === "string") return escapeTextNode(node); if (node instanceof HTMLNode) return node.htmlString; if (isState(node)) return renderHTML(node.init); @@ -92,7 +92,7 @@ const toDOM = function toDOM( opts: { emptyTextNodes?: boolean } = {}, ): "" | ChildNode | HtmlElement { if (typeof node === "string" && (node !== "" || opts.emptyTextNodes)) - return document.createTextNode(escapeHTML(node)); + return document.createTextNode(node); if (isFalsy(node)) return ""; if (node instanceof HTMLNode) return htmlStringToElement(node.htmlString); if (isState(node)) { diff --git a/src/util.ts b/src/util.ts index bdf9100..00dee2a 100644 --- a/src/util.ts +++ b/src/util.ts @@ -6,9 +6,12 @@ const escapables = { '"': """, }; -export const escapeHTML = (s: string) => +export const escapeAttr = (s: string) => s.replace(/<|>|&|"|'/g, r => escapables[r as keyof typeof escapables] || r); +export const escapeTextNode = (s: string) => + s.replace(/<|>|&/g, r => escapables[r as keyof typeof escapables] || r); + export type Falsy = false | "" | 0 | 0n | undefined | null; export const Falsy = new Set([false, "", 0, 0n, undefined, null]); diff --git a/test.ts b/test.ts index 19be201..d5cbcc9 100644 --- a/test.ts +++ b/test.ts @@ -14,6 +14,25 @@ Deno.test({ }, }); +Deno.test({ + name: "renderHTML simple -- escaping attribute and text nodes", + fn: () => { + assertEquals( + renderHTML( + div( + { + id: "hello", + class: "world", + style: `content: '"&"
'`, + }, + "<'\"Hello&world\"'>", + ), + ), + `
<'"Hello&world"'>
`, + ); + }, +}); + assertEquals( renderHTML( div( From bd72bc7799f8600ad17785d0038fa8b96358fa80 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Thu, 26 Aug 2021 03:15:27 +0530 Subject: [PATCH 050/254] feat: major refactor + non-polluting dom-lib dom.lib.d.ts now explicitly exports interfaces we explicitly import Signed-off-by: Muthu Kumar --- external/dom.lib.ts | 26693 ++++++++++++++++++++++++++++ mod.ts | 9 +- scripts/fetchARIA.ts | 13 +- scripts/fetchAttributes.ts | 9 +- scripts/gen.ts | 3 + scripts/generateElements.ts | 7 +- scripts/util/codegen.ts | 5 + src/domTypes.ts | 20 - src/guessEnv.ts | 2 +- src/{h_element.ts => hElement.ts} | 6 +- src/{ => lib}/aria.ts | 3 + src/{ => lib}/attributes.ts | 17 +- src/lib/dom.ts | 13 + src/{ => lib}/elements.ts | 0 src/{ => lib}/emptyElements.ts | 2 +- src/node.ts | 6 +- src/{render.ts => renderDOM.ts} | 58 +- src/renderHTML.ts | 52 + test.ts | 2 +- 19 files changed, 26830 insertions(+), 90 deletions(-) create mode 100644 external/dom.lib.ts create mode 100644 scripts/gen.ts delete mode 100644 src/domTypes.ts rename src/{h_element.ts => hElement.ts} (91%) rename src/{ => lib}/aria.ts (98%) rename src/{ => lib}/attributes.ts (98%) create mode 100644 src/lib/dom.ts rename src/{ => lib}/elements.ts (100%) rename src/{ => lib}/emptyElements.ts (84%) rename src/{render.ts => renderDOM.ts} (62%) create mode 100644 src/renderHTML.ts diff --git a/external/dom.lib.ts b/external/dom.lib.ts new file mode 100644 index 0000000..af59aba --- /dev/null +++ b/external/dom.lib.ts @@ -0,0 +1,26693 @@ +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ + +//// + +///////////////////////////// +/// DOM APIs +///////////////////////////// + +export interface AddEventListenerOptions extends EventListenerOptions { + once?: boolean; + passive?: boolean; +} + +export interface AddressErrors { + addressLine?: string; + city?: string; + country?: string; + dependentLocality?: string; + organization?: string; + phone?: string; + postalCode?: string; + recipient?: string; + region?: string; + sortingCode?: string; +} + +export interface AesCbcParams extends Algorithm { + iv: + | Int8Array + | Int16Array + | Int32Array + | Uint8Array + | Uint16Array + | Uint32Array + | Uint8ClampedArray + | Float32Array + | Float64Array + | DataView + | ArrayBuffer; +} + +export interface AesCtrParams extends Algorithm { + counter: + | Int8Array + | Int16Array + | Int32Array + | Uint8Array + | Uint16Array + | Uint32Array + | Uint8ClampedArray + | Float32Array + | Float64Array + | DataView + | ArrayBuffer; + length: number; +} + +export interface AesDerivedKeyParams extends Algorithm { + length: number; +} + +export interface AesGcmParams extends Algorithm { + additionalData?: + | Int8Array + | Int16Array + | Int32Array + | Uint8Array + | Uint16Array + | Uint32Array + | Uint8ClampedArray + | Float32Array + | Float64Array + | DataView + | ArrayBuffer; + iv: + | Int8Array + | Int16Array + | Int32Array + | Uint8Array + | Uint16Array + | Uint32Array + | Uint8ClampedArray + | Float32Array + | Float64Array + | DataView + | ArrayBuffer; + tagLength?: number; +} + +export interface AesKeyAlgorithm extends KeyAlgorithm { + length: number; +} + +export interface AesKeyGenParams extends Algorithm { + length: number; +} + +export interface Algorithm { + name: string; +} + +export interface AnalyserOptions extends AudioNodeOptions { + fftSize?: number; + maxDecibels?: number; + minDecibels?: number; + smoothingTimeConstant?: number; +} + +export interface AnimationEventInit extends EventInit { + animationName?: string; + elapsedTime?: number; + pseudoElement?: string; +} + +export interface AnimationPlaybackEventInit extends EventInit { + currentTime?: number | null; + timelineTime?: number | null; +} + +export interface AssignedNodesOptions { + flatten?: boolean; +} + +export interface AudioBufferOptions { + length: number; + numberOfChannels?: number; + sampleRate: number; +} + +export interface AudioBufferSourceOptions { + buffer?: AudioBuffer | null; + detune?: number; + loop?: boolean; + loopEnd?: number; + loopStart?: number; + playbackRate?: number; +} + +export interface AudioContextInfo { + currentTime?: number; + sampleRate?: number; +} + +export interface AudioContextOptions { + latencyHint?: AudioContextLatencyCategory | number; + sampleRate?: number; +} + +export interface AudioNodeOptions { + channelCount?: number; + channelCountMode?: ChannelCountMode; + channelInterpretation?: ChannelInterpretation; +} + +export interface AudioParamDescriptor { + automationRate?: AutomationRate; + defaultValue?: number; + maxValue?: number; + minValue?: number; + name: string; +} + +export interface AudioProcessingEventInit extends EventInit { + inputBuffer: AudioBuffer; + outputBuffer: AudioBuffer; + playbackTime: number; +} + +export interface AudioTimestamp { + contextTime?: number; + performanceTime?: number; +} + +export interface AudioWorkletNodeOptions extends AudioNodeOptions { + numberOfInputs?: number; + numberOfOutputs?: number; + outputChannelCount?: number[]; + parameterData?: Record; + processorOptions?: any; +} + +export interface AuthenticationExtensionsClientInputs { + appid?: string; + appidExclude?: string; + credProps?: boolean; + uvm?: boolean; +} + +export interface AuthenticationExtensionsClientOutputs { + appid?: boolean; + credProps?: CredentialPropertiesOutput; + uvm?: UvmEntries; +} + +export interface AuthenticatorSelectionCriteria { + authenticatorAttachment?: AuthenticatorAttachment; + requireResidentKey?: boolean; + residentKey?: ResidentKeyRequirement; + userVerification?: UserVerificationRequirement; +} + +export interface BiquadFilterOptions extends AudioNodeOptions { + Q?: number; + detune?: number; + frequency?: number; + gain?: number; + type?: BiquadFilterType; +} + +export interface BlobPropertyBag { + endings?: EndingType; + type?: string; +} + +export interface ByteLengthChunk { + byteLength?: number; +} + +export interface CacheQueryOptions { + ignoreMethod?: boolean; + ignoreSearch?: boolean; + ignoreVary?: boolean; +} + +export interface CanvasRenderingContext2DSettings { + alpha?: boolean; + desynchronized?: boolean; +} + +export interface ChannelMergerOptions extends AudioNodeOptions { + numberOfInputs?: number; +} + +export interface ChannelSplitterOptions extends AudioNodeOptions { + numberOfOutputs?: number; +} + +export interface ClientQueryOptions { + includeUncontrolled?: boolean; + type?: ClientTypes; +} + +export interface ClipboardEventInit extends EventInit { + clipboardData?: DataTransfer | null; +} + +export interface CloseEventInit extends EventInit { + code?: number; + reason?: string; + wasClean?: boolean; +} + +export interface CompositionEventInit extends UIEventInit { + data?: string; +} + +export interface ComputedEffectTiming extends EffectTiming { + activeDuration?: number; + currentIteration?: number | null; + endTime?: number; + localTime?: number | null; + progress?: number | null; +} + +export interface ComputedKeyframe { + composite: CompositeOperationOrAuto; + computedOffset: number; + easing: string; + offset: number | null; + [property: string]: string | number | null | undefined; +} + +export interface ConfirmSiteSpecificExceptionsInformation + extends ExceptionInformation { + arrayOfDomainStrings?: string[]; +} + +export interface ConstantSourceOptions { + offset?: number; +} + +export interface ConstrainBooleanParameters { + exact?: boolean; + ideal?: boolean; +} + +export interface ConstrainDOMStringParameters { + exact?: string | string[]; + ideal?: string | string[]; +} + +export interface ConstrainDoubleRange extends DoubleRange { + exact?: number; + ideal?: number; +} + +export interface ConstrainULongRange extends ULongRange { + exact?: number; + ideal?: number; +} + +export interface ConstrainVideoFacingModeParameters { + exact?: VideoFacingModeEnum | VideoFacingModeEnum[]; + ideal?: VideoFacingModeEnum | VideoFacingModeEnum[]; +} + +export interface ConvolverOptions extends AudioNodeOptions { + buffer?: AudioBuffer | null; + disableNormalization?: boolean; +} + +export interface CredentialCreationOptions { + publicKey?: PublicKeyCredentialCreationOptions; + signal?: AbortSignal; +} + +export interface CredentialPropertiesOutput { + rk?: boolean; +} + +export interface CredentialRequestOptions { + mediation?: CredentialMediationRequirement; + publicKey?: PublicKeyCredentialRequestOptions; + signal?: AbortSignal; +} + +export interface CustomEventInit extends EventInit { + detail?: T; +} + +export interface DOMMatrix2DInit { + a?: number; + b?: number; + c?: number; + d?: number; + e?: number; + f?: number; + m11?: number; + m12?: number; + m21?: number; + m22?: number; + m41?: number; + m42?: number; +} + +export interface DOMMatrixInit extends DOMMatrix2DInit { + is2D?: boolean; + m13?: number; + m14?: number; + m23?: number; + m24?: number; + m31?: number; + m32?: number; + m33?: number; + m34?: number; + m43?: number; + m44?: number; +} + +export interface DOMPointInit { + w?: number; + x?: number; + y?: number; + z?: number; +} + +export interface DOMQuadInit { + p1?: DOMPointInit; + p2?: DOMPointInit; + p3?: DOMPointInit; + p4?: DOMPointInit; +} + +export interface DOMRectInit { + height?: number; + width?: number; + x?: number; + y?: number; +} + +export interface DelayOptions extends AudioNodeOptions { + delayTime?: number; + maxDelayTime?: number; +} + +export interface DeviceMotionEventAccelerationInit { + x?: number | null; + y?: number | null; + z?: number | null; +} + +export interface DeviceMotionEventInit extends EventInit { + acceleration?: DeviceMotionEventAccelerationInit; + accelerationIncludingGravity?: DeviceMotionEventAccelerationInit; + interval?: number; + rotationRate?: DeviceMotionEventRotationRateInit; +} + +export interface DeviceMotionEventRotationRateInit { + alpha?: number | null; + beta?: number | null; + gamma?: number | null; +} + +export interface DeviceOrientationEventInit extends EventInit { + absolute?: boolean; + alpha?: number | null; + beta?: number | null; + gamma?: number | null; +} + +export interface DevicePermissionDescriptor extends PermissionDescriptor { + deviceId?: string; + name: "camera" | "microphone" | "speaker"; +} + +export interface DocumentTimelineOptions { + originTime?: number; +} + +export interface DoubleRange { + max?: number; + min?: number; +} + +export interface DragEventInit extends MouseEventInit { + dataTransfer?: DataTransfer | null; +} + +export interface DynamicsCompressorOptions extends AudioNodeOptions { + attack?: number; + knee?: number; + ratio?: number; + release?: number; + threshold?: number; +} + +export interface EcKeyAlgorithm extends KeyAlgorithm { + namedCurve: NamedCurve; +} + +export interface EcKeyGenParams extends Algorithm { + namedCurve: NamedCurve; +} + +export interface EcKeyImportParams extends Algorithm { + namedCurve: NamedCurve; +} + +export interface EcdhKeyDeriveParams extends Algorithm { + public: CryptoKey; +} + +export interface EcdsaParams extends Algorithm { + hash: HashAlgorithmIdentifier; +} + +export interface EffectTiming { + delay?: number; + direction?: PlaybackDirection; + duration?: number | string; + easing?: string; + endDelay?: number; + fill?: FillMode; + iterationStart?: number; + iterations?: number; +} + +export interface ElementCreationOptions { + is?: string; +} + +export interface ElementDefinitionOptions { + extends?: string; +} + +export interface ErrorEventInit extends EventInit { + colno?: number; + error?: any; + filename?: string; + lineno?: number; + message?: string; +} + +export interface EventInit { + bubbles?: boolean; + cancelable?: boolean; + composed?: boolean; +} + +export interface EventListenerOptions { + capture?: boolean; +} + +export interface EventModifierInit extends UIEventInit { + altKey?: boolean; + ctrlKey?: boolean; + metaKey?: boolean; + modifierAltGraph?: boolean; + modifierCapsLock?: boolean; + modifierFn?: boolean; + modifierFnLock?: boolean; + modifierHyper?: boolean; + modifierNumLock?: boolean; + modifierScrollLock?: boolean; + modifierSuper?: boolean; + modifierSymbol?: boolean; + modifierSymbolLock?: boolean; + shiftKey?: boolean; +} + +export interface EventSourceInit { + withCredentials?: boolean; +} + +export interface ExceptionInformation { + domain?: string | null; +} + +export interface FilePropertyBag extends BlobPropertyBag { + lastModified?: number; +} + +export interface FocusEventInit extends UIEventInit { + relatedTarget?: EventTarget | null; +} + +export interface FocusNavigationEventInit extends EventInit { + navigationReason?: string | null; + originHeight?: number; + originLeft?: number; + originTop?: number; + originWidth?: number; +} + +export interface FocusNavigationOrigin { + originHeight?: number; + originLeft?: number; + originTop?: number; + originWidth?: number; +} + +export interface FocusOptions { + preventScroll?: boolean; +} + +export interface FullscreenOptions { + navigationUI?: FullscreenNavigationUI; +} + +export interface GainOptions extends AudioNodeOptions { + gain?: number; +} + +export interface GamepadEventInit extends EventInit { + gamepad: Gamepad; +} + +export interface GetNotificationOptions { + tag?: string; +} + +export interface GetRootNodeOptions { + composed?: boolean; +} + +export interface HashChangeEventInit extends EventInit { + newURL?: string; + oldURL?: string; +} + +export interface HkdfParams extends Algorithm { + hash: HashAlgorithmIdentifier; + info: + | Int8Array + | Int16Array + | Int32Array + | Uint8Array + | Uint16Array + | Uint32Array + | Uint8ClampedArray + | Float32Array + | Float64Array + | DataView + | ArrayBuffer; + salt: + | Int8Array + | Int16Array + | Int32Array + | Uint8Array + | Uint16Array + | Uint32Array + | Uint8ClampedArray + | Float32Array + | Float64Array + | DataView + | ArrayBuffer; +} + +export interface HmacImportParams extends Algorithm { + hash: HashAlgorithmIdentifier; + length?: number; +} + +export interface HmacKeyAlgorithm extends KeyAlgorithm { + hash: KeyAlgorithm; + length: number; +} + +export interface HmacKeyGenParams extends Algorithm { + hash: HashAlgorithmIdentifier; + length?: number; +} + +export interface IDBIndexParameters { + multiEntry?: boolean; + unique?: boolean; +} + +export interface IDBObjectStoreParameters { + autoIncrement?: boolean; + keyPath?: string | string[] | null; +} + +export interface IDBVersionChangeEventInit extends EventInit { + newVersion?: number | null; + oldVersion?: number; +} + +export interface IIRFilterOptions extends AudioNodeOptions { + feedback: number[]; + feedforward: number[]; +} + +export interface ImageBitmapOptions { + colorSpaceConversion?: ColorSpaceConversion; + imageOrientation?: ImageOrientation; + premultiplyAlpha?: PremultiplyAlpha; + resizeHeight?: number; + resizeQuality?: ResizeQuality; + resizeWidth?: number; +} + +export interface ImageBitmapRenderingContextSettings { + alpha?: boolean; +} + +export interface ImageEncodeOptions { + quality?: number; + type?: string; +} + +export interface ImportMeta { + url: string; +} + +export interface InputEventInit extends UIEventInit { + data?: string | null; + inputType?: string; + isComposing?: boolean; +} + +export interface IntersectionObserverEntryInit { + boundingClientRect: DOMRectInit; + intersectionRatio: number; + intersectionRect: DOMRectInit; + isIntersecting: boolean; + rootBounds: DOMRectInit | null; + target: Element; + time: number; +} + +export interface IntersectionObserverInit { + root?: Element | Document | null; + rootMargin?: string; + threshold?: number | number[]; +} + +export interface JsonWebKey { + alg?: string; + crv?: string; + d?: string; + dp?: string; + dq?: string; + e?: string; + ext?: boolean; + k?: string; + key_ops?: string[]; + kty?: string; + n?: string; + oth?: RsaOtherPrimesInfo[]; + p?: string; + q?: string; + qi?: string; + use?: string; + x?: string; + y?: string; +} + +export interface KeyAlgorithm { + name: string; +} + +export interface KeyboardEventInit extends EventModifierInit { + /** @deprecated */ + charCode?: number; + code?: string; + isComposing?: boolean; + key?: string; + /** @deprecated */ + keyCode?: number; + location?: number; + repeat?: boolean; +} + +export interface Keyframe { + composite?: CompositeOperationOrAuto; + easing?: string; + offset?: number | null; + [property: string]: string | number | null | undefined; +} + +export interface KeyframeAnimationOptions extends KeyframeEffectOptions { + id?: string; +} + +export interface KeyframeEffectOptions extends EffectTiming { + composite?: CompositeOperation; + iterationComposite?: IterationCompositeOperation; +} + +export interface MediaElementAudioSourceOptions { + mediaElement: HTMLMediaElement; +} + +export interface MediaEncryptedEventInit extends EventInit { + initData?: ArrayBuffer | null; + initDataType?: string; +} + +export interface MediaKeyMessageEventInit extends EventInit { + message: ArrayBuffer; + messageType: MediaKeyMessageType; +} + +export interface MediaKeySystemConfiguration { + audioCapabilities?: MediaKeySystemMediaCapability[]; + distinctiveIdentifier?: MediaKeysRequirement; + initDataTypes?: string[]; + label?: string; + persistentState?: MediaKeysRequirement; + sessionTypes?: string[]; + videoCapabilities?: MediaKeySystemMediaCapability[]; +} + +export interface MediaKeySystemMediaCapability { + contentType?: string; + robustness?: string; +} + +export interface MediaQueryListEventInit extends EventInit { + matches?: boolean; + media?: string; +} + +export interface MediaStreamAudioSourceOptions { + mediaStream: MediaStream; +} + +export interface MediaStreamConstraints { + audio?: boolean | MediaTrackConstraints; + peerIdentity?: string; + video?: boolean | MediaTrackConstraints; +} + +export interface MediaStreamErrorEventInit extends EventInit { + error?: MediaStreamError | null; +} + +export interface MediaStreamEventInit extends EventInit { + stream?: MediaStream; +} + +export interface MediaStreamTrackAudioSourceOptions { + mediaStreamTrack: MediaStreamTrack; +} + +export interface MediaStreamTrackEventInit extends EventInit { + track: MediaStreamTrack; +} + +export interface MediaTrackCapabilities { + aspectRatio?: DoubleRange; + autoGainControl?: boolean[]; + channelCount?: ULongRange; + deviceId?: string; + echoCancellation?: boolean[]; + facingMode?: string[]; + frameRate?: DoubleRange; + groupId?: string; + height?: ULongRange; + latency?: DoubleRange; + noiseSuppression?: boolean[]; + resizeMode?: string[]; + sampleRate?: ULongRange; + sampleSize?: ULongRange; + width?: ULongRange; +} + +export interface MediaTrackConstraintSet { + aspectRatio?: ConstrainDouble; + autoGainControl?: ConstrainBoolean; + channelCount?: ConstrainULong; + deviceId?: ConstrainDOMString; + echoCancellation?: ConstrainBoolean; + facingMode?: ConstrainDOMString; + frameRate?: ConstrainDouble; + groupId?: ConstrainDOMString; + height?: ConstrainULong; + latency?: ConstrainDouble; + noiseSuppression?: ConstrainBoolean; + resizeMode?: ConstrainDOMString; + sampleRate?: ConstrainULong; + sampleSize?: ConstrainULong; + width?: ConstrainULong; +} + +export interface MediaTrackConstraints extends MediaTrackConstraintSet { + advanced?: MediaTrackConstraintSet[]; +} + +export interface MediaTrackSettings { + aspectRatio?: number; + autoGainControl?: boolean; + channelCount?: number; + deviceId?: string; + echoCancellation?: boolean; + facingMode?: string; + frameRate?: number; + groupId?: string; + height?: number; + latency?: number; + noiseSuppression?: boolean; + resizeMode?: string; + sampleRate?: number; + sampleSize?: number; + width?: number; +} + +export interface MediaTrackSupportedConstraints { + aspectRatio?: boolean; + autoGainControl?: boolean; + channelCount?: boolean; + deviceId?: boolean; + echoCancellation?: boolean; + facingMode?: boolean; + frameRate?: boolean; + groupId?: boolean; + height?: boolean; + latency?: boolean; + noiseSuppression?: boolean; + resizeMode?: boolean; + sampleRate?: boolean; + sampleSize?: boolean; + width?: boolean; +} + +export interface MessageEventInit extends EventInit { + data?: T; + lastEventId?: string; + origin?: string; + ports?: MessagePort[]; + source?: MessageEventSource | null; +} + +export interface MidiPermissionDescriptor extends PermissionDescriptor { + name: "midi"; + sysex?: boolean; +} + +export interface MouseEventInit extends EventModifierInit { + button?: number; + buttons?: number; + clientX?: number; + clientY?: number; + movementX?: number; + movementY?: number; + relatedTarget?: EventTarget | null; + screenX?: number; + screenY?: number; +} + +export interface MultiCacheQueryOptions extends CacheQueryOptions { + cacheName?: string; +} + +export interface MutationObserverInit { + /** + * Set to a list of attribute local names (without namespace) if not all attribute mutations need to be observed and attributes is true or omitted. + */ + attributeFilter?: string[]; + /** + * Set to true if attributes is true or omitted and target's attribute value before the mutation needs to be recorded. + */ + attributeOldValue?: boolean; + /** + * Set to true if mutations to target's attributes are to be observed. Can be omitted if attributeOldValue or attributeFilter is specified. + */ + attributes?: boolean; + /** + * Set to true if mutations to target's data are to be observed. Can be omitted if characterDataOldValue is specified. + */ + characterData?: boolean; + /** + * Set to true if characterData is set to true or omitted and target's data before the mutation needs to be recorded. + */ + characterDataOldValue?: boolean; + /** + * Set to true if mutations to target's children are to be observed. + */ + childList?: boolean; + /** + * Set to true if mutations to not just target, but also target's descendants are to be observed. + */ + subtree?: boolean; +} + +export interface NavigationPreloadState { + enabled?: boolean; + headerValue?: string; +} + +export interface NotificationAction { + action: string; + icon?: string; + title: string; +} + +export interface NotificationOptions { + actions?: NotificationAction[]; + badge?: string; + body?: string; + data?: any; + dir?: NotificationDirection; + icon?: string; + image?: string; + lang?: string; + renotify?: boolean; + requireInteraction?: boolean; + silent?: boolean; + tag?: string; + timestamp?: number; + vibrate?: VibratePattern; +} + +export interface OfflineAudioCompletionEventInit extends EventInit { + renderedBuffer: AudioBuffer; +} + +export interface OfflineAudioContextOptions { + length: number; + numberOfChannels?: number; + sampleRate: number; +} + +export interface OptionalEffectTiming { + delay?: number; + direction?: PlaybackDirection; + duration?: number | string; + easing?: string; + endDelay?: number; + fill?: FillMode; + iterationStart?: number; + iterations?: number; +} + +export interface OscillatorOptions extends AudioNodeOptions { + detune?: number; + frequency?: number; + periodicWave?: PeriodicWave; + type?: OscillatorType; +} + +export interface PageTransitionEventInit extends EventInit { + persisted?: boolean; +} + +export interface PannerOptions extends AudioNodeOptions { + coneInnerAngle?: number; + coneOuterAngle?: number; + coneOuterGain?: number; + distanceModel?: DistanceModelType; + maxDistance?: number; + orientationX?: number; + orientationY?: number; + orientationZ?: number; + panningModel?: PanningModelType; + positionX?: number; + positionY?: number; + positionZ?: number; + refDistance?: number; + rolloffFactor?: number; +} + +export interface PayerErrors { + email?: string; + name?: string; + phone?: string; +} + +export interface PaymentCurrencyAmount { + currency: string; + value: string; +} + +export interface PaymentDetailsBase { + displayItems?: PaymentItem[]; + modifiers?: PaymentDetailsModifier[]; + shippingOptions?: PaymentShippingOption[]; +} + +export interface PaymentDetailsInit extends PaymentDetailsBase { + id?: string; + total: PaymentItem; +} + +export interface PaymentDetailsModifier { + additionalDisplayItems?: PaymentItem[]; + data?: any; + supportedMethods: string | string[]; + total?: PaymentItem; +} + +export interface PaymentDetailsUpdate extends PaymentDetailsBase { + error?: string; + payerErrors?: PayerErrors; + paymentMethodErrors?: any; + shippingAddressErrors?: AddressErrors; + total?: PaymentItem; +} + +export interface PaymentItem { + amount: PaymentCurrencyAmount; + label: string; + pending?: boolean; +} + +export interface PaymentMethodChangeEventInit + extends PaymentRequestUpdateEventInit { + methodDetails?: any; + methodName?: string; +} + +export interface PaymentMethodData { + data?: any; + supportedMethods: string | string[]; +} + +export interface PaymentOptions { + requestBillingAddress?: boolean; + requestPayerEmail?: boolean; + requestPayerName?: boolean; + requestPayerPhone?: boolean; + requestShipping?: boolean; + shippingType?: PaymentShippingType; +} + +export interface PaymentRequestUpdateEventInit extends EventInit {} + +export interface PaymentShippingOption { + amount: PaymentCurrencyAmount; + id: string; + label: string; + selected?: boolean; +} + +export interface PaymentValidationErrors { + error?: string; + payer?: PayerErrors; + paymentMethod?: any; + shippingAddress?: AddressErrors; +} + +export interface Pbkdf2Params extends Algorithm { + hash: HashAlgorithmIdentifier; + iterations: number; + salt: + | Int8Array + | Int16Array + | Int32Array + | Uint8Array + | Uint16Array + | Uint32Array + | Uint8ClampedArray + | Float32Array + | Float64Array + | DataView + | ArrayBuffer; +} + +export interface PerformanceObserverInit { + buffered?: boolean; + entryTypes?: string[]; + type?: string; +} + +export interface PeriodicWaveConstraints { + disableNormalization?: boolean; +} + +export interface PeriodicWaveOptions extends PeriodicWaveConstraints { + imag?: number[] | Float32Array; + real?: number[] | Float32Array; +} + +export interface PermissionDescriptor { + name: PermissionName; +} + +export interface PointerEventInit extends MouseEventInit { + coalescedEvents?: PointerEvent[]; + height?: number; + isPrimary?: boolean; + pointerId?: number; + pointerType?: string; + predictedEvents?: PointerEvent[]; + pressure?: number; + tangentialPressure?: number; + tiltX?: number; + tiltY?: number; + twist?: number; + width?: number; +} + +export interface PopStateEventInit extends EventInit { + state?: any; +} + +export interface PositionOptions { + enableHighAccuracy?: boolean; + maximumAge?: number; + timeout?: number; +} + +export interface PostMessageOptions { + transfer?: any[]; +} + +export interface ProgressEventInit extends EventInit { + lengthComputable?: boolean; + loaded?: number; + total?: number; +} + +export interface PromiseRejectionEventInit extends EventInit { + promise: Promise; + reason?: any; +} + +export interface PropertyIndexedKeyframes { + composite?: CompositeOperationOrAuto | CompositeOperationOrAuto[]; + easing?: string | string[]; + offset?: number | (number | null)[]; + [property: string]: + | string + | string[] + | number + | null + | (number | null)[] + | undefined; +} + +export interface PublicKeyCredentialCreationOptions { + attestation?: AttestationConveyancePreference; + authenticatorSelection?: AuthenticatorSelectionCriteria; + challenge: BufferSource; + excludeCredentials?: PublicKeyCredentialDescriptor[]; + extensions?: AuthenticationExtensionsClientInputs; + pubKeyCredParams: PublicKeyCredentialParameters[]; + rp: PublicKeyCredentialRpEntity; + timeout?: number; + user: PublicKeyCredentialUserEntity; +} + +export interface PublicKeyCredentialDescriptor { + id: BufferSource; + transports?: AuthenticatorTransport[]; + type: PublicKeyCredentialType; +} + +export interface PublicKeyCredentialEntity { + name: string; +} + +export interface PublicKeyCredentialParameters { + alg: COSEAlgorithmIdentifier; + type: PublicKeyCredentialType; +} + +export interface PublicKeyCredentialRequestOptions { + allowCredentials?: PublicKeyCredentialDescriptor[]; + challenge: BufferSource; + extensions?: AuthenticationExtensionsClientInputs; + rpId?: string; + timeout?: number; + userVerification?: UserVerificationRequirement; +} + +export interface PublicKeyCredentialRpEntity extends PublicKeyCredentialEntity { + id?: string; +} + +export interface PublicKeyCredentialUserEntity + extends PublicKeyCredentialEntity { + displayName: string; + id: BufferSource; +} + +export interface PushPermissionDescriptor extends PermissionDescriptor { + name: "push"; + userVisibleOnly?: boolean; +} + +export interface PushSubscriptionJSON { + endpoint?: string; + expirationTime?: number | null; + keys?: Record; +} + +export interface PushSubscriptionOptionsInit { + applicationServerKey?: BufferSource | string | null; + userVisibleOnly?: boolean; +} + +export interface QueuingStrategy { + highWaterMark?: number; + size?: QueuingStrategySize; +} + +export interface QueuingStrategyInit { + /** + * Creates a new ByteLengthQueuingStrategy with the provided high water mark. + * + * Note that the provided high water mark will not be validated ahead of time. Instead, if it is negative, NaN, or not a number, the resulting ByteLengthQueuingStrategy will cause the corresponding stream constructor to throw. + */ + highWaterMark: number; +} + +export interface RTCAnswerOptions extends RTCOfferAnswerOptions {} + +export interface RTCCertificateExpiration { + expires?: number; +} + +export interface RTCConfiguration { + bundlePolicy?: RTCBundlePolicy; + certificates?: RTCCertificate[]; + iceCandidatePoolSize?: number; + iceServers?: RTCIceServer[]; + iceTransportPolicy?: RTCIceTransportPolicy; + rtcpMuxPolicy?: RTCRtcpMuxPolicy; +} + +export interface RTCDTMFToneChangeEventInit extends EventInit { + tone?: string; +} + +export interface RTCDataChannelEventInit extends EventInit { + channel: RTCDataChannel; +} + +export interface RTCDataChannelInit { + id?: number; + maxPacketLifeTime?: number; + maxRetransmits?: number; + negotiated?: boolean; + ordered?: boolean; + protocol?: string; +} + +export interface RTCDtlsFingerprint { + algorithm?: string; + value?: string; +} + +export interface RTCDtlsParameters { + fingerprints?: RTCDtlsFingerprint[]; + role?: RTCDtlsRole; +} + +export interface RTCErrorEventInit extends EventInit { + error: RTCError; +} + +export interface RTCErrorInit { + errorDetail: RTCErrorDetailType; + receivedAlert?: number; + sctpCauseCode?: number; + sdpLineNumber?: number; + sentAlert?: number; +} + +export interface RTCIceCandidateAttributes extends RTCStats { + addressSourceUrl?: string; + candidateType?: RTCStatsIceCandidateType; + ipAddress?: string; + portNumber?: number; + priority?: number; + transport?: string; +} + +export interface RTCIceCandidateComplete {} + +export interface RTCIceCandidateDictionary { + foundation?: string; + ip?: string; + msMTurnSessionId?: string; + port?: number; + priority?: number; + protocol?: RTCIceProtocol; + relatedAddress?: string; + relatedPort?: number; + tcpType?: RTCIceTcpCandidateType; + type?: RTCIceCandidateType; +} + +export interface RTCIceCandidateInit { + candidate?: string; + sdpMLineIndex?: number | null; + sdpMid?: string | null; + usernameFragment?: string | null; +} + +export interface RTCIceCandidatePair { + local?: RTCIceCandidate; + remote?: RTCIceCandidate; +} + +export interface RTCIceCandidatePairStats extends RTCStats { + availableIncomingBitrate?: number; + availableOutgoingBitrate?: number; + bytesDiscardedOnSend?: number; + bytesReceived?: number; + bytesSent?: number; + circuitBreakerTriggerCount?: number; + consentExpiredTimestamp?: number; + consentRequestsSent?: number; + currentRoundTripTime?: number; + currentRtt?: number; + firstRequestTimestamp?: number; + lastPacketReceivedTimestamp?: number; + lastPacketSentTimestamp?: number; + lastRequestTimestamp?: number; + lastResponseTimestamp?: number; + localCandidateId?: string; + nominated?: boolean; + packetsDiscardedOnSend?: number; + packetsReceived?: number; + packetsSent?: number; + priority?: number; + remoteCandidateId?: string; + requestsReceived?: number; + requestsSent?: number; + responsesReceived?: number; + responsesSent?: number; + retransmissionsReceived?: number; + retransmissionsSent?: number; + state?: RTCStatsIceCandidatePairState; + totalRoundTripTime?: number; + totalRtt?: number; + transportId?: string; +} + +export interface RTCIceGatherOptions { + gatherPolicy?: RTCIceGatherPolicy; + iceservers?: RTCIceServer[]; +} + +export interface RTCIceParameters { + password?: string; + usernameFragment?: string; +} + +export interface RTCIceServer { + credential?: string; + credentialType?: RTCIceCredentialType; + urls: string | string[]; + username?: string; +} + +export interface RTCIdentityProviderOptions { + peerIdentity?: string; + protocol?: string; + usernameHint?: string; +} + +export interface RTCInboundRTPStreamStats extends RTCRTPStreamStats { + bytesReceived?: number; + fractionLost?: number; + jitter?: number; + packetsLost?: number; + packetsReceived?: number; +} + +export interface RTCLocalSessionDescriptionInit { + sdp?: string; + type?: RTCSdpType; +} + +export interface RTCMediaStreamTrackStats extends RTCStats { + audioLevel?: number; + echoReturnLoss?: number; + echoReturnLossEnhancement?: number; + frameHeight?: number; + frameWidth?: number; + framesCorrupted?: number; + framesDecoded?: number; + framesDropped?: number; + framesPerSecond?: number; + framesReceived?: number; + framesSent?: number; + remoteSource?: boolean; + ssrcIds?: string[]; + trackIdentifier?: string; +} + +export interface RTCOfferAnswerOptions {} + +export interface RTCOfferOptions extends RTCOfferAnswerOptions { + iceRestart?: boolean; + offerToReceiveAudio?: boolean; + offerToReceiveVideo?: boolean; +} + +export interface RTCOutboundRTPStreamStats extends RTCRTPStreamStats { + bytesSent?: number; + packetsSent?: number; + roundTripTime?: number; + targetBitrate?: number; +} + +export interface RTCPeerConnectionIceErrorEventInit extends EventInit { + address?: string | null; + errorCode: number; + port?: number | null; + statusText?: string; + url?: string; +} + +export interface RTCPeerConnectionIceEventInit extends EventInit { + candidate?: RTCIceCandidate | null; + url?: string | null; +} + +export interface RTCRTPStreamStats extends RTCStats { + associateStatsId?: string; + codecId?: string; + firCount?: number; + isRemote?: boolean; + mediaTrackId?: string; + mediaType?: string; + nackCount?: number; + pliCount?: number; + sliCount?: number; + ssrc?: string; + transportId?: string; +} + +export interface RTCRtcpFeedback { + parameter?: string; + type?: string; +} + +export interface RTCRtcpParameters { + cname?: string; + reducedSize?: boolean; +} + +export interface RTCRtpCapabilities { + codecs: RTCRtpCodecCapability[]; + headerExtensions: RTCRtpHeaderExtensionCapability[]; +} + +export interface RTCRtpCodecCapability { + channels?: number; + clockRate: number; + mimeType: string; + sdpFmtpLine?: string; +} + +export interface RTCRtpCodecParameters { + channels?: number; + clockRate: number; + mimeType: string; + payloadType: number; + sdpFmtpLine?: string; +} + +export interface RTCRtpCodingParameters { + rid?: string; +} + +export interface RTCRtpContributingSource { + audioLevel?: number; + rtpTimestamp: number; + source: number; + timestamp: number; +} + +export interface RTCRtpEncodingParameters extends RTCRtpCodingParameters { + active?: boolean; + maxBitrate?: number; + scaleResolutionDownBy?: number; +} + +export interface RTCRtpFecParameters { + mechanism?: string; + ssrc?: number; +} + +export interface RTCRtpHeaderExtension { + kind?: string; + preferredEncrypt?: boolean; + preferredId?: number; + uri?: string; +} + +export interface RTCRtpHeaderExtensionCapability { + uri?: string; +} + +export interface RTCRtpHeaderExtensionParameters { + encrypted?: boolean; + id: number; + uri: string; +} + +export interface RTCRtpParameters { + codecs: RTCRtpCodecParameters[]; + headerExtensions: RTCRtpHeaderExtensionParameters[]; + rtcp: RTCRtcpParameters; +} + +export interface RTCRtpReceiveParameters extends RTCRtpParameters {} + +export interface RTCRtpRtxParameters { + ssrc?: number; +} + +export interface RTCRtpSendParameters extends RTCRtpParameters { + encodings: RTCRtpEncodingParameters[]; + transactionId: string; +} + +export interface RTCRtpSynchronizationSource extends RTCRtpContributingSource { + voiceActivityFlag?: boolean; +} + +export interface RTCRtpTransceiverInit { + direction?: RTCRtpTransceiverDirection; + sendEncodings?: RTCRtpEncodingParameters[]; + streams?: MediaStream[]; +} + +export interface RTCRtpUnhandled { + muxId?: string; + payloadType?: number; + ssrc?: number; +} + +export interface RTCSessionDescriptionInit { + sdp?: string; + type: RTCSdpType; +} + +export interface RTCSrtpKeyParam { + keyMethod?: string; + keySalt?: string; + lifetime?: string; + mkiLength?: number; + mkiValue?: number; +} + +export interface RTCSrtpSdesParameters { + cryptoSuite?: string; + keyParams?: RTCSrtpKeyParam[]; + sessionParams?: string[]; + tag?: number; +} + +export interface RTCSsrcRange { + max?: number; + min?: number; +} + +export interface RTCStats { + id?: string; + timestamp?: number; + type?: RTCStatsType; +} + +export interface RTCStatsReport {} + +export interface RTCTrackEventInit extends EventInit { + receiver: RTCRtpReceiver; + streams?: MediaStream[]; + track: MediaStreamTrack; + transceiver: RTCRtpTransceiver; +} + +export interface RTCTransportStats extends RTCStats { + bytesReceived?: number; + bytesSent?: number; + dtlsCipher?: string; + dtlsState?: RTCDtlsTransportState; + iceRole?: RTCIceRole; + localCertificateId?: string; + packetsReceived?: number; + packetsSent?: number; + remoteCertificateId?: string; + rtcpTransportStatsId?: string; + selectedCandidatePairChanges?: number; + selectedCandidatePairId?: string; + srtpCipher?: string; + tlsGroup?: string; + tlsVersion?: string; +} + +export interface ReadableStreamDefaultReadDoneResult { + done: true; + value?: undefined; +} + +export interface ReadableStreamDefaultReadValueResult { + done: false; + value: T; +} + +export interface ReadableWritablePair { + readable: ReadableStream; + /** + * Provides a convenient, chainable way of piping this readable stream through a transform stream (or any other { writable, readable } pair). It simply pipes the stream into the writable side of the supplied pair, and returns the readable side for further use. + * + * Piping a stream will lock it for the duration of the pipe, preventing any other consumer from acquiring a reader. + */ + writable: WritableStream; +} + +export interface RegistrationOptions { + scope?: string; + type?: WorkerType; + updateViaCache?: ServiceWorkerUpdateViaCache; +} + +export interface RequestInit { + /** + * A BodyInit object or null to set request's body. + */ + body?: BodyInit | null; + /** + * A string indicating how the request will interact with the browser's cache to set request's cache. + */ + cache?: RequestCache; + /** + * A string indicating whether credentials will be sent with the request always, never, or only when sent to a same-origin URL. Sets request's credentials. + */ + credentials?: RequestCredentials; + /** + * A Headers object, an object literal, or an array of two-item arrays to set request's headers. + */ + headers?: HeadersInit; + /** + * A cryptographic hash of the resource to be fetched by request. Sets request's integrity. + */ + integrity?: string; + /** + * A boolean to set request's keepalive. + */ + keepalive?: boolean; + /** + * A string to set request's method. + */ + method?: string; + /** + * A string to indicate whether the request will use CORS, or will be restricted to same-origin URLs. Sets request's mode. + */ + mode?: RequestMode; + /** + * A string indicating whether request follows redirects, results in an error upon encountering a redirect, or returns the redirect (in an opaque fashion). Sets request's redirect. + */ + redirect?: RequestRedirect; + /** + * A string whose value is a same-origin URL, "about:client", or the empty string, to set request's referrer. + */ + referrer?: string; + /** + * A referrer policy to set request's referrerPolicy. + */ + referrerPolicy?: ReferrerPolicy; + /** + * An AbortSignal to set request's signal. + */ + signal?: AbortSignal | null; + /** + * Can only be null. Used to disassociate request from any Window. + */ + window?: any; +} + +export interface ResizeObserverOptions { + box?: ResizeObserverBoxOptions; +} + +export interface ResponseInit { + headers?: HeadersInit; + status?: number; + statusText?: string; +} + +export interface RsaHashedImportParams extends Algorithm { + hash: HashAlgorithmIdentifier; +} + +export interface RsaHashedKeyAlgorithm extends RsaKeyAlgorithm { + hash: KeyAlgorithm; +} + +export interface RsaHashedKeyGenParams extends RsaKeyGenParams { + hash: HashAlgorithmIdentifier; +} + +export interface RsaKeyAlgorithm extends KeyAlgorithm { + modulusLength: number; + publicExponent: BigInteger; +} + +export interface RsaKeyGenParams extends Algorithm { + modulusLength: number; + publicExponent: BigInteger; +} + +export interface RsaOaepParams extends Algorithm { + label?: + | Int8Array + | Int16Array + | Int32Array + | Uint8Array + | Uint16Array + | Uint32Array + | Uint8ClampedArray + | Float32Array + | Float64Array + | DataView + | ArrayBuffer; +} + +export interface RsaOtherPrimesInfo { + d?: string; + r?: string; + t?: string; +} + +export interface RsaPssParams extends Algorithm { + saltLength: number; +} + +export interface SVGBoundingBoxOptions { + clipped?: boolean; + fill?: boolean; + markers?: boolean; + stroke?: boolean; +} + +export interface ScrollIntoViewOptions extends ScrollOptions { + block?: ScrollLogicalPosition; + inline?: ScrollLogicalPosition; +} + +export interface ScrollOptions { + behavior?: ScrollBehavior; +} + +export interface ScrollToOptions extends ScrollOptions { + left?: number; + top?: number; +} + +export interface SecurityPolicyViolationEventInit extends EventInit { + blockedURI?: string; + columnNumber?: number; + documentURI?: string; + effectiveDirective?: string; + lineNumber?: number; + originalPolicy?: string; + referrer?: string; + sourceFile?: string; + statusCode?: number; + violatedDirective?: string; +} + +export interface ShadowRootInit { + delegatesFocus?: boolean; + mode: ShadowRootMode; +} + +export interface ShareData { + text?: string; + title?: string; + url?: string; +} + +export interface SpeechRecognitionErrorEventInit extends EventInit { + error: SpeechRecognitionErrorCode; + message?: string; +} + +export interface SpeechRecognitionEventInit extends EventInit { + resultIndex?: number; + results: SpeechRecognitionResultList; +} + +export interface SpeechSynthesisErrorEventInit + extends SpeechSynthesisEventInit { + error: SpeechSynthesisErrorCode; +} + +export interface SpeechSynthesisEventInit extends EventInit { + charIndex?: number; + charLength?: number; + elapsedTime?: number; + name?: string; + utterance: SpeechSynthesisUtterance; +} + +export interface StaticRangeInit { + endContainer: Node; + endOffset: number; + startContainer: Node; + startOffset: number; +} + +export interface StereoPannerOptions extends AudioNodeOptions { + pan?: number; +} + +export interface StorageEstimate { + quota?: number; + usage?: number; +} + +export interface StorageEventInit extends EventInit { + key?: string | null; + newValue?: string | null; + oldValue?: string | null; + storageArea?: Storage | null; + url?: string; +} + +export interface StoreExceptionsInformation extends ExceptionInformation { + detailURI?: string | null; + explanationString?: string | null; + siteName?: string | null; +} + +export interface StoreSiteSpecificExceptionsInformation + extends StoreExceptionsInformation { + arrayOfDomainStrings?: string[]; +} + +export interface StreamPipeOptions { + preventAbort?: boolean; + preventCancel?: boolean; + /** + * Pipes this readable stream to a given writable stream destination. The way in which the piping process behaves under various error conditions can be customized with a number of passed options. It returns a promise that fulfills when the piping process completes successfully, or rejects if any errors were encountered. + * + * Piping a stream will lock it for the duration of the pipe, preventing any other consumer from acquiring a reader. + * + * Errors and closures of the source and destination streams propagate as follows: + * + * An error in this source readable stream will abort destination, unless preventAbort is truthy. The returned promise will be rejected with the source's error, or with any error that occurs during aborting the destination. + * + * An error in destination will cancel this source readable stream, unless preventCancel is truthy. The returned promise will be rejected with the destination's error, or with any error that occurs during canceling the source. + * + * When this source readable stream closes, destination will be closed, unless preventClose is truthy. The returned promise will be fulfilled once this process completes, unless an error is encountered while closing the destination, in which case it will be rejected with that error. + * + * If destination starts out closed or closing, this source readable stream will be canceled, unless preventCancel is true. The returned promise will be rejected with an error indicating piping to a closed stream failed, or with any error that occurs during canceling the source. + * + * The signal option can be set to an AbortSignal to allow aborting an ongoing pipe operation via the corresponding AbortController. In this case, this source readable stream will be canceled, and destination aborted, unless the respective options preventCancel or preventAbort are set. + */ + preventClose?: boolean; + signal?: AbortSignal; +} + +export interface TextDecodeOptions { + stream?: boolean; +} + +export interface TextDecoderOptions { + fatal?: boolean; + ignoreBOM?: boolean; +} + +export interface TextEncoderEncodeIntoResult { + read?: number; + written?: number; +} + +export interface TouchEventInit extends EventModifierInit { + changedTouches?: Touch[]; + targetTouches?: Touch[]; + touches?: Touch[]; +} + +export interface TouchInit { + altitudeAngle?: number; + azimuthAngle?: number; + clientX?: number; + clientY?: number; + force?: number; + identifier: number; + pageX?: number; + pageY?: number; + radiusX?: number; + radiusY?: number; + rotationAngle?: number; + screenX?: number; + screenY?: number; + target: EventTarget; + touchType?: TouchType; +} + +export interface TrackEventInit extends EventInit { + track?: TextTrack | null; +} + +export interface Transformer { + flush?: TransformerFlushCallback; + readableType?: undefined; + start?: TransformerStartCallback; + transform?: TransformerTransformCallback; + writableType?: undefined; +} + +export interface TransitionEventInit extends EventInit { + elapsedTime?: number; + propertyName?: string; + pseudoElement?: string; +} + +export interface UIEventInit extends EventInit { + detail?: number; + view?: Window | null; +} + +export interface ULongRange { + max?: number; + min?: number; +} + +export interface UnderlyingSink { + abort?: UnderlyingSinkAbortCallback; + close?: UnderlyingSinkCloseCallback; + start?: UnderlyingSinkStartCallback; + type?: undefined; + write?: UnderlyingSinkWriteCallback; +} + +export interface UnderlyingSource { + cancel?: UnderlyingSourceCancelCallback; + pull?: UnderlyingSourcePullCallback; + start?: UnderlyingSourceStartCallback; + type?: undefined; +} + +export interface VRDisplayEventInit extends EventInit { + display: VRDisplay; + reason?: VRDisplayEventReason; +} + +export interface VRLayer { + leftBounds?: number[] | Float32Array | null; + rightBounds?: number[] | Float32Array | null; + source?: HTMLCanvasElement | null; +} + +export interface VRStageParameters { + sittingToStandingTransform?: Float32Array; + sizeX?: number; + sizeY?: number; +} + +export interface WaveShaperOptions extends AudioNodeOptions { + curve?: number[] | Float32Array; + oversample?: OverSampleType; +} + +export interface WebGLContextAttributes { + alpha?: boolean; + antialias?: boolean; + depth?: boolean; + desynchronized?: boolean; + failIfMajorPerformanceCaveat?: boolean; + powerPreference?: WebGLPowerPreference; + premultipliedAlpha?: boolean; + preserveDrawingBuffer?: boolean; + stencil?: boolean; +} + +export interface WebGLContextEventInit extends EventInit { + statusMessage?: string; +} + +export interface WheelEventInit extends MouseEventInit { + deltaMode?: number; + deltaX?: number; + deltaY?: number; + deltaZ?: number; +} + +export interface WorkerOptions { + credentials?: RequestCredentials; + name?: string; + type?: WorkerType; +} + +export interface WorkletOptions { + credentials?: RequestCredentials; +} + +export interface EventListener { + (evt: Event): void; +} + +type XPathNSResolver = + | ((prefix: string | null) => string | null) + | { lookupNamespaceURI(prefix: string | null): string | null }; + +/** The ANGLE_instanced_arrays extension is part of the WebGL API and allows to draw the same object, or groups of similar objects multiple times, if they share the same vertex data, primitive count and type. */ +export interface ANGLE_instanced_arrays { + drawArraysInstancedANGLE( + mode: GLenum, + first: GLint, + count: GLsizei, + primcount: GLsizei, + ): void; + drawElementsInstancedANGLE( + mode: GLenum, + count: GLsizei, + type: GLenum, + offset: GLintptr, + primcount: GLsizei, + ): void; + vertexAttribDivisorANGLE(index: GLuint, divisor: GLuint): void; + readonly VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE: GLenum; +} + +/** A controller object that allows you to abort one or more DOM requests as and when desired. */ +export interface AbortController { + /** + * Returns the AbortSignal object associated with this object. + */ + readonly signal: AbortSignal; + /** + * Invoking this method will set this object's AbortSignal's aborted flag and signal to any observers that the associated activity is to be aborted. + */ + abort(): void; +} + +declare var AbortController: { + prototype: AbortController; + new (): AbortController; +}; + +export interface AbortSignalEventMap { + abort: Event; +} + +/** A signal object that allows you to communicate with a DOM request (such as a Fetch) and abort it if required via an AbortController object. */ +export interface AbortSignal extends EventTarget { + /** + * Returns true if this AbortSignal's AbortController has signaled to abort, and false otherwise. + */ + readonly aborted: boolean; + onabort: ((this: AbortSignal, ev: Event) => any) | null; + addEventListener( + type: K, + listener: (this: AbortSignal, ev: AbortSignalEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: (this: AbortSignal, ev: AbortSignalEventMap[K]) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var AbortSignal: { + prototype: AbortSignal; + new (): AbortSignal; +}; + +export interface AbstractRange { + /** + * Returns true if range is collapsed, and false otherwise. + */ + readonly collapsed: boolean; + /** + * Returns range's end node. + */ + readonly endContainer: Node; + /** + * Returns range's end offset. + */ + readonly endOffset: number; + /** + * Returns range's start node. + */ + readonly startContainer: Node; + /** + * Returns range's start offset. + */ + readonly startOffset: number; +} + +declare var AbstractRange: { + prototype: AbstractRange; + new (): AbstractRange; +}; + +export interface AbstractWorkerEventMap { + error: ErrorEvent; +} + +export interface AbstractWorker { + onerror: ((this: AbstractWorker, ev: ErrorEvent) => any) | null; + addEventListener( + type: K, + listener: (this: AbstractWorker, ev: AbstractWorkerEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: (this: AbstractWorker, ev: AbstractWorkerEventMap[K]) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +export interface AesCfbParams extends Algorithm { + iv: + | Int8Array + | Int16Array + | Int32Array + | Uint8Array + | Uint16Array + | Uint32Array + | Uint8ClampedArray + | Float32Array + | Float64Array + | DataView + | ArrayBuffer; +} + +export interface AesCmacParams extends Algorithm { + length: number; +} + +/** A node able to provide real-time frequency and time-domain analysis information. It is an AudioNode that passes the audio stream unchanged from the input to the output, but allows you to take the generated data, process it, and create audio visualizations. */ +export interface AnalyserNode extends AudioNode { + fftSize: number; + readonly frequencyBinCount: number; + maxDecibels: number; + minDecibels: number; + smoothingTimeConstant: number; + getByteFrequencyData(array: Uint8Array): void; + getByteTimeDomainData(array: Uint8Array): void; + getFloatFrequencyData(array: Float32Array): void; + getFloatTimeDomainData(array: Float32Array): void; +} + +declare var AnalyserNode: { + prototype: AnalyserNode; + new (context: BaseAudioContext, options?: AnalyserOptions): AnalyserNode; +}; + +export interface Animatable { + animate( + keyframes: Keyframe[] | PropertyIndexedKeyframes | null, + options?: number | KeyframeAnimationOptions, + ): Animation; + getAnimations(): Animation[]; +} + +export interface AnimationEventMap { + cancel: AnimationPlaybackEvent; + finish: AnimationPlaybackEvent; +} + +export interface Animation extends EventTarget { + currentTime: number | null; + effect: AnimationEffect | null; + readonly finished: Promise; + id: string; + oncancel: ((this: Animation, ev: AnimationPlaybackEvent) => any) | null; + onfinish: ((this: Animation, ev: AnimationPlaybackEvent) => any) | null; + readonly pending: boolean; + readonly playState: AnimationPlayState; + playbackRate: number; + readonly ready: Promise; + startTime: number | null; + timeline: AnimationTimeline | null; + cancel(): void; + finish(): void; + pause(): void; + play(): void; + reverse(): void; + updatePlaybackRate(playbackRate: number): void; + addEventListener( + type: K, + listener: (this: Animation, ev: AnimationEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: (this: Animation, ev: AnimationEventMap[K]) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var Animation: { + prototype: Animation; + new ( + effect?: AnimationEffect | null, + timeline?: AnimationTimeline | null, + ): Animation; +}; + +export interface AnimationEffect { + getComputedTiming(): ComputedEffectTiming; + getTiming(): EffectTiming; + updateTiming(timing?: OptionalEffectTiming): void; +} + +declare var AnimationEffect: { + prototype: AnimationEffect; + new (): AnimationEffect; +}; + +/** Events providing information related to animations. */ +export interface AnimationEvent extends Event { + readonly animationName: string; + readonly elapsedTime: number; + readonly pseudoElement: string; +} + +declare var AnimationEvent: { + prototype: AnimationEvent; + new ( + type: string, + animationEventInitDict?: AnimationEventInit, + ): AnimationEvent; +}; + +export interface AnimationFrameProvider { + cancelAnimationFrame(handle: number): void; + requestAnimationFrame(callback: FrameRequestCallback): number; +} + +export interface AnimationPlaybackEvent extends Event { + readonly currentTime: number | null; + readonly timelineTime: number | null; +} + +declare var AnimationPlaybackEvent: { + prototype: AnimationPlaybackEvent; + new ( + type: string, + eventInitDict?: AnimationPlaybackEventInit, + ): AnimationPlaybackEvent; +}; + +export interface AnimationTimeline { + readonly currentTime: number | null; +} + +declare var AnimationTimeline: { + prototype: AnimationTimeline; + new (): AnimationTimeline; +}; + +export interface ApplicationCacheEventMap { + cached: Event; + checking: Event; + downloading: Event; + error: Event; + noupdate: Event; + obsolete: Event; + progress: ProgressEvent; + updateready: Event; +} + +export interface ApplicationCache extends EventTarget { + /** @deprecated */ + oncached: ((this: ApplicationCache, ev: Event) => any) | null; + /** @deprecated */ + onchecking: ((this: ApplicationCache, ev: Event) => any) | null; + /** @deprecated */ + ondownloading: ((this: ApplicationCache, ev: Event) => any) | null; + /** @deprecated */ + onerror: ((this: ApplicationCache, ev: Event) => any) | null; + /** @deprecated */ + onnoupdate: ((this: ApplicationCache, ev: Event) => any) | null; + /** @deprecated */ + onobsolete: ((this: ApplicationCache, ev: Event) => any) | null; + /** @deprecated */ + onprogress: + | ((this: ApplicationCache, ev: ProgressEvent) => any) + | null; + /** @deprecated */ + onupdateready: ((this: ApplicationCache, ev: Event) => any) | null; + /** @deprecated */ + readonly status: number; + /** @deprecated */ + abort(): void; + /** @deprecated */ + swapCache(): void; + /** @deprecated */ + update(): void; + readonly CHECKING: number; + readonly DOWNLOADING: number; + readonly IDLE: number; + readonly OBSOLETE: number; + readonly UNCACHED: number; + readonly UPDATEREADY: number; + addEventListener( + type: K, + listener: ( + this: ApplicationCache, + ev: ApplicationCacheEventMap[K], + ) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: ( + this: ApplicationCache, + ev: ApplicationCacheEventMap[K], + ) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var ApplicationCache: { + prototype: ApplicationCache; + new (): ApplicationCache; + readonly CHECKING: number; + readonly DOWNLOADING: number; + readonly IDLE: number; + readonly OBSOLETE: number; + readonly UNCACHED: number; + readonly UPDATEREADY: number; +}; + +/** A DOM element's attribute as an object. In most DOM methods, you will probably directly retrieve the attribute as a string (e.g., Element.getAttribute(), but certain functions (e.g., Element.getAttributeNode()) or means of iterating give Attr types. */ +export interface Attr extends Node { + readonly localName: string; + readonly name: string; + readonly namespaceURI: string | null; + readonly ownerDocument: Document; + readonly ownerElement: Element | null; + readonly prefix: string | null; + readonly specified: boolean; + value: string; +} + +declare var Attr: { + prototype: Attr; + new (): Attr; +}; + +/** A short audio asset residing in memory, created from an audio file using the AudioContext.decodeAudioData() method, or from raw data using AudioContext.createBuffer(). Once put into an AudioBuffer, the audio can then be played by being passed into an AudioBufferSourceNode. */ +export interface AudioBuffer { + readonly duration: number; + readonly length: number; + readonly numberOfChannels: number; + readonly sampleRate: number; + copyFromChannel( + destination: Float32Array, + channelNumber: number, + bufferOffset?: number, + ): void; + copyToChannel( + source: Float32Array, + channelNumber: number, + bufferOffset?: number, + ): void; + getChannelData(channel: number): Float32Array; +} + +declare var AudioBuffer: { + prototype: AudioBuffer; + new (options: AudioBufferOptions): AudioBuffer; +}; + +/** An AudioScheduledSourceNode which represents an audio source consisting of in-memory audio data, stored in an AudioBuffer. It's especially useful for playing back audio which has particularly stringent timing accuracy requirements, such as for sounds that must match a specific rhythm and can be kept in memory rather than being played from disk or the network. */ +export interface AudioBufferSourceNode extends AudioScheduledSourceNode { + buffer: AudioBuffer | null; + readonly detune: AudioParam; + loop: boolean; + loopEnd: number; + loopStart: number; + readonly playbackRate: AudioParam; + start(when?: number, offset?: number, duration?: number): void; + addEventListener( + type: K, + listener: ( + this: AudioBufferSourceNode, + ev: AudioScheduledSourceNodeEventMap[K], + ) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: ( + this: AudioBufferSourceNode, + ev: AudioScheduledSourceNodeEventMap[K], + ) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var AudioBufferSourceNode: { + prototype: AudioBufferSourceNode; + new ( + context: BaseAudioContext, + options?: AudioBufferSourceOptions, + ): AudioBufferSourceNode; +}; + +/** An audio-processing graph built from audio modules linked together, each represented by an AudioNode. */ +export interface AudioContext extends BaseAudioContext { + readonly baseLatency: number; + readonly outputLatency: number; + close(): Promise; + createMediaElementSource( + mediaElement: HTMLMediaElement, + ): MediaElementAudioSourceNode; + createMediaStreamDestination(): MediaStreamAudioDestinationNode; + createMediaStreamSource( + mediaStream: MediaStream, + ): MediaStreamAudioSourceNode; + createMediaStreamTrackSource( + mediaStreamTrack: MediaStreamTrack, + ): MediaStreamTrackAudioSourceNode; + getOutputTimestamp(): AudioTimestamp; + resume(): Promise; + suspend(): Promise; + addEventListener( + type: K, + listener: (this: AudioContext, ev: BaseAudioContextEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: (this: AudioContext, ev: BaseAudioContextEventMap[K]) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var AudioContext: { + prototype: AudioContext; + new (contextOptions?: AudioContextOptions): AudioContext; +}; + +/** AudioDestinationNode has no output (as it is the output, no more AudioNode can be linked after it in the audio graph) and one input. The number of channels in the input must be between 0 and the maxChannelCount value or an exception is raised. */ +export interface AudioDestinationNode extends AudioNode { + readonly maxChannelCount: number; +} + +declare var AudioDestinationNode: { + prototype: AudioDestinationNode; + new (): AudioDestinationNode; +}; + +/** The position and orientation of the unique person listening to the audio scene, and is used in audio spatialization. All PannerNodes spatialize in relation to the AudioListener stored in the BaseAudioContext.listener attribute. */ +export interface AudioListener { + readonly forwardX: AudioParam; + readonly forwardY: AudioParam; + readonly forwardZ: AudioParam; + readonly positionX: AudioParam; + readonly positionY: AudioParam; + readonly positionZ: AudioParam; + readonly upX: AudioParam; + readonly upY: AudioParam; + readonly upZ: AudioParam; + /** @deprecated */ + setOrientation( + x: number, + y: number, + z: number, + xUp: number, + yUp: number, + zUp: number, + ): void; + /** @deprecated */ + setPosition(x: number, y: number, z: number): void; +} + +declare var AudioListener: { + prototype: AudioListener; + new (): AudioListener; +}; + +/** A generic interface for representing an audio processing module. Examples include: */ +export interface AudioNode extends EventTarget { + channelCount: number; + channelCountMode: ChannelCountMode; + channelInterpretation: ChannelInterpretation; + readonly context: BaseAudioContext; + readonly numberOfInputs: number; + readonly numberOfOutputs: number; + connect( + destinationNode: AudioNode, + output?: number, + input?: number, + ): AudioNode; + connect(destinationParam: AudioParam, output?: number): void; + disconnect(): void; + disconnect(output: number): void; + disconnect(destinationNode: AudioNode): void; + disconnect(destinationNode: AudioNode, output: number): void; + disconnect(destinationNode: AudioNode, output: number, input: number): void; + disconnect(destinationParam: AudioParam): void; + disconnect(destinationParam: AudioParam, output: number): void; +} + +declare var AudioNode: { + prototype: AudioNode; + new (): AudioNode; +}; + +/** The Web Audio API's AudioParam interface represents an audio-related parameter, usually a parameter of an AudioNode (such as GainNode.gain). */ +export interface AudioParam { + automationRate: AutomationRate; + readonly defaultValue: number; + readonly maxValue: number; + readonly minValue: number; + value: number; + cancelAndHoldAtTime(cancelTime: number): AudioParam; + cancelScheduledValues(cancelTime: number): AudioParam; + exponentialRampToValueAtTime(value: number, endTime: number): AudioParam; + linearRampToValueAtTime(value: number, endTime: number): AudioParam; + setTargetAtTime( + target: number, + startTime: number, + timeConstant: number, + ): AudioParam; + setValueAtTime(value: number, startTime: number): AudioParam; + setValueCurveAtTime( + values: number[] | Float32Array, + startTime: number, + duration: number, + ): AudioParam; +} + +declare var AudioParam: { + prototype: AudioParam; + new (): AudioParam; +}; + +export interface AudioParamMap { + forEach( + callbackfn: ( + value: AudioParam, + key: string, + parent: AudioParamMap, + ) => void, + thisArg?: any, + ): void; +} + +declare var AudioParamMap: { + prototype: AudioParamMap; + new (): AudioParamMap; +}; + +/** The Web Audio API events that occur when a ScriptProcessorNode input buffer is ready to be processed. + * @deprecated As of the August 29 2014 Web Audio API spec publication, this feature has been marked as deprecated, and is soon to be replaced by AudioWorklet. + */ +export interface AudioProcessingEvent extends Event { + readonly inputBuffer: AudioBuffer; + readonly outputBuffer: AudioBuffer; + readonly playbackTime: number; +} + +declare var AudioProcessingEvent: { + prototype: AudioProcessingEvent; + new ( + type: string, + eventInitDict: AudioProcessingEventInit, + ): AudioProcessingEvent; +}; + +export interface AudioScheduledSourceNodeEventMap { + ended: Event; +} + +export interface AudioScheduledSourceNode extends AudioNode { + onended: ((this: AudioScheduledSourceNode, ev: Event) => any) | null; + start(when?: number): void; + stop(when?: number): void; + addEventListener( + type: K, + listener: ( + this: AudioScheduledSourceNode, + ev: AudioScheduledSourceNodeEventMap[K], + ) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: ( + this: AudioScheduledSourceNode, + ev: AudioScheduledSourceNodeEventMap[K], + ) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var AudioScheduledSourceNode: { + prototype: AudioScheduledSourceNode; + new (): AudioScheduledSourceNode; +}; + +export interface AudioWorklet extends Worklet {} + +declare var AudioWorklet: { + prototype: AudioWorklet; + new (): AudioWorklet; +}; + +export interface AudioWorkletNodeEventMap { + processorerror: Event; +} + +export interface AudioWorkletNode extends AudioNode { + onprocessorerror: ((this: AudioWorkletNode, ev: Event) => any) | null; + readonly parameters: AudioParamMap; + readonly port: MessagePort; + addEventListener( + type: K, + listener: ( + this: AudioWorkletNode, + ev: AudioWorkletNodeEventMap[K], + ) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: ( + this: AudioWorkletNode, + ev: AudioWorkletNodeEventMap[K], + ) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var AudioWorkletNode: { + prototype: AudioWorkletNode; + new ( + context: BaseAudioContext, + name: string, + options?: AudioWorkletNodeOptions, + ): AudioWorkletNode; +}; + +export interface AuthenticatorAssertionResponse extends AuthenticatorResponse { + readonly authenticatorData: ArrayBuffer; + readonly signature: ArrayBuffer; + readonly userHandle: ArrayBuffer | null; +} + +declare var AuthenticatorAssertionResponse: { + prototype: AuthenticatorAssertionResponse; + new (): AuthenticatorAssertionResponse; +}; + +export interface AuthenticatorAttestationResponse + extends AuthenticatorResponse { + readonly attestationObject: ArrayBuffer; +} + +declare var AuthenticatorAttestationResponse: { + prototype: AuthenticatorAttestationResponse; + new (): AuthenticatorAttestationResponse; +}; + +export interface AuthenticatorResponse { + readonly clientDataJSON: ArrayBuffer; +} + +declare var AuthenticatorResponse: { + prototype: AuthenticatorResponse; + new (): AuthenticatorResponse; +}; + +export interface BarProp { + readonly visible: boolean; +} + +declare var BarProp: { + prototype: BarProp; + new (): BarProp; +}; + +export interface BaseAudioContextEventMap { + statechange: Event; +} + +export interface BaseAudioContext extends EventTarget { + readonly audioWorklet: AudioWorklet; + readonly currentTime: number; + readonly destination: AudioDestinationNode; + readonly listener: AudioListener; + onstatechange: ((this: BaseAudioContext, ev: Event) => any) | null; + readonly sampleRate: number; + readonly state: AudioContextState; + createAnalyser(): AnalyserNode; + createBiquadFilter(): BiquadFilterNode; + createBuffer( + numberOfChannels: number, + length: number, + sampleRate: number, + ): AudioBuffer; + createBufferSource(): AudioBufferSourceNode; + createChannelMerger(numberOfInputs?: number): ChannelMergerNode; + createChannelSplitter(numberOfOutputs?: number): ChannelSplitterNode; + createConstantSource(): ConstantSourceNode; + createConvolver(): ConvolverNode; + createDelay(maxDelayTime?: number): DelayNode; + createDynamicsCompressor(): DynamicsCompressorNode; + createGain(): GainNode; + createIIRFilter(feedforward: number[], feedback: number[]): IIRFilterNode; + createOscillator(): OscillatorNode; + createPanner(): PannerNode; + createPeriodicWave( + real: number[] | Float32Array, + imag: number[] | Float32Array, + constraints?: PeriodicWaveConstraints, + ): PeriodicWave; + createScriptProcessor( + bufferSize?: number, + numberOfInputChannels?: number, + numberOfOutputChannels?: number, + ): ScriptProcessorNode; + createStereoPanner(): StereoPannerNode; + createWaveShaper(): WaveShaperNode; + decodeAudioData( + audioData: ArrayBuffer, + successCallback?: DecodeSuccessCallback | null, + errorCallback?: DecodeErrorCallback | null, + ): Promise; + addEventListener( + type: K, + listener: ( + this: BaseAudioContext, + ev: BaseAudioContextEventMap[K], + ) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: ( + this: BaseAudioContext, + ev: BaseAudioContextEventMap[K], + ) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var BaseAudioContext: { + prototype: BaseAudioContext; + new (): BaseAudioContext; +}; + +/** The beforeunload event is fired when the window, the document and its resources are about to be unloaded. */ +export interface BeforeUnloadEvent extends Event { + returnValue: any; +} + +declare var BeforeUnloadEvent: { + prototype: BeforeUnloadEvent; + new (): BeforeUnloadEvent; +}; + +export interface BhxBrowser { + readonly lastError: DOMException; + checkMatchesGlobExpression(pattern: string, value: string): boolean; + checkMatchesUriExpression(pattern: string, value: string): boolean; + clearLastError(): void; + currentWindowId(): number; + fireExtensionApiTelemetry( + functionName: string, + isSucceeded: boolean, + isSupported: boolean, + errorString: string, + ): void; + genericFunction( + functionId: number, + destination: any, + parameters?: string, + callbackId?: number, + ): void; + genericSynchronousFunction(functionId: number, parameters?: string): string; + getExtensionId(): string; + getThisAddress(): any; + registerGenericFunctionCallbackHandler(callbackHandler: Function): void; + registerGenericListenerHandler(eventHandler: Function): void; + setLastError(parameters: string): void; + webPlatformGenericFunction( + destination: any, + parameters?: string, + callbackId?: number, + ): void; +} + +declare var BhxBrowser: { + prototype: BhxBrowser; + new (): BhxBrowser; +}; + +/** A simple low-order filter, and is created using the AudioContext.createBiquadFilter() method. It is an AudioNode that can represent different kinds of filters, tone control devices, and graphic equalizers. */ +export interface BiquadFilterNode extends AudioNode { + readonly Q: AudioParam; + readonly detune: AudioParam; + readonly frequency: AudioParam; + readonly gain: AudioParam; + type: BiquadFilterType; + getFrequencyResponse( + frequencyHz: Float32Array, + magResponse: Float32Array, + phaseResponse: Float32Array, + ): void; +} + +declare var BiquadFilterNode: { + prototype: BiquadFilterNode; + new ( + context: BaseAudioContext, + options?: BiquadFilterOptions, + ): BiquadFilterNode; +}; + +/** A file-like object of immutable, raw data. Blobs represent data that isn't necessarily in a JavaScript-native format. The File interface is based on Blob, inheriting blob functionality and expanding it to support files on the user's system. */ +export interface Blob { + readonly size: number; + readonly type: string; + arrayBuffer(): Promise; + slice(start?: number, end?: number, contentType?: string): Blob; + stream(): ReadableStream; + text(): Promise; +} + +declare var Blob: { + prototype: Blob; + new (blobParts?: BlobPart[], options?: BlobPropertyBag): Blob; +}; + +export interface Body { + readonly body: ReadableStream | null; + readonly bodyUsed: boolean; + arrayBuffer(): Promise; + blob(): Promise; + formData(): Promise; + json(): Promise; + text(): Promise; +} + +export interface BroadcastChannelEventMap { + message: MessageEvent; + messageerror: MessageEvent; +} + +export interface BroadcastChannel extends EventTarget { + /** + * Returns the channel name (as passed to the constructor). + */ + readonly name: string; + onmessage: ((this: BroadcastChannel, ev: MessageEvent) => any) | null; + onmessageerror: ((this: BroadcastChannel, ev: MessageEvent) => any) | null; + /** + * Closes the BroadcastChannel object, opening it up to garbage collection. + */ + close(): void; + /** + * Sends the given message to other BroadcastChannel objects set up for this channel. Messages can be structured objects, e.g. nested objects and arrays. + */ + postMessage(message: any): void; + addEventListener( + type: K, + listener: ( + this: BroadcastChannel, + ev: BroadcastChannelEventMap[K], + ) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: ( + this: BroadcastChannel, + ev: BroadcastChannelEventMap[K], + ) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var BroadcastChannel: { + prototype: BroadcastChannel; + new (name: string): BroadcastChannel; +}; + +/** This Streams API interface provides a built-in byte length queuing strategy that can be used when constructing streams. */ +export interface ByteLengthQueuingStrategy + extends QueuingStrategy { + readonly highWaterMark: number; + readonly size: QueuingStrategySize; +} + +declare var ByteLengthQueuingStrategy: { + prototype: ByteLengthQueuingStrategy; + new (init: QueuingStrategyInit): ByteLengthQueuingStrategy; +}; + +/** A CDATA section that can be used within XML to include extended portions of unescaped text. The symbols < and & don’t need escaping as they normally do when inside a CDATA section. */ +export interface CDATASection extends Text {} + +declare var CDATASection: { + prototype: CDATASection; + new (): CDATASection; +}; + +/** A single condition CSS at-rule, which consists of a condition and a statement block. It is a child of CSSGroupingRule. */ +export interface CSSConditionRule extends CSSGroupingRule { + conditionText: string; +} + +declare var CSSConditionRule: { + prototype: CSSConditionRule; + new (): CSSConditionRule; +}; + +export interface CSSFontFaceRule extends CSSRule { + readonly style: CSSStyleDeclaration; +} + +declare var CSSFontFaceRule: { + prototype: CSSFontFaceRule; + new (): CSSFontFaceRule; +}; + +/** Any CSS at-rule that contains other rules nested within it. */ +export interface CSSGroupingRule extends CSSRule { + readonly cssRules: CSSRuleList; + deleteRule(index: number): void; + insertRule(rule: string, index?: number): number; +} + +declare var CSSGroupingRule: { + prototype: CSSGroupingRule; + new (): CSSGroupingRule; +}; + +export interface CSSImportRule extends CSSRule { + readonly href: string; + readonly media: MediaList; + readonly styleSheet: CSSStyleSheet; +} + +declare var CSSImportRule: { + prototype: CSSImportRule; + new (): CSSImportRule; +}; + +/** An object representing a set of style for a given keyframe. It corresponds to the contains of a single keyframe of a @keyframes at-rule. It implements the CSSRule interface with a type value of 8 (CSSRule.KEYFRAME_RULE). */ +export interface CSSKeyframeRule extends CSSRule { + keyText: string; + readonly style: CSSStyleDeclaration; +} + +declare var CSSKeyframeRule: { + prototype: CSSKeyframeRule; + new (): CSSKeyframeRule; +}; + +/** An object representing a complete set of keyframes for a CSS animation. It corresponds to the contains of a whole @keyframes at-rule. It implements the CSSRule interface with a type value of 7 (CSSRule.KEYFRAMES_RULE). */ +export interface CSSKeyframesRule extends CSSRule { + readonly cssRules: CSSRuleList; + name: string; + appendRule(rule: string): void; + deleteRule(select: string): void; + findRule(select: string): CSSKeyframeRule | null; +} + +declare var CSSKeyframesRule: { + prototype: CSSKeyframesRule; + new (): CSSKeyframesRule; +}; + +/** A single CSS @media rule. It implements the CSSConditionRule interface, and therefore the CSSGroupingRule and the CSSRule interface with a type value of 4 (CSSRule.MEDIA_RULE). */ +export interface CSSMediaRule extends CSSConditionRule { + readonly media: MediaList; +} + +declare var CSSMediaRule: { + prototype: CSSMediaRule; + new (): CSSMediaRule; +}; + +/** An object representing a single CSS @namespace at-rule. It implements the CSSRule interface, with a type value of 10 (CSSRule.NAMESPACE_RULE). */ +export interface CSSNamespaceRule extends CSSRule { + readonly namespaceURI: string; + readonly prefix: string; +} + +declare var CSSNamespaceRule: { + prototype: CSSNamespaceRule; + new (): CSSNamespaceRule; +}; + +/** CSSPageRule is an interface representing a single CSS @page rule. It implements the CSSRule interface with a type value of 6 (CSSRule.PAGE_RULE). */ +export interface CSSPageRule extends CSSGroupingRule { + selectorText: string; + readonly style: CSSStyleDeclaration; +} + +declare var CSSPageRule: { + prototype: CSSPageRule; + new (): CSSPageRule; +}; + +/** A single CSS rule. There are several types of rules, listed in the Type constants section below. */ +export interface CSSRule { + cssText: string; + readonly parentRule: CSSRule | null; + readonly parentStyleSheet: CSSStyleSheet | null; + readonly type: number; + readonly CHARSET_RULE: number; + readonly FONT_FACE_RULE: number; + readonly IMPORT_RULE: number; + readonly KEYFRAMES_RULE: number; + readonly KEYFRAME_RULE: number; + readonly MEDIA_RULE: number; + readonly NAMESPACE_RULE: number; + readonly PAGE_RULE: number; + readonly STYLE_RULE: number; + readonly SUPPORTS_RULE: number; +} + +declare var CSSRule: { + prototype: CSSRule; + new (): CSSRule; + readonly CHARSET_RULE: number; + readonly FONT_FACE_RULE: number; + readonly IMPORT_RULE: number; + readonly KEYFRAMES_RULE: number; + readonly KEYFRAME_RULE: number; + readonly MEDIA_RULE: number; + readonly NAMESPACE_RULE: number; + readonly PAGE_RULE: number; + readonly STYLE_RULE: number; + readonly SUPPORTS_RULE: number; +}; + +/** A CSSRuleList is an (indirect-modify only) array-like object containing an ordered collection of CSSRule objects. */ +export interface CSSRuleList { + readonly length: number; + item(index: number): CSSRule | null; + [index: number]: CSSRule; +} + +declare var CSSRuleList: { + prototype: CSSRuleList; + new (): CSSRuleList; +}; + +/** An object that is a CSS declaration block, and exposes style information and various style-related methods and properties. */ +export interface CSSStyleDeclaration { + alignContent: string; + alignItems: string; + alignSelf: string; + alignmentBaseline: string; + all: string; + animation: string; + animationDelay: string; + animationDirection: string; + animationDuration: string; + animationFillMode: string; + animationIterationCount: string; + animationName: string; + animationPlayState: string; + animationTimingFunction: string; + backfaceVisibility: string; + background: string; + backgroundAttachment: string; + backgroundClip: string; + backgroundColor: string; + backgroundImage: string; + backgroundOrigin: string; + backgroundPosition: string; + backgroundPositionX: string; + backgroundPositionY: string; + backgroundRepeat: string; + backgroundSize: string; + baselineShift: string; + blockSize: string; + border: string; + borderBlockEnd: string; + borderBlockEndColor: string; + borderBlockEndStyle: string; + borderBlockEndWidth: string; + borderBlockStart: string; + borderBlockStartColor: string; + borderBlockStartStyle: string; + borderBlockStartWidth: string; + borderBottom: string; + borderBottomColor: string; + borderBottomLeftRadius: string; + borderBottomRightRadius: string; + borderBottomStyle: string; + borderBottomWidth: string; + borderCollapse: string; + borderColor: string; + borderImage: string; + borderImageOutset: string; + borderImageRepeat: string; + borderImageSlice: string; + borderImageSource: string; + borderImageWidth: string; + borderInlineEnd: string; + borderInlineEndColor: string; + borderInlineEndStyle: string; + borderInlineEndWidth: string; + borderInlineStart: string; + borderInlineStartColor: string; + borderInlineStartStyle: string; + borderInlineStartWidth: string; + borderLeft: string; + borderLeftColor: string; + borderLeftStyle: string; + borderLeftWidth: string; + borderRadius: string; + borderRight: string; + borderRightColor: string; + borderRightStyle: string; + borderRightWidth: string; + borderSpacing: string; + borderStyle: string; + borderTop: string; + borderTopColor: string; + borderTopLeftRadius: string; + borderTopRightRadius: string; + borderTopStyle: string; + borderTopWidth: string; + borderWidth: string; + bottom: string; + boxShadow: string; + boxSizing: string; + breakAfter: string; + breakBefore: string; + breakInside: string; + captionSide: string; + caretColor: string; + clear: string; + clip: string; + clipPath: string; + clipRule: string; + color: string; + colorInterpolation: string; + colorInterpolationFilters: string; + columnCount: string; + columnFill: string; + columnGap: string; + columnRule: string; + columnRuleColor: string; + columnRuleStyle: string; + columnRuleWidth: string; + columnSpan: string; + columnWidth: string; + columns: string; + content: string; + counterIncrement: string; + counterReset: string; + cssFloat: string; + cssText: string; + cursor: string; + direction: string; + display: string; + dominantBaseline: string; + emptyCells: string; + fill: string; + fillOpacity: string; + fillRule: string; + filter: string; + flex: string; + flexBasis: string; + flexDirection: string; + flexFlow: string; + flexGrow: string; + flexShrink: string; + flexWrap: string; + float: string; + floodColor: string; + floodOpacity: string; + font: string; + fontFamily: string; + fontFeatureSettings: string; + fontKerning: string; + fontSize: string; + fontSizeAdjust: string; + fontStretch: string; + fontStyle: string; + fontSynthesis: string; + fontVariant: string; + fontVariantCaps: string; + fontVariantEastAsian: string; + fontVariantLigatures: string; + fontVariantNumeric: string; + fontVariantPosition: string; + fontWeight: string; + gap: string; + glyphOrientationVertical: string; + grid: string; + gridArea: string; + gridAutoColumns: string; + gridAutoFlow: string; + gridAutoRows: string; + gridColumn: string; + gridColumnEnd: string; + gridColumnGap: string; + gridColumnStart: string; + gridGap: string; + gridRow: string; + gridRowEnd: string; + gridRowGap: string; + gridRowStart: string; + gridTemplate: string; + gridTemplateAreas: string; + gridTemplateColumns: string; + gridTemplateRows: string; + height: string; + hyphens: string; + imageOrientation: string; + imageRendering: string; + inlineSize: string; + justifyContent: string; + justifyItems: string; + justifySelf: string; + left: string; + readonly length: number; + letterSpacing: string; + lightingColor: string; + lineBreak: string; + lineHeight: string; + listStyle: string; + listStyleImage: string; + listStylePosition: string; + listStyleType: string; + margin: string; + marginBlockEnd: string; + marginBlockStart: string; + marginBottom: string; + marginInlineEnd: string; + marginInlineStart: string; + marginLeft: string; + marginRight: string; + marginTop: string; + marker: string; + markerEnd: string; + markerMid: string; + markerStart: string; + mask: string; + maskComposite: string; + maskImage: string; + maskPosition: string; + maskRepeat: string; + maskSize: string; + maskType: string; + maxBlockSize: string; + maxHeight: string; + maxInlineSize: string; + maxWidth: string; + minBlockSize: string; + minHeight: string; + minInlineSize: string; + minWidth: string; + objectFit: string; + objectPosition: string; + opacity: string; + order: string; + orphans: string; + outline: string; + outlineColor: string; + outlineOffset: string; + outlineStyle: string; + outlineWidth: string; + overflow: string; + overflowAnchor: string; + overflowWrap: string; + overflowX: string; + overflowY: string; + overscrollBehavior: string; + overscrollBehaviorBlock: string; + overscrollBehaviorInline: string; + overscrollBehaviorX: string; + overscrollBehaviorY: string; + padding: string; + paddingBlockEnd: string; + paddingBlockStart: string; + paddingBottom: string; + paddingInlineEnd: string; + paddingInlineStart: string; + paddingLeft: string; + paddingRight: string; + paddingTop: string; + pageBreakAfter: string; + pageBreakBefore: string; + pageBreakInside: string; + paintOrder: string; + readonly parentRule: CSSRule | null; + perspective: string; + perspectiveOrigin: string; + placeContent: string; + placeItems: string; + placeSelf: string; + pointerEvents: string; + position: string; + quotes: string; + resize: string; + right: string; + rotate: string; + rowGap: string; + rubyAlign: string; + rubyPosition: string; + scale: string; + scrollBehavior: string; + shapeRendering: string; + stopColor: string; + stopOpacity: string; + stroke: string; + strokeDasharray: string; + strokeDashoffset: string; + strokeLinecap: string; + strokeLinejoin: string; + strokeMiterlimit: string; + strokeOpacity: string; + strokeWidth: string; + tabSize: string; + tableLayout: string; + textAlign: string; + textAlignLast: string; + textAnchor: string; + textCombineUpright: string; + textDecoration: string; + textDecorationColor: string; + textDecorationLine: string; + textDecorationStyle: string; + textEmphasis: string; + textEmphasisColor: string; + textEmphasisPosition: string; + textEmphasisStyle: string; + textIndent: string; + textJustify: string; + textOrientation: string; + textOverflow: string; + textRendering: string; + textShadow: string; + textTransform: string; + textUnderlinePosition: string; + top: string; + touchAction: string; + transform: string; + transformBox: string; + transformOrigin: string; + transformStyle: string; + transition: string; + transitionDelay: string; + transitionDuration: string; + transitionProperty: string; + transitionTimingFunction: string; + translate: string; + unicodeBidi: string; + userSelect: string; + verticalAlign: string; + visibility: string; + /** @deprecated */ + webkitAlignContent: string; + /** @deprecated */ + webkitAlignItems: string; + /** @deprecated */ + webkitAlignSelf: string; + /** @deprecated */ + webkitAnimation: string; + /** @deprecated */ + webkitAnimationDelay: string; + /** @deprecated */ + webkitAnimationDirection: string; + /** @deprecated */ + webkitAnimationDuration: string; + /** @deprecated */ + webkitAnimationFillMode: string; + /** @deprecated */ + webkitAnimationIterationCount: string; + /** @deprecated */ + webkitAnimationName: string; + /** @deprecated */ + webkitAnimationPlayState: string; + /** @deprecated */ + webkitAnimationTimingFunction: string; + /** @deprecated */ + webkitAppearance: string; + /** @deprecated */ + webkitBackfaceVisibility: string; + /** @deprecated */ + webkitBackgroundClip: string; + /** @deprecated */ + webkitBackgroundOrigin: string; + /** @deprecated */ + webkitBackgroundSize: string; + /** @deprecated */ + webkitBorderBottomLeftRadius: string; + /** @deprecated */ + webkitBorderBottomRightRadius: string; + /** @deprecated */ + webkitBorderRadius: string; + /** @deprecated */ + webkitBorderTopLeftRadius: string; + /** @deprecated */ + webkitBorderTopRightRadius: string; + /** @deprecated */ + webkitBoxAlign: string; + /** @deprecated */ + webkitBoxFlex: string; + /** @deprecated */ + webkitBoxOrdinalGroup: string; + /** @deprecated */ + webkitBoxOrient: string; + /** @deprecated */ + webkitBoxPack: string; + /** @deprecated */ + webkitBoxShadow: string; + /** @deprecated */ + webkitBoxSizing: string; + /** @deprecated */ + webkitFilter: string; + /** @deprecated */ + webkitFlex: string; + /** @deprecated */ + webkitFlexBasis: string; + /** @deprecated */ + webkitFlexDirection: string; + /** @deprecated */ + webkitFlexFlow: string; + /** @deprecated */ + webkitFlexGrow: string; + /** @deprecated */ + webkitFlexShrink: string; + /** @deprecated */ + webkitFlexWrap: string; + /** @deprecated */ + webkitJustifyContent: string; + webkitLineClamp: string; + /** @deprecated */ + webkitMask: string; + /** @deprecated */ + webkitMaskBoxImage: string; + /** @deprecated */ + webkitMaskBoxImageOutset: string; + /** @deprecated */ + webkitMaskBoxImageRepeat: string; + /** @deprecated */ + webkitMaskBoxImageSlice: string; + /** @deprecated */ + webkitMaskBoxImageSource: string; + /** @deprecated */ + webkitMaskBoxImageWidth: string; + /** @deprecated */ + webkitMaskClip: string; + /** @deprecated */ + webkitMaskComposite: string; + /** @deprecated */ + webkitMaskImage: string; + /** @deprecated */ + webkitMaskOrigin: string; + /** @deprecated */ + webkitMaskPosition: string; + /** @deprecated */ + webkitMaskRepeat: string; + /** @deprecated */ + webkitMaskSize: string; + /** @deprecated */ + webkitOrder: string; + /** @deprecated */ + webkitPerspective: string; + /** @deprecated */ + webkitPerspectiveOrigin: string; + webkitTapHighlightColor: string; + /** @deprecated */ + webkitTextFillColor: string; + /** @deprecated */ + webkitTextSizeAdjust: string; + /** @deprecated */ + webkitTextStroke: string; + /** @deprecated */ + webkitTextStrokeColor: string; + /** @deprecated */ + webkitTextStrokeWidth: string; + /** @deprecated */ + webkitTransform: string; + /** @deprecated */ + webkitTransformOrigin: string; + /** @deprecated */ + webkitTransformStyle: string; + /** @deprecated */ + webkitTransition: string; + /** @deprecated */ + webkitTransitionDelay: string; + /** @deprecated */ + webkitTransitionDuration: string; + /** @deprecated */ + webkitTransitionProperty: string; + /** @deprecated */ + webkitTransitionTimingFunction: string; + /** @deprecated */ + webkitUserSelect: string; + whiteSpace: string; + widows: string; + width: string; + willChange: string; + wordBreak: string; + wordSpacing: string; + wordWrap: string; + writingMode: string; + zIndex: string; + /** @deprecated */ + zoom: string; + getPropertyPriority(property: string): string; + getPropertyValue(property: string): string; + item(index: number): string; + removeProperty(property: string): string; + setProperty( + property: string, + value: string | null, + priority?: string, + ): void; + [index: number]: string; +} + +declare var CSSStyleDeclaration: { + prototype: CSSStyleDeclaration; + new (): CSSStyleDeclaration; +}; + +/** CSSStyleRule represents a single CSS style rule. It implements the CSSRule interface with a type value of 1 (CSSRule.STYLE_RULE). */ +export interface CSSStyleRule extends CSSRule { + selectorText: string; + readonly style: CSSStyleDeclaration; +} + +declare var CSSStyleRule: { + prototype: CSSStyleRule; + new (): CSSStyleRule; +}; + +/** A single CSS style sheet. It inherits properties and methods from its parent, StyleSheet. */ +export interface CSSStyleSheet extends StyleSheet { + readonly cssRules: CSSRuleList; + readonly ownerRule: CSSRule | null; + readonly rules: CSSRuleList; + addRule(selector?: string, style?: string, index?: number): number; + deleteRule(index: number): void; + insertRule(rule: string, index?: number): number; + removeRule(index?: number): void; +} + +declare var CSSStyleSheet: { + prototype: CSSStyleSheet; + new (): CSSStyleSheet; +}; + +/** An object representing a single CSS @supports at-rule. It implements the CSSConditionRule interface, and therefore the CSSRule and CSSGroupingRule interfaces with a type value of 12 (CSSRule.SUPPORTS_RULE). */ +export interface CSSSupportsRule extends CSSConditionRule {} + +declare var CSSSupportsRule: { + prototype: CSSSupportsRule; + new (): CSSSupportsRule; +}; + +/** Provides a storage mechanism for Request / Response object pairs that are cached, for example as part of the ServiceWorker life cycle. Note that the Cache interface is exposed to windowed scopes as well as workers. You don't have to use it in conjunction with service workers, even though it is defined in the service worker spec. */ +export interface Cache { + add(request: RequestInfo): Promise; + addAll(requests: RequestInfo[]): Promise; + delete(request: RequestInfo, options?: CacheQueryOptions): Promise; + keys( + request?: RequestInfo, + options?: CacheQueryOptions, + ): Promise>; + match( + request: RequestInfo, + options?: CacheQueryOptions, + ): Promise; + matchAll( + request?: RequestInfo, + options?: CacheQueryOptions, + ): Promise>; + put(request: RequestInfo, response: Response): Promise; +} + +declare var Cache: { + prototype: Cache; + new (): Cache; +}; + +/** The storage for Cache objects. */ +export interface CacheStorage { + delete(cacheName: string): Promise; + has(cacheName: string): Promise; + keys(): Promise; + match( + request: RequestInfo, + options?: MultiCacheQueryOptions, + ): Promise; + open(cacheName: string): Promise; +} + +declare var CacheStorage: { + prototype: CacheStorage; + new (): CacheStorage; +}; + +export interface CanvasCompositing { + globalAlpha: number; + globalCompositeOperation: string; +} + +export interface CanvasDrawImage { + drawImage(image: CanvasImageSource, dx: number, dy: number): void; + drawImage( + image: CanvasImageSource, + dx: number, + dy: number, + dw: number, + dh: number, + ): void; + drawImage( + image: CanvasImageSource, + sx: number, + sy: number, + sw: number, + sh: number, + dx: number, + dy: number, + dw: number, + dh: number, + ): void; +} + +export interface CanvasDrawPath { + beginPath(): void; + clip(fillRule?: CanvasFillRule): void; + clip(path: Path2D, fillRule?: CanvasFillRule): void; + fill(fillRule?: CanvasFillRule): void; + fill(path: Path2D, fillRule?: CanvasFillRule): void; + isPointInPath(x: number, y: number, fillRule?: CanvasFillRule): boolean; + isPointInPath( + path: Path2D, + x: number, + y: number, + fillRule?: CanvasFillRule, + ): boolean; + isPointInStroke(x: number, y: number): boolean; + isPointInStroke(path: Path2D, x: number, y: number): boolean; + stroke(): void; + stroke(path: Path2D): void; +} + +export interface CanvasFillStrokeStyles { + fillStyle: string | CanvasGradient | CanvasPattern; + strokeStyle: string | CanvasGradient | CanvasPattern; + createLinearGradient( + x0: number, + y0: number, + x1: number, + y1: number, + ): CanvasGradient; + createPattern( + image: CanvasImageSource, + repetition: string | null, + ): CanvasPattern | null; + createRadialGradient( + x0: number, + y0: number, + r0: number, + x1: number, + y1: number, + r1: number, + ): CanvasGradient; +} + +export interface CanvasFilters { + filter: string; +} + +/** An opaque object describing a gradient. It is returned by the methods CanvasRenderingContext2D.createLinearGradient() or CanvasRenderingContext2D.createRadialGradient(). */ +export interface CanvasGradient { + /** + * Adds a color stop with the given color to the gradient at the given offset. 0.0 is the offset at one end of the gradient, 1.0 is the offset at the other end. + * + * Throws an "IndexSizeError" DOMException if the offset is out of range. Throws a "SyntaxError" DOMException if the color cannot be parsed. + */ + addColorStop(offset: number, color: string): void; +} + +declare var CanvasGradient: { + prototype: CanvasGradient; + new (): CanvasGradient; +}; + +export interface CanvasImageData { + createImageData(sw: number, sh: number): ImageData; + createImageData(imagedata: ImageData): ImageData; + getImageData(sx: number, sy: number, sw: number, sh: number): ImageData; + putImageData(imagedata: ImageData, dx: number, dy: number): void; + putImageData( + imagedata: ImageData, + dx: number, + dy: number, + dirtyX: number, + dirtyY: number, + dirtyWidth: number, + dirtyHeight: number, + ): void; +} + +export interface CanvasImageSmoothing { + imageSmoothingEnabled: boolean; + imageSmoothingQuality: ImageSmoothingQuality; +} + +export interface CanvasPath { + arc( + x: number, + y: number, + radius: number, + startAngle: number, + endAngle: number, + anticlockwise?: boolean, + ): void; + arcTo(x1: number, y1: number, x2: number, y2: number, radius: number): void; + bezierCurveTo( + cp1x: number, + cp1y: number, + cp2x: number, + cp2y: number, + x: number, + y: number, + ): void; + closePath(): void; + ellipse( + x: number, + y: number, + radiusX: number, + radiusY: number, + rotation: number, + startAngle: number, + endAngle: number, + anticlockwise?: boolean, + ): void; + lineTo(x: number, y: number): void; + moveTo(x: number, y: number): void; + quadraticCurveTo(cpx: number, cpy: number, x: number, y: number): void; + rect(x: number, y: number, w: number, h: number): void; +} + +export interface CanvasPathDrawingStyles { + lineCap: CanvasLineCap; + lineDashOffset: number; + lineJoin: CanvasLineJoin; + lineWidth: number; + miterLimit: number; + getLineDash(): number[]; + setLineDash(segments: number[]): void; +} + +/** An opaque object describing a pattern, based on an image, a canvas, or a video, created by the CanvasRenderingContext2D.createPattern() method. */ +export interface CanvasPattern { + /** + * Sets the transformation matrix that will be used when rendering the pattern during a fill or stroke painting operation. + */ + setTransform(transform?: DOMMatrix2DInit): void; +} + +declare var CanvasPattern: { + prototype: CanvasPattern; + new (): CanvasPattern; +}; + +export interface CanvasRect { + clearRect(x: number, y: number, w: number, h: number): void; + fillRect(x: number, y: number, w: number, h: number): void; + strokeRect(x: number, y: number, w: number, h: number): void; +} + +/** The CanvasRenderingContext2D interface, part of the Canvas API, provides the 2D rendering context for the drawing surface of a element. It is used for drawing shapes, text, images, and other objects. */ +export interface CanvasRenderingContext2D + extends CanvasCompositing, + CanvasDrawImage, + CanvasDrawPath, + CanvasFillStrokeStyles, + CanvasFilters, + CanvasImageData, + CanvasImageSmoothing, + CanvasPath, + CanvasPathDrawingStyles, + CanvasRect, + CanvasShadowStyles, + CanvasState, + CanvasText, + CanvasTextDrawingStyles, + CanvasTransform, + CanvasUserInterface { + readonly canvas: HTMLCanvasElement; +} + +declare var CanvasRenderingContext2D: { + prototype: CanvasRenderingContext2D; + new (): CanvasRenderingContext2D; +}; + +export interface CanvasShadowStyles { + shadowBlur: number; + shadowColor: string; + shadowOffsetX: number; + shadowOffsetY: number; +} + +export interface CanvasState { + restore(): void; + save(): void; +} + +export interface CanvasText { + fillText(text: string, x: number, y: number, maxWidth?: number): void; + measureText(text: string): TextMetrics; + strokeText(text: string, x: number, y: number, maxWidth?: number): void; +} + +export interface CanvasTextDrawingStyles { + direction: CanvasDirection; + font: string; + textAlign: CanvasTextAlign; + textBaseline: CanvasTextBaseline; +} + +export interface CanvasTransform { + getTransform(): DOMMatrix; + resetTransform(): void; + rotate(angle: number): void; + scale(x: number, y: number): void; + setTransform( + a: number, + b: number, + c: number, + d: number, + e: number, + f: number, + ): void; + setTransform(transform?: DOMMatrix2DInit): void; + transform( + a: number, + b: number, + c: number, + d: number, + e: number, + f: number, + ): void; + translate(x: number, y: number): void; +} + +export interface CanvasUserInterface { + drawFocusIfNeeded(element: Element): void; + drawFocusIfNeeded(path: Path2D, element: Element): void; + scrollPathIntoView(): void; + scrollPathIntoView(path: Path2D): void; +} + +export interface CaretPosition { + readonly offset: number; + readonly offsetNode: Node; + getClientRect(): DOMRect | null; +} + +declare var CaretPosition: { + prototype: CaretPosition; + new (): CaretPosition; +}; + +/** The ChannelMergerNode interface, often used in conjunction with its opposite, ChannelSplitterNode, reunites different mono inputs into a single output. Each input is used to fill a channel of the output. This is useful for accessing each channels separately, e.g. for performing channel mixing where gain must be separately controlled on each channel. */ +export interface ChannelMergerNode extends AudioNode {} + +declare var ChannelMergerNode: { + prototype: ChannelMergerNode; + new ( + context: BaseAudioContext, + options?: ChannelMergerOptions, + ): ChannelMergerNode; +}; + +/** The ChannelSplitterNode interface, often used in conjunction with its opposite, ChannelMergerNode, separates the different channels of an audio source into a set of mono outputs. This is useful for accessing each channel separately, e.g. for performing channel mixing where gain must be separately controlled on each channel. */ +export interface ChannelSplitterNode extends AudioNode {} + +declare var ChannelSplitterNode: { + prototype: ChannelSplitterNode; + new ( + context: BaseAudioContext, + options?: ChannelSplitterOptions, + ): ChannelSplitterNode; +}; + +/** The CharacterData abstract interface represents a Node object that contains characters. This is an abstract interface, meaning there aren't any object of type CharacterData: it is implemented by other interfaces, like Text, Comment, or ProcessingInstruction which aren't abstract. */ +export interface CharacterData + extends Node, + ChildNode, + NonDocumentTypeChildNode { + data: string; + readonly length: number; + readonly ownerDocument: Document; + appendData(data: string): void; + deleteData(offset: number, count: number): void; + insertData(offset: number, data: string): void; + replaceData(offset: number, count: number, data: string): void; + substringData(offset: number, count: number): string; +} + +declare var CharacterData: { + prototype: CharacterData; + new (): CharacterData; +}; + +export interface ChildNode extends Node { + /** + * Inserts nodes just after node, while replacing strings in nodes with equivalent Text nodes. + * + * Throws a "HierarchyRequestError" DOMException if the constraints of the node tree are violated. + */ + after(...nodes: (Node | string)[]): void; + /** + * Inserts nodes just before node, while replacing strings in nodes with equivalent Text nodes. + * + * Throws a "HierarchyRequestError" DOMException if the constraints of the node tree are violated. + */ + before(...nodes: (Node | string)[]): void; + /** + * Removes node. + */ + remove(): void; + /** + * Replaces node with nodes, while replacing strings in nodes with equivalent Text nodes. + * + * Throws a "HierarchyRequestError" DOMException if the constraints of the node tree are violated. + */ + replaceWith(...nodes: (Node | string)[]): void; +} + +export interface ClientRect { + bottom: number; + readonly height: number; + left: number; + right: number; + top: number; + readonly width: number; +} + +declare var ClientRect: { + prototype: ClientRect; + new (): ClientRect; +}; + +export interface ClientRectList { + readonly length: number; + item(index: number): ClientRect; + [index: number]: ClientRect; +} + +declare var ClientRectList: { + prototype: ClientRectList; + new (): ClientRectList; +}; + +export interface Clipboard extends EventTarget { + readText(): Promise; + writeText(data: string): Promise; +} + +declare var Clipboard: { + prototype: Clipboard; + new (): Clipboard; +}; + +/** Events providing information related to modification of the clipboard, that is cut, copy, and paste events. */ +export interface ClipboardEvent extends Event { + readonly clipboardData: DataTransfer | null; +} + +declare var ClipboardEvent: { + prototype: ClipboardEvent; + new (type: string, eventInitDict?: ClipboardEventInit): ClipboardEvent; +}; + +/** A CloseEvent is sent to clients using WebSockets when the connection is closed. This is delivered to the listener indicated by the WebSocket object's onclose attribute. */ +export interface CloseEvent extends Event { + /** + * Returns the WebSocket connection close code provided by the server. + */ + readonly code: number; + /** + * Returns the WebSocket connection close reason provided by the server. + */ + readonly reason: string; + /** + * Returns true if the connection closed cleanly; false otherwise. + */ + readonly wasClean: boolean; +} + +declare var CloseEvent: { + prototype: CloseEvent; + new (type: string, eventInitDict?: CloseEventInit): CloseEvent; +}; + +/** Textual notations within markup; although it is generally not visually shown, such comments are available to be read in the source view. */ +export interface Comment extends CharacterData {} + +declare var Comment: { + prototype: Comment; + new (data?: string): Comment; +}; + +/** The DOM CompositionEvent represents events that occur due to the user indirectly entering text. */ +export interface CompositionEvent extends UIEvent { + readonly data: string; +} + +declare var CompositionEvent: { + prototype: CompositionEvent; + new (type: string, eventInitDict?: CompositionEventInit): CompositionEvent; +}; + +export interface ConcatParams extends Algorithm { + algorithmId: Uint8Array; + hash?: string | Algorithm; + partyUInfo: Uint8Array; + partyVInfo: Uint8Array; + privateInfo?: Uint8Array; + publicInfo?: Uint8Array; +} + +export interface ConstantSourceNode extends AudioScheduledSourceNode { + readonly offset: AudioParam; + addEventListener( + type: K, + listener: ( + this: ConstantSourceNode, + ev: AudioScheduledSourceNodeEventMap[K], + ) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: ( + this: ConstantSourceNode, + ev: AudioScheduledSourceNodeEventMap[K], + ) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var ConstantSourceNode: { + prototype: ConstantSourceNode; + new ( + context: BaseAudioContext, + options?: ConstantSourceOptions, + ): ConstantSourceNode; +}; + +/** An AudioNode that performs a Linear Convolution on a given AudioBuffer, often used to achieve a reverb effect. A ConvolverNode always has exactly one input and one output. */ +export interface ConvolverNode extends AudioNode { + buffer: AudioBuffer | null; + normalize: boolean; +} + +declare var ConvolverNode: { + prototype: ConvolverNode; + new (context: BaseAudioContext, options?: ConvolverOptions): ConvolverNode; +}; + +/** This Streams API interface provides a built-in byte length queuing strategy that can be used when constructing streams. */ +export interface CountQueuingStrategy extends QueuingStrategy { + readonly highWaterMark: number; + readonly size: QueuingStrategySize; +} + +declare var CountQueuingStrategy: { + prototype: CountQueuingStrategy; + new (init: QueuingStrategyInit): CountQueuingStrategy; +}; + +export interface Credential { + readonly id: string; + readonly type: string; +} + +declare var Credential: { + prototype: Credential; + new (): Credential; +}; + +export interface CredentialsContainer { + create(options?: CredentialCreationOptions): Promise; + get(options?: CredentialRequestOptions): Promise; + preventSilentAccess(): Promise; + store(credential: Credential): Promise; +} + +declare var CredentialsContainer: { + prototype: CredentialsContainer; + new (): CredentialsContainer; +}; + +/** Basic cryptography features available in the current context. It allows access to a cryptographically strong random number generator and to cryptographic primitives. */ +export interface Crypto { + readonly subtle: SubtleCrypto; + getRandomValues< + T extends + | Int8Array + | Int16Array + | Int32Array + | Uint8Array + | Uint16Array + | Uint32Array + | Uint8ClampedArray + | Float32Array + | Float64Array + | DataView + | null, + >( + array: T, + ): T; +} + +declare var Crypto: { + prototype: Crypto; + new (): Crypto; +}; + +/** The CryptoKey dictionary of the Web Crypto API represents a cryptographic key. */ +export interface CryptoKey { + readonly algorithm: KeyAlgorithm; + readonly extractable: boolean; + readonly type: KeyType; + readonly usages: KeyUsage[]; +} + +declare var CryptoKey: { + prototype: CryptoKey; + new (): CryptoKey; +}; + +/** The CryptoKeyPair dictionary of the Web Crypto API represents a key pair for an asymmetric cryptography algorithm, also known as a public-key algorithm. */ +export interface CryptoKeyPair { + privateKey: CryptoKey; + publicKey: CryptoKey; +} + +declare var CryptoKeyPair: { + prototype: CryptoKeyPair; + new (): CryptoKeyPair; +}; + +export interface CustomElementRegistry { + define( + name: string, + constructor: CustomElementConstructor, + options?: ElementDefinitionOptions, + ): void; + get(name: string): any; + upgrade(root: Node): void; + whenDefined(name: string): Promise; +} + +declare var CustomElementRegistry: { + prototype: CustomElementRegistry; + new (): CustomElementRegistry; +}; + +export interface CustomEvent extends Event { + /** + * Returns any custom data event was created with. Typically used for synthetic events. + */ + readonly detail: T; + initCustomEvent( + typeArg: string, + canBubbleArg: boolean, + cancelableArg: boolean, + detailArg: T, + ): void; +} + +declare var CustomEvent: { + prototype: CustomEvent; + new ( + typeArg: string, + eventInitDict?: CustomEventInit, + ): CustomEvent; +}; + +/** An error object that contains an error name. */ +export interface DOMError { + readonly name: string; + toString(): string; +} + +declare var DOMError: { + prototype: DOMError; + new (): DOMError; +}; + +/** An abnormal event (called an exception) which occurs as a result of calling a method or accessing a property of a web API. */ +export interface DOMException { + readonly code: number; + readonly message: string; + readonly name: string; + readonly ABORT_ERR: number; + readonly DATA_CLONE_ERR: number; + readonly DOMSTRING_SIZE_ERR: number; + readonly HIERARCHY_REQUEST_ERR: number; + readonly INDEX_SIZE_ERR: number; + readonly INUSE_ATTRIBUTE_ERR: number; + readonly INVALID_ACCESS_ERR: number; + readonly INVALID_CHARACTER_ERR: number; + readonly INVALID_MODIFICATION_ERR: number; + readonly INVALID_NODE_TYPE_ERR: number; + readonly INVALID_STATE_ERR: number; + readonly NAMESPACE_ERR: number; + readonly NETWORK_ERR: number; + readonly NOT_FOUND_ERR: number; + readonly NOT_SUPPORTED_ERR: number; + readonly NO_DATA_ALLOWED_ERR: number; + readonly NO_MODIFICATION_ALLOWED_ERR: number; + readonly QUOTA_EXCEEDED_ERR: number; + readonly SECURITY_ERR: number; + readonly SYNTAX_ERR: number; + readonly TIMEOUT_ERR: number; + readonly TYPE_MISMATCH_ERR: number; + readonly URL_MISMATCH_ERR: number; + readonly VALIDATION_ERR: number; + readonly WRONG_DOCUMENT_ERR: number; +} + +declare var DOMException: { + prototype: DOMException; + new (message?: string, name?: string): DOMException; + readonly ABORT_ERR: number; + readonly DATA_CLONE_ERR: number; + readonly DOMSTRING_SIZE_ERR: number; + readonly HIERARCHY_REQUEST_ERR: number; + readonly INDEX_SIZE_ERR: number; + readonly INUSE_ATTRIBUTE_ERR: number; + readonly INVALID_ACCESS_ERR: number; + readonly INVALID_CHARACTER_ERR: number; + readonly INVALID_MODIFICATION_ERR: number; + readonly INVALID_NODE_TYPE_ERR: number; + readonly INVALID_STATE_ERR: number; + readonly NAMESPACE_ERR: number; + readonly NETWORK_ERR: number; + readonly NOT_FOUND_ERR: number; + readonly NOT_SUPPORTED_ERR: number; + readonly NO_DATA_ALLOWED_ERR: number; + readonly NO_MODIFICATION_ALLOWED_ERR: number; + readonly QUOTA_EXCEEDED_ERR: number; + readonly SECURITY_ERR: number; + readonly SYNTAX_ERR: number; + readonly TIMEOUT_ERR: number; + readonly TYPE_MISMATCH_ERR: number; + readonly URL_MISMATCH_ERR: number; + readonly VALIDATION_ERR: number; + readonly WRONG_DOCUMENT_ERR: number; +}; + +/** An object providing methods which are not dependent on any particular document. Such an object is returned by the Document.implementation property. */ +export interface DOMImplementation { + createDocument( + namespace: string | null, + qualifiedName: string | null, + doctype?: DocumentType | null, + ): XMLDocument; + createDocumentType( + qualifiedName: string, + publicId: string, + systemId: string, + ): DocumentType; + createHTMLDocument(title?: string): Document; + /** @deprecated */ + hasFeature(...args: any[]): true; +} + +declare var DOMImplementation: { + prototype: DOMImplementation; + new (): DOMImplementation; +}; + +export interface DOMMatrix extends DOMMatrixReadOnly { + a: number; + b: number; + c: number; + d: number; + e: number; + f: number; + m11: number; + m12: number; + m13: number; + m14: number; + m21: number; + m22: number; + m23: number; + m24: number; + m31: number; + m32: number; + m33: number; + m34: number; + m41: number; + m42: number; + m43: number; + m44: number; + invertSelf(): DOMMatrix; + multiplySelf(other?: DOMMatrixInit): DOMMatrix; + preMultiplySelf(other?: DOMMatrixInit): DOMMatrix; + rotateAxisAngleSelf( + x?: number, + y?: number, + z?: number, + angle?: number, + ): DOMMatrix; + rotateFromVectorSelf(x?: number, y?: number): DOMMatrix; + rotateSelf(rotX?: number, rotY?: number, rotZ?: number): DOMMatrix; + scale3dSelf( + scale?: number, + originX?: number, + originY?: number, + originZ?: number, + ): DOMMatrix; + scaleSelf( + scaleX?: number, + scaleY?: number, + scaleZ?: number, + originX?: number, + originY?: number, + originZ?: number, + ): DOMMatrix; + setMatrixValue(transformList: string): DOMMatrix; + skewXSelf(sx?: number): DOMMatrix; + skewYSelf(sy?: number): DOMMatrix; + translateSelf(tx?: number, ty?: number, tz?: number): DOMMatrix; +} + +declare var DOMMatrix: { + prototype: DOMMatrix; + new (init?: string | number[]): DOMMatrix; + fromFloat32Array(array32: Float32Array): DOMMatrix; + fromFloat64Array(array64: Float64Array): DOMMatrix; + fromMatrix(other?: DOMMatrixInit): DOMMatrix; +}; + +type SVGMatrix = DOMMatrix; +declare var SVGMatrix: typeof DOMMatrix; + +type WebKitCSSMatrix = DOMMatrix; +declare var WebKitCSSMatrix: typeof DOMMatrix; + +export interface DOMMatrixReadOnly { + readonly a: number; + readonly b: number; + readonly c: number; + readonly d: number; + readonly e: number; + readonly f: number; + readonly is2D: boolean; + readonly isIdentity: boolean; + readonly m11: number; + readonly m12: number; + readonly m13: number; + readonly m14: number; + readonly m21: number; + readonly m22: number; + readonly m23: number; + readonly m24: number; + readonly m31: number; + readonly m32: number; + readonly m33: number; + readonly m34: number; + readonly m41: number; + readonly m42: number; + readonly m43: number; + readonly m44: number; + flipX(): DOMMatrix; + flipY(): DOMMatrix; + inverse(): DOMMatrix; + multiply(other?: DOMMatrixInit): DOMMatrix; + rotate(rotX?: number, rotY?: number, rotZ?: number): DOMMatrix; + rotateAxisAngle( + x?: number, + y?: number, + z?: number, + angle?: number, + ): DOMMatrix; + rotateFromVector(x?: number, y?: number): DOMMatrix; + scale( + scaleX?: number, + scaleY?: number, + scaleZ?: number, + originX?: number, + originY?: number, + originZ?: number, + ): DOMMatrix; + scale3d( + scale?: number, + originX?: number, + originY?: number, + originZ?: number, + ): DOMMatrix; + /** @deprecated */ + scaleNonUniform(scaleX?: number, scaleY?: number): DOMMatrix; + skewX(sx?: number): DOMMatrix; + skewY(sy?: number): DOMMatrix; + toFloat32Array(): Float32Array; + toFloat64Array(): Float64Array; + toJSON(): any; + transformPoint(point?: DOMPointInit): DOMPoint; + translate(tx?: number, ty?: number, tz?: number): DOMMatrix; + toString(): string; +} + +declare var DOMMatrixReadOnly: { + prototype: DOMMatrixReadOnly; + new (init?: string | number[]): DOMMatrixReadOnly; + fromFloat32Array(array32: Float32Array): DOMMatrixReadOnly; + fromFloat64Array(array64: Float64Array): DOMMatrixReadOnly; + fromMatrix(other?: DOMMatrixInit): DOMMatrixReadOnly; + toString(): string; +}; + +/** Provides the ability to parse XML or HTML source code from a string into a DOM Document. */ +export interface DOMParser { + /** + * Parses string using either the HTML or XML parser, according to type, and returns the resulting Document. type can be "text/html" (which will invoke the HTML parser), or any of "text/xml", "application/xml", "application/xhtml+xml", or "image/svg+xml" (which will invoke the XML parser). + * + * For the XML parser, if string cannot be parsed, then the returned Document will contain elements describing the resulting error. + * + * Note that script elements are not evaluated during parsing, and the resulting document's encoding will always be UTF-8. + * + * Values other than the above for type will cause a TypeError exception to be thrown. + */ + parseFromString(string: string, type: DOMParserSupportedType): Document; +} + +declare var DOMParser: { + prototype: DOMParser; + new (): DOMParser; +}; + +export interface DOMPoint extends DOMPointReadOnly { + w: number; + x: number; + y: number; + z: number; +} + +declare var DOMPoint: { + prototype: DOMPoint; + new (x?: number, y?: number, z?: number, w?: number): DOMPoint; + fromPoint(other?: DOMPointInit): DOMPoint; +}; + +type SVGPoint = DOMPoint; +declare var SVGPoint: typeof DOMPoint; + +export interface DOMPointReadOnly { + readonly w: number; + readonly x: number; + readonly y: number; + readonly z: number; + matrixTransform(matrix?: DOMMatrixInit): DOMPoint; + toJSON(): any; +} + +declare var DOMPointReadOnly: { + prototype: DOMPointReadOnly; + new (x?: number, y?: number, z?: number, w?: number): DOMPointReadOnly; + fromPoint(other?: DOMPointInit): DOMPointReadOnly; +}; + +export interface DOMQuad { + readonly p1: DOMPoint; + readonly p2: DOMPoint; + readonly p3: DOMPoint; + readonly p4: DOMPoint; + getBounds(): DOMRect; + toJSON(): any; +} + +declare var DOMQuad: { + prototype: DOMQuad; + new ( + p1?: DOMPointInit, + p2?: DOMPointInit, + p3?: DOMPointInit, + p4?: DOMPointInit, + ): DOMQuad; + fromQuad(other?: DOMQuadInit): DOMQuad; + fromRect(other?: DOMRectInit): DOMQuad; +}; + +export interface DOMRect extends DOMRectReadOnly { + height: number; + width: number; + x: number; + y: number; +} + +declare var DOMRect: { + prototype: DOMRect; + new (x?: number, y?: number, width?: number, height?: number): DOMRect; + fromRect(other?: DOMRectInit): DOMRect; +}; + +type SVGRect = DOMRect; +declare var SVGRect: typeof DOMRect; + +export interface DOMRectList { + readonly length: number; + item(index: number): DOMRect | null; + [index: number]: DOMRect; +} + +declare var DOMRectList: { + prototype: DOMRectList; + new (): DOMRectList; +}; + +export interface DOMRectReadOnly { + readonly bottom: number; + readonly height: number; + readonly left: number; + readonly right: number; + readonly top: number; + readonly width: number; + readonly x: number; + readonly y: number; + toJSON(): any; +} + +declare var DOMRectReadOnly: { + prototype: DOMRectReadOnly; + new ( + x?: number, + y?: number, + width?: number, + height?: number, + ): DOMRectReadOnly; + fromRect(other?: DOMRectInit): DOMRectReadOnly; +}; + +export interface DOMSettableTokenList extends DOMTokenList { + value: string; +} + +declare var DOMSettableTokenList: { + prototype: DOMSettableTokenList; + new (): DOMSettableTokenList; +}; + +/** A type returned by some APIs which contains a list of DOMString (strings). */ +export interface DOMStringList { + /** + * Returns the number of strings in strings. + */ + readonly length: number; + /** + * Returns true if strings contains string, and false otherwise. + */ + contains(string: string): boolean; + /** + * Returns the string with index index from strings. + */ + item(index: number): string | null; + [index: number]: string; +} + +declare var DOMStringList: { + prototype: DOMStringList; + new (): DOMStringList; +}; + +/** Used by the dataset HTML attribute to represent data for custom attributes added to elements. */ +export interface DOMStringMap { + [name: string]: string | undefined; +} + +declare var DOMStringMap: { + prototype: DOMStringMap; + new (): DOMStringMap; +}; + +/** A set of space-separated tokens. Such a set is returned by Element.classList, HTMLLinkElement.relList, HTMLAnchorElement.relList, HTMLAreaElement.relList, HTMLIframeElement.sandbox, or HTMLOutputElement.htmlFor. It is indexed beginning with 0 as with JavaScript Array objects. DOMTokenList is always case-sensitive. */ +export interface DOMTokenList { + /** + * Returns the number of tokens. + */ + readonly length: number; + /** + * Returns the associated set as string. + * + * Can be set, to change the associated attribute. + */ + value: string; + toString(): string; + /** + * Adds all arguments passed, except those already present. + * + * Throws a "SyntaxError" DOMException if one of the arguments is the empty string. + * + * Throws an "InvalidCharacterError" DOMException if one of the arguments contains any ASCII whitespace. + */ + add(...tokens: string[]): void; + /** + * Returns true if token is present, and false otherwise. + */ + contains(token: string): boolean; + /** + * Returns the token with index index. + */ + item(index: number): string | null; + /** + * Removes arguments passed, if they are present. + * + * Throws a "SyntaxError" DOMException if one of the arguments is the empty string. + * + * Throws an "InvalidCharacterError" DOMException if one of the arguments contains any ASCII whitespace. + */ + remove(...tokens: string[]): void; + /** + * Replaces token with newToken. + * + * Returns true if token was replaced with newToken, and false otherwise. + * + * Throws a "SyntaxError" DOMException if one of the arguments is the empty string. + * + * Throws an "InvalidCharacterError" DOMException if one of the arguments contains any ASCII whitespace. + */ + replace(oldToken: string, newToken: string): void; + /** + * Returns true if token is in the associated attribute's supported tokens. Returns false otherwise. + * + * Throws a TypeError if the associated attribute has no supported tokens defined. + */ + supports(token: string): boolean; + /** + * If force is not given, "toggles" token, removing it if it's present and adding it if it's not present. If force is true, adds token (same as add()). If force is false, removes token (same as remove()). + * + * Returns true if token is now present, and false otherwise. + * + * Throws a "SyntaxError" DOMException if token is empty. + * + * Throws an "InvalidCharacterError" DOMException if token contains any spaces. + */ + toggle(token: string, force?: boolean): boolean; + forEach( + callbackfn: (value: string, key: number, parent: DOMTokenList) => void, + thisArg?: any, + ): void; + [index: number]: string; +} + +declare var DOMTokenList: { + prototype: DOMTokenList; + new (): DOMTokenList; +}; + +export interface DataCue extends TextTrackCue { + data: ArrayBuffer; + addEventListener( + type: K, + listener: (this: DataCue, ev: TextTrackCueEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: (this: DataCue, ev: TextTrackCueEventMap[K]) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var DataCue: { + prototype: DataCue; + new (): DataCue; +}; + +/** Used to hold the data that is being dragged during a drag and drop operation. It may hold one or more data items, each of one or more data types. For more information about drag and drop, see HTML Drag and Drop API. */ +export interface DataTransfer { + /** + * Returns the kind of operation that is currently selected. If the kind of operation isn't one of those that is allowed by the effectAllowed attribute, then the operation will fail. + * + * Can be set, to change the selected operation. + * + * The possible values are "none", "copy", "link", and "move". + */ + dropEffect: "none" | "copy" | "link" | "move"; + /** + * Returns the kinds of operations that are to be allowed. + * + * Can be set (during the dragstart event), to change the allowed operations. + * + * The possible values are "none", "copy", "copyLink", "copyMove", "link", "linkMove", "move", "all", and "uninitialized", + */ + effectAllowed: + | "none" + | "copy" + | "copyLink" + | "copyMove" + | "link" + | "linkMove" + | "move" + | "all" + | "uninitialized"; + /** + * Returns a FileList of the files being dragged, if any. + */ + readonly files: FileList; + /** + * Returns a DataTransferItemList object, with the drag data. + */ + readonly items: DataTransferItemList; + /** + * Returns a frozen array listing the formats that were set in the dragstart event. In addition, if any files are being dragged, then one of the types will be the string "Files". + */ + readonly types: ReadonlyArray; + /** + * Removes the data of the specified formats. Removes all data if the argument is omitted. + */ + clearData(format?: string): void; + /** + * Returns the specified data. If there is no such data, returns the empty string. + */ + getData(format: string): string; + /** + * Adds the specified data. + */ + setData(format: string, data: string): void; + /** + * Uses the given element to update the drag feedback, replacing any previously specified feedback. + */ + setDragImage(image: Element, x: number, y: number): void; +} + +declare var DataTransfer: { + prototype: DataTransfer; + new (): DataTransfer; +}; + +/** One drag data item. During a drag operation, each drag event has a dataTransfer property which contains a list of drag data items. Each item in the list is a DataTransferItem object. */ +export interface DataTransferItem { + /** + * Returns the drag data item kind, one of: "string", "file". + */ + readonly kind: string; + /** + * Returns the drag data item type string. + */ + readonly type: string; + /** + * Returns a File object, if the drag data item kind is File. + */ + getAsFile(): File | null; + /** + * Invokes the callback with the string data as the argument, if the drag data item kind is text. + */ + getAsString(callback: FunctionStringCallback | null): void; + webkitGetAsEntry(): any; +} + +declare var DataTransferItem: { + prototype: DataTransferItem; + new (): DataTransferItem; +}; + +/** A list of DataTransferItem objects representing items being dragged. During a drag operation, each DragEvent has a dataTransfer property and that property is a DataTransferItemList. */ +export interface DataTransferItemList { + /** + * Returns the number of items in the drag data store. + */ + readonly length: number; + /** + * Adds a new entry for the given data to the drag data store. If the data is plain text then a type string has to be provided also. + */ + add(data: string, type: string): DataTransferItem | null; + add(data: File): DataTransferItem | null; + /** + * Removes all the entries in the drag data store. + */ + clear(): void; + item(index: number): DataTransferItem; + /** + * Removes the indexth entry in the drag data store. + */ + remove(index: number): void; + [name: number]: DataTransferItem; +} + +declare var DataTransferItemList: { + prototype: DataTransferItemList; + new (): DataTransferItemList; +}; + +export interface DeferredPermissionRequest { + readonly id: number; + readonly type: MSWebViewPermissionType; + readonly uri: string; + allow(): void; + deny(): void; +} + +declare var DeferredPermissionRequest: { + prototype: DeferredPermissionRequest; + new (): DeferredPermissionRequest; +}; + +/** A delay-line; an AudioNode audio-processing module that causes a delay between the arrival of an input data and its propagation to the output. */ +export interface DelayNode extends AudioNode { + readonly delayTime: AudioParam; +} + +declare var DelayNode: { + prototype: DelayNode; + new (context: BaseAudioContext, options?: DelayOptions): DelayNode; +}; + +/** Provides information about the amount of acceleration the device is experiencing along all three axes. */ +export interface DeviceAcceleration { + readonly x: number | null; + readonly y: number | null; + readonly z: number | null; +} + +declare var DeviceAcceleration: { + prototype: DeviceAcceleration; + new (): DeviceAcceleration; +}; + +/** The DeviceMotionEvent provides web developers with information about the speed of changes for the device's position and orientation. */ +export interface DeviceMotionEvent extends Event { + readonly acceleration: DeviceMotionEventAcceleration | null; + readonly accelerationIncludingGravity: DeviceMotionEventAcceleration | null; + readonly interval: number; + readonly rotationRate: DeviceMotionEventRotationRate | null; +} + +declare var DeviceMotionEvent: { + prototype: DeviceMotionEvent; + new ( + type: string, + eventInitDict?: DeviceMotionEventInit, + ): DeviceMotionEvent; + requestPermission(): Promise; +}; + +export interface DeviceMotionEventAcceleration { + readonly x: number | null; + readonly y: number | null; + readonly z: number | null; +} + +export interface DeviceMotionEventRotationRate { + readonly alpha: number | null; + readonly beta: number | null; + readonly gamma: number | null; +} + +/** The DeviceOrientationEvent provides web developers with information from the physical orientation of the device running the web page. */ +export interface DeviceOrientationEvent extends Event { + readonly absolute: boolean; + readonly alpha: number | null; + readonly beta: number | null; + readonly gamma: number | null; +} + +declare var DeviceOrientationEvent: { + prototype: DeviceOrientationEvent; + new ( + type: string, + eventInitDict?: DeviceOrientationEventInit, + ): DeviceOrientationEvent; + requestPermission(): Promise; +}; + +/** Provides information about the rate at which the device is rotating around all three axes. */ +export interface DeviceRotationRate { + readonly alpha: number | null; + readonly beta: number | null; + readonly gamma: number | null; +} + +declare var DeviceRotationRate: { + prototype: DeviceRotationRate; + new (): DeviceRotationRate; +}; + +export interface DhImportKeyParams extends Algorithm { + generator: Uint8Array; + prime: Uint8Array; +} + +export interface DhKeyAlgorithm extends KeyAlgorithm { + generator: Uint8Array; + prime: Uint8Array; +} + +export interface DhKeyDeriveParams extends Algorithm { + public: CryptoKey; +} + +export interface DhKeyGenParams extends Algorithm { + generator: Uint8Array; + prime: Uint8Array; +} + +export interface DocumentEventMap + extends GlobalEventHandlersEventMap, + DocumentAndElementEventHandlersEventMap { + fullscreenchange: Event; + fullscreenerror: Event; + pointerlockchange: Event; + pointerlockerror: Event; + readystatechange: Event; + visibilitychange: Event; +} + +/** Any web page loaded in the browser and serves as an entry point into the web page's content, which is the DOM tree. */ +export interface Document + extends Node, + DocumentAndElementEventHandlers, + DocumentOrShadowRoot, + GlobalEventHandlers, + NonElementParentNode, + ParentNode, + XPathEvaluatorBase { + /** + * Sets or gets the URL for the current document. + */ + readonly URL: string; + /** + * Sets or gets the color of all active links in the document. + */ + /** @deprecated */ + alinkColor: string; + /** + * Returns a reference to the collection of elements contained by the object. + */ + /** @deprecated */ + readonly all: HTMLAllCollection; + /** + * Retrieves a collection of all a objects that have a name and/or id property. Objects in this collection are in HTML source order. + */ + /** @deprecated */ + readonly anchors: HTMLCollectionOf; + /** + * Retrieves a collection of all applet objects in the document. + */ + /** @deprecated */ + readonly applets: HTMLCollectionOf; + /** + * Deprecated. Sets or retrieves a value that indicates the background color behind the object. + */ + /** @deprecated */ + bgColor: string; + /** + * Specifies the beginning and end of the document body. + */ + body: HTMLElement; + /** + * Returns document's encoding. + */ + readonly characterSet: string; + /** + * Gets or sets the character set used to encode the object. + */ + readonly charset: string; + /** + * Gets a value that indicates whether standards-compliant mode is switched on for the object. + */ + readonly compatMode: string; + /** + * Returns document's content type. + */ + readonly contentType: string; + /** + * Returns the HTTP cookies that apply to the Document. If there are no cookies or cookies can't be applied to this resource, the empty string will be returned. + * + * Can be set, to add a new cookie to the element's set of HTTP cookies. + * + * If the contents are sandboxed into a unique origin (e.g. in an iframe with the sandbox attribute), a "SecurityError" DOMException will be thrown on getting and setting. + */ + cookie: string; + /** + * Returns the script element, or the SVG script element, that is currently executing, as long as the element represents a classic script. In the case of reentrant script execution, returns the one that most recently started executing amongst those that have not yet finished executing. + * + * Returns null if the Document is not currently executing a script or SVG script element (e.g., because the running script is an event handler, or a timeout), or if the currently executing script or SVG script element represents a module script. + */ + readonly currentScript: HTMLOrSVGScriptElement | null; + readonly defaultView: (WindowProxy & typeof globalThis) | null; + /** + * Sets or gets a value that indicates whether the document can be edited. + */ + designMode: string; + /** + * Sets or retrieves a value that indicates the reading order of the object. + */ + dir: string; + /** + * Gets an object representing the document type declaration associated with the current document. + */ + readonly doctype: DocumentType | null; + /** + * Gets a reference to the root node of the document. + */ + readonly documentElement: HTMLElement; + /** + * Returns document's URL. + */ + readonly documentURI: string; + /** + * Sets or gets the security domain of the document. + */ + domain: string; + /** + * Retrieves a collection of all embed objects in the document. + */ + readonly embeds: HTMLCollectionOf; + /** + * Sets or gets the foreground (text) color of the document. + */ + /** @deprecated */ + fgColor: string; + /** + * Retrieves a collection, in source order, of all form objects in the document. + */ + readonly forms: HTMLCollectionOf; + /** @deprecated */ + readonly fullscreen: boolean; + /** + * Returns true if document has the ability to display elements fullscreen and fullscreen is supported, or false otherwise. + */ + readonly fullscreenEnabled: boolean; + /** + * Returns the head element. + */ + readonly head: HTMLHeadElement; + readonly hidden: boolean; + /** + * Retrieves a collection, in source order, of img objects in the document. + */ + readonly images: HTMLCollectionOf; + /** + * Gets the implementation object of the current document. + */ + readonly implementation: DOMImplementation; + /** + * Returns the character encoding used to create the webpage that is loaded into the document object. + */ + readonly inputEncoding: string; + /** + * Gets the date that the page was last modified, if the page supplies one. + */ + readonly lastModified: string; + /** + * Sets or gets the color of the document links. + */ + /** @deprecated */ + linkColor: string; + /** + * Retrieves a collection of all a objects that specify the href property and all area objects in the document. + */ + readonly links: HTMLCollectionOf; + /** + * Contains information about the current URL. + */ + location: Location; + onfullscreenchange: ((this: Document, ev: Event) => any) | null; + onfullscreenerror: ((this: Document, ev: Event) => any) | null; + onpointerlockchange: ((this: Document, ev: Event) => any) | null; + onpointerlockerror: ((this: Document, ev: Event) => any) | null; + /** + * Fires when the state of the object has changed. + * @param ev The event + */ + onreadystatechange: ((this: Document, ev: Event) => any) | null; + onvisibilitychange: ((this: Document, ev: Event) => any) | null; + readonly ownerDocument: null; + /** + * Return an HTMLCollection of the embed elements in the Document. + */ + readonly plugins: HTMLCollectionOf; + /** + * Retrieves a value that indicates the current state of the object. + */ + readonly readyState: DocumentReadyState; + /** + * Gets the URL of the location that referred the user to the current page. + */ + readonly referrer: string; + /** + * Retrieves a collection of all script objects in the document. + */ + readonly scripts: HTMLCollectionOf; + readonly scrollingElement: Element | null; + readonly timeline: DocumentTimeline; + /** + * Contains the title of the document. + */ + title: string; + readonly visibilityState: VisibilityState; + /** + * Sets or gets the color of the links that the user has visited. + */ + /** @deprecated */ + vlinkColor: string; + /** + * Moves node from another document and returns it. + * + * If node is a document, throws a "NotSupportedError" DOMException or, if node is a shadow root, throws a "HierarchyRequestError" DOMException. + */ + adoptNode(source: T): T; + /** @deprecated */ + captureEvents(): void; + caretPositionFromPoint(x: number, y: number): CaretPosition | null; + /** @deprecated */ + caretRangeFromPoint(x: number, y: number): Range; + /** @deprecated */ + clear(): void; + /** + * Closes an output stream and forces the sent data to display. + */ + close(): void; + /** + * Creates an attribute object with a specified name. + * @param name String that sets the attribute object's name. + */ + createAttribute(localName: string): Attr; + createAttributeNS(namespace: string | null, qualifiedName: string): Attr; + /** + * Returns a CDATASection node whose data is data. + */ + createCDATASection(data: string): CDATASection; + /** + * Creates a comment object with the specified data. + * @param data Sets the comment object's data. + */ + createComment(data: string): Comment; + /** + * Creates a new document. + */ + createDocumentFragment(): DocumentFragment; + /** + * Creates an instance of the element for the specified tag. + * @param tagName The name of an element. + */ + createElement( + tagName: K, + options?: ElementCreationOptions, + ): HTMLElementTagNameMap[K]; + /** @deprecated */ + createElement( + tagName: K, + options?: ElementCreationOptions, + ): HTMLElementDeprecatedTagNameMap[K]; + createElement( + tagName: string, + options?: ElementCreationOptions, + ): HTMLElement; + /** + * Returns an element with namespace namespace. Its namespace prefix will be everything before ":" (U+003E) in qualifiedName or null. Its local name will be everything after ":" (U+003E) in qualifiedName or qualifiedName. + * + * If localName does not match the Name production an "InvalidCharacterError" DOMException will be thrown. + * + * If one of the following conditions is true a "NamespaceError" DOMException will be thrown: + * + * localName does not match the QName production. + * Namespace prefix is not null and namespace is the empty string. + * Namespace prefix is "xml" and namespace is not the XML namespace. + * qualifiedName or namespace prefix is "xmlns" and namespace is not the XMLNS namespace. + * namespace is the XMLNS namespace and neither qualifiedName nor namespace prefix is "xmlns". + * + * When supplied, options's is can be used to create a customized built-in element. + */ + createElementNS( + namespaceURI: "http://www.w3.org/1999/xhtml", + qualifiedName: string, + ): HTMLElement; + createElementNS( + namespaceURI: "http://www.w3.org/2000/svg", + qualifiedName: K, + ): SVGElementTagNameMap[K]; + createElementNS( + namespaceURI: "http://www.w3.org/2000/svg", + qualifiedName: string, + ): SVGElement; + createElementNS( + namespaceURI: string | null, + qualifiedName: string, + options?: ElementCreationOptions, + ): Element; + createElementNS( + namespace: string | null, + qualifiedName: string, + options?: string | ElementCreationOptions, + ): Element; + createEvent(eventInterface: "AnimationEvent"): AnimationEvent; + createEvent( + eventInterface: "AnimationPlaybackEvent", + ): AnimationPlaybackEvent; + createEvent(eventInterface: "AudioProcessingEvent"): AudioProcessingEvent; + createEvent(eventInterface: "BeforeUnloadEvent"): BeforeUnloadEvent; + createEvent(eventInterface: "ClipboardEvent"): ClipboardEvent; + createEvent(eventInterface: "CloseEvent"): CloseEvent; + createEvent(eventInterface: "CompositionEvent"): CompositionEvent; + createEvent(eventInterface: "CustomEvent"): CustomEvent; + createEvent(eventInterface: "DeviceMotionEvent"): DeviceMotionEvent; + createEvent( + eventInterface: "DeviceOrientationEvent", + ): DeviceOrientationEvent; + createEvent(eventInterface: "DragEvent"): DragEvent; + createEvent(eventInterface: "ErrorEvent"): ErrorEvent; + createEvent(eventInterface: "Event"): Event; + createEvent(eventInterface: "Events"): Event; + createEvent(eventInterface: "FocusEvent"): FocusEvent; + createEvent(eventInterface: "FocusNavigationEvent"): FocusNavigationEvent; + createEvent(eventInterface: "GamepadEvent"): GamepadEvent; + createEvent(eventInterface: "HashChangeEvent"): HashChangeEvent; + createEvent(eventInterface: "IDBVersionChangeEvent"): IDBVersionChangeEvent; + createEvent(eventInterface: "InputEvent"): InputEvent; + createEvent(eventInterface: "KeyboardEvent"): KeyboardEvent; + createEvent( + eventInterface: "ListeningStateChangedEvent", + ): ListeningStateChangedEvent; + createEvent(eventInterface: "MediaEncryptedEvent"): MediaEncryptedEvent; + createEvent(eventInterface: "MediaKeyMessageEvent"): MediaKeyMessageEvent; + createEvent(eventInterface: "MediaQueryListEvent"): MediaQueryListEvent; + createEvent(eventInterface: "MediaStreamErrorEvent"): MediaStreamErrorEvent; + createEvent(eventInterface: "MediaStreamEvent"): MediaStreamEvent; + createEvent(eventInterface: "MediaStreamTrackEvent"): MediaStreamTrackEvent; + createEvent(eventInterface: "MessageEvent"): MessageEvent; + createEvent(eventInterface: "MouseEvent"): MouseEvent; + createEvent(eventInterface: "MouseEvents"): MouseEvent; + createEvent(eventInterface: "MutationEvent"): MutationEvent; + createEvent(eventInterface: "MutationEvents"): MutationEvent; + createEvent( + eventInterface: "OfflineAudioCompletionEvent", + ): OfflineAudioCompletionEvent; + createEvent(eventInterface: "OverflowEvent"): OverflowEvent; + createEvent(eventInterface: "PageTransitionEvent"): PageTransitionEvent; + createEvent( + eventInterface: "PaymentMethodChangeEvent", + ): PaymentMethodChangeEvent; + createEvent( + eventInterface: "PaymentRequestUpdateEvent", + ): PaymentRequestUpdateEvent; + createEvent( + eventInterface: "PermissionRequestedEvent", + ): PermissionRequestedEvent; + createEvent(eventInterface: "PointerEvent"): PointerEvent; + createEvent(eventInterface: "PopStateEvent"): PopStateEvent; + createEvent(eventInterface: "ProgressEvent"): ProgressEvent; + createEvent(eventInterface: "PromiseRejectionEvent"): PromiseRejectionEvent; + createEvent( + eventInterface: "RTCDTMFToneChangeEvent", + ): RTCDTMFToneChangeEvent; + createEvent(eventInterface: "RTCDataChannelEvent"): RTCDataChannelEvent; + createEvent( + eventInterface: "RTCDtlsTransportStateChangedEvent", + ): RTCDtlsTransportStateChangedEvent; + createEvent(eventInterface: "RTCErrorEvent"): RTCErrorEvent; + createEvent( + eventInterface: "RTCIceCandidatePairChangedEvent", + ): RTCIceCandidatePairChangedEvent; + createEvent(eventInterface: "RTCIceGathererEvent"): RTCIceGathererEvent; + createEvent( + eventInterface: "RTCIceTransportStateChangedEvent", + ): RTCIceTransportStateChangedEvent; + createEvent( + eventInterface: "RTCPeerConnectionIceErrorEvent", + ): RTCPeerConnectionIceErrorEvent; + createEvent( + eventInterface: "RTCPeerConnectionIceEvent", + ): RTCPeerConnectionIceEvent; + createEvent(eventInterface: "RTCSsrcConflictEvent"): RTCSsrcConflictEvent; + createEvent(eventInterface: "RTCTrackEvent"): RTCTrackEvent; + createEvent(eventInterface: "SVGZoomEvent"): SVGZoomEvent; + createEvent(eventInterface: "SVGZoomEvents"): SVGZoomEvent; + createEvent( + eventInterface: "SecurityPolicyViolationEvent", + ): SecurityPolicyViolationEvent; + createEvent( + eventInterface: "SpeechRecognitionErrorEvent", + ): SpeechRecognitionErrorEvent; + createEvent( + eventInterface: "SpeechRecognitionEvent", + ): SpeechRecognitionEvent; + createEvent( + eventInterface: "SpeechSynthesisErrorEvent", + ): SpeechSynthesisErrorEvent; + createEvent(eventInterface: "SpeechSynthesisEvent"): SpeechSynthesisEvent; + createEvent(eventInterface: "StorageEvent"): StorageEvent; + createEvent(eventInterface: "TextEvent"): TextEvent; + createEvent(eventInterface: "TouchEvent"): TouchEvent; + createEvent(eventInterface: "TrackEvent"): TrackEvent; + createEvent(eventInterface: "TransitionEvent"): TransitionEvent; + createEvent(eventInterface: "UIEvent"): UIEvent; + createEvent(eventInterface: "UIEvents"): UIEvent; + createEvent(eventInterface: "VRDisplayEvent"): VRDisplayEvent; + createEvent(eventInterface: "VRDisplayEvent "): VRDisplayEvent; + createEvent(eventInterface: "WebGLContextEvent"): WebGLContextEvent; + createEvent(eventInterface: "WheelEvent"): WheelEvent; + createEvent(eventInterface: string): Event; + /** + * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document. + * @param root The root element or node to start traversing on. + * @param whatToShow The type of nodes or elements to appear in the node list + * @param filter A custom NodeFilter function to use. For more information, see filter. Use null for no filter. + * @param entityReferenceExpansion A flag that specifies whether entity reference nodes are expanded. + */ + createNodeIterator( + root: Node, + whatToShow?: number, + filter?: NodeFilter | null, + ): NodeIterator; + /** + * Returns a ProcessingInstruction node whose target is target and data is data. If target does not match the Name production an "InvalidCharacterError" DOMException will be thrown. If data contains "?>" an "InvalidCharacterError" DOMException will be thrown. + */ + createProcessingInstruction( + target: string, + data: string, + ): ProcessingInstruction; + /** + * Returns an empty range object that has both of its boundary points positioned at the beginning of the document. + */ + createRange(): Range; + /** + * Creates a text string from the specified value. + * @param data String that specifies the nodeValue property of the text node. + */ + createTextNode(data: string): Text; + /** + * Creates a TreeWalker object that you can use to traverse filtered lists of nodes or elements in a document. + * @param root The root element or node to start traversing on. + * @param whatToShow The type of nodes or elements to appear in the node list. For more information, see whatToShow. + * @param filter A custom NodeFilter function to use. + * @param entityReferenceExpansion A flag that specifies whether entity reference nodes are expanded. + */ + createTreeWalker( + root: Node, + whatToShow?: number, + filter?: NodeFilter | null, + ): TreeWalker; + /** @deprecated */ + createTreeWalker( + root: Node, + whatToShow: number, + filter: NodeFilter | null, + entityReferenceExpansion?: boolean, + ): TreeWalker; + /** + * Returns the element for the specified x coordinate and the specified y coordinate. + * @param x The x-offset + * @param y The y-offset + */ + elementFromPoint(x: number, y: number): Element | null; + elementsFromPoint(x: number, y: number): Element[]; + /** + * Executes a command on the current document, current selection, or the given range. + * @param commandId String that specifies the command to execute. This command can be any of the command identifiers that can be executed in script. + * @param showUI Display the user interface, defaults to false. + * @param value Value to assign. + */ + execCommand(commandId: string, showUI?: boolean, value?: string): boolean; + /** + * Stops document's fullscreen element from being displayed fullscreen and resolves promise when done. + */ + exitFullscreen(): Promise; + exitPointerLock(): void; + getAnimations(): Animation[]; + /** + * Returns a reference to the first object with the specified value of the ID attribute. + * @param elementId String that specifies the ID value. + */ + getElementById(elementId: string): HTMLElement | null; + /** + * Returns a HTMLCollection of the elements in the object on which the method was invoked (a document or an element) that have all the classes given by classNames. The classNames argument is interpreted as a space-separated list of classes. + */ + getElementsByClassName(classNames: string): HTMLCollectionOf; + /** + * Gets a collection of objects based on the value of the NAME or ID attribute. + * @param elementName Gets a collection of objects based on the value of the NAME or ID attribute. + */ + getElementsByName(elementName: string): NodeListOf; + /** + * Retrieves a collection of objects based on the specified element name. + * @param name Specifies the name of an element. + */ + getElementsByTagName( + qualifiedName: K, + ): HTMLCollectionOf; + getElementsByTagName( + qualifiedName: K, + ): HTMLCollectionOf; + getElementsByTagName(qualifiedName: string): HTMLCollectionOf; + /** + * If namespace and localName are "*" returns a HTMLCollection of all descendant elements. + * + * If only namespace is "*" returns a HTMLCollection of all descendant elements whose local name is localName. + * + * If only localName is "*" returns a HTMLCollection of all descendant elements whose namespace is namespace. + * + * Otherwise, returns a HTMLCollection of all descendant elements whose namespace is namespace and local name is localName. + */ + getElementsByTagNameNS( + namespaceURI: "http://www.w3.org/1999/xhtml", + localName: string, + ): HTMLCollectionOf; + getElementsByTagNameNS( + namespaceURI: "http://www.w3.org/2000/svg", + localName: string, + ): HTMLCollectionOf; + getElementsByTagNameNS( + namespaceURI: string, + localName: string, + ): HTMLCollectionOf; + /** + * Returns an object representing the current selection of the document that is loaded into the object displaying a webpage. + */ + getSelection(): Selection | null; + /** + * Gets a value indicating whether the object currently has focus. + */ + hasFocus(): boolean; + /** + * Returns a copy of node. If deep is true, the copy also includes the node's descendants. + * + * If node is a document or a shadow root, throws a "NotSupportedError" DOMException. + */ + importNode(importedNode: T, deep: boolean): T; + /** + * Opens a new window and loads a document specified by a given URL. Also, opens a new window that uses the url parameter and the name parameter to collect the output of the write method and the writeln method. + * @param url Specifies a MIME type for the document. + * @param name Specifies the name of the window. This name is used as the value for the TARGET attribute on a form or an anchor element. + * @param features Contains a list of items separated by commas. Each item consists of an option and a value, separated by an equals sign (for example, "fullscreen=yes, toolbar=yes"). The following values are supported. + * @param replace Specifies whether the existing entry for the document is replaced in the history list. + */ + open( + url?: string, + name?: string, + features?: string, + replace?: boolean, + ): Document; + /** + * Returns a Boolean value that indicates whether a specified command can be successfully executed using execCommand, given the current state of the document. + * @param commandId Specifies a command identifier. + */ + queryCommandEnabled(commandId: string): boolean; + /** + * Returns a Boolean value that indicates whether the specified command is in the indeterminate state. + * @param commandId String that specifies a command identifier. + */ + queryCommandIndeterm(commandId: string): boolean; + /** + * Returns a Boolean value that indicates the current state of the command. + * @param commandId String that specifies a command identifier. + */ + queryCommandState(commandId: string): boolean; + /** + * Returns a Boolean value that indicates whether the current command is supported on the current range. + * @param commandId Specifies a command identifier. + */ + queryCommandSupported(commandId: string): boolean; + /** + * Returns the current value of the document, range, or current selection for the given command. + * @param commandId String that specifies a command identifier. + */ + queryCommandValue(commandId: string): string; + /** @deprecated */ + releaseEvents(): void; + /** + * Writes one or more HTML expressions to a document in the specified window. + * @param content Specifies the text and HTML tags to write. + */ + write(...text: string[]): void; + /** + * Writes one or more HTML expressions, followed by a carriage return, to a document in the specified window. + * @param content The text and HTML tags to write. + */ + writeln(...text: string[]): void; + addEventListener( + type: K, + listener: (this: Document, ev: DocumentEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: (this: Document, ev: DocumentEventMap[K]) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var Document: { + prototype: Document; + new (): Document; +}; + +export interface DocumentAndElementEventHandlersEventMap { + copy: ClipboardEvent; + cut: ClipboardEvent; + paste: ClipboardEvent; +} + +export interface DocumentAndElementEventHandlers { + oncopy: + | ((this: DocumentAndElementEventHandlers, ev: ClipboardEvent) => any) + | null; + oncut: + | ((this: DocumentAndElementEventHandlers, ev: ClipboardEvent) => any) + | null; + onpaste: + | ((this: DocumentAndElementEventHandlers, ev: ClipboardEvent) => any) + | null; + addEventListener( + type: K, + listener: ( + this: DocumentAndElementEventHandlers, + ev: DocumentAndElementEventHandlersEventMap[K], + ) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener< + K extends keyof DocumentAndElementEventHandlersEventMap, + >( + type: K, + listener: ( + this: DocumentAndElementEventHandlers, + ev: DocumentAndElementEventHandlersEventMap[K], + ) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +export interface DocumentEvent { + createEvent(eventInterface: "AnimationEvent"): AnimationEvent; + createEvent( + eventInterface: "AnimationPlaybackEvent", + ): AnimationPlaybackEvent; + createEvent(eventInterface: "AudioProcessingEvent"): AudioProcessingEvent; + createEvent(eventInterface: "BeforeUnloadEvent"): BeforeUnloadEvent; + createEvent(eventInterface: "ClipboardEvent"): ClipboardEvent; + createEvent(eventInterface: "CloseEvent"): CloseEvent; + createEvent(eventInterface: "CompositionEvent"): CompositionEvent; + createEvent(eventInterface: "CustomEvent"): CustomEvent; + createEvent(eventInterface: "DeviceMotionEvent"): DeviceMotionEvent; + createEvent( + eventInterface: "DeviceOrientationEvent", + ): DeviceOrientationEvent; + createEvent(eventInterface: "DragEvent"): DragEvent; + createEvent(eventInterface: "ErrorEvent"): ErrorEvent; + createEvent(eventInterface: "Event"): Event; + createEvent(eventInterface: "Events"): Event; + createEvent(eventInterface: "FocusEvent"): FocusEvent; + createEvent(eventInterface: "FocusNavigationEvent"): FocusNavigationEvent; + createEvent(eventInterface: "GamepadEvent"): GamepadEvent; + createEvent(eventInterface: "HashChangeEvent"): HashChangeEvent; + createEvent(eventInterface: "IDBVersionChangeEvent"): IDBVersionChangeEvent; + createEvent(eventInterface: "InputEvent"): InputEvent; + createEvent(eventInterface: "KeyboardEvent"): KeyboardEvent; + createEvent( + eventInterface: "ListeningStateChangedEvent", + ): ListeningStateChangedEvent; + createEvent(eventInterface: "MediaEncryptedEvent"): MediaEncryptedEvent; + createEvent(eventInterface: "MediaKeyMessageEvent"): MediaKeyMessageEvent; + createEvent(eventInterface: "MediaQueryListEvent"): MediaQueryListEvent; + createEvent(eventInterface: "MediaStreamErrorEvent"): MediaStreamErrorEvent; + createEvent(eventInterface: "MediaStreamEvent"): MediaStreamEvent; + createEvent(eventInterface: "MediaStreamTrackEvent"): MediaStreamTrackEvent; + createEvent(eventInterface: "MessageEvent"): MessageEvent; + createEvent(eventInterface: "MouseEvent"): MouseEvent; + createEvent(eventInterface: "MouseEvents"): MouseEvent; + createEvent(eventInterface: "MutationEvent"): MutationEvent; + createEvent(eventInterface: "MutationEvents"): MutationEvent; + createEvent( + eventInterface: "OfflineAudioCompletionEvent", + ): OfflineAudioCompletionEvent; + createEvent(eventInterface: "OverflowEvent"): OverflowEvent; + createEvent(eventInterface: "PageTransitionEvent"): PageTransitionEvent; + createEvent( + eventInterface: "PaymentMethodChangeEvent", + ): PaymentMethodChangeEvent; + createEvent( + eventInterface: "PaymentRequestUpdateEvent", + ): PaymentRequestUpdateEvent; + createEvent( + eventInterface: "PermissionRequestedEvent", + ): PermissionRequestedEvent; + createEvent(eventInterface: "PointerEvent"): PointerEvent; + createEvent(eventInterface: "PopStateEvent"): PopStateEvent; + createEvent(eventInterface: "ProgressEvent"): ProgressEvent; + createEvent(eventInterface: "PromiseRejectionEvent"): PromiseRejectionEvent; + createEvent( + eventInterface: "RTCDTMFToneChangeEvent", + ): RTCDTMFToneChangeEvent; + createEvent(eventInterface: "RTCDataChannelEvent"): RTCDataChannelEvent; + createEvent( + eventInterface: "RTCDtlsTransportStateChangedEvent", + ): RTCDtlsTransportStateChangedEvent; + createEvent(eventInterface: "RTCErrorEvent"): RTCErrorEvent; + createEvent( + eventInterface: "RTCIceCandidatePairChangedEvent", + ): RTCIceCandidatePairChangedEvent; + createEvent(eventInterface: "RTCIceGathererEvent"): RTCIceGathererEvent; + createEvent( + eventInterface: "RTCIceTransportStateChangedEvent", + ): RTCIceTransportStateChangedEvent; + createEvent( + eventInterface: "RTCPeerConnectionIceErrorEvent", + ): RTCPeerConnectionIceErrorEvent; + createEvent( + eventInterface: "RTCPeerConnectionIceEvent", + ): RTCPeerConnectionIceEvent; + createEvent(eventInterface: "RTCSsrcConflictEvent"): RTCSsrcConflictEvent; + createEvent(eventInterface: "RTCTrackEvent"): RTCTrackEvent; + createEvent(eventInterface: "SVGZoomEvent"): SVGZoomEvent; + createEvent(eventInterface: "SVGZoomEvents"): SVGZoomEvent; + createEvent( + eventInterface: "SecurityPolicyViolationEvent", + ): SecurityPolicyViolationEvent; + createEvent( + eventInterface: "SpeechRecognitionErrorEvent", + ): SpeechRecognitionErrorEvent; + createEvent( + eventInterface: "SpeechRecognitionEvent", + ): SpeechRecognitionEvent; + createEvent( + eventInterface: "SpeechSynthesisErrorEvent", + ): SpeechSynthesisErrorEvent; + createEvent(eventInterface: "SpeechSynthesisEvent"): SpeechSynthesisEvent; + createEvent(eventInterface: "StorageEvent"): StorageEvent; + createEvent(eventInterface: "TextEvent"): TextEvent; + createEvent(eventInterface: "TouchEvent"): TouchEvent; + createEvent(eventInterface: "TrackEvent"): TrackEvent; + createEvent(eventInterface: "TransitionEvent"): TransitionEvent; + createEvent(eventInterface: "UIEvent"): UIEvent; + createEvent(eventInterface: "UIEvents"): UIEvent; + createEvent(eventInterface: "VRDisplayEvent"): VRDisplayEvent; + createEvent(eventInterface: "VRDisplayEvent "): VRDisplayEvent; + createEvent(eventInterface: "WebGLContextEvent"): WebGLContextEvent; + createEvent(eventInterface: "WheelEvent"): WheelEvent; + createEvent(eventInterface: string): Event; +} + +/** A minimal document object that has no parent. It is used as a lightweight version of Document that stores a segment of a document structure comprised of nodes just like a standard document. The key difference is that because the document fragment isn't part of the active document tree structure, changes made to the fragment don't affect the document, cause reflow, or incur any performance impact that can occur when changes are made. */ +export interface DocumentFragment + extends Node, + NonElementParentNode, + ParentNode { + readonly ownerDocument: Document; + getElementById(elementId: string): HTMLElement | null; +} + +declare var DocumentFragment: { + prototype: DocumentFragment; + new (): DocumentFragment; +}; + +export interface DocumentOrShadowRoot { + readonly activeElement: Element | null; + /** + * Returns document's fullscreen element. + */ + readonly fullscreenElement: Element | null; + readonly pointerLockElement: Element | null; + /** + * Retrieves a collection of styleSheet objects representing the style sheets that correspond to each instance of a link or style object in the document. + */ + readonly styleSheets: StyleSheetList; + caretPositionFromPoint(x: number, y: number): CaretPosition | null; + /** @deprecated */ + caretRangeFromPoint(x: number, y: number): Range; + elementFromPoint(x: number, y: number): Element | null; + elementsFromPoint(x: number, y: number): Element[]; + getSelection(): Selection | null; +} + +export interface DocumentTimeline extends AnimationTimeline {} + +declare var DocumentTimeline: { + prototype: DocumentTimeline; + new (options?: DocumentTimelineOptions): DocumentTimeline; +}; + +/** A Node containing a doctype. */ +export interface DocumentType extends Node, ChildNode { + readonly name: string; + readonly ownerDocument: Document; + readonly publicId: string; + readonly systemId: string; +} + +declare var DocumentType: { + prototype: DocumentType; + new (): DocumentType; +}; + +/** A DOM event that represents a drag and drop interaction. The user initiates a drag by placing a pointer device (such as a mouse) on the touch surface and then dragging the pointer to a new location (such as another DOM element). Applications are free to interpret a drag and drop interaction in an application-specific way. */ +export interface DragEvent extends MouseEvent { + /** + * Returns the DataTransfer object for the event. + */ + readonly dataTransfer: DataTransfer | null; +} + +declare var DragEvent: { + prototype: DragEvent; + new (type: string, eventInitDict?: DragEventInit): DragEvent; +}; + +/** Inherits properties from its parent, AudioNode. */ +export interface DynamicsCompressorNode extends AudioNode { + readonly attack: AudioParam; + readonly knee: AudioParam; + readonly ratio: AudioParam; + readonly reduction: number; + readonly release: AudioParam; + readonly threshold: AudioParam; +} + +declare var DynamicsCompressorNode: { + prototype: DynamicsCompressorNode; + new ( + context: BaseAudioContext, + options?: DynamicsCompressorOptions, + ): DynamicsCompressorNode; +}; + +export interface EXT_blend_minmax { + readonly MAX_EXT: GLenum; + readonly MIN_EXT: GLenum; +} + +/** The EXT_frag_depth extension is part of the WebGL API and enables to set a depth value of a fragment from within the fragment shader. */ +export interface EXT_frag_depth {} + +export interface EXT_sRGB { + readonly FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT: GLenum; + readonly SRGB8_ALPHA8_EXT: GLenum; + readonly SRGB_ALPHA_EXT: GLenum; + readonly SRGB_EXT: GLenum; +} + +export interface EXT_shader_texture_lod {} + +/** The EXT_texture_filter_anisotropic extension is part of the WebGL API and exposes two constants for anisotropic filtering (AF). */ +export interface EXT_texture_filter_anisotropic { + readonly MAX_TEXTURE_MAX_ANISOTROPY_EXT: GLenum; + readonly TEXTURE_MAX_ANISOTROPY_EXT: GLenum; +} + +export interface ElementEventMap { + fullscreenchange: Event; + fullscreenerror: Event; +} + +/** Element is the most general base class from which all objects in a Document inherit. It only has methods and properties common to all kinds of elements. More specific classes inherit from Element. */ +export interface Element + extends Node, + Animatable, + ChildNode, + InnerHTML, + NonDocumentTypeChildNode, + ParentNode, + Slottable { + readonly attributes: NamedNodeMap; + /** + * Allows for manipulation of element's class content attribute as a set of whitespace-separated tokens through a DOMTokenList object. + */ + readonly classList: DOMTokenList; + /** + * Returns the value of element's class content attribute. Can be set to change it. + */ + className: string; + readonly clientHeight: number; + readonly clientLeft: number; + readonly clientTop: number; + readonly clientWidth: number; + /** + * Returns the value of element's id content attribute. Can be set to change it. + */ + id: string; + /** + * Returns the local name. + */ + readonly localName: string; + /** + * Returns the namespace. + */ + readonly namespaceURI: string | null; + onfullscreenchange: ((this: Element, ev: Event) => any) | null; + onfullscreenerror: ((this: Element, ev: Event) => any) | null; + outerHTML: string; + readonly ownerDocument: Document; + /** + * Returns the namespace prefix. + */ + readonly prefix: string | null; + readonly scrollHeight: number; + scrollLeft: number; + scrollTop: number; + readonly scrollWidth: number; + /** + * Returns element's shadow root, if any, and if shadow root's mode is "open", and null otherwise. + */ + readonly shadowRoot: ShadowRoot | null; + /** + * Returns the value of element's slot content attribute. Can be set to change it. + */ + slot: string; + /** + * Returns the HTML-uppercased qualified name. + */ + readonly tagName: string; + /** + * Creates a shadow root for element and returns it. + */ + attachShadow(init: ShadowRootInit): ShadowRoot; + /** + * Returns the first (starting at element) inclusive ancestor that matches selectors, and null otherwise. + */ + closest( + selector: K, + ): HTMLElementTagNameMap[K] | null; + closest( + selector: K, + ): SVGElementTagNameMap[K] | null; + closest(selector: string): E | null; + /** + * Returns element's first attribute whose qualified name is qualifiedName, and null if there is no such attribute otherwise. + */ + getAttribute(qualifiedName: string): string | null; + /** + * Returns element's attribute whose namespace is namespace and local name is localName, and null if there is no such attribute otherwise. + */ + getAttributeNS(namespace: string | null, localName: string): string | null; + /** + * Returns the qualified names of all element's attributes. Can contain duplicates. + */ + getAttributeNames(): string[]; + getAttributeNode(qualifiedName: string): Attr | null; + getAttributeNodeNS( + namespace: string | null, + localName: string, + ): Attr | null; + getBoundingClientRect(): DOMRect; + getClientRects(): DOMRectList; + /** + * Returns a HTMLCollection of the elements in the object on which the method was invoked (a document or an element) that have all the classes given by classNames. The classNames argument is interpreted as a space-separated list of classes. + */ + getElementsByClassName(classNames: string): HTMLCollectionOf; + getElementsByTagName( + qualifiedName: K, + ): HTMLCollectionOf; + getElementsByTagName( + qualifiedName: K, + ): HTMLCollectionOf; + getElementsByTagName(qualifiedName: string): HTMLCollectionOf; + getElementsByTagNameNS( + namespaceURI: "http://www.w3.org/1999/xhtml", + localName: string, + ): HTMLCollectionOf; + getElementsByTagNameNS( + namespaceURI: "http://www.w3.org/2000/svg", + localName: string, + ): HTMLCollectionOf; + getElementsByTagNameNS( + namespaceURI: string, + localName: string, + ): HTMLCollectionOf; + /** + * Returns true if element has an attribute whose qualified name is qualifiedName, and false otherwise. + */ + hasAttribute(qualifiedName: string): boolean; + /** + * Returns true if element has an attribute whose namespace is namespace and local name is localName. + */ + hasAttributeNS(namespace: string | null, localName: string): boolean; + /** + * Returns true if element has attributes, and false otherwise. + */ + hasAttributes(): boolean; + hasPointerCapture(pointerId: number): boolean; + insertAdjacentElement( + position: InsertPosition, + insertedElement: Element, + ): Element | null; + insertAdjacentHTML(where: InsertPosition, html: string): void; + insertAdjacentText(where: InsertPosition, text: string): void; + /** + * Returns true if matching selectors against element's root yields element, and false otherwise. + */ + matches(selectors: string): boolean; + msGetRegionContent(): any; + releasePointerCapture(pointerId: number): void; + /** + * Removes element's first attribute whose qualified name is qualifiedName. + */ + removeAttribute(qualifiedName: string): void; + /** + * Removes element's attribute whose namespace is namespace and local name is localName. + */ + removeAttributeNS(namespace: string | null, localName: string): void; + removeAttributeNode(attr: Attr): Attr; + /** + * Displays element fullscreen and resolves promise when done. + * + * When supplied, options's navigationUI member indicates whether showing navigation UI while in fullscreen is preferred or not. If set to "show", navigation simplicity is preferred over screen space, and if set to "hide", more screen space is preferred. User agents are always free to honor user preference over the application's. The default value "auto" indicates no application preference. + */ + requestFullscreen(options?: FullscreenOptions): Promise; + requestPointerLock(): void; + scroll(options?: ScrollToOptions): void; + scroll(x: number, y: number): void; + scrollBy(options?: ScrollToOptions): void; + scrollBy(x: number, y: number): void; + scrollIntoView(arg?: boolean | ScrollIntoViewOptions): void; + scrollTo(options?: ScrollToOptions): void; + scrollTo(x: number, y: number): void; + /** + * Sets the value of element's first attribute whose qualified name is qualifiedName to value. + */ + setAttribute(qualifiedName: string, value: string): void; + /** + * Sets the value of element's attribute whose namespace is namespace and local name is localName to value. + */ + setAttributeNS( + namespace: string | null, + qualifiedName: string, + value: string, + ): void; + setAttributeNode(attr: Attr): Attr | null; + setAttributeNodeNS(attr: Attr): Attr | null; + setPointerCapture(pointerId: number): void; + /** + * If force is not given, "toggles" qualifiedName, removing it if it is present and adding it if it is not present. If force is true, adds qualifiedName. If force is false, removes qualifiedName. + * + * Returns true if qualifiedName is now present, and false otherwise. + */ + toggleAttribute(qualifiedName: string, force?: boolean): boolean; + webkitMatchesSelector(selectors: string): boolean; + addEventListener( + type: K, + listener: (this: Element, ev: ElementEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: (this: Element, ev: ElementEventMap[K]) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var Element: { + prototype: Element; + new (): Element; +}; + +export interface ElementCSSInlineStyle { + readonly style: CSSStyleDeclaration; +} + +export interface ElementContentEditable { + contentEditable: string; + enterKeyHint: string; + inputMode: string; + readonly isContentEditable: boolean; +} + +/** Events providing information related to errors in scripts or in files. */ +export interface ErrorEvent extends Event { + readonly colno: number; + readonly error: any; + readonly filename: string; + readonly lineno: number; + readonly message: string; +} + +declare var ErrorEvent: { + prototype: ErrorEvent; + new (type: string, eventInitDict?: ErrorEventInit): ErrorEvent; +}; + +/** An event which takes place in the DOM. */ +export interface Event { + /** + * Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise. + */ + readonly bubbles: boolean; + cancelBubble: boolean; + /** + * Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method. + */ + readonly cancelable: boolean; + /** + * Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise. + */ + readonly composed: boolean; + /** + * Returns the object whose event listener's callback is currently being invoked. + */ + readonly currentTarget: EventTarget | null; + /** + * Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise. + */ + readonly defaultPrevented: boolean; + /** + * Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE. + */ + readonly eventPhase: number; + /** + * Returns true if event was dispatched by the user agent, and false otherwise. + */ + readonly isTrusted: boolean; + returnValue: boolean; + /** @deprecated */ + readonly srcElement: EventTarget | null; + /** + * Returns the object to which event is dispatched (its target). + */ + readonly target: EventTarget | null; + /** + * Returns the event's timestamp as the number of milliseconds measured relative to the time origin. + */ + readonly timeStamp: number; + /** + * Returns the type of event, e.g. "click", "hashchange", or "submit". + */ + readonly type: string; + /** + * Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is "closed" that are not reachable from event's currentTarget. + */ + composedPath(): EventTarget[]; + initEvent(type: string, bubbles?: boolean, cancelable?: boolean): void; + /** + * If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled. + */ + preventDefault(): void; + /** + * Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects. + */ + stopImmediatePropagation(): void; + /** + * When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object. + */ + stopPropagation(): void; + readonly AT_TARGET: number; + readonly BUBBLING_PHASE: number; + readonly CAPTURING_PHASE: number; + readonly NONE: number; +} + +declare var Event: { + prototype: Event; + new (type: string, eventInitDict?: EventInit): Event; + readonly AT_TARGET: number; + readonly BUBBLING_PHASE: number; + readonly CAPTURING_PHASE: number; + readonly NONE: number; +}; + +export interface EventListenerObject { + handleEvent(evt: Event): void; +} + +export interface EventSourceEventMap { + error: Event; + message: MessageEvent; + open: Event; +} + +export interface EventSource extends EventTarget { + onerror: ((this: EventSource, ev: Event) => any) | null; + onmessage: ((this: EventSource, ev: MessageEvent) => any) | null; + onopen: ((this: EventSource, ev: Event) => any) | null; + /** + * Returns the state of this EventSource object's connection. It can have the values described below. + */ + readonly readyState: number; + /** + * Returns the URL providing the event stream. + */ + readonly url: string; + /** + * Returns true if the credentials mode for connection requests to the URL providing the event stream is set to "include", and false otherwise. + */ + readonly withCredentials: boolean; + /** + * Aborts any instances of the fetch algorithm started for this EventSource object, and sets the readyState attribute to CLOSED. + */ + close(): void; + readonly CLOSED: number; + readonly CONNECTING: number; + readonly OPEN: number; + addEventListener( + type: K, + listener: (this: EventSource, ev: EventSourceEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: (this: EventSource, ev: EventSourceEventMap[K]) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var EventSource: { + prototype: EventSource; + new (url: string, eventSourceInitDict?: EventSourceInit): EventSource; + readonly CLOSED: number; + readonly CONNECTING: number; + readonly OPEN: number; +}; + +/** EventTarget is a DOM interface implemented by objects that can receive events and may have listeners for them. */ +export interface EventTarget { + /** + * Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched. + * + * The options argument sets listener-specific options. For compatibility this can be a boolean, in which case the method behaves exactly as if the value was specified as options's capture. + * + * When set to true, options's capture prevents callback from being invoked when the event's eventPhase attribute value is BUBBLING_PHASE. When false (or not present), callback will not be invoked when event's eventPhase attribute value is CAPTURING_PHASE. Either way, callback will be invoked if event's eventPhase attribute value is AT_TARGET. + * + * When set to true, options's passive indicates that the callback will not cancel the event by invoking preventDefault(). This is used to enable performance optimizations described in § 2.8 Observing event listeners. + * + * When set to true, options's once indicates that the callback will only be invoked once after which the event listener will be removed. + * + * The event listener is appended to target's event listener list and is not appended if it has the same type, callback, and capture. + */ + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject | null, + options?: boolean | AddEventListenerOptions, + ): void; + /** + * Dispatches a synthetic event event to target and returns true if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise. + */ + dispatchEvent(event: Event): boolean; + /** + * Removes the event listener in target's event listener list with the same type, callback, and options. + */ + removeEventListener( + type: string, + callback: EventListenerOrEventListenerObject | null, + options?: EventListenerOptions | boolean, + ): void; +} + +declare var EventTarget: { + prototype: EventTarget; + new (): EventTarget; +}; + +export interface ExtensionScriptApis { + extensionIdToShortId(extensionId: string): number; + fireExtensionApiTelemetry( + functionName: string, + isSucceeded: boolean, + isSupported: boolean, + errorString: string, + ): void; + genericFunction( + routerAddress: any, + parameters?: string, + callbackId?: number, + ): void; + genericSynchronousFunction(functionId: number, parameters?: string): string; + genericWebRuntimeCallout(to: any, from: any, payload: string): void; + getExtensionId(): string; + registerGenericFunctionCallbackHandler(callbackHandler: Function): void; + registerGenericPersistentCallbackHandler(callbackHandler: Function): void; + registerWebRuntimeCallbackHandler(handler: Function): any; +} + +declare var ExtensionScriptApis: { + prototype: ExtensionScriptApis; + new (): ExtensionScriptApis; +}; + +export interface External { + /** @deprecated */ + AddSearchProvider(): void; + /** @deprecated */ + IsSearchProviderInstalled(): void; +} + +declare var External: { + prototype: External; + new (): External; +}; + +/** Provides information about files and allows JavaScript in a web page to access their content. */ +export interface File extends Blob { + readonly lastModified: number; + readonly name: string; +} + +declare var File: { + prototype: File; + new ( + fileBits: BlobPart[], + fileName: string, + options?: FilePropertyBag, + ): File; +}; + +/** An object of this type is returned by the files property of the HTML element; this lets you access the list of files selected with the element. It's also used for a list of files dropped into web content when using the drag and drop API; see the DataTransfer object for details on this usage. */ +export interface FileList { + readonly length: number; + item(index: number): File | null; + [index: number]: File; +} + +declare var FileList: { + prototype: FileList; + new (): FileList; +}; + +export interface FileReaderEventMap { + abort: ProgressEvent; + error: ProgressEvent; + load: ProgressEvent; + loadend: ProgressEvent; + loadstart: ProgressEvent; + progress: ProgressEvent; +} + +/** Lets web applications asynchronously read the contents of files (or raw data buffers) stored on the user's computer, using File or Blob objects to specify the file or data to read. */ +export interface FileReader extends EventTarget { + readonly error: DOMException | null; + onabort: ((this: FileReader, ev: ProgressEvent) => any) | null; + onerror: ((this: FileReader, ev: ProgressEvent) => any) | null; + onload: ((this: FileReader, ev: ProgressEvent) => any) | null; + onloadend: + | ((this: FileReader, ev: ProgressEvent) => any) + | null; + onloadstart: + | ((this: FileReader, ev: ProgressEvent) => any) + | null; + onprogress: + | ((this: FileReader, ev: ProgressEvent) => any) + | null; + readonly readyState: number; + readonly result: string | ArrayBuffer | null; + abort(): void; + readAsArrayBuffer(blob: Blob): void; + readAsBinaryString(blob: Blob): void; + readAsDataURL(blob: Blob): void; + readAsText(blob: Blob, encoding?: string): void; + readonly DONE: number; + readonly EMPTY: number; + readonly LOADING: number; + addEventListener( + type: K, + listener: (this: FileReader, ev: FileReaderEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: (this: FileReader, ev: FileReaderEventMap[K]) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var FileReader: { + prototype: FileReader; + new (): FileReader; + readonly DONE: number; + readonly EMPTY: number; + readonly LOADING: number; +}; + +/** Focus-related events like focus, blur, focusin, or focusout. */ +export interface FocusEvent extends UIEvent { + readonly relatedTarget: EventTarget | null; +} + +declare var FocusEvent: { + prototype: FocusEvent; + new (type: string, eventInitDict?: FocusEventInit): FocusEvent; +}; + +export interface FocusNavigationEvent extends Event { + readonly navigationReason: NavigationReason; + readonly originHeight: number; + readonly originLeft: number; + readonly originTop: number; + readonly originWidth: number; + requestFocus(): void; +} + +declare var FocusNavigationEvent: { + prototype: FocusNavigationEvent; + new ( + type: string, + eventInitDict?: FocusNavigationEventInit, + ): FocusNavigationEvent; +}; + +/** Provides a way to easily construct a set of key/value pairs representing form fields and their values, which can then be easily sent using the XMLHttpRequest.send() method. It uses the same format a form would use if the encoding type were set to "multipart/form-data". */ +export interface FormData { + append(name: string, value: string | Blob, fileName?: string): void; + delete(name: string): void; + get(name: string): FormDataEntryValue | null; + getAll(name: string): FormDataEntryValue[]; + has(name: string): boolean; + set(name: string, value: string | Blob, fileName?: string): void; + forEach( + callbackfn: ( + value: FormDataEntryValue, + key: string, + parent: FormData, + ) => void, + thisArg?: any, + ): void; +} + +declare var FormData: { + prototype: FormData; + new (form?: HTMLFormElement): FormData; +}; + +/** A change in volume. It is an AudioNode audio-processing module that causes a given gain to be applied to the input data before its propagation to the output. A GainNode always has exactly one input and one output, both with the same number of channels. */ +export interface GainNode extends AudioNode { + readonly gain: AudioParam; +} + +declare var GainNode: { + prototype: GainNode; + new (context: BaseAudioContext, options?: GainOptions): GainNode; +}; + +/** This Gamepad API interface defines an individual gamepad or other controller, allowing access to information such as button presses, axis positions, and id. */ +export interface Gamepad { + readonly axes: ReadonlyArray; + readonly buttons: ReadonlyArray; + readonly connected: boolean; + readonly hand: GamepadHand; + readonly hapticActuators: ReadonlyArray; + readonly id: string; + readonly index: number; + readonly mapping: GamepadMappingType; + readonly pose: GamepadPose | null; + readonly timestamp: number; +} + +declare var Gamepad: { + prototype: Gamepad; + new (): Gamepad; +}; + +/** An individual button of a gamepad or other controller, allowing access to the current state of different types of buttons available on the control device. */ +export interface GamepadButton { + readonly pressed: boolean; + readonly touched: boolean; + readonly value: number; +} + +declare var GamepadButton: { + prototype: GamepadButton; + new (): GamepadButton; +}; + +/** This Gamepad API interface contains references to gamepads connected to the system, which is what the gamepad events Window.gamepadconnected and Window.gamepaddisconnected are fired in response to. */ +export interface GamepadEvent extends Event { + readonly gamepad: Gamepad; +} + +declare var GamepadEvent: { + prototype: GamepadEvent; + new (type: string, eventInitDict: GamepadEventInit): GamepadEvent; +}; + +/** This Gamepad API interface represents hardware in the controller designed to provide haptic feedback to the user (if available), most commonly vibration hardware. */ +export interface GamepadHapticActuator { + readonly type: GamepadHapticActuatorType; + pulse(value: number, duration: number): Promise; +} + +declare var GamepadHapticActuator: { + prototype: GamepadHapticActuator; + new (): GamepadHapticActuator; +}; + +/** This Gamepad API interface represents the pose of a WebVR controller at a given timestamp (which includes orientation, position, velocity, and acceleration information.) */ +export interface GamepadPose { + readonly angularAcceleration: Float32Array | null; + readonly angularVelocity: Float32Array | null; + readonly hasOrientation: boolean; + readonly hasPosition: boolean; + readonly linearAcceleration: Float32Array | null; + readonly linearVelocity: Float32Array | null; + readonly orientation: Float32Array | null; + readonly position: Float32Array | null; +} + +declare var GamepadPose: { + prototype: GamepadPose; + new (): GamepadPose; +}; + +export interface GenericTransformStream { + readonly readable: ReadableStream; + readonly writable: WritableStream; +} + +/** An object able to programmatically obtain the position of the device. It gives Web content access to the location of the device. This allows a Web site or app to offer customized results based on the user's location. */ +export interface Geolocation { + clearWatch(watchId: number): void; + getCurrentPosition( + successCallback: PositionCallback, + errorCallback?: PositionErrorCallback, + options?: PositionOptions, + ): void; + watchPosition( + successCallback: PositionCallback, + errorCallback?: PositionErrorCallback, + options?: PositionOptions, + ): number; +} + +declare var Geolocation: { + prototype: Geolocation; + new (): Geolocation; +}; + +export interface GeolocationCoordinates { + readonly accuracy: number; + readonly altitude: number | null; + readonly altitudeAccuracy: number | null; + readonly heading: number | null; + readonly latitude: number; + readonly longitude: number; + readonly speed: number | null; +} + +declare var GeolocationCoordinates: { + prototype: GeolocationCoordinates; + new (): GeolocationCoordinates; +}; + +export interface GeolocationPosition { + readonly coords: GeolocationCoordinates; + readonly timestamp: number; +} + +declare var GeolocationPosition: { + prototype: GeolocationPosition; + new (): GeolocationPosition; +}; + +export interface GeolocationPositionError { + readonly code: number; + readonly message: string; + readonly PERMISSION_DENIED: number; + readonly POSITION_UNAVAILABLE: number; + readonly TIMEOUT: number; +} + +declare var GeolocationPositionError: { + prototype: GeolocationPositionError; + new (): GeolocationPositionError; + readonly PERMISSION_DENIED: number; + readonly POSITION_UNAVAILABLE: number; + readonly TIMEOUT: number; +}; + +export interface GlobalEventHandlersEventMap { + abort: UIEvent; + animationcancel: AnimationEvent; + animationend: AnimationEvent; + animationiteration: AnimationEvent; + animationstart: AnimationEvent; + auxclick: MouseEvent; + beforeinput: InputEvent; + blur: FocusEvent; + cancel: Event; + canplay: Event; + canplaythrough: Event; + change: Event; + click: MouseEvent; + close: Event; + compositionend: CompositionEvent; + compositionstart: CompositionEvent; + compositionupdate: CompositionEvent; + contextmenu: MouseEvent; + cuechange: Event; + dblclick: MouseEvent; + drag: DragEvent; + dragend: DragEvent; + dragenter: DragEvent; + dragexit: Event; + dragleave: DragEvent; + dragover: DragEvent; + dragstart: DragEvent; + drop: DragEvent; + durationchange: Event; + emptied: Event; + ended: Event; + error: ErrorEvent; + focus: FocusEvent; + focusin: FocusEvent; + focusout: FocusEvent; + gotpointercapture: PointerEvent; + input: Event; + invalid: Event; + keydown: KeyboardEvent; + keypress: KeyboardEvent; + keyup: KeyboardEvent; + load: Event; + loadeddata: Event; + loadedmetadata: Event; + loadstart: Event; + lostpointercapture: PointerEvent; + mousedown: MouseEvent; + mouseenter: MouseEvent; + mouseleave: MouseEvent; + mousemove: MouseEvent; + mouseout: MouseEvent; + mouseover: MouseEvent; + mouseup: MouseEvent; + pause: Event; + play: Event; + playing: Event; + pointercancel: PointerEvent; + pointerdown: PointerEvent; + pointerenter: PointerEvent; + pointerleave: PointerEvent; + pointermove: PointerEvent; + pointerout: PointerEvent; + pointerover: PointerEvent; + pointerup: PointerEvent; + progress: ProgressEvent; + ratechange: Event; + reset: Event; + resize: UIEvent; + scroll: Event; + securitypolicyviolation: SecurityPolicyViolationEvent; + seeked: Event; + seeking: Event; + select: Event; + selectionchange: Event; + selectstart: Event; + stalled: Event; + submit: Event; + suspend: Event; + timeupdate: Event; + toggle: Event; + touchcancel: TouchEvent; + touchend: TouchEvent; + touchmove: TouchEvent; + touchstart: TouchEvent; + transitioncancel: TransitionEvent; + transitionend: TransitionEvent; + transitionrun: TransitionEvent; + transitionstart: TransitionEvent; + volumechange: Event; + waiting: Event; + wheel: WheelEvent; +} + +export interface GlobalEventHandlers { + /** + * Fires when the user aborts the download. + * @param ev The event. + */ + onabort: ((this: GlobalEventHandlers, ev: UIEvent) => any) | null; + onanimationcancel: + | ((this: GlobalEventHandlers, ev: AnimationEvent) => any) + | null; + onanimationend: + | ((this: GlobalEventHandlers, ev: AnimationEvent) => any) + | null; + onanimationiteration: + | ((this: GlobalEventHandlers, ev: AnimationEvent) => any) + | null; + onanimationstart: + | ((this: GlobalEventHandlers, ev: AnimationEvent) => any) + | null; + onauxclick: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; + /** + * Fires when the object loses the input focus. + * @param ev The focus event. + */ + onblur: ((this: GlobalEventHandlers, ev: FocusEvent) => any) | null; + oncancel: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Occurs when playback is possible, but would require further buffering. + * @param ev The event. + */ + oncanplay: ((this: GlobalEventHandlers, ev: Event) => any) | null; + oncanplaythrough: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Fires when the contents of the object or selection have changed. + * @param ev The event. + */ + onchange: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Fires when the user clicks the left mouse button on the object + * @param ev The mouse event. + */ + onclick: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; + onclose: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Fires when the user clicks the right mouse button in the client area, opening the context menu. + * @param ev The mouse event. + */ + oncontextmenu: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; + oncuechange: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Fires when the user double-clicks the object. + * @param ev The mouse event. + */ + ondblclick: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; + /** + * Fires on the source object continuously during a drag operation. + * @param ev The event. + */ + ondrag: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null; + /** + * Fires on the source object when the user releases the mouse at the close of a drag operation. + * @param ev The event. + */ + ondragend: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null; + /** + * Fires on the target element when the user drags the object to a valid drop target. + * @param ev The drag event. + */ + ondragenter: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null; + ondragexit: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Fires on the target object when the user moves the mouse out of a valid drop target during a drag operation. + * @param ev The drag event. + */ + ondragleave: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null; + /** + * Fires on the target element continuously while the user drags the object over a valid drop target. + * @param ev The event. + */ + ondragover: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null; + /** + * Fires on the source object when the user starts to drag a text selection or selected object. + * @param ev The event. + */ + ondragstart: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null; + ondrop: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null; + /** + * Occurs when the duration attribute is updated. + * @param ev The event. + */ + ondurationchange: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Occurs when the media element is reset to its initial state. + * @param ev The event. + */ + onemptied: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Occurs when the end of playback is reached. + * @param ev The event + */ + onended: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Fires when an error occurs during object loading. + * @param ev The event. + */ + onerror: OnErrorEventHandler; + /** + * Fires when the object receives focus. + * @param ev The event. + */ + onfocus: ((this: GlobalEventHandlers, ev: FocusEvent) => any) | null; + ongotpointercapture: + | ((this: GlobalEventHandlers, ev: PointerEvent) => any) + | null; + oninput: ((this: GlobalEventHandlers, ev: Event) => any) | null; + oninvalid: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Fires when the user presses a key. + * @param ev The keyboard event + */ + onkeydown: ((this: GlobalEventHandlers, ev: KeyboardEvent) => any) | null; + /** + * Fires when the user presses an alphanumeric key. + * @param ev The event. + */ + onkeypress: ((this: GlobalEventHandlers, ev: KeyboardEvent) => any) | null; + /** + * Fires when the user releases a key. + * @param ev The keyboard event + */ + onkeyup: ((this: GlobalEventHandlers, ev: KeyboardEvent) => any) | null; + /** + * Fires immediately after the browser loads the object. + * @param ev The event. + */ + onload: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Occurs when media data is loaded at the current playback position. + * @param ev The event. + */ + onloadeddata: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Occurs when the duration and dimensions of the media have been determined. + * @param ev The event. + */ + onloadedmetadata: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Occurs when Internet Explorer begins looking for media data. + * @param ev The event. + */ + onloadstart: ((this: GlobalEventHandlers, ev: Event) => any) | null; + onlostpointercapture: + | ((this: GlobalEventHandlers, ev: PointerEvent) => any) + | null; + /** + * Fires when the user clicks the object with either mouse button. + * @param ev The mouse event. + */ + onmousedown: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; + onmouseenter: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; + onmouseleave: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; + /** + * Fires when the user moves the mouse over the object. + * @param ev The mouse event. + */ + onmousemove: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; + /** + * Fires when the user moves the mouse pointer outside the boundaries of the object. + * @param ev The mouse event. + */ + onmouseout: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; + /** + * Fires when the user moves the mouse pointer into the object. + * @param ev The mouse event. + */ + onmouseover: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; + /** + * Fires when the user releases a mouse button while the mouse is over the object. + * @param ev The mouse event. + */ + onmouseup: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; + /** + * Occurs when playback is paused. + * @param ev The event. + */ + onpause: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Occurs when the play method is requested. + * @param ev The event. + */ + onplay: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Occurs when the audio or video has started playing. + * @param ev The event. + */ + onplaying: ((this: GlobalEventHandlers, ev: Event) => any) | null; + onpointercancel: + | ((this: GlobalEventHandlers, ev: PointerEvent) => any) + | null; + onpointerdown: + | ((this: GlobalEventHandlers, ev: PointerEvent) => any) + | null; + onpointerenter: + | ((this: GlobalEventHandlers, ev: PointerEvent) => any) + | null; + onpointerleave: + | ((this: GlobalEventHandlers, ev: PointerEvent) => any) + | null; + onpointermove: + | ((this: GlobalEventHandlers, ev: PointerEvent) => any) + | null; + onpointerout: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null; + onpointerover: + | ((this: GlobalEventHandlers, ev: PointerEvent) => any) + | null; + onpointerup: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null; + /** + * Occurs to indicate progress while downloading media data. + * @param ev The event. + */ + onprogress: ((this: GlobalEventHandlers, ev: ProgressEvent) => any) | null; + /** + * Occurs when the playback rate is increased or decreased. + * @param ev The event. + */ + onratechange: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Fires when the user resets a form. + * @param ev The event. + */ + onreset: ((this: GlobalEventHandlers, ev: Event) => any) | null; + onresize: ((this: GlobalEventHandlers, ev: UIEvent) => any) | null; + /** + * Fires when the user repositions the scroll box in the scroll bar on the object. + * @param ev The event. + */ + onscroll: ((this: GlobalEventHandlers, ev: Event) => any) | null; + onsecuritypolicyviolation: + | ((this: GlobalEventHandlers, ev: SecurityPolicyViolationEvent) => any) + | null; + /** + * Occurs when the seek operation ends. + * @param ev The event. + */ + onseeked: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Occurs when the current playback position is moved. + * @param ev The event. + */ + onseeking: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Fires when the current selection changes. + * @param ev The event. + */ + onselect: ((this: GlobalEventHandlers, ev: Event) => any) | null; + onselectionchange: ((this: GlobalEventHandlers, ev: Event) => any) | null; + onselectstart: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Occurs when the download has stopped. + * @param ev The event. + */ + onstalled: ((this: GlobalEventHandlers, ev: Event) => any) | null; + onsubmit: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Occurs if the load operation has been intentionally halted. + * @param ev The event. + */ + onsuspend: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Occurs to indicate the current playback position. + * @param ev The event. + */ + ontimeupdate: ((this: GlobalEventHandlers, ev: Event) => any) | null; + ontoggle: ((this: GlobalEventHandlers, ev: Event) => any) | null; + ontouchcancel?: ((this: GlobalEventHandlers, ev: TouchEvent) => any) | null; + ontouchend?: ((this: GlobalEventHandlers, ev: TouchEvent) => any) | null; + ontouchmove?: ((this: GlobalEventHandlers, ev: TouchEvent) => any) | null; + ontouchstart?: ((this: GlobalEventHandlers, ev: TouchEvent) => any) | null; + ontransitioncancel: + | ((this: GlobalEventHandlers, ev: TransitionEvent) => any) + | null; + ontransitionend: + | ((this: GlobalEventHandlers, ev: TransitionEvent) => any) + | null; + ontransitionrun: + | ((this: GlobalEventHandlers, ev: TransitionEvent) => any) + | null; + ontransitionstart: + | ((this: GlobalEventHandlers, ev: TransitionEvent) => any) + | null; + /** + * Occurs when the volume is changed, or playback is muted or unmuted. + * @param ev The event. + */ + onvolumechange: ((this: GlobalEventHandlers, ev: Event) => any) | null; + /** + * Occurs when playback stops because the next frame of a video resource is not available. + * @param ev The event. + */ + onwaiting: ((this: GlobalEventHandlers, ev: Event) => any) | null; + onwheel: ((this: GlobalEventHandlers, ev: WheelEvent) => any) | null; + addEventListener( + type: K, + listener: ( + this: GlobalEventHandlers, + ev: GlobalEventHandlersEventMap[K], + ) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: ( + this: GlobalEventHandlers, + ev: GlobalEventHandlersEventMap[K], + ) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +export interface HTMLAllCollection { + /** + * Returns the number of elements in the collection. + */ + readonly length: number; + /** + * Returns the item with index index from the collection (determined by tree order). + */ + item(nameOrIndex?: string): HTMLCollection | Element | null; + /** + * Returns the item with ID or name name from the collection. + * + * If there are multiple matching items, then an HTMLCollection object containing all those elements is returned. + * + * Only button, form, iframe, input, map, meta, object, select, and textarea elements can have a name for the purpose of this method; their name is given by the value of their name attribute. + */ + namedItem(name: string): HTMLCollection | Element | null; + [index: number]: Element; +} + +declare var HTMLAllCollection: { + prototype: HTMLAllCollection; + new (): HTMLAllCollection; +}; + +/** Hyperlink elements and provides special properties and methods (beyond those of the regular HTMLElement object interface that they inherit from) for manipulating the layout and presentation of such elements. */ +export interface HTMLAnchorElement + extends HTMLElement, + HTMLHyperlinkElementUtils { + /** + * Sets or retrieves the character set used to encode the object. + */ + /** @deprecated */ + charset: string; + /** + * Sets or retrieves the coordinates of the object. + */ + /** @deprecated */ + coords: string; + download: string; + /** + * Sets or retrieves the language code of the object. + */ + hreflang: string; + /** + * Sets or retrieves the shape of the object. + */ + /** @deprecated */ + name: string; + ping: string; + referrerPolicy: string; + /** + * Sets or retrieves the relationship between the object and the destination of the link. + */ + rel: string; + readonly relList: DOMTokenList; + /** + * Sets or retrieves the relationship between the object and the destination of the link. + */ + /** @deprecated */ + rev: string; + /** + * Sets or retrieves the shape of the object. + */ + /** @deprecated */ + shape: string; + /** + * Sets or retrieves the window or frame at which to target content. + */ + target: string; + /** + * Retrieves or sets the text of the object as a string. + */ + text: string; + type: string; + addEventListener( + type: K, + listener: (this: HTMLAnchorElement, ev: HTMLElementEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: (this: HTMLAnchorElement, ev: HTMLElementEventMap[K]) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var HTMLAnchorElement: { + prototype: HTMLAnchorElement; + new (): HTMLAnchorElement; +}; + +export interface HTMLAppletElement extends HTMLElement { + /** @deprecated */ + align: string; + /** + * Sets or retrieves a text alternative to the graphic. + */ + /** @deprecated */ + alt: string; + /** + * Sets or retrieves a character string that can be used to implement your own archive functionality for the object. + */ + /** @deprecated */ + archive: string; + /** @deprecated */ + code: string; + /** + * Sets or retrieves the URL of the component. + */ + /** @deprecated */ + codeBase: string; + readonly form: HTMLFormElement | null; + /** + * Sets or retrieves the height of the object. + */ + /** @deprecated */ + height: string; + /** @deprecated */ + hspace: number; + /** + * Sets or retrieves the shape of the object. + */ + /** @deprecated */ + name: string; + /** @deprecated */ + object: string; + /** @deprecated */ + vspace: number; + /** @deprecated */ + width: string; + addEventListener( + type: K, + listener: (this: HTMLAppletElement, ev: HTMLElementEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: (this: HTMLAppletElement, ev: HTMLElementEventMap[K]) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var HTMLAppletElement: { + prototype: HTMLAppletElement; + new (): HTMLAppletElement; +}; + +/** Provides special properties and methods (beyond those of the regular object HTMLElement interface it also has available to it by inheritance) for manipulating the layout and presentation of elements. */ +export interface HTMLAreaElement + extends HTMLElement, + HTMLHyperlinkElementUtils { + /** + * Sets or retrieves a text alternative to the graphic. + */ + alt: string; + /** + * Sets or retrieves the coordinates of the object. + */ + coords: string; + download: string; + /** + * Sets or gets whether clicks in this region cause action. + */ + /** @deprecated */ + noHref: boolean; + ping: string; + referrerPolicy: string; + rel: string; + readonly relList: DOMTokenList; + /** + * Sets or retrieves the shape of the object. + */ + shape: string; + /** + * Sets or retrieves the window or frame at which to target content. + */ + target: string; + addEventListener( + type: K, + listener: (this: HTMLAreaElement, ev: HTMLElementEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions, + ): void; + removeEventListener( + type: K, + listener: (this: HTMLAreaElement, ev: HTMLElementEventMap[K]) => any, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + +declare var HTMLAreaElement: { + prototype: HTMLAreaElement; + new (): HTMLAreaElement; +}; + +/** Provides access to the properties of