mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-13 23:56:07 +00:00
fix: prune stale generated declarations before tsdown build
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { spawn } from "node:child_process";
|
||||
import { spawn, spawnSync } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
@@ -21,6 +21,8 @@ const DEFAULT_CAPTURE_BYTES = 8 * 1024 * 1024;
|
||||
const DEFAULT_HEARTBEAT_MS = 30_000;
|
||||
const TERMINATION_GRACE_MS = 5_000;
|
||||
const TSDOWN_OUTPUT_ROOTS = ["dist", "dist-runtime"];
|
||||
const GENERATED_SOURCE_DECLARATION_PATHSPEC = ":(glob)extensions/**/*.d.ts";
|
||||
const SOURCE_DECLARATION_SOURCE_EXTENSIONS = [".ts", ".tsx", ".mts", ".cts", ".js", ".mjs", ".cjs"];
|
||||
|
||||
function removeDistPluginNodeModulesSymlinks(rootDir) {
|
||||
const extensionsDir = path.join(rootDir, "extensions");
|
||||
@@ -93,6 +95,52 @@ export function pruneStaleRootChunkFiles(params = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
export function pruneUntrackedGeneratedSourceDeclarations(params = {}) {
|
||||
const cwd = params.cwd ?? process.cwd();
|
||||
const fsImpl = params.fs ?? fs;
|
||||
const spawnSyncImpl = params.spawnSync ?? spawnSync;
|
||||
let result;
|
||||
try {
|
||||
result = spawnSyncImpl(
|
||||
"git",
|
||||
["ls-files", "--others", "--exclude-standard", "--", GENERATED_SOURCE_DECLARATION_PATHSPEC],
|
||||
{
|
||||
cwd,
|
||||
encoding: "utf8",
|
||||
stdio: ["ignore", "pipe", "ignore"],
|
||||
},
|
||||
);
|
||||
} catch {
|
||||
return 0;
|
||||
}
|
||||
if (result.status !== 0 || typeof result.stdout !== "string") {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let removed = 0;
|
||||
for (const rawPath of result.stdout.split(/\r?\n/u)) {
|
||||
const relativePath = rawPath.trim().replaceAll("\\", "/");
|
||||
if (!relativePath.startsWith("extensions/") || !relativePath.endsWith(".d.ts")) {
|
||||
continue;
|
||||
}
|
||||
const declarationPath = path.join(cwd, relativePath);
|
||||
const sourceBase = declarationPath.slice(0, -".d.ts".length);
|
||||
const hasMatchingSource = SOURCE_DECLARATION_SOURCE_EXTENSIONS.some((extension) =>
|
||||
fsImpl.existsSync(`${sourceBase}${extension}`),
|
||||
);
|
||||
if (!hasMatchingSource) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
fsImpl.rmSync(declarationPath, { force: true });
|
||||
removed += 1;
|
||||
} catch {
|
||||
// Best-effort cleanup; tsdown will still report any remaining stale files.
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
export function pruneSourceCheckoutBundledPluginNodeModules(params = {}) {
|
||||
const cwd = params.cwd ?? process.cwd();
|
||||
const logger = params.logger ?? console;
|
||||
@@ -326,6 +374,7 @@ function isMainModule() {
|
||||
|
||||
if (isMainModule()) {
|
||||
pruneSourceCheckoutBundledPluginNodeModules();
|
||||
pruneUntrackedGeneratedSourceDeclarations();
|
||||
pruneStaleRuntimeSymlinks();
|
||||
cleanTsdownOutputRoots();
|
||||
const invocation = resolveTsdownBuildInvocation();
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
createTsdownOutputScanner,
|
||||
pruneSourceCheckoutBundledPluginNodeModules,
|
||||
pruneStaleRootChunkFiles,
|
||||
pruneUntrackedGeneratedSourceDeclarations,
|
||||
resolveTsdownBuildInvocation,
|
||||
runTsdownBuildInvocation,
|
||||
} from "../../scripts/tsdown-build.mjs";
|
||||
@@ -138,6 +139,37 @@ describe("resolveTsdownBuildInvocation", () => {
|
||||
await expectPathMissing(path.join(rootDir, "dist-runtime"));
|
||||
await expect(fsPromises.readFile(unrelatedFile, "utf8")).resolves.toBe("keep\n");
|
||||
});
|
||||
|
||||
it("prunes untracked generated declaration files that shadow source entries", async () => {
|
||||
const rootDir = createTempDir("openclaw-tsdown-source-dts-");
|
||||
const signalDir = path.join(rootDir, "extensions", "signal");
|
||||
const signalSrcDir = path.join(signalDir, "src");
|
||||
await fsPromises.mkdir(signalSrcDir, { recursive: true });
|
||||
await fsPromises.writeFile(path.join(signalDir, "api.ts"), "export {};\n");
|
||||
await fsPromises.writeFile(path.join(signalDir, "api.d.ts"), "export {};\n");
|
||||
await fsPromises.writeFile(path.join(signalSrcDir, "probe.ts"), "export {};\n");
|
||||
await fsPromises.writeFile(path.join(signalSrcDir, "probe.d.ts"), "export {};\n");
|
||||
await fsPromises.writeFile(
|
||||
path.join(signalSrcDir, "ambient.d.ts"),
|
||||
"declare const x: string;\n",
|
||||
);
|
||||
|
||||
const removed = pruneUntrackedGeneratedSourceDeclarations({
|
||||
cwd: rootDir,
|
||||
spawnSync: () => ({
|
||||
status: 0,
|
||||
stdout:
|
||||
"extensions/signal/api.d.ts\nextensions/signal/src/probe.d.ts\nextensions/signal/src/ambient.d.ts\n",
|
||||
}),
|
||||
});
|
||||
|
||||
expect(removed).toBe(2);
|
||||
await expectPathMissing(path.join(signalDir, "api.d.ts"));
|
||||
await expectPathMissing(path.join(signalSrcDir, "probe.d.ts"));
|
||||
await expect(
|
||||
fsPromises.readFile(path.join(signalSrcDir, "ambient.d.ts"), "utf8"),
|
||||
).resolves.toBe("declare const x: string;\n");
|
||||
});
|
||||
});
|
||||
|
||||
describe("createTsdownOutputScanner", () => {
|
||||
|
||||
Reference in New Issue
Block a user