From 819e0f2228846f718900aa0ae9cacb0afaaf558a Mon Sep 17 00:00:00 2001 From: Menghuan1918 Date: Wed, 23 Sep 2026 22:36:05 +0800 Subject: [PATCH] test: stop shelling out to ripgrep in the icon-export guard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `tests/primitives-exports.spec.ts` collected its file list with `execFileSync('rg', …)`. ripgrep is installed on a developer machine but not on the CI runners, so the whole spec failed to COLLECT there (`spawnSync rg ENOENT`, which is why `ci` and `ci-windows` were red on this branch while `pnpm test` was green locally). Replaced with a plain readdir walk over `src/` and `tests/` — no external binary, and the scan is a few hundred small files. Verified by running the spec with a failing `rg` shim first on PATH: it passes, which it cannot do while still calling ripgrep. --- tests/primitives-exports.spec.ts | 34 +++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/tests/primitives-exports.spec.ts b/tests/primitives-exports.spec.ts index 35da0f3..258cc7f 100644 --- a/tests/primitives-exports.spec.ts +++ b/tests/primitives-exports.spec.ts @@ -15,13 +15,39 @@ * bundle through a re-export rather than a direct import. */ import { describe, expect, it } from 'vitest' -import { readFileSync } from 'node:fs' -import { execFileSync } from 'node:child_process' +import { readFileSync, readdirSync } from 'node:fs' +import { join, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' import * as primitives from '@deepseek-ai/dsh-client-ui-primitives' /** The specifier whose named exports the plugin depends on. */ const PACKAGE = '@deepseek-ai/dsh-client-ui-primitives' +const ROOT = resolve(fileURLToPath(new URL('..', import.meta.url))) + +/** + * Every TypeScript source under the given roots. + * + * Deliberately a plain readdir walk rather than a ripgrep call: this spec used + * to shell out to `rg`, which exists on a developer machine but NOT on the CI + * runners, so the whole file failed to COLLECT there (`spawnSync rg ENOENT`) + * while passing locally. The scan is a few hundred small files. + * @param roots - directories relative to the repository root. + * @returns absolute file paths, sorted for a stable failure output. + */ +function sourceFiles(roots: readonly string[]): string[] { + const found: string[] = [] + const walk = (dir: string): void => { + for (const entry of readdirSync(dir, { withFileTypes: true })) { + const path = join(dir, entry.name) + if (entry.isDirectory()) walk(path) + else if (/\.tsx?$/.test(entry.name)) found.push(path) + } + } + for (const root of roots) walk(resolve(ROOT, root)) + return found.sort() +} + /** * Every value symbol the repository imports from the primitives package. * Type-only imports are ignored: they are erased before the bundle is built @@ -29,10 +55,8 @@ const PACKAGE = '@deepseek-ai/dsh-client-ui-primitives' * @returns the imported symbol names, deduplicated. */ function importedSymbols(): string[] { - const files = execFileSync('rg', ['-l', PACKAGE, 'src', 'tests'], { encoding: 'utf8' }) - .trim().split('\n').filter(Boolean) const names = new Set() - for (const file of files) { + for (const file of sourceFiles(['src', 'tests'])) { const source = readFileSync(file, 'utf8') for (const match of source.matchAll( new RegExp(`import\\s+(type\\s+)?\\{([^}]*)\\}\\s+from\\s+['"]${PACKAGE}['"]`, 'g'),