violentmonkey / violentmonkey

Violentmonkey provides userscripts support for browsers. It works on browsers with WebExtensions support.

Home Page:https://violentmonkey.github.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[BUG] Is it something wrong with this part of code?

cyfung1031 opened this issue · comments

bound: {
__proto__: null,
/** @this {GMContext} */
GM_deleteValue(key) {
const { id } = this;
const values = loadValues(id);
const oldRaw = values[key];
delete values[key];
// using `undefined` to match the documentation and TM for GM_addValueChangeListener
return dumpValue(id, key, undefined, null, oldRaw, this);
},
/** @this {GMContext} */
GM_getValue(key, def) {
const raw = loadValues(this.id)[key];
return resolveOrReturn(this, raw ? decodeValue(raw) : def);
},
/** @this {GMContext} */
GM_listValues() {
return resolveOrReturn(this, objectKeys(loadValues(this.id)));
},
/** @this {GMContext} */
GM_setValue(key, val) {
const { id } = this;
const raw = dumpScriptValue(val, jsonDump) || null;
const values = loadValues(id);
const oldRaw = values[key];
values[key] = raw;
return dumpValue(id, key, val, raw, oldRaw, this);
},
/**
* @callback GMValueChangeListener
* @param {String} key
* @param {?} oldValue - `undefined` means value was created
* @param {?} newValue - `undefined` means value was removed
* @param {boolean} remote - `true` means value was modified in another tab
*/
/**
* @this {GMContext}
* @param {String} key - name of the value to monitor
* @param {GMValueChangeListener} fn - callback
* @returns {String} listenerId
*/
GM_addValueChangeListener(key, fn) {
if (!isString(key)) key = `${key}`;
if (!isFunction(fn)) return;
const hooks = ensureNestedProp(changeHooks, this.id, key);
const i = objectValues(hooks)::indexOf(fn);
let listenerId = i >= 0 && objectKeys(hooks)[i];
if (!listenerId) {
listenerId = safeGetUniqId('VMvc');
hooks[listenerId] = fn;
}
return listenerId;
},
/**
* @this {GMContext}
* @param {String} listenerId
*/
GM_removeValueChangeListener(listenerId) {
const keyHooks = changeHooks[this.id];
if (!keyHooks) return;
if (process.env.DEBUG) throwIfProtoPresent(keyHooks);
for (const key in keyHooks) { /* proto is null */// eslint-disable-line guard-for-in
const hooks = keyHooks[key];
if (listenerId in hooks) {
delete hooks[listenerId];
if (isEmpty(hooks)) delete keyHooks[key];
break;
}
}
if (isEmpty(keyHooks)) delete changeHooks[this.id];
},
/** @this {GMContext} */
GM_getResourceText(name) {
return getResource(this, name);
},
GM_getResourceURL: gmGetResourceURL,
/** @this {GMContext} */
GM_registerMenuCommand(text, cb, opts) {
opts = nullObjFrom(opts);
opts.text = text = `${text}`;
if (!text) throw new SafeError('Menu caption text is required!');
const { id } = this;
const key = opts.id || text;
const cmd = ensureNestedProp(commands, id, key);
cmd.cb = cb;
cmd.text = text;
bridge.post('RegisterMenu', { id, key, val: opts });
return key;
},
/** @this {GMContext} */
GM_unregisterMenuCommand(key) {
const { id } = this;
const hub = commands[id];
if (hub && (hub[key] || (key = findCommandIdByText(key, hub)))) {
delete hub[key];
bridge.post('UnregisterMenu', { id, key });
}
},
/**
* @this {GMContext}
* @param {VMScriptGMDownloadOptions|string} opts
* @param {string} [name]
*/
GM_download(opts, name) {
if (isString(opts)) {
opts = { url: opts, name, __proto__: null };
} else if (opts) {
opts = nullObjFrom(opts);
name = opts.name;
}
if (!name ? (name = 'missing') : !isString(name) && (name = 'not a string')) {
onRequestInitError(opts, new SafeError(`Required parameter "name" is ${name}.`));
return;
}
assign(opts, {
[kResponseType]: 'blob',
data: null,
method: 'GET',
overrideMimeType: 'application/octet-stream',
});
return onRequestCreate(opts, this, name);
},
GM_notification: createNotification,
GM_xmlhttpRequest: gmXmlHttpRequest,
},

Screen Shot 2024-04-18 at 7 18 28

It seems that it created nested functions.
Or due to any object reference chain? (WeakRef should solve this case)

I don't see anything wrong. The memory snapshot doesn't show object hierarchy, it's not console.log.