mirror of
https://code.forgejo.org/actions/setup-node.git
synced 2025-05-21 05:24:45 +00:00
.
This commit is contained in:
parent
beb1329f9f
commit
2b95e76931
7736 changed files with 1874747 additions and 51184 deletions
704
node_modules/jsdom/lib/jsdom/browser/Window.js
generated
vendored
Normal file
704
node_modules/jsdom/lib/jsdom/browser/Window.js
generated
vendored
Normal file
|
@ -0,0 +1,704 @@
|
|||
"use strict";
|
||||
|
||||
const webIDLConversions = require("webidl-conversions");
|
||||
const { CSSStyleDeclaration } = require("cssstyle");
|
||||
const { Performance: RawPerformance } = require("w3c-hr-time");
|
||||
const notImplemented = require("./not-implemented");
|
||||
const VirtualConsole = require("../virtual-console");
|
||||
const { define, mixin } = require("../utils");
|
||||
const EventTarget = require("../living/generated/EventTarget");
|
||||
const namedPropertiesWindow = require("../living/named-properties-window");
|
||||
const cssom = require("cssom");
|
||||
const postMessage = require("../living/post-message");
|
||||
const DOMException = require("domexception");
|
||||
const { btoa, atob } = require("abab");
|
||||
const idlUtils = require("../living/generated/utils");
|
||||
const createXMLHttpRequest = require("../living/xmlhttprequest");
|
||||
const createFileReader = require("../living/generated/FileReader").createInterface;
|
||||
const createWebSocket = require("../living/generated/WebSocket").createInterface;
|
||||
const WebSocketImpl = require("../living/websockets/WebSocket-impl").implementation;
|
||||
const BarProp = require("../living/generated/BarProp");
|
||||
const Document = require("../living/generated/Document");
|
||||
const External = require("../living/generated/External");
|
||||
const Navigator = require("../living/generated/Navigator");
|
||||
const Performance = require("../living/generated/Performance");
|
||||
const Screen = require("../living/generated/Screen");
|
||||
const Storage = require("../living/generated/Storage");
|
||||
const createAbortController = require("../living/generated/AbortController").createInterface;
|
||||
const createAbortSignal = require("../living/generated/AbortSignal").createInterface;
|
||||
const reportException = require("../living/helpers/runtime-script-errors");
|
||||
const { matchesDontThrow } = require("../living/helpers/selectors");
|
||||
const SessionHistory = require("../living/window/SessionHistory");
|
||||
const { contextifyWindow } = require("./documentfeatures.js");
|
||||
|
||||
const GlobalEventHandlersImpl = require("../living/nodes/GlobalEventHandlers-impl").implementation;
|
||||
const WindowEventHandlersImpl = require("../living/nodes/WindowEventHandlers-impl").implementation;
|
||||
|
||||
// NB: the require() must be after assigning `module.exports` because this require() is circular
|
||||
// TODO: this above note might not even be true anymore... figure out the cycle and document it, or clean up.
|
||||
module.exports = Window;
|
||||
const dom = require("../living");
|
||||
|
||||
const cssSelectorSplitRE = /((?:[^,"']|"[^"]*"|'[^']*')+)/;
|
||||
|
||||
const defaultStyleSheet = cssom.parse(require("./default-stylesheet"));
|
||||
|
||||
dom.Window = Window;
|
||||
|
||||
// NOTE: per https://heycam.github.io/webidl/#Global, all properties on the Window object must be own-properties.
|
||||
// That is why we assign everything inside of the constructor, instead of using a shared prototype.
|
||||
// You can verify this in e.g. Firefox or Internet Explorer, which do a good job with Web IDL compliance.
|
||||
|
||||
function Window(options) {
|
||||
EventTarget.setup(this);
|
||||
|
||||
const rawPerformance = new RawPerformance();
|
||||
const windowInitialized = rawPerformance.now();
|
||||
|
||||
const window = this;
|
||||
|
||||
mixin(window, WindowEventHandlersImpl.prototype);
|
||||
mixin(window, GlobalEventHandlersImpl.prototype);
|
||||
|
||||
this._initGlobalEvents();
|
||||
|
||||
///// INTERFACES FROM THE DOM
|
||||
// TODO: consider a mode of some sort where these are not shared between all DOM instances
|
||||
// It'd be very memory-expensive in most cases, though.
|
||||
for (const name in dom) {
|
||||
Object.defineProperty(window, name, {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: dom[name]
|
||||
});
|
||||
}
|
||||
|
||||
///// PRIVATE DATA PROPERTIES
|
||||
|
||||
// vm initialization is deferred until script processing is activated
|
||||
this._globalProxy = this;
|
||||
Object.defineProperty(idlUtils.implForWrapper(this), idlUtils.wrapperSymbol, { get: () => this._globalProxy });
|
||||
|
||||
let timers = Object.create(null);
|
||||
let animationFrameCallbacks = Object.create(null);
|
||||
|
||||
// List options explicitly to be clear which are passed through
|
||||
this._document = Document.create([], {
|
||||
options: {
|
||||
parsingMode: options.parsingMode,
|
||||
contentType: options.contentType,
|
||||
encoding: options.encoding,
|
||||
cookieJar: options.cookieJar,
|
||||
url: options.url,
|
||||
lastModified: options.lastModified,
|
||||
referrer: options.referrer,
|
||||
cookie: options.cookie,
|
||||
deferClose: options.deferClose,
|
||||
resourceLoader: options.resourceLoader,
|
||||
concurrentNodeIterators: options.concurrentNodeIterators,
|
||||
pool: options.pool,
|
||||
agent: options.agent,
|
||||
agentClass: options.agentClass,
|
||||
agentOptions: options.agentOptions,
|
||||
strictSSL: options.strictSSL,
|
||||
proxy: options.proxy,
|
||||
parseOptions: options.parseOptions,
|
||||
defaultView: this._globalProxy,
|
||||
global: this
|
||||
}
|
||||
});
|
||||
// https://html.spec.whatwg.org/#session-history
|
||||
this._sessionHistory = new SessionHistory({
|
||||
document: idlUtils.implForWrapper(this._document),
|
||||
url: idlUtils.implForWrapper(this._document)._URL,
|
||||
stateObject: null
|
||||
}, this);
|
||||
|
||||
// TODO NEWAPI can remove this
|
||||
if (options.virtualConsole) {
|
||||
if (options.virtualConsole instanceof VirtualConsole) {
|
||||
this._virtualConsole = options.virtualConsole;
|
||||
} else {
|
||||
throw new TypeError("options.virtualConsole must be a VirtualConsole (from createVirtualConsole)");
|
||||
}
|
||||
} else {
|
||||
this._virtualConsole = new VirtualConsole();
|
||||
}
|
||||
|
||||
this._runScripts = options.runScripts;
|
||||
if (this._runScripts === "outside-only" || this._runScripts === "dangerously") {
|
||||
contextifyWindow(this);
|
||||
}
|
||||
|
||||
// Set up the window as if it's a top level window.
|
||||
// If it's not, then references will be corrected by frame/iframe code.
|
||||
this._parent = this._top = this._globalProxy;
|
||||
this._frameElement = null;
|
||||
|
||||
// This implements window.frames.length, since window.frames returns a
|
||||
// self reference to the window object. This value is incremented in the
|
||||
// HTMLFrameElement implementation.
|
||||
this._length = 0;
|
||||
|
||||
this._pretendToBeVisual = options.pretendToBeVisual;
|
||||
this._storageQuota = options.storageQuota;
|
||||
|
||||
// Some properties (such as localStorage and sessionStorage) share data
|
||||
// between windows in the same origin. This object is intended
|
||||
// to contain such data.
|
||||
if (options.commonForOrigin && options.commonForOrigin[this._document.origin]) {
|
||||
this._commonForOrigin = options.commonForOrigin;
|
||||
} else {
|
||||
this._commonForOrigin = {
|
||||
[this._document.origin]: {
|
||||
localStorageArea: new Map(),
|
||||
sessionStorageArea: new Map(),
|
||||
windowsInSameOrigin: [this]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
this._currentOriginData = this._commonForOrigin[this._document.origin];
|
||||
|
||||
///// WEB STORAGE
|
||||
|
||||
this._localStorage = Storage.create([], {
|
||||
associatedWindow: this,
|
||||
storageArea: this._currentOriginData.localStorageArea,
|
||||
type: "localStorage",
|
||||
url: this._document.documentURI,
|
||||
storageQuota: this._storageQuota
|
||||
});
|
||||
this._sessionStorage = Storage.create([], {
|
||||
associatedWindow: this,
|
||||
storageArea: this._currentOriginData.sessionStorageArea,
|
||||
type: "sessionStorage",
|
||||
url: this._document.documentURI,
|
||||
storageQuota: this._storageQuota
|
||||
});
|
||||
|
||||
///// GETTERS
|
||||
|
||||
const locationbar = BarProp.create();
|
||||
const menubar = BarProp.create();
|
||||
const personalbar = BarProp.create();
|
||||
const scrollbars = BarProp.create();
|
||||
const statusbar = BarProp.create();
|
||||
const toolbar = BarProp.create();
|
||||
const external = External.create();
|
||||
const navigator = Navigator.create([], { userAgent: options.userAgent });
|
||||
const performance = Performance.create([], { rawPerformance });
|
||||
const screen = Screen.create();
|
||||
|
||||
define(this, {
|
||||
get length() {
|
||||
return window._length;
|
||||
},
|
||||
get window() {
|
||||
return window._globalProxy;
|
||||
},
|
||||
get frameElement() {
|
||||
return window._frameElement;
|
||||
},
|
||||
get frames() {
|
||||
return window._globalProxy;
|
||||
},
|
||||
get self() {
|
||||
return window._globalProxy;
|
||||
},
|
||||
get parent() {
|
||||
return window._parent;
|
||||
},
|
||||
get top() {
|
||||
return window._top;
|
||||
},
|
||||
get document() {
|
||||
return window._document;
|
||||
},
|
||||
get external() {
|
||||
return external;
|
||||
},
|
||||
get location() {
|
||||
return idlUtils.wrapperForImpl(idlUtils.implForWrapper(window._document)._location);
|
||||
},
|
||||
get history() {
|
||||
return idlUtils.wrapperForImpl(idlUtils.implForWrapper(window._document)._history);
|
||||
},
|
||||
get navigator() {
|
||||
return navigator;
|
||||
},
|
||||
get locationbar() {
|
||||
return locationbar;
|
||||
},
|
||||
get menubar() {
|
||||
return menubar;
|
||||
},
|
||||
get personalbar() {
|
||||
return personalbar;
|
||||
},
|
||||
get scrollbars() {
|
||||
return scrollbars;
|
||||
},
|
||||
get statusbar() {
|
||||
return statusbar;
|
||||
},
|
||||
get toolbar() {
|
||||
return toolbar;
|
||||
},
|
||||
get performance() {
|
||||
return performance;
|
||||
},
|
||||
get screen() {
|
||||
return screen;
|
||||
},
|
||||
get localStorage() {
|
||||
if (this._document.origin === "null") {
|
||||
throw new DOMException("localStorage is not available for opaque origins", "SecurityError");
|
||||
}
|
||||
|
||||
return this._localStorage;
|
||||
},
|
||||
get sessionStorage() {
|
||||
if (this._document.origin === "null") {
|
||||
throw new DOMException("sessionStorage is not available for opaque origins", "SecurityError");
|
||||
}
|
||||
|
||||
return this._sessionStorage;
|
||||
}
|
||||
});
|
||||
|
||||
namedPropertiesWindow.initializeWindow(this, this._globalProxy);
|
||||
|
||||
///// METHODS for [ImplicitThis] hack
|
||||
// See https://lists.w3.org/Archives/Public/public-script-coord/2015JanMar/0109.html
|
||||
this.addEventListener = this.addEventListener.bind(this);
|
||||
this.removeEventListener = this.removeEventListener.bind(this);
|
||||
this.dispatchEvent = this.dispatchEvent.bind(this);
|
||||
|
||||
///// METHODS
|
||||
|
||||
let latestTimerId = 0;
|
||||
let latestAnimationFrameCallbackId = 0;
|
||||
|
||||
this.setTimeout = function (fn, ms) {
|
||||
const args = [];
|
||||
for (let i = 2; i < arguments.length; ++i) {
|
||||
args[i - 2] = arguments[i];
|
||||
}
|
||||
return startTimer(window, setTimeout, clearTimeout, ++latestTimerId, fn, ms, timers, args);
|
||||
};
|
||||
this.setInterval = function (fn, ms) {
|
||||
const args = [];
|
||||
for (let i = 2; i < arguments.length; ++i) {
|
||||
args[i - 2] = arguments[i];
|
||||
}
|
||||
return startTimer(window, setInterval, clearInterval, ++latestTimerId, fn, ms, timers, args);
|
||||
};
|
||||
this.clearInterval = stopTimer.bind(this, timers);
|
||||
this.clearTimeout = stopTimer.bind(this, timers);
|
||||
|
||||
if (this._pretendToBeVisual) {
|
||||
this.requestAnimationFrame = fn => {
|
||||
const timestamp = rawPerformance.now() - windowInitialized;
|
||||
const fps = 1000 / 60;
|
||||
|
||||
return startTimer(
|
||||
window,
|
||||
setTimeout,
|
||||
clearTimeout,
|
||||
++latestAnimationFrameCallbackId,
|
||||
fn,
|
||||
fps,
|
||||
animationFrameCallbacks,
|
||||
[timestamp]
|
||||
);
|
||||
};
|
||||
this.cancelAnimationFrame = stopTimer.bind(this, animationFrameCallbacks);
|
||||
}
|
||||
|
||||
this.__stopAllTimers = function () {
|
||||
stopAllTimers(timers);
|
||||
stopAllTimers(animationFrameCallbacks);
|
||||
|
||||
latestTimerId = 0;
|
||||
latestAnimationFrameCallbackId = 0;
|
||||
|
||||
timers = Object.create(null);
|
||||
animationFrameCallbacks = Object.create(null);
|
||||
};
|
||||
|
||||
function Option(text, value, defaultSelected, selected) {
|
||||
if (text === undefined) {
|
||||
text = "";
|
||||
}
|
||||
text = webIDLConversions.DOMString(text);
|
||||
|
||||
if (value !== undefined) {
|
||||
value = webIDLConversions.DOMString(value);
|
||||
}
|
||||
|
||||
defaultSelected = webIDLConversions.boolean(defaultSelected);
|
||||
selected = webIDLConversions.boolean(selected);
|
||||
|
||||
const option = window._document.createElement("option");
|
||||
const impl = idlUtils.implForWrapper(option);
|
||||
|
||||
if (text !== "") {
|
||||
impl.text = text;
|
||||
}
|
||||
if (value !== undefined) {
|
||||
impl.setAttribute("value", value);
|
||||
}
|
||||
if (defaultSelected) {
|
||||
impl.setAttribute("selected", "");
|
||||
}
|
||||
impl._selectedness = selected;
|
||||
|
||||
return option;
|
||||
}
|
||||
Object.defineProperty(Option, "prototype", {
|
||||
value: this.HTMLOptionElement.prototype,
|
||||
configurable: false,
|
||||
enumerable: false,
|
||||
writable: false
|
||||
});
|
||||
Object.defineProperty(window, "Option", {
|
||||
value: Option,
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
writable: true
|
||||
});
|
||||
|
||||
function Image() {
|
||||
const img = window._document.createElement("img");
|
||||
const impl = idlUtils.implForWrapper(img);
|
||||
|
||||
if (arguments.length > 0) {
|
||||
impl.setAttribute("width", String(arguments[0]));
|
||||
}
|
||||
if (arguments.length > 1) {
|
||||
impl.setAttribute("height", String(arguments[1]));
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
Object.defineProperty(Image, "prototype", {
|
||||
value: this.HTMLImageElement.prototype,
|
||||
configurable: false,
|
||||
enumerable: false,
|
||||
writable: false
|
||||
});
|
||||
Object.defineProperty(window, "Image", {
|
||||
value: Image,
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
writable: true
|
||||
});
|
||||
|
||||
function Audio(src) {
|
||||
const audio = window._document.createElement("audio");
|
||||
const impl = idlUtils.implForWrapper(audio);
|
||||
impl.setAttribute("preload", "auto");
|
||||
|
||||
if (src !== undefined) {
|
||||
impl.setAttribute("src", String(src));
|
||||
}
|
||||
|
||||
return audio;
|
||||
}
|
||||
Object.defineProperty(Audio, "prototype", {
|
||||
value: this.HTMLAudioElement.prototype,
|
||||
configurable: false,
|
||||
enumerable: false,
|
||||
writable: false
|
||||
});
|
||||
Object.defineProperty(window, "Audio", {
|
||||
value: Audio,
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
writable: true
|
||||
});
|
||||
|
||||
function wrapConsoleMethod(method) {
|
||||
return (...args) => {
|
||||
window._virtualConsole.emit(method, ...args);
|
||||
};
|
||||
}
|
||||
|
||||
this.postMessage = postMessage;
|
||||
|
||||
this.atob = function (str) {
|
||||
const result = atob(str);
|
||||
if (result === null) {
|
||||
throw new DOMException("The string to be decoded contains invalid characters.", "InvalidCharacterError");
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
this.btoa = function (str) {
|
||||
const result = btoa(str);
|
||||
if (result === null) {
|
||||
throw new DOMException("The string to be encoded contains invalid characters.", "InvalidCharacterError");
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
this.FileReader = createFileReader({
|
||||
window: this
|
||||
}).interface;
|
||||
this.WebSocket = createWebSocket({
|
||||
window: this
|
||||
}).interface;
|
||||
|
||||
const AbortSignalWrapper = createAbortSignal({
|
||||
window: this
|
||||
});
|
||||
this.AbortSignal = AbortSignalWrapper.interface;
|
||||
this.AbortController = createAbortController({
|
||||
AbortSignal: AbortSignalWrapper
|
||||
}).interface;
|
||||
|
||||
this.XMLHttpRequest = createXMLHttpRequest(this);
|
||||
|
||||
// TODO: necessary for Blob and FileReader due to different-globals weirdness; investigate how to avoid this.
|
||||
this.ArrayBuffer = ArrayBuffer;
|
||||
this.Int8Array = Int8Array;
|
||||
this.Uint8Array = Uint8Array;
|
||||
this.Uint8ClampedArray = Uint8ClampedArray;
|
||||
this.Int16Array = Int16Array;
|
||||
this.Uint16Array = Uint16Array;
|
||||
this.Int32Array = Int32Array;
|
||||
this.Uint32Array = Uint32Array;
|
||||
this.Float32Array = Float32Array;
|
||||
this.Float64Array = Float64Array;
|
||||
|
||||
this.stop = function () {
|
||||
const manager = idlUtils.implForWrapper(this._document)._requestManager;
|
||||
if (manager) {
|
||||
manager.close();
|
||||
}
|
||||
};
|
||||
|
||||
this.close = function () {
|
||||
// Recursively close child frame windows, then ourselves.
|
||||
const currentWindow = this;
|
||||
(function windowCleaner(windowToClean) {
|
||||
for (let i = 0; i < windowToClean.length; i++) {
|
||||
windowCleaner(windowToClean[i]);
|
||||
}
|
||||
|
||||
// We"re already in our own window.close().
|
||||
if (windowToClean !== currentWindow) {
|
||||
windowToClean.close();
|
||||
}
|
||||
}(this));
|
||||
|
||||
// Clear out all listeners. Any in-flight or upcoming events should not get delivered.
|
||||
idlUtils.implForWrapper(this)._eventListeners = Object.create(null);
|
||||
|
||||
if (this._document) {
|
||||
if (this._document.body) {
|
||||
this._document.body.innerHTML = "";
|
||||
}
|
||||
|
||||
if (this._document.close) {
|
||||
// It's especially important to clear out the listeners here because document.close() causes a "load" event to
|
||||
// fire.
|
||||
idlUtils.implForWrapper(this._document)._eventListeners = Object.create(null);
|
||||
this._document.close();
|
||||
}
|
||||
const doc = idlUtils.implForWrapper(this._document);
|
||||
if (doc._requestManager) {
|
||||
doc._requestManager.close();
|
||||
}
|
||||
delete this._document;
|
||||
}
|
||||
|
||||
this.__stopAllTimers();
|
||||
WebSocketImpl.cleanUpWindow(this);
|
||||
};
|
||||
|
||||
this.getComputedStyle = function (node) {
|
||||
const nodeImpl = idlUtils.implForWrapper(node);
|
||||
const s = node.style;
|
||||
const cs = new CSSStyleDeclaration();
|
||||
const { forEach } = Array.prototype;
|
||||
|
||||
function setPropertiesFromRule(rule) {
|
||||
if (!rule.selectorText) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selectors = rule.selectorText.split(cssSelectorSplitRE);
|
||||
let matched = false;
|
||||
for (const selectorText of selectors) {
|
||||
if (selectorText !== "" && selectorText !== "," && !matched && matchesDontThrow(nodeImpl, selectorText)) {
|
||||
matched = true;
|
||||
forEach.call(rule.style, property => {
|
||||
cs.setProperty(property, rule.style.getPropertyValue(property), rule.style.getPropertyPriority(property));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function readStylesFromStyleSheet(sheet) {
|
||||
forEach.call(sheet.cssRules, rule => {
|
||||
if (rule.media) {
|
||||
if (Array.prototype.indexOf.call(rule.media, "screen") !== -1) {
|
||||
forEach.call(rule.cssRules, setPropertiesFromRule);
|
||||
}
|
||||
} else {
|
||||
setPropertiesFromRule(rule);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
readStylesFromStyleSheet(defaultStyleSheet);
|
||||
forEach.call(node.ownerDocument.styleSheets, readStylesFromStyleSheet);
|
||||
|
||||
forEach.call(s, property => {
|
||||
cs.setProperty(property, s.getPropertyValue(property), s.getPropertyPriority(property));
|
||||
});
|
||||
|
||||
return cs;
|
||||
};
|
||||
|
||||
// The captureEvents() and releaseEvents() methods must do nothing
|
||||
this.captureEvents = function () {};
|
||||
|
||||
this.releaseEvents = function () {};
|
||||
|
||||
///// PUBLIC DATA PROPERTIES (TODO: should be getters)
|
||||
|
||||
this.console = {
|
||||
assert: wrapConsoleMethod("assert"),
|
||||
clear: wrapConsoleMethod("clear"),
|
||||
count: wrapConsoleMethod("count"),
|
||||
debug: wrapConsoleMethod("debug"),
|
||||
error: wrapConsoleMethod("error"),
|
||||
group: wrapConsoleMethod("group"),
|
||||
groupCollapsed: wrapConsoleMethod("groupCollapsed"),
|
||||
groupEnd: wrapConsoleMethod("groupEnd"),
|
||||
info: wrapConsoleMethod("info"),
|
||||
log: wrapConsoleMethod("log"),
|
||||
table: wrapConsoleMethod("table"),
|
||||
time: wrapConsoleMethod("time"),
|
||||
timeEnd: wrapConsoleMethod("timeEnd"),
|
||||
trace: wrapConsoleMethod("trace"),
|
||||
warn: wrapConsoleMethod("warn")
|
||||
};
|
||||
|
||||
function notImplementedMethod(name) {
|
||||
return function () {
|
||||
notImplemented(name, window);
|
||||
};
|
||||
}
|
||||
|
||||
define(this, {
|
||||
name: "nodejs",
|
||||
// Node v6 has issues (presumably in the vm module)
|
||||
// which this property exposes through an XHR test
|
||||
// status: "",
|
||||
devicePixelRatio: 1,
|
||||
innerWidth: 1024,
|
||||
innerHeight: 768,
|
||||
outerWidth: 1024,
|
||||
outerHeight: 768,
|
||||
pageXOffset: 0,
|
||||
pageYOffset: 0,
|
||||
screenX: 0,
|
||||
screenY: 0,
|
||||
scrollX: 0,
|
||||
scrollY: 0,
|
||||
|
||||
// Not in spec, but likely to be added eventually:
|
||||
// https://github.com/w3c/csswg-drafts/issues/1091
|
||||
screenLeft: 0,
|
||||
screenTop: 0,
|
||||
|
||||
alert: notImplementedMethod("window.alert"),
|
||||
blur: notImplementedMethod("window.blur"),
|
||||
confirm: notImplementedMethod("window.confirm"),
|
||||
focus: notImplementedMethod("window.focus"),
|
||||
moveBy: notImplementedMethod("window.moveBy"),
|
||||
moveTo: notImplementedMethod("window.moveTo"),
|
||||
open: notImplementedMethod("window.open"),
|
||||
print: notImplementedMethod("window.print"),
|
||||
prompt: notImplementedMethod("window.prompt"),
|
||||
resizeBy: notImplementedMethod("window.resizeBy"),
|
||||
resizeTo: notImplementedMethod("window.resizeTo"),
|
||||
scroll: notImplementedMethod("window.scroll"),
|
||||
scrollBy: notImplementedMethod("window.scrollBy"),
|
||||
scrollTo: notImplementedMethod("window.scrollTo")
|
||||
});
|
||||
|
||||
///// INITIALIZATION
|
||||
|
||||
process.nextTick(() => {
|
||||
if (!window.document) {
|
||||
return; // window might've been closed already
|
||||
}
|
||||
|
||||
if (window.document.readyState === "complete") {
|
||||
const ev = window.document.createEvent("HTMLEvents");
|
||||
ev.initEvent("load", false, false);
|
||||
window.dispatchEvent(ev);
|
||||
} else {
|
||||
window.document.addEventListener("load", () => {
|
||||
const ev = window.document.createEvent("HTMLEvents");
|
||||
ev.initEvent("load", false, false);
|
||||
window.dispatchEvent(ev);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Object.setPrototypeOf(Window, EventTarget.interface);
|
||||
Object.setPrototypeOf(Window.prototype, EventTarget.interface.prototype);
|
||||
Object.defineProperty(Window.prototype, Symbol.toStringTag, {
|
||||
value: "Window",
|
||||
writable: false,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
|
||||
function startTimer(window, startFn, stopFn, timerId, callback, ms, timerStorage, args) {
|
||||
if (!window || !window._document) {
|
||||
return undefined;
|
||||
}
|
||||
if (typeof callback !== "function") {
|
||||
const code = String(callback);
|
||||
callback = window._globalProxy.eval.bind(window, code + `\n//# sourceURL=${window.location.href}`);
|
||||
}
|
||||
|
||||
const oldCallback = callback;
|
||||
callback = () => {
|
||||
try {
|
||||
oldCallback.apply(window._globalProxy, args);
|
||||
} catch (e) {
|
||||
reportException(window, e, window.location.href);
|
||||
}
|
||||
};
|
||||
|
||||
const res = startFn(callback, ms);
|
||||
timerStorage[timerId] = [res, stopFn];
|
||||
return timerId;
|
||||
}
|
||||
|
||||
function stopTimer(timerStorage, id) {
|
||||
const timer = timerStorage[id];
|
||||
if (timer) {
|
||||
// Need to .call() with undefined to ensure the thisArg is not timer itself
|
||||
timer[1].call(undefined, timer[0]);
|
||||
delete timerStorage[id];
|
||||
}
|
||||
}
|
||||
|
||||
function stopAllTimers(timers) {
|
||||
Object.keys(timers).forEach(key => {
|
||||
const timer = timers[key];
|
||||
// Need to .call() with undefined to ensure the thisArg is not timer itself
|
||||
timer[1].call(undefined, timer[0]);
|
||||
});
|
||||
}
|
785
node_modules/jsdom/lib/jsdom/browser/default-stylesheet.js
generated
vendored
Normal file
785
node_modules/jsdom/lib/jsdom/browser/default-stylesheet.js
generated
vendored
Normal file
|
@ -0,0 +1,785 @@
|
|||
// Ideally, we would use
|
||||
// https://html.spec.whatwg.org/multipage/rendering.html#the-css-user-agent-style-sheet-and-presentational-hints
|
||||
// but for now, just use the version from blink. This file is copied from
|
||||
// https://chromium.googlesource.com/chromium/blink/+/96aa3a280ab7d67178c8f122a04949ce5f8579e0/Source/core/css/html.css
|
||||
// (removed a line which had octal literals inside since octal literals are not allowed in template strings)
|
||||
|
||||
// We use a .js file because otherwise we can't browserify this. (brfs is unusable due to lack of ES2015 support)
|
||||
|
||||
module.exports = `
|
||||
/*
|
||||
* The default style sheet used to render HTML.
|
||||
*
|
||||
* Copyright (C) 2000 Lars Knoll (knoll@kde.org)
|
||||
* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public License
|
||||
* along with this library; see the file COPYING.LIB. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
@namespace "http://www.w3.org/1999/xhtml";
|
||||
|
||||
html {
|
||||
display: block
|
||||
}
|
||||
|
||||
:root {
|
||||
scroll-blocks-on: start-touch wheel-event
|
||||
}
|
||||
|
||||
/* children of the <head> element all have display:none */
|
||||
head {
|
||||
display: none
|
||||
}
|
||||
|
||||
meta {
|
||||
display: none
|
||||
}
|
||||
|
||||
title {
|
||||
display: none
|
||||
}
|
||||
|
||||
link {
|
||||
display: none
|
||||
}
|
||||
|
||||
style {
|
||||
display: none
|
||||
}
|
||||
|
||||
script {
|
||||
display: none
|
||||
}
|
||||
|
||||
/* generic block-level elements */
|
||||
|
||||
body {
|
||||
display: block;
|
||||
margin: 8px
|
||||
}
|
||||
|
||||
p {
|
||||
display: block;
|
||||
-webkit-margin-before: 1__qem;
|
||||
-webkit-margin-after: 1__qem;
|
||||
-webkit-margin-start: 0;
|
||||
-webkit-margin-end: 0;
|
||||
}
|
||||
|
||||
div {
|
||||
display: block
|
||||
}
|
||||
|
||||
layer {
|
||||
display: block
|
||||
}
|
||||
|
||||
article, aside, footer, header, hgroup, main, nav, section {
|
||||
display: block
|
||||
}
|
||||
|
||||
marquee {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
address {
|
||||
display: block
|
||||
}
|
||||
|
||||
blockquote {
|
||||
display: block;
|
||||
-webkit-margin-before: 1__qem;
|
||||
-webkit-margin-after: 1em;
|
||||
-webkit-margin-start: 40px;
|
||||
-webkit-margin-end: 40px;
|
||||
}
|
||||
|
||||
figcaption {
|
||||
display: block
|
||||
}
|
||||
|
||||
figure {
|
||||
display: block;
|
||||
-webkit-margin-before: 1em;
|
||||
-webkit-margin-after: 1em;
|
||||
-webkit-margin-start: 40px;
|
||||
-webkit-margin-end: 40px;
|
||||
}
|
||||
|
||||
q {
|
||||
display: inline
|
||||
}
|
||||
|
||||
/* nwmatcher does not support ::before and ::after, so we can't render q
|
||||
correctly: https://html.spec.whatwg.org/multipage/rendering.html#phrasing-content-3
|
||||
TODO: add q::before and q::after selectors
|
||||
*/
|
||||
|
||||
center {
|
||||
display: block;
|
||||
/* special centering to be able to emulate the html4/netscape behaviour */
|
||||
text-align: -webkit-center
|
||||
}
|
||||
|
||||
hr {
|
||||
display: block;
|
||||
-webkit-margin-before: 0.5em;
|
||||
-webkit-margin-after: 0.5em;
|
||||
-webkit-margin-start: auto;
|
||||
-webkit-margin-end: auto;
|
||||
border-style: inset;
|
||||
border-width: 1px;
|
||||
box-sizing: border-box
|
||||
}
|
||||
|
||||
map {
|
||||
display: inline
|
||||
}
|
||||
|
||||
video {
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
/* heading elements */
|
||||
|
||||
h1 {
|
||||
display: block;
|
||||
font-size: 2em;
|
||||
-webkit-margin-before: 0.67__qem;
|
||||
-webkit-margin-after: 0.67em;
|
||||
-webkit-margin-start: 0;
|
||||
-webkit-margin-end: 0;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
article h1,
|
||||
aside h1,
|
||||
nav h1,
|
||||
section h1 {
|
||||
font-size: 1.5em;
|
||||
-webkit-margin-before: 0.83__qem;
|
||||
-webkit-margin-after: 0.83em;
|
||||
}
|
||||
|
||||
article article h1,
|
||||
article aside h1,
|
||||
article nav h1,
|
||||
article section h1,
|
||||
aside article h1,
|
||||
aside aside h1,
|
||||
aside nav h1,
|
||||
aside section h1,
|
||||
nav article h1,
|
||||
nav aside h1,
|
||||
nav nav h1,
|
||||
nav section h1,
|
||||
section article h1,
|
||||
section aside h1,
|
||||
section nav h1,
|
||||
section section h1 {
|
||||
font-size: 1.17em;
|
||||
-webkit-margin-before: 1__qem;
|
||||
-webkit-margin-after: 1em;
|
||||
}
|
||||
|
||||
/* Remaining selectors are deleted because nwmatcher does not support
|
||||
:matches() and expanding the selectors manually would be far too verbose.
|
||||
Also see https://html.spec.whatwg.org/multipage/rendering.html#sections-and-headings
|
||||
TODO: rewrite to use :matches() when nwmatcher supports it.
|
||||
*/
|
||||
|
||||
h2 {
|
||||
display: block;
|
||||
font-size: 1.5em;
|
||||
-webkit-margin-before: 0.83__qem;
|
||||
-webkit-margin-after: 0.83em;
|
||||
-webkit-margin-start: 0;
|
||||
-webkit-margin-end: 0;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
h3 {
|
||||
display: block;
|
||||
font-size: 1.17em;
|
||||
-webkit-margin-before: 1__qem;
|
||||
-webkit-margin-after: 1em;
|
||||
-webkit-margin-start: 0;
|
||||
-webkit-margin-end: 0;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
h4 {
|
||||
display: block;
|
||||
-webkit-margin-before: 1.33__qem;
|
||||
-webkit-margin-after: 1.33em;
|
||||
-webkit-margin-start: 0;
|
||||
-webkit-margin-end: 0;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
h5 {
|
||||
display: block;
|
||||
font-size: .83em;
|
||||
-webkit-margin-before: 1.67__qem;
|
||||
-webkit-margin-after: 1.67em;
|
||||
-webkit-margin-start: 0;
|
||||
-webkit-margin-end: 0;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
h6 {
|
||||
display: block;
|
||||
font-size: .67em;
|
||||
-webkit-margin-before: 2.33__qem;
|
||||
-webkit-margin-after: 2.33em;
|
||||
-webkit-margin-start: 0;
|
||||
-webkit-margin-end: 0;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
/* tables */
|
||||
|
||||
table {
|
||||
display: table;
|
||||
border-collapse: separate;
|
||||
border-spacing: 2px;
|
||||
border-color: gray
|
||||
}
|
||||
|
||||
thead {
|
||||
display: table-header-group;
|
||||
vertical-align: middle;
|
||||
border-color: inherit
|
||||
}
|
||||
|
||||
tbody {
|
||||
display: table-row-group;
|
||||
vertical-align: middle;
|
||||
border-color: inherit
|
||||
}
|
||||
|
||||
tfoot {
|
||||
display: table-footer-group;
|
||||
vertical-align: middle;
|
||||
border-color: inherit
|
||||
}
|
||||
|
||||
/* for tables without table section elements (can happen with XHTML or dynamically created tables) */
|
||||
table > tr {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
col {
|
||||
display: table-column
|
||||
}
|
||||
|
||||
colgroup {
|
||||
display: table-column-group
|
||||
}
|
||||
|
||||
tr {
|
||||
display: table-row;
|
||||
vertical-align: inherit;
|
||||
border-color: inherit
|
||||
}
|
||||
|
||||
td, th {
|
||||
display: table-cell;
|
||||
vertical-align: inherit
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
caption {
|
||||
display: table-caption;
|
||||
text-align: -webkit-center
|
||||
}
|
||||
|
||||
/* lists */
|
||||
|
||||
ul, menu, dir {
|
||||
display: block;
|
||||
list-style-type: disc;
|
||||
-webkit-margin-before: 1__qem;
|
||||
-webkit-margin-after: 1em;
|
||||
-webkit-margin-start: 0;
|
||||
-webkit-margin-end: 0;
|
||||
-webkit-padding-start: 40px
|
||||
}
|
||||
|
||||
ol {
|
||||
display: block;
|
||||
list-style-type: decimal;
|
||||
-webkit-margin-before: 1__qem;
|
||||
-webkit-margin-after: 1em;
|
||||
-webkit-margin-start: 0;
|
||||
-webkit-margin-end: 0;
|
||||
-webkit-padding-start: 40px
|
||||
}
|
||||
|
||||
li {
|
||||
display: list-item;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
ul ul, ol ul {
|
||||
list-style-type: circle
|
||||
}
|
||||
|
||||
ol ol ul, ol ul ul, ul ol ul, ul ul ul {
|
||||
list-style-type: square
|
||||
}
|
||||
|
||||
dd {
|
||||
display: block;
|
||||
-webkit-margin-start: 40px
|
||||
}
|
||||
|
||||
dl {
|
||||
display: block;
|
||||
-webkit-margin-before: 1__qem;
|
||||
-webkit-margin-after: 1em;
|
||||
-webkit-margin-start: 0;
|
||||
-webkit-margin-end: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
display: block
|
||||
}
|
||||
|
||||
ol ul, ul ol, ul ul, ol ol {
|
||||
-webkit-margin-before: 0;
|
||||
-webkit-margin-after: 0
|
||||
}
|
||||
|
||||
/* form elements */
|
||||
|
||||
form {
|
||||
display: block;
|
||||
margin-top: 0__qem;
|
||||
}
|
||||
|
||||
label {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
legend {
|
||||
display: block;
|
||||
-webkit-padding-start: 2px;
|
||||
-webkit-padding-end: 2px;
|
||||
border: none
|
||||
}
|
||||
|
||||
fieldset {
|
||||
display: block;
|
||||
-webkit-margin-start: 2px;
|
||||
-webkit-margin-end: 2px;
|
||||
-webkit-padding-before: 0.35em;
|
||||
-webkit-padding-start: 0.75em;
|
||||
-webkit-padding-end: 0.75em;
|
||||
-webkit-padding-after: 0.625em;
|
||||
border: 2px groove ThreeDFace;
|
||||
min-width: -webkit-min-content;
|
||||
}
|
||||
|
||||
button {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
/* Form controls don't go vertical. */
|
||||
input, textarea, select, button, meter, progress {
|
||||
-webkit-writing-mode: horizontal-tb !important;
|
||||
}
|
||||
|
||||
input, textarea, select, button {
|
||||
margin: 0__qem;
|
||||
font: -webkit-small-control;
|
||||
text-rendering: auto; /* FIXME: Remove when tabs work with optimizeLegibility. */
|
||||
color: initial;
|
||||
letter-spacing: normal;
|
||||
word-spacing: normal;
|
||||
line-height: normal;
|
||||
text-transform: none;
|
||||
text-indent: 0;
|
||||
text-shadow: none;
|
||||
display: inline-block;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
/* TODO: Add " i" to attribute matchers to support case-insensitive matching */
|
||||
input[type="hidden"] {
|
||||
display: none
|
||||
}
|
||||
|
||||
input {
|
||||
-webkit-appearance: textfield;
|
||||
padding: 1px;
|
||||
background-color: white;
|
||||
border: 2px inset;
|
||||
-webkit-rtl-ordering: logical;
|
||||
-webkit-user-select: text;
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
input[type="search"] {
|
||||
-webkit-appearance: searchfield;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
select {
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
-webkit-appearance: textarea;
|
||||
background-color: white;
|
||||
border: 1px solid;
|
||||
-webkit-rtl-ordering: logical;
|
||||
-webkit-user-select: text;
|
||||
flex-direction: column;
|
||||
resize: auto;
|
||||
cursor: auto;
|
||||
padding: 2px;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
input[type="password"] {
|
||||
-webkit-text-security: disc !important;
|
||||
}
|
||||
|
||||
input[type="hidden"], input[type="image"], input[type="file"] {
|
||||
-webkit-appearance: initial;
|
||||
padding: initial;
|
||||
background-color: initial;
|
||||
border: initial;
|
||||
}
|
||||
|
||||
input[type="file"] {
|
||||
align-items: baseline;
|
||||
color: inherit;
|
||||
text-align: start !important;
|
||||
}
|
||||
|
||||
input[type="radio"], input[type="checkbox"] {
|
||||
margin: 3px 0.5ex;
|
||||
padding: initial;
|
||||
background-color: initial;
|
||||
border: initial;
|
||||
}
|
||||
|
||||
input[type="button"], input[type="submit"], input[type="reset"] {
|
||||
-webkit-appearance: push-button;
|
||||
-webkit-user-select: none;
|
||||
white-space: pre
|
||||
}
|
||||
|
||||
input[type="button"], input[type="submit"], input[type="reset"], button {
|
||||
align-items: flex-start;
|
||||
text-align: center;
|
||||
cursor: default;
|
||||
color: ButtonText;
|
||||
padding: 2px 6px 3px 6px;
|
||||
border: 2px outset ButtonFace;
|
||||
background-color: ButtonFace;
|
||||
box-sizing: border-box
|
||||
}
|
||||
|
||||
input[type="range"] {
|
||||
-webkit-appearance: slider-horizontal;
|
||||
padding: initial;
|
||||
border: initial;
|
||||
margin: 2px;
|
||||
color: #909090;
|
||||
}
|
||||
|
||||
input[type="button"]:disabled, input[type="submit"]:disabled, input[type="reset"]:disabled,
|
||||
button:disabled, select:disabled, optgroup:disabled, option:disabled,
|
||||
select[disabled]>option {
|
||||
color: GrayText
|
||||
}
|
||||
|
||||
input[type="button"]:active, input[type="submit"]:active, input[type="reset"]:active, button:active {
|
||||
border-style: inset
|
||||
}
|
||||
|
||||
input[type="button"]:active:disabled, input[type="submit"]:active:disabled, input[type="reset"]:active:disabled, button:active:disabled {
|
||||
border-style: outset
|
||||
}
|
||||
|
||||
datalist {
|
||||
display: none
|
||||
}
|
||||
|
||||
area {
|
||||
display: inline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
param {
|
||||
display: none
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
-webkit-appearance: checkbox;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
input[type="radio"] {
|
||||
-webkit-appearance: radio;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
input[type="color"] {
|
||||
-webkit-appearance: square-button;
|
||||
width: 44px;
|
||||
height: 23px;
|
||||
background-color: ButtonFace;
|
||||
/* Same as native_theme_base. */
|
||||
border: 1px #a9a9a9 solid;
|
||||
padding: 1px 2px;
|
||||
}
|
||||
|
||||
input[type="color"][list] {
|
||||
-webkit-appearance: menulist;
|
||||
width: 88px;
|
||||
height: 23px
|
||||
}
|
||||
|
||||
select {
|
||||
-webkit-appearance: menulist;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
border: 1px solid;
|
||||
white-space: pre;
|
||||
-webkit-rtl-ordering: logical;
|
||||
color: black;
|
||||
background-color: white;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
optgroup {
|
||||
font-weight: bolder;
|
||||
display: block;
|
||||
}
|
||||
|
||||
option {
|
||||
font-weight: normal;
|
||||
display: block;
|
||||
padding: 0 2px 1px 2px;
|
||||
white-space: pre;
|
||||
min-height: 1.2em;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* meter */
|
||||
|
||||
meter {
|
||||
-webkit-appearance: meter;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
height: 1em;
|
||||
width: 5em;
|
||||
vertical-align: -0.2em;
|
||||
}
|
||||
|
||||
/* progress */
|
||||
|
||||
progress {
|
||||
-webkit-appearance: progress-bar;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
height: 1em;
|
||||
width: 10em;
|
||||
vertical-align: -0.2em;
|
||||
}
|
||||
|
||||
/* inline elements */
|
||||
|
||||
u, ins {
|
||||
text-decoration: underline
|
||||
}
|
||||
|
||||
strong, b {
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
i, cite, em, var, address, dfn {
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
tt, code, kbd, samp {
|
||||
font-family: monospace
|
||||
}
|
||||
|
||||
pre, xmp, plaintext, listing {
|
||||
display: block;
|
||||
font-family: monospace;
|
||||
white-space: pre;
|
||||
margin: 1__qem 0
|
||||
}
|
||||
|
||||
mark {
|
||||
background-color: yellow;
|
||||
color: black
|
||||
}
|
||||
|
||||
big {
|
||||
font-size: larger
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: smaller
|
||||
}
|
||||
|
||||
s, strike, del {
|
||||
text-decoration: line-through
|
||||
}
|
||||
|
||||
sub {
|
||||
vertical-align: sub;
|
||||
font-size: smaller
|
||||
}
|
||||
|
||||
sup {
|
||||
vertical-align: super;
|
||||
font-size: smaller
|
||||
}
|
||||
|
||||
nobr {
|
||||
white-space: nowrap
|
||||
}
|
||||
|
||||
/* states */
|
||||
|
||||
:focus {
|
||||
outline: auto 5px -webkit-focus-ring-color
|
||||
}
|
||||
|
||||
/* Read-only text fields do not show a focus ring but do still receive focus */
|
||||
html:focus, body:focus, input[readonly]:focus {
|
||||
outline: none
|
||||
}
|
||||
|
||||
embed:focus, iframe:focus, object:focus {
|
||||
outline: none
|
||||
}
|
||||
|
||||
input:focus, textarea:focus, select:focus {
|
||||
outline-offset: -2px
|
||||
}
|
||||
|
||||
input[type="button"]:focus,
|
||||
input[type="checkbox"]:focus,
|
||||
input[type="file"]:focus,
|
||||
input[type="hidden"]:focus,
|
||||
input[type="image"]:focus,
|
||||
input[type="radio"]:focus,
|
||||
input[type="reset"]:focus,
|
||||
input[type="search"]:focus,
|
||||
input[type="submit"]:focus {
|
||||
outline-offset: 0
|
||||
}
|
||||
|
||||
/* HTML5 ruby elements */
|
||||
|
||||
ruby, rt {
|
||||
text-indent: 0; /* blocks used for ruby rendering should not trigger this */
|
||||
}
|
||||
|
||||
rt {
|
||||
line-height: normal;
|
||||
-webkit-text-emphasis: none;
|
||||
}
|
||||
|
||||
ruby > rt {
|
||||
display: block;
|
||||
font-size: 50%;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
ruby > rp {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* other elements */
|
||||
|
||||
noframes {
|
||||
display: none
|
||||
}
|
||||
|
||||
frameset, frame {
|
||||
display: block
|
||||
}
|
||||
|
||||
frameset {
|
||||
border-color: inherit
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 2px inset
|
||||
}
|
||||
|
||||
details {
|
||||
display: block
|
||||
}
|
||||
|
||||
summary {
|
||||
display: block
|
||||
}
|
||||
|
||||
template {
|
||||
display: none
|
||||
}
|
||||
|
||||
bdi, output {
|
||||
unicode-bidi: -webkit-isolate;
|
||||
}
|
||||
|
||||
bdo {
|
||||
unicode-bidi: bidi-override;
|
||||
}
|
||||
|
||||
textarea[dir=auto] {
|
||||
unicode-bidi: -webkit-plaintext;
|
||||
}
|
||||
|
||||
dialog:not([open]) {
|
||||
display: none
|
||||
}
|
||||
|
||||
dialog {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: -webkit-fit-content;
|
||||
height: -webkit-fit-content;
|
||||
margin: auto;
|
||||
border: solid;
|
||||
padding: 1em;
|
||||
background: white;
|
||||
color: black
|
||||
}
|
||||
|
||||
/* noscript is handled internally, as it depends on settings. */
|
||||
|
||||
`;
|
55
node_modules/jsdom/lib/jsdom/browser/documentfeatures.js
generated
vendored
Normal file
55
node_modules/jsdom/lib/jsdom/browser/documentfeatures.js
generated
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
"use strict";
|
||||
const vm = require("vm");
|
||||
const idlUtils = require("../living/generated/utils");
|
||||
|
||||
exports.availableDocumentFeatures = [
|
||||
"FetchExternalResources",
|
||||
"SkipExternalResources"
|
||||
];
|
||||
|
||||
exports.defaultDocumentFeatures = {
|
||||
FetchExternalResources: ["script", "link"], // omitted by default: "frame"
|
||||
SkipExternalResources: false
|
||||
};
|
||||
|
||||
exports.applyDocumentFeatures = (documentImpl, features = {}) => {
|
||||
for (let i = 0; i < exports.availableDocumentFeatures.length; ++i) {
|
||||
const featureName = exports.availableDocumentFeatures[i];
|
||||
let featureSource;
|
||||
|
||||
if (features[featureName] !== undefined) {
|
||||
featureSource = features[featureName];
|
||||
// We have to check the lowercase version also because the Document feature
|
||||
// methods convert everything to lowercase.
|
||||
} else if (typeof features[featureName.toLowerCase()] !== "undefined") {
|
||||
featureSource = features[featureName.toLowerCase()];
|
||||
} else if (exports.defaultDocumentFeatures[featureName]) {
|
||||
featureSource = exports.defaultDocumentFeatures[featureName];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
const implImpl = documentImpl._implementation;
|
||||
implImpl._removeFeature(featureName);
|
||||
|
||||
if (featureSource !== undefined) {
|
||||
if (Array.isArray(featureSource)) {
|
||||
for (let j = 0; j < featureSource.length; ++j) {
|
||||
implImpl._addFeature(featureName, featureSource[j]);
|
||||
}
|
||||
} else {
|
||||
implImpl._addFeature(featureName, featureSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.contextifyWindow = window => {
|
||||
if (vm.isContext(window)) {
|
||||
return;
|
||||
}
|
||||
|
||||
vm.createContext(window);
|
||||
const documentImpl = idlUtils.implForWrapper(window._document);
|
||||
documentImpl._defaultView = window._globalProxy = vm.runInContext("this", window);
|
||||
};
|
18
node_modules/jsdom/lib/jsdom/browser/domtohtml.js
generated
vendored
Normal file
18
node_modules/jsdom/lib/jsdom/browser/domtohtml.js
generated
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
"use strict";
|
||||
const parse5 = require("parse5");
|
||||
const treeAdapter = require("./parse5-adapter-serialization");
|
||||
const NODE_TYPE = require("../living/node-type");
|
||||
|
||||
exports.domToHtml = iterable => {
|
||||
let ret = "";
|
||||
for (const node of iterable) {
|
||||
if (node.nodeType === NODE_TYPE.DOCUMENT_NODE) {
|
||||
ret += parse5.serialize(node, { treeAdapter });
|
||||
} else {
|
||||
// TODO: maybe parse5 can give us a hook where it serializes the node itself too:
|
||||
// https://github.com/inikulin/parse5/issues/230
|
||||
ret += parse5.serialize({ childNodesForSerializing: [node] }, { treeAdapter });
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
271
node_modules/jsdom/lib/jsdom/browser/htmltodom.js
generated
vendored
Normal file
271
node_modules/jsdom/lib/jsdom/browser/htmltodom.js
generated
vendored
Normal file
|
@ -0,0 +1,271 @@
|
|||
"use strict";
|
||||
|
||||
const parse5 = require("parse5");
|
||||
const sax = require("sax");
|
||||
const attributes = require("../living/attributes");
|
||||
const DocumentType = require("../living/generated/DocumentType");
|
||||
const JSDOMParse5Adapter = require("./parse5-adapter-parsing");
|
||||
const { HTML_NS } = require("../living/helpers/namespaces");
|
||||
|
||||
// Horrible monkey-patch to implement https://github.com/inikulin/parse5/issues/237
|
||||
const OpenElementStack = require("parse5/lib/parser/open_element_stack");
|
||||
const originalPop = OpenElementStack.prototype.pop;
|
||||
OpenElementStack.prototype.pop = function (...args) {
|
||||
const before = this.items[this.stackTop];
|
||||
originalPop.apply(this, args);
|
||||
if (before._poppedOffStackOfOpenElements) {
|
||||
before._poppedOffStackOfOpenElements();
|
||||
}
|
||||
};
|
||||
|
||||
const originalPush = OpenElementStack.prototype.push;
|
||||
OpenElementStack.prototype.push = function (...args) {
|
||||
originalPush.apply(this, args);
|
||||
const after = this.items[this.stackTop];
|
||||
if (after._pushedOnStackOfOpenElements) {
|
||||
after._pushedOnStackOfOpenElements();
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = class HTMLToDOM {
|
||||
constructor(parsingMode) {
|
||||
this.parser = parsingMode === "xml" ? sax : parse5;
|
||||
}
|
||||
|
||||
appendToNode(html, node) {
|
||||
html = String(html);
|
||||
|
||||
return this._doParse(html, true, node);
|
||||
}
|
||||
|
||||
appendToDocument(html, documentImpl) {
|
||||
html = String(html);
|
||||
|
||||
return this._doParse(html, false, documentImpl, documentImpl._parseOptions);
|
||||
}
|
||||
|
||||
_doParse(...args) {
|
||||
return this.parser === parse5 ? this._parseWithParse5(...args) : this._parseWithSax(...args);
|
||||
}
|
||||
|
||||
_parseWithParse5(html, isFragment, contextNode, options = {}) {
|
||||
const adapter = new JSDOMParse5Adapter(contextNode._ownerDocument || contextNode);
|
||||
options.treeAdapter = adapter;
|
||||
|
||||
if (isFragment) {
|
||||
const fragment = this.parser.parseFragment(contextNode, html, options);
|
||||
|
||||
if (contextNode._templateContents) {
|
||||
contextNode._templateContents.appendChild(fragment);
|
||||
} else {
|
||||
contextNode.appendChild(fragment);
|
||||
}
|
||||
} else {
|
||||
this.parser.parse(html, options);
|
||||
}
|
||||
|
||||
return contextNode;
|
||||
}
|
||||
|
||||
_parseWithSax(html, isFragment, contextNode) {
|
||||
const SaxParser = this.parser.parser;
|
||||
const parser = new SaxParser(/* strict = */true, { xmlns: true, strictEntities: true });
|
||||
parser.noscript = false;
|
||||
parser.looseCase = "toString";
|
||||
const openStack = [contextNode];
|
||||
parser.ontext = text => {
|
||||
setChildForSax(openStack[openStack.length - 1], {
|
||||
type: "text",
|
||||
data: text
|
||||
});
|
||||
};
|
||||
parser.oncdata = cdata => {
|
||||
setChildForSax(openStack[openStack.length - 1], {
|
||||
type: "cdata",
|
||||
data: cdata
|
||||
});
|
||||
};
|
||||
parser.onopentag = arg => {
|
||||
const attrs = Object.keys(arg.attributes).map(key => {
|
||||
const rawAttribute = arg.attributes[key];
|
||||
|
||||
let { prefix } = rawAttribute;
|
||||
let localName = rawAttribute.local;
|
||||
if (prefix === "xmlns" && localName === "") {
|
||||
// intended weirdness in node-sax, see https://github.com/isaacs/sax-js/issues/165
|
||||
localName = prefix;
|
||||
prefix = null;
|
||||
}
|
||||
|
||||
if (prefix === "") {
|
||||
prefix = null;
|
||||
}
|
||||
|
||||
const namespace = rawAttribute.uri === "" ? null : rawAttribute.uri;
|
||||
|
||||
return { name: rawAttribute.name, value: rawAttribute.value, prefix, localName, namespace };
|
||||
});
|
||||
const tag = {
|
||||
type: "tag",
|
||||
name: arg.local,
|
||||
prefix: arg.prefix,
|
||||
namespace: arg.uri,
|
||||
attributes: attrs
|
||||
};
|
||||
|
||||
if (arg.local === "script" && arg.uri === HTML_NS) {
|
||||
openStack.push(tag);
|
||||
} else {
|
||||
const elem = setChildForSax(openStack[openStack.length - 1], tag);
|
||||
openStack.push(elem);
|
||||
}
|
||||
};
|
||||
parser.onclosetag = () => {
|
||||
const elem = openStack.pop();
|
||||
if (elem.constructor.name === "Object") { // we have an empty script tag
|
||||
setChildForSax(openStack[openStack.length - 1], elem);
|
||||
}
|
||||
};
|
||||
parser.onscript = scriptText => {
|
||||
const tag = openStack.pop();
|
||||
tag.children = [{ type: "text", data: scriptText }];
|
||||
const elem = setChildForSax(openStack[openStack.length - 1], tag);
|
||||
openStack.push(elem);
|
||||
};
|
||||
parser.oncomment = comment => {
|
||||
setChildForSax(openStack[openStack.length - 1], {
|
||||
type: "comment",
|
||||
data: comment
|
||||
});
|
||||
};
|
||||
parser.onprocessinginstruction = pi => {
|
||||
setChildForSax(openStack[openStack.length - 1], {
|
||||
type: "directive",
|
||||
name: "?" + pi.name,
|
||||
data: "?" + pi.name + " " + pi.body + "?"
|
||||
});
|
||||
};
|
||||
parser.ondoctype = dt => {
|
||||
setChildForSax(openStack[openStack.length - 1], {
|
||||
type: "directive",
|
||||
name: "!doctype",
|
||||
data: "!doctype " + dt
|
||||
});
|
||||
|
||||
const entityMatcher = /<!ENTITY ([^ ]+) "([^"]+)">/g;
|
||||
let result;
|
||||
while ((result = entityMatcher.exec(dt))) {
|
||||
const [, name, value] = result;
|
||||
if (!(name in parser.ENTITIES)) {
|
||||
parser.ENTITIES[name] = value;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
parser.onerror = err => {
|
||||
throw err;
|
||||
};
|
||||
parser.write(html).close();
|
||||
}
|
||||
};
|
||||
|
||||
function setChildForSax(parentImpl, node) {
|
||||
const currentDocument = (parentImpl && parentImpl._ownerDocument) || parentImpl;
|
||||
|
||||
let newNode;
|
||||
let isTemplateContents = false;
|
||||
switch (node.type) {
|
||||
case "tag":
|
||||
case "script":
|
||||
case "style":
|
||||
newNode = currentDocument._createElementWithCorrectElementInterface(node.name, node.namespace);
|
||||
newNode._prefix = node.prefix || null;
|
||||
newNode._namespaceURI = node.namespace || null;
|
||||
break;
|
||||
|
||||
case "root":
|
||||
// If we are in <template> then add all children to the parent's _templateContents; skip this virtual root node.
|
||||
if (parentImpl.tagName === "TEMPLATE" && parentImpl._namespaceURI === HTML_NS) {
|
||||
newNode = parentImpl._templateContents;
|
||||
isTemplateContents = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case "text":
|
||||
// HTML entities should already be decoded by the parser, so no need to decode them
|
||||
newNode = currentDocument.createTextNode(node.data);
|
||||
break;
|
||||
|
||||
case "cdata":
|
||||
newNode = currentDocument.createCDATASection(node.data);
|
||||
break;
|
||||
|
||||
case "comment":
|
||||
newNode = currentDocument.createComment(node.data);
|
||||
break;
|
||||
|
||||
case "directive":
|
||||
if (node.name[0] === "?" && node.name.toLowerCase() !== "?xml") {
|
||||
const data = node.data.slice(node.name.length + 1, -1);
|
||||
newNode = currentDocument.createProcessingInstruction(node.name.substring(1), data);
|
||||
} else if (node.name.toLowerCase() === "!doctype") {
|
||||
newNode = parseDocType(currentDocument, "<" + node.data + ">");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!newNode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (node.attributes) {
|
||||
for (const a of node.attributes) {
|
||||
attributes.setAttributeValue(newNode, a.localName, a.value, a.prefix, a.namespace);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.children) {
|
||||
for (let c = 0; c < node.children.length; c++) {
|
||||
setChildForSax(newNode, node.children[c]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isTemplateContents) {
|
||||
if (parentImpl._templateContents) {
|
||||
// Setting innerHTML on a <template>
|
||||
parentImpl._templateContents.appendChild(newNode);
|
||||
} else {
|
||||
parentImpl.appendChild(newNode);
|
||||
}
|
||||
}
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
const HTML5_DOCTYPE = /<!doctype html>/i;
|
||||
const PUBLIC_DOCTYPE = /<!doctype\s+([^\s]+)\s+public\s+"([^"]+)"\s+"([^"]+)"/i;
|
||||
const SYSTEM_DOCTYPE = /<!doctype\s+([^\s]+)\s+system\s+"([^"]+)"/i;
|
||||
|
||||
function parseDocType(doc, html) {
|
||||
if (HTML5_DOCTYPE.test(html)) {
|
||||
return createDocumentTypeInternal(doc, "html", "", "");
|
||||
}
|
||||
|
||||
const publicPieces = PUBLIC_DOCTYPE.exec(html);
|
||||
if (publicPieces) {
|
||||
return createDocumentTypeInternal(doc, publicPieces[1], publicPieces[2], publicPieces[3]);
|
||||
}
|
||||
|
||||
const systemPieces = SYSTEM_DOCTYPE.exec(html);
|
||||
if (systemPieces) {
|
||||
return createDocumentTypeInternal(doc, systemPieces[1], "", systemPieces[2]);
|
||||
}
|
||||
|
||||
// Shouldn't get here (the parser shouldn't let us know about invalid doctypes), but our logic likely isn't
|
||||
// real-world perfect, so let's fallback.
|
||||
return createDocumentTypeInternal(doc, "html", "", "");
|
||||
}
|
||||
|
||||
function createDocumentTypeInternal(ownerDocument, name, publicId, systemId) {
|
||||
return DocumentType.createImpl([], { ownerDocument, name, publicId, systemId });
|
||||
}
|
13
node_modules/jsdom/lib/jsdom/browser/not-implemented.js
generated
vendored
Normal file
13
node_modules/jsdom/lib/jsdom/browser/not-implemented.js
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = function (nameForErrorMessage, window) {
|
||||
if (!window) {
|
||||
// Do nothing for window-less documents.
|
||||
return;
|
||||
}
|
||||
|
||||
const error = new Error(`Not implemented: ${nameForErrorMessage}`);
|
||||
error.type = "not implemented";
|
||||
|
||||
window._virtualConsole.emit("jsdomError", error);
|
||||
};
|
110
node_modules/jsdom/lib/jsdom/browser/parse5-adapter-parsing.js
generated
vendored
Normal file
110
node_modules/jsdom/lib/jsdom/browser/parse5-adapter-parsing.js
generated
vendored
Normal file
|
@ -0,0 +1,110 @@
|
|||
"use strict";
|
||||
const DocumentType = require("../living/generated/DocumentType");
|
||||
const DocumentFragment = require("../living/generated/DocumentFragment");
|
||||
const Text = require("../living/generated/Text");
|
||||
const Comment = require("../living/generated/Comment");
|
||||
const attributes = require("../living/attributes");
|
||||
const nodeTypes = require("../living/node-type");
|
||||
const serializationAdapter = require("./parse5-adapter-serialization");
|
||||
|
||||
module.exports = class JSDOMParse5Adapter {
|
||||
constructor(documentImpl) {
|
||||
this._documentImpl = documentImpl;
|
||||
}
|
||||
|
||||
createDocument() {
|
||||
// parse5's model assumes that parse(html) will call into here to create the new Document, then return it. However,
|
||||
// jsdom's model assumes we can create a Window (and through that create an empty Document), do some other setup
|
||||
// stuff, and then parse, stuffing nodes into that Document as we go. So to adapt between these two models, we just
|
||||
// return the already-created Document when asked by parse5 to "create" a Document.
|
||||
return this._documentImpl;
|
||||
}
|
||||
|
||||
createDocumentFragment() {
|
||||
return DocumentFragment.createImpl([], { ownerDocument: this._documentImpl });
|
||||
}
|
||||
|
||||
createElement(localName, namespace, attrs) {
|
||||
const element = this._documentImpl._createElementWithCorrectElementInterface(localName, namespace);
|
||||
element._namespaceURI = namespace;
|
||||
this.adoptAttributes(element, attrs);
|
||||
|
||||
if ("_parserInserted" in element) {
|
||||
element._parserInserted = true;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
createCommentNode(data) {
|
||||
return Comment.createImpl([], { data, ownerDocument: this._documentImpl });
|
||||
}
|
||||
|
||||
appendChild(parentNode, newNode) {
|
||||
parentNode.appendChild(newNode);
|
||||
}
|
||||
|
||||
insertBefore(parentNode, newNode, referenceNode) {
|
||||
parentNode.insertBefore(newNode, referenceNode);
|
||||
}
|
||||
|
||||
setTemplateContent(templateElement, contentFragment) {
|
||||
templateElement._templateContents = contentFragment;
|
||||
}
|
||||
|
||||
setDocumentType(document, name, publicId, systemId) {
|
||||
// parse5 sometimes gives us these as null.
|
||||
if (name === null) {
|
||||
name = "";
|
||||
}
|
||||
if (publicId === null) {
|
||||
publicId = "";
|
||||
}
|
||||
if (systemId === null) {
|
||||
systemId = "";
|
||||
}
|
||||
|
||||
const documentType = DocumentType.createImpl([], { name, publicId, systemId, ownerDocument: this._documentImpl });
|
||||
document.appendChild(documentType);
|
||||
}
|
||||
|
||||
setDocumentMode(document, mode) {
|
||||
// TODO: the rest of jsdom ignores this
|
||||
document._mode = mode;
|
||||
}
|
||||
|
||||
detachNode(node) {
|
||||
node.remove();
|
||||
}
|
||||
|
||||
insertText(parentNode, text) {
|
||||
const { lastChild } = parentNode;
|
||||
if (lastChild && lastChild.nodeType === nodeTypes.TEXT_NODE) {
|
||||
lastChild.data += text;
|
||||
} else {
|
||||
const textNode = Text.createImpl([], { data: text, ownerDocument: this._documentImpl });
|
||||
|
||||
parentNode.appendChild(textNode);
|
||||
}
|
||||
}
|
||||
|
||||
insertTextBefore(parentNode, text, referenceNode) {
|
||||
const { previousSibling } = referenceNode;
|
||||
if (previousSibling && previousSibling.nodeType === nodeTypes.TEXT_NODE) {
|
||||
previousSibling.data += text;
|
||||
} else {
|
||||
const textNode = Text.createImpl([], { data: text, ownerDocument: this._documentImpl });
|
||||
|
||||
parentNode.insertBefore(textNode, referenceNode);
|
||||
}
|
||||
}
|
||||
|
||||
adoptAttributes(element, attrs) {
|
||||
for (const attr of attrs) {
|
||||
const prefix = attr.prefix === "" ? null : attr.prefix;
|
||||
attributes.setAttributeValue(element, attr.name, attr.value, prefix, attr.namespace);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Object.assign(module.exports.prototype, serializationAdapter);
|
41
node_modules/jsdom/lib/jsdom/browser/parse5-adapter-serialization.js
generated
vendored
Normal file
41
node_modules/jsdom/lib/jsdom/browser/parse5-adapter-serialization.js
generated
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
"use strict";
|
||||
const idlUtils = require("../living/generated/utils");
|
||||
const nodeTypes = require("../living/node-type");
|
||||
const { domSymbolTree } = require("../living/helpers/internal-constants");
|
||||
// Serialization only requires a subset of the tree adapter interface.
|
||||
|
||||
// Tree traversing
|
||||
exports.getFirstChild = node => node.firstChild;
|
||||
|
||||
exports.getChildNodes = node => node.childNodesForSerializing || domSymbolTree.childrenToArray(node);
|
||||
|
||||
exports.getParentNode = node => node.parentNode;
|
||||
|
||||
exports.getAttrList = node => idlUtils.wrapperForImpl(node._attributes);
|
||||
|
||||
// Node data
|
||||
exports.getTagName = element => element._qualifiedName; // https://github.com/inikulin/parse5/issues/231
|
||||
|
||||
exports.getNamespaceURI = element => element.namespaceURI;
|
||||
|
||||
exports.getTextNodeContent = exports.getCommentNodeContent = node => node.data;
|
||||
|
||||
exports.getDocumentTypeNodeName = node => node.name;
|
||||
|
||||
exports.getDocumentTypeNodePublicId = node => node.publicId;
|
||||
|
||||
exports.getDocumentTypeNodeSystemId = node => node.systemId;
|
||||
|
||||
exports.getTemplateContent = templateElement => templateElement._templateContents;
|
||||
|
||||
exports.getDocumentMode = document => document._mode;
|
||||
|
||||
// Node types
|
||||
|
||||
exports.isTextNode = node => node.nodeType === nodeTypes.TEXT_NODE;
|
||||
|
||||
exports.isCommentNode = node => node.nodeType === nodeTypes.COMMENT_NODE;
|
||||
|
||||
exports.isDocumentTypeNode = node => node.nodeType === nodeTypes.DOCUMENT_TYPE_NODE;
|
||||
|
||||
exports.isElementNode = node => node.nodeType === nodeTypes.ELEMENT_NODE;
|
275
node_modules/jsdom/lib/jsdom/browser/resource-loader.js
generated
vendored
Normal file
275
node_modules/jsdom/lib/jsdom/browser/resource-loader.js
generated
vendored
Normal file
|
@ -0,0 +1,275 @@
|
|||
"use strict";
|
||||
|
||||
const MIMEType = require("whatwg-mimetype");
|
||||
const parseDataURL = require("data-urls");
|
||||
const sniffHTMLEncoding = require("html-encoding-sniffer");
|
||||
const whatwgEncoding = require("whatwg-encoding");
|
||||
const fs = require("fs");
|
||||
const request = require("request");
|
||||
const { documentBaseURLSerialized } = require("../living/helpers/document-base-url");
|
||||
const NODE_TYPE = require("../living/node-type");
|
||||
|
||||
/* eslint-disable no-restricted-modules */
|
||||
// TODO: stop using the built-in URL in favor of the spec-compliant whatwg-url package
|
||||
// This legacy usage is in the process of being purged.
|
||||
const URL = require("url");
|
||||
/* eslint-enable no-restricted-modules */
|
||||
|
||||
const IS_BROWSER = Object.prototype.toString.call(process) !== "[object process]";
|
||||
|
||||
function createResourceLoadHandler(element, resourceUrl, document, loadCallback) {
|
||||
if (loadCallback === undefined) {
|
||||
loadCallback = () => {
|
||||
// do nothing
|
||||
};
|
||||
}
|
||||
return (err, data, response) => {
|
||||
const ev = document.createEvent("HTMLEvents");
|
||||
|
||||
if (!err) {
|
||||
try {
|
||||
loadCallback.call(element, data, resourceUrl, response);
|
||||
ev.initEvent("load", false, false);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
if (!err.isAbortError) {
|
||||
ev.initEvent("error", false, false);
|
||||
ev.error = err;
|
||||
element.dispatchEvent(ev);
|
||||
|
||||
const error = new Error(`Could not load ${element.localName}: "${resourceUrl}"`);
|
||||
error.detail = err;
|
||||
error.type = "resource loading";
|
||||
|
||||
document._defaultView._virtualConsole.emit("jsdomError", error);
|
||||
}
|
||||
} else {
|
||||
element.dispatchEvent(ev);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
exports.readFile = function (filePath, { defaultEncoding, detectMetaCharset }, callback) {
|
||||
const readableStream = fs.createReadStream(filePath);
|
||||
|
||||
let data = Buffer.alloc(0);
|
||||
|
||||
readableStream.on("error", callback);
|
||||
|
||||
readableStream.on("data", chunk => {
|
||||
data = Buffer.concat([data, chunk]);
|
||||
});
|
||||
|
||||
readableStream.on("end", () => {
|
||||
// Not passing default encoding means binary
|
||||
if (defaultEncoding) {
|
||||
const encoding = detectMetaCharset ?
|
||||
sniffHTMLEncoding(data, { defaultEncoding }) :
|
||||
whatwgEncoding.getBOMEncoding(data) || defaultEncoding;
|
||||
const decoded = whatwgEncoding.decode(data, encoding);
|
||||
callback(null, decoded, { headers: { "content-type": "text/plain;charset=" + encoding } });
|
||||
} else {
|
||||
callback(null, data);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
abort() {
|
||||
readableStream.destroy();
|
||||
const error = new Error("request canceled by user");
|
||||
error.isAbortError = true;
|
||||
callback(error);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
function readDataURL(dataURL, { defaultEncoding, detectMetaCharset }, callback) {
|
||||
try {
|
||||
const parsed = parseDataURL(dataURL);
|
||||
// If default encoding does not exist, pass on binary data.
|
||||
if (defaultEncoding) {
|
||||
const sniffOptions = {
|
||||
transportLayerEncodingLabel: parsed.mimeType.parameters.get("charset"),
|
||||
defaultEncoding
|
||||
};
|
||||
|
||||
const encoding = detectMetaCharset ?
|
||||
sniffHTMLEncoding(parsed.body, sniffOptions) :
|
||||
whatwgEncoding.getBOMEncoding(parsed.body) ||
|
||||
whatwgEncoding.labelToName(parsed.mimeType.parameters.get("charset")) ||
|
||||
defaultEncoding;
|
||||
const decoded = whatwgEncoding.decode(parsed.body, encoding);
|
||||
|
||||
parsed.mimeType.parameters.set("charset", encoding);
|
||||
|
||||
callback(null, decoded, { headers: { "content-type": parsed.mimeType.toString() } });
|
||||
} else {
|
||||
callback(null, parsed.body, { headers: { "content-type": parsed.mimeType.toString() } });
|
||||
}
|
||||
} catch (err) {
|
||||
callback(err, null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// NOTE: request wraps tough-cookie cookie jar
|
||||
// (see: https://github.com/request/request/blob/master/lib/cookies.js).
|
||||
// Therefore, to pass our cookie jar to the request, we need to create
|
||||
// request's wrapper and monkey patch it with our jar.
|
||||
exports.wrapCookieJarForRequest = cookieJar => {
|
||||
const jarWrapper = request.jar();
|
||||
jarWrapper._jar = cookieJar;
|
||||
return jarWrapper;
|
||||
};
|
||||
|
||||
function fetch(urlObj, options, callback) {
|
||||
if (urlObj.protocol === "data:") {
|
||||
return readDataURL(urlObj.href, options, callback);
|
||||
} else if (urlObj.hostname) {
|
||||
return exports.download(urlObj, options, callback);
|
||||
}
|
||||
const filePath = urlObj.pathname
|
||||
.replace(/^file:\/\//, "")
|
||||
.replace(/^\/([a-z]):\//i, "$1:/")
|
||||
.replace(/%20/g, " ");
|
||||
return exports.readFile(filePath, options, callback);
|
||||
}
|
||||
|
||||
exports.enqueue = function (element, resourceUrl, callback) {
|
||||
const document = element.nodeType === NODE_TYPE.DOCUMENT_NODE ? element : element._ownerDocument;
|
||||
|
||||
if (document._queue) {
|
||||
const loadHandler = createResourceLoadHandler(element, resourceUrl || document.URL, document, callback);
|
||||
return document._queue.push(loadHandler);
|
||||
}
|
||||
|
||||
return () => {
|
||||
// do nothing in queue-less documents
|
||||
};
|
||||
};
|
||||
|
||||
exports.download = function (url, options, callback) {
|
||||
const requestOptions = {
|
||||
pool: options.pool,
|
||||
agent: options.agent,
|
||||
agentOptions: options.agentOptions,
|
||||
agentClass: options.agentClass,
|
||||
strictSSL: options.strictSSL,
|
||||
gzip: true,
|
||||
jar: exports.wrapCookieJarForRequest(options.cookieJar),
|
||||
encoding: null,
|
||||
headers: {
|
||||
"User-Agent": options.userAgent,
|
||||
"Accept-Language": "en",
|
||||
Accept: options.accept || "*/*"
|
||||
}
|
||||
};
|
||||
if (options.referrer && !IS_BROWSER) {
|
||||
requestOptions.headers.referer = options.referrer;
|
||||
}
|
||||
if (options.proxy) {
|
||||
requestOptions.proxy = options.proxy;
|
||||
}
|
||||
Object.assign(requestOptions.headers, options.headers);
|
||||
|
||||
const { defaultEncoding, detectMetaCharset } = options;
|
||||
|
||||
const req = request(url, requestOptions, (error, response, bufferData) => {
|
||||
if (!error) {
|
||||
// If default encoding does not exist, pass on binary data.
|
||||
if (defaultEncoding) {
|
||||
const contentType = MIMEType.parse(response.headers["content-type"]) || new MIMEType("text/plain");
|
||||
const sniffOptions = {
|
||||
transportLayerEncodingLabel: contentType.parameters.get("charset"),
|
||||
defaultEncoding
|
||||
};
|
||||
|
||||
const encoding = detectMetaCharset ?
|
||||
sniffHTMLEncoding(bufferData, sniffOptions) :
|
||||
whatwgEncoding.getBOMEncoding(bufferData) ||
|
||||
whatwgEncoding.labelToName(contentType.parameters.get("charset")) ||
|
||||
defaultEncoding;
|
||||
const decoded = whatwgEncoding.decode(bufferData, encoding);
|
||||
|
||||
contentType.parameters.set("charset", encoding);
|
||||
response.headers["content-type"] = contentType.toString();
|
||||
|
||||
callback(null, decoded, response);
|
||||
} else {
|
||||
callback(null, bufferData, response);
|
||||
}
|
||||
} else {
|
||||
callback(error, null, response);
|
||||
}
|
||||
});
|
||||
return {
|
||||
abort() {
|
||||
req.abort();
|
||||
const error = new Error("request canceled by user");
|
||||
error.isAbortError = true;
|
||||
callback(error);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
exports.load = function (element, urlString, options, callback) {
|
||||
const document = element._ownerDocument;
|
||||
const documentImpl = document.implementation;
|
||||
|
||||
if (!documentImpl._hasFeature("FetchExternalResources", element.tagName.toLowerCase())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (documentImpl._hasFeature("SkipExternalResources", urlString)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const urlObj = URL.parse(urlString);
|
||||
const enqueued = exports.enqueue(element, urlString, callback);
|
||||
const customLoader = document._customResourceLoader;
|
||||
const requestManager = document._requestManager;
|
||||
const cookieJar = document._cookieJar;
|
||||
|
||||
options.accept = element._accept;
|
||||
options.cookieJar = cookieJar;
|
||||
options.referrer = document.URL;
|
||||
options.pool = document._pool;
|
||||
options.agentOptions = document._agentOptions;
|
||||
options.strictSSL = document._strictSSL;
|
||||
options.proxy = document._proxy;
|
||||
options.userAgent = document._defaultView.navigator.userAgent;
|
||||
|
||||
let req = null;
|
||||
function wrappedEnqueued() {
|
||||
if (req && requestManager) {
|
||||
requestManager.remove(req);
|
||||
}
|
||||
// do not trigger if the window is closed
|
||||
if (element._ownerDocument && element._ownerDocument.defaultView.document) {
|
||||
enqueued.apply(this, arguments);
|
||||
}
|
||||
}
|
||||
if (typeof customLoader === "function") {
|
||||
req = customLoader(
|
||||
{
|
||||
element,
|
||||
url: urlObj,
|
||||
cookie: cookieJar.getCookieStringSync(urlObj, { http: true }),
|
||||
baseUrl: documentBaseURLSerialized(document),
|
||||
defaultFetch(fetchCallback) {
|
||||
return fetch(urlObj, options, fetchCallback);
|
||||
}
|
||||
},
|
||||
wrappedEnqueued
|
||||
);
|
||||
} else {
|
||||
req = fetch(urlObj, options, wrappedEnqueued);
|
||||
}
|
||||
if (req && requestManager) {
|
||||
requestManager.add(req);
|
||||
}
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue