From 64806006ccf838ca588e60dd93c5d928ce3eb0a8 Mon Sep 17 00:00:00 2001 From: Florens Verschelde <243601+fvsch@users.noreply.github.com> Date: Tue, 3 Dec 2024 18:42:22 +0100 Subject: [PATCH] fix: use trailing slashes in URLs to directories --- src/logger.ts | 20 +++++++++----------- src/pages.ts | 45 ++++++++++++++++++++++++++++----------------- test/logger.test.ts | 11 ++++++++++- test/pages.test.ts | 8 ++++---- 4 files changed, 51 insertions(+), 33 deletions(-) diff --git a/src/logger.ts b/src/logger.ts index 9952479..a8d8c97 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -124,12 +124,8 @@ export function requestLogLine({ let displayPath = _(urlPath ?? url, 'cyan'); if (isSuccess && urlPath != null && localPath != null) { - const basePath = urlPath.length > 1 ? trimSlash(urlPath, { end: true }) : urlPath; - const suffix = pathSuffix(basePath, `/${fwdSlash(localPath)}`); - if (suffix) { - displayPath = _(basePath, 'cyan') + brackets(suffix, 'dim,gray,dim'); - if (urlPath.length > 1 && urlPath.endsWith('/')) displayPath += _('/', 'cyan'); - } + const parts = pathSuffix(urlPath, localPath); + if (parts) displayPath = _(parts[0], 'cyan') + brackets(parts[1], 'dim,gray,dim'); } const line = [ @@ -149,11 +145,13 @@ export function requestLogLine({ return line; } -function pathSuffix(basePath: string, fullPath: string): string | undefined { - if (basePath === fullPath) { - return ''; - } else if (fullPath.startsWith(basePath)) { - return fullPath.slice(basePath.length); +function pathSuffix(urlPath: string, localPath: string): [string, string] | undefined { + const filePath = trimSlash(`/${fwdSlash(localPath)}`, { end: true }); + for (const path of [urlPath, trimSlash(urlPath, { end: true })]) { + if (filePath !== path && filePath.startsWith(path)) { + const index = path.length; + return [filePath.slice(0, index), filePath.slice(index)]; + } } } diff --git a/src/pages.ts b/src/pages.ts index ab9c48f..486424a 100644 --- a/src/pages.ts +++ b/src/pages.ts @@ -97,28 +97,39 @@ ${sorted.map((item) => renderListItem({ item, ext, parentPath })).join('\n')} function renderListItem(data: { item: FSLocation; ext: string[]; parentPath: string }) { const { item, ext, parentPath } = data; const isDir = isDirLike(item); - const isParent = isDir && item.filePath === parentPath; - - let icon = isDir ? 'icon-dir' : 'icon-file'; - if (item.kind === 'link') icon += '-link'; - let name = basename(item.filePath); - let suffix = ''; - let label = ''; + const icon = `icon-${isDir ? 'dir' : 'file'}${item.kind === 'link' ? '-link' : ''}`; + const name = basename(item.filePath); let href = encodeURIComponent(name); - if (isParent) { - name = '..'; - href = '..'; - label = 'Parent directory'; + if (isDir && item.filePath === parentPath) { + const label = 'Parent directory'; + return listItem({ icon, href: '../', name: '..', suffix: '/', label }); + } else if (isDir) { + return listItem({ icon, href: href + '/', name, suffix: '/' }); } - if (isDir) { - suffix = '/'; - } else { - // clean url: remove extension if possible - const match = ext.find((e) => item.filePath.endsWith(e)); - if (match) href = href.slice(0, href.length - match.length); + + // clean url: remove extension if possible + const knownExt = ext.find((e) => item.filePath.endsWith(e)); + if (knownExt) { + href = href.slice(0, href.length - knownExt.length); } + return listItem({ icon, href, name }); +} + +function listItem({ + href, + icon, + name, + suffix = '', + label = '', +}: { + href: string; + icon: string; + name: string; + suffix?: string; + label?: string; +}) { return [ `
  • \n`, ``, diff --git a/test/logger.test.ts b/test/logger.test.ts index 7b00620..2122fc3 100644 --- a/test/logger.test.ts +++ b/test/logger.test.ts @@ -191,6 +191,15 @@ suite('responseLogLine', () => { }, `200 — GET /some/page[.htm]`, ); + matchLogLine( + { + method: 'GET', + status: 200, + urlPath: '/some/page/', + localPath: 'some/page/index.html', + }, + `200 — GET /some/page/[index.html]`, + ); matchLogLine( { method: 'GET', @@ -198,7 +207,7 @@ suite('responseLogLine', () => { urlPath: '/other/page/', localPath: 'other\\page.html', }, - `200 — GET /other/page[.html]/`, + `200 — GET /other/page[.html]`, ); matchLogLine( { diff --git a/test/pages.test.ts b/test/pages.test.ts index 0d9cc3e..ead6005 100644 --- a/test/pages.test.ts +++ b/test/pages.test.ts @@ -42,7 +42,7 @@ suite('dirListPage', () => { if (shouldExist) { expect(link).toBeTruthy(); expect(link?.getAttribute('aria-label')).toBe('Parent directory'); - expect(link?.getAttribute('href')).toBe('..'); + expect(link?.getAttribute('href')).toBe('../'); expect(link?.textContent).toBe('../'); } else { expect(link).toBe(null); @@ -99,9 +99,9 @@ suite('dirListPage', () => { // Items should be sorted by type: directories first, files second expect(links).toEqual([ - { href: '..', text: '../' }, - { href: 'Library', text: 'Library/' }, - { href: 'public', text: 'public/' }, + { href: '../', text: '../' }, + { href: 'Library/', text: 'Library/' }, + { href: 'public/', text: 'public/' }, { href: '%20%20I%20have%20spaces%20%20', text: ' I have spaces ' }, { href: '.gitignore', text: '.gitignore' }, { href: 'CHANGELOG', text: 'CHANGELOG' },