Skip to content

Commit 3064d61

Browse files
committed
fix(test): avoid scanning static asset metadata
1 parent 783ef1d commit 3064d61

2 files changed

Lines changed: 98 additions & 3 deletions

File tree

scripts/lib/static-extension-assets.mjs

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { spawnSync } from "node:child_process";
12
import fs from "node:fs";
23
import path from "node:path";
34

@@ -19,7 +20,46 @@ function normalizePackageRelativePath(value) {
1920
return normalized;
2021
}
2122

23+
function listTrackedExtensionPackageDirs(rootDir, fsImpl) {
24+
if (fsImpl !== fs) {
25+
return null;
26+
}
27+
const result = spawnSync("git", ["ls-files", "--", ":(glob)extensions/*/package.json"], {
28+
cwd: rootDir,
29+
encoding: "utf8",
30+
stdio: ["ignore", "pipe", "ignore"],
31+
});
32+
if (result.status !== 0) {
33+
return null;
34+
}
35+
return result.stdout
36+
.split("\n")
37+
.map((line) => toPosixPath(line.trim()))
38+
.filter((line) => line.length > 0)
39+
.flatMap((line) => {
40+
const match = /^extensions\/([^/]+)\/package\.json$/u.exec(line);
41+
if (!match?.[1]) {
42+
return [];
43+
}
44+
const packageDir = path.join(rootDir, "extensions", match[1]);
45+
return [
46+
{
47+
dirName: match[1],
48+
hasPackageJson: true,
49+
packageDir,
50+
packageJsonPath: path.join(packageDir, "package.json"),
51+
},
52+
];
53+
})
54+
.toSorted((left, right) => left.dirName.localeCompare(right.dirName));
55+
}
56+
2257
function listExtensionPackageDirs(rootDir, fsImpl) {
58+
const trackedDirs = listTrackedExtensionPackageDirs(rootDir, fsImpl);
59+
if (trackedDirs) {
60+
return trackedDirs;
61+
}
62+
2363
const extensionsRoot = path.join(rootDir, "extensions");
2464
if (!fsImpl.existsSync(extensionsRoot)) {
2565
return [];
@@ -29,7 +69,9 @@ function listExtensionPackageDirs(rootDir, fsImpl) {
2969
.filter((entry) => entry.isDirectory())
3070
.map((entry) => ({
3171
dirName: entry.name,
72+
hasPackageJson: undefined,
3273
packageDir: path.join(extensionsRoot, entry.name),
74+
packageJsonPath: path.join(extensionsRoot, entry.name, "package.json"),
3375
}))
3476
.toSorted((left, right) => left.dirName.localeCompare(right.dirName));
3577
}
@@ -58,9 +100,11 @@ export function discoverStaticExtensionAssets(params = {}) {
58100
const rootDir = params.rootDir ?? process.cwd();
59101
const fsImpl = params.fs ?? fs;
60102
const assets = [];
61-
for (const { dirName, packageDir } of listExtensionPackageDirs(rootDir, fsImpl)) {
62-
const packageJsonPath = path.join(packageDir, "package.json");
63-
if (!fsImpl.existsSync(packageJsonPath)) {
103+
for (const { dirName, hasPackageJson, packageJsonPath } of listExtensionPackageDirs(
104+
rootDir,
105+
fsImpl,
106+
)) {
107+
if (!(hasPackageJson ?? fsImpl.existsSync(packageJsonPath))) {
64108
continue;
65109
}
66110
const packageJson = readJsonFile(packageJsonPath, fsImpl);

test/scripts/runtime-postbuild.test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { execFileSync } from "node:child_process";
12
import fs from "node:fs/promises";
23
import path from "node:path";
34
import { describe, expect, it, vi } from "vitest";
@@ -42,6 +43,56 @@ describe("runtime postbuild static assets", () => {
4243
]);
4344
});
4445

46+
it("discovers repo static asset metadata without scanning extension directories", () => {
47+
const output = execFileSync(
48+
process.execPath,
49+
[
50+
"--input-type=module",
51+
"--eval",
52+
`
53+
import fs from "node:fs";
54+
import { syncBuiltinESMExports } from "node:module";
55+
const counts = { existsSync: 0, readdirSync: 0 };
56+
const originalExistsSync = fs.existsSync;
57+
const originalReaddirSync = fs.readdirSync;
58+
fs.existsSync = (...args) => {
59+
counts.existsSync += 1;
60+
return originalExistsSync(...args);
61+
};
62+
fs.readdirSync = (...args) => {
63+
counts.readdirSync += 1;
64+
return originalReaddirSync(...args);
65+
};
66+
syncBuiltinESMExports();
67+
const assets = await import("./scripts/lib/static-extension-assets.mjs");
68+
console.log(JSON.stringify({
69+
counts,
70+
outputs: assets.listStaticExtensionAssetOutputs(),
71+
sources: assets.listStaticExtensionAssetSources(),
72+
}));
73+
`,
74+
],
75+
{
76+
cwd: process.cwd(),
77+
encoding: "utf8",
78+
},
79+
);
80+
const payload = JSON.parse(output) as {
81+
counts: { existsSync: number; readdirSync: number };
82+
outputs: string[];
83+
sources: string[];
84+
};
85+
86+
expect(payload.outputs).toEqual([
87+
"dist/extensions/acpx/error-format.mjs",
88+
"dist/extensions/acpx/mcp-command-line.mjs",
89+
"dist/extensions/acpx/mcp-proxy.mjs",
90+
"dist/extensions/diffs/assets/viewer-runtime.js",
91+
]);
92+
expect(payload.sources).toContain("extensions/diffs/assets/viewer-runtime.js");
93+
expect(payload.counts).toEqual({ existsSync: 0, readdirSync: 0 });
94+
});
95+
4596
it("discovers static assets from plugin package metadata", async () => {
4697
const rootDir = createTempDir("openclaw-runtime-postbuild-");
4798
const packageDir = path.join(rootDir, "extensions", "demo");

0 commit comments

Comments
 (0)