mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
refactor(tooling): enforce zero wrapper and export debt (#123020)
This commit is contained in:
committed by
GitHub
parent
732b3da091
commit
fce5b6688a
@@ -1881,12 +1881,17 @@ describe("scripts/changed-lanes", () => {
|
||||
"src/channels/turn/run-channel-turn.ts",
|
||||
"scripts/check-wrapper-shadowing.mts",
|
||||
"scripts/check-export-name-collisions.mts",
|
||||
"scripts/lib/wrapper-shadowing-baseline.json",
|
||||
"scripts/lib/ts-guard-utils.mts",
|
||||
"package.json",
|
||||
]),
|
||||
).toBe(true);
|
||||
expect(shouldRunWrapperShadowingCheck(["docs/concepts/message-lifecycle.md"])).toBe(false);
|
||||
expect(
|
||||
shouldRunWrapperShadowingCheck([
|
||||
"docs/concepts/message-lifecycle.md",
|
||||
"scripts/lib/wrapper-shadowing-baseline.json",
|
||||
"scripts/lib/export-name-collision-baseline.json",
|
||||
]),
|
||||
).toBe(false);
|
||||
|
||||
const plan = createChangedCheckPlan(
|
||||
detectChangedLanes(["scripts/check-wrapper-shadowing.mts"]),
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
collectModuleExportNames,
|
||||
collectRepositoryCollisions,
|
||||
compareExportNameCollisionDebt,
|
||||
findAliasingReExports,
|
||||
findExportNameCollisions,
|
||||
isExcludedExportCollisionSource,
|
||||
} from "../../scripts/check-export-name-collisions.mts";
|
||||
import { withTempDir } from "../../src/test-utils/temp-dir.js";
|
||||
|
||||
const guardScriptPath = fileURLToPath(
|
||||
new URL("../../scripts/check-export-name-collisions.mts", import.meta.url),
|
||||
);
|
||||
|
||||
describe("export name collision guard", () => {
|
||||
it.each([
|
||||
["src/example.test.ts", true],
|
||||
@@ -244,34 +249,17 @@ describe("export name collision guard", () => {
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("export name collision debt baseline", () => {
|
||||
it("separates new debt from baseline improvements", () => {
|
||||
expect(
|
||||
compareExportNameCollisionDebt(
|
||||
[
|
||||
{ name: "added", files: ["src/a.ts", "src/b.ts"] },
|
||||
{ name: "expanded", files: ["src/a.ts", "src/b.ts", "src/c.ts"], sdk: true },
|
||||
],
|
||||
[
|
||||
{ name: "expanded", files: ["src/a.ts", "src/b.ts"] },
|
||||
{ name: "removed", files: ["src/c.ts", "src/d.ts"] },
|
||||
],
|
||||
),
|
||||
).toEqual({
|
||||
regressions: [
|
||||
{ current: { name: "added", files: ["src/a.ts", "src/b.ts"] } },
|
||||
{
|
||||
baseline: { name: "expanded", files: ["src/a.ts", "src/b.ts"] },
|
||||
current: {
|
||||
name: "expanded",
|
||||
files: ["src/a.ts", "src/b.ts", "src/c.ts"],
|
||||
sdk: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
improvements: [{ baseline: { name: "removed", files: ["src/c.ts", "src/d.ts"] } }],
|
||||
});
|
||||
it("rejects debt-baseline updates with the collision trailer", () => {
|
||||
const result = spawnSync(
|
||||
process.execPath,
|
||||
["--import", "tsx", guardScriptPath, "--update-debt-baseline"],
|
||||
{ encoding: "utf8" },
|
||||
);
|
||||
|
||||
expect(result.status).toBe(2);
|
||||
expect(result.stderr.trimEnd().split("\n").at(-1)).toBe(
|
||||
"[check-export-name-collisions] FAILED (exit 2)",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,38 +3,29 @@ import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
evaluateWrapperShadowing,
|
||||
type WrapperShadowingViolation,
|
||||
} from "../../scripts/check-wrapper-shadowing.mts";
|
||||
import { collectRepositoryWrapperShadowing } from "../../scripts/check-wrapper-shadowing.mts";
|
||||
import { withTempDir } from "../../src/test-utils/temp-dir.js";
|
||||
|
||||
const guardScriptPath = fileURLToPath(
|
||||
new URL("../../scripts/check-wrapper-shadowing.mts", import.meta.url),
|
||||
);
|
||||
|
||||
type GuardFixture = {
|
||||
baseline?: WrapperShadowingViolation[];
|
||||
files: Record<string, string>;
|
||||
};
|
||||
type GuardFixture = Record<string, string>;
|
||||
|
||||
async function runFixture(fixture: GuardFixture) {
|
||||
async function runFixture(files: GuardFixture) {
|
||||
return await withTempDir("openclaw-wrapper-shadowing-", async (repoRoot) => {
|
||||
await Promise.all(
|
||||
Object.entries(fixture.files).map(async ([repoPath, content]) => {
|
||||
Object.entries(files).map(async ([repoPath, content]) => {
|
||||
const filePath = path.join(repoRoot, repoPath);
|
||||
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
||||
await fs.writeFile(filePath, content);
|
||||
}),
|
||||
);
|
||||
const baselinePath = path.join(repoRoot, "scripts/lib/wrapper-shadowing-baseline.json");
|
||||
await fs.mkdir(path.dirname(baselinePath), { recursive: true });
|
||||
await fs.writeFile(baselinePath, `${JSON.stringify(fixture.baseline ?? [], null, 2)}\n`);
|
||||
return await evaluateWrapperShadowing(repoRoot);
|
||||
return await collectRepositoryWrapperShadowing(repoRoot);
|
||||
});
|
||||
}
|
||||
|
||||
const directViolation: GuardFixture["files"] = {
|
||||
const directViolation: GuardFixture = {
|
||||
"src/inner.ts": "export function runTask() { return 'inner'; }\n",
|
||||
"src/outer.ts": [
|
||||
'import { runTask as runTaskInner } from "./inner.js";',
|
||||
@@ -47,71 +38,26 @@ const directViolation: GuardFixture["files"] = {
|
||||
|
||||
describe("wrapper shadowing guard", () => {
|
||||
it("fails for a same-name wrapper around an imported implementation", async () => {
|
||||
const result = await runFixture({ files: directViolation });
|
||||
const result = await runFixture(directViolation);
|
||||
|
||||
expect(result.regressions).toEqual([
|
||||
{ name: "runTask", wrapped: "src/inner.ts", wrapper: "src/outer.ts" },
|
||||
]);
|
||||
expect(result).toEqual([{ name: "runTask", wrapped: "src/inner.ts", wrapper: "src/outer.ts" }]);
|
||||
});
|
||||
|
||||
it("passes for a pure re-export", async () => {
|
||||
const result = await runFixture({
|
||||
files: {
|
||||
"src/inner.ts": "export function runTask() { return 'inner'; }\n",
|
||||
"src/outer.ts": 'export { runTask } from "./inner.js";\n',
|
||||
},
|
||||
"src/inner.ts": "export function runTask() { return 'inner'; }\n",
|
||||
"src/outer.ts": 'export { runTask } from "./inner.js";\n',
|
||||
});
|
||||
|
||||
expect(result.current).toEqual([]);
|
||||
expect(result.regressions).toEqual([]);
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it("passes for a baselined violation", async () => {
|
||||
const violation = { name: "runTask", wrapped: "src/inner.ts", wrapper: "src/outer.ts" };
|
||||
const result = await runFixture({
|
||||
baseline: [
|
||||
violation,
|
||||
{ name: "removedTask", wrapped: "src/old-inner.ts", wrapper: "src/old-outer.ts" },
|
||||
],
|
||||
files: directViolation,
|
||||
});
|
||||
|
||||
expect(result.current).toEqual([violation]);
|
||||
expect(result.regressions).toEqual([]);
|
||||
});
|
||||
|
||||
it("fails for a new violation on top of the baseline", async () => {
|
||||
const baseline = { name: "runTask", wrapped: "src/inner.ts", wrapper: "src/outer.ts" };
|
||||
const result = await runFixture({
|
||||
baseline: [baseline],
|
||||
files: {
|
||||
...directViolation,
|
||||
"src/barrel.ts": 'export { sendTask } from "./sender.js";\n',
|
||||
"src/sender.ts": "export const sendTask = () => 'sent';\n",
|
||||
"src/send-wrapper.ts": [
|
||||
'import { sendTask as sendTaskInner } from "./barrel.js";',
|
||||
"export const sendTask = (...args: unknown[]) => {",
|
||||
" recordSend();",
|
||||
" return sendTaskInner(...args);",
|
||||
"};",
|
||||
].join("\n"),
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.regressions).toEqual([
|
||||
{
|
||||
name: "sendTask",
|
||||
wrapped: "src/sender.ts",
|
||||
wrapper: "src/send-wrapper.ts",
|
||||
via: "src/barrel.ts",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("ends failures with the wrapper trailer", () => {
|
||||
const result = spawnSync(process.execPath, ["--import", "tsx", guardScriptPath, "--invalid"], {
|
||||
encoding: "utf8",
|
||||
});
|
||||
it("rejects debt-baseline updates with the wrapper trailer", () => {
|
||||
const result = spawnSync(
|
||||
process.execPath,
|
||||
["--import", "tsx", guardScriptPath, "--update-debt-baseline"],
|
||||
{ encoding: "utf8" },
|
||||
);
|
||||
|
||||
expect(result.status).toBe(2);
|
||||
expect(result.stderr.trimEnd().split("\n").at(-1)).toBe(
|
||||
|
||||
Reference in New Issue
Block a user