Skip to content

Instantly share code, notes, and snippets.

@bathos
Created July 6, 2021 15:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save bathos/bbf1344d0c78bdc1d0ee4ef4a5dbf42c to your computer and use it in GitHub Desktop.
Save bathos/bbf1344d0c78bdc1d0ee4ef4a5dbf42c to your computer and use it in GitHub Desktop.
moplogger.js
// This is useful for a few things:
//
// 1. Checking what dictionary options are supported by some platform API.
// 2. Debugging mysterious cases where an object you pass as input to another
// API doesn’t seem to get treated the way you’re expecting.
// 3. When designing another Proxy’s handler implementation, verifying that you
// are accounting for everything correctly and that the intended abstraction
// isn’t leaking in quirky ways.
//
// ex:
//
// navigator.credentials.get(new Moplogger('CredentialsRequestOptions', {
// mediation: 'silent',
// password: true
// }));
let {
apply, construct, defineProperty, deleteProperty, get,
getOwnPropertyDescriptor, getPrototypeOf, has, isExtensible, ownKeys,
preventExtensions, set, setPrototypeOf
} = Reflect;
class Moplogger {
#name = '';
constructor(name, obj) {
this.#name = `${ name }`;
return new Proxy(obj, this);
}
apply() {
return this.#log('Call', apply, arguments);
}
construct() {
return this.#log('Construct', construct, arguments);
}
defineProperty() {
return this.#log('DefineOwnProperty', defineProperty, arguments);
}
deleteProperty() {
return this.#log('Delete', deleteProperty, arguments);
}
get() {
return this.#log('Get', get, arguments);
}
getOwnPropertyDescriptor() {
return this.#log('GetOwnProperty', getOwnPropertyDescriptor, arguments);
}
getPrototypeOf() {
return this.#log('GetPrototypeOf', getPrototypeOf, arguments);
}
has() {
return this.#log('HasProperty', has, arguments);
}
isExtensible() {
return this.#log('IsExtensible', isExtensible, arguments);
}
ownKeys() {
return this.#log('OwnPropertyKeys', ownKeys, arguments);
}
preventExtensions() {
return this.#log('PreventExtensions', preventExtensions, arguments);
}
set() {
return this.#log('Set', set, arguments);
}
setPrototypeOf() {
return this.#log('SetPrototypeOf', setPrototypeOf, arguments);
}
#log(mop, op, args) {
let completion, value;
try {
value = apply(op, null, args);
completion = 'NormalCompletion';
} catch (err) {
value = err;
completion = 'AbruptCompletion';
}
console.debug(
`%c${ this.#name }%c.[[%c${ mop }%c]]` +
`(%c${ [ ...args ].slice(1).map(this.#serialize, this).join(', ') }%c)` +
`%c → %c${ completion }(%c${ this.#serialize(value) }%c)`,
`color: highlight; font-weight:bold;`,
`color: graytext;`,
`color: highlight;`,
`color: graytext;`,
`font-style: italic;`,
`color: graytext;`,
`color: highlight;`,
`color: graytext;`,
`font-style: italic;`,
`color: graytext`
);
if (completion === 'NormalCompletion') {
return value;
} else {
throw value;
}
}
#serialize(value) {
switch (typeof value) {
case 'bigint': return `${ value }n`;
case 'boolean': return `${ value }`;
case 'number': return `${ value }`;
case 'string': return JSON.stringify(value);
case 'symbol': return String(value);
case 'undefined': return 'undefined';
}
if (value === null) {
return 'null';
} else {
return '<object>';
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment