fix(test): avoid walking package boundary scans

This commit is contained in:
Vincent Koc
2026-05-16 11:02:08 +08:00
parent 9c7e36bf81
commit 72581fbb48

View File

@@ -1,6 +1,7 @@
import { existsSync, readdirSync, readFileSync } from "node:fs";
import { spawnSync } from "node:child_process";
import fs from "node:fs";
import { relative, resolve } from "node:path";
import { describe, expect, it } from "vitest";
import { describe, expect, it, vi } from "vitest";
import {
collectExtensionsWithTsconfig,
collectOptInExtensionPackageBoundaries,
@@ -18,6 +19,7 @@ const EXTENSION_PACKAGE_BOUNDARY_PATHS_CONFIG =
"extensions/tsconfig.package-boundary.paths.json" as const;
const EXTENSION_PACKAGE_BOUNDARY_BASE_CONFIG =
"extensions/tsconfig.package-boundary.base.json" as const;
const trackedCodeFilesByRoot = new Map<string, readonly string[] | null>();
type TsConfigJson = {
extends?: unknown;
@@ -71,13 +73,41 @@ const MEMORY_HOST_SDK_RUNTIME_ADAPTER_FILES = [
// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Test helper lets assertions ascribe JSON file shape.
function readJsonFile<T>(relativePath: string): T {
return JSON.parse(readFileSync(resolve(REPO_ROOT, relativePath), "utf8")) as T;
return JSON.parse(fs.readFileSync(resolve(REPO_ROOT, relativePath), "utf8")) as T;
}
function listTrackedCodeFiles(relativeDir: string): string[] | null {
if (trackedCodeFilesByRoot.has(relativeDir)) {
const files = trackedCodeFilesByRoot.get(relativeDir);
return files ? [...files] : null;
}
const result = spawnSync("git", ["ls-files", "--", relativeDir], {
cwd: REPO_ROOT,
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"],
});
if (result.status !== 0) {
trackedCodeFilesByRoot.set(relativeDir, null);
return null;
}
const files = result.stdout
.split("\n")
.map((line) => line.trim().replaceAll("\\", "/"))
.filter((line) => line.length > 0 && /\.(?:[cm]?ts|tsx|mts|cts)$/u.test(line))
.toSorted();
trackedCodeFilesByRoot.set(relativeDir, files);
return [...files];
}
function collectCodeFiles(relativeDir: string): string[] {
const trackedFiles = listTrackedCodeFiles(relativeDir);
if (trackedFiles) {
return trackedFiles;
}
const dir = resolve(REPO_ROOT, relativeDir);
const files: string[] = [];
for (const entry of readdirSync(dir, { withFileTypes: true })) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const nextPath = resolve(dir, entry.name);
if (entry.isDirectory()) {
files.push(...collectCodeFiles(relative(REPO_ROOT, nextPath).replaceAll("\\", "/")));
@@ -92,19 +122,33 @@ function collectCodeFiles(relativeDir: string): string[] {
function collectCoreReferenceFiles(relativeDir: string): string[] {
return collectCodeFiles(relativeDir).filter((file) => {
const source = readFileSync(resolve(REPO_ROOT, file), "utf8");
const source = fs.readFileSync(resolve(REPO_ROOT, file), "utf8");
return source.includes("../../../../src/") || source.includes("../../../src/");
});
}
function collectOpenClawRuntimeDirectImportFiles(relativeDir: string): string[] {
return collectCodeFiles(relativeDir).filter((file) => {
const source = readFileSync(resolve(REPO_ROOT, file), "utf8");
const source = fs.readFileSync(resolve(REPO_ROOT, file), "utf8");
return source.includes('"./openclaw-runtime.js"');
});
}
describe("opt-in extension package boundaries", () => {
it("lists package boundary code files from git without walking package roots", () => {
const readDir = vi.spyOn(fs, "readdirSync");
try {
const memoryHostFiles = collectCodeFiles("packages/memory-host-sdk/src");
const packageContractFiles = collectCodeFiles("packages/plugin-package-contract/src");
expect(memoryHostFiles.length).toBeGreaterThan(0);
expect(packageContractFiles.length).toBeGreaterThan(0);
expect(readDir).not.toHaveBeenCalled();
} finally {
readDir.mockRestore();
}
});
it("keeps path aliases in a dedicated shared config", () => {
const pathsConfig = readJsonFile<TsConfigJson>(EXTENSION_PACKAGE_BOUNDARY_PATHS_CONFIG);
expect(pathsConfig.extends).toBe("../tsconfig.json");
@@ -244,7 +288,7 @@ describe("opt-in extension package boundaries", () => {
"./dist/src/plugin-sdk/text-runtime.d.ts",
);
expect(packageJson.exports?.["./zod"]?.types).toBe("./dist/src/plugin-sdk/zod.d.ts");
expect(existsSync(resolve(REPO_ROOT, "packages/plugin-sdk/types/plugin-entry.d.ts"))).toBe(
expect(fs.existsSync(resolve(REPO_ROOT, "packages/plugin-sdk/types/plugin-entry.d.ts"))).toBe(
false,
);
});
@@ -265,7 +309,10 @@ describe("opt-in extension package boundaries", () => {
if (!target) {
throw new Error(`Missing memory-host-sdk export target for ${exportPath}`);
}
const source = readFileSync(resolve(REPO_ROOT, "packages/memory-host-sdk", target), "utf8");
const source = fs.readFileSync(
resolve(REPO_ROOT, "packages/memory-host-sdk", target),
"utf8",
);
expect(source, target).not.toContain("src/memory-host-sdk/");
}