forked from coder/code-server
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathutil.ts
130 lines (115 loc) · 3.58 KB
/
util.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
/*
* This file exists in two locations:
* - src/common/util.ts
* - lib/vscode/src/vs/server/common/util.ts
* The second is a symlink to the first.
*/
/**
* Base options included on every page.
*/
export interface Options {
base: string
csStaticBase: string
logLevel: number
}
/**
* Split a string up to the delimiter. If the delimiter doesn't exist the first
* item will have all the text and the second item will be an empty string.
*/
export const split = (str: string, delimiter: string): [string, string] => {
const index = str.indexOf(delimiter)
return index !== -1 ? [str.substring(0, index).trim(), str.substring(index + 1)] : [str, ""]
}
/**
* Appends an 's' to the provided string if count is greater than one;
* otherwise the string is returned
*/
export const plural = (count: number, str: string): string => (count === 1 ? str : `${str}s`)
export const generateUuid = (length = 24): string => {
const possible = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
return Array(length)
.fill(1)
.map(() => possible[Math.floor(Math.random() * possible.length)])
.join("")
}
/**
* Remove extra slashes in a URL.
*/
export const normalize = (url: string, keepTrailing = false): string => {
return url.replace(/\/\/+/g, "/").replace(/\/+$/, keepTrailing ? "/" : "")
}
/**
* Remove leading and trailing slashes.
*/
export const trimSlashes = (url: string): string => {
return url.replace(/^\/+|\/+$/g, "")
}
/**
* Resolve a relative base against the window location. This is used for
* anything that doesn't work with a relative path.
*/
export const resolveBase = (base?: string): string => {
// After resolving the base will either start with / or be an empty string.
if (!base || base.startsWith("/")) {
return base ?? ""
}
const parts = location.pathname.split("/")
parts[parts.length - 1] = base
const url = new URL(location.origin + "/" + parts.join("/"))
return normalize(url.pathname)
}
/**
* Get options embedded in the HTML or query params.
*/
export const getOptions = <T extends Options>(): T => {
let options: T
try {
options = JSON.parse(document.getElementById("coder-options")!.getAttribute("data-settings")!)
} catch (error) {
options = {} as T
}
// You can also pass options in stringified form to the options query
// variable. Options provided here will override the ones in the options
// element.
const params = new URLSearchParams(location.search)
const queryOpts = params.get("options")
if (queryOpts) {
options = {
...options,
...JSON.parse(queryOpts),
}
}
options.base = resolveBase(options.base)
options.csStaticBase = resolveBase(options.csStaticBase)
return options
}
/**
* Wrap the value in an array if it's not already an array. If the value is
* undefined return an empty array.
*/
export const arrayify = <T>(value?: T | T[]): T[] => {
if (Array.isArray(value)) {
return value
}
if (typeof value === "undefined") {
return []
}
return [value]
}
/**
* Get the first string. If there's no string return undefined.
*/
export const getFirstString = (value: string | string[] | object | undefined): string | undefined => {
if (Array.isArray(value)) {
return value[0]
}
return typeof value === "string" ? value : undefined
}
// TODO: Might make sense to add Error handling to the logger itself.
export function logError(logger: { error: (msg: string) => void }, prefix: string, err: Error | string): void {
if (err instanceof Error) {
logger.error(`${prefix}: ${err.message} ${err.stack}`)
} else {
logger.error(`${prefix}: ${err}`)
}
}