mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
chore(lint): enable structured clone rules
This commit is contained in:
@@ -52,7 +52,9 @@
|
||||
"eslint/unicode-bom": "error",
|
||||
"eslint/yoda": "error",
|
||||
"import/no-absolute-path": "error",
|
||||
"import/first": "error",
|
||||
"import/no-empty-named-blocks": "error",
|
||||
"import/no-duplicates": "error",
|
||||
"import/no-self-import": "error",
|
||||
"node/no-exports-assign": "error",
|
||||
"eslint-plugin-unicorn/prefer-set-size": "error",
|
||||
@@ -81,7 +83,7 @@
|
||||
"typescript/no-unnecessary-type-constraint": "error",
|
||||
"typescript/no-unnecessary-type-conversion": "error",
|
||||
"typescript/no-unnecessary-type-parameters": "error",
|
||||
"typescript/no-unsafe-type-assertion": "off",
|
||||
"typescript/no-unsafe-type-assertion": "error",
|
||||
"typescript/no-useless-default-assignment": "error",
|
||||
"typescript/no-useless-empty-export": "error",
|
||||
"typescript/no-wrapper-object-types": "error",
|
||||
@@ -134,6 +136,8 @@
|
||||
"unicorn/prefer-prototype-methods": "error",
|
||||
"unicorn/prefer-regexp-test": "error",
|
||||
"unicorn/prefer-set-size": "error",
|
||||
"unicorn/prefer-set-has": "error",
|
||||
"unicorn/prefer-structured-clone": "error",
|
||||
"unicorn/prefer-string-starts-ends-with": "error",
|
||||
"unicorn/prefer-string-slice": "error",
|
||||
"unicorn/require-array-join-separator": "error",
|
||||
|
||||
@@ -16,12 +16,12 @@ function inMemoryIO(
|
||||
} {
|
||||
const store: CodexPluginsConfigBlock = {
|
||||
enabled: options.enabled,
|
||||
plugins: JSON.parse(JSON.stringify(initial)),
|
||||
plugins: structuredClone(initial),
|
||||
};
|
||||
return {
|
||||
current: () => JSON.parse(JSON.stringify(store.plugins ?? {})),
|
||||
currentConfig: () => JSON.parse(JSON.stringify(store)),
|
||||
readConfig: () => Promise.resolve(JSON.parse(JSON.stringify(store))),
|
||||
current: () => structuredClone(store.plugins ?? {}),
|
||||
currentConfig: () => structuredClone(store),
|
||||
readConfig: () => Promise.resolve(structuredClone(store)),
|
||||
mutate: async (update) => {
|
||||
update(store);
|
||||
},
|
||||
|
||||
@@ -112,12 +112,12 @@ function inMemoryCodexPluginsIO(
|
||||
} {
|
||||
const store: CodexPluginsConfigBlock = {
|
||||
enabled: options.enabled,
|
||||
plugins: JSON.parse(JSON.stringify(initial)),
|
||||
plugins: structuredClone(initial),
|
||||
};
|
||||
return {
|
||||
current: () => JSON.parse(JSON.stringify(store.plugins ?? {})),
|
||||
currentConfig: () => JSON.parse(JSON.stringify(store)),
|
||||
readConfig: () => Promise.resolve(JSON.parse(JSON.stringify(store))),
|
||||
current: () => structuredClone(store.plugins ?? {}),
|
||||
currentConfig: () => structuredClone(store),
|
||||
readConfig: () => Promise.resolve(structuredClone(store)),
|
||||
mutate: async (update) => {
|
||||
update(store);
|
||||
},
|
||||
|
||||
@@ -8,6 +8,11 @@ import {
|
||||
} from "./inbound-job.js";
|
||||
import { createBaseDiscordMessageContext } from "./message-handler.test-harness.js";
|
||||
|
||||
function jsonRoundTrip<T>(value: T): T {
|
||||
const serialized = JSON.stringify(value);
|
||||
return JSON.parse(serialized) as T;
|
||||
}
|
||||
|
||||
describe("buildDiscordInboundJob", () => {
|
||||
it("prefers route session key, then base session key, then channel id for queueing", async () => {
|
||||
const routed = await createBaseDiscordMessageContext({
|
||||
@@ -88,7 +93,7 @@ describe("buildDiscordInboundJob", () => {
|
||||
},
|
||||
ownerId: "user-1",
|
||||
});
|
||||
const serializedPayload = JSON.parse(JSON.stringify(job.payload));
|
||||
const serializedPayload = jsonRoundTrip(job.payload);
|
||||
expect(serializedPayload.threadChannel).toEqual({
|
||||
id: "thread-1",
|
||||
name: "codex",
|
||||
@@ -125,7 +130,7 @@ describe("buildDiscordInboundJob", () => {
|
||||
parent: undefined,
|
||||
ownerId: undefined,
|
||||
});
|
||||
const serializedPayload = JSON.parse(JSON.stringify(job.payload));
|
||||
const serializedPayload = jsonRoundTrip(job.payload);
|
||||
expect(serializedPayload.threadChannel).toEqual({
|
||||
id: "thread-1",
|
||||
});
|
||||
|
||||
@@ -842,7 +842,8 @@ function resolveGoogleGemini3RetryThinkingLevel(modelId: string): GoogleThinking
|
||||
function cloneGoogleGenerateContentRequest(
|
||||
params: GoogleGenerateContentRequest,
|
||||
): GoogleGenerateContentRequest {
|
||||
return JSON.parse(JSON.stringify(params)) as GoogleGenerateContentRequest;
|
||||
const serialized = JSON.stringify(params);
|
||||
return JSON.parse(serialized) as GoogleGenerateContentRequest;
|
||||
}
|
||||
|
||||
export function buildGoogleGemini3FirstResponseRetryParams(params: {
|
||||
|
||||
@@ -192,7 +192,8 @@ async function loadBindingsFromPluginState(params: {
|
||||
}
|
||||
|
||||
function toPluginJsonValue<T>(value: T): T {
|
||||
return JSON.parse(JSON.stringify(value)) as T;
|
||||
const serialized = JSON.stringify(value);
|
||||
return JSON.parse(serialized) as T;
|
||||
}
|
||||
|
||||
async function persistBindingsSnapshot(params: {
|
||||
|
||||
@@ -41,7 +41,8 @@ export function resolveMSTeamsSqliteStateEnv(
|
||||
}
|
||||
|
||||
export function toPluginJsonValue<T>(value: T): T {
|
||||
return JSON.parse(JSON.stringify(value)) as T;
|
||||
const serialized = JSON.stringify(value);
|
||||
return JSON.parse(serialized) as T;
|
||||
}
|
||||
|
||||
export function resolveMSTeamsSqliteStateDir(
|
||||
|
||||
@@ -358,7 +358,7 @@ function extractLiveDockerPackageScripts(packageJson) {
|
||||
}
|
||||
|
||||
function stripLiveDockerPackageScripts(packageJson) {
|
||||
const clone = JSON.parse(JSON.stringify(packageJson));
|
||||
const clone = structuredClone(packageJson);
|
||||
const scripts = clone.scripts;
|
||||
if (!scripts || typeof scripts !== "object" || Array.isArray(scripts)) {
|
||||
return clone;
|
||||
@@ -377,7 +377,7 @@ function extractPackageScripts(packageJson) {
|
||||
}
|
||||
|
||||
function stripPackageScripts(packageJson) {
|
||||
const clone = JSON.parse(JSON.stringify(packageJson));
|
||||
const clone = structuredClone(packageJson);
|
||||
delete clone.scripts;
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -295,7 +295,8 @@ function toJsonSafe(value: unknown): unknown {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return JSON.parse(JSON.stringify(value)) as unknown;
|
||||
const serialized = JSON.stringify(value);
|
||||
return serialized === undefined ? null : (JSON.parse(serialized) as unknown);
|
||||
} catch {
|
||||
if (value instanceof Error) {
|
||||
return { name: value.name, message: value.message };
|
||||
|
||||
@@ -271,7 +271,8 @@ function toJsonSafe(value: unknown): unknown {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return JSON.parse(JSON.stringify(value)) as unknown;
|
||||
const serialized = JSON.stringify(value);
|
||||
return serialized === undefined ? null : (JSON.parse(serialized) as unknown);
|
||||
} catch {
|
||||
if (value instanceof Error) {
|
||||
return { name: value.name, message: value.message };
|
||||
|
||||
@@ -146,7 +146,8 @@ function toJsonSafe(value: unknown): unknown {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return JSON.parse(JSON.stringify(value)) as unknown;
|
||||
const serialized = JSON.stringify(value);
|
||||
return serialized === undefined ? null : (JSON.parse(serialized) as unknown);
|
||||
} catch {
|
||||
if (value instanceof Error) {
|
||||
return { name: value.name, message: value.message };
|
||||
|
||||
@@ -111,7 +111,8 @@ function cloneDiagnosticContentValue(value: unknown): unknown {
|
||||
return structuredClone(value);
|
||||
} catch {
|
||||
try {
|
||||
return JSON.parse(JSON.stringify(value)) as unknown;
|
||||
const serialized = JSON.stringify(value);
|
||||
return serialized === undefined ? null : (JSON.parse(serialized) as unknown);
|
||||
} catch {
|
||||
return String(value);
|
||||
}
|
||||
|
||||
@@ -1344,7 +1344,8 @@ function toJsonSafe(value: unknown): unknown {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return JSON.parse(JSON.stringify(value)) as unknown;
|
||||
const serialized = JSON.stringify(value);
|
||||
return serialized === undefined ? null : (JSON.parse(serialized) as unknown);
|
||||
} catch {
|
||||
if (value instanceof Error) {
|
||||
return value.message;
|
||||
|
||||
@@ -22,6 +22,11 @@ import { makeZeroUsageSnapshot } from "../usage.js";
|
||||
import { testing, createImageTool, resolveImageModelConfigForTool } from "./image-tool.js";
|
||||
import { resolveMediaToolInboundRoots } from "./media-tool-shared.js";
|
||||
|
||||
function jsonRoundTrip<T>(value: T): T {
|
||||
const serialized = JSON.stringify(value);
|
||||
return JSON.parse(serialized) as T;
|
||||
}
|
||||
|
||||
const publicSurfaceLoaderMocks = vi.hoisted(() => ({
|
||||
loadBundledPluginPublicArtifactModuleSync: vi.fn(
|
||||
({ artifactBasename, dirName }: { artifactBasename: string; dirName: string }) => {
|
||||
@@ -1685,7 +1690,7 @@ describe("image tool implicit imageModel config", () => {
|
||||
|
||||
it("keeps an Anthropic-safe image schema snapshot", async () => {
|
||||
await withMinimaxImageToolFromTempAgentDir(async (tool) => {
|
||||
expect(JSON.parse(JSON.stringify(tool.parameters))).toEqual({
|
||||
expect(jsonRoundTrip(tool.parameters)).toEqual({
|
||||
type: "object",
|
||||
properties: {
|
||||
prompt: { type: "string" },
|
||||
|
||||
@@ -7,6 +7,11 @@ import {
|
||||
const DREAMING_TOKEN = "__openclaw_memory_core_short_term_promotion_dream__";
|
||||
const DREAMING_TAG = "[managed-by=memory-core.short-term-promotion]";
|
||||
|
||||
function jsonRoundTrip<T>(value: T): T {
|
||||
const serialized = JSON.stringify(value);
|
||||
return JSON.parse(serialized) as T;
|
||||
}
|
||||
|
||||
function staleDreamingJob() {
|
||||
return {
|
||||
id: "job-1",
|
||||
@@ -99,7 +104,7 @@ describe("migrateLegacyDreamingPayloadShape", () => {
|
||||
wakeMode: "now",
|
||||
payload: { kind: "agentTurn", message: "good morning" },
|
||||
} as Record<string, unknown>;
|
||||
const snapshot = JSON.parse(JSON.stringify(unrelated)) as Record<string, unknown>;
|
||||
const snapshot = jsonRoundTrip(unrelated) as Record<string, unknown>;
|
||||
const jobs = [unrelated];
|
||||
const result = migrateLegacyDreamingPayloadShape(jobs);
|
||||
expect(result).toEqual({ changed: false, rewrittenCount: 0 });
|
||||
|
||||
@@ -19,6 +19,11 @@ vi.mock("../config/config.js", () => ({
|
||||
|
||||
const ORIGINAL_STATE_DIR = process.env.OPENCLAW_STATE_DIR;
|
||||
|
||||
function jsonRoundTrip<T>(value: T): T {
|
||||
const serialized = JSON.stringify(value);
|
||||
return JSON.parse(serialized) as T;
|
||||
}
|
||||
|
||||
function createRuntime(): RuntimeEnv {
|
||||
return {
|
||||
log: vi.fn(),
|
||||
@@ -95,8 +100,8 @@ describe("flows commands", () => {
|
||||
status: "blocked",
|
||||
flows: [
|
||||
{
|
||||
...JSON.parse(JSON.stringify(flow)),
|
||||
tasks: [JSON.parse(JSON.stringify(childTask))],
|
||||
...jsonRoundTrip(flow),
|
||||
tasks: [jsonRoundTrip(childTask)],
|
||||
taskSummary: {
|
||||
total: 1,
|
||||
active: 1,
|
||||
|
||||
@@ -28,6 +28,11 @@ function readJsonLog(runtime: RuntimeEnv): unknown {
|
||||
return JSON.parse(String(call[0]));
|
||||
}
|
||||
|
||||
function jsonRoundTrip<T>(value: T): T {
|
||||
const serialized = JSON.stringify(value);
|
||||
return JSON.parse(serialized) as T;
|
||||
}
|
||||
|
||||
async function withTaskJsonStateDir(run: () => Promise<void>): Promise<void> {
|
||||
await withOpenClawTestState(
|
||||
{ layout: "state-only", prefix: "openclaw-tasks-json-command-" },
|
||||
@@ -84,7 +89,7 @@ describe("tasks JSON commands", () => {
|
||||
count: 1,
|
||||
runtime: "cli",
|
||||
status: "running",
|
||||
tasks: [JSON.parse(JSON.stringify(cliTask))],
|
||||
tasks: [jsonRoundTrip(cliTask)],
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -170,7 +175,7 @@ describe("tasks JSON commands", () => {
|
||||
ageMs: 45 * 60_000,
|
||||
status: "running",
|
||||
token: runningFlow.flowId,
|
||||
flow: JSON.parse(JSON.stringify(runningFlow)),
|
||||
flow: jsonRoundTrip(runningFlow),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -31,6 +31,11 @@ function readFirstJsonLog(runtime: RuntimeEnv): unknown {
|
||||
return JSON.parse(String(message));
|
||||
}
|
||||
|
||||
function jsonRoundTrip<T>(value: T): T {
|
||||
const serialized = JSON.stringify(value);
|
||||
return JSON.parse(serialized) as T;
|
||||
}
|
||||
|
||||
const zeroTaskAuditCounts = {
|
||||
delivery_failed: 0,
|
||||
inconsistent_timestamps: 0,
|
||||
@@ -137,7 +142,7 @@ describe("tasks commands", () => {
|
||||
ageMs: 45 * 60_000,
|
||||
status: "running",
|
||||
token: runningFlow.flowId,
|
||||
flow: JSON.parse(JSON.stringify(runningFlow)),
|
||||
flow: jsonRoundTrip(runningFlow),
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -38,6 +38,11 @@ const ENFORCED_MAINTENANCE_OVERRIDE = {
|
||||
highWaterBytes: null,
|
||||
};
|
||||
|
||||
function jsonRoundTrip<T>(value: T): T {
|
||||
const serialized = JSON.stringify(value);
|
||||
return JSON.parse(serialized) as T;
|
||||
}
|
||||
|
||||
const archiveTimestamp = (ms: number) => new Date(ms).toISOString().replaceAll(":", "-");
|
||||
|
||||
const suiteRootTracker = createSuiteTempRootTracker({ prefix: "openclaw-pruning-integ-" });
|
||||
@@ -1193,10 +1198,7 @@ describe("Integration: saveSessionStore with pruning", () => {
|
||||
};
|
||||
await fs.writeFile(storePath, JSON.stringify(store, null, 2), "utf-8");
|
||||
|
||||
await saveSessionStore(
|
||||
storePath,
|
||||
JSON.parse(JSON.stringify(store)) as Record<string, SessionEntry>,
|
||||
);
|
||||
await saveSessionStore(storePath, jsonRoundTrip(store) as Record<string, SessionEntry>);
|
||||
|
||||
const files = await fs.readdir(testDir);
|
||||
const backups = files.filter((file) => file.startsWith("sessions.json.bak."));
|
||||
|
||||
@@ -68,7 +68,7 @@ function cloneRestartSentinelPayload(
|
||||
if (!payload) {
|
||||
return null;
|
||||
}
|
||||
return JSON.parse(JSON.stringify(payload)) as RestartSentinelPayload;
|
||||
return structuredClone(payload) as RestartSentinelPayload;
|
||||
}
|
||||
|
||||
function hasRoutableDeliveryContext(context?: {
|
||||
|
||||
@@ -91,7 +91,7 @@ export async function writeRestartSentinel(
|
||||
}
|
||||
|
||||
function cloneRestartSentinelPayload(payload: RestartSentinelPayload): RestartSentinelPayload {
|
||||
return JSON.parse(JSON.stringify(payload)) as RestartSentinelPayload;
|
||||
return structuredClone(payload) as RestartSentinelPayload;
|
||||
}
|
||||
|
||||
async function rewriteRestartSentinel(
|
||||
|
||||
@@ -36,7 +36,9 @@ const ZERO_BASELINE_RULES = [
|
||||
"eslint/unicode-bom",
|
||||
"eslint/yoda",
|
||||
"import/no-absolute-path",
|
||||
"import/first",
|
||||
"import/no-empty-named-blocks",
|
||||
"import/no-duplicates",
|
||||
"import/no-self-import",
|
||||
"node/no-exports-assign",
|
||||
"promise/no-new-statics",
|
||||
@@ -45,6 +47,7 @@ const ZERO_BASELINE_RULES = [
|
||||
"typescript/no-import-type-side-effects",
|
||||
"typescript/no-inferrable-types",
|
||||
"typescript/no-non-null-asserted-nullish-coalescing",
|
||||
"typescript/no-unsafe-type-assertion",
|
||||
"typescript/no-unnecessary-qualifier",
|
||||
"typescript/prefer-find",
|
||||
"typescript/prefer-for-of",
|
||||
@@ -74,6 +77,8 @@ const ZERO_BASELINE_RULES = [
|
||||
"unicorn/prefer-optional-catch-binding",
|
||||
"unicorn/prefer-prototype-methods",
|
||||
"unicorn/prefer-regexp-test",
|
||||
"unicorn/prefer-set-has",
|
||||
"unicorn/prefer-structured-clone",
|
||||
"unicorn/prefer-string-slice",
|
||||
"unicorn/require-array-join-separator",
|
||||
"unicorn/require-number-to-fixed-digits-argument",
|
||||
|
||||
Reference in New Issue
Block a user