Add node modules and new code for release (#39)
Co-authored-by: tbarnes94 <tbarnes94@users.noreply.github.com>
This commit is contained in:
parent
a10d84bc2e
commit
7ad2aa66bb
7655 changed files with 1763577 additions and 14 deletions
793
node_modules/jsdom/lib/jsdom/browser/Window.js
generated
vendored
Normal file
793
node_modules/jsdom/lib/jsdom/browser/Window.js
generated
vendored
Normal file
|
@ -0,0 +1,793 @@
|
|||
"use strict";
|
||||
const vm = require("vm");
|
||||
const webIDLConversions = require("webidl-conversions");
|
||||
const { CSSStyleDeclaration } = require("cssstyle");
|
||||
const { Performance: RawPerformance } = require("w3c-hr-time");
|
||||
const notImplemented = require("./not-implemented");
|
||||
const { installInterfaces } = require("../living/interfaces");
|
||||
const { define, mixin } = require("../utils");
|
||||
const Element = require("../living/generated/Element");
|
||||
const EventTarget = require("../living/generated/EventTarget");
|
||||
const PageTransitionEvent = require("../living/generated/PageTransitionEvent");
|
||||
const namedPropertiesWindow = require("../living/named-properties-window");
|
||||
const postMessage = require("../living/post-message");
|
||||
const DOMException = require("domexception/webidl2js-wrapper");
|
||||
const { btoa, atob } = require("abab");
|
||||
const idlUtils = require("../living/generated/utils");
|
||||
const WebSocketImpl = require("../living/websockets/WebSocket-impl").implementation;
|
||||
const BarProp = require("../living/generated/BarProp");
|
||||
const documents = require("../living/documents.js");
|
||||
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 Selection = require("../living/generated/Selection");
|
||||
const reportException = require("../living/helpers/runtime-script-errors");
|
||||
const { fireAnEvent } = require("../living/helpers/events");
|
||||
const SessionHistory = require("../living/window/SessionHistory");
|
||||
const { forEachMatchingSheetRuleOfElement, getResolvedValue, propertiesWithResolvedValueImplemented,
|
||||
SHADOW_DOM_PSEUDO_REGEXP } = require("../living/helpers/style-rules.js");
|
||||
const CustomElementRegistry = require("../living/generated/CustomElementRegistry");
|
||||
const jsGlobals = require("./js-globals.json");
|
||||
|
||||
const GlobalEventHandlersImpl = require("../living/nodes/GlobalEventHandlers-impl").implementation;
|
||||
const WindowEventHandlersImpl = require("../living/nodes/WindowEventHandlers-impl").implementation;
|
||||
|
||||
exports.createWindow = function (options) {
|
||||
return new Window(options);
|
||||
};
|
||||
|
||||
const jsGlobalEntriesToInstall = Object.entries(jsGlobals).filter(([name]) => name in global);
|
||||
|
||||
// https://html.spec.whatwg.org/#the-window-object
|
||||
function setupWindow(windowInstance, { runScripts }) {
|
||||
if (runScripts === "outside-only" || runScripts === "dangerously") {
|
||||
contextifyWindow(windowInstance);
|
||||
|
||||
// Without this, these globals will only appear to scripts running inside the context using vm.runScript; they will
|
||||
// not appear to scripts running from the outside, including to JSDOM implementation code.
|
||||
for (const [globalName, globalPropDesc] of jsGlobalEntriesToInstall) {
|
||||
const propDesc = { ...globalPropDesc, value: vm.runInContext(globalName, windowInstance) };
|
||||
Object.defineProperty(windowInstance, globalName, propDesc);
|
||||
}
|
||||
} else {
|
||||
// Without contextifying the window, none of the globals will exist. So, let's at least alias them from the Node.js
|
||||
// context. See https://github.com/jsdom/jsdom/issues/2727 for more background and discussion.
|
||||
for (const [globalName, globalPropDesc] of jsGlobalEntriesToInstall) {
|
||||
const propDesc = { ...globalPropDesc, value: global[globalName] };
|
||||
Object.defineProperty(windowInstance, globalName, propDesc);
|
||||
}
|
||||
}
|
||||
|
||||
installInterfaces(windowInstance, ["Window"]);
|
||||
|
||||
const EventTargetConstructor = windowInstance.EventTarget;
|
||||
|
||||
// eslint-disable-next-line func-name-matching, func-style, no-shadow
|
||||
const windowConstructor = function Window() {
|
||||
throw new TypeError("Illegal constructor");
|
||||
};
|
||||
Object.setPrototypeOf(windowConstructor, EventTargetConstructor);
|
||||
|
||||
Object.defineProperty(windowInstance, "Window", {
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: windowConstructor
|
||||
});
|
||||
|
||||
const windowPrototype = Object.create(EventTargetConstructor.prototype);
|
||||
Object.defineProperties(windowPrototype, {
|
||||
constructor: {
|
||||
value: windowConstructor,
|
||||
writable: true,
|
||||
configurable: true
|
||||
},
|
||||
[Symbol.toStringTag]: {
|
||||
value: "Window",
|
||||
configurable: true
|
||||
}
|
||||
});
|
||||
|
||||
windowConstructor.prototype = windowPrototype;
|
||||
Object.setPrototypeOf(windowInstance, windowPrototype);
|
||||
|
||||
EventTarget.setup(windowInstance, windowInstance);
|
||||
mixin(windowInstance, WindowEventHandlersImpl.prototype);
|
||||
mixin(windowInstance, GlobalEventHandlersImpl.prototype);
|
||||
windowInstance._initGlobalEvents();
|
||||
|
||||
windowInstance._globalObject = windowInstance;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
setupWindow(this, { runScripts: options.runScripts });
|
||||
|
||||
const rawPerformance = new RawPerformance();
|
||||
const windowInitialized = rawPerformance.now();
|
||||
|
||||
const window = this;
|
||||
|
||||
///// PRIVATE DATA PROPERTIES
|
||||
|
||||
this._resourceLoader = options.resourceLoader;
|
||||
|
||||
// vm initialization is deferred until script processing is activated
|
||||
this._globalProxy = this;
|
||||
Object.defineProperty(idlUtils.implForWrapper(this), idlUtils.wrapperSymbol, { get: () => this._globalProxy });
|
||||
|
||||
// List options explicitly to be clear which are passed through
|
||||
this._document = documents.createWrapper(window, {
|
||||
parsingMode: options.parsingMode,
|
||||
contentType: options.contentType,
|
||||
encoding: options.encoding,
|
||||
cookieJar: options.cookieJar,
|
||||
url: options.url,
|
||||
lastModified: options.lastModified,
|
||||
referrer: options.referrer,
|
||||
concurrentNodeIterators: options.concurrentNodeIterators,
|
||||
parseOptions: options.parseOptions,
|
||||
defaultView: this._globalProxy,
|
||||
global: this
|
||||
}, { alwaysUseDocumentClass: true });
|
||||
|
||||
if (vm.isContext(window)) {
|
||||
const documentImpl = idlUtils.implForWrapper(window._document);
|
||||
documentImpl._defaultView = window._globalProxy = vm.runInContext("this", window);
|
||||
}
|
||||
|
||||
const documentOrigin = idlUtils.implForWrapper(this._document)._origin;
|
||||
this._origin = documentOrigin;
|
||||
|
||||
// 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);
|
||||
|
||||
this._virtualConsole = options.virtualConsole;
|
||||
|
||||
this._runScripts = options.runScripts;
|
||||
|
||||
// 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[documentOrigin]) {
|
||||
this._commonForOrigin = options.commonForOrigin;
|
||||
} else {
|
||||
this._commonForOrigin = {
|
||||
[documentOrigin]: {
|
||||
localStorageArea: new Map(),
|
||||
sessionStorageArea: new Map(),
|
||||
windowsInSameOrigin: [this]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
this._currentOriginData = this._commonForOrigin[documentOrigin];
|
||||
|
||||
///// WEB STORAGE
|
||||
|
||||
this._localStorage = Storage.create(window, [], {
|
||||
associatedWindow: this,
|
||||
storageArea: this._currentOriginData.localStorageArea,
|
||||
type: "localStorage",
|
||||
url: this._document.documentURI,
|
||||
storageQuota: this._storageQuota
|
||||
});
|
||||
this._sessionStorage = Storage.create(window, [], {
|
||||
associatedWindow: this,
|
||||
storageArea: this._currentOriginData.sessionStorageArea,
|
||||
type: "sessionStorage",
|
||||
url: this._document.documentURI,
|
||||
storageQuota: this._storageQuota
|
||||
});
|
||||
|
||||
///// SELECTION
|
||||
|
||||
// https://w3c.github.io/selection-api/#dfn-selection
|
||||
this._selection = Selection.createImpl(window);
|
||||
|
||||
// https://w3c.github.io/selection-api/#dom-window
|
||||
this.getSelection = function () {
|
||||
return window._selection;
|
||||
};
|
||||
|
||||
///// GETTERS
|
||||
|
||||
const locationbar = BarProp.create(window);
|
||||
const menubar = BarProp.create(window);
|
||||
const personalbar = BarProp.create(window);
|
||||
const scrollbars = BarProp.create(window);
|
||||
const statusbar = BarProp.create(window);
|
||||
const toolbar = BarProp.create(window);
|
||||
const external = External.create(window);
|
||||
const navigator = Navigator.create(window, [], { userAgent: this._resourceLoader._userAgent });
|
||||
const performance = Performance.create(window, [], { rawPerformance });
|
||||
const screen = Screen.create(window);
|
||||
const customElementRegistry = CustomElementRegistry.create(window);
|
||||
|
||||
define(this, {
|
||||
get length() {
|
||||
return window._length;
|
||||
},
|
||||
get window() {
|
||||
return window._globalProxy;
|
||||
},
|
||||
get frameElement() {
|
||||
return idlUtils.wrapperForImpl(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 origin() {
|
||||
return window._origin;
|
||||
},
|
||||
// The origin IDL attribute is defined with [Replaceable].
|
||||
set origin(value) {
|
||||
Object.defineProperty(this, "origin", {
|
||||
value,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
},
|
||||
get localStorage() {
|
||||
if (idlUtils.implForWrapper(this._document)._origin === "null") {
|
||||
throw DOMException.create(window, [
|
||||
"localStorage is not available for opaque origins",
|
||||
"SecurityError"
|
||||
]);
|
||||
}
|
||||
|
||||
return this._localStorage;
|
||||
},
|
||||
get sessionStorage() {
|
||||
if (idlUtils.implForWrapper(this._document)._origin === "null") {
|
||||
throw DOMException.create(window, [
|
||||
"sessionStorage is not available for opaque origins",
|
||||
"SecurityError"
|
||||
]);
|
||||
}
|
||||
|
||||
return this._sessionStorage;
|
||||
},
|
||||
get customElements() {
|
||||
return customElementRegistry;
|
||||
}
|
||||
});
|
||||
|
||||
namedPropertiesWindow.initializeWindow(this, this._globalProxy);
|
||||
|
||||
///// METHODS
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers
|
||||
|
||||
// In the spec the list of active timers is a set of IDs. We make it a map of IDs to Node.js timer objects, so that
|
||||
// we can call Node.js-side clearTimeout() when clearing, and thus allow process shutdown faster.
|
||||
const listOfActiveTimers = new Map();
|
||||
let latestTimerId = 0;
|
||||
|
||||
this.setTimeout = function (handler, timeout = 0, ...args) {
|
||||
if (typeof handler !== "function") {
|
||||
handler = webIDLConversions.DOMString(handler);
|
||||
}
|
||||
timeout = webIDLConversions.long(timeout);
|
||||
|
||||
return timerInitializationSteps(handler, timeout, args, { methodContext: window, repeat: false });
|
||||
};
|
||||
this.setInterval = function (handler, timeout = 0, ...args) {
|
||||
if (typeof handler !== "function") {
|
||||
handler = webIDLConversions.DOMString(handler);
|
||||
}
|
||||
timeout = webIDLConversions.long(timeout);
|
||||
|
||||
return timerInitializationSteps(handler, timeout, args, { methodContext: window, repeat: true });
|
||||
};
|
||||
|
||||
this.clearTimeout = function (handle = 0) {
|
||||
handle = webIDLConversions.long(handle);
|
||||
|
||||
const nodejsTimer = listOfActiveTimers.get(handle);
|
||||
if (nodejsTimer) {
|
||||
clearTimeout(nodejsTimer);
|
||||
listOfActiveTimers.delete(handle);
|
||||
}
|
||||
};
|
||||
this.clearInterval = function (handle = 0) {
|
||||
handle = webIDLConversions.long(handle);
|
||||
|
||||
const nodejsTimer = listOfActiveTimers.get(handle);
|
||||
if (nodejsTimer) {
|
||||
// We use setTimeout() in timerInitializationSteps even for this.setInterval().
|
||||
clearTimeout(nodejsTimer);
|
||||
listOfActiveTimers.delete(handle);
|
||||
}
|
||||
};
|
||||
|
||||
function timerInitializationSteps(handler, timeout, args, { methodContext, repeat, previousHandle }) {
|
||||
// This appears to be unspecced, but matches browser behavior for close()ed windows.
|
||||
if (!methodContext._document) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: implement timer nesting level behavior.
|
||||
|
||||
const methodContextProxy = methodContext._globalProxy;
|
||||
const handle = previousHandle !== undefined ? previousHandle : ++latestTimerId;
|
||||
|
||||
function task() {
|
||||
if (!listOfActiveTimers.has(handle)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (typeof handler === "function") {
|
||||
handler.apply(methodContextProxy, args);
|
||||
} else if (window._runScripts === "dangerously") {
|
||||
vm.runInContext(handler, window, { filename: window.location.href, displayErrors: false });
|
||||
}
|
||||
} catch (e) {
|
||||
reportException(window, e, window.location.href);
|
||||
}
|
||||
|
||||
if (listOfActiveTimers.has(handle)) {
|
||||
if (repeat) {
|
||||
timerInitializationSteps(handler, timeout, args, { methodContext, repeat: true, previousHandle: handle });
|
||||
} else {
|
||||
listOfActiveTimers.delete(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout < 0) {
|
||||
timeout = 0;
|
||||
}
|
||||
|
||||
const nodejsTimer = setTimeout(task, timeout);
|
||||
listOfActiveTimers.set(handle, nodejsTimer);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#animation-frames
|
||||
|
||||
let animationFrameCallbackId = 0;
|
||||
const mapOfAnimationFrameCallbacks = new Map();
|
||||
let animationFrameNodejsInterval = null;
|
||||
|
||||
// Unlike the spec, where an animation frame happens every 60 Hz regardless, we optimize so that if there are no
|
||||
// requestAnimationFrame() calls outstanding, we don't fire the timer. This helps us track that.
|
||||
let numberOfOngoingAnimationFrameCallbacks = 0;
|
||||
|
||||
if (this._pretendToBeVisual) {
|
||||
this.requestAnimationFrame = function (callback) {
|
||||
callback = webIDLConversions.Function(callback);
|
||||
|
||||
const handle = ++animationFrameCallbackId;
|
||||
mapOfAnimationFrameCallbacks.set(handle, callback);
|
||||
|
||||
++numberOfOngoingAnimationFrameCallbacks;
|
||||
if (numberOfOngoingAnimationFrameCallbacks === 1) {
|
||||
animationFrameNodejsInterval = setInterval(() => {
|
||||
runAnimationFrameCallbacks(rawPerformance.now() - windowInitialized);
|
||||
}, 1000 / 60);
|
||||
}
|
||||
|
||||
return handle;
|
||||
};
|
||||
|
||||
this.cancelAnimationFrame = function (handle) {
|
||||
handle = webIDLConversions["unsigned long"](handle);
|
||||
|
||||
removeAnimationFrameCallback(handle);
|
||||
};
|
||||
|
||||
function runAnimationFrameCallbacks(now) {
|
||||
// Converting to an array is important to get a sync snapshot and thus match spec semantics.
|
||||
const callbackHandles = [...mapOfAnimationFrameCallbacks.keys()];
|
||||
for (const handle of callbackHandles) {
|
||||
// This has() can be false if a callback calls cancelAnimationFrame().
|
||||
if (mapOfAnimationFrameCallbacks.has(handle)) {
|
||||
const callback = mapOfAnimationFrameCallbacks.get(handle);
|
||||
removeAnimationFrameCallback(handle);
|
||||
try {
|
||||
callback(now);
|
||||
} catch (e) {
|
||||
reportException(window, e, window.location.href);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function removeAnimationFrameCallback(handle) {
|
||||
if (mapOfAnimationFrameCallbacks.has(handle)) {
|
||||
--numberOfOngoingAnimationFrameCallbacks;
|
||||
if (numberOfOngoingAnimationFrameCallbacks === 0) {
|
||||
clearInterval(animationFrameNodejsInterval);
|
||||
}
|
||||
}
|
||||
|
||||
mapOfAnimationFrameCallbacks.delete(handle);
|
||||
}
|
||||
}
|
||||
|
||||
function stopAllTimers() {
|
||||
for (const nodejsTimer of listOfActiveTimers.values()) {
|
||||
clearTimeout(nodejsTimer);
|
||||
}
|
||||
listOfActiveTimers.clear();
|
||||
|
||||
clearInterval(animationFrameNodejsInterval);
|
||||
}
|
||||
|
||||
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.setAttributeNS(null, "value", value);
|
||||
}
|
||||
if (defaultSelected) {
|
||||
impl.setAttributeNS(null, "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.setAttributeNS(null, "width", String(arguments[0]));
|
||||
}
|
||||
if (arguments.length > 1) {
|
||||
impl.setAttributeNS(null, "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.setAttributeNS(null, "preload", "auto");
|
||||
|
||||
if (src !== undefined) {
|
||||
impl.setAttributeNS(null, "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
|
||||
});
|
||||
|
||||
this.postMessage = postMessage(window);
|
||||
|
||||
this.atob = function (str) {
|
||||
const result = atob(str);
|
||||
if (result === null) {
|
||||
throw DOMException.create(window, [
|
||||
"The string to be decoded contains invalid characters.",
|
||||
"InvalidCharacterError"
|
||||
]);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
this.btoa = function (str) {
|
||||
const result = btoa(str);
|
||||
if (result === null) {
|
||||
throw DOMException.create(window, [
|
||||
"The string to be encoded contains invalid characters.",
|
||||
"InvalidCharacterError"
|
||||
]);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
this.stop = function () {
|
||||
const manager = idlUtils.implForWrapper(this._document)._requestManager;
|
||||
if (manager) {
|
||||
manager.close();
|
||||
}
|
||||
};
|
||||
|
||||
this.close = function () {
|
||||
// Recursively close child frame windows, then ourselves (depth-first).
|
||||
for (let i = 0; i < this.length; ++i) {
|
||||
this[i].close();
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
stopAllTimers();
|
||||
WebSocketImpl.cleanUpWindow(this);
|
||||
};
|
||||
|
||||
this.getComputedStyle = function (elt) {
|
||||
elt = Element.convert(elt);
|
||||
let pseudoElt = arguments[1];
|
||||
if (pseudoElt !== undefined && pseudoElt !== null) {
|
||||
pseudoElt = webIDLConversions.DOMString(pseudoElt);
|
||||
}
|
||||
|
||||
if (pseudoElt !== undefined && pseudoElt !== null && pseudoElt !== "") {
|
||||
// TODO: Parse pseudoElt
|
||||
|
||||
if (SHADOW_DOM_PSEUDO_REGEXP.test(pseudoElt)) {
|
||||
throw new TypeError("Tried to get the computed style of a Shadow DOM pseudo-element.");
|
||||
}
|
||||
|
||||
notImplemented("window.computedStyle(elt, pseudoElt)", this);
|
||||
}
|
||||
|
||||
const declaration = new CSSStyleDeclaration();
|
||||
const { forEach } = Array.prototype;
|
||||
const { style } = elt;
|
||||
|
||||
forEachMatchingSheetRuleOfElement(elt, rule => {
|
||||
forEach.call(rule.style, property => {
|
||||
declaration.setProperty(
|
||||
property,
|
||||
rule.style.getPropertyValue(property),
|
||||
rule.style.getPropertyPriority(property)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// https://drafts.csswg.org/cssom/#dom-window-getcomputedstyle
|
||||
const declarations = Object.keys(propertiesWithResolvedValueImplemented);
|
||||
forEach.call(declarations, property => {
|
||||
declaration.setProperty(property, getResolvedValue(elt, property));
|
||||
});
|
||||
|
||||
forEach.call(style, property => {
|
||||
declaration.setProperty(property, style.getPropertyValue(property), style.getPropertyPriority(property));
|
||||
});
|
||||
|
||||
return declaration;
|
||||
};
|
||||
|
||||
this.getSelection = function () {
|
||||
return window._document.getSelection();
|
||||
};
|
||||
|
||||
// The captureEvents() and releaseEvents() methods must do nothing
|
||||
this.captureEvents = function () {};
|
||||
|
||||
this.releaseEvents = function () {};
|
||||
|
||||
///// PUBLIC DATA PROPERTIES (TODO: should be getters)
|
||||
|
||||
function wrapConsoleMethod(method) {
|
||||
return (...args) => {
|
||||
window._virtualConsole.emit(method, ...args);
|
||||
};
|
||||
}
|
||||
|
||||
this.console = {
|
||||
assert: wrapConsoleMethod("assert"),
|
||||
clear: wrapConsoleMethod("clear"),
|
||||
count: wrapConsoleMethod("count"),
|
||||
countReset: wrapConsoleMethod("countReset"),
|
||||
debug: wrapConsoleMethod("debug"),
|
||||
dir: wrapConsoleMethod("dir"),
|
||||
dirxml: wrapConsoleMethod("dirxml"),
|
||||
error: wrapConsoleMethod("error"),
|
||||
group: wrapConsoleMethod("group"),
|
||||
groupCollapsed: wrapConsoleMethod("groupCollapsed"),
|
||||
groupEnd: wrapConsoleMethod("groupEnd"),
|
||||
info: wrapConsoleMethod("info"),
|
||||
log: wrapConsoleMethod("log"),
|
||||
table: wrapConsoleMethod("table"),
|
||||
time: wrapConsoleMethod("time"),
|
||||
timeLog: wrapConsoleMethod("timeLog"),
|
||||
timeEnd: wrapConsoleMethod("timeEnd"),
|
||||
trace: wrapConsoleMethod("trace"),
|
||||
warn: wrapConsoleMethod("warn")
|
||||
};
|
||||
|
||||
function notImplementedMethod(name) {
|
||||
return function () {
|
||||
notImplemented(name, window);
|
||||
};
|
||||
}
|
||||
|
||||
define(this, {
|
||||
name: "",
|
||||
status: "",
|
||||
devicePixelRatio: 1,
|
||||
innerWidth: 1024,
|
||||
innerHeight: 768,
|
||||
outerWidth: 1024,
|
||||
outerHeight: 768,
|
||||
pageXOffset: 0,
|
||||
pageYOffset: 0,
|
||||
screenX: 0,
|
||||
screenLeft: 0,
|
||||
screenY: 0,
|
||||
screenTop: 0,
|
||||
scrollX: 0,
|
||||
scrollY: 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") {
|
||||
fireAnEvent("load", window, undefined, {}, window.document);
|
||||
} else {
|
||||
window.document.addEventListener("load", () => {
|
||||
fireAnEvent("load", window, undefined, {}, window.document);
|
||||
|
||||
if (!idlUtils.implForWrapper(window._document)._pageShowingFlag) {
|
||||
idlUtils.implForWrapper(window._document)._pageShowingFlag = true;
|
||||
fireAnEvent("pageshow", window, PageTransitionEvent, { persisted: false }, window.document);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function contextifyWindow(window) {
|
||||
if (vm.isContext(window)) {
|
||||
return;
|
||||
}
|
||||
|
||||
vm.createContext(window);
|
||||
}
|
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. */
|
||||
|
||||
`;
|
292
node_modules/jsdom/lib/jsdom/browser/js-globals.json
generated
vendored
Normal file
292
node_modules/jsdom/lib/jsdom/browser/js-globals.json
generated
vendored
Normal file
|
@ -0,0 +1,292 @@
|
|||
{
|
||||
"Object": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Function": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Array": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Number": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"parseFloat": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"parseInt": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Infinity": {
|
||||
"writable": false,
|
||||
"enumerable": false,
|
||||
"configurable": false
|
||||
},
|
||||
"NaN": {
|
||||
"writable": false,
|
||||
"enumerable": false,
|
||||
"configurable": false
|
||||
},
|
||||
"undefined": {
|
||||
"writable": false,
|
||||
"enumerable": false,
|
||||
"configurable": false
|
||||
},
|
||||
"Boolean": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"String": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Symbol": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Date": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Promise": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"RegExp": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Error": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"EvalError": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"RangeError": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"ReferenceError": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"SyntaxError": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"TypeError": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"URIError": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"globalThis": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"JSON": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Math": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Intl": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"ArrayBuffer": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Uint8Array": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Int8Array": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Uint16Array": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Int16Array": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Uint32Array": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Int32Array": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Float32Array": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Float64Array": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Uint8ClampedArray": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"BigUint64Array": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"BigInt64Array": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"DataView": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Map": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"BigInt": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Set": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"WeakMap": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"WeakSet": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Proxy": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Reflect": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"decodeURI": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"decodeURIComponent": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"encodeURI": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"encodeURIComponent": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"escape": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"unescape": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"eval": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"isFinite": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"isNaN": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"SharedArrayBuffer": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"Atomics": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
},
|
||||
"WebAssembly": {
|
||||
"writable": true,
|
||||
"enumerable": false,
|
||||
"configurable": true
|
||||
}
|
||||
}
|
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);
|
||||
};
|
222
node_modules/jsdom/lib/jsdom/browser/parser/html.js
generated
vendored
Normal file
222
node_modules/jsdom/lib/jsdom/browser/parser/html.js
generated
vendored
Normal file
|
@ -0,0 +1,222 @@
|
|||
"use strict";
|
||||
|
||||
const parse5 = require("parse5");
|
||||
|
||||
const { createElement } = require("../../living/helpers/create-element");
|
||||
|
||||
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("../../living/domparsing/parse5-adapter-serialization");
|
||||
const {
|
||||
customElementReactionsStack, invokeCEReactions, lookupCEDefinition
|
||||
} = require("../../living/helpers/custom-elements");
|
||||
|
||||
// Horrible monkey-patch to implement https://github.com/inikulin/parse5/issues/237 and
|
||||
// https://github.com/inikulin/parse5/issues/285.
|
||||
const OpenElementStack = require("parse5/lib/parser/open-element-stack");
|
||||
|
||||
const openElementStackOriginalPush = OpenElementStack.prototype.push;
|
||||
OpenElementStack.prototype.push = function (...args) {
|
||||
openElementStackOriginalPush.apply(this, args);
|
||||
this.treeAdapter._currentElement = this.current;
|
||||
|
||||
const after = this.items[this.stackTop];
|
||||
if (after._pushedOnStackOfOpenElements) {
|
||||
after._pushedOnStackOfOpenElements();
|
||||
}
|
||||
};
|
||||
|
||||
const openElementStackOriginalPop = OpenElementStack.prototype.pop;
|
||||
OpenElementStack.prototype.pop = function (...args) {
|
||||
const before = this.items[this.stackTop];
|
||||
|
||||
openElementStackOriginalPop.apply(this, args);
|
||||
this.treeAdapter._currentElement = this.current;
|
||||
|
||||
if (before._poppedOffStackOfOpenElements) {
|
||||
before._poppedOffStackOfOpenElements();
|
||||
}
|
||||
};
|
||||
|
||||
class JSDOMParse5Adapter {
|
||||
constructor(documentImpl, options = {}) {
|
||||
this._documentImpl = documentImpl;
|
||||
this._globalObject = documentImpl._globalObject;
|
||||
this._fragment = options.fragment || false;
|
||||
|
||||
// Since the createElement hook doesn't provide the parent element, we keep track of this using _currentElement:
|
||||
// https://github.com/inikulin/parse5/issues/285. See above horrible monkey-patch for how this is maintained.
|
||||
this._currentElement = undefined;
|
||||
}
|
||||
|
||||
_ownerDocument() {
|
||||
const { _currentElement } = this;
|
||||
|
||||
// The _currentElement is undefined when parsing elements at the root of the document.
|
||||
if (_currentElement) {
|
||||
return _currentElement.localName === "template" ?
|
||||
_currentElement.content._ownerDocument :
|
||||
_currentElement._ownerDocument;
|
||||
}
|
||||
|
||||
return this._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() {
|
||||
const ownerDocument = this._ownerDocument();
|
||||
return DocumentFragment.createImpl(this._globalObject, [], { ownerDocument });
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/#create-an-element-for-the-token
|
||||
createElement(localName, namespace, attrs) {
|
||||
const ownerDocument = this._ownerDocument();
|
||||
|
||||
const isAttribute = attrs.find(attr => attr.name === "is");
|
||||
const isValue = isAttribute ? isAttribute.value : null;
|
||||
|
||||
const definition = lookupCEDefinition(ownerDocument, namespace, localName);
|
||||
|
||||
let willExecuteScript = false;
|
||||
if (definition !== null && !this._fragment) {
|
||||
willExecuteScript = true;
|
||||
}
|
||||
|
||||
if (willExecuteScript) {
|
||||
ownerDocument._throwOnDynamicMarkupInsertionCounter++;
|
||||
customElementReactionsStack.push([]);
|
||||
}
|
||||
|
||||
const element = createElement(ownerDocument, localName, namespace, null, isValue, willExecuteScript);
|
||||
this.adoptAttributes(element, attrs);
|
||||
|
||||
if (willExecuteScript) {
|
||||
const queue = customElementReactionsStack.pop();
|
||||
invokeCEReactions(queue);
|
||||
ownerDocument._throwOnDynamicMarkupInsertionCounter--;
|
||||
}
|
||||
|
||||
if ("_parserInserted" in element) {
|
||||
element._parserInserted = true;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
createCommentNode(data) {
|
||||
const ownerDocument = this._ownerDocument();
|
||||
return Comment.createImpl(this._globalObject, [], { data, ownerDocument });
|
||||
}
|
||||
|
||||
appendChild(parentNode, newNode) {
|
||||
parentNode._append(newNode);
|
||||
}
|
||||
|
||||
insertBefore(parentNode, newNode, referenceNode) {
|
||||
parentNode._insert(newNode, referenceNode);
|
||||
}
|
||||
|
||||
setTemplateContent(templateElement, contentFragment) {
|
||||
// This code makes the glue between jsdom and parse5 HTMLTemplateElement parsing:
|
||||
//
|
||||
// * jsdom during the construction of the HTMLTemplateElement (for example when create via
|
||||
// `document.createElement("template")`), creates a DocumentFragment and set it into _templateContents.
|
||||
// * parse5 when parsing a <template> tag creates an HTMLTemplateElement (`createElement` adapter hook) and also
|
||||
// create a DocumentFragment (`createDocumentFragment` adapter hook).
|
||||
//
|
||||
// At this point we now have to replace the one created in jsdom with one created by parse5.
|
||||
const { _ownerDocument, _host } = templateElement._templateContents;
|
||||
contentFragment._ownerDocument = _ownerDocument;
|
||||
contentFragment._host = _host;
|
||||
|
||||
templateElement._templateContents = contentFragment;
|
||||
}
|
||||
|
||||
setDocumentType(document, name, publicId, systemId) {
|
||||
const ownerDocument = this._ownerDocument();
|
||||
const documentType = DocumentType.createImpl(this._globalObject, [], { name, publicId, systemId, ownerDocument });
|
||||
|
||||
document._append(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 ownerDocument = this._ownerDocument();
|
||||
const textNode = Text.createImpl(this._globalObject, [], { data: text, ownerDocument });
|
||||
parentNode._append(textNode);
|
||||
}
|
||||
}
|
||||
|
||||
insertTextBefore(parentNode, text, referenceNode) {
|
||||
const { previousSibling } = referenceNode;
|
||||
if (previousSibling && previousSibling.nodeType === nodeTypes.TEXT_NODE) {
|
||||
previousSibling.data += text;
|
||||
} else {
|
||||
const ownerDocument = this._ownerDocument();
|
||||
const textNode = Text.createImpl(this._globalObject, [], { data: text, ownerDocument });
|
||||
parentNode._append(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assign shared adapters with serializer.
|
||||
Object.assign(JSDOMParse5Adapter.prototype, serializationAdapter);
|
||||
|
||||
function parseFragment(markup, contextElement) {
|
||||
const ownerDocument = contextElement.localName === "template" ?
|
||||
contextElement.content._ownerDocument :
|
||||
contextElement._ownerDocument;
|
||||
|
||||
const config = Object.assign({}, ownerDocument._parseOptions, {
|
||||
treeAdapter: new JSDOMParse5Adapter(ownerDocument, {
|
||||
fragment: true
|
||||
})
|
||||
});
|
||||
|
||||
return parse5.parseFragment(contextElement, markup, config);
|
||||
}
|
||||
|
||||
function parseIntoDocument(markup, ownerDocument) {
|
||||
const config = Object.assign({}, ownerDocument._parseOptions, {
|
||||
treeAdapter: new JSDOMParse5Adapter(ownerDocument)
|
||||
});
|
||||
|
||||
return parse5.parse(markup, config);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
parseFragment,
|
||||
parseIntoDocument
|
||||
};
|
37
node_modules/jsdom/lib/jsdom/browser/parser/index.js
generated
vendored
Normal file
37
node_modules/jsdom/lib/jsdom/browser/parser/index.js
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
"use strict";
|
||||
|
||||
const xmlParser = require("./xml");
|
||||
const htmlParser = require("./html");
|
||||
|
||||
// https://w3c.github.io/DOM-Parsing/#dfn-fragment-parsing-algorithm
|
||||
function parseFragment(markup, contextElement) {
|
||||
const { _parsingMode } = contextElement._ownerDocument;
|
||||
|
||||
let parseAlgorithm;
|
||||
if (_parsingMode === "html") {
|
||||
parseAlgorithm = htmlParser.parseFragment;
|
||||
} else if (_parsingMode === "xml") {
|
||||
parseAlgorithm = xmlParser.parseFragment;
|
||||
}
|
||||
|
||||
// Note: HTML and XML fragment parsing algorithm already return a document fragments; no need to do steps 3 and 4
|
||||
return parseAlgorithm(markup, contextElement);
|
||||
}
|
||||
|
||||
function parseIntoDocument(markup, ownerDocument) {
|
||||
const { _parsingMode } = ownerDocument;
|
||||
|
||||
let parseAlgorithm;
|
||||
if (_parsingMode === "html") {
|
||||
parseAlgorithm = htmlParser.parseIntoDocument;
|
||||
} else if (_parsingMode === "xml") {
|
||||
parseAlgorithm = xmlParser.parseIntoDocument;
|
||||
}
|
||||
|
||||
return parseAlgorithm(markup, ownerDocument);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
parseFragment,
|
||||
parseIntoDocument
|
||||
};
|
205
node_modules/jsdom/lib/jsdom/browser/parser/xml.js
generated
vendored
Normal file
205
node_modules/jsdom/lib/jsdom/browser/parser/xml.js
generated
vendored
Normal file
|
@ -0,0 +1,205 @@
|
|||
"use strict";
|
||||
|
||||
const { SaxesParser } = require("saxes");
|
||||
const DOMException = require("domexception/webidl2js-wrapper");
|
||||
|
||||
const { createElement } = require("../../living/helpers/create-element");
|
||||
|
||||
const DocumentFragment = require("../../living/generated/DocumentFragment");
|
||||
const DocumentType = require("../../living/generated/DocumentType");
|
||||
const CDATASection = require("../../living/generated/CDATASection");
|
||||
const Comment = require("../../living/generated/Comment");
|
||||
const ProcessingInstruction = require("../../living/generated/ProcessingInstruction");
|
||||
const Text = require("../../living/generated/Text");
|
||||
|
||||
const attributes = require("../../living/attributes");
|
||||
const { HTML_NS } = require("../../living/helpers/namespaces");
|
||||
|
||||
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;
|
||||
const CUSTOM_NAME_DOCTYPE = /<!doctype\s+([^\s>]+)/i;
|
||||
|
||||
function parseDocType(globalObject, ownerDocument, html) {
|
||||
if (HTML5_DOCTYPE.test(html)) {
|
||||
return createDocumentType(globalObject, ownerDocument, "html", "", "");
|
||||
}
|
||||
|
||||
const publicPieces = PUBLIC_DOCTYPE.exec(html);
|
||||
if (publicPieces) {
|
||||
return createDocumentType(globalObject, ownerDocument, publicPieces[1], publicPieces[2], publicPieces[3]);
|
||||
}
|
||||
|
||||
const systemPieces = SYSTEM_DOCTYPE.exec(html);
|
||||
if (systemPieces) {
|
||||
return createDocumentType(globalObject, ownerDocument, systemPieces[1], "", systemPieces[2]);
|
||||
}
|
||||
|
||||
const namePiece = CUSTOM_NAME_DOCTYPE.exec(html)[1] || "html";
|
||||
return createDocumentType(globalObject, ownerDocument, namePiece, "", "");
|
||||
}
|
||||
|
||||
function createDocumentType(globalObject, ownerDocument, name, publicId, systemId) {
|
||||
return DocumentType.createImpl(globalObject, [], { ownerDocument, name, publicId, systemId });
|
||||
}
|
||||
|
||||
function isHTMLTemplateElement(element) {
|
||||
return element.tagName === "template" && element.namespaceURI === HTML_NS;
|
||||
}
|
||||
|
||||
|
||||
function createParser(rootNode, globalObject, saxesOptions) {
|
||||
const parser = new SaxesParser({
|
||||
...saxesOptions,
|
||||
// Browsers always have namespace support.
|
||||
xmlns: true,
|
||||
// We force the parser to treat all documents (even documents declaring themselves to be XML 1.1 documents) as XML
|
||||
// 1.0 documents. See https://github.com/jsdom/jsdom/issues/2677 for a discussion of the stakes.
|
||||
defaultXMLVersion: "1.0",
|
||||
forceXMLVersion: true
|
||||
});
|
||||
const openStack = [rootNode];
|
||||
|
||||
function getOwnerDocument() {
|
||||
const currentElement = openStack[openStack.length - 1];
|
||||
|
||||
return isHTMLTemplateElement(currentElement) ?
|
||||
currentElement._templateContents._ownerDocument :
|
||||
currentElement._ownerDocument;
|
||||
}
|
||||
|
||||
function appendChild(child) {
|
||||
const parentElement = openStack[openStack.length - 1];
|
||||
|
||||
if (isHTMLTemplateElement(parentElement)) {
|
||||
parentElement._templateContents._insert(child, null);
|
||||
} else {
|
||||
parentElement._insert(child, null);
|
||||
}
|
||||
}
|
||||
|
||||
parser.on("text", saxesOptions.fragment ?
|
||||
// In a fragment, all text events produced by saxes must result in a text
|
||||
// node.
|
||||
data => {
|
||||
const ownerDocument = getOwnerDocument();
|
||||
appendChild(Text.createImpl(globalObject, [], { data, ownerDocument }));
|
||||
} :
|
||||
// When parsing a whole document, we must ignore those text nodes that are
|
||||
// produced outside the root element. Saxes produces events for them,
|
||||
// but DOM trees do not record text outside the root element.
|
||||
data => {
|
||||
if (openStack.length > 1) {
|
||||
const ownerDocument = getOwnerDocument();
|
||||
appendChild(Text.createImpl(globalObject, [], { data, ownerDocument }));
|
||||
}
|
||||
});
|
||||
|
||||
parser.on("cdata", data => {
|
||||
const ownerDocument = getOwnerDocument();
|
||||
appendChild(CDATASection.createImpl(globalObject, [], { data, ownerDocument }));
|
||||
});
|
||||
|
||||
parser.on("opentag", tag => {
|
||||
const { local: tagLocal, attributes: tagAttributes } = tag;
|
||||
|
||||
const ownerDocument = getOwnerDocument();
|
||||
const tagNamespace = tag.uri === "" ? null : tag.uri;
|
||||
const tagPrefix = tag.prefix === "" ? null : tag.prefix;
|
||||
const isValue = tagAttributes.is === undefined ? null : tagAttributes.is.value;
|
||||
|
||||
const elem = createElement(ownerDocument, tagLocal, tagNamespace, tagPrefix, isValue, true);
|
||||
|
||||
// We mark a script element as "parser-inserted", which prevents it from
|
||||
// being immediately executed.
|
||||
if (tagLocal === "script" && tagNamespace === HTML_NS) {
|
||||
elem._parserInserted = true;
|
||||
}
|
||||
|
||||
for (const key of Object.keys(tagAttributes)) {
|
||||
const { prefix, local, uri, value } = tagAttributes[key];
|
||||
attributes.setAttributeValue(
|
||||
elem, local, value, prefix === "" ? null : prefix,
|
||||
uri === "" ? null : uri
|
||||
);
|
||||
}
|
||||
|
||||
appendChild(elem);
|
||||
openStack.push(elem);
|
||||
});
|
||||
|
||||
parser.on("closetag", () => {
|
||||
const elem = openStack.pop();
|
||||
// Once a script is populated, we can execute it.
|
||||
if (elem.localName === "script" && elem.namespaceURI === HTML_NS) {
|
||||
elem._eval();
|
||||
}
|
||||
});
|
||||
|
||||
parser.on("comment", data => {
|
||||
const ownerDocument = getOwnerDocument();
|
||||
appendChild(Comment.createImpl(globalObject, [], { data, ownerDocument }));
|
||||
});
|
||||
|
||||
parser.on("processinginstruction", ({ target, body }) => {
|
||||
const ownerDocument = getOwnerDocument();
|
||||
appendChild(ProcessingInstruction.createImpl(globalObject, [], { target, data: body, ownerDocument }));
|
||||
});
|
||||
|
||||
parser.on("doctype", dt => {
|
||||
const ownerDocument = getOwnerDocument();
|
||||
appendChild(parseDocType(globalObject, ownerDocument, `<!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.on("error", err => {
|
||||
throw DOMException.create(globalObject, [err.message, "SyntaxError"]);
|
||||
});
|
||||
|
||||
return parser;
|
||||
}
|
||||
|
||||
function parseFragment(markup, contextElement) {
|
||||
const { _globalObject, _ownerDocument } = contextElement;
|
||||
|
||||
const fragment = DocumentFragment.createImpl(_globalObject, [], { ownerDocument: _ownerDocument });
|
||||
|
||||
// Only parseFragment needs resolvePrefix per the saxes documentation:
|
||||
// https://github.com/lddubeau/saxes#parsing-xml-fragments
|
||||
const parser = createParser(fragment, _globalObject, {
|
||||
fragment: true,
|
||||
resolvePrefix(prefix) {
|
||||
// saxes wants undefined as the return value if the prefix is not defined, not null.
|
||||
return contextElement.lookupNamespaceURI(prefix) || undefined;
|
||||
}
|
||||
});
|
||||
|
||||
parser.write(markup).close();
|
||||
|
||||
return fragment;
|
||||
}
|
||||
|
||||
function parseIntoDocument(markup, ownerDocument) {
|
||||
const { _globalObject } = ownerDocument;
|
||||
|
||||
const parser = createParser(ownerDocument, _globalObject, {
|
||||
fileName: ownerDocument.location && ownerDocument.location.href
|
||||
});
|
||||
|
||||
parser.write(markup).close();
|
||||
|
||||
return ownerDocument;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
parseFragment,
|
||||
parseIntoDocument
|
||||
};
|
114
node_modules/jsdom/lib/jsdom/browser/resources/async-resource-queue.js
generated
vendored
Normal file
114
node_modules/jsdom/lib/jsdom/browser/resources/async-resource-queue.js
generated
vendored
Normal file
|
@ -0,0 +1,114 @@
|
|||
"use strict";
|
||||
|
||||
class QueueItem {
|
||||
constructor(onLoad, onError, dependentItem) {
|
||||
this.onLoad = onLoad;
|
||||
this.onError = onError;
|
||||
this.data = null;
|
||||
this.error = null;
|
||||
this.dependentItem = dependentItem;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AsyncResourceQueue is the queue in charge of run the async scripts
|
||||
* and notify when they finish.
|
||||
*/
|
||||
module.exports = class AsyncResourceQueue {
|
||||
constructor() {
|
||||
this.items = new Set();
|
||||
this.dependentItems = new Set();
|
||||
}
|
||||
|
||||
count() {
|
||||
return this.items.size + this.dependentItems.size;
|
||||
}
|
||||
|
||||
_notify() {
|
||||
if (this._listener) {
|
||||
this._listener();
|
||||
}
|
||||
}
|
||||
|
||||
_check(item) {
|
||||
let promise;
|
||||
|
||||
if (item.onError && item.error) {
|
||||
promise = item.onError(item.error);
|
||||
} else if (item.onLoad && item.data) {
|
||||
promise = item.onLoad(item.data);
|
||||
}
|
||||
|
||||
promise
|
||||
.then(() => {
|
||||
this.items.delete(item);
|
||||
this.dependentItems.delete(item);
|
||||
|
||||
if (this.count() === 0) {
|
||||
this._notify();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setListener(listener) {
|
||||
this._listener = listener;
|
||||
}
|
||||
|
||||
push(request, onLoad, onError, dependentItem) {
|
||||
const q = this;
|
||||
|
||||
const item = new QueueItem(onLoad, onError, dependentItem);
|
||||
|
||||
q.items.add(item);
|
||||
|
||||
return request
|
||||
.then(data => {
|
||||
item.data = data;
|
||||
|
||||
if (dependentItem && !dependentItem.finished) {
|
||||
q.dependentItems.add(item);
|
||||
return q.items.delete(item);
|
||||
}
|
||||
|
||||
if (onLoad) {
|
||||
return q._check(item);
|
||||
}
|
||||
|
||||
q.items.delete(item);
|
||||
|
||||
if (q.count() === 0) {
|
||||
q._notify();
|
||||
}
|
||||
|
||||
return null;
|
||||
})
|
||||
.catch(err => {
|
||||
item.error = err;
|
||||
|
||||
if (dependentItem && !dependentItem.finished) {
|
||||
q.dependentItems.add(item);
|
||||
return q.items.delete(item);
|
||||
}
|
||||
|
||||
if (onError) {
|
||||
return q._check(item);
|
||||
}
|
||||
|
||||
q.items.delete(item);
|
||||
|
||||
if (q.count() === 0) {
|
||||
q._notify();
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
notifyItem(syncItem) {
|
||||
for (const item of this.dependentItems) {
|
||||
if (item.dependentItem === syncItem) {
|
||||
this._check(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
8
node_modules/jsdom/lib/jsdom/browser/resources/no-op-resource-loader.js
generated
vendored
Normal file
8
node_modules/jsdom/lib/jsdom/browser/resources/no-op-resource-loader.js
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
"use strict";
|
||||
const ResourceLoader = require("./resource-loader.js");
|
||||
|
||||
module.exports = class NoOpResourceLoader extends ResourceLoader {
|
||||
fetch() {
|
||||
return null;
|
||||
}
|
||||
};
|
95
node_modules/jsdom/lib/jsdom/browser/resources/per-document-resource-loader.js
generated
vendored
Normal file
95
node_modules/jsdom/lib/jsdom/browser/resources/per-document-resource-loader.js
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
"use strict";
|
||||
const idlUtils = require("../../living/generated/utils");
|
||||
const { fireAnEvent } = require("../../living/helpers/events");
|
||||
|
||||
module.exports = class PerDocumentResourceLoader {
|
||||
constructor(document) {
|
||||
this._document = document;
|
||||
this._defaultEncoding = document._encoding;
|
||||
this._resourceLoader = document._defaultView ? document._defaultView._resourceLoader : null;
|
||||
this._requestManager = document._requestManager;
|
||||
this._queue = document._queue;
|
||||
this._deferQueue = document._deferQueue;
|
||||
this._asyncQueue = document._asyncQueue;
|
||||
}
|
||||
|
||||
fetch(url, { element, onLoad, onError }) {
|
||||
const request = this._resourceLoader.fetch(url, {
|
||||
cookieJar: this._document._cookieJar,
|
||||
element: idlUtils.wrapperForImpl(element),
|
||||
referrer: this._document.URL
|
||||
});
|
||||
|
||||
if (request === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this._requestManager.add(request);
|
||||
|
||||
const onErrorWrapped = error => {
|
||||
this._requestManager.remove(request);
|
||||
|
||||
if (onError) {
|
||||
onError(error);
|
||||
}
|
||||
|
||||
fireAnEvent("error", element);
|
||||
|
||||
const err = new Error(`Could not load ${element.localName}: "${url}"`);
|
||||
err.type = "resource loading";
|
||||
err.detail = error;
|
||||
|
||||
this._document._defaultView._virtualConsole.emit("jsdomError", err);
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
const onLoadWrapped = data => {
|
||||
this._requestManager.remove(request);
|
||||
|
||||
this._addCookies(url, request.response ? request.response.headers : {});
|
||||
|
||||
try {
|
||||
const result = onLoad ? onLoad(data) : undefined;
|
||||
|
||||
return Promise.resolve(result)
|
||||
.then(() => {
|
||||
fireAnEvent("load", element);
|
||||
|
||||
return Promise.resolve();
|
||||
})
|
||||
.catch(err => {
|
||||
return onErrorWrapped(err);
|
||||
});
|
||||
} catch (err) {
|
||||
return onErrorWrapped(err);
|
||||
}
|
||||
};
|
||||
|
||||
if (element.localName === "script" && element.hasAttributeNS(null, "async")) {
|
||||
this._asyncQueue.push(request, onLoadWrapped, onErrorWrapped, this._queue.getLastScript());
|
||||
} else if (element.localName === "script" && element.hasAttributeNS(null, "defer")) {
|
||||
this._deferQueue.push(request, onLoadWrapped, onErrorWrapped, false, element);
|
||||
} else {
|
||||
this._queue.push(request, onLoadWrapped, onErrorWrapped, false, element);
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
_addCookies(url, headers) {
|
||||
let cookies = headers["set-cookie"];
|
||||
|
||||
if (!cookies) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Array.isArray(cookies)) {
|
||||
cookies = [cookies];
|
||||
}
|
||||
|
||||
cookies.forEach(cookie => {
|
||||
this._document._cookieJar.setCookieSync(cookie, url, { http: true, ignoreError: true });
|
||||
});
|
||||
}
|
||||
};
|
33
node_modules/jsdom/lib/jsdom/browser/resources/request-manager.js
generated
vendored
Normal file
33
node_modules/jsdom/lib/jsdom/browser/resources/request-manager.js
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
"use strict";
|
||||
|
||||
/**
|
||||
* Manage all the request and it is able to abort
|
||||
* all pending request.
|
||||
*/
|
||||
module.exports = class RequestManager {
|
||||
constructor() {
|
||||
this.openedRequests = [];
|
||||
}
|
||||
|
||||
add(req) {
|
||||
this.openedRequests.push(req);
|
||||
}
|
||||
|
||||
remove(req) {
|
||||
const idx = this.openedRequests.indexOf(req);
|
||||
if (idx !== -1) {
|
||||
this.openedRequests.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
for (const openedRequest of this.openedRequests) {
|
||||
openedRequest.abort();
|
||||
}
|
||||
this.openedRequests = [];
|
||||
}
|
||||
|
||||
size() {
|
||||
return this.openedRequests.length;
|
||||
}
|
||||
};
|
127
node_modules/jsdom/lib/jsdom/browser/resources/resource-loader.js
generated
vendored
Normal file
127
node_modules/jsdom/lib/jsdom/browser/resources/resource-loader.js
generated
vendored
Normal file
|
@ -0,0 +1,127 @@
|
|||
"use strict";
|
||||
const fs = require("fs");
|
||||
const { parseURL } = require("whatwg-url");
|
||||
const dataURLFromRecord = require("data-urls").fromURLRecord;
|
||||
const request = require("request-promise-native");
|
||||
const wrapCookieJarForRequest = require("../../living/helpers/wrap-cookie-jar-for-request");
|
||||
const packageVersion = require("../../../../package.json").version;
|
||||
const IS_BROWSER = Object.prototype.toString.call(process) !== "[object process]";
|
||||
|
||||
module.exports = class ResourceLoader {
|
||||
constructor({
|
||||
strictSSL = true,
|
||||
proxy = undefined,
|
||||
userAgent = `Mozilla/5.0 (${process.platform || "unknown OS"}) AppleWebKit/537.36 ` +
|
||||
`(KHTML, like Gecko) jsdom/${packageVersion}`
|
||||
} = {}) {
|
||||
this._strictSSL = strictSSL;
|
||||
this._proxy = proxy;
|
||||
this._userAgent = userAgent;
|
||||
}
|
||||
|
||||
_readDataURL(urlRecord) {
|
||||
const dataURL = dataURLFromRecord(urlRecord);
|
||||
let timeoutId;
|
||||
const promise = new Promise(resolve => {
|
||||
timeoutId = setTimeout(resolve, 0, dataURL.body);
|
||||
});
|
||||
promise.abort = () => {
|
||||
if (timeoutId !== undefined) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
};
|
||||
return promise;
|
||||
}
|
||||
|
||||
_readFile(filePath) {
|
||||
let readableStream;
|
||||
let abort; // Native Promises doesn't have an "abort" method.
|
||||
|
||||
/*
|
||||
* Creating a promise for two reason:
|
||||
* 1. fetch always return a promise.
|
||||
* 2. We need to add an abort handler.
|
||||
*/
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
readableStream = fs.createReadStream(filePath);
|
||||
let data = Buffer.alloc(0);
|
||||
|
||||
abort = reject;
|
||||
|
||||
readableStream.on("error", reject);
|
||||
|
||||
readableStream.on("data", chunk => {
|
||||
data = Buffer.concat([data, chunk]);
|
||||
});
|
||||
|
||||
readableStream.on("end", () => {
|
||||
resolve(data);
|
||||
});
|
||||
});
|
||||
|
||||
promise.abort = () => {
|
||||
readableStream.destroy();
|
||||
const error = new Error("request canceled by user");
|
||||
error.isAbortError = true;
|
||||
abort(error);
|
||||
};
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
_getRequestOptions({ cookieJar, referrer, accept = "*/*" }) {
|
||||
const requestOptions = {
|
||||
encoding: null,
|
||||
gzip: true,
|
||||
jar: wrapCookieJarForRequest(cookieJar),
|
||||
strictSSL: this._strictSSL,
|
||||
proxy: this._proxy,
|
||||
forever: true,
|
||||
headers: {
|
||||
"User-Agent": this._userAgent,
|
||||
"Accept-Language": "en",
|
||||
Accept: accept
|
||||
}
|
||||
};
|
||||
|
||||
if (referrer && !IS_BROWSER) {
|
||||
requestOptions.headers.referer = referrer;
|
||||
}
|
||||
|
||||
return requestOptions;
|
||||
}
|
||||
|
||||
fetch(urlString, options = {}) {
|
||||
const url = parseURL(urlString);
|
||||
|
||||
if (!url) {
|
||||
return Promise.reject(new Error(`Tried to fetch invalid URL ${urlString}`));
|
||||
}
|
||||
|
||||
switch (url.scheme) {
|
||||
case "data": {
|
||||
return this._readDataURL(url);
|
||||
}
|
||||
|
||||
case "http":
|
||||
case "https": {
|
||||
const requestOptions = this._getRequestOptions(options);
|
||||
return request(urlString, requestOptions);
|
||||
}
|
||||
|
||||
case "file": {
|
||||
// TODO: Improve the URL => file algorithm. See https://github.com/jsdom/jsdom/pull/2279#discussion_r199977987
|
||||
const filePath = urlString
|
||||
.replace(/^file:\/\//, "")
|
||||
.replace(/^\/([a-z]):\//i, "$1:/")
|
||||
.replace(/%20/g, " ");
|
||||
|
||||
return this._readFile(filePath);
|
||||
}
|
||||
|
||||
default: {
|
||||
return Promise.reject(new Error(`Tried to fetch URL ${urlString} with invalid scheme ${url.scheme}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
142
node_modules/jsdom/lib/jsdom/browser/resources/resource-queue.js
generated
vendored
Normal file
142
node_modules/jsdom/lib/jsdom/browser/resources/resource-queue.js
generated
vendored
Normal file
|
@ -0,0 +1,142 @@
|
|||
"use strict";
|
||||
|
||||
/**
|
||||
* Queue for all the resources to be download except async scripts.
|
||||
* Async scripts have their own queue AsyncResourceQueue.
|
||||
*/
|
||||
module.exports = class ResourceQueue {
|
||||
constructor({ paused, asyncQueue } = {}) {
|
||||
this.paused = Boolean(paused);
|
||||
this._asyncQueue = asyncQueue;
|
||||
}
|
||||
|
||||
getLastScript() {
|
||||
let head = this.tail;
|
||||
|
||||
while (head) {
|
||||
if (head.isScript) {
|
||||
return head;
|
||||
}
|
||||
head = head.prev;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
_moreScripts() {
|
||||
let found = false;
|
||||
|
||||
let head = this.tail;
|
||||
while (head && !found) {
|
||||
found = head.isScript;
|
||||
head = head.prev;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
_notify() {
|
||||
if (this._listener) {
|
||||
this._listener();
|
||||
}
|
||||
}
|
||||
|
||||
setListener(listener) {
|
||||
this._listener = listener;
|
||||
}
|
||||
|
||||
push(request, onLoad, onError, keepLast, element) {
|
||||
const isScript = element ? element.localName === "script" : false;
|
||||
|
||||
if (!request) {
|
||||
if (isScript && !this._moreScripts()) {
|
||||
return onLoad();
|
||||
}
|
||||
|
||||
request = new Promise(resolve => resolve());
|
||||
}
|
||||
const q = this;
|
||||
const item = {
|
||||
isScript,
|
||||
err: null,
|
||||
element,
|
||||
fired: false,
|
||||
data: null,
|
||||
keepLast,
|
||||
prev: q.tail,
|
||||
check() {
|
||||
if (!q.paused && !this.prev && this.fired) {
|
||||
let promise;
|
||||
|
||||
if (this.err && onError) {
|
||||
promise = onError(this.err);
|
||||
}
|
||||
|
||||
if (!this.err && onLoad) {
|
||||
promise = onLoad(this.data);
|
||||
}
|
||||
|
||||
Promise.resolve(promise)
|
||||
.then(() => {
|
||||
if (this.next) {
|
||||
this.next.prev = null;
|
||||
this.next.check();
|
||||
} else { // q.tail===this
|
||||
q.tail = null;
|
||||
q._notify();
|
||||
}
|
||||
|
||||
this.finished = true;
|
||||
|
||||
if (q._asyncQueue) {
|
||||
q._asyncQueue.notifyItem(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
if (q.tail) {
|
||||
if (q.tail.keepLast) {
|
||||
// if the tail is the load event in document and we receive a new element to load
|
||||
// we should add this new request before the load event.
|
||||
if (q.tail.prev) {
|
||||
q.tail.prev.next = item;
|
||||
}
|
||||
item.prev = q.tail.prev;
|
||||
q.tail.prev = item;
|
||||
item.next = q.tail;
|
||||
} else {
|
||||
q.tail.next = item;
|
||||
q.tail = item;
|
||||
}
|
||||
} else {
|
||||
q.tail = item;
|
||||
}
|
||||
return request
|
||||
.then(data => {
|
||||
item.fired = 1;
|
||||
item.data = data;
|
||||
item.check();
|
||||
})
|
||||
.catch(err => {
|
||||
item.fired = true;
|
||||
item.err = err;
|
||||
item.check();
|
||||
});
|
||||
}
|
||||
|
||||
resume() {
|
||||
if (!this.paused) {
|
||||
return;
|
||||
}
|
||||
this.paused = false;
|
||||
|
||||
let head = this.tail;
|
||||
while (head && head.prev) {
|
||||
head = head.prev;
|
||||
}
|
||||
if (head) {
|
||||
head.check();
|
||||
}
|
||||
}
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue