feat: implement FluentUrl class with configuration and options normalization
This commit is contained in:
33
lib/core/config-defaults.ts
Normal file
33
lib/core/config-defaults.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { parseQuery, stringifyQuery } from '@/core/serializer/query-serializer'
|
||||||
|
import { deepClone } from '@/shared/helpers/deep-clone'
|
||||||
|
import { parseUrl } from './serializer/url-serializer'
|
||||||
|
|
||||||
|
export function normalizeConfig(config?: FluentUrlConfig): FluentUrlConfig {
|
||||||
|
return {
|
||||||
|
parseQuery: config?.parseQuery ?? parseQuery,
|
||||||
|
stringifyQuery: config?.stringifyQuery ?? stringifyQuery,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeOptions(args: {
|
||||||
|
urlOptions?: Partial<FLuentUrlPlainObject> | string
|
||||||
|
parseQuery: QuerySerializer['parseQuery']
|
||||||
|
}): FLuentUrlPlainObject {
|
||||||
|
const { urlOptions: urlOrOptions, parseQuery } = args
|
||||||
|
|
||||||
|
if (typeof urlOrOptions === 'string') {
|
||||||
|
return parseUrl({
|
||||||
|
str: urlOrOptions,
|
||||||
|
parseQuery: parseQuery,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
protocol: urlOrOptions?.protocol,
|
||||||
|
hostname: urlOrOptions?.hostname,
|
||||||
|
paths: deepClone(urlOrOptions?.paths) ?? [],
|
||||||
|
port: urlOrOptions?.port,
|
||||||
|
fragment: urlOrOptions?.fragment,
|
||||||
|
queries: deepClone(urlOrOptions?.queries) ?? Object.create(null),
|
||||||
|
}
|
||||||
|
}
|
||||||
86
lib/core/fluent-url.ts
Normal file
86
lib/core/fluent-url.ts
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import { normalizeConfig, normalizeOptions } from '@/core/config-defaults'
|
||||||
|
import { deepClone } from '@/shared/helpers/deep-clone'
|
||||||
|
import { stringifyUrl } from './serializer/url-serializer'
|
||||||
|
|
||||||
|
export class FluentUrl {
|
||||||
|
private config: FluentUrlConfig
|
||||||
|
private readonly protocol?: string
|
||||||
|
private readonly hostname?: string
|
||||||
|
private readonly paths: string[]
|
||||||
|
private readonly port?: number
|
||||||
|
private readonly fragment?: string
|
||||||
|
private readonly queries: QueriesPlainObject
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
urlOrOptions?: Partial<FLuentUrlPlainObject> | string,
|
||||||
|
config?: FluentUrlConfig,
|
||||||
|
) {
|
||||||
|
this.config = normalizeConfig(config)
|
||||||
|
|
||||||
|
const { protocol, hostname, paths, port, fragment, queries } =
|
||||||
|
normalizeOptions({
|
||||||
|
urlOptions: urlOrOptions,
|
||||||
|
parseQuery: this.config.parseQuery,
|
||||||
|
})
|
||||||
|
|
||||||
|
this.protocol = protocol
|
||||||
|
this.hostname = hostname
|
||||||
|
this.paths = paths
|
||||||
|
this.port = port
|
||||||
|
this.fragment = fragment
|
||||||
|
this.queries = queries
|
||||||
|
}
|
||||||
|
|
||||||
|
public toString(): string {
|
||||||
|
return stringifyUrl({
|
||||||
|
obj: {
|
||||||
|
protocol: this.protocol,
|
||||||
|
hostname: this.hostname,
|
||||||
|
paths: this.paths,
|
||||||
|
port: this.port,
|
||||||
|
fragment: this.fragment,
|
||||||
|
queries: this.queries,
|
||||||
|
},
|
||||||
|
stringifyQuery: this.config.stringifyQuery,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public toJSON(): string {
|
||||||
|
return this.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
public valueOf(): string {
|
||||||
|
return this.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
public toPlainObject(): FLuentUrlPlainObject {
|
||||||
|
return deepClone({
|
||||||
|
protocol: this.protocol,
|
||||||
|
hostname: this.hostname,
|
||||||
|
paths: this.paths,
|
||||||
|
port: this.port,
|
||||||
|
fragment: this.fragment,
|
||||||
|
queries: this.queries,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public clone(
|
||||||
|
options?: Partial<FLuentUrlPlainObject>,
|
||||||
|
config?: FluentUrlConfig,
|
||||||
|
): FluentUrl {
|
||||||
|
return new FluentUrl(
|
||||||
|
{
|
||||||
|
protocol: options?.protocol ?? this.protocol,
|
||||||
|
hostname: options?.hostname ?? this.hostname,
|
||||||
|
paths: options?.paths ?? this.paths,
|
||||||
|
port: options?.port ?? this.port,
|
||||||
|
fragment: options?.fragment ?? this.fragment,
|
||||||
|
queries: options?.queries ?? this.queries,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parseQuery: config?.parseQuery ?? this.config.parseQuery,
|
||||||
|
stringifyQuery: config?.stringifyQuery ?? this.config.stringifyQuery,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
7
lib/core/serializer/query-serializer.ts
Normal file
7
lib/core/serializer/query-serializer.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export const parseQuery: QuerySerializer['parseQuery'] = () => {
|
||||||
|
throw new Error('Not implemented')
|
||||||
|
}
|
||||||
|
|
||||||
|
export const stringifyQuery: QuerySerializer['stringifyQuery'] = () => {
|
||||||
|
throw new Error('Not implemented')
|
||||||
|
}
|
||||||
7
lib/core/serializer/url-serializer.ts
Normal file
7
lib/core/serializer/url-serializer.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export const parseUrl: UrlSerializer['parseUrl'] = () => {
|
||||||
|
throw new Error('Not implemented')
|
||||||
|
}
|
||||||
|
|
||||||
|
export const stringifyUrl: UrlSerializer['stringifyUrl'] = () => {
|
||||||
|
throw new Error('Not implemented')
|
||||||
|
}
|
||||||
3
lib/index.ts
Normal file
3
lib/index.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { FluentUrl } from '@/core/fluent-url'
|
||||||
|
|
||||||
|
export { FluentUrl }
|
||||||
33
lib/shared/types/index.d.ts
vendored
Normal file
33
lib/shared/types/index.d.ts
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/** biome-ignore-all lint/correctness/noUnusedVariables: <> */
|
||||||
|
|
||||||
|
type QueriesPlainObject = Record<string, any>
|
||||||
|
|
||||||
|
interface FLuentUrlPlainObject {
|
||||||
|
protocol?: string
|
||||||
|
hostname?: string
|
||||||
|
paths: string[]
|
||||||
|
port?: number
|
||||||
|
fragment?: string
|
||||||
|
queries: QueriesPlainObject
|
||||||
|
}
|
||||||
|
|
||||||
|
interface QuerySerializer {
|
||||||
|
parseQuery: (str: string) => QueriesPlainObject
|
||||||
|
stringifyQuery: (obj: QueriesPlainObject) => string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UrlSerializer {
|
||||||
|
parseUrl: (args: {
|
||||||
|
str: string
|
||||||
|
parseQuery?: QuerySerializer['parseQuery']
|
||||||
|
}) => FLuentUrlPlainObject
|
||||||
|
stringifyUrl: (args: {
|
||||||
|
obj: FLuentUrlPlainObject
|
||||||
|
stringifyQuery?: QuerySerializer['stringifyQuery']
|
||||||
|
}) => string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FluentUrlConfig {
|
||||||
|
parseQuery: Serializer['parseQuery']
|
||||||
|
stringifyQuery: Serializer['stringifyQuery']
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user