Files
superwork/vscode/src/codeReader/workspaceScope.test.ts
T

85 lines
3.3 KiB
TypeScript

import type { FolderReader } from './workspaceScope'
import { describe, expect, it } from 'vitest'
import { folderScope } from './workspaceScope'
/** 内存里的工作区文件夹:路径 → 内容(目录不用列,列出来的文件所在的目录都算有);记下读过哪些。 */
function memoryFolder(files: Record<string, string>): FolderReader & { asked: string[] } {
const asked: string[] = []
const directories = new Set(Object.keys(files).flatMap((file) => {
const parts = file.split('/')
return parts.slice(0, -1).map((_, i) => parts.slice(0, i + 1).join('/'))
}))
return {
asked,
exists: async (path) => {
asked.push(path)
return path in files || directories.has(path)
},
read: async (path) => {
asked.push(path)
return files[path]
},
}
}
async function kept(files: Record<string, string>, paths: string[], useIgnoreFiles = true): Promise<string[]> {
const scope = folderScope(memoryFolder(files), useIgnoreFiles)
const skipped = await Promise.all(paths.map(path => scope.skips(path)))
return paths.filter((_, i) => !skipped[i])
}
const TASKS = 'backend/src/luffy_agent/commerce/tasks.py'
const WORKTREE = '.claude/worktrees/agent-aa35211c29ea9e068'
describe('工作区扫描还要跳过的文件', () => {
it('嵌套的 git worktree(子目录里的 .git 是个文件)整个跳过,工作区自己的 .git 不算', async () => {
const files = {
'.git/HEAD': 'ref: refs/heads/main',
[TASKS]: '',
[`${WORKTREE}/.git`]: 'gitdir: /repo/.git/worktrees/agent-aa35211c29ea9e068',
[`${WORKTREE}/${TASKS}`]: '',
}
expect(await kept(files, [TASKS, `${WORKTREE}/${TASKS}`], false)).toEqual([TASKS])
})
it('嵌套的仓库(子目录里的 .git 是个目录)也跳过', async () => {
expect(await kept({ 'vendor/lib/.git/HEAD': '', 'vendor/lib/a.py': '', 'vendor/b.py': '' }, ['vendor/lib/a.py', 'vendor/b.py'])).toEqual(['vendor/b.py'])
})
it('.gitignore 忽略的目录跳过;每层的规则相对那一层,取反照 gitignore 写法;.ignore 也读', async () => {
const files = {
'.gitignore': '.claude/worktrees/\nbuild/\n*.log\n!keep.log\n',
'pkg/.gitignore': 'generated/\n',
'tools/.ignore': 'scratch.py\n',
[`${WORKTREE}/${TASKS}`]: '',
}
const paths = [
TASKS,
`${WORKTREE}/${TASKS}`,
'build/out/a.py',
'src/build.py',
'pkg/generated/a.py',
'generated/a.py',
'logs/x.log',
'logs/keep.log',
'tools/scratch.py',
'tools/run.py',
]
expect(await kept(files, paths)).toEqual([TASKS, 'src/build.py', 'generated/a.py', 'logs/keep.log', 'tools/run.py'])
})
it('search.useIgnoreFiles 关着时不读忽略文件,嵌套的 checkout 照样跳过', async () => {
const files = { '.gitignore': 'build/\n', 'sub/.git': 'gitdir: x', 'sub/a.py': '' }
expect(await kept(files, ['build/a.py', 'sub/a.py'], false)).toEqual(['build/a.py'])
})
it('同一个目录只查一次', async () => {
const folder = memoryFolder({ 'a/b/c.py': '', 'a/b/d.py': '' })
const scope = folderScope(folder, true)
await scope.skips('a/b/c.py')
await scope.skips('a/b/d.py')
expect(folder.asked.filter(path => path === 'a/b/.git')).toEqual(['a/b/.git'])
expect(folder.asked.filter(path => path === 'a/.gitignore')).toEqual(['a/.gitignore'])
})
})