/
utils.ts
150 lines (120 loc) Β· 4.03 KB
/
utils.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import { $URL } from './url'
import { parseURL, stringifyParsedURL } from './parse'
import { QueryObject, parseQuery, stringifyQuery } from './query'
import { decode } from './encoding'
export function isRelative (inputStr: string) {
return ['./', '../'].some(str => inputStr.startsWith(str))
}
export function hasProtocol (inputStr: string, acceptProtocolRelative = false): boolean {
return /^\w+:(\/\/)?.+/.test(inputStr) || (acceptProtocolRelative && /^\/\/[^/]+/.test(inputStr))
}
const TRAILING_SLASH_RE = /\/$|\/\?/
export function hasTrailingSlash (input: string = '', queryParams: boolean = false): boolean {
if (!queryParams) {
return input.endsWith('/')
}
return TRAILING_SLASH_RE.test(input)
}
export function withoutTrailingSlash (input: string = '', queryParams: boolean = false): string {
if (!queryParams) {
return (hasTrailingSlash(input) ? input.slice(0, -1) : input) || '/'
}
if (!hasTrailingSlash(input, true)) {
return input || '/'
}
const [s0, ...s] = input.split('?')
return (s0.slice(0, -1) || '/') + (s.length ? `?${s.join('?')}` : '')
}
export function withTrailingSlash (input: string = '', queryParams: boolean = false): string {
if (!queryParams) {
return input.endsWith('/') ? input : (input + '/')
}
if (hasTrailingSlash(input, true)) {
return input || '/'
}
const [s0, ...s] = input.split('?')
return s0 + '/' + (s.length ? `?${s.join('?')}` : '')
}
export function hasLeadingSlash (input: string = ''): boolean {
return input.startsWith('/')
}
export function withoutLeadingSlash (input: string = ''): string {
return (hasLeadingSlash(input) ? input.substr(1) : input) || '/'
}
export function withLeadingSlash (input: string = ''): string {
return hasLeadingSlash(input) ? input : ('/' + input)
}
export function cleanDoubleSlashes (input: string = ''): string {
return input.split('://').map(str => str.replace(/\/{2,}/g, '/')).join('://')
}
export function withBase (input: string, base: string) {
if (isEmptyURL(base)) {
return input
}
const _base = withoutTrailingSlash(base)
if (input.startsWith(_base)) {
return input
}
return joinURL(_base, input)
}
export function withoutBase (input: string, base: string) {
if (isEmptyURL(base)) {
return input
}
const _base = withoutTrailingSlash(base)
if (input.startsWith(_base)) {
return input.substr(_base.length) || '/'
}
return input
}
export function withQuery (input: string, query: QueryObject): string {
const parsed = parseURL(input)
const mergedQuery = { ...parseQuery(parsed.search), ...query }
parsed.search = stringifyQuery(mergedQuery)
return stringifyParsedURL(parsed)
}
export function getQuery (input: string): QueryObject {
return parseQuery(parseURL(input).search)
}
export function isEmptyURL (url: string) {
return !url || url === '/'
}
export function isNonEmptyURL (url: string) {
return url && url !== '/'
}
export function joinURL (base: string, ...input: string[]): string {
let url = base || ''
for (const i of input.filter(isNonEmptyURL)) {
url = url ? withTrailingSlash(url) + withoutLeadingSlash(i) : i
}
return url
}
export function withHttp (input: string): string {
return withProtocol(input, 'http://')
}
export function withHttps (input: string): string {
return withProtocol(input, 'https://')
}
export function withoutProtocol (input: string): string {
return withProtocol(input, '')
}
export function withProtocol (input: string, protocol: string): string {
return input.replace(/^\w+:(\/\/)?/, protocol)
}
// $URL based utils
export function createURL (input: string): $URL {
return new $URL(input)
}
export function normalizeURL (input: string): string {
return createURL(input).toString()
}
export function resolveURL (base: string, ...input: string[]): string {
const url = createURL(base)
for (const i of input.filter(isNonEmptyURL)) {
url.append(createURL(i))
}
return url.toString()
}
export function isSamePath (p1: string, p2: string) {
return decode(withoutTrailingSlash(p1)) === decode(withoutTrailingSlash(p2))
}