diff --git a/README.md b/README.md index df1b8903..11f71e83 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,16 @@ getQuery('http://foo.com/foo?test=123&unicode=%E5%A5%BD') // { test: '123', unicode: '好' } ``` +### `parseFilename` + +```ts +// Result: filename.ext +parseFilename('http://example.com/path/to/filename.ext') + +// Result: undefined +parseFilename('/path/to/.hidden-file', { strict: true }) +``` + ### `$URL` Implementing URL interface with improvements: diff --git a/src/parse.ts b/src/parse.ts index 53adecf9..96975408 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -119,3 +119,14 @@ export function stringifyParsedURL(parsed: ParsedURL): string { fullpath ); } + +const FILENAME_STRICT_REGEX = /\/([^/]+\.[^/]+)$/; +const FILENAME_REGEX = /\/([^/]+)$/; + +export function parseFilename(input = "", { strict }): string | undefined { + const { pathname } = parseURL(input); + const matches = strict + ? pathname.match(FILENAME_STRICT_REGEX) + : pathname.match(FILENAME_REGEX); + return matches ? matches[1] : undefined; +} diff --git a/test/parse.test.ts b/test/parse.test.ts index 8ee7fedb..0b9dc539 100644 --- a/test/parse.test.ts +++ b/test/parse.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "vitest"; -import { parseURL, parseHost } from "../src"; +import { parseURL, parseHost, parseFilename } from "../src"; describe("parseURL", () => { const tests = [ @@ -102,3 +102,98 @@ describe("parseHost", () => { }); } }); + +describe("parseFilename", () => { + const tests = [ + { input: ["/path/to/filename.ext", false], out: "filename.ext" }, + { input: ["/path/to/.hidden-file", false], out: ".hidden-file" }, + { input: ["/path/to/dir/", false], out: undefined }, + { input: [".", false], out: undefined }, + { input: ["/", false], out: undefined }, + { input: ["", false], out: undefined }, + { + input: ["http://example.com/path/to/filename.ext", false], + out: "filename.ext", + }, + { + input: ["http://example.com/path/to/filename.ext?query=true", false], + out: "filename.ext", + }, + { + input: ["http://example.com/path/to/filename.ext#hash", false], + out: "filename.ext", + }, + { + input: ["http://example.com/path/to/filename.ext?query=true#hash", false], + out: "filename.ext", + }, + { + input: [ + "http://example.com/path/to/filename.ext/?query=true#hash", + false, + ], + out: undefined, + }, + { input: ["http://example.com/path/to/dir/", false], out: undefined }, + { + input: ["http://example.com/path/to/dir/?query=true#hash", false], + out: undefined, + }, + { input: ["http://example.com/path/to/dir/#hash", false], out: undefined }, + { input: ["http://example.com", false], out: undefined }, + { + input: ["ftp://example.com/path/to/filename.ext", false], + out: "filename.ext", + }, + { input: ["file:///path/to/filename.ext", false], out: "filename.ext" }, + { input: ["/path/to/filename.ext", true], out: "filename.ext" }, + { input: ["/path/to/.hidden-file", true], out: undefined }, + { input: ["/path/to/dir/", true], out: undefined }, + { input: [".", true], out: undefined }, + { input: ["/", true], out: undefined }, + { input: ["", true], out: undefined }, + { + input: ["http://example.com/path/to/filename.ext", true], + out: "filename.ext", + }, + { + input: ["http://example.com/path/to/filename.ext?query=true", true], + out: "filename.ext", + }, + { + input: ["http://example.com/path/to/filename.ext#hash", true], + out: "filename.ext", + }, + { + input: ["http://example.com/path/to/filename.ext?query=true#hash", true], + out: "filename.ext", + }, + { + input: ["http://example.com/path/to/filename.ext/?query=true#hash", true], + out: undefined, + }, + { input: ["http://example.com/path/to/dir/", true], out: undefined }, + { + input: ["http://example.com/path/to/dir/?query=true#hash", true], + out: undefined, + }, + { input: ["http://example.com/path/to/dir/#hash", true], out: undefined }, + { input: ["http://example.com", true], out: undefined }, + { + input: ["ftp://example.com/path/to/filename.ext", true], + out: "filename.ext", + }, + { input: ["file:///path/to/filename.ext", true], out: "filename.ext" }, + { input: ["/path/to/filename.ext/", true], out: undefined }, + { input: ["/path/to/dir/../filename.ext", true], out: "filename.ext" }, + { input: ["/path/to/dir/../filename.ext/", true], out: undefined }, + ]; + + for (const t of tests) { + test(t.input.toString(), () => { + expect( + parseFilename(t.input[0].toString(), { strict: t.input[1] }) + ).toStrictEqual(t.out); + }); + } +});