Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions apps/web/src/markdown-links.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,3 +273,28 @@ describe("resolveInlineCodeFileLinkMeta", () => {
expect(resolveInlineCodeFileLinkMeta(".plans/worktree-management-v1.md")).toBeNull();
});
});

describe("directory paths with a trailing separator", () => {
it("keeps the final segment for a POSIX directory path", () => {
expect(resolveMarkdownFileLinkMeta("/tmp/favicons/", "/repo/project")).toMatchObject({
basename: "favicons",
});
});

it("keeps the final segment for a Windows directory path", () => {
expect(
resolveMarkdownFileLinkMeta("C:\\Users\\kelchm\\.claude\\", "/repo/project"),
).toMatchObject({ basename: ".claude" });
});

it("matches the label of the same path without a trailing separator", () => {
const withSlash = resolveMarkdownFileLinkMeta("/tmp/favicons/", "/repo/project");
const withoutSlash = resolveMarkdownFileLinkMeta("/tmp/favicons", "/repo/project");
expect(withSlash?.basename).toBe(withoutSlash?.basename);
});

it("does not produce an empty label for the filesystem root", () => {
const meta = resolveMarkdownFileLinkMeta("/tmp/", "/repo/project");
expect(meta?.basename).not.toBe("");
});
});
8 changes: 6 additions & 2 deletions apps/web/src/markdown-links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,12 @@ export function resolveInlineCodeFileLinkMeta(
}

function basenameOfPath(path: string): string {
const separatorIndex = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
return separatorIndex >= 0 ? path.slice(separatorIndex + 1) : path;
// A trailing separator is a valid way to write a directory, so trim it before
// taking the final segment. Without this the segment reads as empty and the
// chip renders with no label at all.
const trimmed = path.replace(/[/\\]+$/, "") || path;
const separatorIndex = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
return separatorIndex >= 0 ? trimmed.slice(separatorIndex + 1) : trimmed;
}

function workspaceRelativePath(path: string, workspaceRoot: string | undefined): string | null {
Expand Down