/* Place this inside an Inspector Bootstrap Script <https://webkit.org/web-inspector/inspector-bootstrap-script/> and use local overrides <https://webkit.org/web-inspector/local-overrides/> to call these functions when needed. */
(function() {
const console_log = console.log;
const console_trace = console.trace;
const Reflect_apply = Reflect.apply;
const Reflect_construct = Reflect.construct;
const Reflect_defineProperty = Reflect.defineProperty;
const Reflect_deleteProperty = Reflect.deleteProperty;
const Reflect_get = Reflect.get;
const Reflect_getOwnPropertyDescriptor = Reflect.getOwnPropertyDescriptor;
const Reflect_getPrototypeOf = Reflect.getPrototypeOf;
const Reflect_has = Reflect.has;
const Reflect_isExtensible = Reflect.isExtensible;
const Reflect_ownKeys = Reflect.ownKeys;
const Reflect_preventExtensions = Reflect.preventExtensions;
const Reflect_set = Reflect.set;
const Reflect_setPrototypeOf = Reflect.setPrototypeOf;
const Object_getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
const Object_defineProperty = Object.defineProperty;
const Proxy_constructor = Proxy;
const Promise_constructor = Promise;
const Array_isArray = Array.isArray;
const Array_prototype_push = Array.prototype.push;
const Array_prototype_includes = Array.prototype.includes;
const Set_constructor = Set;
const Set_prototype_has = Set.prototype.has;
function forward(func, data = []) {
return function(...args) {
debugger;
let result = (func.prototype && func.prototype.constructor.name) ? Reflect_construct(func, args) : Reflect_apply(func, this, args);
// console_trace([...data, result, this, ...arguments]);
return result;
};
}
/* Replaces a specific `property` on the given `object` such that invoking the property, fetching it, or modifying it will log a backtrace in Web Inspector and pause using the Debugger Statements global breakpoint. */
/* This can be overridden if `Object.defineProperty` is called with the same `object` and `property`. */
globalThis.REPLACE = function(object, property) {
let original = Object_getOwnPropertyDescriptor(object, property);
if (!original)
throw `Property '${property}' missing on ${object}`;
if (!original.configurable)
throw `Property '${property}' is not configurable on ${object}`;
let replaced = {};
if ("enumerable" in original)
replaced.enumerable = original.enumerable;
if ("value" in original && typeof original.value !== "function") {
let symbol = Symbol("replaced-property-" + property);
object[symbol] = original.value;
replaced.get = function() {
debugger;
// console_trace([this, property, "get", this[symbol]]);
return this[symbol];
};
replaced.set = function(value) {
debugger;
// console_trace([this, property, "set", value]);
this[symbol] = value;
};
} else {
if ("writable" in original)
replaced.writable = original.writable;
for (let key in original) {
if (key === "get" || key === "set" || key === "value") {
replaced[key] = forward(original[key], [property, key]);
continue;
}
replaced[key] = original[key];
}
}
return Object_defineProperty(object, property, replaced);
};
/* Watches a given object (either directly or via a given `key` on a given `owner`) such that any operation performed on/with that object will log a backtrace in Web Inspector and pause using the Debugger Statements global breakpoint. */
/* Comment/Uncomment any of the functions below if the log output is too noisy or execution pausing is too frequent. */
globalThis.WATCH = function(owner, key) {
if (arguments.length === 1) {
key = "<direct>";
owner = {[key]: owner};
}
return owner[key] = new Proxy_constructor(owner[key], {
/* The object is invoked as a function. */
apply(target, thisArgument, argumentsList) {
debugger;
let result = Reflect_apply(target, thisArgument, argumentsList);
// console_trace({target, trap: "apply", thisArgument, argumentsList, result});
return result;
},
/* The object is invoked as a constructor using the `new` operator. */
construct(target, argumentsList, newTarget) {
debugger;
let result = Reflect_construct(target, argumentsList, newTarget);
// console_trace({target, trap: "construct", argumentsList, newTarget, result});
return result;
},
/* A property is defined on the object using `Object.defineProperty` (user explicit and engine implicit). */
defineProperty(target, propertyKey, attributes) {
debugger;
let result = Reflect_defineProperty(target, propertyKey, attributes);
// console_trace({target, trap: "defineProperty", propertyKey, attributes, result});
return result;
},
/* A property is deleted from the object using the `delete` operator. */
deleteProperty(target, propertyKey) {
debugger;
let result = Reflect_deleteProperty(target, propertyKey);
// console_trace({target, trap: "deleteProperty", propertyKey, result});
return result;
},
/* The value for a property is fetched from the object (including it's prototype chain). */
get(target, propertyKey, receiver) {
debugger;
let result = Reflect_get(target, propertyKey, receiver);
// console_trace({target, trap: "get", propertyKey, receiver, result});
return result;
},
/* An own property descriptor is fetched from the object using `Object.getOwnPropertyDescriptor` (user explicit and engine implicit). */
// getOwnPropertyDescriptor(target, propertyKey) {
// debugger;
// let result = Reflect_getOwnPropertyDescriptor(target, propertyKey);
// // console_trace({target, trap: "getOwnPropertyDescriptor", propertyKey, result});
// return result;
// },
/* The prototype of the object is fetched using `Object.getPrototypeOf` (user explicit and engine implicit). */
// getPrototypeOf(target) {
// debugger;
// let result = Reflect_getPrototypeOf(target);
// // console_trace({target, trap: "getPrototypeOf", result});
// return result;
// },
/* The existence of property in the object is queried using the `in` operator (user explicit and engine implicit). */
// has(target, propertyKey) {
// debugger;
// let result = Reflect_has(target, propertyKey);
// // console_trace({target, trap: "has", propertyKey, result});
// return result;
// },
/* The extensibility state of the object is fetched using `Object.isExtensible` (user explicit and engine implicit). */
// isExtensible(target) {
// debugger;
// let result = Reflect_isExtensible(target);
// // console_trace({target, trap: "isExtensible", result});
// return result;
// },
/* The own properties of the object is fetched using `Object.getOwnPropertyNames` (user explicit and engine implicit) or `Object.getOwnPropertySymbols` (user explicit and engine implicit). */
// ownKeys(target) {
// debugger;
// let result = Reflect_ownKeys(target);
// // console_trace({target, trap: "ownKeys", result});
// return result;
// },
/* A request is made to prevent extensions to the object using `Object.preventExtensions` (user explicit and engine implicit). */
preventExtensions(target) {
debugger;
let result = Reflect_preventExtensions(target);
// console_trace({target, trap: "preventExtensions", result});
return result;
},
/* The value for a property in the object is changed. */
set(target, propertyKey, value, receiver) {
debugger;
let result = Reflect_set(target, propertyKey, value, receiver);
// console_trace({target, trap: "set", propertyKey, value, receiver, result});
return result;
},
/* The prototype of the object is changed using `Object.setPrototypeOf` (user explicit and engine implicit). */
setPrototypeOf(target, prototype) {
debugger;
let result = Reflect_setPrototypeOf(target, prototype);
// console_trace({target, trap: "setPrototypeOf", prototype, result});
return result;
},
});
};
// globalThis.Promise = function(executor) {
// return Reflect_construct(Promise_constructor, [function(resolve, reject) {
// return executor(forward(resolve), forward(reject));
// }]);
// };
/* DOM */
if (window) {
const Event_prototype_stopPropagation = Event.prototype.stopPropagation;
const Event_prototype_stopImmediatePropagation = Event.prototype.stopImmediatePropagation;
/* Add event types/names to the array on the line below and: */
/* - set `window.EVENT_LOG = true` to log details about those events to the console. */
/* - set `window.EVENT_LOG = []` to save details from each event into an array for later use. */
for (let type of []) {
window.addEventListener(type, (event) => {
if (window.EVENT_LOG === true)
console_log("EVENT", type, event.pageX, event.pageY, event.target);
else if (Reflect_apply(Array_isArray, undefined, [window.EVENT_LOG]))
Reflect_apply(Array_prototype_push, window.EVENT_LOG, [{type, x: event.pageX, y: event.pageY, target: event.target}]);
}, {capture: true});
}
/* Add event types/names to the array on the line below to completely disable those events when `window.DISABLE_EVENTS = true`. */
for (let type of []) {
window.addEventListener(type, (event) => {
if (window.DISABLE_EVENTS === true || (Reflect_apply(Array_isArray, undefined, [window.DISABLE_EVENTS]) && Reflect_apply(Array_prototype_includes, window.DISABLE_EVENTS, [type])) || (window.DISABLE_EVENTS instanceof Set_constructor && Reflect_apply(Set_prototype_has, window.DISABLE_EVENTS, [type]))) {
Reflect_apply(Event_prototype_stopPropagation, event, []);
Reflect_apply(Event_prototype_stopImmediatePropagation, event, []);
}
}, {capture: true});
}
}
})();