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