-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
133 lines (104 loc) · 3.31 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* eslint-disable import/no-unused-modules */
/** Query object */
export type Query = Record<string, any>
/** Parsed query object */
export type ParsedQuery<T = string> = Record<string, T | T[] | null | undefined>
/** URL object */
export interface UrlObject {
protocol?: string | null
host?: string | null
pathname?: string | null
query?: string | Query | null
}
/** Format URL to string */
export function formatUrl(urlObject: UrlObject): string {
const {protocol, host, pathname, query} = urlObject
let cleanedQueryString
if (query && typeof query === 'object') {
// NOTE: remove undefined or null values from query
const cleanedQuery = removeUrlNullableParams(query)
cleanedQueryString = new URLSearchParams(cleanedQuery).toString()
} else {
cleanedQueryString = query
}
return (
(protocol ? `${protocol}//` : '') +
(host ?? '') +
pathname +
(cleanedQueryString ? `?${cleanedQueryString}` : '')
)
}
/** Get URL query params */
export function getUrlParams(url: string): ParsedQuery {
const searchParams: ParsedQuery = {}
const {searchParams: iterableSearchParams} = new URL(url)
iterableSearchParams.forEach((value, key) => {
searchParams[key] = value
})
return searchParams
}
/** Get URL hash params */
export function getUrlHashParams(url: string): ParsedQuery {
const hashParams: ParsedQuery = {}
const {hash} = new URL(url)
const iterableHashParams = new URLSearchParams(hash.substring(1))
iterableHashParams.forEach((value, key) => {
hashParams[key] = value
})
return hashParams
}
/** Add URL query params */
export function addUrlParams(
url: string,
searchParams: Query,
hashParams?: Query
): string {
if (
!Object.keys(searchParams).length &&
(!hashParams || !Object.keys(hashParams).length)
)
return url
const {protocol, host, pathname} = new URL(url)
const initialSearchParams = getUrlParams(url)
const mergedSearchParams = removeUrlNullableParams({
...initialSearchParams,
...searchParams
})
const search = new URLSearchParams(mergedSearchParams).toString()
const urlSearch = search ? `?${search}` : ''
const initialHashParams = getUrlHashParams(url)
const mergedHashParams = removeUrlNullableParams({
...initialHashParams,
...hashParams
})
const hash = new URLSearchParams(mergedHashParams).toString()
const urlHash = hash ? `#${hash}` : ''
return `${protocol}//${host}${pathname}${urlSearch}${urlHash}`
}
/** Remove URL nullable query params (`null` or `undefined`) */
export function removeUrlNullableParams<T extends Query>(query: T): T {
const resultQuery: Query = {}
Object.keys(query).forEach((key) => {
if (query[key] != null) {
resultQuery[key] = query[key]
}
})
return resultQuery as T
}
/** Remove URL hash */
export function removeUrlHash(url: string): string {
const {protocol, host, pathname, search} = new URL(url)
return `${protocol}//${host}${pathname}${search}`
}
/**
* Encode URI for RFC3986
*
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
*/
export function encodeURIComponentRFC3986(value: string): string {
return encodeURIComponent(value).replace(
/[!'()*]/g,
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
(c) => `%${c.charCodeAt(0).toString(16)}`
)
}