From 8b7d28354e31ebc20b246cd71dc75f877391fc25 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sat, 16 May 2026 14:16:28 +0800 Subject: [PATCH] fix(test): avoid scanning plugin docs examples --- src/docs/plugin-doc-examples.test.ts | 64 +++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/src/docs/plugin-doc-examples.test.ts b/src/docs/plugin-doc-examples.test.ts index 45c173bab5a..6dd119ddf2c 100644 --- a/src/docs/plugin-doc-examples.test.ts +++ b/src/docs/plugin-doc-examples.test.ts @@ -1,7 +1,8 @@ +import { spawnSync } from "node:child_process"; import fs from "node:fs"; import path from "node:path"; import JSON5 from "json5"; -import { describe, expect, it } from "vitest"; +import { describe, expect, it, vi } from "vitest"; const PLUGIN_DOCS_DIR = path.join(process.cwd(), "docs", "plugins"); @@ -10,6 +11,54 @@ function lineNumberAt(source: string, index: number): number { } function listMarkdownFiles(dir: string): string[] { + const externalFiles = listExternalMarkdownFiles(dir); + if (externalFiles) { + return externalFiles; + } + return walkMarkdownFiles(dir); +} + +function listExternalMarkdownFiles(dir: string): string[] | null { + const repoPath = path.relative(process.cwd(), dir).split(path.sep).join("/"); + return listGitMarkdownFiles(repoPath) ?? listFindMarkdownFiles(dir); +} + +function listGitMarkdownFiles(repoPath: string): string[] | null { + const result = spawnSync("git", ["ls-files", "--", repoPath], { + cwd: process.cwd(), + encoding: "utf8", + maxBuffer: 1024 * 1024, + stdio: ["ignore", "pipe", "ignore"], + }); + if (result.status !== 0) { + return null; + } + return result.stdout + .split("\n") + .map((line) => line.trim()) + .filter((line) => line.endsWith(".md")) + .map((filePath) => path.join(process.cwd(), filePath)) + .toSorted(); +} + +function listFindMarkdownFiles(dir: string): string[] | null { + const result = spawnSync("find", [dir, "-type", "f", "-name", "*.md"], { + cwd: process.cwd(), + encoding: "utf8", + maxBuffer: 1024 * 1024, + stdio: ["ignore", "pipe", "ignore"], + }); + if (result.status !== 0) { + return null; + } + return result.stdout + .split("\n") + .map((line) => line.trim()) + .filter((line) => line.length > 0) + .toSorted(); +} + +function walkMarkdownFiles(dir: string): string[] { const files: string[] = []; for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { const entryPath = path.join(dir, entry.name); @@ -23,6 +72,19 @@ function listMarkdownFiles(dir: string): string[] { } describe("plugin docs examples", () => { + it("lists plugin docs without scanning directories in-process", () => { + const readDir = vi.spyOn(fs, "readdirSync"); + try { + const files = listMarkdownFiles(PLUGIN_DOCS_DIR); + + expect(files.length).toBeGreaterThan(0); + expect(files.every((filePath) => filePath.endsWith(".md"))).toBe(true); + expect(readDir).not.toHaveBeenCalled(); + } finally { + readDir.mockRestore(); + } + }); + it("keeps plugin docs JSON fences parseable", () => { const failures: string[] = []; for (const docPath of listMarkdownFiles(PLUGIN_DOCS_DIR)) {