-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmod.ts
156 lines (144 loc) · 3.43 KB
/
mod.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
151
152
153
154
155
156
export interface Using<T> {
_aenter: () => Promise<T>;
_aexit: ((any: any) => Promise<Boolean>) | ((any: any) => Promise<void>);
_timeout?: Promise<void>;
}
export interface UsingSync<T> {
_enter: () => T;
_exit: ((any: any) => Boolean) | ((any: any) => void);
}
export async function using<T>(
w: Using<T>,
f: (t: T) => Promise<void>,
): Promise<void> {
const item = await w._aenter();
let e;
try {
w._timeout === undefined
? await f(item)
: await Promise.race([f(item), w._timeout]);
} catch (err) {
e = err;
} finally {
if (!(await w._aexit(e)) && e !== undefined) {
// throw e;
return Promise.reject(e);
}
}
}
export function usingSync<T>(w: UsingSync<T>, f: (t: T) => void): void {
const item = w._enter();
let e;
try {
f(item);
} catch (err) {
e = err;
} finally {
if (!w._exit(e) && e !== undefined) {
throw e;
}
}
}
export class Open implements Using<Deno.File> {
constructor(filename: string, mode?: Deno.OpenOptions) {
this.filename = filename;
this.mode = mode;
}
public async _aenter() {
this.file = await Deno.open(this.filename, this.mode);
return this.file;
}
public async _aexit(e: any) {
this.file.close();
}
// @ts-ignore property 'file' has no initializer and is not definitely assigned in the constructor
private file: Deno.File;
private filename: string;
private mode: Deno.OpenOptions | undefined;
}
// TODO use the actual deno interface
// Also make whether to chdir optional
export interface MakeTempDirOptions {
dir?: string;
prefix?: string;
suffix?: string;
}
export class TempDir implements Using<string>, UsingSync<string> {
constructor(options: MakeTempDirOptions = {}) {
this.options = options;
this.cwd = "";
this.dir = "";
}
public async _aenter() {
this.dir = await Deno.makeTempDir(this.options);
this.cwd = Deno.cwd();
Deno.chdir(this.dir);
return this.dir;
}
public async _aexit(e: any) {
Deno.chdir(this.cwd);
await Deno.remove(this.dir);
}
public _enter() {
this.dir = Deno.makeTempDirSync(this.options);
this.cwd = Deno.cwd();
Deno.chdir(this.dir);
return this.dir;
}
public _exit(e: any) {
Deno.chdir(this.cwd);
Deno.remove(this.dir);
}
private cwd: string;
private dir: string;
private options: MakeTempDirOptions;
}
export class ChDir implements Using<void>, UsingSync<void> {
constructor(dir: string) {
this.dir = dir;
this.cwd = "";
}
public async _aenter() {
this.cwd = Deno.cwd();
Deno.chdir(this.dir);
}
public async _aexit(e: any) {
Deno.chdir(this.cwd);
}
public _enter() {
this.cwd = Deno.cwd();
Deno.chdir(this.dir);
}
public _exit(e: any) {
Deno.chdir(this.cwd);
}
private cwd: string;
private dir: string;
}
export class TimeoutError extends Error {
constructor(ms: number) {
const message = `Timeout after ${ms}ms`;
super(message);
this.name = "TimeoutError";
}
}
export class Timeout implements Using<void> {
constructor(ms: number) {
this.ms = ms;
this.id = 0;
this._timeout = Promise.resolve();
}
public async _aenter() {
this._timeout = new Promise((resolve, reject) => {
this.id = setTimeout(() => {
reject(new TimeoutError(this.ms));
}, this.ms);
});
}
public async _aexit(e: any) {
clearTimeout(this.id);
}
private id: number;
private ms: number;
_timeout: Promise<void>;
}