feat: refine FluentUrl class and enhance URL serializer with improved parsing logic

This commit is contained in:
2026-02-22 20:10:42 -05:00
parent 80065fee88
commit d2dbb6f93e
3 changed files with 73 additions and 8 deletions

View File

@@ -13,7 +13,7 @@ import type {
} from '@/shared/types' } from '@/shared/types'
export class FluentUrl { export class FluentUrl {
private config: FluentUrlConfig private readonly config: FluentUrlConfig
private readonly protocol?: string private readonly protocol?: string
private readonly hostname?: string private readonly hostname?: string
private readonly paths: string[] private readonly paths: string[]
@@ -76,7 +76,7 @@ export class FluentUrl {
public clone( public clone(
options?: Partial<FLuentUrlPlainObject>, options?: Partial<FLuentUrlPlainObject>,
config?: FluentUrlConfig, config?: Partial<FluentUrlConfig>,
): FluentUrl { ): FluentUrl {
return new FluentUrl( return new FluentUrl(
mergeOptions( mergeOptions(

View File

@@ -1,9 +1,74 @@
import type { UrlSerializer } from '@/shared/types' import type { FLuentUrlPlainObject, UrlSerializer } from '@/shared/types'
export const parseUrl: UrlSerializer['parseUrl'] = () => { const URLTypesObj = {
throw new Error('Not implemented') absolute: 'absolute',
relative: 'relative',
protocolRelative: 'protocol-relative',
} as const
type URLTypes = (typeof URLTypesObj)[keyof typeof URLTypesObj]
const defaultProtocol = 'https'
const defaultHost = 'example.com'
export const parseUrl: UrlSerializer['parseUrl'] = ({ str, parseQuery }) => {
const urlString = str.trim()
const urlType: URLTypes = urlString.startsWith('//')
? URLTypesObj.protocolRelative
: urlString.startsWith('/')
? URLTypesObj.relative
: URLTypesObj.absolute
let newUrlString = urlString
if (urlType === URLTypesObj.protocolRelative) {
newUrlString = `${defaultProtocol}:${newUrlString}`
}
if (urlType === URLTypesObj.relative) {
newUrlString = `${defaultProtocol}://${defaultHost}${newUrlString}`
}
let url: URL
try {
url = new URL(newUrlString)
} catch {
throw new Error('Invalid URL')
}
const urlPlainObject: FLuentUrlPlainObject = {
paths: [],
queries: {},
}
if (urlType === URLTypesObj.absolute) {
urlPlainObject.protocol =
url.protocol !== '' ? url.protocol.replace(':', '') : undefined
}
if (
urlType === URLTypesObj.absolute ||
urlType === URLTypesObj.protocolRelative
) {
urlPlainObject.hostname = url.hostname || undefined
}
urlPlainObject.paths =
url.pathname === '/' ? [] : url.pathname.split('/').filter((p) => p !== '')
urlPlainObject.port = url.port !== '' ? Number(url.port) : undefined
urlPlainObject.fragment =
url.hash !== '' ? url.hash.replace('#', '') : undefined
urlPlainObject.queries =
url.search !== '' ? parseQuery(url.search) : Object.create(null)
return urlPlainObject
} }
export const stringifyUrl: UrlSerializer['stringifyUrl'] = () => { export const stringifyUrl: UrlSerializer['stringifyUrl'] = (_args) => {
throw new Error('Not implemented') throw new Error('Not implemented')
} }

View File

@@ -17,11 +17,11 @@ export interface QuerySerializer {
export interface UrlSerializer { export interface UrlSerializer {
parseUrl: (args: { parseUrl: (args: {
str: string str: string
parseQuery?: QuerySerializer['parseQuery'] parseQuery: QuerySerializer['parseQuery']
}) => FLuentUrlPlainObject }) => FLuentUrlPlainObject
stringifyUrl: (args: { stringifyUrl: (args: {
obj: FLuentUrlPlainObject obj: FLuentUrlPlainObject
stringifyQuery?: QuerySerializer['stringifyQuery'] stringifyQuery: QuerySerializer['stringifyQuery']
}) => string }) => string
} }