From 1dd92df1f242e2be81df679f7a078c064584b8ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9renger?= Date: Fri, 20 Dec 2024 22:22:43 +0000 Subject: [PATCH] feat: add url/cleanPath --- benchmarks/url/cleanPath.bench.ts | 19 +++++++++++++++++++ docs/url/cleanPath.mdx | 18 ++++++++++++++++++ src/mod.ts | 1 + src/url/cleanPath.ts | 23 +++++++++++++++++++++++ tests/url/cleanPath.test.ts | 29 +++++++++++++++++++++++++++++ 5 files changed, 90 insertions(+) create mode 100644 benchmarks/url/cleanPath.bench.ts create mode 100644 docs/url/cleanPath.mdx create mode 100644 src/url/cleanPath.ts create mode 100644 tests/url/cleanPath.test.ts diff --git a/benchmarks/url/cleanPath.bench.ts b/benchmarks/url/cleanPath.bench.ts new file mode 100644 index 00000000..15f4022b --- /dev/null +++ b/benchmarks/url/cleanPath.bench.ts @@ -0,0 +1,19 @@ +import { cleanPath } from 'radashi' + +describe('cleanPath', () => { + bench('with no input', () => { + cleanPath(undefined) + }) + bench('with empty string', () => { + cleanPath('') + }) + bench('with correct path', () => { + cleanPath('/some/path') + }) + bench('with multiple slashes in path', () => { + cleanPath('/some//path') + }) + bench('with protocol, path, query, and fragment', () => { + cleanPath('https://server//some//path?query=thing#fragment') + }) +}) diff --git a/docs/url/cleanPath.mdx b/docs/url/cleanPath.mdx new file mode 100644 index 00000000..f4549d8d --- /dev/null +++ b/docs/url/cleanPath.mdx @@ -0,0 +1,18 @@ +--- +title: cleanPath +description: Clean a path +--- + +### Usage + +Clean a path by removing duplicate slashes. +The protocol part of the URL is not modified. + +```ts +import { cleanPath } from 'radashi' + +cleanPath('/path//to///resource') // => '/path/to/resource' +cleanPath('http://example.com//path//to///resource') // => 'http://example.com/path/to/resource' +cleanPath(undefined) // => undefined +cleanPath(null) // => null +``` diff --git a/src/mod.ts b/src/mod.ts index 95bc9218..c4275820 100644 --- a/src/mod.ts +++ b/src/mod.ts @@ -142,6 +142,7 @@ export * from './typed/isUndefined.ts' export * from './typed/isWeakMap.ts' export * from './typed/isWeakSet.ts' +export * from './url/cleanPath.ts' export * from './url/onlyPath.ts' export * from './url/withLeadingSlash.ts' export * from './url/withoutLeadingSlash.ts' diff --git a/src/url/cleanPath.ts b/src/url/cleanPath.ts new file mode 100644 index 00000000..192c57af --- /dev/null +++ b/src/url/cleanPath.ts @@ -0,0 +1,23 @@ +/** + * Clean an URL by removing duplicate slashes. + * The protocol part of the URL is not modified. + * + * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`. + * @returns The cleaned URL string, or `undefined` if the input is `undefined`, or `null` if the input is `null`. + * + * @example + * ```ts + * cleanPath('/path//to///resource') // => '/path/to/resource' + * cleanPath('http://example.com//path//to///resource') // => 'http://example.com/path/to/resource' + * cleanPath(undefined) // => undefined + * cleanPath(null) // => null + * ``` + */ +export function cleanPath( + url: string | undefined | null, +): string | undefined | null { + if (url === undefined || url === null) { + return url + } + return url.replace(/([^:]\/)\/+/g, '$1') +} diff --git a/tests/url/cleanPath.test.ts b/tests/url/cleanPath.test.ts new file mode 100644 index 00000000..61e720c8 --- /dev/null +++ b/tests/url/cleanPath.test.ts @@ -0,0 +1,29 @@ +import { cleanPath } from 'radashi' + +describe('cleanPath', () => { + test('should remove duplicate slashes', () => { + expect(cleanPath('/path//to///resource')).toBe('/path/to/resource') + }) + test('should handle URLs with protocol correctly', () => { + expect(cleanPath('http://example.com//path//to///resource')).toBe( + 'http://example.com/path/to/resource', + ) + }) + test('should return undefined if input is undefined', () => { + expect(cleanPath(undefined)).toBe(undefined) + }) + test('should return null if input is null', () => { + expect(cleanPath(null)).toBe(null) + }) + test('should handle path without duplicate slashes', () => { + expect(cleanPath('/path/to/resource')).toBe('/path/to/resource') + }) + test('should handle URLs with fragments and queries', () => { + expect(cleanPath('/path//to///resource?query=thing#fragment')).toBe( + '/path/to/resource?query=thing#fragment', + ) + expect( + cleanPath('http://example.com//path//to///resource?query=thing#fragment'), + ).toBe('http://example.com/path/to/resource?query=thing#fragment') + }) +})