Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/app/repo/scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,12 @@ export interface ScriptSite {

export type ScriptAndCode = Script & ScriptCode;

export type ValueStore = { [key: string]: any };

// 脚本运行时的资源,包含已经编译好的脚本与脚本需要的资源
export interface ScriptRunResource extends Script {
code: string; // 原始代码
value: { [key: string]: any };
value: ValueStore;
flag: string;
resource: { [key: string]: { base64?: string } & Omit<Resource, "base64"> }; // 资源列表,包含脚本需要的资源
metadata: SCMetadata; // 经自定义覆盖的 Metadata
Expand Down
2 changes: 1 addition & 1 deletion src/app/service/content/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export default class ContentRuntime {
let parentNode: EventTarget | undefined;
// 判断是不是content脚本发过来的
let msg: CustomEventMessage;
if (this.contentScriptSet.has(data.uuid) || this.scriptExecutor.execMap.has(data.uuid)) {
if (this.contentScriptSet.has(data.uuid) || this.scriptExecutor.execScriptMap.has(data.uuid)) {
msg = this.scriptExecutorMsg;
} else {
msg = this.senderToInject;
Expand Down
21 changes: 18 additions & 3 deletions src/app/service/content/exec_script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import type { Message } from "@Packages/message/types";
import type { ValueUpdateDataEncoded } from "./types";
import { evaluateGMInfo } from "./gm_api/gm_info";
import type { IGM_Base } from "./gm_api/gm_api";
import type { TScriptInfo } from "@App/app/repo/scripts";
import type { ScriptRunResource, TScriptInfo } from "@App/app/repo/scripts";
import { getStorageName } from "@App/pkg/utils/utils";

// 执行脚本,控制脚本执行与停止
export default class ExecScript {
Expand Down Expand Up @@ -64,8 +65,22 @@ export default class ExecScript {
this.sandboxContext?.emitEvent(event, eventId, data);
}

valueUpdate(data: ValueUpdateDataEncoded) {
this.sandboxContext?.valueUpdate(data);
valueUpdate(storageName: string, uuid: string, responses: ValueUpdateDataEncoded[]) {
const scriptRes = this.scriptRes;
if (scriptRes.uuid === uuid || getStorageName(scriptRes) === storageName) {
const context = this.sandboxContext;
if (context) {
const contextScriptRes = context.scriptRes as ScriptRunResource | null | undefined;
if (contextScriptRes) {
if (uuid === contextScriptRes.uuid || storageName === getStorageName(contextScriptRes)) {
contextScriptRes.value = context.extValueStoreCopy || contextScriptRes.value;
const valueStore = contextScriptRes.value;
context.valueStoreUpdate(valueStore, responses);
context.extValueStoreCopy = { ...valueStore };
}
Comment on lines +75 to +80
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

valueUpdate 方法中,对 scriptRescontextScriptRes 进行了重复的 uuid 和 storageName 检查。由于外层已经检查了 scriptRes.uuid === uuid || getStorageName(scriptRes) === storageName,而 contextScriptRes 通常是 scriptRes 的引用或相同对象,内层的检查(第 75 行)是冗余的。建议移除内层重复检查,简化逻辑。

Suggested change
if (uuid === contextScriptRes.uuid || storageName === getStorageName(contextScriptRes)) {
contextScriptRes.value = context.extValueStoreCopy || contextScriptRes.value;
const valueStore = contextScriptRes.value;
context.valueStoreUpdate(valueStore, responses);
context.extValueStoreCopy = { ...valueStore };
}
contextScriptRes.value = context.extValueStoreCopy || contextScriptRes.value;
const valueStore = contextScriptRes.value;
context.valueStoreUpdate(valueStore, responses);
context.extValueStoreCopy = { ...valueStore };

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ScriptCat原本的奇葩设计我不在这PR处理

}
}
}
}

execContext: any;
Expand Down
131 changes: 81 additions & 50 deletions src/app/service/content/gm_api/gm_api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { compileScript, compileScriptCode } from "../utils";
import type { Message } from "@Packages/message/types";
import { encodeRValue } from "@App/pkg/utils/message_value";
import { v4 as uuidv4 } from "uuid";
import { getStorageName } from "@App/pkg/utils/utils";
const nilFn: ScriptFunc = () => {};

const scriptRes = {
Expand Down Expand Up @@ -123,10 +124,14 @@ describe.concurrent("GM Api", () => {
script.value = { test: "ok" };
script.metadata.grant = ["GM.getValue"];
script.code = `return GM.getValue("test").then(v=>v+"!");`;
// @ts-ignore
const exec = new ExecScript(script, undefined, undefined, nilFn, envInfo);
const mockSendMessage = vi.fn().mockResolvedValue({ code: 0 });
const mockMessage = {
sendMessage: mockSendMessage,
} as unknown as Message;
const exec = new ExecScript(script, "content", mockMessage, nilFn, envInfo);
exec.scriptFunc = compileScript(compileScriptCode(script));
const ret = await exec.exec();
const retPromise = exec.exec();
const ret = await retPromise;
expect(ret).toEqual("ok!");
});

Expand All @@ -135,10 +140,14 @@ describe.concurrent("GM Api", () => {
script.value = { test1: "23", test2: "45", test3: "67" };
script.metadata.grant = ["GM_listValues"];
script.code = `return GM_listValues().join("-");`;
// @ts-ignore
const exec = new ExecScript(script, undefined, undefined, nilFn, envInfo);
const mockSendMessage = vi.fn().mockResolvedValue({ code: 0 });
const mockMessage = {
sendMessage: mockSendMessage,
} as unknown as Message;
const exec = new ExecScript(script, "content", mockMessage, nilFn, envInfo);
exec.scriptFunc = compileScript(compileScriptCode(script));
const ret = await exec.exec();
const retPromise = exec.exec();
const ret = await retPromise;
expect(ret).toEqual("test1-test2-test3");
});

Expand All @@ -151,22 +160,30 @@ describe.concurrent("GM Api", () => {
script.value.test1 = "40";
script.metadata.grant = ["GM_listValues"];
script.code = `return GM_listValues().join("-");`;
// @ts-ignore
const exec = new ExecScript(script, undefined, undefined, nilFn, envInfo);
const mockSendMessage = vi.fn().mockResolvedValue({ code: 0 });
const mockMessage = {
sendMessage: mockSendMessage,
} as unknown as Message;
const exec = new ExecScript(script, "content", mockMessage, nilFn, envInfo);
exec.scriptFunc = compileScript(compileScriptCode(script));
const ret = await exec.exec();
expect(ret).toEqual("test5-test2-test3-test1"); // TM也沒有sort
const retPromise = exec.exec();
const ret = await retPromise;
expect(ret).toEqual("test5-test2-test3-test1"); // TM也没有sort
});

it.concurrent("GM.listValues", async () => {
const script = Object.assign({}, scriptRes) as ScriptLoadInfo;
script.value = { test1: "23", test2: "45", test3: "67" };
script.metadata.grant = ["GM.listValues"];
script.code = `return GM.listValues().then(v=>v.join("-"));`;
// @ts-ignore
const exec = new ExecScript(script, undefined, undefined, nilFn, envInfo);
const mockSendMessage = vi.fn().mockResolvedValue({ code: 0 });
const mockMessage = {
sendMessage: mockSendMessage,
} as unknown as Message;
const exec = new ExecScript(script, "content", mockMessage, nilFn, envInfo);
exec.scriptFunc = compileScript(compileScriptCode(script));
const ret = await exec.exec();
const retPromise = exec.exec();
const ret = await retPromise;
expect(ret).toEqual("test1-test2-test3");
});

Expand All @@ -179,11 +196,15 @@ describe.concurrent("GM Api", () => {
script.value.test1 = "40";
script.metadata.grant = ["GM.listValues"];
script.code = `return GM.listValues().then(v=>v.join("-"));`;
// @ts-ignore
const exec = new ExecScript(script, undefined, undefined, nilFn, envInfo);
const mockSendMessage = vi.fn().mockResolvedValue({ code: 0 });
const mockMessage = {
sendMessage: mockSendMessage,
} as unknown as Message;
const exec = new ExecScript(script, "content", mockMessage, nilFn, envInfo);
exec.scriptFunc = compileScript(compileScriptCode(script));
const ret = await exec.exec();
expect(ret).toEqual("test5-test2-test3-test1"); // TM也沒有sort
const retPromise = exec.exec();
const ret = await retPromise;
expect(ret).toEqual("test5-test2-test3-test1"); // TM也没有sort
});

it.concurrent("GM_getValues", async () => {
Expand Down Expand Up @@ -212,10 +233,14 @@ describe.concurrent("GM Api", () => {
script.value = { test1: "23", test2: 45, test3: "67" };
script.metadata.grant = ["GM.getValues"];
script.code = `return GM.getValues(["test2", "test3", "test1"]).then(v=>v);`;
// @ts-ignore
const exec = new ExecScript(script, undefined, undefined, nilFn, envInfo);
const mockSendMessage = vi.fn().mockResolvedValue({ code: 0 });
const mockMessage = {
sendMessage: mockSendMessage,
} as unknown as Message;
const exec = new ExecScript(script, "content", mockMessage, nilFn, envInfo);
exec.scriptFunc = compileScript(compileScriptCode(script));
const ret = await exec.exec();
const retPromise = exec.exec();
const ret = await retPromise;
expect(ret.test1).toEqual("23");
expect(ret.test2).toEqual(45);
expect(ret.test3).toEqual("67");
Expand Down Expand Up @@ -499,7 +524,7 @@ describe.concurrent("GM_value", () => {
api: "GM_setValues",
params: [
// event id
expect.stringMatching(/^.+::\d$/),
expect.stringMatching(/^.+::\d+$/),
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.3 在这PR修正了问题 (虽然这个PR一直未被合并)

// the object payload
keyValuePairs1,
],
Expand All @@ -523,7 +548,7 @@ describe.concurrent("GM_value", () => {
api: "GM_setValues",
params: [
// event id
expect.stringMatching(/^.+::\d$/),
expect.stringMatching(/^.+::\d+$/),
// the object payload
keyValuePairs2,
],
Expand Down Expand Up @@ -573,7 +598,7 @@ describe.concurrent("GM_value", () => {
api: "GM_setValues",
params: [
// event id
expect.stringMatching(/^.+::\d$/),
expect.stringMatching(/^.+::\d+$/),
// the object payload
keyValuePairs1,
],
Expand All @@ -592,7 +617,7 @@ describe.concurrent("GM_value", () => {
api: "GM_setValue",
params: [
// event id
expect.stringMatching(/^.+::\d$/),
expect.stringMatching(/^.+::\d+$/),
// the string payload
"b",
],
Expand Down Expand Up @@ -643,7 +668,7 @@ describe.concurrent("GM_value", () => {
api: "GM_setValues",
params: [
// event id
expect.stringMatching(/^.+::\d$/),
expect.stringMatching(/^.+::\d+$/),
// the object payload
keyValuePairs1,
],
Expand All @@ -667,7 +692,7 @@ describe.concurrent("GM_value", () => {
api: "GM_setValues",
params: [
// event id
expect.stringMatching(/^.+::\d$/),
expect.stringMatching(/^.+::\d+$/),
// the string payload
keyValuePairs2,
],
Expand Down Expand Up @@ -702,14 +727,16 @@ describe.concurrent("GM_value", () => {
const retPromise = exec.exec();
expect(mockSendMessage).toHaveBeenCalledTimes(1);
// 模拟值变化
exec.valueUpdate({
id: "id-1",
entries: [["param1", encodeRValue(123), encodeRValue(undefined)]],
uuid: script.uuid,
storageName: script.uuid,
sender: { runFlag: exec.sandboxContext!.runFlag, tabId: -2 },
valueUpdated: true,
});
exec.valueUpdate(getStorageName(script), script.uuid, [
{
id: "id-1",
valueChanges: [["param1", encodeRValue(123), encodeRValue(undefined)]],
uuid: script.uuid,
storageName: script.uuid,
sender: { runFlag: exec.sandboxContext!.runFlag, tabId: -2 },
updatetime: Date.now(),
},
]);
const ret = await retPromise;
expect(ret).toEqual({ name: "param1", oldValue: undefined, newValue: 123, remote: false });
});
Expand Down Expand Up @@ -737,14 +764,16 @@ describe.concurrent("GM_value", () => {
const retPromise = exec.exec();
expect(mockSendMessage).toHaveBeenCalledTimes(1);
// 模拟值变化
exec.valueUpdate({
id: "id-2",
entries: [["param2", encodeRValue(456), encodeRValue(undefined)]],
uuid: script.uuid,
storageName: "testStorage",
sender: { runFlag: "user", tabId: -2 },
valueUpdated: true,
});
exec.valueUpdate(getStorageName(script), script.uuid, [
{
id: "id-2",
valueChanges: [["param2", encodeRValue(456), encodeRValue(undefined)]],
uuid: script.uuid,
storageName: "testStorage",
sender: { runFlag: "user", tabId: -2 },
updatetime: Date.now(),
},
]);
const ret2 = await retPromise;
expect(ret2).toEqual({ name: "param2", oldValue: undefined, newValue: 456, remote: true });
});
Expand Down Expand Up @@ -772,14 +801,16 @@ describe.concurrent("GM_value", () => {
expect(id).toBeTypeOf("string");
expect(id.length).greaterThan(0);
// 触发valueUpdate
exec.valueUpdate({
id: id,
entries: [["a", encodeRValue(123), encodeRValue(undefined)]],
uuid: script.uuid,
storageName: script.uuid,
sender: { runFlag: exec.sandboxContext!.runFlag, tabId: -2 },
valueUpdated: true,
});
exec.valueUpdate(getStorageName(script), script.uuid, [
{
id: id,
valueChanges: [["a", encodeRValue(123), encodeRValue(undefined)]],
uuid: script.uuid,
storageName: script.uuid,
sender: { runFlag: exec.sandboxContext!.runFlag, tabId: -2 },
updatetime: Date.now(),
},
]);

const ret = await retPromise;
expect(ret).toEqual(123);
Expand Down
Loading
Loading