From 49a2053b3b34363326857dcf784f056725ecd317 Mon Sep 17 00:00:00 2001 From: flakey5 <73616808+flakey5@users.noreply.github.com> Date: Sat, 11 Nov 2023 15:31:04 -0800 Subject: [PATCH] fix: don't treat vX.X.X folders as files Fixes nodejs/nodejs.org#6110 --- src/util.ts | 35 +++++++++++++++++++++++++++++------ tests/unit/util.test.ts | 8 ++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/util.ts b/src/util.ts index 11d10d3..fed2322 100644 --- a/src/util.ts +++ b/src/util.ts @@ -201,12 +201,35 @@ export function hasTrailingSlash(path: string): boolean { } export function isExtensionless(path: string): boolean { - // `path.lastIndexOf('.') == -1` is a Node-specific - // heuristic here. There aren't any files that don't - // have file extensions, so, if there are no file extensions - // specified in the url, treat it like a directory. - // One exception is `latest-vXX.x`, which is a directory - return path.lastIndexOf('.') === -1 || path.toLowerCase().endsWith('.x'); + // `path.lastIndexOf('.') == -1` is a Node-specific heuristic here. + // There aren't any files in the bucket that don't have file extensions, + // so, if there is no file extension specified in the url, treat it + // like a directory. + // + // Two exceptions: + // - `latest-vXX.x` directories + // - `vX.X.X` directories + + const extensionDelimiter = path.lastIndexOf('.'); + if (extensionDelimiter === -1) { + return true; + } + + const fileExtension = path.substring(extensionDelimiter + 1); // +1 to remove the `.` + + // `latest-vXX.x` directory + if (fileExtension.toLowerCase() === 'x') { + return true; + } + + // `vX.X.X` directory + // File extensions generally aren't numbers, so if we can parse this to + // one we can be pretty certain that it's a directory + if (!isNaN(Number.parseInt(fileExtension))) { + return true; + } + + return false; } /** diff --git a/tests/unit/util.test.ts b/tests/unit/util.test.ts index 036c454..5c7ead3 100644 --- a/tests/unit/util.test.ts +++ b/tests/unit/util.test.ts @@ -209,6 +209,14 @@ describe('isDirectoryPath', () => { assert.strictEqual(isDirectoryPath('/dist'), true); }); + it('returns true for `/dist/latest-v20.x`', () => { + assert.strictEqual(isDirectoryPath('/dist/latest-v20.x'), true); + }); + + it('returns true for `/dist/v20.20.2`', () => { + assert.strictEqual(isDirectoryPath('/dist/v20.20.2'), true); + }); + it('returns false for `/dist/index.json`', () => { assert.strictEqual(isDirectoryPath('/dist/index.json'), false); });