Switch to double quotes and reformat codebase with Biome
This commit is contained in:
@@ -1,266 +1,266 @@
|
||||
import { mkdtempSync, mkdirSync, realpathSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import path from 'node:path'
|
||||
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
||||
import { searchHomeDirectories, searchWorkspaceEntries } from './directory-suggestions.js'
|
||||
import { mkdtempSync, mkdirSync, realpathSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import { searchHomeDirectories, searchWorkspaceEntries } from "./directory-suggestions.js";
|
||||
|
||||
describe('searchHomeDirectories', () => {
|
||||
let tempRoot: string
|
||||
let homeDir: string
|
||||
let outsideDir: string
|
||||
describe("searchHomeDirectories", () => {
|
||||
let tempRoot: string;
|
||||
let homeDir: string;
|
||||
let outsideDir: string;
|
||||
|
||||
beforeEach(() => {
|
||||
tempRoot = realpathSync(mkdtempSync(path.join(tmpdir(), 'directory-suggestions-')))
|
||||
homeDir = path.join(tempRoot, 'home')
|
||||
outsideDir = path.join(tempRoot, 'outside')
|
||||
tempRoot = realpathSync(mkdtempSync(path.join(tmpdir(), "directory-suggestions-")));
|
||||
homeDir = path.join(tempRoot, "home");
|
||||
outsideDir = path.join(tempRoot, "outside");
|
||||
|
||||
mkdirSync(homeDir, { recursive: true })
|
||||
mkdirSync(outsideDir, { recursive: true })
|
||||
mkdirSync(homeDir, { recursive: true });
|
||||
mkdirSync(outsideDir, { recursive: true });
|
||||
|
||||
mkdirSync(path.join(homeDir, 'projects', 'paseo'), { recursive: true })
|
||||
mkdirSync(path.join(homeDir, 'projects', 'playground'), { recursive: true })
|
||||
mkdirSync(path.join(homeDir, 'documents', 'plans'), { recursive: true })
|
||||
mkdirSync(path.join(homeDir, '.hidden', 'cache'), { recursive: true })
|
||||
writeFileSync(path.join(homeDir, 'projects', 'README.md'), 'not a directory\n')
|
||||
mkdirSync(path.join(homeDir, "projects", "paseo"), { recursive: true });
|
||||
mkdirSync(path.join(homeDir, "projects", "playground"), { recursive: true });
|
||||
mkdirSync(path.join(homeDir, "documents", "plans"), { recursive: true });
|
||||
mkdirSync(path.join(homeDir, ".hidden", "cache"), { recursive: true });
|
||||
writeFileSync(path.join(homeDir, "projects", "README.md"), "not a directory\n");
|
||||
|
||||
mkdirSync(path.join(outsideDir, 'outside-match'), { recursive: true })
|
||||
symlinkSync(path.join(outsideDir, 'outside-match'), path.join(homeDir, 'outside-link'))
|
||||
})
|
||||
mkdirSync(path.join(outsideDir, "outside-match"), { recursive: true });
|
||||
symlinkSync(path.join(outsideDir, "outside-match"), path.join(homeDir, "outside-link"));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
rmSync(tempRoot, { recursive: true, force: true })
|
||||
})
|
||||
rmSync(tempRoot, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('returns an empty list for blank queries', async () => {
|
||||
it("returns an empty list for blank queries", async () => {
|
||||
await expect(
|
||||
searchHomeDirectories({
|
||||
homeDir,
|
||||
query: ' ',
|
||||
query: " ",
|
||||
limit: 10,
|
||||
})
|
||||
).resolves.toEqual([])
|
||||
})
|
||||
}),
|
||||
).resolves.toEqual([]);
|
||||
});
|
||||
|
||||
it('returns only existing directories', async () => {
|
||||
it("returns only existing directories", async () => {
|
||||
const results = await searchHomeDirectories({
|
||||
homeDir,
|
||||
query: 'proj',
|
||||
query: "proj",
|
||||
limit: 10,
|
||||
})
|
||||
});
|
||||
|
||||
expect(results).toContain(path.join(homeDir, 'projects'))
|
||||
expect(results).toContain(path.join(homeDir, 'projects', 'paseo'))
|
||||
expect(results).not.toContain(path.join(homeDir, 'projects', 'README.md'))
|
||||
})
|
||||
expect(results).toContain(path.join(homeDir, "projects"));
|
||||
expect(results).toContain(path.join(homeDir, "projects", "paseo"));
|
||||
expect(results).not.toContain(path.join(homeDir, "projects", "README.md"));
|
||||
});
|
||||
|
||||
it('supports home-relative path query syntax', async () => {
|
||||
it("supports home-relative path query syntax", async () => {
|
||||
const results = await searchHomeDirectories({
|
||||
homeDir,
|
||||
query: '~/projects/pa',
|
||||
query: "~/projects/pa",
|
||||
limit: 10,
|
||||
})
|
||||
});
|
||||
|
||||
expect(results).toEqual([path.join(homeDir, 'projects', 'paseo')])
|
||||
})
|
||||
expect(results).toEqual([path.join(homeDir, "projects", "paseo")]);
|
||||
});
|
||||
|
||||
it('prioritizes exact segment matches before segment-prefix matches', async () => {
|
||||
const exactSegmentPath = path.join(homeDir, 'something', 'faro', 'something-else')
|
||||
const prefixSegmentPath = path.join(homeDir, 'something', 'somethingelse', 'faro-bla')
|
||||
mkdirSync(exactSegmentPath, { recursive: true })
|
||||
mkdirSync(prefixSegmentPath, { recursive: true })
|
||||
it("prioritizes exact segment matches before segment-prefix matches", async () => {
|
||||
const exactSegmentPath = path.join(homeDir, "something", "faro", "something-else");
|
||||
const prefixSegmentPath = path.join(homeDir, "something", "somethingelse", "faro-bla");
|
||||
mkdirSync(exactSegmentPath, { recursive: true });
|
||||
mkdirSync(prefixSegmentPath, { recursive: true });
|
||||
|
||||
const results = await searchHomeDirectories({
|
||||
homeDir,
|
||||
query: 'faro',
|
||||
query: "faro",
|
||||
limit: 30,
|
||||
})
|
||||
});
|
||||
|
||||
const exactIndex = results.indexOf(exactSegmentPath)
|
||||
const prefixIndex = results.indexOf(prefixSegmentPath)
|
||||
expect(exactIndex).toBeGreaterThanOrEqual(0)
|
||||
expect(prefixIndex).toBeGreaterThanOrEqual(0)
|
||||
expect(exactIndex).toBeLessThan(prefixIndex)
|
||||
})
|
||||
const exactIndex = results.indexOf(exactSegmentPath);
|
||||
const prefixIndex = results.indexOf(prefixSegmentPath);
|
||||
expect(exactIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(prefixIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(exactIndex).toBeLessThan(prefixIndex);
|
||||
});
|
||||
|
||||
it('prioritizes partial matches that appear earlier in the path', async () => {
|
||||
const earlierPath = path.join(homeDir, 'farofoo')
|
||||
const laterPath = path.join(homeDir, 'x', 'y', 'farofoo')
|
||||
mkdirSync(earlierPath, { recursive: true })
|
||||
mkdirSync(laterPath, { recursive: true })
|
||||
it("prioritizes partial matches that appear earlier in the path", async () => {
|
||||
const earlierPath = path.join(homeDir, "farofoo");
|
||||
const laterPath = path.join(homeDir, "x", "y", "farofoo");
|
||||
mkdirSync(earlierPath, { recursive: true });
|
||||
mkdirSync(laterPath, { recursive: true });
|
||||
|
||||
const results = await searchHomeDirectories({
|
||||
homeDir,
|
||||
query: 'arofo',
|
||||
query: "arofo",
|
||||
limit: 30,
|
||||
})
|
||||
});
|
||||
|
||||
const earlierIndex = results.indexOf(earlierPath)
|
||||
const laterIndex = results.indexOf(laterPath)
|
||||
expect(earlierIndex).toBeGreaterThanOrEqual(0)
|
||||
expect(laterIndex).toBeGreaterThanOrEqual(0)
|
||||
expect(earlierIndex).toBeLessThan(laterIndex)
|
||||
})
|
||||
const earlierIndex = results.indexOf(earlierPath);
|
||||
const laterIndex = results.indexOf(laterPath);
|
||||
expect(earlierIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(laterIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(earlierIndex).toBeLessThan(laterIndex);
|
||||
});
|
||||
|
||||
it("returns home-root suggestions when query is '~'", async () => {
|
||||
const results = await searchHomeDirectories({
|
||||
homeDir,
|
||||
query: '~',
|
||||
query: "~",
|
||||
limit: 20,
|
||||
})
|
||||
});
|
||||
|
||||
expect(results).toContain(path.join(homeDir, 'projects'))
|
||||
expect(results).toContain(path.join(homeDir, 'documents'))
|
||||
expect(results).not.toContain(path.join(homeDir, '.hidden'))
|
||||
})
|
||||
expect(results).toContain(path.join(homeDir, "projects"));
|
||||
expect(results).toContain(path.join(homeDir, "documents"));
|
||||
expect(results).not.toContain(path.join(homeDir, ".hidden"));
|
||||
});
|
||||
|
||||
it('does not return hidden directories during tree search', async () => {
|
||||
it("does not return hidden directories during tree search", async () => {
|
||||
const results = await searchHomeDirectories({
|
||||
homeDir,
|
||||
query: 'cache',
|
||||
query: "cache",
|
||||
limit: 20,
|
||||
})
|
||||
});
|
||||
|
||||
expect(results).not.toContain(path.join(homeDir, '.hidden', 'cache'))
|
||||
})
|
||||
expect(results).not.toContain(path.join(homeDir, ".hidden", "cache"));
|
||||
});
|
||||
|
||||
it('does not return paths that escape home through symlinks', async () => {
|
||||
it("does not return paths that escape home through symlinks", async () => {
|
||||
const results = await searchHomeDirectories({
|
||||
homeDir,
|
||||
query: 'outside',
|
||||
query: "outside",
|
||||
limit: 20,
|
||||
})
|
||||
});
|
||||
|
||||
expect(results).not.toContain(path.join(homeDir, 'outside-link'))
|
||||
expect(results).not.toContain(path.join(outsideDir, 'outside-match'))
|
||||
})
|
||||
expect(results).not.toContain(path.join(homeDir, "outside-link"));
|
||||
expect(results).not.toContain(path.join(outsideDir, "outside-match"));
|
||||
});
|
||||
|
||||
it('respects the result limit', async () => {
|
||||
it("respects the result limit", async () => {
|
||||
const results = await searchHomeDirectories({
|
||||
homeDir,
|
||||
query: 'p',
|
||||
query: "p",
|
||||
limit: 1,
|
||||
})
|
||||
});
|
||||
|
||||
expect(results).toHaveLength(1)
|
||||
})
|
||||
})
|
||||
expect(results).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('searchWorkspaceEntries', () => {
|
||||
let tempRoot: string
|
||||
let workspaceDir: string
|
||||
let outsideDir: string
|
||||
describe("searchWorkspaceEntries", () => {
|
||||
let tempRoot: string;
|
||||
let workspaceDir: string;
|
||||
let outsideDir: string;
|
||||
|
||||
beforeEach(() => {
|
||||
tempRoot = realpathSync(mkdtempSync(path.join(tmpdir(), 'workspace-suggestions-')))
|
||||
workspaceDir = path.join(tempRoot, 'workspace')
|
||||
outsideDir = path.join(tempRoot, 'outside')
|
||||
tempRoot = realpathSync(mkdtempSync(path.join(tmpdir(), "workspace-suggestions-")));
|
||||
workspaceDir = path.join(tempRoot, "workspace");
|
||||
outsideDir = path.join(tempRoot, "outside");
|
||||
|
||||
mkdirSync(path.join(workspaceDir, 'src', 'components'), {
|
||||
mkdirSync(path.join(workspaceDir, "src", "components"), {
|
||||
recursive: true,
|
||||
})
|
||||
mkdirSync(path.join(workspaceDir, 'docs'), { recursive: true })
|
||||
mkdirSync(path.join(outsideDir, 'escaped'), { recursive: true })
|
||||
});
|
||||
mkdirSync(path.join(workspaceDir, "docs"), { recursive: true });
|
||||
mkdirSync(path.join(outsideDir, "escaped"), { recursive: true });
|
||||
|
||||
writeFileSync(path.join(workspaceDir, 'README.md'), '# paseo\n')
|
||||
writeFileSync(path.join(workspaceDir, "README.md"), "# paseo\n");
|
||||
writeFileSync(
|
||||
path.join(workspaceDir, 'src', 'components', 'chat-input.tsx'),
|
||||
'export const ChatInput = null;\n'
|
||||
)
|
||||
writeFileSync(path.join(workspaceDir, 'docs', 'notes.md'), 'notes\n')
|
||||
path.join(workspaceDir, "src", "components", "chat-input.tsx"),
|
||||
"export const ChatInput = null;\n",
|
||||
);
|
||||
writeFileSync(path.join(workspaceDir, "docs", "notes.md"), "notes\n");
|
||||
|
||||
symlinkSync(path.join(outsideDir, 'escaped'), path.join(workspaceDir, 'escaped-link'))
|
||||
})
|
||||
symlinkSync(path.join(outsideDir, "escaped"), path.join(workspaceDir, "escaped-link"));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
rmSync(tempRoot, { recursive: true, force: true })
|
||||
})
|
||||
rmSync(tempRoot, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('returns relative file and directory suggestions for workspace queries', async () => {
|
||||
it("returns relative file and directory suggestions for workspace queries", async () => {
|
||||
const results = await searchWorkspaceEntries({
|
||||
cwd: workspaceDir,
|
||||
query: 'chat',
|
||||
query: "chat",
|
||||
limit: 20,
|
||||
includeFiles: true,
|
||||
includeDirectories: true,
|
||||
})
|
||||
});
|
||||
|
||||
expect(results).toContainEqual({
|
||||
path: 'src/components/chat-input.tsx',
|
||||
kind: 'file',
|
||||
})
|
||||
expect(results.some((entry) => entry.path === path.join(workspaceDir, 'src'))).toBe(false)
|
||||
})
|
||||
path: "src/components/chat-input.tsx",
|
||||
kind: "file",
|
||||
});
|
||||
expect(results.some((entry) => entry.path === path.join(workspaceDir, "src"))).toBe(false);
|
||||
});
|
||||
|
||||
it('filters entries by kind', async () => {
|
||||
it("filters entries by kind", async () => {
|
||||
const dirsOnly = await searchWorkspaceEntries({
|
||||
cwd: workspaceDir,
|
||||
query: 'src',
|
||||
query: "src",
|
||||
limit: 20,
|
||||
includeFiles: false,
|
||||
includeDirectories: true,
|
||||
})
|
||||
expect(dirsOnly.some((entry) => entry.kind === 'file')).toBe(false)
|
||||
expect(dirsOnly.some((entry) => entry.path === 'src')).toBe(true)
|
||||
});
|
||||
expect(dirsOnly.some((entry) => entry.kind === "file")).toBe(false);
|
||||
expect(dirsOnly.some((entry) => entry.path === "src")).toBe(true);
|
||||
|
||||
const filesOnly = await searchWorkspaceEntries({
|
||||
cwd: workspaceDir,
|
||||
query: 'readme',
|
||||
query: "readme",
|
||||
limit: 20,
|
||||
includeFiles: true,
|
||||
includeDirectories: false,
|
||||
})
|
||||
expect(filesOnly).toEqual([{ path: 'README.md', kind: 'file' }])
|
||||
})
|
||||
});
|
||||
expect(filesOnly).toEqual([{ path: "README.md", kind: "file" }]);
|
||||
});
|
||||
|
||||
it('supports path-style queries and does not escape cwd through symlinks', async () => {
|
||||
it("supports path-style queries and does not escape cwd through symlinks", async () => {
|
||||
const pathResults = await searchWorkspaceEntries({
|
||||
cwd: workspaceDir,
|
||||
query: 'src/co',
|
||||
query: "src/co",
|
||||
limit: 20,
|
||||
includeFiles: true,
|
||||
includeDirectories: true,
|
||||
})
|
||||
});
|
||||
expect(pathResults).toContainEqual({
|
||||
path: 'src/components',
|
||||
kind: 'directory',
|
||||
})
|
||||
path: "src/components",
|
||||
kind: "directory",
|
||||
});
|
||||
|
||||
const escapedResults = await searchWorkspaceEntries({
|
||||
cwd: workspaceDir,
|
||||
query: 'escaped',
|
||||
query: "escaped",
|
||||
limit: 20,
|
||||
includeFiles: true,
|
||||
includeDirectories: true,
|
||||
})
|
||||
expect(escapedResults.some((entry) => entry.path.includes('escaped-link'))).toBe(false)
|
||||
})
|
||||
});
|
||||
expect(escapedResults.some((entry) => entry.path.includes("escaped-link"))).toBe(false);
|
||||
});
|
||||
|
||||
it('ignores node_modules entries so deep workspace files still resolve under scan limits', async () => {
|
||||
mkdirSync(path.join(workspaceDir, 'packages', 'app', 'src', 'app'), { recursive: true })
|
||||
writeFileSync(path.join(workspaceDir, 'packages', 'app', 'src', 'app', '_layout.tsx'), '')
|
||||
it("ignores node_modules entries so deep workspace files still resolve under scan limits", async () => {
|
||||
mkdirSync(path.join(workspaceDir, "packages", "app", "src", "app"), { recursive: true });
|
||||
writeFileSync(path.join(workspaceDir, "packages", "app", "src", "app", "_layout.tsx"), "");
|
||||
|
||||
for (let index = 0; index < 120; index += 1) {
|
||||
mkdirSync(path.join(workspaceDir, 'node_modules', `pkg-${index}`), { recursive: true })
|
||||
mkdirSync(path.join(workspaceDir, "node_modules", `pkg-${index}`), { recursive: true });
|
||||
writeFileSync(
|
||||
path.join(workspaceDir, 'node_modules', `pkg-${index}`, 'index.js'),
|
||||
'module.exports = {};\n'
|
||||
)
|
||||
path.join(workspaceDir, "node_modules", `pkg-${index}`, "index.js"),
|
||||
"module.exports = {};\n",
|
||||
);
|
||||
}
|
||||
writeFileSync(path.join(workspaceDir, 'node_modules', '_layout.tsx'), '')
|
||||
writeFileSync(path.join(workspaceDir, "node_modules", "_layout.tsx"), "");
|
||||
|
||||
const results = await searchWorkspaceEntries({
|
||||
cwd: workspaceDir,
|
||||
query: '_layout.tsx',
|
||||
query: "_layout.tsx",
|
||||
limit: 20,
|
||||
includeFiles: true,
|
||||
includeDirectories: true,
|
||||
maxEntriesScanned: 60,
|
||||
})
|
||||
});
|
||||
|
||||
expect(results).toContainEqual({
|
||||
path: 'packages/app/src/app/_layout.tsx',
|
||||
kind: 'file',
|
||||
})
|
||||
expect(results.some((entry) => entry.path.startsWith('node_modules/'))).toBe(false)
|
||||
})
|
||||
})
|
||||
path: "packages/app/src/app/_layout.tsx",
|
||||
kind: "file",
|
||||
});
|
||||
expect(results.some((entry) => entry.path.startsWith("node_modules/"))).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user