mirror of
https://github.com/titaniumnetwork-dev/Ultraviolet.git
synced 2025-05-14 12:20:01 -04:00
prettier
This commit is contained in:
parent
d230e0e551
commit
8f999e7236
42 changed files with 10481 additions and 8966 deletions
10
.github/ISSUE_TEMPLATE/bug_report.md
vendored
10
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -4,39 +4,45 @@ about: Create a report to help us improve
|
||||||
title: ''
|
title: ''
|
||||||
labels: ''
|
labels: ''
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Issue tracker is **ONLY** used for reporting bugs. New features should be discussed on our Discord server.
|
Issue tracker is **ONLY** used for reporting bugs. New features should be discussed on our Discord server.
|
||||||
|
|
||||||
|
|
||||||
<!--- Provide a general summary of the issue in the Title above -->
|
<!--- Provide a general summary of the issue in the Title above -->
|
||||||
|
|
||||||
## Expected Behavior
|
## Expected Behavior
|
||||||
|
|
||||||
<!--- Tell us what should happen -->
|
<!--- Tell us what should happen -->
|
||||||
|
|
||||||
## Current Behavior
|
## Current Behavior
|
||||||
|
|
||||||
<!--- Tell us what happens instead of the expected behavior -->
|
<!--- Tell us what happens instead of the expected behavior -->
|
||||||
|
|
||||||
## Possible Solution
|
## Possible Solution
|
||||||
|
|
||||||
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
|
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
|
||||||
|
|
||||||
## Steps to Reproduce
|
## Steps to Reproduce
|
||||||
|
|
||||||
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
|
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
|
||||||
<!--- reproduce this bug. Include code to reproduce, if relevant -->
|
<!--- reproduce this bug. Include code to reproduce, if relevant -->
|
||||||
|
|
||||||
1.
|
1.
|
||||||
2.
|
2.
|
||||||
3.
|
3.
|
||||||
4.
|
4.
|
||||||
|
|
||||||
## Context (Environment)
|
## Context (Environment)
|
||||||
|
|
||||||
<!--- How has this issue affected you? What are you trying to accomplish? -->
|
<!--- How has this issue affected you? What are you trying to accomplish? -->
|
||||||
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
|
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
|
||||||
|
|
||||||
<!--- Provide a general summary of the issue in the Title above -->
|
<!--- Provide a general summary of the issue in the Title above -->
|
||||||
|
|
||||||
## Detailed Description
|
## Detailed Description
|
||||||
|
|
||||||
<!--- Provide a detailed description of the change or addition you are proposing -->
|
<!--- Provide a detailed description of the change or addition you are proposing -->
|
||||||
|
|
||||||
## Possible Implementation
|
## Possible Implementation
|
||||||
|
|
||||||
<!--- Not obligatory, but suggest an idea for implementing addition or change -->
|
<!--- Not obligatory, but suggest an idea for implementing addition or change -->
|
||||||
|
|
12
.github/ISSUE_TEMPLATE/config.yml
vendored
12
.github/ISSUE_TEMPLATE/config.yml
vendored
|
@ -1,8 +1,8 @@
|
||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Community Support
|
- name: Community Support
|
||||||
url: https://discord.gg/unblock
|
url: https://discord.gg/unblock
|
||||||
about: Please ask and answer questions here.
|
about: Please ask and answer questions here.
|
||||||
- name: Heroku, Repl.it, Blocked site issues
|
- name: Heroku, Repl.it, Blocked site issues
|
||||||
url: https://www.youtube.com/watch?v=BLUkgRAy_Vo
|
url: https://www.youtube.com/watch?v=BLUkgRAy_Vo
|
||||||
about: Do not create issues for these.
|
about: Do not create issues for these.
|
||||||
|
|
4
.prettierrc
Normal file
4
.prettierrc
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"tabWidth": 4,
|
||||||
|
"singleQuote": true
|
||||||
|
}
|
9280
package-lock.json
generated
9280
package-lock.json
generated
File diff suppressed because it is too large
Load diff
69
package.json
69
package.json
|
@ -1,36 +1,37 @@
|
||||||
{
|
{
|
||||||
"name": "@titaniumnetwork-dev/ultraviolet",
|
"name": "@titaniumnetwork-dev/ultraviolet",
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"description": "Proxy",
|
"description": "Proxy",
|
||||||
"main": "lib/index.cjs",
|
"main": "lib/index.cjs",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "cross-env NODE_ENV=production webpack-cli",
|
"build": "cross-env NODE_ENV=production webpack-cli",
|
||||||
"build:dev": "cross-env NODE_ENV=development webpack-cli",
|
"build:dev": "cross-env NODE_ENV=development webpack-cli",
|
||||||
"build:watch": "cross-env NODE_ENV=development webpack-cli --watch"
|
"build:watch": "cross-env NODE_ENV=development webpack-cli --watch"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bowser": "^2.11.0",
|
"bowser": "^2.11.0",
|
||||||
"css-tree": "^2.0.4",
|
"css-tree": "^2.0.4",
|
||||||
"esotope-hammerhead": "^0.6.1",
|
"esotope-hammerhead": "^0.6.1",
|
||||||
"idb": "^7.0.0",
|
"idb": "^7.0.0",
|
||||||
"meriyah": "^4.2.0",
|
"meriyah": "^4.2.0",
|
||||||
"mime-db": "^1.51.0",
|
"mime-db": "^1.51.0",
|
||||||
"parse5": "^6.0.1",
|
"parse5": "^6.0.1",
|
||||||
"set-cookie-parser": "^2.4.8"
|
"set-cookie-parser": "^2.4.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"copy-webpack-plugin": "^11.0.0",
|
"copy-webpack-plugin": "^11.0.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^8.8.0",
|
"eslint": "^8.8.0",
|
||||||
"terser-webpack-plugin": "^5.3.6",
|
"prettier": "^2.7.1",
|
||||||
"webpack": "^5.74.0",
|
"terser-webpack-plugin": "^5.3.6",
|
||||||
"webpack-cli": "^4.10.0"
|
"webpack": "^5.74.0",
|
||||||
},
|
"webpack-cli": "^4.10.0"
|
||||||
"files": [
|
},
|
||||||
"dist",
|
"files": [
|
||||||
"lib"
|
"dist",
|
||||||
]
|
"lib"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import EventEmitter from "../events.js";
|
import EventEmitter from '../events.js';
|
||||||
import HookEvent from "../hook.js";
|
import HookEvent from '../hook.js';
|
||||||
|
|
||||||
class AttrApi extends EventEmitter {
|
class AttrApi extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -8,8 +8,14 @@ class AttrApi extends EventEmitter {
|
||||||
this.window = ctx.window;
|
this.window = ctx.window;
|
||||||
this.Attr = this.window.Attr || {};
|
this.Attr = this.window.Attr || {};
|
||||||
this.attrProto = this.Attr.prototype || {};
|
this.attrProto = this.Attr.prototype || {};
|
||||||
this.value = ctx.nativeMethods.getOwnPropertyDescriptor(this.attrProto, 'value');
|
this.value = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
this.name = ctx.nativeMethods.getOwnPropertyDescriptor(this.attrProto, 'name');
|
this.attrProto,
|
||||||
|
'value'
|
||||||
|
);
|
||||||
|
this.name = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.attrProto,
|
||||||
|
'name'
|
||||||
|
);
|
||||||
this.getNamedItem = this.attrProto.getNamedItem || null;
|
this.getNamedItem = this.attrProto.getNamedItem || null;
|
||||||
this.setNamedItem = this.attrProto.setNamedItem || null;
|
this.setNamedItem = this.attrProto.setNamedItem || null;
|
||||||
this.removeNamedItem = this.attrProto.removeNamedItem || null;
|
this.removeNamedItem = this.attrProto.removeNamedItem || null;
|
||||||
|
@ -17,11 +23,15 @@ class AttrApi extends EventEmitter {
|
||||||
this.setNamedItemNS = this.attrProto.setNamedItemNS || null;
|
this.setNamedItemNS = this.attrProto.setNamedItemNS || null;
|
||||||
this.removeNamedItemNS = this.attrProto.removeNamedItemNS || null;
|
this.removeNamedItemNS = this.attrProto.removeNamedItemNS || null;
|
||||||
this.item = this.attrProto.item || null;
|
this.item = this.attrProto.item || null;
|
||||||
};
|
}
|
||||||
overrideNameValue() {
|
overrideNameValue() {
|
||||||
this.ctx.overrideDescriptor(this.attrProto, 'name', {
|
this.ctx.overrideDescriptor(this.attrProto, 'name', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('name', event);
|
this.emit('name', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
|
@ -31,55 +41,82 @@ class AttrApi extends EventEmitter {
|
||||||
|
|
||||||
this.ctx.overrideDescriptor(this.attrProto, 'value', {
|
this.ctx.overrideDescriptor(this.attrProto, 'value', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ name: this.name.get.call(that), value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{
|
||||||
|
name: this.name.get.call(that),
|
||||||
|
value: target.call(that),
|
||||||
|
},
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('getValue', event);
|
this.emit('getValue', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.value;
|
return event.data.value;
|
||||||
},
|
},
|
||||||
set: (target, that, [ val ]) => {
|
set: (target, that, [val]) => {
|
||||||
const event = new HookEvent({ name: this.name.get.call(that), value: val }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ name: this.name.get.call(that), value: val },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('setValue', event);
|
this.emit('setValue', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
event.target.call(event.that, event.data.value);
|
event.target.call(event.that, event.data.value);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideItemMethods() {
|
overrideItemMethods() {
|
||||||
this.ctx.override(this.attrProto, 'getNamedItem', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return target.apply(that, args);
|
this.attrProto,
|
||||||
let [ name ] = args;
|
'getNamedItem',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return target.apply(that, args);
|
||||||
|
let [name] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ name }, target, that);
|
const event = new HookEvent({ name }, target, that);
|
||||||
this.emit('getNamedItem', event);
|
this.emit('getNamedItem', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.name);
|
return event.target.call(event.that, event.data.name);
|
||||||
});
|
}
|
||||||
this.ctx.override(this.attrProto, 'setNamedItem', (target, that, args) => {
|
);
|
||||||
if (2 > args.length) return target.apply(that, args);
|
this.ctx.override(
|
||||||
let [ name, value ] = args;
|
this.attrProto,
|
||||||
|
'setNamedItem',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (2 > args.length) return target.apply(that, args);
|
||||||
|
let [name, value] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ name, value }, target, that);
|
const event = new HookEvent({ name, value }, target, that);
|
||||||
this.emit('setNamedItem', event);
|
this.emit('setNamedItem', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.name, event.data.value);
|
return event.target.call(
|
||||||
});
|
event.that,
|
||||||
this.ctx.override(this.attrProto, 'removeNamedItem', (target, that, args) => {
|
event.data.name,
|
||||||
if (!args.length) return target.apply(that, args);
|
event.data.value
|
||||||
let [ name ] = args;
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.ctx.override(
|
||||||
|
this.attrProto,
|
||||||
|
'removeNamedItem',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return target.apply(that, args);
|
||||||
|
let [name] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ name }, target, that);
|
const event = new HookEvent({ name }, target, that);
|
||||||
this.emit('removeNamedItem', event);
|
this.emit('removeNamedItem', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.name);
|
return event.target.call(event.that, event.data.name);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
this.ctx.override(this.attrProto, 'item', (target, that, args) => {
|
this.ctx.override(this.attrProto, 'item', (target, that, args) => {
|
||||||
if (!args.length) return target.apply(that, args);
|
if (!args.length) return target.apply(that, args);
|
||||||
let [ index ] = args;
|
let [index] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ index }, target, that);
|
const event = new HookEvent({ index }, target, that);
|
||||||
this.emit('item', event);
|
this.emit('item', event);
|
||||||
|
@ -87,37 +124,65 @@ class AttrApi extends EventEmitter {
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.name);
|
return event.target.call(event.that, event.data.name);
|
||||||
});
|
});
|
||||||
this.ctx.override(this.attrProto, 'getNamedItemNS', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (2 > args.length) return target.apply(that, args);
|
this.attrProto,
|
||||||
let [ namespace, localName ] = args;
|
'getNamedItemNS',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (2 > args.length) return target.apply(that, args);
|
||||||
|
let [namespace, localName] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ namespace, localName }, target, that);
|
const event = new HookEvent(
|
||||||
this.emit('getNamedItemNS', event);
|
{ namespace, localName },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
this.emit('getNamedItemNS', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.namespace, event.data.localName);
|
return event.target.call(
|
||||||
});
|
event.that,
|
||||||
this.ctx.override(this.attrProto, 'setNamedItemNS', (target, that, args) => {
|
event.data.namespace,
|
||||||
if (!args.length) return target.apply(that, args);
|
event.data.localName
|
||||||
let [ attr ] = args;
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.ctx.override(
|
||||||
|
this.attrProto,
|
||||||
|
'setNamedItemNS',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return target.apply(that, args);
|
||||||
|
let [attr] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ attr }, target, that);
|
const event = new HookEvent({ attr }, target, that);
|
||||||
this.emit('setNamedItemNS', event);
|
this.emit('setNamedItemNS', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.name);
|
return event.target.call(event.that, event.data.name);
|
||||||
});
|
}
|
||||||
this.ctx.override(this.attrProto, 'removeNamedItemNS', (target, that, args) => {
|
);
|
||||||
if (2 > args.length) return target.apply(that, args);
|
this.ctx.override(
|
||||||
let [ namespace, localName ] = args;
|
this.attrProto,
|
||||||
|
'removeNamedItemNS',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (2 > args.length) return target.apply(that, args);
|
||||||
|
let [namespace, localName] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ namespace, localName }, target, that);
|
const event = new HookEvent(
|
||||||
this.emit('removeNamedItemNS', event);
|
{ namespace, localName },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
this.emit('removeNamedItemNS', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.namespace, event.data.localName);
|
return event.target.call(
|
||||||
});
|
event.that,
|
||||||
};
|
event.data.namespace,
|
||||||
};
|
event.data.localName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default AttrApi;
|
export default AttrApi;
|
|
@ -1,5 +1,5 @@
|
||||||
import EventEmitter from "../events.js";
|
import EventEmitter from '../events.js';
|
||||||
import HookEvent from "../hook.js";
|
import HookEvent from '../hook.js';
|
||||||
|
|
||||||
class DocumentHook extends EventEmitter {
|
class DocumentHook extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -11,52 +11,86 @@ class DocumentHook extends EventEmitter {
|
||||||
this.DOMParser = this.window.DOMParser || {};
|
this.DOMParser = this.window.DOMParser || {};
|
||||||
this.docProto = this.Document.prototype || {};
|
this.docProto = this.Document.prototype || {};
|
||||||
this.domProto = this.DOMParser.prototype || {};
|
this.domProto = this.DOMParser.prototype || {};
|
||||||
this.title = ctx.nativeMethods.getOwnPropertyDescriptor(this.docProto, 'title');
|
this.title = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
this.cookie = ctx.nativeMethods.getOwnPropertyDescriptor(this.docProto, 'cookie');
|
this.docProto,
|
||||||
this.referrer = ctx.nativeMethods.getOwnPropertyDescriptor(this.docProto, 'referrer');
|
'title'
|
||||||
this.domain = ctx.nativeMethods.getOwnPropertyDescriptor(this.docProto, 'domain');
|
);
|
||||||
this.documentURI = ctx.nativeMethods.getOwnPropertyDescriptor(this.docProto, 'documentURI');
|
this.cookie = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.docProto,
|
||||||
|
'cookie'
|
||||||
|
);
|
||||||
|
this.referrer = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.docProto,
|
||||||
|
'referrer'
|
||||||
|
);
|
||||||
|
this.domain = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.docProto,
|
||||||
|
'domain'
|
||||||
|
);
|
||||||
|
this.documentURI = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.docProto,
|
||||||
|
'documentURI'
|
||||||
|
);
|
||||||
this.write = this.docProto.write;
|
this.write = this.docProto.write;
|
||||||
this.writeln = this.docProto.writeln;
|
this.writeln = this.docProto.writeln;
|
||||||
this.querySelector = this.docProto.querySelector;
|
this.querySelector = this.docProto.querySelector;
|
||||||
this.querySelectorAll = this.docProto.querySelectorAll;
|
this.querySelectorAll = this.docProto.querySelectorAll;
|
||||||
this.parseFromString = this.domProto.parseFromString;
|
this.parseFromString = this.domProto.parseFromString;
|
||||||
this.URL = ctx.nativeMethods.getOwnPropertyDescriptor(this.docProto, 'URL');
|
this.URL = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
};
|
this.docProto,
|
||||||
|
'URL'
|
||||||
|
);
|
||||||
|
}
|
||||||
overrideParseFromString() {
|
overrideParseFromString() {
|
||||||
this.ctx.override(this.domProto, 'parseFromString', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (2 > args.length) return target.apply(that, args);
|
this.domProto,
|
||||||
let [ string, type ] = args;
|
'parseFromString',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (2 > args.length) return target.apply(that, args);
|
||||||
|
let [string, type] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ string, type }, target, that);
|
const event = new HookEvent({ string, type }, target, that);
|
||||||
this.emit('parseFromString', event);
|
this.emit('parseFromString', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.string, event.data.type);
|
return event.target.call(
|
||||||
});
|
event.that,
|
||||||
};
|
event.data.string,
|
||||||
|
event.data.type
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
overrideQuerySelector() {
|
overrideQuerySelector() {
|
||||||
this.ctx.override(this.docProto, 'querySelector', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return target.apply(that, args);
|
this.docProto,
|
||||||
let [ selectors ] = args;
|
'querySelector',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return target.apply(that, args);
|
||||||
|
let [selectors] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ selectors }, target, that);
|
const event = new HookEvent({ selectors }, target, that);
|
||||||
this.emit('querySelector', event);
|
this.emit('querySelector', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.selectors);
|
return event.target.call(event.that, event.data.selectors);
|
||||||
});
|
}
|
||||||
};
|
);
|
||||||
|
}
|
||||||
overrideDomain() {
|
overrideDomain() {
|
||||||
this.ctx.overrideDescriptor(this.docProto, 'domain', {
|
this.ctx.overrideDescriptor(this.docProto, 'domain', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('getDomain', event);
|
this.emit('getDomain', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.value;
|
return event.data.value;
|
||||||
},
|
},
|
||||||
set: (target, that, [ val ]) => {
|
set: (target, that, [val]) => {
|
||||||
const event = new HookEvent({ value: val }, target, that);
|
const event = new HookEvent({ value: val }, target, that);
|
||||||
this.emit('setDomain', event);
|
this.emit('setDomain', event);
|
||||||
|
|
||||||
|
@ -64,34 +98,53 @@ class DocumentHook extends EventEmitter {
|
||||||
return event.target.call(event.that, event.data.value);
|
return event.target.call(event.that, event.data.value);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideReferrer() {
|
overrideReferrer() {
|
||||||
this.ctx.overrideDescriptor(this.docProto, 'referrer', {
|
this.ctx.overrideDescriptor(this.docProto, 'referrer', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('referrer', event);
|
this.emit('referrer', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.value;
|
return event.data.value;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideCreateTreeWalker() {
|
overrideCreateTreeWalker() {
|
||||||
this.ctx.override(this.docProto, 'createTreeWalker', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return target.apply(that, args);
|
this.docProto,
|
||||||
let [ root, show = 0xFFFFFFFF, filter, expandEntityReferences ] = args;
|
'createTreeWalker',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return target.apply(that, args);
|
||||||
|
let [root, show = 0xffffffff, filter, expandEntityReferences] =
|
||||||
|
args;
|
||||||
|
|
||||||
const event = new HookEvent({ root, show, filter, expandEntityReferences }, target, that);
|
const event = new HookEvent(
|
||||||
this.emit('createTreeWalker', event);
|
{ root, show, filter, expandEntityReferences },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
this.emit('createTreeWalker', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.root, event.data.show, event.data.filter, event.data.expandEntityReferences);
|
return event.target.call(
|
||||||
});
|
event.that,
|
||||||
};
|
event.data.root,
|
||||||
|
event.data.show,
|
||||||
|
event.data.filter,
|
||||||
|
event.data.expandEntityReferences
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
overrideWrite() {
|
overrideWrite() {
|
||||||
this.ctx.override(this.docProto, 'write', (target, that, args) => {
|
this.ctx.override(this.docProto, 'write', (target, that, args) => {
|
||||||
if (!args.length) return target.apply(that, args);
|
if (!args.length) return target.apply(that, args);
|
||||||
let [ ...html ] = args;
|
let [...html] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ html }, target, that);
|
const event = new HookEvent({ html }, target, that);
|
||||||
this.emit('write', event);
|
this.emit('write', event);
|
||||||
|
@ -101,7 +154,7 @@ class DocumentHook extends EventEmitter {
|
||||||
});
|
});
|
||||||
this.ctx.override(this.docProto, 'writeln', (target, that, args) => {
|
this.ctx.override(this.docProto, 'writeln', (target, that, args) => {
|
||||||
if (!args.length) return target.apply(that, args);
|
if (!args.length) return target.apply(that, args);
|
||||||
let [ ...html ] = args;
|
let [...html] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ html }, target, that);
|
const event = new HookEvent({ html }, target, that);
|
||||||
this.emit('writeln', event);
|
this.emit('writeln', event);
|
||||||
|
@ -109,76 +162,96 @@ class DocumentHook extends EventEmitter {
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.apply(event.that, event.data.html);
|
return event.target.apply(event.that, event.data.html);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideDocumentURI() {
|
overrideDocumentURI() {
|
||||||
this.ctx.overrideDescriptor(this.docProto, 'documentURI', {
|
this.ctx.overrideDescriptor(this.docProto, 'documentURI', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('documentURI', event);
|
this.emit('documentURI', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.value;
|
return event.data.value;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideURL() {
|
overrideURL() {
|
||||||
this.ctx.overrideDescriptor(this.docProto, 'URL', {
|
this.ctx.overrideDescriptor(this.docProto, 'URL', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('url', event);
|
this.emit('url', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.value;
|
return event.data.value;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideReferrer() {
|
overrideReferrer() {
|
||||||
this.ctx.overrideDescriptor(this.docProto, 'referrer', {
|
this.ctx.overrideDescriptor(this.docProto, 'referrer', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('referrer', event);
|
this.emit('referrer', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.value;
|
return event.data.value;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideCookie() {
|
overrideCookie() {
|
||||||
this.ctx.overrideDescriptor(this.docProto, 'cookie', {
|
this.ctx.overrideDescriptor(this.docProto, 'cookie', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('getCookie', event);
|
this.emit('getCookie', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.value;
|
return event.data.value;
|
||||||
},
|
},
|
||||||
set: (target, that, [ value ]) => {
|
set: (target, that, [value]) => {
|
||||||
const event = new HookEvent({ value, }, target, that);
|
const event = new HookEvent({ value }, target, that);
|
||||||
this.emit('setCookie', event);
|
this.emit('setCookie', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.value);
|
return event.target.call(event.that, event.data.value);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideTitle() {
|
overrideTitle() {
|
||||||
this.ctx.overrideDescriptor(this.docProto, 'title', {
|
this.ctx.overrideDescriptor(this.docProto, 'title', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('getTitle', event);
|
this.emit('getTitle', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.value;
|
return event.data.value;
|
||||||
},
|
},
|
||||||
set: (target, that, [ value ]) => {
|
set: (target, that, [value]) => {
|
||||||
const event = new HookEvent({ value, }, target, that);
|
const event = new HookEvent({ value }, target, that);
|
||||||
this.emit('setTitle', event);
|
this.emit('setTitle', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.value);
|
return event.target.call(event.that, event.data.value);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default DocumentHook;
|
export default DocumentHook;
|
|
@ -1,5 +1,5 @@
|
||||||
import EventEmitter from "../events.js";
|
import EventEmitter from '../events.js';
|
||||||
import HookEvent from "../hook.js";
|
import HookEvent from '../hook.js';
|
||||||
|
|
||||||
class ElementApi extends EventEmitter {
|
class ElementApi extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -9,8 +9,14 @@ class ElementApi extends EventEmitter {
|
||||||
this.Audio = this.window.Audio;
|
this.Audio = this.window.Audio;
|
||||||
this.Element = this.window.Element;
|
this.Element = this.window.Element;
|
||||||
this.elemProto = this.Element ? this.Element.prototype : {};
|
this.elemProto = this.Element ? this.Element.prototype : {};
|
||||||
this.innerHTML = ctx.nativeMethods.getOwnPropertyDescriptor(this.elemProto, 'innerHTML');
|
this.innerHTML = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
this.outerHTML = ctx.nativeMethods.getOwnPropertyDescriptor(this.elemProto, 'outerHTML');
|
this.elemProto,
|
||||||
|
'innerHTML'
|
||||||
|
);
|
||||||
|
this.outerHTML = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.elemProto,
|
||||||
|
'outerHTML'
|
||||||
|
);
|
||||||
this.setAttribute = this.elemProto.setAttribute;
|
this.setAttribute = this.elemProto.setAttribute;
|
||||||
this.getAttribute = this.elemProto.getAttribute;
|
this.getAttribute = this.elemProto.getAttribute;
|
||||||
this.removeAttribute = this.elemProto.removeAttribute;
|
this.removeAttribute = this.elemProto.removeAttribute;
|
||||||
|
@ -19,83 +25,116 @@ class ElementApi extends EventEmitter {
|
||||||
this.querySelectorAll = this.elemProto.querySelectorAll;
|
this.querySelectorAll = this.elemProto.querySelectorAll;
|
||||||
this.insertAdjacentHTML = this.elemProto.insertAdjacentHTML;
|
this.insertAdjacentHTML = this.elemProto.insertAdjacentHTML;
|
||||||
this.insertAdjacentText = this.elemProto.insertAdjacentText;
|
this.insertAdjacentText = this.elemProto.insertAdjacentText;
|
||||||
};
|
}
|
||||||
overrideQuerySelector() {
|
overrideQuerySelector() {
|
||||||
this.ctx.override(this.elemProto, 'querySelector', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return target.apply(that, args);
|
this.elemProto,
|
||||||
let [ selectors ] = args;
|
'querySelector',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return target.apply(that, args);
|
||||||
|
let [selectors] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ selectors }, target, that);
|
const event = new HookEvent({ selectors }, target, that);
|
||||||
this.emit('querySelector', event);
|
this.emit('querySelector', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.selectors);
|
return event.target.call(event.that, event.data.selectors);
|
||||||
});
|
}
|
||||||
};
|
);
|
||||||
|
}
|
||||||
overrideAttribute() {
|
overrideAttribute() {
|
||||||
this.ctx.override(this.elemProto, 'getAttribute', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return target.apply(that, args);
|
this.elemProto,
|
||||||
let [ name ] = args;
|
'getAttribute',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return target.apply(that, args);
|
||||||
|
let [name] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ name }, target, that);
|
const event = new HookEvent({ name }, target, that);
|
||||||
this.emit('getAttribute', event);
|
this.emit('getAttribute', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.name);
|
return event.target.call(event.that, event.data.name);
|
||||||
});
|
}
|
||||||
this.ctx.override(this.elemProto, 'setAttribute', (target, that, args) => {
|
);
|
||||||
if (2 > args.length) return target.apply(that, args);
|
this.ctx.override(
|
||||||
let [ name, value ] = args;
|
this.elemProto,
|
||||||
|
'setAttribute',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (2 > args.length) return target.apply(that, args);
|
||||||
|
let [name, value] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ name, value }, target, that);
|
const event = new HookEvent({ name, value }, target, that);
|
||||||
this.emit('setAttribute', event);
|
this.emit('setAttribute', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.name, event.data.value);
|
return event.target.call(
|
||||||
});
|
event.that,
|
||||||
this.ctx.override(this.elemProto, 'hasAttribute', (target, that, args) => {
|
event.data.name,
|
||||||
if (!args.length) return target.apply(that, args);
|
event.data.value
|
||||||
let [ name ] = args;
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.ctx.override(
|
||||||
|
this.elemProto,
|
||||||
|
'hasAttribute',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return target.apply(that, args);
|
||||||
|
let [name] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ name }, target, that);
|
const event = new HookEvent({ name }, target, that);
|
||||||
this.emit('hasAttribute', event);
|
this.emit('hasAttribute', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.name);
|
return event.target.call(event.that, event.data.name);
|
||||||
});
|
}
|
||||||
this.ctx.override(this.elemProto, 'removeAttribute', (target, that, args) => {
|
);
|
||||||
if (!args.length) return target.apply(that, args);
|
this.ctx.override(
|
||||||
let [ name ] = args;
|
this.elemProto,
|
||||||
|
'removeAttribute',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return target.apply(that, args);
|
||||||
|
let [name] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ name }, target, that);
|
const event = new HookEvent({ name }, target, that);
|
||||||
this.emit('removeAttribute', event);
|
this.emit('removeAttribute', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.name);
|
return event.target.call(event.that, event.data.name);
|
||||||
});
|
}
|
||||||
};
|
);
|
||||||
|
}
|
||||||
overrideAudio() {
|
overrideAudio() {
|
||||||
this.ctx.override(this.window, 'Audio', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return new target(...args);
|
this.window,
|
||||||
let [ url ] = args;
|
'Audio',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return new target(...args);
|
||||||
|
let [url] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ url }, target, that);
|
const event = new HookEvent({ url }, target, that);
|
||||||
this.emit('audio', event);
|
this.emit('audio', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return new event.target(event.data.url);
|
return new event.target(event.data.url);
|
||||||
}, true);
|
},
|
||||||
};
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
overrideHtml() {
|
overrideHtml() {
|
||||||
this.hookProperty(this.Element, 'innerHTML', {
|
this.hookProperty(this.Element, 'innerHTML', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('getInnerHTML', event);
|
this.emit('getInnerHTML', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.value;
|
return event.data.value;
|
||||||
},
|
},
|
||||||
set: (target, that, [ val ]) => {
|
set: (target, that, [val]) => {
|
||||||
const event = new HookEvent({ value: val }, target, that);
|
const event = new HookEvent({ value: val }, target, that);
|
||||||
this.emit('setInnerHTML', event);
|
this.emit('setInnerHTML', event);
|
||||||
|
|
||||||
|
@ -105,13 +144,17 @@ class ElementApi extends EventEmitter {
|
||||||
});
|
});
|
||||||
this.hookProperty(this.Element, 'outerHTML', {
|
this.hookProperty(this.Element, 'outerHTML', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('getOuterHTML', event);
|
this.emit('getOuterHTML', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.value;
|
return event.data.value;
|
||||||
},
|
},
|
||||||
set: (target, that, [ val ]) => {
|
set: (target, that, [val]) => {
|
||||||
const event = new HookEvent({ value: val }, target, that);
|
const event = new HookEvent({ value: val }, target, that);
|
||||||
this.emit('setOuterHTML', event);
|
this.emit('setOuterHTML', event);
|
||||||
|
|
||||||
|
@ -119,47 +162,63 @@ class ElementApi extends EventEmitter {
|
||||||
target.call(that, event.data.value);
|
target.call(that, event.data.value);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideInsertAdjacentHTML() {
|
overrideInsertAdjacentHTML() {
|
||||||
this.ctx.override(this.elemProto, 'insertAdjacentHTML', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (2 > args.length) return target.apply(that, args);
|
this.elemProto,
|
||||||
let [ position, html ] = args;
|
'insertAdjacentHTML',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (2 > args.length) return target.apply(that, args);
|
||||||
|
let [position, html] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ position, html }, target, that);
|
const event = new HookEvent({ position, html }, target, that);
|
||||||
this.emit('insertAdjacentHTML', event);
|
this.emit('insertAdjacentHTML', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.position, event.data.html);
|
return event.target.call(
|
||||||
});
|
event.that,
|
||||||
};
|
event.data.position,
|
||||||
|
event.data.html
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
overrideInsertAdjacentText() {
|
overrideInsertAdjacentText() {
|
||||||
this.ctx.override(this.elemProto, 'insertAdjacentText', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (2 > args.length) return target.apply(that, args);
|
this.elemProto,
|
||||||
let [ position, text ] = args;
|
'insertAdjacentText',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (2 > args.length) return target.apply(that, args);
|
||||||
|
let [position, text] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ position, text }, target, that);
|
const event = new HookEvent({ position, text }, target, that);
|
||||||
this.emit('insertAdjacentText', event);
|
this.emit('insertAdjacentText', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.position, event.data.text);
|
return event.target.call(
|
||||||
});
|
event.that,
|
||||||
};
|
event.data.position,
|
||||||
|
event.data.text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
hookProperty(element, prop, handler) {
|
hookProperty(element, prop, handler) {
|
||||||
if (!element || !prop in element) return false;
|
if (!element || !prop in element) return false;
|
||||||
|
|
||||||
if (this.ctx.nativeMethods.isArray(element)) {
|
if (this.ctx.nativeMethods.isArray(element)) {
|
||||||
for (const elem of element) {
|
for (const elem of element) {
|
||||||
this.hookProperty(elem, prop, handler);
|
this.hookProperty(elem, prop, handler);
|
||||||
};
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
const proto = element.prototype;
|
const proto = element.prototype;
|
||||||
|
|
||||||
this.ctx.overrideDescriptor(proto, prop, handler);
|
this.ctx.overrideDescriptor(proto, prop, handler);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default ElementApi;
|
export default ElementApi;
|
|
@ -1,5 +1,5 @@
|
||||||
import EventEmitter from "../events.js";
|
import EventEmitter from '../events.js';
|
||||||
import HookEvent from "../hook.js";
|
import HookEvent from '../hook.js';
|
||||||
|
|
||||||
class NodeApi extends EventEmitter {
|
class NodeApi extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -16,24 +16,49 @@ class NodeApi extends EventEmitter {
|
||||||
this.appendChild = this.nodeProto.appendChild;
|
this.appendChild = this.nodeProto.appendChild;
|
||||||
this.removeChild = this.nodeProto.removeChild;
|
this.removeChild = this.nodeProto.removeChild;
|
||||||
|
|
||||||
this.textContent = ctx.nativeMethods.getOwnPropertyDescriptor(this.nodeProto, 'textContent');
|
this.textContent = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
this.parentNode = ctx.nativeMethods.getOwnPropertyDescriptor(this.nodeProto, 'parentNode');
|
this.nodeProto,
|
||||||
this.parentElement = ctx.nativeMethods.getOwnPropertyDescriptor(this.nodeProto, 'parentElement');
|
'textContent'
|
||||||
this.childNodes = ctx.nativeMethods.getOwnPropertyDescriptor(this.nodeProto, 'childNodes');
|
);
|
||||||
this.baseURI = ctx.nativeMethods.getOwnPropertyDescriptor(this.nodeProto, 'baseURI');
|
this.parentNode = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
this.previousSibling = ctx.nativeMethods.getOwnPropertyDescriptor(this.nodeProto, 'previousSibling');
|
this.nodeProto,
|
||||||
this.ownerDocument = ctx.nativeMethods.getOwnPropertyDescriptor(this.nodeProto, 'ownerDocument');
|
'parentNode'
|
||||||
};
|
);
|
||||||
|
this.parentElement = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.nodeProto,
|
||||||
|
'parentElement'
|
||||||
|
);
|
||||||
|
this.childNodes = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.nodeProto,
|
||||||
|
'childNodes'
|
||||||
|
);
|
||||||
|
this.baseURI = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.nodeProto,
|
||||||
|
'baseURI'
|
||||||
|
);
|
||||||
|
this.previousSibling = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.nodeProto,
|
||||||
|
'previousSibling'
|
||||||
|
);
|
||||||
|
this.ownerDocument = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.nodeProto,
|
||||||
|
'ownerDocument'
|
||||||
|
);
|
||||||
|
}
|
||||||
overrideTextContent() {
|
overrideTextContent() {
|
||||||
this.ctx.overrideDescriptor(this.nodeProto, 'textContent', {
|
this.ctx.overrideDescriptor(this.nodeProto, 'textContent', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('getTextContent', event);
|
this.emit('getTextContent', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.value;
|
return event.data.value;
|
||||||
},
|
},
|
||||||
set: (target, that, [ val ]) => {
|
set: (target, that, [val]) => {
|
||||||
const event = new HookEvent({ value: val }, target, that);
|
const event = new HookEvent({ value: val }, target, that);
|
||||||
this.emit('setTextContent', event);
|
this.emit('setTextContent', event);
|
||||||
|
|
||||||
|
@ -41,41 +66,57 @@ class NodeApi extends EventEmitter {
|
||||||
target.call(that, event.data.value);
|
target.call(that, event.data.value);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideAppend() {
|
overrideAppend() {
|
||||||
this.ctx.override(this.nodeProto, 'append', (target, that, [ ...nodes ]) => {
|
this.ctx.override(
|
||||||
const event = new HookEvent({ nodes }, target, that);
|
this.nodeProto,
|
||||||
this.emit('append', event);
|
'append',
|
||||||
|
(target, that, [...nodes]) => {
|
||||||
|
const event = new HookEvent({ nodes }, target, that);
|
||||||
|
this.emit('append', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.nodes);
|
return event.target.call(event.that, event.data.nodes);
|
||||||
});
|
}
|
||||||
this.ctx.override(this.nodeProto, 'appendChild', (target, that, args) => {
|
);
|
||||||
if (!args.length) return target.apply(that, args);
|
this.ctx.override(
|
||||||
let [ node ] = args;
|
this.nodeProto,
|
||||||
|
'appendChild',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return target.apply(that, args);
|
||||||
|
let [node] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ node }, target, that);
|
const event = new HookEvent({ node }, target, that);
|
||||||
this.emit('appendChild', event);
|
this.emit('appendChild', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.node);
|
return event.target.call(event.that, event.data.node);
|
||||||
});
|
}
|
||||||
};
|
);
|
||||||
|
}
|
||||||
overrideBaseURI() {
|
overrideBaseURI() {
|
||||||
this.ctx.overrideDescriptor(this.nodeProto, 'baseURI', {
|
this.ctx.overrideDescriptor(this.nodeProto, 'baseURI', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('baseURI', event);
|
this.emit('baseURI', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.value;
|
return event.data.value;
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
};
|
}
|
||||||
overrideParent() {
|
overrideParent() {
|
||||||
this.ctx.overrideDescriptor(this.nodeProto, 'parentNode', {
|
this.ctx.overrideDescriptor(this.nodeProto, 'parentNode', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ node: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ node: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('parentNode', event);
|
this.emit('parentNode', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
|
@ -84,38 +125,50 @@ class NodeApi extends EventEmitter {
|
||||||
});
|
});
|
||||||
this.ctx.overrideDescriptor(this.nodeProto, 'parentElement', {
|
this.ctx.overrideDescriptor(this.nodeProto, 'parentElement', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ element: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ element: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('parentElement', event);
|
this.emit('parentElement', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.node;
|
return event.data.node;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideOwnerDocument() {
|
overrideOwnerDocument() {
|
||||||
this.ctx.overrideDescriptor(this.nodeProto, 'ownerDocument', {
|
this.ctx.overrideDescriptor(this.nodeProto, 'ownerDocument', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ document: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ document: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('ownerDocument', event);
|
this.emit('ownerDocument', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.document;
|
return event.data.document;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideCompareDocumentPosit1ion() {
|
overrideCompareDocumentPosit1ion() {
|
||||||
this.ctx.override(this.nodeProto, 'compareDocumentPosition', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return target.apply(that, args);
|
this.nodeProto,
|
||||||
let [ node ] = args;
|
'compareDocumentPosition',
|
||||||
const event = new HookEvent({ node }, target, that);
|
(target, that, args) => {
|
||||||
|
if (!args.length) return target.apply(that, args);
|
||||||
|
let [node] = args;
|
||||||
|
const event = new HookEvent({ node }, target, that);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.node);
|
return event.target.call(event.that, event.data.node);
|
||||||
});
|
}
|
||||||
};
|
);
|
||||||
|
}
|
||||||
overrideChildMethods() {
|
overrideChildMethods() {
|
||||||
this.ctx.override(this.nodeProto, 'removeChild')
|
this.ctx.override(this.nodeProto, 'removeChild');
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default NodeApi;
|
export default NodeApi;
|
|
@ -1,5 +1,5 @@
|
||||||
import EventEmitter from "../events.js";
|
import EventEmitter from '../events.js';
|
||||||
import HookEvent from "../hook.js";
|
import HookEvent from '../hook.js';
|
||||||
|
|
||||||
class StyleApi extends EventEmitter {
|
class StyleApi extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -10,9 +10,29 @@ class StyleApi extends EventEmitter {
|
||||||
this.cssStyleProto = this.CSSStyleDeclaration.prototype || {};
|
this.cssStyleProto = this.CSSStyleDeclaration.prototype || {};
|
||||||
this.getPropertyValue = this.cssStyleProto.getPropertyValue || null;
|
this.getPropertyValue = this.cssStyleProto.getPropertyValue || null;
|
||||||
this.setProperty = this.cssStyleProto.setProperty || null;
|
this.setProperty = this.cssStyleProto.setProperty || null;
|
||||||
this.cssText - ctx.nativeMethods.getOwnPropertyDescriptors(this.cssStyleProto, 'cssText');
|
this.cssText -
|
||||||
this.urlProps = ['background', 'backgroundImage', 'borderImage', 'borderImageSource', 'listStyle', 'listStyleImage', 'cursor'];
|
ctx.nativeMethods.getOwnPropertyDescriptors(
|
||||||
this.dashedUrlProps = ['background', 'background-image', 'border-image', 'border-image-source', 'list-style', 'list-style-image', 'cursor'];
|
this.cssStyleProto,
|
||||||
|
'cssText'
|
||||||
|
);
|
||||||
|
this.urlProps = [
|
||||||
|
'background',
|
||||||
|
'backgroundImage',
|
||||||
|
'borderImage',
|
||||||
|
'borderImageSource',
|
||||||
|
'listStyle',
|
||||||
|
'listStyleImage',
|
||||||
|
'cursor',
|
||||||
|
];
|
||||||
|
this.dashedUrlProps = [
|
||||||
|
'background',
|
||||||
|
'background-image',
|
||||||
|
'border-image',
|
||||||
|
'border-image-source',
|
||||||
|
'list-style',
|
||||||
|
'list-style-image',
|
||||||
|
'cursor',
|
||||||
|
];
|
||||||
this.propToDashed = {
|
this.propToDashed = {
|
||||||
background: 'background',
|
background: 'background',
|
||||||
backgroundImage: 'background-image',
|
backgroundImage: 'background-image',
|
||||||
|
@ -20,42 +40,58 @@ class StyleApi extends EventEmitter {
|
||||||
borderImageSource: 'border-image-source',
|
borderImageSource: 'border-image-source',
|
||||||
listStyle: 'list-style',
|
listStyle: 'list-style',
|
||||||
listStyleImage: 'list-style-image',
|
listStyleImage: 'list-style-image',
|
||||||
cursor: 'cursor'
|
cursor: 'cursor',
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
overrideSetGetProperty() {
|
overrideSetGetProperty() {
|
||||||
this.ctx.override(this.cssStyleProto, 'getPropertyValue', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return target.apply(that, args);
|
this.cssStyleProto,
|
||||||
|
'getPropertyValue',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return target.apply(that, args);
|
||||||
|
|
||||||
let [ property ] = args;
|
let [property] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ property }, target, that);
|
const event = new HookEvent({ property }, target, that);
|
||||||
this.emit('getPropertyValue', event);
|
this.emit('getPropertyValue', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.property);
|
return event.target.call(event.that, event.data.property);
|
||||||
});
|
}
|
||||||
this.ctx.override(this.cssStyleProto, 'setProperty', (target, that, args) => {
|
);
|
||||||
if (2 > args.length) return target.apply(that, args);
|
this.ctx.override(
|
||||||
let [ property, value ] = args;
|
this.cssStyleProto,
|
||||||
|
'setProperty',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (2 > args.length) return target.apply(that, args);
|
||||||
|
let [property, value] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ property, value }, target, that);
|
const event = new HookEvent({ property, value }, target, that);
|
||||||
this.emit('setProperty', event);
|
this.emit('setProperty', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.property, event.data.value);
|
return event.target.call(
|
||||||
});
|
event.that,
|
||||||
};
|
event.data.property,
|
||||||
|
event.data.value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
overrideCssText() {
|
overrideCssText() {
|
||||||
this.ctx.overrideDescriptor(this.cssStyleProto, 'cssText', {
|
this.ctx.overrideDescriptor(this.cssStyleProto, 'cssText', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('getCssText', event);
|
this.emit('getCssText', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.value;
|
return event.data.value;
|
||||||
},
|
},
|
||||||
set: (target, that, [ val ]) => {
|
set: (target, that, [val]) => {
|
||||||
const event = new HookEvent({ value: val }, target, that);
|
const event = new HookEvent({ value: val }, target, that);
|
||||||
this.emit('setCssText', event);
|
this.emit('setCssText', event);
|
||||||
|
|
||||||
|
@ -63,7 +99,7 @@ class StyleApi extends EventEmitter {
|
||||||
return event.target.call(event.that, event.data.value);
|
return event.target.call(event.that, event.data.value);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default StyleApi;
|
export default StyleApi;
|
|
@ -21,37 +21,41 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var R = typeof Reflect === 'object' ? Reflect : null
|
var R = typeof Reflect === 'object' ? Reflect : null;
|
||||||
var ReflectApply = R && typeof R.apply === 'function'
|
var ReflectApply =
|
||||||
? R.apply
|
R && typeof R.apply === 'function'
|
||||||
: function ReflectApply(target, receiver, args) {
|
? R.apply
|
||||||
return Function.prototype.apply.call(target, receiver, args);
|
: function ReflectApply(target, receiver, args) {
|
||||||
}
|
return Function.prototype.apply.call(target, receiver, args);
|
||||||
|
};
|
||||||
|
|
||||||
var ReflectOwnKeys
|
var ReflectOwnKeys;
|
||||||
if (R && typeof R.ownKeys === 'function') {
|
if (R && typeof R.ownKeys === 'function') {
|
||||||
ReflectOwnKeys = R.ownKeys
|
ReflectOwnKeys = R.ownKeys;
|
||||||
} else if (Object.getOwnPropertySymbols) {
|
} else if (Object.getOwnPropertySymbols) {
|
||||||
ReflectOwnKeys = function ReflectOwnKeys(target) {
|
ReflectOwnKeys = function ReflectOwnKeys(target) {
|
||||||
return Object.getOwnPropertyNames(target)
|
return Object.getOwnPropertyNames(target).concat(
|
||||||
.concat(Object.getOwnPropertySymbols(target));
|
Object.getOwnPropertySymbols(target)
|
||||||
};
|
);
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
ReflectOwnKeys = function ReflectOwnKeys(target) {
|
ReflectOwnKeys = function ReflectOwnKeys(target) {
|
||||||
return Object.getOwnPropertyNames(target);
|
return Object.getOwnPropertyNames(target);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function ProcessEmitWarning(warning) {
|
function ProcessEmitWarning(warning) {
|
||||||
if (console && console.warn) console.warn(warning);
|
if (console && console.warn) console.warn(warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {
|
var NumberIsNaN =
|
||||||
return value !== value;
|
Number.isNaN ||
|
||||||
}
|
function NumberIsNaN(value) {
|
||||||
|
return value !== value;
|
||||||
|
};
|
||||||
|
|
||||||
function EventEmitter() {
|
function EventEmitter() {
|
||||||
EventEmitter.init.call(this);
|
EventEmitter.init.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default EventEmitter;
|
export default EventEmitter;
|
||||||
|
@ -68,430 +72,451 @@ EventEmitter.prototype._maxListeners = undefined;
|
||||||
var defaultMaxListeners = 10;
|
var defaultMaxListeners = 10;
|
||||||
|
|
||||||
function checkListener(listener) {
|
function checkListener(listener) {
|
||||||
if (typeof listener !== 'function') {
|
if (typeof listener !== 'function') {
|
||||||
throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
|
throw new TypeError(
|
||||||
}
|
'The "listener" argument must be of type Function. Received type ' +
|
||||||
|
typeof listener
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
|
Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
get: function() {
|
get: function () {
|
||||||
return defaultMaxListeners;
|
return defaultMaxListeners;
|
||||||
},
|
},
|
||||||
set: function(arg) {
|
set: function (arg) {
|
||||||
if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
|
if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
|
||||||
throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.');
|
throw new RangeError(
|
||||||
}
|
'The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' +
|
||||||
defaultMaxListeners = arg;
|
arg +
|
||||||
}
|
'.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
defaultMaxListeners = arg;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
EventEmitter.init = function() {
|
EventEmitter.init = function () {
|
||||||
|
if (
|
||||||
|
this._events === undefined ||
|
||||||
|
this._events === Object.getPrototypeOf(this)._events
|
||||||
|
) {
|
||||||
|
this._events = Object.create(null);
|
||||||
|
this._eventsCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (this._events === undefined ||
|
this._maxListeners = this._maxListeners || undefined;
|
||||||
this._events === Object.getPrototypeOf(this)._events) {
|
|
||||||
this._events = Object.create(null);
|
|
||||||
this._eventsCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._maxListeners = this._maxListeners || undefined;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Obviously not all Emitters should be limited to 10. This function allows
|
// Obviously not all Emitters should be limited to 10. This function allows
|
||||||
// that to be increased. Set to zero for unlimited.
|
// that to be increased. Set to zero for unlimited.
|
||||||
EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
|
EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
|
||||||
if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
|
if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
|
||||||
throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.');
|
throw new RangeError(
|
||||||
}
|
'The value of "n" is out of range. It must be a non-negative number. Received ' +
|
||||||
this._maxListeners = n;
|
n +
|
||||||
return this;
|
'.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this._maxListeners = n;
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
function _getMaxListeners(that) {
|
function _getMaxListeners(that) {
|
||||||
if (that._maxListeners === undefined)
|
if (that._maxListeners === undefined)
|
||||||
return EventEmitter.defaultMaxListeners;
|
return EventEmitter.defaultMaxListeners;
|
||||||
return that._maxListeners;
|
return that._maxListeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
|
EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
|
||||||
return _getMaxListeners(this);
|
return _getMaxListeners(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
EventEmitter.prototype.emit = function emit(type) {
|
EventEmitter.prototype.emit = function emit(type) {
|
||||||
var args = [];
|
var args = [];
|
||||||
for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
|
for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
|
||||||
var doError = (type === 'error');
|
var doError = type === 'error';
|
||||||
|
|
||||||
var events = this._events;
|
var events = this._events;
|
||||||
if (events !== undefined)
|
if (events !== undefined) doError = doError && events.error === undefined;
|
||||||
doError = (doError && events.error === undefined);
|
else if (!doError) return false;
|
||||||
else if (!doError)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// If there is no 'error' event listener then throw.
|
// If there is no 'error' event listener then throw.
|
||||||
if (doError) {
|
if (doError) {
|
||||||
var er;
|
var er;
|
||||||
if (args.length > 0)
|
if (args.length > 0) er = args[0];
|
||||||
er = args[0];
|
if (er instanceof Error) {
|
||||||
if (er instanceof Error) {
|
// Note: The comments on the `throw` lines are intentional, they show
|
||||||
// Note: The comments on the `throw` lines are intentional, they show
|
// up in Node's output if this results in an unhandled exception.
|
||||||
// up in Node's output if this results in an unhandled exception.
|
throw er; // Unhandled 'error' event
|
||||||
throw er; // Unhandled 'error' event
|
}
|
||||||
|
// At least give some kind of context to the user
|
||||||
|
var err = new Error(
|
||||||
|
'Unhandled error.' + (er ? ' (' + er.message + ')' : '')
|
||||||
|
);
|
||||||
|
err.context = er;
|
||||||
|
throw err; // Unhandled 'error' event
|
||||||
}
|
}
|
||||||
// At least give some kind of context to the user
|
|
||||||
var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));
|
|
||||||
err.context = er;
|
|
||||||
throw err; // Unhandled 'error' event
|
|
||||||
}
|
|
||||||
|
|
||||||
var handler = events[type];
|
var handler = events[type];
|
||||||
|
|
||||||
if (handler === undefined)
|
if (handler === undefined) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
if (typeof handler === 'function') {
|
if (typeof handler === 'function') {
|
||||||
ReflectApply(handler, this, args);
|
ReflectApply(handler, this, args);
|
||||||
} else {
|
} else {
|
||||||
var len = handler.length;
|
var len = handler.length;
|
||||||
var listeners = arrayClone(handler, len);
|
var listeners = arrayClone(handler, len);
|
||||||
for (var i = 0; i < len; ++i)
|
for (var i = 0; i < len; ++i) ReflectApply(listeners[i], this, args);
|
||||||
ReflectApply(listeners[i], this, args);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
function _addListener(target, type, listener, prepend) {
|
function _addListener(target, type, listener, prepend) {
|
||||||
var m;
|
var m;
|
||||||
var events;
|
var events;
|
||||||
var existing;
|
var existing;
|
||||||
|
|
||||||
checkListener(listener);
|
checkListener(listener);
|
||||||
|
|
||||||
events = target._events;
|
events = target._events;
|
||||||
if (events === undefined) {
|
if (events === undefined) {
|
||||||
events = target._events = Object.create(null);
|
events = target._events = Object.create(null);
|
||||||
target._eventsCount = 0;
|
target._eventsCount = 0;
|
||||||
} else {
|
|
||||||
// To avoid recursion in the case that type === "newListener"! Before
|
|
||||||
// adding it to the listeners, first emit "newListener".
|
|
||||||
if (events.newListener !== undefined) {
|
|
||||||
target.emit('newListener', type,
|
|
||||||
listener.listener ? listener.listener : listener);
|
|
||||||
|
|
||||||
// Re-assign `events` because a newListener handler could have caused the
|
|
||||||
// this._events to be assigned to a new object
|
|
||||||
events = target._events;
|
|
||||||
}
|
|
||||||
existing = events[type];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existing === undefined) {
|
|
||||||
// Optimize the case of one listener. Don't need the extra array object.
|
|
||||||
existing = events[type] = listener;
|
|
||||||
++target._eventsCount;
|
|
||||||
} else {
|
|
||||||
if (typeof existing === 'function') {
|
|
||||||
// Adding the second element, need to change to array.
|
|
||||||
existing = events[type] =
|
|
||||||
prepend ? [listener, existing] : [existing, listener];
|
|
||||||
// If we've already got an array, just append.
|
|
||||||
} else if (prepend) {
|
|
||||||
existing.unshift(listener);
|
|
||||||
} else {
|
} else {
|
||||||
existing.push(listener);
|
// To avoid recursion in the case that type === "newListener"! Before
|
||||||
|
// adding it to the listeners, first emit "newListener".
|
||||||
|
if (events.newListener !== undefined) {
|
||||||
|
target.emit(
|
||||||
|
'newListener',
|
||||||
|
type,
|
||||||
|
listener.listener ? listener.listener : listener
|
||||||
|
);
|
||||||
|
|
||||||
|
// Re-assign `events` because a newListener handler could have caused the
|
||||||
|
// this._events to be assigned to a new object
|
||||||
|
events = target._events;
|
||||||
|
}
|
||||||
|
existing = events[type];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for listener leak
|
if (existing === undefined) {
|
||||||
m = _getMaxListeners(target);
|
// Optimize the case of one listener. Don't need the extra array object.
|
||||||
if (m > 0 && existing.length > m && !existing.warned) {
|
existing = events[type] = listener;
|
||||||
existing.warned = true;
|
++target._eventsCount;
|
||||||
// No error code for this since it is a Warning
|
} else {
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
if (typeof existing === 'function') {
|
||||||
var w = new Error('Possible EventEmitter memory leak detected. ' +
|
// Adding the second element, need to change to array.
|
||||||
existing.length + ' ' + String(type) + ' listeners ' +
|
existing = events[type] = prepend
|
||||||
'added. Use emitter.setMaxListeners() to ' +
|
? [listener, existing]
|
||||||
'increase limit');
|
: [existing, listener];
|
||||||
w.name = 'MaxListenersExceededWarning';
|
// If we've already got an array, just append.
|
||||||
w.emitter = target;
|
} else if (prepend) {
|
||||||
w.type = type;
|
existing.unshift(listener);
|
||||||
w.count = existing.length;
|
} else {
|
||||||
ProcessEmitWarning(w);
|
existing.push(listener);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return target;
|
// Check for listener leak
|
||||||
|
m = _getMaxListeners(target);
|
||||||
|
if (m > 0 && existing.length > m && !existing.warned) {
|
||||||
|
existing.warned = true;
|
||||||
|
// No error code for this since it is a Warning
|
||||||
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
|
var w = new Error(
|
||||||
|
'Possible EventEmitter memory leak detected. ' +
|
||||||
|
existing.length +
|
||||||
|
' ' +
|
||||||
|
String(type) +
|
||||||
|
' listeners ' +
|
||||||
|
'added. Use emitter.setMaxListeners() to ' +
|
||||||
|
'increase limit'
|
||||||
|
);
|
||||||
|
w.name = 'MaxListenersExceededWarning';
|
||||||
|
w.emitter = target;
|
||||||
|
w.type = type;
|
||||||
|
w.count = existing.length;
|
||||||
|
ProcessEmitWarning(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventEmitter.prototype.addListener = function addListener(type, listener) {
|
EventEmitter.prototype.addListener = function addListener(type, listener) {
|
||||||
return _addListener(this, type, listener, false);
|
return _addListener(this, type, listener, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
|
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
|
||||||
|
|
||||||
EventEmitter.prototype.prependListener =
|
EventEmitter.prototype.prependListener = function prependListener(
|
||||||
function prependListener(type, listener) {
|
type,
|
||||||
return _addListener(this, type, listener, true);
|
listener
|
||||||
};
|
) {
|
||||||
|
return _addListener(this, type, listener, true);
|
||||||
|
};
|
||||||
|
|
||||||
function onceWrapper() {
|
function onceWrapper() {
|
||||||
if (!this.fired) {
|
if (!this.fired) {
|
||||||
this.target.removeListener(this.type, this.wrapFn);
|
this.target.removeListener(this.type, this.wrapFn);
|
||||||
this.fired = true;
|
this.fired = true;
|
||||||
if (arguments.length === 0)
|
if (arguments.length === 0) return this.listener.call(this.target);
|
||||||
return this.listener.call(this.target);
|
return this.listener.apply(this.target, arguments);
|
||||||
return this.listener.apply(this.target, arguments);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _onceWrap(target, type, listener) {
|
function _onceWrap(target, type, listener) {
|
||||||
var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
|
var state = {
|
||||||
var wrapped = onceWrapper.bind(state);
|
fired: false,
|
||||||
wrapped.listener = listener;
|
wrapFn: undefined,
|
||||||
state.wrapFn = wrapped;
|
target: target,
|
||||||
return wrapped;
|
type: type,
|
||||||
|
listener: listener,
|
||||||
|
};
|
||||||
|
var wrapped = onceWrapper.bind(state);
|
||||||
|
wrapped.listener = listener;
|
||||||
|
state.wrapFn = wrapped;
|
||||||
|
return wrapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventEmitter.prototype.once = function once(type, listener) {
|
EventEmitter.prototype.once = function once(type, listener) {
|
||||||
checkListener(listener);
|
checkListener(listener);
|
||||||
this.on(type, _onceWrap(this, type, listener));
|
this.on(type, _onceWrap(this, type, listener));
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
EventEmitter.prototype.prependOnceListener =
|
EventEmitter.prototype.prependOnceListener = function prependOnceListener(
|
||||||
function prependOnceListener(type, listener) {
|
type,
|
||||||
checkListener(listener);
|
listener
|
||||||
this.prependListener(type, _onceWrap(this, type, listener));
|
) {
|
||||||
return this;
|
checkListener(listener);
|
||||||
};
|
this.prependListener(type, _onceWrap(this, type, listener));
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
// Emits a 'removeListener' event if and only if the listener was removed.
|
// Emits a 'removeListener' event if and only if the listener was removed.
|
||||||
EventEmitter.prototype.removeListener =
|
EventEmitter.prototype.removeListener = function removeListener(
|
||||||
function removeListener(type, listener) {
|
type,
|
||||||
var list, events, position, i, originalListener;
|
listener
|
||||||
|
) {
|
||||||
|
var list, events, position, i, originalListener;
|
||||||
|
|
||||||
checkListener(listener);
|
checkListener(listener);
|
||||||
|
|
||||||
events = this._events;
|
events = this._events;
|
||||||
if (events === undefined)
|
if (events === undefined) return this;
|
||||||
return this;
|
|
||||||
|
|
||||||
list = events[type];
|
list = events[type];
|
||||||
if (list === undefined)
|
if (list === undefined) return this;
|
||||||
return this;
|
|
||||||
|
|
||||||
if (list === listener || list.listener === listener) {
|
if (list === listener || list.listener === listener) {
|
||||||
if (--this._eventsCount === 0)
|
if (--this._eventsCount === 0) this._events = Object.create(null);
|
||||||
this._events = Object.create(null);
|
|
||||||
else {
|
else {
|
||||||
delete events[type];
|
delete events[type];
|
||||||
if (events.removeListener)
|
if (events.removeListener)
|
||||||
this.emit('removeListener', type, list.listener || listener);
|
this.emit('removeListener', type, list.listener || listener);
|
||||||
}
|
}
|
||||||
} else if (typeof list !== 'function') {
|
} else if (typeof list !== 'function') {
|
||||||
position = -1;
|
position = -1;
|
||||||
|
|
||||||
for (i = list.length - 1; i >= 0; i--) {
|
for (i = list.length - 1; i >= 0; i--) {
|
||||||
if (list[i] === listener || list[i].listener === listener) {
|
if (list[i] === listener || list[i].listener === listener) {
|
||||||
originalListener = list[i].listener;
|
originalListener = list[i].listener;
|
||||||
position = i;
|
position = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (position < 0)
|
if (position < 0) return this;
|
||||||
return this;
|
|
||||||
|
|
||||||
if (position === 0)
|
if (position === 0) list.shift();
|
||||||
list.shift();
|
|
||||||
else {
|
else {
|
||||||
spliceOne(list, position);
|
spliceOne(list, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list.length === 1)
|
if (list.length === 1) events[type] = list[0];
|
||||||
events[type] = list[0];
|
|
||||||
|
|
||||||
if (events.removeListener !== undefined)
|
if (events.removeListener !== undefined)
|
||||||
this.emit('removeListener', type, originalListener || listener);
|
this.emit('removeListener', type, originalListener || listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
||||||
|
|
||||||
EventEmitter.prototype.removeAllListeners =
|
EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) {
|
||||||
function removeAllListeners(type) {
|
var listeners, events, i;
|
||||||
var listeners, events, i;
|
|
||||||
|
|
||||||
events = this._events;
|
events = this._events;
|
||||||
if (events === undefined)
|
if (events === undefined) return this;
|
||||||
return this;
|
|
||||||
|
|
||||||
// not listening for removeListener, no need to emit
|
// not listening for removeListener, no need to emit
|
||||||
if (events.removeListener === undefined) {
|
if (events.removeListener === undefined) {
|
||||||
if (arguments.length === 0) {
|
if (arguments.length === 0) {
|
||||||
this._events = Object.create(null);
|
|
||||||
this._eventsCount = 0;
|
|
||||||
} else if (events[type] !== undefined) {
|
|
||||||
if (--this._eventsCount === 0)
|
|
||||||
this._events = Object.create(null);
|
this._events = Object.create(null);
|
||||||
else
|
this._eventsCount = 0;
|
||||||
delete events[type];
|
} else if (events[type] !== undefined) {
|
||||||
|
if (--this._eventsCount === 0) this._events = Object.create(null);
|
||||||
|
else delete events[type];
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// emit removeListener for all listeners on all events
|
// emit removeListener for all listeners on all events
|
||||||
if (arguments.length === 0) {
|
if (arguments.length === 0) {
|
||||||
var keys = Object.keys(events);
|
var keys = Object.keys(events);
|
||||||
var key;
|
var key;
|
||||||
for (i = 0; i < keys.length; ++i) {
|
for (i = 0; i < keys.length; ++i) {
|
||||||
key = keys[i];
|
key = keys[i];
|
||||||
if (key === 'removeListener') continue;
|
if (key === 'removeListener') continue;
|
||||||
this.removeAllListeners(key);
|
this.removeAllListeners(key);
|
||||||
}
|
}
|
||||||
this.removeAllListeners('removeListener');
|
this.removeAllListeners('removeListener');
|
||||||
this._events = Object.create(null);
|
this._events = Object.create(null);
|
||||||
this._eventsCount = 0;
|
this._eventsCount = 0;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
listeners = events[type];
|
listeners = events[type];
|
||||||
|
|
||||||
if (typeof listeners === 'function') {
|
if (typeof listeners === 'function') {
|
||||||
this.removeListener(type, listeners);
|
this.removeListener(type, listeners);
|
||||||
} else if (listeners !== undefined) {
|
} else if (listeners !== undefined) {
|
||||||
// LIFO order
|
// LIFO order
|
||||||
for (i = listeners.length - 1; i >= 0; i--) {
|
for (i = listeners.length - 1; i >= 0; i--) {
|
||||||
this.removeListener(type, listeners[i]);
|
this.removeListener(type, listeners[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
function _listeners(target, type, unwrap) {
|
function _listeners(target, type, unwrap) {
|
||||||
var events = target._events;
|
var events = target._events;
|
||||||
|
|
||||||
if (events === undefined)
|
if (events === undefined) return [];
|
||||||
return [];
|
|
||||||
|
|
||||||
var evlistener = events[type];
|
var evlistener = events[type];
|
||||||
if (evlistener === undefined)
|
if (evlistener === undefined) return [];
|
||||||
return [];
|
|
||||||
|
|
||||||
if (typeof evlistener === 'function')
|
if (typeof evlistener === 'function')
|
||||||
return unwrap ? [evlistener.listener || evlistener] : [evlistener];
|
return unwrap ? [evlistener.listener || evlistener] : [evlistener];
|
||||||
|
|
||||||
return unwrap ?
|
return unwrap
|
||||||
unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
|
? unwrapListeners(evlistener)
|
||||||
|
: arrayClone(evlistener, evlistener.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventEmitter.prototype.listeners = function listeners(type) {
|
EventEmitter.prototype.listeners = function listeners(type) {
|
||||||
return _listeners(this, type, true);
|
return _listeners(this, type, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
EventEmitter.prototype.rawListeners = function rawListeners(type) {
|
EventEmitter.prototype.rawListeners = function rawListeners(type) {
|
||||||
return _listeners(this, type, false);
|
return _listeners(this, type, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
EventEmitter.listenerCount = function(emitter, type) {
|
EventEmitter.listenerCount = function (emitter, type) {
|
||||||
if (typeof emitter.listenerCount === 'function') {
|
if (typeof emitter.listenerCount === 'function') {
|
||||||
return emitter.listenerCount(type);
|
return emitter.listenerCount(type);
|
||||||
} else {
|
} else {
|
||||||
return listenerCount.call(emitter, type);
|
return listenerCount.call(emitter, type);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
EventEmitter.prototype.listenerCount = listenerCount;
|
EventEmitter.prototype.listenerCount = listenerCount;
|
||||||
function listenerCount(type) {
|
function listenerCount(type) {
|
||||||
var events = this._events;
|
var events = this._events;
|
||||||
|
|
||||||
if (events !== undefined) {
|
if (events !== undefined) {
|
||||||
var evlistener = events[type];
|
var evlistener = events[type];
|
||||||
|
|
||||||
if (typeof evlistener === 'function') {
|
if (typeof evlistener === 'function') {
|
||||||
return 1;
|
return 1;
|
||||||
} else if (evlistener !== undefined) {
|
} else if (evlistener !== undefined) {
|
||||||
return evlistener.length;
|
return evlistener.length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventEmitter.prototype.eventNames = function eventNames() {
|
EventEmitter.prototype.eventNames = function eventNames() {
|
||||||
return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
|
return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
|
||||||
};
|
};
|
||||||
|
|
||||||
function arrayClone(arr, n) {
|
function arrayClone(arr, n) {
|
||||||
var copy = new Array(n);
|
var copy = new Array(n);
|
||||||
for (var i = 0; i < n; ++i)
|
for (var i = 0; i < n; ++i) copy[i] = arr[i];
|
||||||
copy[i] = arr[i];
|
return copy;
|
||||||
return copy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function spliceOne(list, index) {
|
function spliceOne(list, index) {
|
||||||
for (; index + 1 < list.length; index++)
|
for (; index + 1 < list.length; index++) list[index] = list[index + 1];
|
||||||
list[index] = list[index + 1];
|
list.pop();
|
||||||
list.pop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function unwrapListeners(arr) {
|
function unwrapListeners(arr) {
|
||||||
var ret = new Array(arr.length);
|
var ret = new Array(arr.length);
|
||||||
for (var i = 0; i < ret.length; ++i) {
|
for (var i = 0; i < ret.length; ++i) {
|
||||||
ret[i] = arr[i].listener || arr[i];
|
ret[i] = arr[i].listener || arr[i];
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
function once(emitter, name) {
|
function once(emitter, name) {
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
function errorListener(err) {
|
function errorListener(err) {
|
||||||
emitter.removeListener(name, resolver);
|
emitter.removeListener(name, resolver);
|
||||||
reject(err);
|
reject(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolver() {
|
function resolver() {
|
||||||
if (typeof emitter.removeListener === 'function') {
|
if (typeof emitter.removeListener === 'function') {
|
||||||
emitter.removeListener('error', errorListener);
|
emitter.removeListener('error', errorListener);
|
||||||
}
|
}
|
||||||
resolve([].slice.call(arguments));
|
resolve([].slice.call(arguments));
|
||||||
};
|
}
|
||||||
|
|
||||||
eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });
|
eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });
|
||||||
if (name !== 'error') {
|
if (name !== 'error') {
|
||||||
addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });
|
addErrorHandlerIfEventEmitter(emitter, errorListener, {
|
||||||
}
|
once: true,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addErrorHandlerIfEventEmitter(emitter, handler, flags) {
|
function addErrorHandlerIfEventEmitter(emitter, handler, flags) {
|
||||||
if (typeof emitter.on === 'function') {
|
if (typeof emitter.on === 'function') {
|
||||||
eventTargetAgnosticAddListener(emitter, 'error', handler, flags);
|
eventTargetAgnosticAddListener(emitter, 'error', handler, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
|
function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
|
||||||
if (typeof emitter.on === 'function') {
|
if (typeof emitter.on === 'function') {
|
||||||
if (flags.once) {
|
if (flags.once) {
|
||||||
emitter.once(name, listener);
|
emitter.once(name, listener);
|
||||||
|
} else {
|
||||||
|
emitter.on(name, listener);
|
||||||
|
}
|
||||||
|
} else if (typeof emitter.addEventListener === 'function') {
|
||||||
|
// EventTarget does not have `error` event semantics like Node
|
||||||
|
// EventEmitters, we do not listen for `error` events here.
|
||||||
|
emitter.addEventListener(name, function wrapListener(arg) {
|
||||||
|
// IE does not have builtin `{ once: true }` support so we
|
||||||
|
// have to do it manually.
|
||||||
|
if (flags.once) {
|
||||||
|
emitter.removeEventListener(name, wrapListener);
|
||||||
|
}
|
||||||
|
listener(arg);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
emitter.on(name, listener);
|
throw new TypeError(
|
||||||
|
'The "emitter" argument must be of type EventEmitter. Received type ' +
|
||||||
|
typeof emitter
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if (typeof emitter.addEventListener === 'function') {
|
|
||||||
// EventTarget does not have `error` event semantics like Node
|
|
||||||
// EventEmitters, we do not listen for `error` events here.
|
|
||||||
emitter.addEventListener(name, function wrapListener(arg) {
|
|
||||||
// IE does not have builtin `{ once: true }` support so we
|
|
||||||
// have to do it manually.
|
|
||||||
if (flags.once) {
|
|
||||||
emitter.removeEventListener(name, wrapListener);
|
|
||||||
}
|
|
||||||
listener(arg);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import EventEmitter from "./events.js";
|
import EventEmitter from './events.js';
|
||||||
import HookEvent from "./hook.js";
|
import HookEvent from './hook.js';
|
||||||
|
|
||||||
class History extends EventEmitter {
|
class History extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -14,47 +14,73 @@ class History extends EventEmitter {
|
||||||
this.go = this.historyProto.go;
|
this.go = this.historyProto.go;
|
||||||
this.back = this.historyProto.back;
|
this.back = this.historyProto.back;
|
||||||
this.forward = this.historyProto.forward;
|
this.forward = this.historyProto.forward;
|
||||||
};
|
}
|
||||||
override() {
|
override() {
|
||||||
this.overridePushState();
|
this.overridePushState();
|
||||||
this.overrideReplaceState();
|
this.overrideReplaceState();
|
||||||
this.overrideGo();
|
this.overrideGo();
|
||||||
this.overrideForward();
|
this.overrideForward();
|
||||||
this.overrideBack();
|
this.overrideBack();
|
||||||
};
|
}
|
||||||
overridePushState() {
|
overridePushState() {
|
||||||
this.ctx.override(this.historyProto, 'pushState', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (2 > args.length) return target.apply(that, args);
|
this.historyProto,
|
||||||
let [ state, title, url = '' ] = args;
|
'pushState',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (2 > args.length) return target.apply(that, args);
|
||||||
|
let [state, title, url = ''] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ state, title, url }, target, that);
|
const event = new HookEvent(
|
||||||
this.emit('pushState', event);
|
{ state, title, url },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
this.emit('pushState', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.state, event.data.title, event.data.url);
|
return event.target.call(
|
||||||
});
|
event.that,
|
||||||
};
|
event.data.state,
|
||||||
|
event.data.title,
|
||||||
|
event.data.url
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
overrideReplaceState() {
|
overrideReplaceState() {
|
||||||
this.ctx.override(this.historyProto, 'replaceState', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (2 > args.length) return target.apply(that, args);
|
this.historyProto,
|
||||||
let [ state, title, url = '' ] = args;
|
'replaceState',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (2 > args.length) return target.apply(that, args);
|
||||||
|
let [state, title, url = ''] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ state, title, url }, target, that);
|
const event = new HookEvent(
|
||||||
this.emit('replaceState', event);
|
{ state, title, url },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
this.emit('replaceState', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.state, event.data.title, event.data.url);
|
return event.target.call(
|
||||||
});
|
event.that,
|
||||||
};
|
event.data.state,
|
||||||
|
event.data.title,
|
||||||
|
event.data.url
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
overrideGo() {
|
overrideGo() {
|
||||||
this.ctx.override(this.historyProto, 'go', (target, that, [ delta ]) => {
|
this.ctx.override(this.historyProto, 'go', (target, that, [delta]) => {
|
||||||
const event = new HookEvent({ delta }, target, that);
|
const event = new HookEvent({ delta }, target, that);
|
||||||
this.emit('go', event);
|
this.emit('go', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.delta);
|
return event.target.call(event.that, event.data.delta);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideForward() {
|
overrideForward() {
|
||||||
this.ctx.override(this.historyProto, 'forward', (target, that) => {
|
this.ctx.override(this.historyProto, 'forward', (target, that) => {
|
||||||
const event = new HookEvent(null, target, that);
|
const event = new HookEvent(null, target, that);
|
||||||
|
@ -63,7 +89,7 @@ class History extends EventEmitter {
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that);
|
return event.target.call(event.that);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideBack() {
|
overrideBack() {
|
||||||
this.ctx.override(this.historyProto, 'back', (target, that) => {
|
this.ctx.override(this.historyProto, 'back', (target, that) => {
|
||||||
const event = new HookEvent(null, target, that);
|
const event = new HookEvent(null, target, that);
|
||||||
|
@ -72,7 +98,7 @@ class History extends EventEmitter {
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that);
|
return event.target.call(event.that);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default History;
|
export default History;
|
|
@ -7,17 +7,17 @@ class HookEvent {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
this.that = that;
|
this.that = that;
|
||||||
};
|
}
|
||||||
get intercepted() {
|
get intercepted() {
|
||||||
return this.#intercepted;
|
return this.#intercepted;
|
||||||
};
|
}
|
||||||
get returnValue() {
|
get returnValue() {
|
||||||
return this.#returnValue;
|
return this.#returnValue;
|
||||||
};
|
}
|
||||||
respondWith(input) {
|
respondWith(input) {
|
||||||
this.#returnValue = input;
|
this.#returnValue = input;
|
||||||
this.#intercepted = true;
|
this.#intercepted = true;
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default HookEvent;
|
export default HookEvent;
|
|
@ -1,22 +1,22 @@
|
||||||
import DocumentHook from "./dom/document.js";
|
import DocumentHook from './dom/document.js';
|
||||||
import ElementApi from "./dom/element.js";
|
import ElementApi from './dom/element.js';
|
||||||
import NodeApi from "./dom/node.js";
|
import NodeApi from './dom/node.js';
|
||||||
import AttrApi from "./dom/attr.js";
|
import AttrApi from './dom/attr.js';
|
||||||
import FunctionHook from "./native/function.js";
|
import FunctionHook from './native/function.js';
|
||||||
import ObjectHook from "./native/object.js";
|
import ObjectHook from './native/object.js';
|
||||||
import Fetch from "./requests/fetch.js";
|
import Fetch from './requests/fetch.js';
|
||||||
import WebSocketApi from "./requests/websocket.js";
|
import WebSocketApi from './requests/websocket.js';
|
||||||
import Xhr from "./requests/xhr.js";
|
import Xhr from './requests/xhr.js';
|
||||||
import EventSourceApi from "./requests/eventsource.js";
|
import EventSourceApi from './requests/eventsource.js';
|
||||||
import History from "./history.js";
|
import History from './history.js';
|
||||||
import LocationApi from "./location.js";
|
import LocationApi from './location.js';
|
||||||
import MessageApi from "./message.js";
|
import MessageApi from './message.js';
|
||||||
import NavigatorApi from "./navigator.js";
|
import NavigatorApi from './navigator.js';
|
||||||
import Workers from "./worker.js";
|
import Workers from './worker.js';
|
||||||
import URLApi from "./url.js";
|
import URLApi from './url.js';
|
||||||
import EventEmitter from "./events.js";
|
import EventEmitter from './events.js';
|
||||||
import StorageApi from "./storage.js";
|
import StorageApi from './storage.js';
|
||||||
import StyleApi from "./dom/style.js";
|
import StyleApi from './dom/style.js';
|
||||||
|
|
||||||
class UVClient extends EventEmitter {
|
class UVClient extends EventEmitter {
|
||||||
constructor(window = self, worker = !window.window) {
|
constructor(window = self, worker = !window.window) {
|
||||||
|
@ -25,8 +25,10 @@ class UVClient extends EventEmitter {
|
||||||
this.nativeMethods = {
|
this.nativeMethods = {
|
||||||
fnToString: this.window.Function.prototype.toString,
|
fnToString: this.window.Function.prototype.toString,
|
||||||
defineProperty: this.window.Object.defineProperty,
|
defineProperty: this.window.Object.defineProperty,
|
||||||
getOwnPropertyDescriptor: this.window.Object.getOwnPropertyDescriptor,
|
getOwnPropertyDescriptor:
|
||||||
getOwnPropertyDescriptors: this.window.Object.getOwnPropertyDescriptors,
|
this.window.Object.getOwnPropertyDescriptor,
|
||||||
|
getOwnPropertyDescriptors:
|
||||||
|
this.window.Object.getOwnPropertyDescriptors,
|
||||||
getOwnPropertyNames: this.window.Object.getOwnPropertyNames,
|
getOwnPropertyNames: this.window.Object.getOwnPropertyNames,
|
||||||
keys: this.window.Object.keys,
|
keys: this.window.Object.keys,
|
||||||
getOwnPropertySymbols: this.window.Object.getOwnPropertySymbols,
|
getOwnPropertySymbols: this.window.Object.getOwnPropertySymbols,
|
||||||
|
@ -41,7 +43,7 @@ class UVClient extends EventEmitter {
|
||||||
this.xhr = new Xhr(this);
|
this.xhr = new Xhr(this);
|
||||||
this.history = new History(this);
|
this.history = new History(this);
|
||||||
this.element = new ElementApi(this);
|
this.element = new ElementApi(this);
|
||||||
this.node = new NodeApi(this)
|
this.node = new NodeApi(this);
|
||||||
this.document = new DocumentHook(this);
|
this.document = new DocumentHook(this);
|
||||||
this.function = new FunctionHook(this);
|
this.function = new FunctionHook(this);
|
||||||
this.object = new ObjectHook(this);
|
this.object = new ObjectHook(this);
|
||||||
|
@ -55,56 +57,70 @@ class UVClient extends EventEmitter {
|
||||||
this.location = new LocationApi(this);
|
this.location = new LocationApi(this);
|
||||||
this.storage = new StorageApi(this);
|
this.storage = new StorageApi(this);
|
||||||
this.style = new StyleApi(this);
|
this.style = new StyleApi(this);
|
||||||
};
|
}
|
||||||
initLocation(rewriteUrl, sourceUrl) {
|
initLocation(rewriteUrl, sourceUrl) {
|
||||||
this.location = new LocationApi(this, sourceUrl, rewriteUrl, this.worker);
|
this.location = new LocationApi(
|
||||||
};
|
this,
|
||||||
|
sourceUrl,
|
||||||
|
rewriteUrl,
|
||||||
|
this.worker
|
||||||
|
);
|
||||||
|
}
|
||||||
override(obj, prop, wrapper, construct) {
|
override(obj, prop, wrapper, construct) {
|
||||||
if (!prop in obj) return false;
|
if (!prop in obj) return false;
|
||||||
const wrapped = this.wrap(obj, prop, wrapper, construct);
|
const wrapped = this.wrap(obj, prop, wrapper, construct);
|
||||||
return obj[prop] = wrapped;
|
return (obj[prop] = wrapped);
|
||||||
};
|
}
|
||||||
overrideDescriptor(obj, prop, wrapObj = {}) {
|
overrideDescriptor(obj, prop, wrapObj = {}) {
|
||||||
const wrapped = this.wrapDescriptor(obj, prop, wrapObj);
|
const wrapped = this.wrapDescriptor(obj, prop, wrapObj);
|
||||||
if (!wrapped) return {};
|
if (!wrapped) return {};
|
||||||
this.nativeMethods.defineProperty(obj, prop, wrapped);
|
this.nativeMethods.defineProperty(obj, prop, wrapped);
|
||||||
return wrapped;
|
return wrapped;
|
||||||
};
|
}
|
||||||
wrap(obj, prop, wrap, construct) {
|
wrap(obj, prop, wrap, construct) {
|
||||||
const fn = obj[prop];
|
const fn = obj[prop];
|
||||||
if (!fn) return fn;
|
if (!fn) return fn;
|
||||||
const wrapped = 'prototype' in fn ? function attach() {
|
const wrapped =
|
||||||
return wrap(fn, this, [...arguments]);
|
'prototype' in fn
|
||||||
} : {
|
? function attach() {
|
||||||
attach() {
|
return wrap(fn, this, [...arguments]);
|
||||||
return wrap(fn, this, [...arguments]);
|
}
|
||||||
},
|
: {
|
||||||
}.attach;
|
attach() {
|
||||||
|
return wrap(fn, this, [...arguments]);
|
||||||
|
},
|
||||||
|
}.attach;
|
||||||
|
|
||||||
if (!!construct) {
|
if (!!construct) {
|
||||||
wrapped.prototype = fn.prototype;
|
wrapped.prototype = fn.prototype;
|
||||||
wrapped.prototype.constructor = wrapped;
|
wrapped.prototype.constructor = wrapped;
|
||||||
};
|
}
|
||||||
|
|
||||||
this.emit('wrap', fn, wrapped, !!construct);
|
this.emit('wrap', fn, wrapped, !!construct);
|
||||||
|
|
||||||
return wrapped;
|
return wrapped;
|
||||||
};
|
}
|
||||||
wrapDescriptor(obj, prop, wrapObj = {}) {
|
wrapDescriptor(obj, prop, wrapObj = {}) {
|
||||||
const descriptor = this.nativeMethods.getOwnPropertyDescriptor(obj, prop);
|
const descriptor = this.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
obj,
|
||||||
|
prop
|
||||||
|
);
|
||||||
if (!descriptor) return false;
|
if (!descriptor) return false;
|
||||||
for (let key in wrapObj) {
|
for (let key in wrapObj) {
|
||||||
if (key in descriptor) {
|
if (key in descriptor) {
|
||||||
if (key === 'get' || key === 'set') {
|
if (key === 'get' || key === 'set') {
|
||||||
descriptor[key] = this.wrap(descriptor, key, wrapObj[key]);
|
descriptor[key] = this.wrap(descriptor, key, wrapObj[key]);
|
||||||
} else {
|
} else {
|
||||||
descriptor[key] = typeof wrapObj[key] == 'function' ? wrapObj[key](descriptor[key]) : wrapObj[key];
|
descriptor[key] =
|
||||||
};
|
typeof wrapObj[key] == 'function'
|
||||||
|
? wrapObj[key](descriptor[key])
|
||||||
|
: wrapObj[key];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
return descriptor;
|
return descriptor;
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default UVClient;
|
export default UVClient;
|
||||||
if (typeof self === 'object') self.UVClient = UVClient;
|
if (typeof self === 'object') self.UVClient = UVClient;
|
|
@ -1,4 +1,4 @@
|
||||||
import EventEmitter from "./events.js";
|
import EventEmitter from './events.js';
|
||||||
|
|
||||||
class LocationApi extends EventEmitter {
|
class LocationApi extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -6,13 +6,31 @@ class LocationApi extends EventEmitter {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.window = ctx.window;
|
this.window = ctx.window;
|
||||||
this.location = this.window.location;
|
this.location = this.window.location;
|
||||||
this.WorkerLocation = this.ctx.worker ? this.window.WorkerLocation : null;
|
this.WorkerLocation = this.ctx.worker
|
||||||
this.workerLocProto = this.WorkerLocation ? this.WorkerLocation.prototype : {};
|
? this.window.WorkerLocation
|
||||||
this.keys = ['href', 'protocol', 'host', 'hostname', 'port', 'pathname', 'search', 'hash', 'origin'];
|
: null;
|
||||||
|
this.workerLocProto = this.WorkerLocation
|
||||||
|
? this.WorkerLocation.prototype
|
||||||
|
: {};
|
||||||
|
this.keys = [
|
||||||
|
'href',
|
||||||
|
'protocol',
|
||||||
|
'host',
|
||||||
|
'hostname',
|
||||||
|
'port',
|
||||||
|
'pathname',
|
||||||
|
'search',
|
||||||
|
'hash',
|
||||||
|
'origin',
|
||||||
|
];
|
||||||
this.HashChangeEvent = this.window.HashChangeEvent || null;
|
this.HashChangeEvent = this.window.HashChangeEvent || null;
|
||||||
this.href = this.WorkerLocation ? ctx.nativeMethods.getOwnPropertyDescriptor(this.workerLocProto, 'href') :
|
this.href = this.WorkerLocation
|
||||||
ctx.nativeMethods.getOwnPropertyDescriptor(this.location, 'href');
|
? ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
};
|
this.workerLocProto,
|
||||||
|
'href'
|
||||||
|
)
|
||||||
|
: ctx.nativeMethods.getOwnPropertyDescriptor(this.location, 'href');
|
||||||
|
}
|
||||||
overrideWorkerLocation(parse) {
|
overrideWorkerLocation(parse) {
|
||||||
if (!this.WorkerLocation) return false;
|
if (!this.WorkerLocation) return false;
|
||||||
const uv = this;
|
const uv = this;
|
||||||
|
@ -20,15 +38,13 @@ class LocationApi extends EventEmitter {
|
||||||
for (const key of this.keys) {
|
for (const key of this.keys) {
|
||||||
this.ctx.overrideDescriptor(this.workerLocProto, key, {
|
this.ctx.overrideDescriptor(this.workerLocProto, key, {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
return parse(
|
return parse(uv.href.get.call(this.location))[key];
|
||||||
uv.href.get.call(this.location)
|
|
||||||
)[key]
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
emulate(parse, wrap) {
|
emulate(parse, wrap) {
|
||||||
const emulation = {};
|
const emulation = {};
|
||||||
const that = this;
|
const that = this;
|
||||||
|
@ -36,81 +52,124 @@ class LocationApi extends EventEmitter {
|
||||||
for (const key of that.keys) {
|
for (const key of that.keys) {
|
||||||
this.ctx.nativeMethods.defineProperty(emulation, key, {
|
this.ctx.nativeMethods.defineProperty(emulation, key, {
|
||||||
get() {
|
get() {
|
||||||
return parse(
|
return parse(that.href.get.call(that.location))[key];
|
||||||
that.href.get.call(that.location)
|
|
||||||
)[key];
|
|
||||||
},
|
},
|
||||||
set: key !== 'origin' ? function (val) {
|
set:
|
||||||
switch(key) {
|
key !== 'origin'
|
||||||
case 'href':
|
? function (val) {
|
||||||
that.location.href = wrap(val);
|
switch (key) {
|
||||||
break;
|
case 'href':
|
||||||
case 'hash':
|
that.location.href = wrap(val);
|
||||||
that.emit('hashchange', emulation.href, (val.trim().startsWith('#') ? new URL(val.trim(), emulation.href).href : new URL('#' + val.trim(), emulation.href).href), that);
|
break;
|
||||||
break;
|
case 'hash':
|
||||||
default:
|
that.emit(
|
||||||
const url = new URL(emulation.href);
|
'hashchange',
|
||||||
url[key] = val;
|
emulation.href,
|
||||||
that.location.href = wrap(url.href);
|
val.trim().startsWith('#')
|
||||||
};
|
? new URL(
|
||||||
} : undefined,
|
val.trim(),
|
||||||
|
emulation.href
|
||||||
|
).href
|
||||||
|
: new URL(
|
||||||
|
'#' + val.trim(),
|
||||||
|
emulation.href
|
||||||
|
).href,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
const url = new URL(emulation.href);
|
||||||
|
url[key] = val;
|
||||||
|
that.location.href = wrap(url.href);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
configurable: false,
|
configurable: false,
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
if ('reload' in this.location) {
|
if ('reload' in this.location) {
|
||||||
this.ctx.nativeMethods.defineProperty(emulation, 'reload', {
|
this.ctx.nativeMethods.defineProperty(emulation, 'reload', {
|
||||||
value: this.ctx.wrap(this.location, 'reload', (target, that) => {
|
value: this.ctx.wrap(
|
||||||
return target.call(that === emulation ? this.location : that);
|
this.location,
|
||||||
}),
|
'reload',
|
||||||
|
(target, that) => {
|
||||||
|
return target.call(
|
||||||
|
that === emulation ? this.location : that
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
writable: false,
|
writable: false,
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
if ('replace' in this.location) {
|
if ('replace' in this.location) {
|
||||||
this.ctx.nativeMethods.defineProperty(emulation, 'replace', {
|
this.ctx.nativeMethods.defineProperty(emulation, 'replace', {
|
||||||
value: this.ctx.wrap(this.location, 'assign', (target, that, args) => {
|
value: this.ctx.wrap(
|
||||||
if (!args.length || that !== emulation) target.call(that);
|
this.location,
|
||||||
that = this.location;
|
'assign',
|
||||||
let [ input ] = args;
|
(target, that, args) => {
|
||||||
|
if (!args.length || that !== emulation)
|
||||||
|
target.call(that);
|
||||||
|
that = this.location;
|
||||||
|
let [input] = args;
|
||||||
|
|
||||||
const url = new URL(input, emulation.href);
|
const url = new URL(input, emulation.href);
|
||||||
return target.call(that === emulation ? this.location : that, wrap(url.href));
|
return target.call(
|
||||||
}),
|
that === emulation ? this.location : that,
|
||||||
|
wrap(url.href)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
writable: false,
|
writable: false,
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
if ('assign' in this.location) {
|
if ('assign' in this.location) {
|
||||||
this.ctx.nativeMethods.defineProperty(emulation, 'assign', {
|
this.ctx.nativeMethods.defineProperty(emulation, 'assign', {
|
||||||
value: this.ctx.wrap(this.location, 'assign', (target, that, args) => {
|
value: this.ctx.wrap(
|
||||||
if (!args.length || that !== emulation) target.call(that);
|
this.location,
|
||||||
that = this.location;
|
'assign',
|
||||||
let [ input ] = args;
|
(target, that, args) => {
|
||||||
|
if (!args.length || that !== emulation)
|
||||||
|
target.call(that);
|
||||||
|
that = this.location;
|
||||||
|
let [input] = args;
|
||||||
|
|
||||||
const url = new URL(input, emulation.href);
|
const url = new URL(input, emulation.href);
|
||||||
return target.call(that === emulation ? this.location : that, wrap(url.href));
|
return target.call(
|
||||||
}),
|
that === emulation ? this.location : that,
|
||||||
|
wrap(url.href)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
writable: false,
|
writable: false,
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
if ('ancestorOrigins' in this.location) {
|
if ('ancestorOrigins' in this.location) {
|
||||||
this.ctx.nativeMethods.defineProperty(emulation, 'ancestorOrigins', {
|
this.ctx.nativeMethods.defineProperty(
|
||||||
get() {
|
emulation,
|
||||||
const arr = [];
|
'ancestorOrigins',
|
||||||
if (that.window.DOMStringList) that.ctx.nativeMethods.setPrototypeOf(arr, that.window.DOMStringList.prototype);
|
{
|
||||||
return arr;
|
get() {
|
||||||
},
|
const arr = [];
|
||||||
set: undefined,
|
if (that.window.DOMStringList)
|
||||||
enumerable: true,
|
that.ctx.nativeMethods.setPrototypeOf(
|
||||||
});
|
arr,
|
||||||
};
|
that.window.DOMStringList.prototype
|
||||||
|
);
|
||||||
|
return arr;
|
||||||
|
},
|
||||||
|
set: undefined,
|
||||||
|
enumerable: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this.ctx.nativeMethods.defineProperty(emulation, 'toString', {
|
this.ctx.nativeMethods.defineProperty(emulation, 'toString', {
|
||||||
value: this.ctx.wrap(this.location, 'toString', () => {
|
value: this.ctx.wrap(this.location, 'toString', () => {
|
||||||
|
@ -126,10 +185,14 @@ class LocationApi extends EventEmitter {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.ctx.window.Location) this.ctx.nativeMethods.setPrototypeOf(emulation, this.ctx.window.Location.prototype);
|
if (this.ctx.window.Location)
|
||||||
|
this.ctx.nativeMethods.setPrototypeOf(
|
||||||
|
emulation,
|
||||||
|
this.ctx.window.Location.prototype
|
||||||
|
);
|
||||||
|
|
||||||
return emulation;
|
return emulation;
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default LocationApi;
|
export default LocationApi;
|
|
@ -1,5 +1,5 @@
|
||||||
import EventEmitter from "./events.js";
|
import EventEmitter from './events.js';
|
||||||
import HookEvent from "./hook.js";
|
import HookEvent from './hook.js';
|
||||||
|
|
||||||
class MessageApi extends EventEmitter {
|
class MessageApi extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -12,9 +12,15 @@ class MessageApi extends EventEmitter {
|
||||||
this.mpProto = this.MessagePort.prototype || {};
|
this.mpProto = this.MessagePort.prototype || {};
|
||||||
this.mpPostMessage = this.mpProto.postMessage;
|
this.mpPostMessage = this.mpProto.postMessage;
|
||||||
this.messageProto = this.MessageEvent.prototype || {};
|
this.messageProto = this.MessageEvent.prototype || {};
|
||||||
this.messageData = ctx.nativeMethods.getOwnPropertyDescriptor(this.messageProto, 'data');
|
this.messageData = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
this.messageOrigin = ctx.nativeMethods.getOwnPropertyDescriptor(this.messageProto, 'origin');
|
this.messageProto,
|
||||||
};
|
'data'
|
||||||
|
);
|
||||||
|
this.messageOrigin = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.messageProto,
|
||||||
|
'origin'
|
||||||
|
);
|
||||||
|
}
|
||||||
overridePostMessage() {
|
overridePostMessage() {
|
||||||
this.ctx.override(this.window, 'postMessage', (target, that, args) => {
|
this.ctx.override(this.window, 'postMessage', (target, that, args) => {
|
||||||
if (!args.length) return target.apply(that, args);
|
if (!args.length) return target.apply(that, args);
|
||||||
|
@ -24,61 +30,100 @@ class MessageApi extends EventEmitter {
|
||||||
let transfer;
|
let transfer;
|
||||||
|
|
||||||
if (!this.ctx.worker) {
|
if (!this.ctx.worker) {
|
||||||
[ message, origin, transfer = [] ] = args;
|
[message, origin, transfer = []] = args;
|
||||||
} else {
|
} else {
|
||||||
[ message, transfer = [] ] = args;
|
[message, transfer = []] = args;
|
||||||
};
|
}
|
||||||
|
|
||||||
const event = new HookEvent({ message, origin, transfer, worker: this.ctx.worker }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ message, origin, transfer, worker: this.ctx.worker },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('postMessage', event);
|
this.emit('postMessage', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return this.ctx.worker ? event.target.call(event.that, event.data.message, event.data.transfer) : event.target.call(event.that, event.data.message, event.data.origin, event.data.transfer);
|
return this.ctx.worker
|
||||||
|
? event.target.call(
|
||||||
|
event.that,
|
||||||
|
event.data.message,
|
||||||
|
event.data.transfer
|
||||||
|
)
|
||||||
|
: event.target.call(
|
||||||
|
event.that,
|
||||||
|
event.data.message,
|
||||||
|
event.data.origin,
|
||||||
|
event.data.transfer
|
||||||
|
);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
wrapPostMessage(obj, prop, noOrigin = false) {
|
wrapPostMessage(obj, prop, noOrigin = false) {
|
||||||
return this.ctx.wrap(obj, prop, (target, that, args) => {
|
return this.ctx.wrap(obj, prop, (target, that, args) => {
|
||||||
if (this.ctx.worker ? !args.length : 2 > args) return target.apply(that, args);
|
if (this.ctx.worker ? !args.length : 2 > args)
|
||||||
|
return target.apply(that, args);
|
||||||
let message;
|
let message;
|
||||||
let origin;
|
let origin;
|
||||||
let transfer;
|
let transfer;
|
||||||
|
|
||||||
if (!noOrigin) {
|
if (!noOrigin) {
|
||||||
[ message, origin, transfer = [] ] = args;
|
[message, origin, transfer = []] = args;
|
||||||
} else {
|
} else {
|
||||||
[ message, transfer = [] ] = args;
|
[message, transfer = []] = args;
|
||||||
origin = null;
|
origin = null;
|
||||||
};
|
}
|
||||||
|
|
||||||
const event = new HookEvent({ message, origin, transfer, worker: this.ctx.worker }, target, obj);
|
const event = new HookEvent(
|
||||||
|
{ message, origin, transfer, worker: this.ctx.worker },
|
||||||
|
target,
|
||||||
|
obj
|
||||||
|
);
|
||||||
this.emit('postMessage', event);
|
this.emit('postMessage', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return noOrigin ? event.target.call(event.that, event.data.message, event.data.transfer) : event.target.call(event.that, event.data.message, event.data.origin, event.data.transfer);
|
return noOrigin
|
||||||
|
? event.target.call(
|
||||||
|
event.that,
|
||||||
|
event.data.message,
|
||||||
|
event.data.transfer
|
||||||
|
)
|
||||||
|
: event.target.call(
|
||||||
|
event.that,
|
||||||
|
event.data.message,
|
||||||
|
event.data.origin,
|
||||||
|
event.data.transfer
|
||||||
|
);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideMessageOrigin() {
|
overrideMessageOrigin() {
|
||||||
this.ctx.overrideDescriptor(this.messageProto, 'origin', {
|
this.ctx.overrideDescriptor(this.messageProto, 'origin', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('origin', event);
|
this.emit('origin', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.value;
|
return event.data.value;
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideMessageData() {
|
overrideMessageData() {
|
||||||
this.ctx.overrideDescriptor(this.messageProto, 'data', {
|
this.ctx.overrideDescriptor(this.messageProto, 'data', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('data', event);
|
this.emit('data', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.value;
|
return event.data.value;
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default MessageApi;
|
export default MessageApi;
|
|
@ -1,5 +1,5 @@
|
||||||
import EventEmitter from "../events.js";
|
import EventEmitter from '../events.js';
|
||||||
import HookEvent from "../hook.js";
|
import HookEvent from '../hook.js';
|
||||||
|
|
||||||
class FunctionHook extends EventEmitter {
|
class FunctionHook extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -13,25 +13,38 @@ class FunctionHook extends EventEmitter {
|
||||||
this.call = this.fnProto.call;
|
this.call = this.fnProto.call;
|
||||||
this.apply = this.fnProto.apply;
|
this.apply = this.fnProto.apply;
|
||||||
this.bind = this.fnProto.bind;
|
this.bind = this.fnProto.bind;
|
||||||
};
|
}
|
||||||
overrideFunction() {
|
overrideFunction() {
|
||||||
this.ctx.override(this.window, 'Function', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return target.apply(that, args);
|
this.window,
|
||||||
|
'Function',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return target.apply(that, args);
|
||||||
|
|
||||||
let script = args[args.length - 1];
|
let script = args[args.length - 1];
|
||||||
let fnArgs = [];
|
let fnArgs = [];
|
||||||
|
|
||||||
for (let i = 0; i < args.length - 1; i++) {
|
for (let i = 0; i < args.length - 1; i++) {
|
||||||
fnArgs.push(args[i]);
|
fnArgs.push(args[i]);
|
||||||
};
|
}
|
||||||
|
|
||||||
const event = new HookEvent({ script, args: fnArgs }, target, that);
|
const event = new HookEvent(
|
||||||
this.emit('function', event);
|
{ script, args: fnArgs },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
this.emit('function', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, ...event.data.args, event.data.script);
|
return event.target.call(
|
||||||
}, true);
|
event.that,
|
||||||
};
|
...event.data.args,
|
||||||
|
event.data.script
|
||||||
|
);
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
overrideToString() {
|
overrideToString() {
|
||||||
this.ctx.override(this.fnProto, 'toString', (target, that) => {
|
this.ctx.override(this.fnProto, 'toString', (target, that) => {
|
||||||
const event = new HookEvent({ fn: that }, target, that);
|
const event = new HookEvent({ fn: that }, target, that);
|
||||||
|
@ -40,7 +53,7 @@ class FunctionHook extends EventEmitter {
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.data.fn);
|
return event.target.call(event.data.fn);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default FunctionHook;
|
export default FunctionHook;
|
|
@ -1,5 +1,5 @@
|
||||||
import EventEmitter from "../events.js";
|
import EventEmitter from '../events.js';
|
||||||
import HookEvent from "../hook.js";
|
import HookEvent from '../hook.js';
|
||||||
|
|
||||||
class ObjectHook extends EventEmitter {
|
class ObjectHook extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -10,31 +10,47 @@ class ObjectHook extends EventEmitter {
|
||||||
this.getOwnPropertyDescriptors = this.Object.getOwnPropertyDescriptors;
|
this.getOwnPropertyDescriptors = this.Object.getOwnPropertyDescriptors;
|
||||||
this.getOwnPropertyDescriptor = this.Object.getOwnPropertyDescriptor;
|
this.getOwnPropertyDescriptor = this.Object.getOwnPropertyDescriptor;
|
||||||
this.getOwnPropertyNames = this.Object.getOwnPropertyNames;
|
this.getOwnPropertyNames = this.Object.getOwnPropertyNames;
|
||||||
};
|
}
|
||||||
overrideGetPropertyNames() {
|
overrideGetPropertyNames() {
|
||||||
this.ctx.override(this.Object, 'getOwnPropertyNames', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return target.apply(that, args);
|
this.Object,
|
||||||
let [ object ] = args;
|
'getOwnPropertyNames',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return target.apply(that, args);
|
||||||
|
let [object] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ names: target.call(that, object) }, target, that);
|
const event = new HookEvent(
|
||||||
this.emit('getOwnPropertyNames', event);
|
{ names: target.call(that, object) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
this.emit('getOwnPropertyNames', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.names;
|
return event.data.names;
|
||||||
});
|
}
|
||||||
};
|
);
|
||||||
|
}
|
||||||
overrideGetOwnPropertyDescriptors() {
|
overrideGetOwnPropertyDescriptors() {
|
||||||
this.ctx.override(this.Object, 'getOwnPropertyDescriptors', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return target.apply(that, args);
|
this.Object,
|
||||||
let [ object ] = args;
|
'getOwnPropertyDescriptors',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return target.apply(that, args);
|
||||||
|
let [object] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ descriptors: target.call(that, object) }, target, that);
|
const event = new HookEvent(
|
||||||
this.emit('getOwnPropertyDescriptors', event);
|
{ descriptors: target.call(that, object) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
this.emit('getOwnPropertyDescriptors', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.descriptors;
|
return event.data.descriptors;
|
||||||
});
|
}
|
||||||
};
|
);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default ObjectHook;
|
export default ObjectHook;
|
|
@ -1,5 +1,5 @@
|
||||||
import EventEmitter from "./events.js";
|
import EventEmitter from './events.js';
|
||||||
import HookEvent from "./hook.js";
|
import HookEvent from './hook.js';
|
||||||
|
|
||||||
class NavigatorApi extends EventEmitter {
|
class NavigatorApi extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -10,19 +10,23 @@ class NavigatorApi extends EventEmitter {
|
||||||
this.Navigator = this.window.Navigator || {};
|
this.Navigator = this.window.Navigator || {};
|
||||||
this.navProto = this.Navigator.prototype || {};
|
this.navProto = this.Navigator.prototype || {};
|
||||||
this.sendBeacon = this.navProto.sendBeacon;
|
this.sendBeacon = this.navProto.sendBeacon;
|
||||||
};
|
}
|
||||||
overrideSendBeacon() {
|
overrideSendBeacon() {
|
||||||
this.ctx.override(this.navProto, 'sendBeacon', (target, that, args) => {
|
this.ctx.override(this.navProto, 'sendBeacon', (target, that, args) => {
|
||||||
if (!args.length) return target.apply(that, args);
|
if (!args.length) return target.apply(that, args);
|
||||||
let [ url, data = '' ] = args;
|
let [url, data = ''] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ url, data }, target, that);
|
const event = new HookEvent({ url, data }, target, that);
|
||||||
this.emit('sendBeacon', event);
|
this.emit('sendBeacon', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.url, event.data.data);
|
return event.target.call(
|
||||||
|
event.that,
|
||||||
|
event.data.url,
|
||||||
|
event.data.data
|
||||||
|
);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default NavigatorApi;
|
export default NavigatorApi;
|
|
@ -1,5 +1,5 @@
|
||||||
import EventEmitter from "../events.js";
|
import EventEmitter from '../events.js';
|
||||||
import HookEvent from "../hook.js";
|
import HookEvent from '../hook.js';
|
||||||
|
|
||||||
class EventSourceApi extends EventEmitter {
|
class EventSourceApi extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -8,38 +8,50 @@ class EventSourceApi extends EventEmitter {
|
||||||
this.window = ctx.window;
|
this.window = ctx.window;
|
||||||
this.EventSource = this.window.EventSource || {};
|
this.EventSource = this.window.EventSource || {};
|
||||||
this.esProto = this.EventSource.prototype || {};
|
this.esProto = this.EventSource.prototype || {};
|
||||||
this.url = ctx.nativeMethods.getOwnPropertyDescriptor(this.esProto, 'url');
|
this.url = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.esProto,
|
||||||
|
'url'
|
||||||
|
);
|
||||||
this.CONNECTING = 0;
|
this.CONNECTING = 0;
|
||||||
this.OPEN = 1;
|
this.OPEN = 1;
|
||||||
this.CLOSED = 2;
|
this.CLOSED = 2;
|
||||||
};
|
}
|
||||||
overrideConstruct() {
|
overrideConstruct() {
|
||||||
this.ctx.override(this.window, 'EventSource', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return new target(...args);
|
this.window,
|
||||||
let [ url, config = {} ] = args;
|
'EventSource',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return new target(...args);
|
||||||
|
let [url, config = {}] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ url, config }, target, that);
|
const event = new HookEvent({ url, config }, target, that);
|
||||||
this.emit('construct', event);
|
this.emit('construct', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return new event.target(event.data.url, event.data.config);
|
return new event.target(event.data.url, event.data.config);
|
||||||
}, true);
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
if ('EventSource' in this.window) {
|
if ('EventSource' in this.window) {
|
||||||
this.window.EventSource.CONNECTING = this.CONNECTING;
|
this.window.EventSource.CONNECTING = this.CONNECTING;
|
||||||
this.window.EventSource.OPEN = this.OPEN;
|
this.window.EventSource.OPEN = this.OPEN;
|
||||||
this.window.EventSource.CLOSED = this.CLOSED;
|
this.window.EventSource.CLOSED = this.CLOSED;
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
overrideUrl() {
|
overrideUrl() {
|
||||||
this.ctx.overrideDescriptor(this.esProto, 'url', {
|
this.ctx.overrideDescriptor(this.esProto, 'url', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
this.emit('url', event);
|
{ value: target.call(that) },
|
||||||
return event.data.value;
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
this.emit('url', event);
|
||||||
|
return event.data.value;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default EventSourceApi;
|
export default EventSourceApi;
|
|
@ -1,5 +1,5 @@
|
||||||
import EventEmitter from "../events.js";
|
import EventEmitter from '../events.js';
|
||||||
import HookEvent from "../hook.js";
|
import HookEvent from '../hook.js';
|
||||||
|
|
||||||
class Fetch extends EventEmitter {
|
class Fetch extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -13,49 +13,75 @@ class Fetch extends EventEmitter {
|
||||||
this.reqProto = this.Request ? this.Request.prototype : {};
|
this.reqProto = this.Request ? this.Request.prototype : {};
|
||||||
this.resProto = this.Response ? this.Response.prototype : {};
|
this.resProto = this.Response ? this.Response.prototype : {};
|
||||||
this.headersProto = this.Headers ? this.Headers.prototype : {};
|
this.headersProto = this.Headers ? this.Headers.prototype : {};
|
||||||
this.reqUrl = ctx.nativeMethods.getOwnPropertyDescriptor(this.reqProto, 'url');
|
this.reqUrl = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
this.resUrl = ctx.nativeMethods.getOwnPropertyDescriptor(this.resProto, 'url');
|
this.reqProto,
|
||||||
this.reqHeaders = ctx.nativeMethods.getOwnPropertyDescriptor(this.reqProto, 'headers');
|
'url'
|
||||||
this.resHeaders = ctx.nativeMethods.getOwnPropertyDescriptor(this.resProto, 'headers');
|
);
|
||||||
};
|
this.resUrl = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.resProto,
|
||||||
|
'url'
|
||||||
|
);
|
||||||
|
this.reqHeaders = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.reqProto,
|
||||||
|
'headers'
|
||||||
|
);
|
||||||
|
this.resHeaders = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.resProto,
|
||||||
|
'headers'
|
||||||
|
);
|
||||||
|
}
|
||||||
override() {
|
override() {
|
||||||
this.overrideRequest();
|
this.overrideRequest();
|
||||||
this.overrideUrl();
|
this.overrideUrl();
|
||||||
this.overrideHeaders();
|
this.overrideHeaders();
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
overrideRequest() {
|
overrideRequest() {
|
||||||
if (!this.fetch) return false;
|
if (!this.fetch) return false;
|
||||||
|
|
||||||
this.ctx.override(this.window, 'fetch', (target, that, args) => {
|
this.ctx.override(this.window, 'fetch', (target, that, args) => {
|
||||||
if (!args.length || args[0] instanceof this.Request) return target.apply(that, args);
|
if (!args.length || args[0] instanceof this.Request)
|
||||||
|
return target.apply(that, args);
|
||||||
|
|
||||||
let [ input, options = {} ] = args;
|
let [input, options = {}] = args;
|
||||||
const event = new HookEvent({ input, options }, target, that);
|
const event = new HookEvent({ input, options }, target, that);
|
||||||
|
|
||||||
this.emit('request', event);
|
this.emit('request', event);
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
|
|
||||||
return event.target.call(event.that, event.data.input, event.data.options);
|
return event.target.call(
|
||||||
|
event.that,
|
||||||
|
event.data.input,
|
||||||
|
event.data.options
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.ctx.override(this.window, 'Request', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return new target(...args);
|
this.window,
|
||||||
|
'Request',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return new target(...args);
|
||||||
|
|
||||||
let [ input, options = {} ] = args;
|
let [input, options = {}] = args;
|
||||||
const event = new HookEvent({ input, options }, target);
|
const event = new HookEvent({ input, options }, target);
|
||||||
|
|
||||||
this.emit('request', event);
|
this.emit('request', event);
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
|
|
||||||
return new event.target(event.data.input, event.data.options);
|
return new event.target(event.data.input, event.data.options);
|
||||||
}, true);
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
overrideUrl() {
|
overrideUrl() {
|
||||||
this.ctx.overrideDescriptor(this.reqProto, 'url', {
|
this.ctx.overrideDescriptor(this.reqProto, 'url', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
|
||||||
this.emit('requestUrl', event);
|
this.emit('requestUrl', event);
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
|
@ -66,7 +92,11 @@ class Fetch extends EventEmitter {
|
||||||
|
|
||||||
this.ctx.overrideDescriptor(this.resProto, 'url', {
|
this.ctx.overrideDescriptor(this.resProto, 'url', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
|
||||||
this.emit('responseUrl', event);
|
this.emit('responseUrl', event);
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
|
@ -75,13 +105,17 @@ class Fetch extends EventEmitter {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
overrideHeaders() {
|
overrideHeaders() {
|
||||||
if (!this.Headers) return false;
|
if (!this.Headers) return false;
|
||||||
|
|
||||||
this.ctx.overrideDescriptor(this.reqProto, 'headers', {
|
this.ctx.overrideDescriptor(this.reqProto, 'headers', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
|
||||||
this.emit('requestHeaders', event);
|
this.emit('requestHeaders', event);
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
|
@ -92,7 +126,11 @@ class Fetch extends EventEmitter {
|
||||||
|
|
||||||
this.ctx.overrideDescriptor(this.resProto, 'headers', {
|
this.ctx.overrideDescriptor(this.resProto, 'headers', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
|
||||||
this.emit('responseHeaders', event);
|
this.emit('responseHeaders', event);
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
|
@ -101,9 +139,13 @@ class Fetch extends EventEmitter {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
this.ctx.override(this.headersProto, 'get', (target, that, [ name ]) => {
|
this.ctx.override(this.headersProto, 'get', (target, that, [name]) => {
|
||||||
if (!name) return target.call(that);
|
if (!name) return target.call(that);
|
||||||
const event = new HookEvent({ name, value: target.call(that, name) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ name, value: target.call(that, name) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
|
||||||
this.emit('getHeader', event);
|
this.emit('getHeader', event);
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
|
@ -114,20 +156,28 @@ class Fetch extends EventEmitter {
|
||||||
this.ctx.override(this.headersProto, 'set', (target, that, args) => {
|
this.ctx.override(this.headersProto, 'set', (target, that, args) => {
|
||||||
if (2 > args.length) return target.apply(that, args);
|
if (2 > args.length) return target.apply(that, args);
|
||||||
|
|
||||||
let [ name, value ] = args;
|
let [name, value] = args;
|
||||||
const event = new HookEvent({ name, value }, target, that);
|
const event = new HookEvent({ name, value }, target, that);
|
||||||
|
|
||||||
this.emit('setHeader', event);
|
this.emit('setHeader', event);
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
|
|
||||||
return event.target.call(event.that, event.data.name, event.data.value);
|
return event.target.call(
|
||||||
|
event.that,
|
||||||
|
event.data.name,
|
||||||
|
event.data.value
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.ctx.override(this.headersProto, 'has', (target, that, args) => {
|
this.ctx.override(this.headersProto, 'has', (target, that, args) => {
|
||||||
if (!args.length) return target.call(that);
|
if (!args.length) return target.call(that);
|
||||||
let [ name ] = args;
|
let [name] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ name, value: target.call(that, name) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ name, value: target.call(that, name) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
|
||||||
this.emit('hasHeader', event);
|
this.emit('hasHeader', event);
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
|
@ -138,19 +188,23 @@ class Fetch extends EventEmitter {
|
||||||
this.ctx.override(this.headersProto, 'append', (target, that, args) => {
|
this.ctx.override(this.headersProto, 'append', (target, that, args) => {
|
||||||
if (2 > args.length) return target.apply(that, args);
|
if (2 > args.length) return target.apply(that, args);
|
||||||
|
|
||||||
let [ name, value ] = args;
|
let [name, value] = args;
|
||||||
const event = new HookEvent({ name, value }, target, that);
|
const event = new HookEvent({ name, value }, target, that);
|
||||||
|
|
||||||
this.emit('appendHeader', event);
|
this.emit('appendHeader', event);
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
|
|
||||||
return event.target.call(event.that, event.data.name, event.data.value);
|
return event.target.call(
|
||||||
|
event.that,
|
||||||
|
event.data.name,
|
||||||
|
event.data.value
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.ctx.override(this.headersProto, 'delete', (target, that, args) => {
|
this.ctx.override(this.headersProto, 'delete', (target, that, args) => {
|
||||||
if (!args.length) return target.apply(that, args);
|
if (!args.length) return target.apply(that, args);
|
||||||
|
|
||||||
let [ name ] = args;
|
let [name] = args;
|
||||||
const event = new HookEvent({ name }, target, that);
|
const event = new HookEvent({ name }, target, that);
|
||||||
|
|
||||||
this.emit('deleteHeader', event);
|
this.emit('deleteHeader', event);
|
||||||
|
@ -160,7 +214,7 @@ class Fetch extends EventEmitter {
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default Fetch;
|
export default Fetch;
|
|
@ -1,5 +1,5 @@
|
||||||
import EventEmitter from "../events.js";
|
import EventEmitter from '../events.js';
|
||||||
import HookEvent from "../hook.js";
|
import HookEvent from '../hook.js';
|
||||||
|
|
||||||
class WebSocketApi extends EventEmitter {
|
class WebSocketApi extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -8,51 +8,71 @@ class WebSocketApi extends EventEmitter {
|
||||||
this.window = ctx.window;
|
this.window = ctx.window;
|
||||||
this.WebSocket = this.window.WebSocket || {};
|
this.WebSocket = this.window.WebSocket || {};
|
||||||
this.wsProto = this.WebSocket.prototype || {};
|
this.wsProto = this.WebSocket.prototype || {};
|
||||||
this.url = ctx.nativeMethods.getOwnPropertyDescriptor(this.wsProto, 'url');
|
this.url = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
this.protocol = ctx.nativeMethods.getOwnPropertyDescriptor(this.wsProto, 'protocol');
|
this.wsProto,
|
||||||
|
'url'
|
||||||
|
);
|
||||||
|
this.protocol = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.wsProto,
|
||||||
|
'protocol'
|
||||||
|
);
|
||||||
this.send = this.wsProto.send;
|
this.send = this.wsProto.send;
|
||||||
this.close = this.wsProto.close;
|
this.close = this.wsProto.close;
|
||||||
this.CONNECTING = 0;
|
this.CONNECTING = 0;
|
||||||
this.OPEN = 1;
|
this.OPEN = 1;
|
||||||
this.CLOSING = 2;
|
this.CLOSING = 2;
|
||||||
this.CLOSED = 3;
|
this.CLOSED = 3;
|
||||||
};
|
}
|
||||||
overrideWebSocket() {
|
overrideWebSocket() {
|
||||||
this.ctx.override(this.window, 'WebSocket', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return new target(...args);
|
this.window,
|
||||||
let [ url, protocols = [] ] = args;
|
'WebSocket',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return new target(...args);
|
||||||
|
let [url, protocols = []] = args;
|
||||||
|
|
||||||
if (!this.ctx.nativeMethods.isArray(protocols)) protocols = [ protocols ];
|
if (!this.ctx.nativeMethods.isArray(protocols))
|
||||||
const event = new HookEvent({ url, protocols }, target, that);
|
protocols = [protocols];
|
||||||
this.emit('websocket', event);
|
const event = new HookEvent({ url, protocols }, target, that);
|
||||||
|
this.emit('websocket', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return new event.target(event.data.url, event.data.protocols);
|
return new event.target(event.data.url, event.data.protocols);
|
||||||
}, true);
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
this.window.WebSocket.CONNECTING = this.CONNECTING;
|
this.window.WebSocket.CONNECTING = this.CONNECTING;
|
||||||
this.window.WebSocket.OPEN = this.OPEN;
|
this.window.WebSocket.OPEN = this.OPEN;
|
||||||
this.window.WebSocket.CLOSING = this.CLOSING;
|
this.window.WebSocket.CLOSING = this.CLOSING;
|
||||||
this.window.WebSocket.CLOSED = this.CLOSED;
|
this.window.WebSocket.CLOSED = this.CLOSED;
|
||||||
};
|
}
|
||||||
overrideUrl() {
|
overrideUrl() {
|
||||||
this.ctx.overrideDescriptor(this.wsProto, 'url', {
|
this.ctx.overrideDescriptor(this.wsProto, 'url', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
this.emit('url', event);
|
{ value: target.call(that) },
|
||||||
return event.data.value;
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
this.emit('url', event);
|
||||||
|
return event.data.value;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideProtocol() {
|
overrideProtocol() {
|
||||||
this.ctx.overrideDescriptor(this.wsProto, 'protocol', {
|
this.ctx.overrideDescriptor(this.wsProto, 'protocol', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
this.emit('protocol', event);
|
{ value: target.call(that) },
|
||||||
return event.data.value;
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
this.emit('protocol', event);
|
||||||
|
return event.data.value;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default WebSocketApi;
|
export default WebSocketApi;
|
|
@ -1,5 +1,5 @@
|
||||||
import EventEmitter from "../events.js";
|
import EventEmitter from '../events.js';
|
||||||
import HookEvent from "../hook.js";
|
import HookEvent from '../hook.js';
|
||||||
|
|
||||||
class Xhr extends EventEmitter {
|
class Xhr extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -7,17 +7,25 @@ class Xhr extends EventEmitter {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.window = ctx.window;
|
this.window = ctx.window;
|
||||||
this.XMLHttpRequest = this.window.XMLHttpRequest;
|
this.XMLHttpRequest = this.window.XMLHttpRequest;
|
||||||
this.xhrProto = this.window.XMLHttpRequest ? this.window.XMLHttpRequest.prototype : {};
|
this.xhrProto = this.window.XMLHttpRequest
|
||||||
|
? this.window.XMLHttpRequest.prototype
|
||||||
|
: {};
|
||||||
this.open = this.xhrProto.open;
|
this.open = this.xhrProto.open;
|
||||||
this.abort = this.xhrProto.abort;
|
this.abort = this.xhrProto.abort;
|
||||||
this.send = this.xhrProto.send;
|
this.send = this.xhrProto.send;
|
||||||
this.overrideMimeType = this.xhrProto.overrideMimeType
|
this.overrideMimeType = this.xhrProto.overrideMimeType;
|
||||||
this.getAllResponseHeaders = this.xhrProto.getAllResponseHeaders;
|
this.getAllResponseHeaders = this.xhrProto.getAllResponseHeaders;
|
||||||
this.getResponseHeader = this.xhrProto.getResponseHeader;
|
this.getResponseHeader = this.xhrProto.getResponseHeader;
|
||||||
this.setRequestHeader = this.xhrProto.setRequestHeader;
|
this.setRequestHeader = this.xhrProto.setRequestHeader;
|
||||||
this.responseURL = ctx.nativeMethods.getOwnPropertyDescriptor(this.xhrProto, 'responseURL');
|
this.responseURL = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
this.responseText = ctx.nativeMethods.getOwnPropertyDescriptor(this.xhrProto, 'responseText');
|
this.xhrProto,
|
||||||
};
|
'responseURL'
|
||||||
|
);
|
||||||
|
this.responseText = ctx.nativeMethods.getOwnPropertyDescriptor(
|
||||||
|
this.xhrProto,
|
||||||
|
'responseText'
|
||||||
|
);
|
||||||
|
}
|
||||||
override() {
|
override() {
|
||||||
this.overrideOpen();
|
this.overrideOpen();
|
||||||
this.overrideSend();
|
this.overrideSend();
|
||||||
|
@ -25,13 +33,18 @@ class Xhr extends EventEmitter {
|
||||||
this.overrideGetResHeader();
|
this.overrideGetResHeader();
|
||||||
this.overrideGetResHeaders();
|
this.overrideGetResHeaders();
|
||||||
this.overrideSetReqHeader();
|
this.overrideSetReqHeader();
|
||||||
};
|
}
|
||||||
overrideOpen() {
|
overrideOpen() {
|
||||||
this.ctx.override(this.xhrProto, 'open', (target, that, args) => {
|
this.ctx.override(this.xhrProto, 'open', (target, that, args) => {
|
||||||
if (2 > args.length) return target.apply(that, args);
|
if (2 > args.length) return target.apply(that, args);
|
||||||
|
|
||||||
let [ method, input, async = true, user = null, password = null ] = args;
|
let [method, input, async = true, user = null, password = null] =
|
||||||
const event = new HookEvent({ method, input, async, user, password }, target, that);
|
args;
|
||||||
|
const event = new HookEvent(
|
||||||
|
{ method, input, async, user, password },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
|
||||||
this.emit('open', event);
|
this.emit('open', event);
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
|
@ -45,65 +58,94 @@ class Xhr extends EventEmitter {
|
||||||
event.data.password
|
event.data.password
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideResponseUrl() {
|
overrideResponseUrl() {
|
||||||
this.ctx.overrideDescriptor(this.xhrProto, 'responseURL', {
|
this.ctx.overrideDescriptor(this.xhrProto, 'responseURL', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
this.emit('responseUrl', event);
|
this.emit('responseUrl', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.value;
|
return event.data.value;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideSend() {
|
overrideSend() {
|
||||||
this.ctx.override(this.xhrProto, 'send', (target, that, [ body = null ]) => {
|
this.ctx.override(
|
||||||
const event = new HookEvent({ body }, target, that);
|
this.xhrProto,
|
||||||
|
'send',
|
||||||
|
(target, that, [body = null]) => {
|
||||||
|
const event = new HookEvent({ body }, target, that);
|
||||||
|
|
||||||
this.emit('send', event);
|
this.emit('send', event);
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
|
|
||||||
return event.target.call(
|
return event.target.call(event.that, event.data.body);
|
||||||
event.that,
|
}
|
||||||
event.data.body,
|
);
|
||||||
);
|
}
|
||||||
});
|
|
||||||
};
|
|
||||||
overrideSetReqHeader() {
|
overrideSetReqHeader() {
|
||||||
this.ctx.override(this.xhrProto, 'setRequestHeader', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (2 > args.length) return target.apply(that, args);
|
this.xhrProto,
|
||||||
|
'setRequestHeader',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (2 > args.length) return target.apply(that, args);
|
||||||
|
|
||||||
let [ name, value ] = args;
|
let [name, value] = args;
|
||||||
const event = new HookEvent({ name, value }, target, that);
|
const event = new HookEvent({ name, value }, target, that);
|
||||||
|
|
||||||
this.emit('setReqHeader', event);
|
this.emit('setReqHeader', event);
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
|
|
||||||
return event.target.call(event.that, event.data.name, event.data.value);
|
return event.target.call(
|
||||||
});
|
event.that,
|
||||||
};
|
event.data.name,
|
||||||
|
event.data.value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
overrideGetResHeaders() {
|
overrideGetResHeaders() {
|
||||||
this.ctx.override(this.xhrProto, 'getAllResponseHeaders', (target, that) => {
|
this.ctx.override(
|
||||||
const event = new HookEvent({ value: target.call(that) }, target, that);
|
this.xhrProto,
|
||||||
|
'getAllResponseHeaders',
|
||||||
|
(target, that) => {
|
||||||
|
const event = new HookEvent(
|
||||||
|
{ value: target.call(that) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
|
||||||
this.emit('getAllResponseHeaders', event);
|
this.emit('getAllResponseHeaders', event);
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
|
|
||||||
return event.data.value;
|
return event.data.value;
|
||||||
});
|
}
|
||||||
};
|
);
|
||||||
|
}
|
||||||
overrideGetResHeader() {
|
overrideGetResHeader() {
|
||||||
this.ctx.override(this.xhrProto, 'getResponseHeader', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return target.apply(that, args);
|
this.xhrProto,
|
||||||
let [ name ] = args;
|
'getResponseHeader',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return target.apply(that, args);
|
||||||
|
let [name] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ name, value: target.call(that, name) }, target, that);
|
const event = new HookEvent(
|
||||||
if (event.intercepted) return event.returnValue;
|
{ name, value: target.call(that, name) },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
if (event.intercepted) return event.returnValue;
|
||||||
|
|
||||||
return event.data.value;
|
return event.data.value;
|
||||||
});
|
}
|
||||||
};
|
);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default Xhr
|
export default Xhr;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import EventEmitter from "./events.js";
|
import EventEmitter from './events.js';
|
||||||
import HookEvent from "./hook.js";
|
import HookEvent from './hook.js';
|
||||||
|
|
||||||
class StorageApi extends EventEmitter {
|
class StorageApi extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -17,73 +17,110 @@ class StorageApi extends EventEmitter {
|
||||||
this.key = this.storeProto.key || null;
|
this.key = this.storeProto.key || null;
|
||||||
this.methods = ['key', 'getItem', 'setItem', 'removeItem', 'clear'];
|
this.methods = ['key', 'getItem', 'setItem', 'removeItem', 'clear'];
|
||||||
this.wrappers = new ctx.nativeMethods.Map();
|
this.wrappers = new ctx.nativeMethods.Map();
|
||||||
};
|
}
|
||||||
overrideMethods() {
|
overrideMethods() {
|
||||||
this.ctx.override(this.storeProto, 'getItem', (target, that, args) => {
|
this.ctx.override(this.storeProto, 'getItem', (target, that, args) => {
|
||||||
if (!args.length) return target.apply((this.wrappers.get(that) || that), args);
|
if (!args.length)
|
||||||
let [ name ] = args;
|
return target.apply(this.wrappers.get(that) || that, args);
|
||||||
|
let [name] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ name }, target, (this.wrappers.get(that) || that));
|
const event = new HookEvent(
|
||||||
|
{ name },
|
||||||
|
target,
|
||||||
|
this.wrappers.get(that) || that
|
||||||
|
);
|
||||||
this.emit('getItem', event);
|
this.emit('getItem', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.name);
|
return event.target.call(event.that, event.data.name);
|
||||||
});
|
});
|
||||||
this.ctx.override(this.storeProto, 'setItem', (target, that, args) => {
|
this.ctx.override(this.storeProto, 'setItem', (target, that, args) => {
|
||||||
if (2 > args.length) return target.apply((this.wrappers.get(that) || that), args);
|
if (2 > args.length)
|
||||||
let [ name, value ] = args;
|
return target.apply(this.wrappers.get(that) || that, args);
|
||||||
|
let [name, value] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ name, value }, target, (this.wrappers.get(that) || that));
|
const event = new HookEvent(
|
||||||
|
{ name, value },
|
||||||
|
target,
|
||||||
|
this.wrappers.get(that) || that
|
||||||
|
);
|
||||||
this.emit('setItem', event);
|
this.emit('setItem', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.name, event.data.value);
|
return event.target.call(
|
||||||
|
event.that,
|
||||||
|
event.data.name,
|
||||||
|
event.data.value
|
||||||
|
);
|
||||||
});
|
});
|
||||||
this.ctx.override(this.storeProto, 'removeItem', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return target.apply((this.wrappers.get(that) || that), args);
|
this.storeProto,
|
||||||
let [ name ] = args;
|
'removeItem',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length)
|
||||||
|
return target.apply(this.wrappers.get(that) || that, args);
|
||||||
|
let [name] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ name }, target, (this.wrappers.get(that) || that));
|
const event = new HookEvent(
|
||||||
this.emit('removeItem', event);
|
{ name },
|
||||||
|
target,
|
||||||
|
this.wrappers.get(that) || that
|
||||||
|
);
|
||||||
|
this.emit('removeItem', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.name);
|
return event.target.call(event.that, event.data.name);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
this.ctx.override(this.storeProto, 'clear', (target, that) => {
|
this.ctx.override(this.storeProto, 'clear', (target, that) => {
|
||||||
const event = new HookEvent(null, target, (this.wrappers.get(that) || that));
|
const event = new HookEvent(
|
||||||
|
null,
|
||||||
|
target,
|
||||||
|
this.wrappers.get(that) || that
|
||||||
|
);
|
||||||
this.emit('clear', event);
|
this.emit('clear', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that);
|
return event.target.call(event.that);
|
||||||
});
|
});
|
||||||
this.ctx.override(this.storeProto, 'key', (target, that, args) => {
|
this.ctx.override(this.storeProto, 'key', (target, that, args) => {
|
||||||
if (!args.length) return target.apply((this.wrappers.get(that) || that), args);
|
if (!args.length)
|
||||||
let [ index ] = args;
|
return target.apply(this.wrappers.get(that) || that, args);
|
||||||
|
let [index] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ index }, target, (this.wrappers.get(that) || that));
|
const event = new HookEvent(
|
||||||
|
{ index },
|
||||||
|
target,
|
||||||
|
this.wrappers.get(that) || that
|
||||||
|
);
|
||||||
this.emit('key', event);
|
this.emit('key', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.index);
|
return event.target.call(event.that, event.data.index);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
overrideLength() {
|
overrideLength() {
|
||||||
this.ctx.overrideDescriptor(this.storeProto, 'length', {
|
this.ctx.overrideDescriptor(this.storeProto, 'length', {
|
||||||
get: (target, that) => {
|
get: (target, that) => {
|
||||||
const event = new HookEvent({ length: target.call((this.wrappers.get(that) || that)) }, target, (this.wrappers.get(that) || that));
|
const event = new HookEvent(
|
||||||
|
{ length: target.call(this.wrappers.get(that) || that) },
|
||||||
|
target,
|
||||||
|
this.wrappers.get(that) || that
|
||||||
|
);
|
||||||
this.emit('length', event);
|
this.emit('length', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.data.length;
|
return event.data.length;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
emulate(storage, obj = {}) {
|
emulate(storage, obj = {}) {
|
||||||
this.ctx.nativeMethods.setPrototypeOf(obj, this.storeProto);
|
this.ctx.nativeMethods.setPrototypeOf(obj, this.storeProto);
|
||||||
|
|
||||||
const proxy = new this.ctx.window.Proxy(obj, {
|
const proxy = new this.ctx.window.Proxy(obj, {
|
||||||
get: (target, prop) => {
|
get: (target, prop) => {
|
||||||
if (prop in this.storeProto || typeof prop === 'symbol') return storage[prop];
|
if (prop in this.storeProto || typeof prop === 'symbol')
|
||||||
|
return storage[prop];
|
||||||
|
|
||||||
const event = new HookEvent({ name: prop }, null, storage);
|
const event = new HookEvent({ name: prop }, null, storage);
|
||||||
this.emit('get', event);
|
this.emit('get', event);
|
||||||
|
@ -92,14 +129,19 @@ class StorageApi extends EventEmitter {
|
||||||
return storage[event.data.name];
|
return storage[event.data.name];
|
||||||
},
|
},
|
||||||
set: (target, prop, value) => {
|
set: (target, prop, value) => {
|
||||||
if (prop in this.storeProto || typeof prop === 'symbol') return storage[prop] = value;
|
if (prop in this.storeProto || typeof prop === 'symbol')
|
||||||
|
return (storage[prop] = value);
|
||||||
|
|
||||||
const event = new HookEvent({ name: prop, value }, null, storage);
|
const event = new HookEvent(
|
||||||
|
{ name: prop, value },
|
||||||
|
null,
|
||||||
|
storage
|
||||||
|
);
|
||||||
this.emit('set', event);
|
this.emit('set', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
|
|
||||||
return storage[event.data.name] = event.data.value;
|
return (storage[event.data.name] = event.data.value);
|
||||||
},
|
},
|
||||||
deleteProperty: (target, prop) => {
|
deleteProperty: (target, prop) => {
|
||||||
if (typeof prop === 'symbol') return delete storage[prop];
|
if (typeof prop === 'symbol') return delete storage[prop];
|
||||||
|
@ -117,8 +159,7 @@ class StorageApi extends EventEmitter {
|
||||||
this.ctx.nativeMethods.setPrototypeOf(proxy, this.storeProto);
|
this.ctx.nativeMethods.setPrototypeOf(proxy, this.storeProto);
|
||||||
|
|
||||||
return proxy;
|
return proxy;
|
||||||
};
|
}
|
||||||
|
}
|
||||||
};
|
|
||||||
|
|
||||||
export default StorageApi;
|
export default StorageApi;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import EventEmitter from "./events.js";
|
import EventEmitter from './events.js';
|
||||||
import HookEvent from "./hook.js";
|
import HookEvent from './hook.js';
|
||||||
|
|
||||||
class URLApi extends EventEmitter {
|
class URLApi extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -9,11 +9,11 @@ class URLApi extends EventEmitter {
|
||||||
this.URL = this.window.URL || {};
|
this.URL = this.window.URL || {};
|
||||||
this.createObjectURL = this.URL.createObjectURL;
|
this.createObjectURL = this.URL.createObjectURL;
|
||||||
this.revokeObjectURL = this.URL.revokeObjectURL;
|
this.revokeObjectURL = this.URL.revokeObjectURL;
|
||||||
};
|
}
|
||||||
overrideObjectURL() {
|
overrideObjectURL() {
|
||||||
this.ctx.override(this.URL, 'createObjectURL', (target, that, args) => {
|
this.ctx.override(this.URL, 'createObjectURL', (target, that, args) => {
|
||||||
if (!args.length) return target.apply(that, args);
|
if (!args.length) return target.apply(that, args);
|
||||||
let [ object ] = args;
|
let [object] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ object }, target, that);
|
const event = new HookEvent({ object }, target, that);
|
||||||
this.emit('createObjectURL', event);
|
this.emit('createObjectURL', event);
|
||||||
|
@ -23,7 +23,7 @@ class URLApi extends EventEmitter {
|
||||||
});
|
});
|
||||||
this.ctx.override(this.URL, 'revokeObjectURL', (target, that, args) => {
|
this.ctx.override(this.URL, 'revokeObjectURL', (target, that, args) => {
|
||||||
if (!args.length) return target.apply(that, args);
|
if (!args.length) return target.apply(that, args);
|
||||||
let [ url ] = args;
|
let [url] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ url }, target, that);
|
const event = new HookEvent({ url }, target, that);
|
||||||
this.emit('revokeObjectURL', event);
|
this.emit('revokeObjectURL', event);
|
||||||
|
@ -31,7 +31,7 @@ class URLApi extends EventEmitter {
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.url);
|
return event.target.call(event.that, event.data.url);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default URLApi;
|
export default URLApi;
|
|
@ -1,5 +1,5 @@
|
||||||
import EventEmitter from "./events.js";
|
import EventEmitter from './events.js';
|
||||||
import HookEvent from "./hook.js";
|
import HookEvent from './hook.js';
|
||||||
|
|
||||||
class Workers extends EventEmitter {
|
class Workers extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -13,54 +13,85 @@ class Workers extends EventEmitter {
|
||||||
this.postMessage = this.workerProto.postMessage;
|
this.postMessage = this.workerProto.postMessage;
|
||||||
this.terminate = this.workerProto.terminate;
|
this.terminate = this.workerProto.terminate;
|
||||||
this.addModule = this.workletProto.addModule;
|
this.addModule = this.workletProto.addModule;
|
||||||
};
|
}
|
||||||
overrideWorker() {
|
overrideWorker() {
|
||||||
this.ctx.override(this.window, 'Worker', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return new target(...args);
|
this.window,
|
||||||
let [ url, options = {} ] = args;
|
'Worker',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return new target(...args);
|
||||||
|
let [url, options = {}] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ url, options }, target, that);
|
const event = new HookEvent({ url, options }, target, that);
|
||||||
this.emit('worker', event);
|
this.emit('worker', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return new event.target(...[ event.data.url, event.data.options ]);
|
return new event.target(
|
||||||
}, true);
|
...[event.data.url, event.data.options]
|
||||||
};
|
);
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
overrideAddModule() {
|
overrideAddModule() {
|
||||||
this.ctx.override(this.workletProto, 'addModule', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return target.apply(that, args);
|
this.workletProto,
|
||||||
let [ url, options = {} ] = args;
|
'addModule',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return target.apply(that, args);
|
||||||
|
let [url, options = {}] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ url, options }, target, that);
|
const event = new HookEvent({ url, options }, target, that);
|
||||||
this.emit('addModule', event);
|
this.emit('addModule', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.url, event.data.options);
|
return event.target.call(
|
||||||
});
|
event.that,
|
||||||
};
|
event.data.url,
|
||||||
|
event.data.options
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
overridePostMessage() {
|
overridePostMessage() {
|
||||||
this.ctx.override(this.workerProto, 'postMessage', (target, that, args) => {
|
this.ctx.override(
|
||||||
if (!args.length) return target.apply(that, args);
|
this.workerProto,
|
||||||
let [ message, transfer = [] ] = args;
|
'postMessage',
|
||||||
|
(target, that, args) => {
|
||||||
|
if (!args.length) return target.apply(that, args);
|
||||||
|
let [message, transfer = []] = args;
|
||||||
|
|
||||||
const event = new HookEvent({ message, transfer }, target, that);
|
const event = new HookEvent(
|
||||||
this.emit('postMessage', event);
|
{ message, transfer },
|
||||||
|
target,
|
||||||
|
that
|
||||||
|
);
|
||||||
|
this.emit('postMessage', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.call(event.that, event.data.message, event.data.transfer);
|
return event.target.call(
|
||||||
});
|
event.that,
|
||||||
};
|
event.data.message,
|
||||||
|
event.data.transfer
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
overrideImportScripts() {
|
overrideImportScripts() {
|
||||||
this.ctx.override(this.window, 'importScripts', (target, that, scripts) => {
|
this.ctx.override(
|
||||||
if (!scripts.length) return target.apply(that, scripts);
|
this.window,
|
||||||
|
'importScripts',
|
||||||
|
(target, that, scripts) => {
|
||||||
|
if (!scripts.length) return target.apply(that, scripts);
|
||||||
|
|
||||||
const event = new HookEvent({ scripts }, target, that);
|
const event = new HookEvent({ scripts }, target, that);
|
||||||
this.emit('importScripts', event);
|
this.emit('importScripts', event);
|
||||||
|
|
||||||
if (event.intercepted) return event.returnValue;
|
if (event.intercepted) return event.returnValue;
|
||||||
return event.target.apply(event.that, event.data.scripts);
|
return event.target.apply(event.that, event.data.scripts);
|
||||||
});
|
}
|
||||||
};
|
);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default Workers;
|
export default Workers;
|
|
@ -3,15 +3,30 @@
|
||||||
// Do not use any browser or node-specific API!
|
// Do not use any browser or node-specific API!
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
export const xor = {
|
export const xor = {
|
||||||
encode(str){
|
encode(str) {
|
||||||
if (!str) return str;
|
if (!str) return str;
|
||||||
return encodeURIComponent(str.toString().split('').map((char, ind) => ind % 2 ? String.fromCharCode(char.charCodeAt() ^ 2) : char).join(''));
|
return encodeURIComponent(
|
||||||
|
str
|
||||||
|
.toString()
|
||||||
|
.split('')
|
||||||
|
.map((char, ind) =>
|
||||||
|
ind % 2 ? String.fromCharCode(char.charCodeAt() ^ 2) : char
|
||||||
|
)
|
||||||
|
.join('')
|
||||||
|
);
|
||||||
},
|
},
|
||||||
decode(str){
|
decode(str) {
|
||||||
if (!str) return str;
|
if (!str) return str;
|
||||||
let [ input, ...search ] = str.split('?');
|
let [input, ...search] = str.split('?');
|
||||||
|
|
||||||
return decodeURIComponent(input).split('').map((char, ind) => ind % 2 ? String.fromCharCode(char.charCodeAt(0) ^ 2) : char).join('') + (search.length ? '?' + search.join('?') : '');
|
return (
|
||||||
|
decodeURIComponent(input)
|
||||||
|
.split('')
|
||||||
|
.map((char, ind) =>
|
||||||
|
ind % 2 ? String.fromCharCode(char.charCodeAt(0) ^ 2) : char
|
||||||
|
)
|
||||||
|
.join('') + (search.length ? '?' + search.join('?') : '')
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -27,10 +42,12 @@ export const plain = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const base64 = {
|
export const base64 = {
|
||||||
encode(str){
|
encode(str) {
|
||||||
if (!str) return str;
|
if (!str) return str;
|
||||||
str = str.toString();
|
str = str.toString();
|
||||||
const b64chs = Array.from('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=');
|
const b64chs = Array.from(
|
||||||
|
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
|
||||||
|
);
|
||||||
let u32;
|
let u32;
|
||||||
let c0;
|
let c0;
|
||||||
let c1;
|
let c1;
|
||||||
|
@ -38,21 +55,95 @@ export const base64 = {
|
||||||
let asc = '';
|
let asc = '';
|
||||||
let pad = str.length % 3;
|
let pad = str.length % 3;
|
||||||
|
|
||||||
for (let i = 0; i < str.length;) {
|
for (let i = 0; i < str.length; ) {
|
||||||
if((c0 = str.charCodeAt(i++)) > 255 || (c1 = str.charCodeAt(i++)) > 255 || (c2 = str.charCodeAt(i++)) > 255)throw new TypeError('invalid character found');
|
if (
|
||||||
|
(c0 = str.charCodeAt(i++)) > 255 ||
|
||||||
|
(c1 = str.charCodeAt(i++)) > 255 ||
|
||||||
|
(c2 = str.charCodeAt(i++)) > 255
|
||||||
|
)
|
||||||
|
throw new TypeError('invalid character found');
|
||||||
u32 = (c0 << 16) | (c1 << 8) | c2;
|
u32 = (c0 << 16) | (c1 << 8) | c2;
|
||||||
asc += b64chs[u32 >> 18 & 63]
|
asc +=
|
||||||
+ b64chs[u32 >> 12 & 63]
|
b64chs[(u32 >> 18) & 63] +
|
||||||
+ b64chs[u32 >> 6 & 63]
|
b64chs[(u32 >> 12) & 63] +
|
||||||
+ b64chs[u32 & 63];
|
b64chs[(u32 >> 6) & 63] +
|
||||||
|
b64chs[u32 & 63];
|
||||||
}
|
}
|
||||||
|
|
||||||
return encodeURIComponent(pad ? asc.slice(0, pad - 3) + '==='.substr(pad) : asc);
|
return encodeURIComponent(
|
||||||
|
pad ? asc.slice(0, pad - 3) + '==='.substr(pad) : asc
|
||||||
|
);
|
||||||
},
|
},
|
||||||
decode(str){
|
decode(str) {
|
||||||
if (!str) return str;
|
if (!str) return str;
|
||||||
str = decodeURIComponent(str.toString());
|
str = decodeURIComponent(str.toString());
|
||||||
const b64tab = {"0":52,"1":53,"2":54,"3":55,"4":56,"5":57,"6":58,"7":59,"8":60,"9":61,"A":0,"B":1,"C":2,"D":3,"E":4,"F":5,"G":6,"H":7,"I":8,"J":9,"K":10,"L":11,"M":12,"N":13,"O":14,"P":15,"Q":16,"R":17,"S":18,"T":19,"U":20,"V":21,"W":22,"X":23,"Y":24,"Z":25,"a":26,"b":27,"c":28,"d":29,"e":30,"f":31,"g":32,"h":33,"i":34,"j":35,"k":36,"l":37,"m":38,"n":39,"o":40,"p":41,"q":42,"r":43,"s":44,"t":45,"u":46,"v":47,"w":48,"x":49,"y":50,"z":51,"+":62,"/":63,"=":64};
|
const b64tab = {
|
||||||
|
0: 52,
|
||||||
|
1: 53,
|
||||||
|
2: 54,
|
||||||
|
3: 55,
|
||||||
|
4: 56,
|
||||||
|
5: 57,
|
||||||
|
6: 58,
|
||||||
|
7: 59,
|
||||||
|
8: 60,
|
||||||
|
9: 61,
|
||||||
|
A: 0,
|
||||||
|
B: 1,
|
||||||
|
C: 2,
|
||||||
|
D: 3,
|
||||||
|
E: 4,
|
||||||
|
F: 5,
|
||||||
|
G: 6,
|
||||||
|
H: 7,
|
||||||
|
I: 8,
|
||||||
|
J: 9,
|
||||||
|
K: 10,
|
||||||
|
L: 11,
|
||||||
|
M: 12,
|
||||||
|
N: 13,
|
||||||
|
O: 14,
|
||||||
|
P: 15,
|
||||||
|
Q: 16,
|
||||||
|
R: 17,
|
||||||
|
S: 18,
|
||||||
|
T: 19,
|
||||||
|
U: 20,
|
||||||
|
V: 21,
|
||||||
|
W: 22,
|
||||||
|
X: 23,
|
||||||
|
Y: 24,
|
||||||
|
Z: 25,
|
||||||
|
a: 26,
|
||||||
|
b: 27,
|
||||||
|
c: 28,
|
||||||
|
d: 29,
|
||||||
|
e: 30,
|
||||||
|
f: 31,
|
||||||
|
g: 32,
|
||||||
|
h: 33,
|
||||||
|
i: 34,
|
||||||
|
j: 35,
|
||||||
|
k: 36,
|
||||||
|
l: 37,
|
||||||
|
m: 38,
|
||||||
|
n: 39,
|
||||||
|
o: 40,
|
||||||
|
p: 41,
|
||||||
|
q: 42,
|
||||||
|
r: 43,
|
||||||
|
s: 44,
|
||||||
|
t: 45,
|
||||||
|
u: 46,
|
||||||
|
v: 47,
|
||||||
|
w: 48,
|
||||||
|
x: 49,
|
||||||
|
y: 50,
|
||||||
|
z: 51,
|
||||||
|
'+': 62,
|
||||||
|
'/': 63,
|
||||||
|
'=': 64,
|
||||||
|
};
|
||||||
str = str.replace(/\s+/g, '');
|
str = str.replace(/\s+/g, '');
|
||||||
str += '=='.slice(2 - (str.length & 3));
|
str += '=='.slice(2 - (str.length & 3));
|
||||||
let u24;
|
let u24;
|
||||||
|
@ -60,15 +151,23 @@ export const base64 = {
|
||||||
let r1;
|
let r1;
|
||||||
let r2;
|
let r2;
|
||||||
|
|
||||||
for (let i = 0; i < str.length;) {
|
for (let i = 0; i < str.length; ) {
|
||||||
u24 = b64tab[str.charAt(i++)] << 18
|
u24 =
|
||||||
| b64tab[str.charAt(i++)] << 12
|
(b64tab[str.charAt(i++)] << 18) |
|
||||||
| (r1 = b64tab[str.charAt(i++)]) << 6
|
(b64tab[str.charAt(i++)] << 12) |
|
||||||
| (r2 = b64tab[str.charAt(i++)]);
|
((r1 = b64tab[str.charAt(i++)]) << 6) |
|
||||||
bin += r1 === 64 ? String.fromCharCode(u24 >> 16 & 255)
|
(r2 = b64tab[str.charAt(i++)]);
|
||||||
: r2 === 64 ? String.fromCharCode(u24 >> 16 & 255, u24 >> 8 & 255)
|
bin +=
|
||||||
: String.fromCharCode(u24 >> 16 & 255, u24 >> 8 & 255, u24 & 255);
|
r1 === 64
|
||||||
};
|
? String.fromCharCode((u24 >> 16) & 255)
|
||||||
|
: r2 === 64
|
||||||
|
? String.fromCharCode((u24 >> 16) & 255, (u24 >> 8) & 255)
|
||||||
|
: String.fromCharCode(
|
||||||
|
(u24 >> 16) & 255,
|
||||||
|
(u24 >> 8) & 255,
|
||||||
|
u24 & 255
|
||||||
|
);
|
||||||
|
}
|
||||||
return bin;
|
return bin;
|
||||||
},
|
},
|
||||||
};
|
};
|
|
@ -8,17 +8,16 @@ function validateCookie(cookie, meta, js = false) {
|
||||||
if (cookie.httpOnly && !!js) return false;
|
if (cookie.httpOnly && !!js) return false;
|
||||||
|
|
||||||
if (cookie.domain.startsWith('.')) {
|
if (cookie.domain.startsWith('.')) {
|
||||||
|
|
||||||
if (!meta.url.hostname.endsWith(cookie.domain.slice(1))) return false;
|
if (!meta.url.hostname.endsWith(cookie.domain.slice(1))) return false;
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
if (cookie.domain !== meta.url.hostname) return false;
|
if (cookie.domain !== meta.url.hostname) return false;
|
||||||
if (cookie.secure && meta.url.protocol === 'http:') return false;
|
if (cookie.secure && meta.url.protocol === 'http:') return false;
|
||||||
if (!meta.url.pathname.startsWith(cookie.path)) return false;
|
if (!meta.url.pathname.startsWith(cookie.path)) return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
async function db(openDB) {
|
async function db(openDB) {
|
||||||
const db = await openDB('__op', 1, {
|
const db = await openDB('__op', 1, {
|
||||||
|
@ -31,8 +30,7 @@ async function db(openDB) {
|
||||||
});
|
});
|
||||||
db.transaction(['cookies'], 'readwrite').store.index('path');
|
db.transaction(['cookies'], 'readwrite').store.index('path');
|
||||||
return db;
|
return db;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
function serialize(cookies = [], meta, js) {
|
function serialize(cookies = [], meta, js) {
|
||||||
let str = '';
|
let str = '';
|
||||||
|
@ -40,40 +38,39 @@ function serialize(cookies = [], meta, js) {
|
||||||
if (!validateCookie(cookie, meta, js)) continue;
|
if (!validateCookie(cookie, meta, js)) continue;
|
||||||
if (str.length) str += '; ';
|
if (str.length) str += '; ';
|
||||||
str += cookie.name;
|
str += cookie.name;
|
||||||
str += '='
|
str += '=';
|
||||||
str += cookie.value;
|
str += cookie.value;
|
||||||
};
|
}
|
||||||
return str;
|
return str;
|
||||||
};
|
}
|
||||||
|
|
||||||
async function getCookies(db) {
|
async function getCookies(db) {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
return (await db.getAll('cookies')).filter(cookie => {
|
return (await db.getAll('cookies')).filter((cookie) => {
|
||||||
|
|
||||||
let expired = false;
|
let expired = false;
|
||||||
if (cookie.set) {
|
if (cookie.set) {
|
||||||
if (cookie.maxAge) {
|
if (cookie.maxAge) {
|
||||||
expired = (cookie.set.getTime() + (cookie.maxAge * 1e3)) < now;
|
expired = cookie.set.getTime() + cookie.maxAge * 1e3 < now;
|
||||||
} else if (cookie.expires) {
|
} else if (cookie.expires) {
|
||||||
expired = new Date(cookie.expires.toLocaleString()) < now;
|
expired = new Date(cookie.expires.toLocaleString()) < now;
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
if (expired) {
|
if (expired) {
|
||||||
db.delete('cookies', cookie.id);
|
db.delete('cookies', cookie.id);
|
||||||
return false;
|
return false;
|
||||||
};
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
function setCookies(data, db, meta) {
|
function setCookies(data, db, meta) {
|
||||||
if (!db) return false;
|
if (!db) return false;
|
||||||
|
|
||||||
const cookies = setCookie(data, {
|
const cookies = setCookie(data, {
|
||||||
decodeValues: false,
|
decodeValues: false,
|
||||||
})
|
});
|
||||||
|
|
||||||
for (const cookie of cookies) {
|
for (const cookie of cookies) {
|
||||||
if (!cookie.domain) cookie.domain = '.' + meta.url.hostname;
|
if (!cookie.domain) cookie.domain = '.' + meta.url.hostname;
|
||||||
|
@ -81,15 +78,15 @@ function setCookies(data, db, meta) {
|
||||||
|
|
||||||
if (!cookie.domain.startsWith('.')) {
|
if (!cookie.domain.startsWith('.')) {
|
||||||
cookie.domain = '.' + cookie.domain;
|
cookie.domain = '.' + cookie.domain;
|
||||||
};
|
}
|
||||||
|
|
||||||
db.put('cookies', {
|
db.put('cookies', {
|
||||||
...cookie,
|
...cookie,
|
||||||
id: `${cookie.domain}@${cookie.path}@${cookie.name}`,
|
id: `${cookie.domain}@${cookie.path}@${cookie.name}`,
|
||||||
set: new Date(Date.now()),
|
set: new Date(Date.now()),
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
export { validateCookie, getCookies, setCookies, db , serialize };
|
export { validateCookie, getCookies, setCookies, db, serialize };
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { parse, walk, generate } from "css-tree";
|
import { parse, walk, generate } from 'css-tree';
|
||||||
import EventEmitter from "./events.js";
|
import EventEmitter from './events.js';
|
||||||
import parsel from "./parsel.js";
|
import parsel from './parsel.js';
|
||||||
|
|
||||||
class CSS extends EventEmitter {
|
class CSS extends EventEmitter {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
@ -11,26 +11,29 @@ class CSS extends EventEmitter {
|
||||||
this.parse = parse;
|
this.parse = parse;
|
||||||
this.walk = walk;
|
this.walk = walk;
|
||||||
this.generate = generate;
|
this.generate = generate;
|
||||||
};
|
}
|
||||||
rewrite(str, options) {
|
rewrite(str, options) {
|
||||||
return this.recast(str, options, 'rewrite');
|
return this.recast(str, options, 'rewrite');
|
||||||
};
|
}
|
||||||
source(str, options) {
|
source(str, options) {
|
||||||
return this.recast(str, options, 'source');
|
return this.recast(str, options, 'source');
|
||||||
};
|
}
|
||||||
recast(str, options, type) {
|
recast(str, options, type) {
|
||||||
if (!str) return str;
|
if (!str) return str;
|
||||||
str = new String(str).toString();
|
str = new String(str).toString();
|
||||||
try {
|
try {
|
||||||
const ast = this.parse(str, { ...options, parseCustomProperty: true });
|
const ast = this.parse(str, {
|
||||||
this.walk(ast, node => {
|
...options,
|
||||||
|
parseCustomProperty: true,
|
||||||
|
});
|
||||||
|
this.walk(ast, (node) => {
|
||||||
this.emit(node.type, node, options, type);
|
this.emit(node.type, node, options, type);
|
||||||
});
|
});
|
||||||
return this.generate(ast);
|
return this.generate(ast);
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
return str;
|
return str;
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default CSS;
|
export default CSS;
|
|
@ -21,37 +21,41 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var R = typeof Reflect === 'object' ? Reflect : null
|
var R = typeof Reflect === 'object' ? Reflect : null;
|
||||||
var ReflectApply = R && typeof R.apply === 'function'
|
var ReflectApply =
|
||||||
? R.apply
|
R && typeof R.apply === 'function'
|
||||||
: function ReflectApply(target, receiver, args) {
|
? R.apply
|
||||||
return Function.prototype.apply.call(target, receiver, args);
|
: function ReflectApply(target, receiver, args) {
|
||||||
}
|
return Function.prototype.apply.call(target, receiver, args);
|
||||||
|
};
|
||||||
|
|
||||||
var ReflectOwnKeys
|
var ReflectOwnKeys;
|
||||||
if (R && typeof R.ownKeys === 'function') {
|
if (R && typeof R.ownKeys === 'function') {
|
||||||
ReflectOwnKeys = R.ownKeys
|
ReflectOwnKeys = R.ownKeys;
|
||||||
} else if (Object.getOwnPropertySymbols) {
|
} else if (Object.getOwnPropertySymbols) {
|
||||||
ReflectOwnKeys = function ReflectOwnKeys(target) {
|
ReflectOwnKeys = function ReflectOwnKeys(target) {
|
||||||
return Object.getOwnPropertyNames(target)
|
return Object.getOwnPropertyNames(target).concat(
|
||||||
.concat(Object.getOwnPropertySymbols(target));
|
Object.getOwnPropertySymbols(target)
|
||||||
};
|
);
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
ReflectOwnKeys = function ReflectOwnKeys(target) {
|
ReflectOwnKeys = function ReflectOwnKeys(target) {
|
||||||
return Object.getOwnPropertyNames(target);
|
return Object.getOwnPropertyNames(target);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function ProcessEmitWarning(warning) {
|
function ProcessEmitWarning(warning) {
|
||||||
if (console && console.warn) console.warn(warning);
|
if (console && console.warn) console.warn(warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {
|
var NumberIsNaN =
|
||||||
return value !== value;
|
Number.isNaN ||
|
||||||
}
|
function NumberIsNaN(value) {
|
||||||
|
return value !== value;
|
||||||
|
};
|
||||||
|
|
||||||
function EventEmitter() {
|
function EventEmitter() {
|
||||||
EventEmitter.init.call(this);
|
EventEmitter.init.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default EventEmitter;
|
export default EventEmitter;
|
||||||
|
@ -68,430 +72,451 @@ EventEmitter.prototype._maxListeners = undefined;
|
||||||
var defaultMaxListeners = 10;
|
var defaultMaxListeners = 10;
|
||||||
|
|
||||||
function checkListener(listener) {
|
function checkListener(listener) {
|
||||||
if (typeof listener !== 'function') {
|
if (typeof listener !== 'function') {
|
||||||
throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
|
throw new TypeError(
|
||||||
}
|
'The "listener" argument must be of type Function. Received type ' +
|
||||||
|
typeof listener
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
|
Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
get: function() {
|
get: function () {
|
||||||
return defaultMaxListeners;
|
return defaultMaxListeners;
|
||||||
},
|
},
|
||||||
set: function(arg) {
|
set: function (arg) {
|
||||||
if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
|
if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
|
||||||
throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.');
|
throw new RangeError(
|
||||||
}
|
'The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' +
|
||||||
defaultMaxListeners = arg;
|
arg +
|
||||||
}
|
'.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
defaultMaxListeners = arg;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
EventEmitter.init = function() {
|
EventEmitter.init = function () {
|
||||||
|
if (
|
||||||
|
this._events === undefined ||
|
||||||
|
this._events === Object.getPrototypeOf(this)._events
|
||||||
|
) {
|
||||||
|
this._events = Object.create(null);
|
||||||
|
this._eventsCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (this._events === undefined ||
|
this._maxListeners = this._maxListeners || undefined;
|
||||||
this._events === Object.getPrototypeOf(this)._events) {
|
|
||||||
this._events = Object.create(null);
|
|
||||||
this._eventsCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._maxListeners = this._maxListeners || undefined;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Obviously not all Emitters should be limited to 10. This function allows
|
// Obviously not all Emitters should be limited to 10. This function allows
|
||||||
// that to be increased. Set to zero for unlimited.
|
// that to be increased. Set to zero for unlimited.
|
||||||
EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
|
EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
|
||||||
if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
|
if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
|
||||||
throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.');
|
throw new RangeError(
|
||||||
}
|
'The value of "n" is out of range. It must be a non-negative number. Received ' +
|
||||||
this._maxListeners = n;
|
n +
|
||||||
return this;
|
'.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this._maxListeners = n;
|
||||||
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
function _getMaxListeners(that) {
|
function _getMaxListeners(that) {
|
||||||
if (that._maxListeners === undefined)
|
if (that._maxListeners === undefined)
|
||||||
return EventEmitter.defaultMaxListeners;
|
return EventEmitter.defaultMaxListeners;
|
||||||
return that._maxListeners;
|
return that._maxListeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
|
EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
|
||||||
return _getMaxListeners(this);
|
return _getMaxListeners(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
EventEmitter.prototype.emit = function emit(type) {
|
EventEmitter.prototype.emit = function emit(type) {
|
||||||
var args = [];
|
var args = [];
|
||||||
for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
|
for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
|
||||||
var doError = (type === 'error');
|
var doError = type === 'error';
|
||||||
|
|
||||||
var events = this._events;
|
var events = this._events;
|
||||||
if (events !== undefined)
|
if (events !== undefined) doError = doError && events.error === undefined;
|
||||||
doError = (doError && events.error === undefined);
|
else if (!doError) return false;
|
||||||
else if (!doError)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// If there is no 'error' event listener then throw.
|
// If there is no 'error' event listener then throw.
|
||||||
if (doError) {
|
if (doError) {
|
||||||
var er;
|
var er;
|
||||||
if (args.length > 0)
|
if (args.length > 0) er = args[0];
|
||||||
er = args[0];
|
if (er instanceof Error) {
|
||||||
if (er instanceof Error) {
|
// Note: The comments on the `throw` lines are intentional, they show
|
||||||
// Note: The comments on the `throw` lines are intentional, they show
|
// up in Node's output if this results in an unhandled exception.
|
||||||
// up in Node's output if this results in an unhandled exception.
|
throw er; // Unhandled 'error' event
|
||||||
throw er; // Unhandled 'error' event
|
}
|
||||||
|
// At least give some kind of context to the user
|
||||||
|
var err = new Error(
|
||||||
|
'Unhandled error.' + (er ? ' (' + er.message + ')' : '')
|
||||||
|
);
|
||||||
|
err.context = er;
|
||||||
|
throw err; // Unhandled 'error' event
|
||||||
}
|
}
|
||||||
// At least give some kind of context to the user
|
|
||||||
var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));
|
|
||||||
err.context = er;
|
|
||||||
throw err; // Unhandled 'error' event
|
|
||||||
}
|
|
||||||
|
|
||||||
var handler = events[type];
|
var handler = events[type];
|
||||||
|
|
||||||
if (handler === undefined)
|
if (handler === undefined) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
if (typeof handler === 'function') {
|
if (typeof handler === 'function') {
|
||||||
ReflectApply(handler, this, args);
|
ReflectApply(handler, this, args);
|
||||||
} else {
|
} else {
|
||||||
var len = handler.length;
|
var len = handler.length;
|
||||||
var listeners = arrayClone(handler, len);
|
var listeners = arrayClone(handler, len);
|
||||||
for (var i = 0; i < len; ++i)
|
for (var i = 0; i < len; ++i) ReflectApply(listeners[i], this, args);
|
||||||
ReflectApply(listeners[i], this, args);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
function _addListener(target, type, listener, prepend) {
|
function _addListener(target, type, listener, prepend) {
|
||||||
var m;
|
var m;
|
||||||
var events;
|
var events;
|
||||||
var existing;
|
var existing;
|
||||||
|
|
||||||
checkListener(listener);
|
checkListener(listener);
|
||||||
|
|
||||||
events = target._events;
|
events = target._events;
|
||||||
if (events === undefined) {
|
if (events === undefined) {
|
||||||
events = target._events = Object.create(null);
|
events = target._events = Object.create(null);
|
||||||
target._eventsCount = 0;
|
target._eventsCount = 0;
|
||||||
} else {
|
|
||||||
// To avoid recursion in the case that type === "newListener"! Before
|
|
||||||
// adding it to the listeners, first emit "newListener".
|
|
||||||
if (events.newListener !== undefined) {
|
|
||||||
target.emit('newListener', type,
|
|
||||||
listener.listener ? listener.listener : listener);
|
|
||||||
|
|
||||||
// Re-assign `events` because a newListener handler could have caused the
|
|
||||||
// this._events to be assigned to a new object
|
|
||||||
events = target._events;
|
|
||||||
}
|
|
||||||
existing = events[type];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existing === undefined) {
|
|
||||||
// Optimize the case of one listener. Don't need the extra array object.
|
|
||||||
existing = events[type] = listener;
|
|
||||||
++target._eventsCount;
|
|
||||||
} else {
|
|
||||||
if (typeof existing === 'function') {
|
|
||||||
// Adding the second element, need to change to array.
|
|
||||||
existing = events[type] =
|
|
||||||
prepend ? [listener, existing] : [existing, listener];
|
|
||||||
// If we've already got an array, just append.
|
|
||||||
} else if (prepend) {
|
|
||||||
existing.unshift(listener);
|
|
||||||
} else {
|
} else {
|
||||||
existing.push(listener);
|
// To avoid recursion in the case that type === "newListener"! Before
|
||||||
|
// adding it to the listeners, first emit "newListener".
|
||||||
|
if (events.newListener !== undefined) {
|
||||||
|
target.emit(
|
||||||
|
'newListener',
|
||||||
|
type,
|
||||||
|
listener.listener ? listener.listener : listener
|
||||||
|
);
|
||||||
|
|
||||||
|
// Re-assign `events` because a newListener handler could have caused the
|
||||||
|
// this._events to be assigned to a new object
|
||||||
|
events = target._events;
|
||||||
|
}
|
||||||
|
existing = events[type];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for listener leak
|
if (existing === undefined) {
|
||||||
m = _getMaxListeners(target);
|
// Optimize the case of one listener. Don't need the extra array object.
|
||||||
if (m > 0 && existing.length > m && !existing.warned) {
|
existing = events[type] = listener;
|
||||||
existing.warned = true;
|
++target._eventsCount;
|
||||||
// No error code for this since it is a Warning
|
} else {
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
if (typeof existing === 'function') {
|
||||||
var w = new Error('Possible EventEmitter memory leak detected. ' +
|
// Adding the second element, need to change to array.
|
||||||
existing.length + ' ' + String(type) + ' listeners ' +
|
existing = events[type] = prepend
|
||||||
'added. Use emitter.setMaxListeners() to ' +
|
? [listener, existing]
|
||||||
'increase limit');
|
: [existing, listener];
|
||||||
w.name = 'MaxListenersExceededWarning';
|
// If we've already got an array, just append.
|
||||||
w.emitter = target;
|
} else if (prepend) {
|
||||||
w.type = type;
|
existing.unshift(listener);
|
||||||
w.count = existing.length;
|
} else {
|
||||||
ProcessEmitWarning(w);
|
existing.push(listener);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return target;
|
// Check for listener leak
|
||||||
|
m = _getMaxListeners(target);
|
||||||
|
if (m > 0 && existing.length > m && !existing.warned) {
|
||||||
|
existing.warned = true;
|
||||||
|
// No error code for this since it is a Warning
|
||||||
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
|
var w = new Error(
|
||||||
|
'Possible EventEmitter memory leak detected. ' +
|
||||||
|
existing.length +
|
||||||
|
' ' +
|
||||||
|
String(type) +
|
||||||
|
' listeners ' +
|
||||||
|
'added. Use emitter.setMaxListeners() to ' +
|
||||||
|
'increase limit'
|
||||||
|
);
|
||||||
|
w.name = 'MaxListenersExceededWarning';
|
||||||
|
w.emitter = target;
|
||||||
|
w.type = type;
|
||||||
|
w.count = existing.length;
|
||||||
|
ProcessEmitWarning(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventEmitter.prototype.addListener = function addListener(type, listener) {
|
EventEmitter.prototype.addListener = function addListener(type, listener) {
|
||||||
return _addListener(this, type, listener, false);
|
return _addListener(this, type, listener, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
|
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
|
||||||
|
|
||||||
EventEmitter.prototype.prependListener =
|
EventEmitter.prototype.prependListener = function prependListener(
|
||||||
function prependListener(type, listener) {
|
type,
|
||||||
return _addListener(this, type, listener, true);
|
listener
|
||||||
};
|
) {
|
||||||
|
return _addListener(this, type, listener, true);
|
||||||
|
};
|
||||||
|
|
||||||
function onceWrapper() {
|
function onceWrapper() {
|
||||||
if (!this.fired) {
|
if (!this.fired) {
|
||||||
this.target.removeListener(this.type, this.wrapFn);
|
this.target.removeListener(this.type, this.wrapFn);
|
||||||
this.fired = true;
|
this.fired = true;
|
||||||
if (arguments.length === 0)
|
if (arguments.length === 0) return this.listener.call(this.target);
|
||||||
return this.listener.call(this.target);
|
return this.listener.apply(this.target, arguments);
|
||||||
return this.listener.apply(this.target, arguments);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _onceWrap(target, type, listener) {
|
function _onceWrap(target, type, listener) {
|
||||||
var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
|
var state = {
|
||||||
var wrapped = onceWrapper.bind(state);
|
fired: false,
|
||||||
wrapped.listener = listener;
|
wrapFn: undefined,
|
||||||
state.wrapFn = wrapped;
|
target: target,
|
||||||
return wrapped;
|
type: type,
|
||||||
|
listener: listener,
|
||||||
|
};
|
||||||
|
var wrapped = onceWrapper.bind(state);
|
||||||
|
wrapped.listener = listener;
|
||||||
|
state.wrapFn = wrapped;
|
||||||
|
return wrapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventEmitter.prototype.once = function once(type, listener) {
|
EventEmitter.prototype.once = function once(type, listener) {
|
||||||
checkListener(listener);
|
checkListener(listener);
|
||||||
this.on(type, _onceWrap(this, type, listener));
|
this.on(type, _onceWrap(this, type, listener));
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
EventEmitter.prototype.prependOnceListener =
|
EventEmitter.prototype.prependOnceListener = function prependOnceListener(
|
||||||
function prependOnceListener(type, listener) {
|
type,
|
||||||
checkListener(listener);
|
listener
|
||||||
this.prependListener(type, _onceWrap(this, type, listener));
|
) {
|
||||||
return this;
|
checkListener(listener);
|
||||||
};
|
this.prependListener(type, _onceWrap(this, type, listener));
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
// Emits a 'removeListener' event if and only if the listener was removed.
|
// Emits a 'removeListener' event if and only if the listener was removed.
|
||||||
EventEmitter.prototype.removeListener =
|
EventEmitter.prototype.removeListener = function removeListener(
|
||||||
function removeListener(type, listener) {
|
type,
|
||||||
var list, events, position, i, originalListener;
|
listener
|
||||||
|
) {
|
||||||
|
var list, events, position, i, originalListener;
|
||||||
|
|
||||||
checkListener(listener);
|
checkListener(listener);
|
||||||
|
|
||||||
events = this._events;
|
events = this._events;
|
||||||
if (events === undefined)
|
if (events === undefined) return this;
|
||||||
return this;
|
|
||||||
|
|
||||||
list = events[type];
|
list = events[type];
|
||||||
if (list === undefined)
|
if (list === undefined) return this;
|
||||||
return this;
|
|
||||||
|
|
||||||
if (list === listener || list.listener === listener) {
|
if (list === listener || list.listener === listener) {
|
||||||
if (--this._eventsCount === 0)
|
if (--this._eventsCount === 0) this._events = Object.create(null);
|
||||||
this._events = Object.create(null);
|
|
||||||
else {
|
else {
|
||||||
delete events[type];
|
delete events[type];
|
||||||
if (events.removeListener)
|
if (events.removeListener)
|
||||||
this.emit('removeListener', type, list.listener || listener);
|
this.emit('removeListener', type, list.listener || listener);
|
||||||
}
|
}
|
||||||
} else if (typeof list !== 'function') {
|
} else if (typeof list !== 'function') {
|
||||||
position = -1;
|
position = -1;
|
||||||
|
|
||||||
for (i = list.length - 1; i >= 0; i--) {
|
for (i = list.length - 1; i >= 0; i--) {
|
||||||
if (list[i] === listener || list[i].listener === listener) {
|
if (list[i] === listener || list[i].listener === listener) {
|
||||||
originalListener = list[i].listener;
|
originalListener = list[i].listener;
|
||||||
position = i;
|
position = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (position < 0)
|
if (position < 0) return this;
|
||||||
return this;
|
|
||||||
|
|
||||||
if (position === 0)
|
if (position === 0) list.shift();
|
||||||
list.shift();
|
|
||||||
else {
|
else {
|
||||||
spliceOne(list, position);
|
spliceOne(list, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list.length === 1)
|
if (list.length === 1) events[type] = list[0];
|
||||||
events[type] = list[0];
|
|
||||||
|
|
||||||
if (events.removeListener !== undefined)
|
if (events.removeListener !== undefined)
|
||||||
this.emit('removeListener', type, originalListener || listener);
|
this.emit('removeListener', type, originalListener || listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
||||||
|
|
||||||
EventEmitter.prototype.removeAllListeners =
|
EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) {
|
||||||
function removeAllListeners(type) {
|
var listeners, events, i;
|
||||||
var listeners, events, i;
|
|
||||||
|
|
||||||
events = this._events;
|
events = this._events;
|
||||||
if (events === undefined)
|
if (events === undefined) return this;
|
||||||
return this;
|
|
||||||
|
|
||||||
// not listening for removeListener, no need to emit
|
// not listening for removeListener, no need to emit
|
||||||
if (events.removeListener === undefined) {
|
if (events.removeListener === undefined) {
|
||||||
if (arguments.length === 0) {
|
if (arguments.length === 0) {
|
||||||
this._events = Object.create(null);
|
|
||||||
this._eventsCount = 0;
|
|
||||||
} else if (events[type] !== undefined) {
|
|
||||||
if (--this._eventsCount === 0)
|
|
||||||
this._events = Object.create(null);
|
this._events = Object.create(null);
|
||||||
else
|
this._eventsCount = 0;
|
||||||
delete events[type];
|
} else if (events[type] !== undefined) {
|
||||||
|
if (--this._eventsCount === 0) this._events = Object.create(null);
|
||||||
|
else delete events[type];
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// emit removeListener for all listeners on all events
|
// emit removeListener for all listeners on all events
|
||||||
if (arguments.length === 0) {
|
if (arguments.length === 0) {
|
||||||
var keys = Object.keys(events);
|
var keys = Object.keys(events);
|
||||||
var key;
|
var key;
|
||||||
for (i = 0; i < keys.length; ++i) {
|
for (i = 0; i < keys.length; ++i) {
|
||||||
key = keys[i];
|
key = keys[i];
|
||||||
if (key === 'removeListener') continue;
|
if (key === 'removeListener') continue;
|
||||||
this.removeAllListeners(key);
|
this.removeAllListeners(key);
|
||||||
}
|
}
|
||||||
this.removeAllListeners('removeListener');
|
this.removeAllListeners('removeListener');
|
||||||
this._events = Object.create(null);
|
this._events = Object.create(null);
|
||||||
this._eventsCount = 0;
|
this._eventsCount = 0;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
listeners = events[type];
|
listeners = events[type];
|
||||||
|
|
||||||
if (typeof listeners === 'function') {
|
if (typeof listeners === 'function') {
|
||||||
this.removeListener(type, listeners);
|
this.removeListener(type, listeners);
|
||||||
} else if (listeners !== undefined) {
|
} else if (listeners !== undefined) {
|
||||||
// LIFO order
|
// LIFO order
|
||||||
for (i = listeners.length - 1; i >= 0; i--) {
|
for (i = listeners.length - 1; i >= 0; i--) {
|
||||||
this.removeListener(type, listeners[i]);
|
this.removeListener(type, listeners[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
function _listeners(target, type, unwrap) {
|
function _listeners(target, type, unwrap) {
|
||||||
var events = target._events;
|
var events = target._events;
|
||||||
|
|
||||||
if (events === undefined)
|
if (events === undefined) return [];
|
||||||
return [];
|
|
||||||
|
|
||||||
var evlistener = events[type];
|
var evlistener = events[type];
|
||||||
if (evlistener === undefined)
|
if (evlistener === undefined) return [];
|
||||||
return [];
|
|
||||||
|
|
||||||
if (typeof evlistener === 'function')
|
if (typeof evlistener === 'function')
|
||||||
return unwrap ? [evlistener.listener || evlistener] : [evlistener];
|
return unwrap ? [evlistener.listener || evlistener] : [evlistener];
|
||||||
|
|
||||||
return unwrap ?
|
return unwrap
|
||||||
unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
|
? unwrapListeners(evlistener)
|
||||||
|
: arrayClone(evlistener, evlistener.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventEmitter.prototype.listeners = function listeners(type) {
|
EventEmitter.prototype.listeners = function listeners(type) {
|
||||||
return _listeners(this, type, true);
|
return _listeners(this, type, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
EventEmitter.prototype.rawListeners = function rawListeners(type) {
|
EventEmitter.prototype.rawListeners = function rawListeners(type) {
|
||||||
return _listeners(this, type, false);
|
return _listeners(this, type, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
EventEmitter.listenerCount = function(emitter, type) {
|
EventEmitter.listenerCount = function (emitter, type) {
|
||||||
if (typeof emitter.listenerCount === 'function') {
|
if (typeof emitter.listenerCount === 'function') {
|
||||||
return emitter.listenerCount(type);
|
return emitter.listenerCount(type);
|
||||||
} else {
|
} else {
|
||||||
return listenerCount.call(emitter, type);
|
return listenerCount.call(emitter, type);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
EventEmitter.prototype.listenerCount = listenerCount;
|
EventEmitter.prototype.listenerCount = listenerCount;
|
||||||
function listenerCount(type) {
|
function listenerCount(type) {
|
||||||
var events = this._events;
|
var events = this._events;
|
||||||
|
|
||||||
if (events !== undefined) {
|
if (events !== undefined) {
|
||||||
var evlistener = events[type];
|
var evlistener = events[type];
|
||||||
|
|
||||||
if (typeof evlistener === 'function') {
|
if (typeof evlistener === 'function') {
|
||||||
return 1;
|
return 1;
|
||||||
} else if (evlistener !== undefined) {
|
} else if (evlistener !== undefined) {
|
||||||
return evlistener.length;
|
return evlistener.length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventEmitter.prototype.eventNames = function eventNames() {
|
EventEmitter.prototype.eventNames = function eventNames() {
|
||||||
return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
|
return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
|
||||||
};
|
};
|
||||||
|
|
||||||
function arrayClone(arr, n) {
|
function arrayClone(arr, n) {
|
||||||
var copy = new Array(n);
|
var copy = new Array(n);
|
||||||
for (var i = 0; i < n; ++i)
|
for (var i = 0; i < n; ++i) copy[i] = arr[i];
|
||||||
copy[i] = arr[i];
|
return copy;
|
||||||
return copy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function spliceOne(list, index) {
|
function spliceOne(list, index) {
|
||||||
for (; index + 1 < list.length; index++)
|
for (; index + 1 < list.length; index++) list[index] = list[index + 1];
|
||||||
list[index] = list[index + 1];
|
list.pop();
|
||||||
list.pop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function unwrapListeners(arr) {
|
function unwrapListeners(arr) {
|
||||||
var ret = new Array(arr.length);
|
var ret = new Array(arr.length);
|
||||||
for (var i = 0; i < ret.length; ++i) {
|
for (var i = 0; i < ret.length; ++i) {
|
||||||
ret[i] = arr[i].listener || arr[i];
|
ret[i] = arr[i].listener || arr[i];
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
function once(emitter, name) {
|
function once(emitter, name) {
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
function errorListener(err) {
|
function errorListener(err) {
|
||||||
emitter.removeListener(name, resolver);
|
emitter.removeListener(name, resolver);
|
||||||
reject(err);
|
reject(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolver() {
|
function resolver() {
|
||||||
if (typeof emitter.removeListener === 'function') {
|
if (typeof emitter.removeListener === 'function') {
|
||||||
emitter.removeListener('error', errorListener);
|
emitter.removeListener('error', errorListener);
|
||||||
}
|
}
|
||||||
resolve([].slice.call(arguments));
|
resolve([].slice.call(arguments));
|
||||||
};
|
}
|
||||||
|
|
||||||
eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });
|
eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });
|
||||||
if (name !== 'error') {
|
if (name !== 'error') {
|
||||||
addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });
|
addErrorHandlerIfEventEmitter(emitter, errorListener, {
|
||||||
}
|
once: true,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addErrorHandlerIfEventEmitter(emitter, handler, flags) {
|
function addErrorHandlerIfEventEmitter(emitter, handler, flags) {
|
||||||
if (typeof emitter.on === 'function') {
|
if (typeof emitter.on === 'function') {
|
||||||
eventTargetAgnosticAddListener(emitter, 'error', handler, flags);
|
eventTargetAgnosticAddListener(emitter, 'error', handler, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
|
function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
|
||||||
if (typeof emitter.on === 'function') {
|
if (typeof emitter.on === 'function') {
|
||||||
if (flags.once) {
|
if (flags.once) {
|
||||||
emitter.once(name, listener);
|
emitter.once(name, listener);
|
||||||
|
} else {
|
||||||
|
emitter.on(name, listener);
|
||||||
|
}
|
||||||
|
} else if (typeof emitter.addEventListener === 'function') {
|
||||||
|
// EventTarget does not have `error` event semantics like Node
|
||||||
|
// EventEmitters, we do not listen for `error` events here.
|
||||||
|
emitter.addEventListener(name, function wrapListener(arg) {
|
||||||
|
// IE does not have builtin `{ once: true }` support so we
|
||||||
|
// have to do it manually.
|
||||||
|
if (flags.once) {
|
||||||
|
emitter.removeEventListener(name, wrapListener);
|
||||||
|
}
|
||||||
|
listener(arg);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
emitter.on(name, listener);
|
throw new TypeError(
|
||||||
|
'The "emitter" argument must be of type EventEmitter. Received type ' +
|
||||||
|
typeof emitter
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if (typeof emitter.addEventListener === 'function') {
|
|
||||||
// EventTarget does not have `error` event semantics like Node
|
|
||||||
// EventEmitters, we do not listen for `error` events here.
|
|
||||||
emitter.addEventListener(name, function wrapListener(arg) {
|
|
||||||
// IE does not have builtin `{ once: true }` support so we
|
|
||||||
// have to do it manually.
|
|
||||||
if (flags.once) {
|
|
||||||
emitter.removeEventListener(name, wrapListener);
|
|
||||||
}
|
|
||||||
listener(arg);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -7,32 +7,44 @@ class HTML extends EventEmitter {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.rewriteUrl = ctx.rewriteUrl;
|
this.rewriteUrl = ctx.rewriteUrl;
|
||||||
this.sourceUrl = ctx.sourceUrl;
|
this.sourceUrl = ctx.sourceUrl;
|
||||||
};
|
}
|
||||||
rewrite(str, options = {}) {
|
rewrite(str, options = {}) {
|
||||||
if (!str) return str;
|
if (!str) return str;
|
||||||
return this.recast(str, node => {
|
return this.recast(
|
||||||
if (node.tagName) this.emit('element', node, 'rewrite');
|
str,
|
||||||
if (node.attr) this.emit('attr', node, 'rewrite');
|
(node) => {
|
||||||
if (node.nodeName === '#text') this.emit('text', node, 'rewrite');
|
if (node.tagName) this.emit('element', node, 'rewrite');
|
||||||
}, options)
|
if (node.attr) this.emit('attr', node, 'rewrite');
|
||||||
};
|
if (node.nodeName === '#text')
|
||||||
|
this.emit('text', node, 'rewrite');
|
||||||
|
},
|
||||||
|
options
|
||||||
|
);
|
||||||
|
}
|
||||||
source(str, options = {}) {
|
source(str, options = {}) {
|
||||||
if (!str) return str;
|
if (!str) return str;
|
||||||
return this.recast(str, node => {
|
return this.recast(
|
||||||
if (node.tagName) this.emit('element', node, 'source');
|
str,
|
||||||
if (node.attr) this.emit('attr', node, 'source');
|
(node) => {
|
||||||
if (node.nodeName === '#text') this.emit('text', node, 'source');
|
if (node.tagName) this.emit('element', node, 'source');
|
||||||
}, options)
|
if (node.attr) this.emit('attr', node, 'source');
|
||||||
};
|
if (node.nodeName === '#text')
|
||||||
|
this.emit('text', node, 'source');
|
||||||
|
},
|
||||||
|
options
|
||||||
|
);
|
||||||
|
}
|
||||||
recast(str, fn, options = {}) {
|
recast(str, fn, options = {}) {
|
||||||
try {
|
try {
|
||||||
const ast = (options.document ? parse : parseFragment)(new String(str).toString());
|
const ast = (options.document ? parse : parseFragment)(
|
||||||
|
new String(str).toString()
|
||||||
|
);
|
||||||
this.iterate(ast, fn, options);
|
this.iterate(ast, fn, options);
|
||||||
return serialize(ast);
|
return serialize(ast);
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
return str;
|
return str;
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
iterate(ast, fn, fnOptions) {
|
iterate(ast, fn, fnOptions) {
|
||||||
if (!ast) return ast;
|
if (!ast) return ast;
|
||||||
|
|
||||||
|
@ -41,41 +53,55 @@ class HTML extends EventEmitter {
|
||||||
fn(element);
|
fn(element);
|
||||||
if (ast.attrs) {
|
if (ast.attrs) {
|
||||||
for (const attr of ast.attrs) {
|
for (const attr of ast.attrs) {
|
||||||
if (!attr.skip) fn(new AttributeEvent(element, attr, fnOptions));
|
if (!attr.skip)
|
||||||
};
|
fn(new AttributeEvent(element, attr, fnOptions));
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ast.childNodes) {
|
if (ast.childNodes) {
|
||||||
for (const child of ast.childNodes) {
|
for (const child of ast.childNodes) {
|
||||||
if (!child.skip) this.iterate(child, fn, fnOptions);
|
if (!child.skip) this.iterate(child, fn, fnOptions);
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
if (ast.nodeName === '#text') {
|
if (ast.nodeName === '#text') {
|
||||||
fn(new TextEvent(ast, new P5Element(ast.parentNode), false, fnOptions));
|
fn(
|
||||||
};
|
new TextEvent(
|
||||||
|
ast,
|
||||||
|
new P5Element(ast.parentNode),
|
||||||
|
false,
|
||||||
|
fnOptions
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return ast;
|
return ast;
|
||||||
};
|
}
|
||||||
wrapSrcset(str, meta = this.ctx.meta) {
|
wrapSrcset(str, meta = this.ctx.meta) {
|
||||||
return str.split(',').map(src => {
|
return str
|
||||||
const parts = src.trimStart().split(' ');
|
.split(',')
|
||||||
if (parts[0]) parts[0] = this.ctx.rewriteUrl(parts[0], meta);
|
.map((src) => {
|
||||||
return parts.join(' ');
|
const parts = src.trimStart().split(' ');
|
||||||
}).join(', ');
|
if (parts[0]) parts[0] = this.ctx.rewriteUrl(parts[0], meta);
|
||||||
};
|
return parts.join(' ');
|
||||||
|
})
|
||||||
|
.join(', ');
|
||||||
|
}
|
||||||
unwrapSrcset(str, meta = this.ctx.meta) {
|
unwrapSrcset(str, meta = this.ctx.meta) {
|
||||||
return str.split(',').map(src => {
|
return str
|
||||||
const parts = src.trimStart().split(' ');
|
.split(',')
|
||||||
if (parts[0]) parts[0] = this.ctx.sourceUrl(parts[0], meta);
|
.map((src) => {
|
||||||
return parts.join(' ');
|
const parts = src.trimStart().split(' ');
|
||||||
}).join(', ');
|
if (parts[0]) parts[0] = this.ctx.sourceUrl(parts[0], meta);
|
||||||
};
|
return parts.join(' ');
|
||||||
|
})
|
||||||
|
.join(', ');
|
||||||
|
}
|
||||||
static parse = parse;
|
static parse = parse;
|
||||||
static parseFragment = parseFragment;
|
static parseFragment = parseFragment;
|
||||||
static serialize = serialize;
|
static serialize = serialize;
|
||||||
};
|
}
|
||||||
|
|
||||||
class P5Element extends EventEmitter {
|
class P5Element extends EventEmitter {
|
||||||
constructor(node, stream = false, options = {}) {
|
constructor(node, stream = false, options = {}) {
|
||||||
|
@ -83,96 +109,104 @@ class P5Element extends EventEmitter {
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
this.node = node;
|
this.node = node;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
};
|
}
|
||||||
setAttribute(name, value) {
|
setAttribute(name, value) {
|
||||||
for (const attr of this.attrs) {
|
for (const attr of this.attrs) {
|
||||||
if (attr.name === name) {
|
if (attr.name === name) {
|
||||||
attr.value = value;
|
attr.value = value;
|
||||||
return true;
|
return true;
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
this.attrs.push(
|
|
||||||
{
|
|
||||||
name,
|
|
||||||
value,
|
|
||||||
}
|
}
|
||||||
);
|
}
|
||||||
};
|
|
||||||
|
this.attrs.push({
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
}
|
||||||
getAttribute(name) {
|
getAttribute(name) {
|
||||||
const attr = this.attrs.find(attr => attr.name === name) || {};
|
const attr = this.attrs.find((attr) => attr.name === name) || {};
|
||||||
return attr.value;
|
return attr.value;
|
||||||
};
|
}
|
||||||
hasAttribute(name) {
|
hasAttribute(name) {
|
||||||
return !!this.attrs.find(attr => attr.name === name);
|
return !!this.attrs.find((attr) => attr.name === name);
|
||||||
};
|
}
|
||||||
removeAttribute(name) {
|
removeAttribute(name) {
|
||||||
const i = this.attrs.findIndex(attr => attr.name === name);
|
const i = this.attrs.findIndex((attr) => attr.name === name);
|
||||||
if (typeof i !== 'undefined') this.attrs.splice(i, 1);
|
if (typeof i !== 'undefined') this.attrs.splice(i, 1);
|
||||||
};
|
}
|
||||||
get tagName() {
|
get tagName() {
|
||||||
return this.node.tagName;
|
return this.node.tagName;
|
||||||
};
|
}
|
||||||
set tagName(val) {
|
set tagName(val) {
|
||||||
this.node.tagName = val;
|
this.node.tagName = val;
|
||||||
};
|
}
|
||||||
get childNodes() {
|
get childNodes() {
|
||||||
return !this.stream ? this.node.childNodes : null;
|
return !this.stream ? this.node.childNodes : null;
|
||||||
};
|
}
|
||||||
get innerHTML() {
|
get innerHTML() {
|
||||||
return !this.stream ? serialize(
|
return !this.stream
|
||||||
{
|
? serialize({
|
||||||
nodeName: '#document-fragment',
|
nodeName: '#document-fragment',
|
||||||
childNodes: this.childNodes,
|
childNodes: this.childNodes,
|
||||||
}
|
})
|
||||||
) : null;
|
: null;
|
||||||
};
|
}
|
||||||
set innerHTML(val) {
|
set innerHTML(val) {
|
||||||
if (!this.stream) this.node.childNodes = parseFragment(val).childNodes;
|
if (!this.stream) this.node.childNodes = parseFragment(val).childNodes;
|
||||||
};
|
}
|
||||||
get outerHTML() {
|
get outerHTML() {
|
||||||
return !this.stream ? serialize(
|
return !this.stream
|
||||||
{
|
? serialize({
|
||||||
nodeName: '#document-fragment',
|
nodeName: '#document-fragment',
|
||||||
childNodes: [ this ],
|
childNodes: [this],
|
||||||
}
|
})
|
||||||
) : null;
|
: null;
|
||||||
};
|
}
|
||||||
set outerHTML(val) {
|
set outerHTML(val) {
|
||||||
if (!this.stream) this.parentNode.childNodes.splice(this.parentNode.childNodes.findIndex(node => node === this.node), 1, ...parseFragment(val).childNodes);
|
if (!this.stream)
|
||||||
};
|
this.parentNode.childNodes.splice(
|
||||||
|
this.parentNode.childNodes.findIndex(
|
||||||
|
(node) => node === this.node
|
||||||
|
),
|
||||||
|
1,
|
||||||
|
...parseFragment(val).childNodes
|
||||||
|
);
|
||||||
|
}
|
||||||
get textContent() {
|
get textContent() {
|
||||||
if (this.stream) return null;
|
if (this.stream) return null;
|
||||||
|
|
||||||
let str = '';
|
let str = '';
|
||||||
iterate(this.node, node => {
|
iterate(this.node, (node) => {
|
||||||
if (node.nodeName === '#text') str += node.value;
|
if (node.nodeName === '#text') str += node.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
};
|
}
|
||||||
set textContent(val) {
|
set textContent(val) {
|
||||||
if (!this.stream) this.node.childNodes = [
|
if (!this.stream)
|
||||||
{
|
this.node.childNodes = [
|
||||||
nodeName: '#text',
|
{
|
||||||
value: val,
|
nodeName: '#text',
|
||||||
parentNode: this.node
|
value: val,
|
||||||
}
|
parentNode: this.node,
|
||||||
];
|
},
|
||||||
};
|
];
|
||||||
|
}
|
||||||
get nodeName() {
|
get nodeName() {
|
||||||
return this.node.nodeName;
|
return this.node.nodeName;
|
||||||
}
|
}
|
||||||
get parentNode() {
|
get parentNode() {
|
||||||
return this.node.parentNode ? new P5Element(this.node.parentNode) : null;
|
return this.node.parentNode
|
||||||
};
|
? new P5Element(this.node.parentNode)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
get attrs() {
|
get attrs() {
|
||||||
return this.node.attrs;
|
return this.node.attrs;
|
||||||
}
|
}
|
||||||
get namespaceURI() {
|
get namespaceURI() {
|
||||||
return this.node.namespaceURI;
|
return this.node.namespaceURI;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
class AttributeEvent {
|
class AttributeEvent {
|
||||||
constructor(node, attr, options = {}) {
|
constructor(node, attr, options = {}) {
|
||||||
|
@ -180,9 +214,9 @@ class AttributeEvent {
|
||||||
this.attrs = node.attrs;
|
this.attrs = node.attrs;
|
||||||
this.node = node;
|
this.node = node;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
};
|
}
|
||||||
delete() {
|
delete() {
|
||||||
const i = this.attrs.findIndex(attr => attr === this.attr);
|
const i = this.attrs.findIndex((attr) => attr === this.attr);
|
||||||
|
|
||||||
this.attrs.splice(i, 1);
|
this.attrs.splice(i, 1);
|
||||||
|
|
||||||
|
@ -191,25 +225,25 @@ class AttributeEvent {
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
get name() {
|
get name() {
|
||||||
return this.attr.name;
|
return this.attr.name;
|
||||||
};
|
}
|
||||||
|
|
||||||
set name(val) {
|
set name(val) {
|
||||||
this.attr.name = val;
|
this.attr.name = val;
|
||||||
};
|
}
|
||||||
get value() {
|
get value() {
|
||||||
return this.attr.value;
|
return this.attr.value;
|
||||||
};
|
}
|
||||||
|
|
||||||
set value(val) {
|
set value(val) {
|
||||||
this.attr.value = val;
|
this.attr.value = val;
|
||||||
};
|
}
|
||||||
get deleted() {
|
get deleted() {
|
||||||
return false;
|
return false;
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
class TextEvent {
|
class TextEvent {
|
||||||
constructor(node, element, stream = false, options = {}) {
|
constructor(node, element, stream = false, options = {}) {
|
||||||
|
@ -217,21 +251,20 @@ class TextEvent {
|
||||||
this.node = node;
|
this.node = node;
|
||||||
this.element = element;
|
this.element = element;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
};
|
}
|
||||||
get nodeName() {
|
get nodeName() {
|
||||||
return this.node.nodeName;
|
return this.node.nodeName;
|
||||||
}
|
}
|
||||||
get parentNode() {
|
get parentNode() {
|
||||||
return this.element;
|
return this.element;
|
||||||
};
|
}
|
||||||
get value() {
|
get value() {
|
||||||
return this.stream ? this.node.text : this.node.value;
|
return this.stream ? this.node.text : this.node.value;
|
||||||
};
|
}
|
||||||
set value(val) {
|
set value(val) {
|
||||||
|
|
||||||
if (this.stream) this.node.text = val;
|
if (this.stream) this.node.text = val;
|
||||||
else this.node.value = val;
|
else this.node.value = val;
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default HTML;
|
export default HTML;
|
|
@ -4,25 +4,48 @@ import JS from './js.js';
|
||||||
import setCookie from 'set-cookie-parser';
|
import setCookie from 'set-cookie-parser';
|
||||||
import { xor, base64, plain } from './codecs.js';
|
import { xor, base64, plain } from './codecs.js';
|
||||||
import mimeTypes from './mime.js';
|
import mimeTypes from './mime.js';
|
||||||
import { validateCookie, db, getCookies, setCookies, serialize } from './cookie.js';
|
import {
|
||||||
import { attributes, isUrl, isForbidden, isHtml, isSrcset, isStyle, text, injectHead, createInjection } from './rewrite.html.js';
|
validateCookie,
|
||||||
|
db,
|
||||||
|
getCookies,
|
||||||
|
setCookies,
|
||||||
|
serialize,
|
||||||
|
} from './cookie.js';
|
||||||
|
import {
|
||||||
|
attributes,
|
||||||
|
isUrl,
|
||||||
|
isForbidden,
|
||||||
|
isHtml,
|
||||||
|
isSrcset,
|
||||||
|
isStyle,
|
||||||
|
text,
|
||||||
|
injectHead,
|
||||||
|
createInjection,
|
||||||
|
} from './rewrite.html.js';
|
||||||
import { importStyle, url } from './rewrite.css.js';
|
import { importStyle, url } from './rewrite.css.js';
|
||||||
//import { call, destructureDeclaration, dynamicImport, getProperty, importDeclaration, setProperty, sourceMethods, wrapEval, wrapIdentifier } from './rewrite.script.js';
|
//import { call, destructureDeclaration, dynamicImport, getProperty, importDeclaration, setProperty, sourceMethods, wrapEval, wrapIdentifier } from './rewrite.script.js';
|
||||||
import { dynamicImport, identifier, importDeclaration, property, unwrap, wrapEval } from './rewrite.script.js';
|
import {
|
||||||
|
dynamicImport,
|
||||||
|
identifier,
|
||||||
|
importDeclaration,
|
||||||
|
property,
|
||||||
|
unwrap,
|
||||||
|
wrapEval,
|
||||||
|
} from './rewrite.script.js';
|
||||||
import { openDB } from 'idb';
|
import { openDB } from 'idb';
|
||||||
import parsel from './parsel.js';
|
import parsel from './parsel.js';
|
||||||
import UVClient from '../client/index.js';
|
import UVClient from '../client/index.js';
|
||||||
import Bowser from 'bowser';
|
import Bowser from 'bowser';
|
||||||
|
|
||||||
|
const valid_chars =
|
||||||
const valid_chars = "!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~";
|
"!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~";
|
||||||
const reserved_chars = "%";
|
const reserved_chars = '%';
|
||||||
|
|
||||||
class Ultraviolet {
|
class Ultraviolet {
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
this.prefix = options.prefix || '/service/';
|
this.prefix = options.prefix || '/service/';
|
||||||
//this.urlRegex = /^(#|about:|data:|mailto:|javascript:)/;
|
//this.urlRegex = /^(#|about:|data:|mailto:|javascript:)/;
|
||||||
this.urlRegex = /^(#|about:|data:|mailto:)/
|
this.urlRegex = /^(#|about:|data:|mailto:)/;
|
||||||
this.rewriteUrl = options.rewriteUrl || this.rewriteUrl;
|
this.rewriteUrl = options.rewriteUrl || this.rewriteUrl;
|
||||||
this.sourceUrl = options.sourceUrl || this.sourceUrl;
|
this.sourceUrl = options.sourceUrl || this.sourceUrl;
|
||||||
this.encodeUrl = options.encodeUrl || this.encodeUrl;
|
this.encodeUrl = options.encodeUrl || this.encodeUrl;
|
||||||
|
@ -42,7 +65,10 @@ class Ultraviolet {
|
||||||
this.parsel = parsel;
|
this.parsel = parsel;
|
||||||
this.openDB = this.constructor.openDB;
|
this.openDB = this.constructor.openDB;
|
||||||
this.Bowser = this.constructor.Bowser;
|
this.Bowser = this.constructor.Bowser;
|
||||||
this.client = typeof self !== 'undefined' ? new UVClient((options.window || self)) : null;
|
this.client =
|
||||||
|
typeof self !== 'undefined'
|
||||||
|
? new UVClient(options.window || self)
|
||||||
|
: null;
|
||||||
this.master = '__uv';
|
this.master = '__uv';
|
||||||
this.dataPrefix = '__uv$';
|
this.dataPrefix = '__uv$';
|
||||||
this.attributePrefix = '__uv';
|
this.attributePrefix = '__uv';
|
||||||
|
@ -65,71 +91,82 @@ class Ultraviolet {
|
||||||
serialize,
|
serialize,
|
||||||
setCookie,
|
setCookie,
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
rewriteUrl(str, meta = this.meta) {
|
rewriteUrl(str, meta = this.meta) {
|
||||||
str = new String(str).trim();
|
str = new String(str).trim();
|
||||||
if (!str || this.urlRegex.test(str)) return str;
|
if (!str || this.urlRegex.test(str)) return str;
|
||||||
|
|
||||||
if (str.startsWith('javascript:')) {
|
if (str.startsWith('javascript:')) {
|
||||||
return 'javascript:' + this.js.rewrite(str.slice('javascript:'.length));
|
return (
|
||||||
};
|
'javascript:' + this.js.rewrite(str.slice('javascript:'.length))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return meta.origin + this.prefix + this.encodeUrl(new URL(str, meta.base).href);
|
return (
|
||||||
} catch(e) {
|
meta.origin +
|
||||||
|
this.prefix +
|
||||||
|
this.encodeUrl(new URL(str, meta.base).href)
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
return meta.origin + this.prefix + this.encodeUrl(str);
|
return meta.origin + this.prefix + this.encodeUrl(str);
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
sourceUrl(str, meta = this.meta) {
|
sourceUrl(str, meta = this.meta) {
|
||||||
if (!str || this.urlRegex.test(str)) return str;
|
if (!str || this.urlRegex.test(str)) return str;
|
||||||
try {
|
try {
|
||||||
return new URL(
|
return new URL(
|
||||||
this.decodeUrl(str.slice(this.prefix.length + meta.origin.length)),
|
this.decodeUrl(
|
||||||
|
str.slice(this.prefix.length + meta.origin.length)
|
||||||
|
),
|
||||||
meta.base
|
meta.base
|
||||||
).href;
|
).href;
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
return this.decodeUrl(str.slice(this.prefix.length + meta.origin.length));
|
return this.decodeUrl(
|
||||||
};
|
str.slice(this.prefix.length + meta.origin.length)
|
||||||
};
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
encodeUrl(str) {
|
encodeUrl(str) {
|
||||||
return encodeURIComponent(str);
|
return encodeURIComponent(str);
|
||||||
};
|
}
|
||||||
decodeUrl(str) {
|
decodeUrl(str) {
|
||||||
return decodeURIComponent(str);
|
return decodeURIComponent(str);
|
||||||
};
|
}
|
||||||
encodeProtocol(protocol) {
|
encodeProtocol(protocol) {
|
||||||
protocol = protocol.toString();
|
protocol = protocol.toString();
|
||||||
|
|
||||||
let result = '';
|
let result = '';
|
||||||
|
|
||||||
for(let i = 0; i < protocol.length; i++){
|
for (let i = 0; i < protocol.length; i++) {
|
||||||
const char = protocol[i];
|
const char = protocol[i];
|
||||||
|
|
||||||
if(valid_chars.includes(char) && !reserved_chars.includes(char)){
|
if (valid_chars.includes(char) && !reserved_chars.includes(char)) {
|
||||||
result += char;
|
result += char;
|
||||||
}else{
|
} else {
|
||||||
const code = char.charCodeAt();
|
const code = char.charCodeAt();
|
||||||
result += '%' + code.toString(16).padStart(2, 0);
|
result += '%' + code.toString(16).padStart(2, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
}
|
||||||
decodeProtocol(protocol) {
|
decodeProtocol(protocol) {
|
||||||
if(typeof protocol != 'string')throw new TypeError('protocol must be a string');
|
if (typeof protocol != 'string')
|
||||||
|
throw new TypeError('protocol must be a string');
|
||||||
|
|
||||||
let result = '';
|
let result = '';
|
||||||
|
|
||||||
for(let i = 0; i < protocol.length; i++){
|
for (let i = 0; i < protocol.length; i++) {
|
||||||
const char = protocol[i];
|
const char = protocol[i];
|
||||||
|
|
||||||
if(char == '%'){
|
if (char == '%') {
|
||||||
const code = parseInt(protocol.slice(i + 1, i + 3), 16);
|
const code = parseInt(protocol.slice(i + 1, i + 3), 16);
|
||||||
const decoded = String.fromCharCode(code);
|
const decoded = String.fromCharCode(code);
|
||||||
|
|
||||||
result += decoded;
|
result += decoded;
|
||||||
i += 2;
|
i += 2;
|
||||||
}else{
|
} else {
|
||||||
result += char;
|
result += char;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,31 +188,31 @@ class Ultraviolet {
|
||||||
wrapEval(this);
|
wrapEval(this);
|
||||||
identifier(this);
|
identifier(this);
|
||||||
unwrap(this);
|
unwrap(this);
|
||||||
};
|
}
|
||||||
get rewriteHtml() {
|
get rewriteHtml() {
|
||||||
return this.html.rewrite.bind(this.html);
|
return this.html.rewrite.bind(this.html);
|
||||||
};
|
}
|
||||||
get sourceHtml() {
|
get sourceHtml() {
|
||||||
return this.html.source.bind(this.html);
|
return this.html.source.bind(this.html);
|
||||||
};
|
}
|
||||||
get rewriteCSS() {
|
get rewriteCSS() {
|
||||||
return this.css.rewrite.bind(this.css);
|
return this.css.rewrite.bind(this.css);
|
||||||
};
|
}
|
||||||
get sourceCSS() {
|
get sourceCSS() {
|
||||||
return this.css.source.bind(this.css);
|
return this.css.source.bind(this.css);
|
||||||
};
|
}
|
||||||
get rewriteJS() {
|
get rewriteJS() {
|
||||||
return this.js.rewrite.bind(this.js);
|
return this.js.rewrite.bind(this.js);
|
||||||
};
|
}
|
||||||
get sourceJS() {
|
get sourceJS() {
|
||||||
return this.js.source.bind(this.js);
|
return this.js.source.bind(this.js);
|
||||||
};
|
}
|
||||||
static codec = { xor, base64, plain };
|
static codec = { xor, base64, plain };
|
||||||
static mime = mimeTypes;
|
static mime = mimeTypes;
|
||||||
static setCookie = setCookie;
|
static setCookie = setCookie;
|
||||||
static openDB = openDB;
|
static openDB = openDB;
|
||||||
static Bowser = Bowser;
|
static Bowser = Bowser;
|
||||||
};
|
}
|
||||||
|
|
||||||
export default Ultraviolet;
|
export default Ultraviolet;
|
||||||
if (typeof self === 'object') self.Ultraviolet = Ultraviolet;
|
if (typeof self === 'object') self.Ultraviolet = Ultraviolet;
|
|
@ -27,13 +27,13 @@ class JS extends EventEmitter {
|
||||||
};
|
};
|
||||||
this.parse = parseScript /*parse*/;
|
this.parse = parseScript /*parse*/;
|
||||||
this.generate = generate;
|
this.generate = generate;
|
||||||
};
|
}
|
||||||
rewrite(str, data = {}) {
|
rewrite(str, data = {}) {
|
||||||
return this.recast(str, data, 'rewrite');
|
return this.recast(str, data, 'rewrite');
|
||||||
};
|
}
|
||||||
source(str, data = {}) {
|
source(str, data = {}) {
|
||||||
return this.recast(str, data, 'source');
|
return this.recast(str, data, 'source');
|
||||||
};
|
}
|
||||||
recast(str, data = {}, type = '') {
|
recast(str, data = {}, type = '') {
|
||||||
try {
|
try {
|
||||||
const output = [];
|
const output = [];
|
||||||
|
@ -56,19 +56,26 @@ class JS extends EventEmitter {
|
||||||
this.emit(node.type, node, meta, type);
|
this.emit(node.type, node, meta, type);
|
||||||
});
|
});
|
||||||
|
|
||||||
meta.changes.sort((a, b) => (a.start - b.start) || (a.end - b.end));
|
meta.changes.sort((a, b) => a.start - b.start || a.end - b.end);
|
||||||
|
|
||||||
for (const change of meta.changes) {
|
for (const change of meta.changes) {
|
||||||
if ('start' in change && typeof change.start === 'number') output.push(str.slice(slice, change.start));
|
if ('start' in change && typeof change.start === 'number')
|
||||||
if (change.node) output.push(typeof change.node === 'string' ? change.node : generate(change.node, this.generationOptions));
|
output.push(str.slice(slice, change.start));
|
||||||
if ('end' in change && typeof change.end === 'number') slice = change.end;
|
if (change.node)
|
||||||
};
|
output.push(
|
||||||
|
typeof change.node === 'string'
|
||||||
|
? change.node
|
||||||
|
: generate(change.node, this.generationOptions)
|
||||||
|
);
|
||||||
|
if ('end' in change && typeof change.end === 'number')
|
||||||
|
slice = change.end;
|
||||||
|
}
|
||||||
output.push(str.slice(slice));
|
output.push(str.slice(slice));
|
||||||
return output.join('');
|
return output.join('');
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
return str;
|
return str;
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
iterate(ast, handler) {
|
iterate(ast, handler) {
|
||||||
if (typeof ast != 'object' || !handler) return;
|
if (typeof ast != 'object' || !handler) return;
|
||||||
walk(ast, null, handler);
|
walk(ast, null, handler);
|
||||||
|
@ -78,16 +85,16 @@ class JS extends EventEmitter {
|
||||||
for (const child in node) {
|
for (const child in node) {
|
||||||
if (child === 'parent') continue;
|
if (child === 'parent') continue;
|
||||||
if (Array.isArray(node[child])) {
|
if (Array.isArray(node[child])) {
|
||||||
node[child].forEach(entry => {
|
node[child].forEach((entry) => {
|
||||||
if (entry) walk(entry, node, handler)
|
if (entry) walk(entry, node, handler);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (node[child]) walk(node[child], node, handler);
|
if (node[child]) walk(node[child], node, handler);
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
if (typeof node.iterateEnd === 'function') node.iterateEnd();
|
if (typeof node.iterateEnd === 'function') node.iterateEnd();
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default JS;
|
export default JS;
|
|
@ -5,18 +5,18 @@
|
||||||
* MIT Licensed
|
* MIT Licensed
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var $exports = {}
|
var $exports = {};
|
||||||
|
|
||||||
import db from "mime-db";
|
import db from 'mime-db';
|
||||||
|
|
||||||
var extname = function(path = '') {
|
var extname = function (path = '') {
|
||||||
if (!path.includes('.')) return '';
|
if (!path.includes('.')) return '';
|
||||||
const map = path.split('.');
|
const map = path.split('.');
|
||||||
|
|
||||||
|
@ -28,24 +28,24 @@ var extname = function(path = '') {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/
|
var EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/;
|
||||||
var TEXT_TYPE_REGEXP = /^text\//i
|
var TEXT_TYPE_REGEXP = /^text\//i;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module exports.
|
* Module exports.
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$exports.charset = charset
|
$exports.charset = charset;
|
||||||
$exports.charsets = { lookup: charset }
|
$exports.charsets = { lookup: charset };
|
||||||
$exports.contentType = contentType
|
$exports.contentType = contentType;
|
||||||
$exports.extension = extension
|
$exports.extension = extension;
|
||||||
$exports.extensions = Object.create(null)
|
$exports.extensions = Object.create(null);
|
||||||
$exports.lookup = lookup
|
$exports.lookup = lookup;
|
||||||
$exports.types = Object.create(null)
|
$exports.types = Object.create(null);
|
||||||
|
|
||||||
// Populate the extensions/types maps
|
// Populate the extensions/types maps
|
||||||
populateMaps($exports.extensions, $exports.types)
|
populateMaps($exports.extensions, $exports.types);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the default charset for a MIME type.
|
* Get the default charset for a MIME type.
|
||||||
|
@ -54,25 +54,25 @@ populateMaps($exports.extensions, $exports.types)
|
||||||
* @return {boolean|string}
|
* @return {boolean|string}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function charset (type) {
|
function charset(type) {
|
||||||
if (!type || typeof type !== 'string') {
|
if (!type || typeof type !== 'string') {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use media-typer
|
// TODO: use media-typer
|
||||||
var match = EXTRACT_TYPE_REGEXP.exec(type)
|
var match = EXTRACT_TYPE_REGEXP.exec(type);
|
||||||
var mime = match && db[match[1].toLowerCase()]
|
var mime = match && db[match[1].toLowerCase()];
|
||||||
|
|
||||||
if (mime && mime.charset) {
|
if (mime && mime.charset) {
|
||||||
return mime.charset
|
return mime.charset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// default text/* to utf-8
|
// default text/* to utf-8
|
||||||
if (match && TEXT_TYPE_REGEXP.test(match[1])) {
|
if (match && TEXT_TYPE_REGEXP.test(match[1])) {
|
||||||
return 'UTF-8'
|
return 'UTF-8';
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -82,27 +82,25 @@ function charset (type) {
|
||||||
* @return {boolean|string}
|
* @return {boolean|string}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function contentType (str) {
|
function contentType(str) {
|
||||||
// TODO: should this even be in this module?
|
// TODO: should this even be in this module?
|
||||||
if (!str || typeof str !== 'string') {
|
if (!str || typeof str !== 'string') {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var mime = str.indexOf('/') === -1
|
var mime = str.indexOf('/') === -1 ? $exports.lookup(str) : str;
|
||||||
? $exports.lookup(str)
|
|
||||||
: str
|
|
||||||
|
|
||||||
if (!mime) {
|
if (!mime) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use content-type or other module
|
// TODO: use content-type or other module
|
||||||
if (mime.indexOf('charset') === -1) {
|
if (mime.indexOf('charset') === -1) {
|
||||||
var charset = $exports.charset(mime)
|
var charset = $exports.charset(mime);
|
||||||
if (charset) mime += '; charset=' + charset.toLowerCase()
|
if (charset) mime += '; charset=' + charset.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
return mime
|
return mime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -112,22 +110,22 @@ function contentType (str) {
|
||||||
* @return {boolean|string}
|
* @return {boolean|string}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function extension (type) {
|
function extension(type) {
|
||||||
if (!type || typeof type !== 'string') {
|
if (!type || typeof type !== 'string') {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use media-typer
|
// TODO: use media-typer
|
||||||
var match = EXTRACT_TYPE_REGEXP.exec(type)
|
var match = EXTRACT_TYPE_REGEXP.exec(type);
|
||||||
|
|
||||||
// get extensions
|
// get extensions
|
||||||
var exts = match && $exports.extensions[match[1].toLowerCase()]
|
var exts = match && $exports.extensions[match[1].toLowerCase()];
|
||||||
|
|
||||||
if (!exts || !exts.length) {
|
if (!exts || !exts.length) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return exts[0]
|
return exts[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -137,21 +135,21 @@ function extension (type) {
|
||||||
* @return {boolean|string}
|
* @return {boolean|string}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function lookup (path) {
|
function lookup(path) {
|
||||||
if (!path || typeof path !== 'string') {
|
if (!path || typeof path !== 'string') {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the extension ("ext" or ".ext" or full path)
|
// get the extension ("ext" or ".ext" or full path)
|
||||||
var extension = extname('x.' + path)
|
var extension = extname('x.' + path)
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.substr(1)
|
.substr(1);
|
||||||
|
|
||||||
if (!extension) {
|
if (!extension) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $exports.types[extension] || false
|
return $exports.types[extension] || false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -159,40 +157,44 @@ function lookup (path) {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function populateMaps (extensions, types) {
|
function populateMaps(extensions, types) {
|
||||||
// source preference (least -> most)
|
// source preference (least -> most)
|
||||||
var preference = ['nginx', 'apache', undefined, 'iana']
|
var preference = ['nginx', 'apache', undefined, 'iana'];
|
||||||
|
|
||||||
Object.keys(db).forEach(function forEachMimeType (type) {
|
Object.keys(db).forEach(function forEachMimeType(type) {
|
||||||
var mime = db[type]
|
var mime = db[type];
|
||||||
var exts = mime.extensions
|
var exts = mime.extensions;
|
||||||
|
|
||||||
if (!exts || !exts.length) {
|
if (!exts || !exts.length) {
|
||||||
return
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// mime -> extensions
|
|
||||||
extensions[type] = exts
|
|
||||||
|
|
||||||
// extension -> mime
|
|
||||||
for (var i = 0; i < exts.length; i++) {
|
|
||||||
var extension = exts[i]
|
|
||||||
|
|
||||||
if (types[extension]) {
|
|
||||||
var from = preference.indexOf(db[types[extension]].source)
|
|
||||||
var to = preference.indexOf(mime.source)
|
|
||||||
|
|
||||||
if (types[extension] !== 'application/octet-stream' &&
|
|
||||||
(from > to || (from === to && types[extension].substr(0, 12) === 'application/'))) {
|
|
||||||
// skip the remapping
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// set the extension -> mime
|
// mime -> extensions
|
||||||
types[extension] = type
|
extensions[type] = exts;
|
||||||
}
|
|
||||||
})
|
// extension -> mime
|
||||||
|
for (var i = 0; i < exts.length; i++) {
|
||||||
|
var extension = exts[i];
|
||||||
|
|
||||||
|
if (types[extension]) {
|
||||||
|
var from = preference.indexOf(db[types[extension]].source);
|
||||||
|
var to = preference.indexOf(mime.source);
|
||||||
|
|
||||||
|
if (
|
||||||
|
types[extension] !== 'application/octet-stream' &&
|
||||||
|
(from > to ||
|
||||||
|
(from === to &&
|
||||||
|
types[extension].substr(0, 12) === 'application/'))
|
||||||
|
) {
|
||||||
|
// skip the remapping
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the extension -> mime
|
||||||
|
types[extension] = type;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default $exports;
|
export default $exports;
|
|
@ -1,382 +1,435 @@
|
||||||
export default (function (exports) {
|
export default (function (exports) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const TOKENS = {
|
const TOKENS = {
|
||||||
attribute: /\[\s*(?:(?<namespace>\*|[-\w]*)\|)?(?<name>[-\w\u{0080}-\u{FFFF}]+)\s*(?:(?<operator>\W?=)\s*(?<value>.+?)\s*(?<caseSensitive>[iIsS])?\s*)?\]/gu,
|
attribute:
|
||||||
id: /#(?<name>(?:[-\w\u{0080}-\u{FFFF}]|\\.)+)/gu,
|
/\[\s*(?:(?<namespace>\*|[-\w]*)\|)?(?<name>[-\w\u{0080}-\u{FFFF}]+)\s*(?:(?<operator>\W?=)\s*(?<value>.+?)\s*(?<caseSensitive>[iIsS])?\s*)?\]/gu,
|
||||||
class: /\.(?<name>(?:[-\w\u{0080}-\u{FFFF}]|\\.)+)/gu,
|
id: /#(?<name>(?:[-\w\u{0080}-\u{FFFF}]|\\.)+)/gu,
|
||||||
comma: /\s*,\s*/g, // must be before combinator
|
class: /\.(?<name>(?:[-\w\u{0080}-\u{FFFF}]|\\.)+)/gu,
|
||||||
combinator: /\s*[\s>+~]\s*/g, // this must be after attribute
|
comma: /\s*,\s*/g, // must be before combinator
|
||||||
"pseudo-element": /::(?<name>[-\w\u{0080}-\u{FFFF}]+)(?:\((?<argument>¶+)\))?/gu, // this must be before pseudo-class
|
combinator: /\s*[\s>+~]\s*/g, // this must be after attribute
|
||||||
"pseudo-class": /:(?<name>[-\w\u{0080}-\u{FFFF}]+)(?:\((?<argument>¶+)\))?/gu,
|
'pseudo-element':
|
||||||
type: /(?:(?<namespace>\*|[-\w]*)\|)?(?<name>[-\w\u{0080}-\u{FFFF}]+)|\*/gu // this must be last
|
/::(?<name>[-\w\u{0080}-\u{FFFF}]+)(?:\((?<argument>¶+)\))?/gu, // this must be before pseudo-class
|
||||||
};
|
'pseudo-class':
|
||||||
|
/:(?<name>[-\w\u{0080}-\u{FFFF}]+)(?:\((?<argument>¶+)\))?/gu,
|
||||||
const TOKENS_WITH_PARENS = new Set(["pseudo-class", "pseudo-element"]);
|
type: /(?:(?<namespace>\*|[-\w]*)\|)?(?<name>[-\w\u{0080}-\u{FFFF}]+)|\*/gu, // this must be last
|
||||||
const TOKENS_WITH_STRINGS = new Set([...TOKENS_WITH_PARENS, "attribute"]);
|
};
|
||||||
const TRIM_TOKENS = new Set(["combinator", "comma"]);
|
|
||||||
const RECURSIVE_PSEUDO_CLASSES = new Set(["not", "is", "where", "has", "matches", "-moz-any", "-webkit-any", "nth-child", "nth-last-child"]);
|
const TOKENS_WITH_PARENS = new Set(['pseudo-class', 'pseudo-element']);
|
||||||
|
const TOKENS_WITH_STRINGS = new Set([...TOKENS_WITH_PARENS, 'attribute']);
|
||||||
const RECURSIVE_PSEUDO_CLASSES_ARGS = {
|
const TRIM_TOKENS = new Set(['combinator', 'comma']);
|
||||||
"nth-child": /(?<index>[\dn+-]+)\s+of\s+(?<subtree>.+)/
|
const RECURSIVE_PSEUDO_CLASSES = new Set([
|
||||||
};
|
'not',
|
||||||
|
'is',
|
||||||
RECURSIVE_PSEUDO_CLASSES["nth-last-child"] = RECURSIVE_PSEUDO_CLASSES_ARGS["nth-child"];
|
'where',
|
||||||
|
'has',
|
||||||
const TOKENS_FOR_RESTORE = Object.assign({}, TOKENS);
|
'matches',
|
||||||
TOKENS_FOR_RESTORE["pseudo-element"] = RegExp(TOKENS["pseudo-element"].source.replace("(?<argument>¶+)", "(?<argument>.+?)"), "gu");
|
'-moz-any',
|
||||||
TOKENS_FOR_RESTORE["pseudo-class"] = RegExp(TOKENS["pseudo-class"].source.replace("(?<argument>¶+)", "(?<argument>.+)"), "gu");
|
'-webkit-any',
|
||||||
|
'nth-child',
|
||||||
function gobbleParens(text, i) {
|
'nth-last-child',
|
||||||
let str = "", stack = [];
|
]);
|
||||||
|
|
||||||
for (; i < text.length; i++) {
|
const RECURSIVE_PSEUDO_CLASSES_ARGS = {
|
||||||
let char = text[i];
|
'nth-child': /(?<index>[\dn+-]+)\s+of\s+(?<subtree>.+)/,
|
||||||
|
};
|
||||||
if (char === "(") {
|
|
||||||
stack.push(char);
|
RECURSIVE_PSEUDO_CLASSES['nth-last-child'] =
|
||||||
}
|
RECURSIVE_PSEUDO_CLASSES_ARGS['nth-child'];
|
||||||
else if (char === ")") {
|
|
||||||
if (stack.length > 0) {
|
const TOKENS_FOR_RESTORE = Object.assign({}, TOKENS);
|
||||||
stack.pop();
|
TOKENS_FOR_RESTORE['pseudo-element'] = RegExp(
|
||||||
}
|
TOKENS['pseudo-element'].source.replace(
|
||||||
else {
|
'(?<argument>¶+)',
|
||||||
throw new Error("Closing paren without opening paren at " + i);
|
'(?<argument>.+?)'
|
||||||
}
|
),
|
||||||
}
|
'gu'
|
||||||
|
);
|
||||||
str += char;
|
TOKENS_FOR_RESTORE['pseudo-class'] = RegExp(
|
||||||
|
TOKENS['pseudo-class'].source.replace(
|
||||||
if (stack.length === 0) {
|
'(?<argument>¶+)',
|
||||||
return str;
|
'(?<argument>.+)'
|
||||||
}
|
),
|
||||||
}
|
'gu'
|
||||||
|
);
|
||||||
throw new Error("Opening paren without closing paren");
|
|
||||||
}
|
function gobbleParens(text, i) {
|
||||||
|
let str = '',
|
||||||
function tokenizeBy (text, grammar) {
|
stack = [];
|
||||||
if (!text) {
|
|
||||||
return [];
|
for (; i < text.length; i++) {
|
||||||
}
|
let char = text[i];
|
||||||
|
|
||||||
var strarr = [text];
|
if (char === '(') {
|
||||||
|
stack.push(char);
|
||||||
for (var token in grammar) {
|
} else if (char === ')') {
|
||||||
let pattern = grammar[token];
|
if (stack.length > 0) {
|
||||||
|
stack.pop();
|
||||||
for (var i=0; i < strarr.length; i++) { // Don’t cache length as it changes during the loop
|
} else {
|
||||||
var str = strarr[i];
|
throw new Error(
|
||||||
|
'Closing paren without opening paren at ' + i
|
||||||
if (typeof str === "string") {
|
);
|
||||||
pattern.lastIndex = 0;
|
}
|
||||||
|
}
|
||||||
var match = pattern.exec(str);
|
|
||||||
|
str += char;
|
||||||
if (match) {
|
|
||||||
let from = match.index - 1;
|
if (stack.length === 0) {
|
||||||
let args = [];
|
return str;
|
||||||
let content = match[0];
|
}
|
||||||
|
}
|
||||||
let before = str.slice(0, from + 1);
|
|
||||||
if (before) {
|
throw new Error('Opening paren without closing paren');
|
||||||
args.push(before);
|
}
|
||||||
}
|
|
||||||
|
function tokenizeBy(text, grammar) {
|
||||||
args.push({
|
if (!text) {
|
||||||
type: token,
|
return [];
|
||||||
content,
|
}
|
||||||
...match.groups
|
|
||||||
});
|
var strarr = [text];
|
||||||
|
|
||||||
let after = str.slice(from + content.length + 1);
|
for (var token in grammar) {
|
||||||
if (after) {
|
let pattern = grammar[token];
|
||||||
args.push(after);
|
|
||||||
}
|
for (var i = 0; i < strarr.length; i++) {
|
||||||
|
// Don’t cache length as it changes during the loop
|
||||||
strarr.splice(i, 1, ...args);
|
var str = strarr[i];
|
||||||
}
|
|
||||||
|
if (typeof str === 'string') {
|
||||||
}
|
pattern.lastIndex = 0;
|
||||||
}
|
|
||||||
}
|
var match = pattern.exec(str);
|
||||||
|
|
||||||
let offset = 0;
|
if (match) {
|
||||||
for (let i=0; i<strarr.length; i++) {
|
let from = match.index - 1;
|
||||||
let token = strarr[i];
|
let args = [];
|
||||||
let length = token.length || token.content.length;
|
let content = match[0];
|
||||||
|
|
||||||
if (typeof token === "object") {
|
let before = str.slice(0, from + 1);
|
||||||
token.pos = [offset, offset + length];
|
if (before) {
|
||||||
|
args.push(before);
|
||||||
if (TRIM_TOKENS.has(token.type)) {
|
}
|
||||||
token.content = token.content.trim() || " ";
|
|
||||||
}
|
args.push({
|
||||||
}
|
type: token,
|
||||||
|
content,
|
||||||
offset += length;
|
...match.groups,
|
||||||
}
|
});
|
||||||
|
|
||||||
return strarr;
|
let after = str.slice(from + content.length + 1);
|
||||||
}
|
if (after) {
|
||||||
|
args.push(after);
|
||||||
function tokenize (selector) {
|
}
|
||||||
if (!selector) {
|
|
||||||
return null;
|
strarr.splice(i, 1, ...args);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
selector = selector.trim(); // prevent leading/trailing whitespace be interpreted as combinators
|
}
|
||||||
|
}
|
||||||
// Replace strings with whitespace strings (to preserve offsets)
|
|
||||||
let strings = [];
|
let offset = 0;
|
||||||
// FIXME Does not account for escaped backslashes before a quote
|
for (let i = 0; i < strarr.length; i++) {
|
||||||
selector = selector.replace(/(['"])(\\\1|.)+?\1/g, (str, quote, content, start) => {
|
let token = strarr[i];
|
||||||
strings.push({str, start});
|
let length = token.length || token.content.length;
|
||||||
return quote + "§".repeat(content.length) + quote;
|
|
||||||
});
|
if (typeof token === 'object') {
|
||||||
|
token.pos = [offset, offset + length];
|
||||||
// Now that strings are out of the way, extract parens and replace them with parens with whitespace (to preserve offsets)
|
|
||||||
let parens = [], offset = 0, start;
|
if (TRIM_TOKENS.has(token.type)) {
|
||||||
while ((start = selector.indexOf("(", offset)) > -1) {
|
token.content = token.content.trim() || ' ';
|
||||||
let str = gobbleParens(selector, start);
|
}
|
||||||
parens.push({str, start});
|
}
|
||||||
selector = selector.substring(0, start) + "(" + "¶".repeat(str.length - 2) + ")" + selector.substring(start + str.length);
|
|
||||||
offset = start + str.length;
|
offset += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we have no nested structures and we can parse with regexes
|
return strarr;
|
||||||
let tokens = tokenizeBy(selector, TOKENS);
|
}
|
||||||
|
|
||||||
// Now restore parens and strings in reverse order
|
function tokenize(selector) {
|
||||||
function restoreNested(strings, regex, types) {
|
if (!selector) {
|
||||||
for (let str of strings) {
|
return null;
|
||||||
for (let token of tokens) {
|
}
|
||||||
if (types.has(token.type) && token.pos[0] < str.start && str.start < token.pos[1]) {
|
|
||||||
let content = token.content;
|
selector = selector.trim(); // prevent leading/trailing whitespace be interpreted as combinators
|
||||||
token.content = token.content.replace(regex, str.str);
|
|
||||||
|
// Replace strings with whitespace strings (to preserve offsets)
|
||||||
if (token.content !== content) { // actually changed?
|
let strings = [];
|
||||||
// Re-evaluate groups
|
// FIXME Does not account for escaped backslashes before a quote
|
||||||
TOKENS_FOR_RESTORE[token.type].lastIndex = 0;
|
selector = selector.replace(
|
||||||
let match = TOKENS_FOR_RESTORE[token.type].exec(token.content);
|
/(['"])(\\\1|.)+?\1/g,
|
||||||
let groups = match.groups;
|
(str, quote, content, start) => {
|
||||||
Object.assign(token, groups);
|
strings.push({ str, start });
|
||||||
}
|
return quote + '§'.repeat(content.length) + quote;
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
}
|
|
||||||
}
|
// Now that strings are out of the way, extract parens and replace them with parens with whitespace (to preserve offsets)
|
||||||
|
let parens = [],
|
||||||
restoreNested(parens, /\(¶+\)/, TOKENS_WITH_PARENS);
|
offset = 0,
|
||||||
restoreNested(strings, /(['"])§+?\1/, TOKENS_WITH_STRINGS);
|
start;
|
||||||
|
while ((start = selector.indexOf('(', offset)) > -1) {
|
||||||
return tokens;
|
let str = gobbleParens(selector, start);
|
||||||
}
|
parens.push({ str, start });
|
||||||
|
selector =
|
||||||
// Convert a flat list of tokens into a tree of complex & compound selectors
|
selector.substring(0, start) +
|
||||||
function nestTokens(tokens, {list = true} = {}) {
|
'(' +
|
||||||
if (list && tokens.find(t => t.type === "comma")) {
|
'¶'.repeat(str.length - 2) +
|
||||||
let selectors = [], temp = [];
|
')' +
|
||||||
|
selector.substring(start + str.length);
|
||||||
for (let i=0; i<tokens.length; i++) {
|
offset = start + str.length;
|
||||||
if (tokens[i].type === "comma") {
|
}
|
||||||
if (temp.length === 0) {
|
|
||||||
throw new Error("Incorrect comma at " + i);
|
// Now we have no nested structures and we can parse with regexes
|
||||||
}
|
let tokens = tokenizeBy(selector, TOKENS);
|
||||||
|
|
||||||
selectors.push(nestTokens(temp, {list: false}));
|
// Now restore parens and strings in reverse order
|
||||||
temp.length = 0;
|
function restoreNested(strings, regex, types) {
|
||||||
}
|
for (let str of strings) {
|
||||||
else {
|
for (let token of tokens) {
|
||||||
temp.push(tokens[i]);
|
if (
|
||||||
}
|
types.has(token.type) &&
|
||||||
}
|
token.pos[0] < str.start &&
|
||||||
|
str.start < token.pos[1]
|
||||||
if (temp.length === 0) {
|
) {
|
||||||
throw new Error("Trailing comma");
|
let content = token.content;
|
||||||
}
|
token.content = token.content.replace(regex, str.str);
|
||||||
else {
|
|
||||||
selectors.push(nestTokens(temp, {list: false}));
|
if (token.content !== content) {
|
||||||
}
|
// actually changed?
|
||||||
|
// Re-evaluate groups
|
||||||
return { type: "list", list: selectors };
|
TOKENS_FOR_RESTORE[token.type].lastIndex = 0;
|
||||||
}
|
let match = TOKENS_FOR_RESTORE[token.type].exec(
|
||||||
|
token.content
|
||||||
for (let i=tokens.length - 1; i>=0; i--) {
|
);
|
||||||
let token = tokens[i];
|
let groups = match.groups;
|
||||||
|
Object.assign(token, groups);
|
||||||
if (token.type === "combinator") {
|
}
|
||||||
let left = tokens.slice(0, i);
|
}
|
||||||
let right = tokens.slice(i + 1);
|
}
|
||||||
|
}
|
||||||
return {
|
}
|
||||||
type: "complex",
|
|
||||||
combinator: token.content,
|
restoreNested(parens, /\(¶+\)/, TOKENS_WITH_PARENS);
|
||||||
left: nestTokens(left),
|
restoreNested(strings, /(['"])§+?\1/, TOKENS_WITH_STRINGS);
|
||||||
right: nestTokens(right)
|
|
||||||
};
|
return tokens;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Convert a flat list of tokens into a tree of complex & compound selectors
|
||||||
if (tokens.length === 0) {
|
function nestTokens(tokens, { list = true } = {}) {
|
||||||
return null;
|
if (list && tokens.find((t) => t.type === 'comma')) {
|
||||||
}
|
let selectors = [],
|
||||||
|
temp = [];
|
||||||
// If we're here, there are no combinators, so it's just a list
|
|
||||||
return tokens.length === 1? tokens[0] : {
|
for (let i = 0; i < tokens.length; i++) {
|
||||||
type: "compound",
|
if (tokens[i].type === 'comma') {
|
||||||
list: [...tokens] // clone to avoid pointers messing up the AST
|
if (temp.length === 0) {
|
||||||
};
|
throw new Error('Incorrect comma at ' + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Traverse an AST (or part thereof), in depth-first order
|
selectors.push(nestTokens(temp, { list: false }));
|
||||||
function walk(node, callback, o, parent) {
|
temp.length = 0;
|
||||||
if (!node) {
|
} else {
|
||||||
return;
|
temp.push(tokens[i]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (node.type === "complex") {
|
|
||||||
walk(node.left, callback, o, node);
|
if (temp.length === 0) {
|
||||||
walk(node.right, callback, o, node);
|
throw new Error('Trailing comma');
|
||||||
}
|
} else {
|
||||||
else if (node.type === "compound") {
|
selectors.push(nestTokens(temp, { list: false }));
|
||||||
for (let n of node.list) {
|
}
|
||||||
walk(n, callback, o, node);
|
|
||||||
}
|
return { type: 'list', list: selectors };
|
||||||
}
|
}
|
||||||
else if (node.subtree && o && o.subtree) {
|
|
||||||
walk(node.subtree, callback, o, node);
|
for (let i = tokens.length - 1; i >= 0; i--) {
|
||||||
}
|
let token = tokens[i];
|
||||||
|
|
||||||
callback(node, parent);
|
if (token.type === 'combinator') {
|
||||||
}
|
let left = tokens.slice(0, i);
|
||||||
|
let right = tokens.slice(i + 1);
|
||||||
/**
|
|
||||||
* Parse a CSS selector
|
return {
|
||||||
* @param selector {String} The selector to parse
|
type: 'complex',
|
||||||
* @param options.recursive {Boolean} Whether to parse the arguments of pseudo-classes like :is(), :has() etc. Defaults to true.
|
combinator: token.content,
|
||||||
* @param options.list {Boolean} Whether this can be a selector list (A, B, C etc). Defaults to true.
|
left: nestTokens(left),
|
||||||
*/
|
right: nestTokens(right),
|
||||||
function parse(selector, {recursive = true, list = true} = {}) {
|
};
|
||||||
let tokens = tokenize(selector);
|
}
|
||||||
|
}
|
||||||
if (!tokens) {
|
|
||||||
return null;
|
if (tokens.length === 0) {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
let ast = nestTokens(tokens, {list});
|
|
||||||
|
// If we're here, there are no combinators, so it's just a list
|
||||||
if (recursive) {
|
return tokens.length === 1
|
||||||
walk(ast, node => {
|
? tokens[0]
|
||||||
if (node.type === "pseudo-class" && node.argument) {
|
: {
|
||||||
if (RECURSIVE_PSEUDO_CLASSES.has(node.name)) {
|
type: 'compound',
|
||||||
let argument = node.argument;
|
list: [...tokens], // clone to avoid pointers messing up the AST
|
||||||
const childArg = RECURSIVE_PSEUDO_CLASSES_ARGS[node.name];
|
};
|
||||||
if (childArg) {
|
}
|
||||||
const match = childArg.exec(argument);
|
|
||||||
if (!match) {
|
// Traverse an AST (or part thereof), in depth-first order
|
||||||
return;
|
function walk(node, callback, o, parent) {
|
||||||
}
|
if (!node) {
|
||||||
|
return;
|
||||||
Object.assign(node, match.groups);
|
}
|
||||||
argument = match.groups.subtree;
|
|
||||||
}
|
if (node.type === 'complex') {
|
||||||
if (argument) {
|
walk(node.left, callback, o, node);
|
||||||
node.subtree = parse(argument, {recursive: true, list: true});
|
walk(node.right, callback, o, node);
|
||||||
}
|
} else if (node.type === 'compound') {
|
||||||
}
|
for (let n of node.list) {
|
||||||
}
|
walk(n, callback, o, node);
|
||||||
});
|
}
|
||||||
}
|
} else if (node.subtree && o && o.subtree) {
|
||||||
|
walk(node.subtree, callback, o, node);
|
||||||
return ast;
|
}
|
||||||
}
|
|
||||||
|
callback(node, parent);
|
||||||
function specificityToNumber(specificity, base) {
|
}
|
||||||
base = base || Math.max(...specificity) + 1;
|
|
||||||
|
/**
|
||||||
return specificity[0] * base ** 2 + specificity[1] * base + specificity[2];
|
* Parse a CSS selector
|
||||||
}
|
* @param selector {String} The selector to parse
|
||||||
|
* @param options.recursive {Boolean} Whether to parse the arguments of pseudo-classes like :is(), :has() etc. Defaults to true.
|
||||||
function maxIndexOf(arr) {
|
* @param options.list {Boolean} Whether this can be a selector list (A, B, C etc). Defaults to true.
|
||||||
let max = arr[0], ret = 0;
|
*/
|
||||||
|
function parse(selector, { recursive = true, list = true } = {}) {
|
||||||
for (let i=0; i<arr.length; i++) {
|
let tokens = tokenize(selector);
|
||||||
if (arr[i] > max) {
|
|
||||||
ret = i;
|
if (!tokens) {
|
||||||
max = arr[i];
|
return null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
let ast = nestTokens(tokens, { list });
|
||||||
return arr.length === 0? -1 : ret;
|
|
||||||
}
|
if (recursive) {
|
||||||
|
walk(ast, (node) => {
|
||||||
/**
|
if (node.type === 'pseudo-class' && node.argument) {
|
||||||
* Calculate specificity of a selector.
|
if (RECURSIVE_PSEUDO_CLASSES.has(node.name)) {
|
||||||
* If the selector is a list, the max specificity is returned.
|
let argument = node.argument;
|
||||||
*/
|
const childArg =
|
||||||
function specificity(selector, {format = "array"} = {}) {
|
RECURSIVE_PSEUDO_CLASSES_ARGS[node.name];
|
||||||
let ast = typeof selector === "object"? selector : parse(selector, {recursive: true});
|
if (childArg) {
|
||||||
|
const match = childArg.exec(argument);
|
||||||
if (!ast) {
|
if (!match) {
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ast.type === "list") {
|
Object.assign(node, match.groups);
|
||||||
// Return max specificity
|
argument = match.groups.subtree;
|
||||||
let base = 10;
|
}
|
||||||
let specificities = ast.list.map(s => {
|
if (argument) {
|
||||||
let sp = specificity(s);
|
node.subtree = parse(argument, {
|
||||||
base = Math.max(base, ...sp);
|
recursive: true,
|
||||||
return sp;
|
list: true,
|
||||||
});
|
});
|
||||||
let numbers = specificities.map(s => specificityToNumber(s, base));
|
}
|
||||||
let i = maxIndexOf(numbers);
|
}
|
||||||
return specificities[i];
|
}
|
||||||
}
|
});
|
||||||
|
}
|
||||||
let ret = [0, 0, 0];
|
|
||||||
|
return ast;
|
||||||
walk(ast, node => {
|
}
|
||||||
if (node.type === "id") {
|
|
||||||
ret[0]++;
|
function specificityToNumber(specificity, base) {
|
||||||
}
|
base = base || Math.max(...specificity) + 1;
|
||||||
else if (node.type === "class" || node.type === "attribute") {
|
|
||||||
ret[1]++;
|
return (
|
||||||
}
|
specificity[0] * base ** 2 + specificity[1] * base + specificity[2]
|
||||||
else if ((node.type === "type" && node.content !== "*") || node.type === "pseudo-element") {
|
);
|
||||||
ret[2]++;
|
}
|
||||||
}
|
|
||||||
else if (node.type === "pseudo-class" && node.name !== "where") {
|
function maxIndexOf(arr) {
|
||||||
if (RECURSIVE_PSEUDO_CLASSES.has(node.name) && node.subtree) {
|
let max = arr[0],
|
||||||
// Max of argument list
|
ret = 0;
|
||||||
let sub = specificity(node.subtree);
|
|
||||||
sub.forEach((s, i) => ret[i] += s);
|
for (let i = 0; i < arr.length; i++) {
|
||||||
}
|
if (arr[i] > max) {
|
||||||
else {
|
ret = i;
|
||||||
ret[1]++;
|
max = arr[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
return arr.length === 0 ? -1 : ret;
|
||||||
return ret;
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
exports.RECURSIVE_PSEUDO_CLASSES = RECURSIVE_PSEUDO_CLASSES;
|
* Calculate specificity of a selector.
|
||||||
exports.RECURSIVE_PSEUDO_CLASSES_ARGS = RECURSIVE_PSEUDO_CLASSES_ARGS;
|
* If the selector is a list, the max specificity is returned.
|
||||||
exports.TOKENS = TOKENS;
|
*/
|
||||||
exports.TRIM_TOKENS = TRIM_TOKENS;
|
function specificity(selector, { format = 'array' } = {}) {
|
||||||
exports.gobbleParens = gobbleParens;
|
let ast =
|
||||||
exports.nestTokens = nestTokens;
|
typeof selector === 'object'
|
||||||
exports.parse = parse;
|
? selector
|
||||||
exports.specificity = specificity;
|
: parse(selector, { recursive: true });
|
||||||
exports.specificityToNumber = specificityToNumber;
|
|
||||||
exports.tokenize = tokenize;
|
if (!ast) {
|
||||||
exports.tokenizeBy = tokenizeBy;
|
return null;
|
||||||
exports.walk = walk;
|
}
|
||||||
|
|
||||||
Object.defineProperty(exports, '__esModule', { value: true });
|
if (ast.type === 'list') {
|
||||||
|
// Return max specificity
|
||||||
return exports;
|
let base = 10;
|
||||||
|
let specificities = ast.list.map((s) => {
|
||||||
}({}));
|
let sp = specificity(s);
|
||||||
|
base = Math.max(base, ...sp);
|
||||||
|
return sp;
|
||||||
|
});
|
||||||
|
let numbers = specificities.map((s) =>
|
||||||
|
specificityToNumber(s, base)
|
||||||
|
);
|
||||||
|
let i = maxIndexOf(numbers);
|
||||||
|
return specificities[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret = [0, 0, 0];
|
||||||
|
|
||||||
|
walk(ast, (node) => {
|
||||||
|
if (node.type === 'id') {
|
||||||
|
ret[0]++;
|
||||||
|
} else if (node.type === 'class' || node.type === 'attribute') {
|
||||||
|
ret[1]++;
|
||||||
|
} else if (
|
||||||
|
(node.type === 'type' && node.content !== '*') ||
|
||||||
|
node.type === 'pseudo-element'
|
||||||
|
) {
|
||||||
|
ret[2]++;
|
||||||
|
} else if (node.type === 'pseudo-class' && node.name !== 'where') {
|
||||||
|
if (RECURSIVE_PSEUDO_CLASSES.has(node.name) && node.subtree) {
|
||||||
|
// Max of argument list
|
||||||
|
let sub = specificity(node.subtree);
|
||||||
|
sub.forEach((s, i) => (ret[i] += s));
|
||||||
|
} else {
|
||||||
|
ret[1]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.RECURSIVE_PSEUDO_CLASSES = RECURSIVE_PSEUDO_CLASSES;
|
||||||
|
exports.RECURSIVE_PSEUDO_CLASSES_ARGS = RECURSIVE_PSEUDO_CLASSES_ARGS;
|
||||||
|
exports.TOKENS = TOKENS;
|
||||||
|
exports.TRIM_TOKENS = TRIM_TOKENS;
|
||||||
|
exports.gobbleParens = gobbleParens;
|
||||||
|
exports.nestTokens = nestTokens;
|
||||||
|
exports.parse = parse;
|
||||||
|
exports.specificity = specificity;
|
||||||
|
exports.specificityToNumber = specificityToNumber;
|
||||||
|
exports.tokenize = tokenize;
|
||||||
|
exports.tokenizeBy = tokenizeBy;
|
||||||
|
exports.walk = walk;
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
|
return exports;
|
||||||
|
})({});
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
function url(ctx) {
|
function url(ctx) {
|
||||||
const { css } = ctx;
|
const { css } = ctx;
|
||||||
css.on('Url', (node, data, type) => {
|
css.on('Url', (node, data, type) => {
|
||||||
node.value = type === 'rewrite' ? ctx.rewriteUrl(node.value) : ctx.sourceUrl(node.value);
|
node.value =
|
||||||
|
type === 'rewrite'
|
||||||
|
? ctx.rewriteUrl(node.value)
|
||||||
|
: ctx.sourceUrl(node.value);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
function importStyle(ctx) {
|
function importStyle(ctx) {
|
||||||
const { css } = ctx;
|
const { css } = ctx;
|
||||||
|
@ -12,9 +15,11 @@ function importStyle(ctx) {
|
||||||
const { data: url } = node.prelude.children.head;
|
const { data: url } = node.prelude.children.head;
|
||||||
// Already handling Url's
|
// Already handling Url's
|
||||||
if (url.type === 'Url') return false;
|
if (url.type === 'Url') return false;
|
||||||
url.value = type === 'rewrite' ? ctx.rewriteUrl(url.value) : ctx.sourceUrl(url.value);
|
url.value =
|
||||||
|
type === 'rewrite'
|
||||||
|
? ctx.rewriteUrl(url.value)
|
||||||
|
: ctx.sourceUrl(url.value);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
export { url, importStyle };
|
export { url, importStyle };
|
|
@ -3,20 +3,23 @@ function attributes(ctx, meta = ctx.meta) {
|
||||||
const origPrefix = attributePrefix + '-attr-';
|
const origPrefix = attributePrefix + '-attr-';
|
||||||
|
|
||||||
html.on('attr', (attr, type) => {
|
html.on('attr', (attr, type) => {
|
||||||
if (attr.node.tagName === 'base' && attr.name === 'href' && attr.options.document) {
|
if (
|
||||||
|
attr.node.tagName === 'base' &&
|
||||||
|
attr.name === 'href' &&
|
||||||
|
attr.options.document
|
||||||
|
) {
|
||||||
meta.base = new URL(attr.value, meta.url);
|
meta.base = new URL(attr.value, meta.url);
|
||||||
};
|
}
|
||||||
|
|
||||||
if (type === 'rewrite' && isUrl(attr.name, attr.tagName)) {
|
if (type === 'rewrite' && isUrl(attr.name, attr.tagName)) {
|
||||||
attr.node.setAttribute(origPrefix + attr.name, attr.value);
|
attr.node.setAttribute(origPrefix + attr.name, attr.value);
|
||||||
attr.value = ctx.rewriteUrl(attr.value, meta);
|
attr.value = ctx.rewriteUrl(attr.value, meta);
|
||||||
};
|
}
|
||||||
|
|
||||||
if (type === 'rewrite' && isSrcset(attr.name)) {
|
if (type === 'rewrite' && isSrcset(attr.name)) {
|
||||||
attr.node.setAttribute(origPrefix + attr.name, attr.value);
|
attr.node.setAttribute(origPrefix + attr.name, attr.value);
|
||||||
attr.value = html.wrapSrcset(attr.value, meta);
|
attr.value = html.wrapSrcset(attr.value, meta);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
if (type === 'rewrite' && isHtml(attr.name)) {
|
if (type === 'rewrite' && isHtml(attr.name)) {
|
||||||
attr.node.setAttribute(origPrefix + attr.name, attr.value);
|
attr.node.setAttribute(origPrefix + attr.name, attr.value);
|
||||||
|
@ -25,28 +28,29 @@ function attributes(ctx, meta = ctx.meta) {
|
||||||
document: true,
|
document: true,
|
||||||
injectHead: attr.options.injectHead || [],
|
injectHead: attr.options.injectHead || [],
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
if (type === 'rewrite' && isStyle(attr.name)) {
|
if (type === 'rewrite' && isStyle(attr.name)) {
|
||||||
attr.node.setAttribute(origPrefix + attr.name, attr.value);
|
attr.node.setAttribute(origPrefix + attr.name, attr.value);
|
||||||
attr.value = ctx.rewriteCSS(attr.value, { context: 'declarationList', });
|
attr.value = ctx.rewriteCSS(attr.value, {
|
||||||
};
|
context: 'declarationList',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (type === 'rewrite' && isForbidden(attr.name)) {
|
if (type === 'rewrite' && isForbidden(attr.name)) {
|
||||||
attr.name = origPrefix + attr.name;
|
attr.name = origPrefix + attr.name;
|
||||||
};
|
}
|
||||||
|
|
||||||
if (type === 'rewrite' && isEvent(attr.name)) {
|
if (type === 'rewrite' && isEvent(attr.name)) {
|
||||||
attr.node.setAttribute(origPrefix + attr.name, attr.value);
|
attr.node.setAttribute(origPrefix + attr.name, attr.value);
|
||||||
attr.value = js.rewrite(attr.value, meta);
|
attr.value = js.rewrite(attr.value, meta);
|
||||||
};
|
}
|
||||||
|
|
||||||
if (type === 'source' && attr.name.startsWith(origPrefix)) {
|
if (type === 'source' && attr.name.startsWith(origPrefix)) {
|
||||||
if (attr.node.hasAttribute(attr.name.slice(origPrefix.length))) attr.node.removeAttribute(attr.name.slice(origPrefix.length));
|
if (attr.node.hasAttribute(attr.name.slice(origPrefix.length)))
|
||||||
|
attr.node.removeAttribute(attr.name.slice(origPrefix.length));
|
||||||
attr.name = attr.name.slice(origPrefix.length);
|
attr.name = attr.name.slice(origPrefix.length);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (isHtml(attr.name)) {
|
if (isHtml(attr.name)) {
|
||||||
|
@ -62,101 +66,119 @@ function attributes(ctx, meta = ctx.meta) {
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
});
|
});
|
||||||
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
function text(ctx, meta = ctx.meta) {
|
function text(ctx, meta = ctx.meta) {
|
||||||
const { html, js, css, attributePrefix } = ctx;
|
const { html, js, css, attributePrefix } = ctx;
|
||||||
|
|
||||||
html.on('text', (text, type) => {
|
html.on('text', (text, type) => {
|
||||||
if (text.element.tagName === 'script') {
|
if (text.element.tagName === 'script') {
|
||||||
text.value = type === 'rewrite' ? js.rewrite(text.value) : js.source(text.value);
|
text.value =
|
||||||
};
|
type === 'rewrite'
|
||||||
|
? js.rewrite(text.value)
|
||||||
|
: js.source(text.value);
|
||||||
|
}
|
||||||
|
|
||||||
if (text.element.tagName === 'style') {
|
if (text.element.tagName === 'style') {
|
||||||
text.value = type === 'rewrite' ? css.rewrite(text.value) : css.source(text.value);
|
text.value =
|
||||||
};
|
type === 'rewrite'
|
||||||
|
? css.rewrite(text.value)
|
||||||
|
: css.source(text.value);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
function isUrl(name, tag) {
|
function isUrl(name, tag) {
|
||||||
return tag === 'object' && name === 'data' || ['src', 'href', 'ping', 'movie', 'action', 'poster', 'profile', 'background'].indexOf(name) > -1;
|
return (
|
||||||
};
|
(tag === 'object' && name === 'data') ||
|
||||||
|
[
|
||||||
|
'src',
|
||||||
|
'href',
|
||||||
|
'ping',
|
||||||
|
'movie',
|
||||||
|
'action',
|
||||||
|
'poster',
|
||||||
|
'profile',
|
||||||
|
'background',
|
||||||
|
].indexOf(name) > -1
|
||||||
|
);
|
||||||
|
}
|
||||||
function isEvent(name) {
|
function isEvent(name) {
|
||||||
return [
|
return (
|
||||||
'onafterprint',
|
[
|
||||||
'onbeforeprint',
|
'onafterprint',
|
||||||
'onbeforeunload',
|
'onbeforeprint',
|
||||||
'onerror',
|
'onbeforeunload',
|
||||||
'onhashchange',
|
'onerror',
|
||||||
'onload',
|
'onhashchange',
|
||||||
'onmessage',
|
'onload',
|
||||||
'onoffline',
|
'onmessage',
|
||||||
'ononline',
|
'onoffline',
|
||||||
'onpagehide',
|
'ononline',
|
||||||
'onpopstate',
|
'onpagehide',
|
||||||
'onstorage',
|
'onpopstate',
|
||||||
'onunload',
|
'onstorage',
|
||||||
'onblur',
|
'onunload',
|
||||||
'onchange',
|
'onblur',
|
||||||
'oncontextmenu',
|
'onchange',
|
||||||
'onfocus',
|
'oncontextmenu',
|
||||||
'oninput',
|
'onfocus',
|
||||||
'oninvalid',
|
'oninput',
|
||||||
'onreset',
|
'oninvalid',
|
||||||
'onsearch',
|
'onreset',
|
||||||
'onselect',
|
'onsearch',
|
||||||
'onsubmit',
|
'onselect',
|
||||||
'onkeydown',
|
'onsubmit',
|
||||||
'onkeypress',
|
'onkeydown',
|
||||||
'onkeyup',
|
'onkeypress',
|
||||||
'onclick',
|
'onkeyup',
|
||||||
'ondblclick',
|
'onclick',
|
||||||
'onmousedown',
|
'ondblclick',
|
||||||
'onmousemove',
|
'onmousedown',
|
||||||
'onmouseout',
|
'onmousemove',
|
||||||
'onmouseover',
|
'onmouseout',
|
||||||
'onmouseup',
|
'onmouseover',
|
||||||
'onmousewheel',
|
'onmouseup',
|
||||||
'onwheel',
|
'onmousewheel',
|
||||||
'ondrag',
|
'onwheel',
|
||||||
'ondragend',
|
'ondrag',
|
||||||
'ondragenter',
|
'ondragend',
|
||||||
'ondragleave',
|
'ondragenter',
|
||||||
'ondragover',
|
'ondragleave',
|
||||||
'ondragstart',
|
'ondragover',
|
||||||
'ondrop',
|
'ondragstart',
|
||||||
'onscroll',
|
'ondrop',
|
||||||
'oncopy',
|
'onscroll',
|
||||||
'oncut',
|
'oncopy',
|
||||||
'onpaste',
|
'oncut',
|
||||||
'onabort',
|
'onpaste',
|
||||||
'oncanplay',
|
'onabort',
|
||||||
'oncanplaythrough',
|
'oncanplay',
|
||||||
'oncuechange',
|
'oncanplaythrough',
|
||||||
'ondurationchange',
|
'oncuechange',
|
||||||
'onemptied',
|
'ondurationchange',
|
||||||
'onended',
|
'onemptied',
|
||||||
'onerror',
|
'onended',
|
||||||
'onloadeddata',
|
'onerror',
|
||||||
'onloadedmetadata',
|
'onloadeddata',
|
||||||
'onloadstart',
|
'onloadedmetadata',
|
||||||
'onpause',
|
'onloadstart',
|
||||||
'onplay',
|
'onpause',
|
||||||
'onplaying',
|
'onplay',
|
||||||
'onprogress',
|
'onplaying',
|
||||||
'onratechange',
|
'onprogress',
|
||||||
'onseeked',
|
'onratechange',
|
||||||
'onseeking',
|
'onseeked',
|
||||||
'onstalled',
|
'onseeking',
|
||||||
'onsuspend',
|
'onstalled',
|
||||||
'ontimeupdate',
|
'onsuspend',
|
||||||
'onvolumechange',
|
'ontimeupdate',
|
||||||
'onwaiting',
|
'onvolumechange',
|
||||||
].indexOf(name) > -1;
|
'onwaiting',
|
||||||
};
|
].indexOf(name) > -1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function injectHead(ctx) {
|
function injectHead(ctx) {
|
||||||
const { html, js, css, attributePrefix } = ctx;
|
const { html, js, css, attributePrefix } = ctx;
|
||||||
|
@ -166,13 +188,17 @@ function injectHead(ctx) {
|
||||||
if (element.tagName !== 'head') return false;
|
if (element.tagName !== 'head') return false;
|
||||||
if (!('injectHead' in element.options)) return false;
|
if (!('injectHead' in element.options)) return false;
|
||||||
|
|
||||||
element.childNodes.unshift(
|
element.childNodes.unshift(...element.options.injectHead);
|
||||||
...element.options.injectHead
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
function createInjection(handler = '/uv.handler.js', bundle = '/uv.bundle.js', config = '/uv.config.js', cookies = '', referrer = '') {
|
function createInjection(
|
||||||
|
handler = '/uv.handler.js',
|
||||||
|
bundle = '/uv.bundle.js',
|
||||||
|
config = '/uv.config.js',
|
||||||
|
cookies = '',
|
||||||
|
referrer = ''
|
||||||
|
) {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
tagName: 'script',
|
tagName: 'script',
|
||||||
|
@ -180,7 +206,9 @@ function createInjection(handler = '/uv.handler.js', bundle = '/uv.bundle.js', c
|
||||||
childNodes: [
|
childNodes: [
|
||||||
{
|
{
|
||||||
nodeName: '#text',
|
nodeName: '#text',
|
||||||
value: `window.__uv$cookies = atob("${btoa(cookies)}");\nwindow.__uv$referrer = atob("${btoa(referrer)}");`
|
value: `window.__uv$cookies = atob("${btoa(
|
||||||
|
cookies
|
||||||
|
)}");\nwindow.__uv$referrer = atob("${btoa(referrer)}");`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
attrs: [
|
attrs: [
|
||||||
|
@ -188,7 +216,7 @@ function createInjection(handler = '/uv.handler.js', bundle = '/uv.bundle.js', c
|
||||||
name: '__uv-script',
|
name: '__uv-script',
|
||||||
value: '1',
|
value: '1',
|
||||||
skip: true,
|
skip: true,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
skip: true,
|
skip: true,
|
||||||
},
|
},
|
||||||
|
@ -202,7 +230,7 @@ function createInjection(handler = '/uv.handler.js', bundle = '/uv.bundle.js', c
|
||||||
name: '__uv-script',
|
name: '__uv-script',
|
||||||
value: '1',
|
value: '1',
|
||||||
skip: true,
|
skip: true,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -215,7 +243,7 @@ function createInjection(handler = '/uv.handler.js', bundle = '/uv.bundle.js', c
|
||||||
name: '__uv-script',
|
name: '__uv-script',
|
||||||
value: '1',
|
value: '1',
|
||||||
skip: true,
|
skip: true,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -228,27 +256,41 @@ function createInjection(handler = '/uv.handler.js', bundle = '/uv.bundle.js', c
|
||||||
name: '__uv-script',
|
name: '__uv-script',
|
||||||
value: '1',
|
value: '1',
|
||||||
skip: true,
|
skip: true,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
};
|
}
|
||||||
|
|
||||||
function isForbidden(name) {
|
function isForbidden(name) {
|
||||||
return ['http-equiv', 'integrity', 'sandbox', 'nonce', 'crossorigin'].indexOf(name) > -1;
|
return (
|
||||||
};
|
['http-equiv', 'integrity', 'sandbox', 'nonce', 'crossorigin'].indexOf(
|
||||||
|
name
|
||||||
|
) > -1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function isHtml(name){
|
function isHtml(name) {
|
||||||
return name === 'srcdoc';
|
return name === 'srcdoc';
|
||||||
};
|
}
|
||||||
|
|
||||||
function isStyle(name) {
|
function isStyle(name) {
|
||||||
return name === 'style';
|
return name === 'style';
|
||||||
};
|
}
|
||||||
|
|
||||||
function isSrcset(name) {
|
function isSrcset(name) {
|
||||||
return name === 'srcset' || name === 'imagesrcset';
|
return name === 'srcset' || name === 'imagesrcset';
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
attributes,
|
||||||
|
createInjection,
|
||||||
|
text,
|
||||||
|
isUrl,
|
||||||
|
isEvent,
|
||||||
|
isForbidden,
|
||||||
|
isHtml,
|
||||||
|
isStyle,
|
||||||
|
isSrcset,
|
||||||
|
injectHead,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export { attributes, createInjection, text, isUrl, isEvent, isForbidden, isHtml, isStyle, isSrcset, injectHead };
|
|
|
@ -10,92 +10,167 @@ function property(ctx) {
|
||||||
node: '__uv.$wrap((',
|
node: '__uv.$wrap((',
|
||||||
start: node.property.start,
|
start: node.property.start,
|
||||||
end: node.property.start,
|
end: node.property.start,
|
||||||
})
|
});
|
||||||
node.iterateEnd = function() {
|
node.iterateEnd = function () {
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
node: '))',
|
node: '))',
|
||||||
start: node.property.end,
|
start: node.property.end,
|
||||||
end: node.property.end,
|
end: node.property.end,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
};
|
if (
|
||||||
|
(!node.computed &&
|
||||||
if (!node.computed && node.property.name === 'location' && type === 'rewrite' || node.property.name === '__uv$location' && type === 'source') {
|
node.property.name === 'location' &&
|
||||||
|
type === 'rewrite') ||
|
||||||
|
(node.property.name === '__uv$location' && type === 'source')
|
||||||
|
) {
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
start: node.property.start,
|
start: node.property.start,
|
||||||
end: node.property.end,
|
end: node.property.end,
|
||||||
node: type === 'rewrite' ? '__uv$setSource(__uv).__uv$location' : 'location'
|
node:
|
||||||
|
type === 'rewrite'
|
||||||
|
? '__uv$setSource(__uv).__uv$location'
|
||||||
|
: 'location',
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
if (!node.computed && node.property.name === 'top' && type === 'rewrite' || node.property.name === '__uv$top' && type === 'source') {
|
(!node.computed &&
|
||||||
|
node.property.name === 'top' &&
|
||||||
|
type === 'rewrite') ||
|
||||||
|
(node.property.name === '__uv$top' && type === 'source')
|
||||||
|
) {
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
start: node.property.start,
|
start: node.property.start,
|
||||||
end: node.property.end,
|
end: node.property.end,
|
||||||
node: type === 'rewrite' ? '__uv$setSource(__uv).__uv$top' : 'top'
|
node:
|
||||||
|
type === 'rewrite'
|
||||||
|
? '__uv$setSource(__uv).__uv$top'
|
||||||
|
: 'top',
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
if (!node.computed && node.property.name === 'parent' && type === 'rewrite' || node.property.name === '__uv$parent' && type === 'source') {
|
if (
|
||||||
|
(!node.computed &&
|
||||||
|
node.property.name === 'parent' &&
|
||||||
|
type === 'rewrite') ||
|
||||||
|
(node.property.name === '__uv$parent' && type === 'source')
|
||||||
|
) {
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
start: node.property.start,
|
start: node.property.start,
|
||||||
end: node.property.end,
|
end: node.property.end,
|
||||||
node: type === 'rewrite' ? '__uv$setSource(__uv).__uv$parent' : 'parent'
|
node:
|
||||||
|
type === 'rewrite'
|
||||||
|
? '__uv$setSource(__uv).__uv$parent'
|
||||||
|
: 'parent',
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
if (!node.computed && node.property.name === 'postMessage' && type === 'rewrite') {
|
!node.computed &&
|
||||||
|
node.property.name === 'postMessage' &&
|
||||||
|
type === 'rewrite'
|
||||||
|
) {
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
start: node.property.start,
|
start: node.property.start,
|
||||||
end: node.property.end,
|
end: node.property.end,
|
||||||
node:'__uv$setSource(__uv).postMessage',
|
node: '__uv$setSource(__uv).postMessage',
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
if (!node.computed && node.property.name === 'eval' && type === 'rewrite' || node.property.name === '__uv$eval' && type === 'source') {
|
(!node.computed &&
|
||||||
|
node.property.name === 'eval' &&
|
||||||
|
type === 'rewrite') ||
|
||||||
|
(node.property.name === '__uv$eval' && type === 'source')
|
||||||
|
) {
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
start: node.property.start,
|
start: node.property.start,
|
||||||
end: node.property.end,
|
end: node.property.end,
|
||||||
node: type === 'rewrite' ? '__uv$setSource(__uv).__uv$eval' : 'eval'
|
node:
|
||||||
|
type === 'rewrite'
|
||||||
|
? '__uv$setSource(__uv).__uv$eval'
|
||||||
|
: 'eval',
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
if (!node.computed && node.property.name === '__uv$setSource' && type === 'source' && node.parent.type === Syntax.CallExpression) {
|
if (
|
||||||
|
!node.computed &&
|
||||||
|
node.property.name === '__uv$setSource' &&
|
||||||
|
type === 'source' &&
|
||||||
|
node.parent.type === Syntax.CallExpression
|
||||||
|
) {
|
||||||
const { parent, property } = node;
|
const { parent, property } = node;
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
start: property.start - 1,
|
start: property.start - 1,
|
||||||
end: parent.end,
|
end: parent.end,
|
||||||
});
|
});
|
||||||
|
|
||||||
node.iterateEnd = function() {
|
node.iterateEnd = function () {
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
start: property.start,
|
start: property.start,
|
||||||
end: parent.end,
|
end: parent.end,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
function identifier(ctx) {
|
function identifier(ctx) {
|
||||||
const { js } = ctx;
|
const { js } = ctx;
|
||||||
js.on('Identifier', (node, data, type) => {
|
js.on('Identifier', (node, data, type) => {
|
||||||
if (type !== 'rewrite') return false;
|
if (type !== 'rewrite') return false;
|
||||||
const { parent } = node;
|
const { parent } = node;
|
||||||
if (!['location', 'eval', 'parent', 'top'].includes(node.name)) return false;
|
if (!['location', 'eval', 'parent', 'top'].includes(node.name))
|
||||||
if (parent.type === Syntax.VariableDeclarator && parent.id === node) return false;
|
return false;
|
||||||
if ((parent.type === Syntax.AssignmentExpression || parent.type === Syntax.AssignmentPattern) && parent.left === node) return false;
|
if (parent.type === Syntax.VariableDeclarator && parent.id === node)
|
||||||
if ((parent.type === Syntax.FunctionExpression || parent.type === Syntax.FunctionDeclaration) && parent.id === node) return false;
|
return false;
|
||||||
if (parent.type === Syntax.MemberExpression && parent.property === node && !parent.computed) return false;
|
if (
|
||||||
if (node.name === 'eval' && parent.type === Syntax.CallExpression && parent.callee === node) return false;
|
(parent.type === Syntax.AssignmentExpression ||
|
||||||
if (parent.type === Syntax.Property && parent.key === node) return false;
|
parent.type === Syntax.AssignmentPattern) &&
|
||||||
if (parent.type === Syntax.Property && parent.value === node && parent.shorthand) return false;
|
parent.left === node
|
||||||
if (parent.type === Syntax.UpdateExpression && (parent.operator === '++' || parent.operator === '--')) return false;
|
)
|
||||||
if ((parent.type === Syntax.FunctionExpression || parent.type === Syntax.FunctionDeclaration || parent.type === Syntax.ArrowFunctionExpression) && parent.params.indexOf(node) !== -1) return false;
|
return false;
|
||||||
|
if (
|
||||||
|
(parent.type === Syntax.FunctionExpression ||
|
||||||
|
parent.type === Syntax.FunctionDeclaration) &&
|
||||||
|
parent.id === node
|
||||||
|
)
|
||||||
|
return false;
|
||||||
|
if (
|
||||||
|
parent.type === Syntax.MemberExpression &&
|
||||||
|
parent.property === node &&
|
||||||
|
!parent.computed
|
||||||
|
)
|
||||||
|
return false;
|
||||||
|
if (
|
||||||
|
node.name === 'eval' &&
|
||||||
|
parent.type === Syntax.CallExpression &&
|
||||||
|
parent.callee === node
|
||||||
|
)
|
||||||
|
return false;
|
||||||
|
if (parent.type === Syntax.Property && parent.key === node)
|
||||||
|
return false;
|
||||||
|
if (
|
||||||
|
parent.type === Syntax.Property &&
|
||||||
|
parent.value === node &&
|
||||||
|
parent.shorthand
|
||||||
|
)
|
||||||
|
return false;
|
||||||
|
if (
|
||||||
|
parent.type === Syntax.UpdateExpression &&
|
||||||
|
(parent.operator === '++' || parent.operator === '--')
|
||||||
|
)
|
||||||
|
return false;
|
||||||
|
if (
|
||||||
|
(parent.type === Syntax.FunctionExpression ||
|
||||||
|
parent.type === Syntax.FunctionDeclaration ||
|
||||||
|
parent.type === Syntax.ArrowFunctionExpression) &&
|
||||||
|
parent.params.indexOf(node) !== -1
|
||||||
|
)
|
||||||
|
return false;
|
||||||
if (parent.type === Syntax.MethodDefinition) return false;
|
if (parent.type === Syntax.MethodDefinition) return false;
|
||||||
if (parent.type === Syntax.ClassDeclaration) return false;
|
if (parent.type === Syntax.ClassDeclaration) return false;
|
||||||
if (parent.type === Syntax.RestElement) return false;
|
if (parent.type === Syntax.RestElement) return false;
|
||||||
|
@ -105,10 +180,10 @@ function identifier(ctx) {
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
start: node.start,
|
start: node.start,
|
||||||
end: node.end,
|
end: node.end,
|
||||||
node: '__uv.$get(' + node.name + ')'
|
node: '__uv.$get(' + node.name + ')',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
function wrapEval(ctx) {
|
function wrapEval(ctx) {
|
||||||
const { js } = ctx;
|
const { js } = ctx;
|
||||||
|
@ -118,14 +193,14 @@ function wrapEval(ctx) {
|
||||||
if (node.callee.type !== 'Identifier') return false;
|
if (node.callee.type !== 'Identifier') return false;
|
||||||
if (node.callee.name !== 'eval') return false;
|
if (node.callee.name !== 'eval') return false;
|
||||||
|
|
||||||
const [ script ] = node.arguments;
|
const [script] = node.arguments;
|
||||||
|
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
node: '__uv.js.rewrite(',
|
node: '__uv.js.rewrite(',
|
||||||
start: script.start,
|
start: script.start,
|
||||||
end: script.start,
|
end: script.start,
|
||||||
})
|
});
|
||||||
node.iterateEnd = function() {
|
node.iterateEnd = function () {
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
node: ')',
|
node: ')',
|
||||||
start: script.end,
|
start: script.end,
|
||||||
|
@ -133,21 +208,31 @@ function wrapEval(ctx) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
function importDeclaration(ctx) {
|
function importDeclaration(ctx) {
|
||||||
const { js } = ctx;
|
const { js } = ctx;
|
||||||
js.on(Syntax.Literal, (node, data, type) => {
|
js.on(Syntax.Literal, (node, data, type) => {
|
||||||
if (!((node.parent.type === Syntax.ImportDeclaration || node.parent.type === Syntax.ExportAllDeclaration || node.parent.type === Syntax.ExportNamedDeclaration)
|
if (
|
||||||
&& node.parent.source === node)) return false;
|
!(
|
||||||
|
(node.parent.type === Syntax.ImportDeclaration ||
|
||||||
|
node.parent.type === Syntax.ExportAllDeclaration ||
|
||||||
|
node.parent.type === Syntax.ExportNamedDeclaration) &&
|
||||||
|
node.parent.source === node
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return false;
|
||||||
|
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
start: node.start + 1,
|
start: node.start + 1,
|
||||||
end: node.end - 1,
|
end: node.end - 1,
|
||||||
node: type === 'rewrite' ? ctx.rewriteUrl(node.value) : ctx.sourceUrl(node.value)
|
node:
|
||||||
|
type === 'rewrite'
|
||||||
|
? ctx.rewriteUrl(node.value)
|
||||||
|
: ctx.sourceUrl(node.value),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
function dynamicImport(ctx) {
|
function dynamicImport(ctx) {
|
||||||
const { js } = ctx;
|
const { js } = ctx;
|
||||||
|
@ -157,8 +242,8 @@ function dynamicImport(ctx) {
|
||||||
node: '__uv.rewriteUrl(',
|
node: '__uv.rewriteUrl(',
|
||||||
start: node.source.start,
|
start: node.source.start,
|
||||||
end: node.source.start,
|
end: node.source.start,
|
||||||
})
|
});
|
||||||
node.iterateEnd = function() {
|
node.iterateEnd = function () {
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
node: ')',
|
node: ')',
|
||||||
start: node.source.end,
|
start: node.source.end,
|
||||||
|
@ -166,7 +251,7 @@ function dynamicImport(ctx) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
function unwrap(ctx) {
|
function unwrap(ctx) {
|
||||||
const { js } = ctx;
|
const { js } = ctx;
|
||||||
|
@ -174,17 +259,22 @@ function unwrap(ctx) {
|
||||||
if (type !== 'source') return false;
|
if (type !== 'source') return false;
|
||||||
if (!isWrapped(node.callee)) return false;
|
if (!isWrapped(node.callee)) return false;
|
||||||
|
|
||||||
switch(node.callee.property.name) {
|
switch (node.callee.property.name) {
|
||||||
case '$wrap':
|
case '$wrap':
|
||||||
if (!node.arguments || node.parent.type !== Syntax.MemberExpression || node.parent.property !== node) return false;
|
if (
|
||||||
const [ property ] = node.arguments;
|
!node.arguments ||
|
||||||
|
node.parent.type !== Syntax.MemberExpression ||
|
||||||
|
node.parent.property !== node
|
||||||
|
)
|
||||||
|
return false;
|
||||||
|
const [property] = node.arguments;
|
||||||
|
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
start: node.callee.start,
|
start: node.callee.start,
|
||||||
end: property.start,
|
end: property.start,
|
||||||
});
|
});
|
||||||
|
|
||||||
node.iterateEnd = function() {
|
node.iterateEnd = function () {
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
start: node.end - 2,
|
start: node.end - 2,
|
||||||
end: node.end,
|
end: node.end,
|
||||||
|
@ -193,14 +283,14 @@ function unwrap(ctx) {
|
||||||
break;
|
break;
|
||||||
case '$get':
|
case '$get':
|
||||||
case 'rewriteUrl':
|
case 'rewriteUrl':
|
||||||
const [ arg ] = node.arguments;
|
const [arg] = node.arguments;
|
||||||
|
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
start: node.callee.start,
|
start: node.callee.start,
|
||||||
end: arg.start,
|
end: arg.start,
|
||||||
});
|
});
|
||||||
|
|
||||||
node.iterateEnd = function() {
|
node.iterateEnd = function () {
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
start: node.end - 1,
|
start: node.end - 1,
|
||||||
end: node.end,
|
end: node.end,
|
||||||
|
@ -208,36 +298,43 @@ function unwrap(ctx) {
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case 'rewrite':
|
case 'rewrite':
|
||||||
const [ script ] = node.arguments;
|
const [script] = node.arguments;
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
start: node.callee.start,
|
start: node.callee.start,
|
||||||
end: script.start,
|
end: script.start,
|
||||||
});
|
});
|
||||||
node.iterateEnd = function() {
|
node.iterateEnd = function () {
|
||||||
data.changes.push({
|
data.changes.push({
|
||||||
start: node.end - 1,
|
start: node.end - 1,
|
||||||
end: node.end,
|
end: node.end,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
function isWrapped(node) {
|
function isWrapped(node) {
|
||||||
if (node.type !== Syntax.MemberExpression) return false;
|
if (node.type !== Syntax.MemberExpression) return false;
|
||||||
if (node.property.name === 'rewrite' && isWrapped(node.object)) return true;
|
if (node.property.name === 'rewrite' && isWrapped(node.object)) return true;
|
||||||
if (node.object.type !== Syntax.Identifier || node.object.name !== '__uv') return false;
|
if (node.object.type !== Syntax.Identifier || node.object.name !== '__uv')
|
||||||
if (!['js', '$get', '$wrap', 'rewriteUrl'].includes(node.property.name)) return false;
|
return false;
|
||||||
|
if (!['js', '$get', '$wrap', 'rewriteUrl'].includes(node.property.name))
|
||||||
|
return false;
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
function computedProperty(parent) {
|
function computedProperty(parent) {
|
||||||
if (!parent.computed) return false;
|
if (!parent.computed) return false;
|
||||||
const { property: node } = parent;
|
const { property: node } = parent;
|
||||||
if (node.type === 'Literal' && !['location', 'top', 'parent']) return false;
|
if (node.type === 'Literal' && !['location', 'top', 'parent']) return false;
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
property,
|
||||||
|
wrapEval,
|
||||||
|
dynamicImport,
|
||||||
|
importDeclaration,
|
||||||
|
identifier,
|
||||||
|
unwrap,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export { property, wrapEval, dynamicImport, importDeclaration, identifier, unwrap };
|
|
1155
src/uv.handler.js
1155
src/uv.handler.js
File diff suppressed because it is too large
Load diff
893
src/uv.sw.js
893
src/uv.sw.js
File diff suppressed because it is too large
Load diff
|
@ -9,40 +9,46 @@ const isDevelopment = process.env.NODE_ENV !== 'production';
|
||||||
* @type {webpack.Configuration}
|
* @type {webpack.Configuration}
|
||||||
*/
|
*/
|
||||||
const config = {
|
const config = {
|
||||||
mode: isDevelopment ? 'development' : 'production',
|
mode: isDevelopment ? 'development' : 'production',
|
||||||
entry: {
|
entry: {
|
||||||
bundle: fileURLToPath(new URL('./src/rewrite/index.js', import.meta.url)),
|
bundle: fileURLToPath(
|
||||||
handler: fileURLToPath(new URL('./src/uv.handler.js', import.meta.url)),
|
new URL('./src/rewrite/index.js', import.meta.url)
|
||||||
sw: fileURLToPath(new URL('./src/uv.sw.js', import.meta.url)),
|
),
|
||||||
},
|
handler: fileURLToPath(new URL('./src/uv.handler.js', import.meta.url)),
|
||||||
output: {
|
sw: fileURLToPath(new URL('./src/uv.sw.js', import.meta.url)),
|
||||||
path: fileURLToPath(new URL('./dist/', import.meta.url)),
|
},
|
||||||
filename: 'uv.[name].js',
|
output: {
|
||||||
},
|
path: fileURLToPath(new URL('./dist/', import.meta.url)),
|
||||||
optimization: {
|
filename: 'uv.[name].js',
|
||||||
minimize: !isDevelopment,
|
},
|
||||||
minimizer: [
|
optimization: {
|
||||||
new TerserPlugin({
|
minimize: !isDevelopment,
|
||||||
exclude: ['sw.js', 'uv.config.js'],
|
minimizer: [
|
||||||
}),
|
new TerserPlugin({
|
||||||
],
|
exclude: ['sw.js', 'uv.config.js'],
|
||||||
},
|
}),
|
||||||
plugins: [
|
],
|
||||||
new CopyPlugin({
|
},
|
||||||
patterns: [
|
plugins: [
|
||||||
{
|
new CopyPlugin({
|
||||||
from: fileURLToPath(new URL('./src/uv.config.js', import.meta.url)),
|
patterns: [
|
||||||
},
|
{
|
||||||
{
|
from: fileURLToPath(
|
||||||
from: fileURLToPath(new URL('./src/sw.js', import.meta.url)),
|
new URL('./src/uv.config.js', import.meta.url)
|
||||||
},
|
),
|
||||||
],
|
},
|
||||||
}),
|
{
|
||||||
],
|
from: fileURLToPath(
|
||||||
performance: {
|
new URL('./src/sw.js', import.meta.url)
|
||||||
// suppress "entrypoint size limit" warning
|
),
|
||||||
hints: false,
|
},
|
||||||
},
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
performance: {
|
||||||
|
// suppress "entrypoint size limit" warning
|
||||||
|
hints: false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue