mirror of
https://github.com/MercuryWorkshop/scramjet.git
synced 2025-05-13 14:30:02 -04:00
116 lines
3.9 KiB
TypeScript
116 lines
3.9 KiB
TypeScript
import { iswindow, isworker } from "..";
|
|
import { SCRAMJETCLIENT } from "../../symbols";
|
|
import { ScramjetClient } from "../client";
|
|
import { config } from "../shared";
|
|
|
|
export function createWrapFn(client: ScramjetClient, self: typeof globalThis) {
|
|
return function (identifier: any, args: any) {
|
|
if (args && typeof args === "object" && args.length === 0)
|
|
for (const arg of args) {
|
|
// argdbg(arg);
|
|
}
|
|
if (iswindow && identifier instanceof self.Window) {
|
|
return client.globalProxy;
|
|
} else if (iswindow && identifier instanceof self.parent.self.Window) {
|
|
if (SCRAMJETCLIENT in self.parent.self) {
|
|
// ... then we're in a subframe, and the parent frame is also in a proxy context, so we should return its proxy
|
|
return self.parent.self[SCRAMJETCLIENT].globalProxy;
|
|
} else {
|
|
// ... then we should pretend we aren't nested and return the current window
|
|
return client.globalProxy;
|
|
}
|
|
} else if (iswindow && identifier instanceof self.top.self.Window) {
|
|
// instead of returning top, we need to return the uppermost parent that's inside a scramjet context
|
|
let current = self.self;
|
|
|
|
for (;;) {
|
|
const test = current.parent.self;
|
|
if (test === current) break; // there is no parent, actual or emulated.
|
|
|
|
// ... then `test` represents a window outside of the proxy context, and therefore `current` is the topmost window in the proxy context
|
|
if (!(SCRAMJETCLIENT in test)) break;
|
|
|
|
// test is also insde a proxy, so we should continue up the chain
|
|
current = test;
|
|
}
|
|
|
|
return current[SCRAMJETCLIENT].globalProxy.window;
|
|
} else if (
|
|
(iswindow && identifier instanceof self.Location) ||
|
|
(isworker && identifier instanceof self.WorkerLocation)
|
|
) {
|
|
return client.locationProxy;
|
|
} else if (iswindow && identifier instanceof self.Document) {
|
|
return client.documentProxy;
|
|
} else if (isworker && identifier instanceof self.WorkerGlobalScope) {
|
|
return client.globalProxy;
|
|
}
|
|
|
|
return identifier;
|
|
};
|
|
}
|
|
|
|
export default function (client: ScramjetClient, self: typeof globalThis) {
|
|
// the main magic of the proxy. all attempts to access any "banned objects" will be redirected here, and instead served a proxy object
|
|
// this contrasts from how other proxies will leave the root object alone and instead attempt to catch every member access
|
|
// this presents some issues (see element.ts), but makes us a good bit faster at runtime!
|
|
Object.defineProperty(self, config.wrapfn, {
|
|
value: client.wrapfn,
|
|
writable: false,
|
|
configurable: false,
|
|
});
|
|
|
|
// location = "..." can't be rewritten as wrapfn(location) = ..., so instead it will actually be rewritten as
|
|
// ((t)=>$scramjet$tryset(location,"+=",t)||location+=t)(...);
|
|
// it has to be a discrete function because there's always the possibility that "location" is a local variable
|
|
// we have to use an IIFE to avoid duplicating side-effects in the getter
|
|
Object.defineProperty(self, config.trysetfn, {
|
|
value: function (lhs: any, op: string, rhs: any) {
|
|
if (lhs instanceof Location) {
|
|
// @ts-ignore
|
|
locationProxy.href = rhs;
|
|
|
|
return true;
|
|
}
|
|
},
|
|
writable: false,
|
|
configurable: false,
|
|
});
|
|
|
|
function argdbg(arg) {
|
|
switch (typeof arg) {
|
|
case "string":
|
|
if (arg.includes("scramjet") && !arg.includes("\n")) debugger;
|
|
break;
|
|
case "object":
|
|
if (arg instanceof Location) debugger;
|
|
if (
|
|
arg &&
|
|
arg[Symbol.iterator] &&
|
|
typeof arg[Symbol.iterator] === "function"
|
|
)
|
|
for (let ar of arg) argdbg(ar);
|
|
break;
|
|
}
|
|
}
|
|
self.$scramerr = function scramerr(e) {
|
|
console.warn("CAUGHT ERROR", e);
|
|
};
|
|
|
|
self.$scramdbg = function scramdbg(args, t) {
|
|
if (args && typeof args === "object" && args.length > 0) argdbg(args);
|
|
argdbg(t);
|
|
return t;
|
|
};
|
|
|
|
client.Proxy("Promise.prototype.catch", {
|
|
apply(ctx) {
|
|
ctx.args[0] = new Proxy(ctx.args[0], {
|
|
apply(target, thisArg, argArray) {
|
|
// console.warn("CAUGHT PROMISE REJECTION", argArray);
|
|
Reflect.apply(target, thisArg, argArray);
|
|
},
|
|
});
|
|
},
|
|
});
|
|
}
|