History

fix(web): keep the final segment of directory paths with a trailing separator (#5460)

jorvarea committed 2 months ago

Commit f9153201 parent 7c8848e2 files · +31 −2Browse files

Unified · Split

2 files
  1. apps/web/src/markdown-links.test.ts +25 −0
  2. apps/web/src/markdown-links.ts +6 −2
apps/web/src/markdown-links.test.ts+25−0
@@ -273,3 +273,28 @@ describe("resolveInlineCodeFileLinkMeta", () => { · 272 unmodified lines
273273 expect(resolveInlineCodeFileLinkMeta(".plans/worktree-management-v1.md")).toBeNull();
274274 });
275275 });
276+
277+describe("directory paths with a trailing separator", () => {
278+ it("keeps the final segment for a POSIX directory path", () => {
279+ expect(resolveMarkdownFileLinkMeta("/tmp/favicons/", "/repo/project")).toMatchObject({
280+ basename: "favicons",
281+ });
282+ });
283+
284+ it("keeps the final segment for a Windows directory path", () => {
285+ expect(
286+ resolveMarkdownFileLinkMeta("C:\\Users\\kelchm\\.claude\\", "/repo/project"),
287+ ).toMatchObject({ basename: ".claude" });
288+ });
289+
290+ it("matches the label of the same path without a trailing separator", () => {
291+ const withSlash = resolveMarkdownFileLinkMeta("/tmp/favicons/", "/repo/project");
292+ const withoutSlash = resolveMarkdownFileLinkMeta("/tmp/favicons", "/repo/project");
293+ expect(withSlash?.basename).toBe(withoutSlash?.basename);
294+ });
295+
296+ it("does not produce an empty label for the filesystem root", () => {
297+ const meta = resolveMarkdownFileLinkMeta("/tmp/", "/repo/project");
298+ expect(meta?.basename).not.toBe("");
299+ });
300+});
apps/web/src/markdown-links.ts+6−2
@@ -359,8 +359,12 @@ export function resolveInlineCodeFileLinkMeta( · 358 unmodified lines
359359 }
360360
361361 function basenameOfPath(path: string): string {
362− const separatorIndex = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
363− return separatorIndex >= 0 ? path.slice(separatorIndex + 1) : path;
362+ // A trailing separator is a valid way to write a directory, so trim it before
363+ // taking the final segment. Without this the segment reads as empty and the
364+ // chip renders with no label at all.
365+ const trimmed = path.replace(/[/\\]+$/, "") || path;
366+ const separatorIndex = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
367+ return separatorIndex >= 0 ? trimmed.slice(separatorIndex + 1) : trimmed;
364368 }
365369
366370 function workspaceRelativePath(path: string, workspaceRoot: string | undefined): string | null {