mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-06 00:44:07 +01:00
fix(context-bill): walk both links to one directory so the walk never depends on readdir order
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
9bf11e738e
commit
7f3ab43ed2
2 files changed
+9
-8
No files matched your search
+7
-8
@@ -233,8 +233,9 @@ function encloses(outer: string, inner: string): boolean {
|
||||
*
|
||||
* Symlinked files and directories are followed, and every returned path stays
|
||||
* the lexical path under `dir`, so buildBill and --exact key the same files.
|
||||
* Each real directory is walked once (cycle guard), and a link to a directory
|
||||
* that encloses `dir` is never followed.
|
||||
* Two links to one directory are both walked (each is real scanner load), so
|
||||
* the result never depends on readdir order. A directory that is already on
|
||||
* the current walk (a loop) or that encloses `dir` is never entered.
|
||||
*/
|
||||
export function walkMd(dir: string): string[] {
|
||||
const out: string[] = [];
|
||||
@@ -244,8 +245,7 @@ export function walkMd(dir: string): string[] {
|
||||
} catch {
|
||||
return out;
|
||||
}
|
||||
const visited = new Set([rootReal]);
|
||||
const walk = (current: string) => {
|
||||
const walk = (current: string, ancestors: string[]) => {
|
||||
let entries: fs.Dirent[];
|
||||
try {
|
||||
entries = fs.readdirSync(current, { withFileTypes: true });
|
||||
@@ -267,12 +267,11 @@ export function walkMd(dir: string): string[] {
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
if (visited.has(real) || encloses(real, rootReal)) continue;
|
||||
visited.add(real);
|
||||
walk(p);
|
||||
if (ancestors.includes(real) || encloses(real, rootReal)) continue;
|
||||
walk(p, [...ancestors, real]);
|
||||
}
|
||||
};
|
||||
walk(dir);
|
||||
walk(dir, [rootReal]);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
@@ -273,7 +273,9 @@ describe("upstream fix b: installed-tree layout (repo-checkout subdir skip)", ()
|
||||
}
|
||||
// Every path the bill (and --exact) keys on stays under the skills root.
|
||||
for (const file of walkMd(skills)) expect(file.startsWith(skills + path.sep)).toBe(true);
|
||||
// dirlink/SKILL.md links to review/sections, so its file is walked under both names.
|
||||
expect(walkMd(skills).map((f) => path.relative(skills, f)).sort()).toEqual([
|
||||
path.join("dirlink", "SKILL.md", "flow.md"),
|
||||
path.join("office-hours", "SKILL.md"),
|
||||
path.join("office-hours", "sections", "flow.md"),
|
||||
path.join("review", "SKILL.md"),
|
||||
|
||||
Reference in new issue
Block a user