forked from coder/code-server
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutil.ts
More file actions
137 lines (119 loc) · 3.65 KB
/
Copy pathutil.ts
File metadata and controls
137 lines (119 loc) · 3.65 KB
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
// The type doesn't matter for these since we're just throwing.
// tslint:disable no-any
export const throwUnimplementedError = (): any => {
throw new Error("not implemented");
};
// In case the types except the promisify property.
throwUnimplementedError.__promisify__ = undefined as any;
// This one seems to be a mistake in the types for `link`.
throwUnimplementedError.link = undefined as any;
export const throwSyncError = (): any => {
throw new Error("sync is not supported");
};
// tslint:enable no-any
/**
* Return true if the options specify to use a Buffer instead of string.
*/
export const useBuffer = (options: { encoding?: string | null } | string | undefined | null | Function): boolean => {
return options === "buffer"
|| (!!options && typeof options !== "string" && typeof options !== "function"
&& (options.encoding === "buffer" || options.encoding === null));
};
/**
* Run a command with bash.
*/
export const bashCommand = (command: string): string => {
return `bash -c "${command.replace(/"/g, "\\\"")}"`;
};
/**
* Return true if we're in a browser environment (including web workers).
*/
export const isBrowserEnvironment = (): boolean => {
return typeof process === "undefined" || typeof process.stdout === "undefined";
};
/**
* Escape a path. This prevents any issues with file names that have quotes,
* spaces, braces, etc.
*/
export const escapePath = (path: string): string => {
return `'${path.replace(/'/g, "'\\''")}'`;
};
/**
* This queues up items then runs on all the items at once after a timeout. Each
* item has a callback that expects the response for that item which is the
* extending class's responsibility to call.
*
* You can also specify a maximum number of items to keep in the queue.
*/
export abstract class Queue<T> {
private items: Map<string, T[]>;
private timeout: number | NodeJS.Timer | undefined;
private max: number | undefined;
private timeoutDelay = 1;
public constructor(max?: number) {
this.items = new Map();
this.run = run;
this.max = max;
}
/**
* Add an item to the queue.
*/
public add(key: string, callback: T): void {
if (this.items.has(key)) {
this.items.get(key)!.push(callback);
} else {
this.items.set(key, [callback]);
}
const run = (): void => {
// tslint:disable-next-line no-any because NodeJS.Timer is valid.
clearTimeout(this.timeout as any);
this.timeout = undefined;
const newMap = new Map(this.items);
this.items.clear();
this.run(newMap);
};
if (typeof this.max !== "undefined" && this.items.size >= this.max) {
return run();
}
if (typeof this.timeout === "undefined") {
this.timeout = setTimeout(() => {
run();
}, this.timeoutDelay);
}
}
/**
* Run on the specified items then call their callbacks.
*/
protected abstract run(items: Map<string, T[]>): void;
}
/**
* Class for safely taking input and turning it into separate messages.
* Assumes that messages are split by newlines.
*/
export class NewlineInputBuffer {
private callback: (msg: string) => void;
private buffer: string | undefined;
public constructor(callback: (msg: string) => void) {
this.callback = callback;
}
/**
* Add data to be buffered.
*/
public push(data: string | Uint8Array): void {
let input = typeof data === "string" ? data : data.toString();
if (this.buffer) {
input = this.buffer + input;
this.buffer = undefined;
}
const lines = input.split("\n");
const length = lines.length - 1;
const lastLine = lines[length];
if (lastLine.length > 0) {
this.buffer = lastLine;
}
lines.pop(); // This is either the line we buffered or an empty string.
for (let i = 0; i < length; ++i) {
this.callback(lines[i]);
}
}
}