clojurific 0.12.5 → 0.12.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cljf/repl.js +24 -6
- package/package.json +1 -1
package/cljf/repl.js
CHANGED
|
@@ -99,14 +99,27 @@ export function complete(code) {
|
|
|
99
99
|
return depth <= 0;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
/**
|
|
102
|
+
/**
|
|
103
|
+
* An nREPL connection: requests whose responses end with status done. Once the
|
|
104
|
+
* socket closes, pending and later requests reject.
|
|
105
|
+
*/
|
|
103
106
|
export class Connection {
|
|
104
107
|
#socket;
|
|
105
108
|
#ids = 0;
|
|
106
109
|
#pending = new Map();
|
|
110
|
+
#closed = null;
|
|
107
111
|
|
|
108
112
|
constructor(socket) {
|
|
109
113
|
this.#socket = socket;
|
|
114
|
+
const fail = e => {
|
|
115
|
+
if (this.#closed) return;
|
|
116
|
+
this.#closed = new LauncherError(`cljf repl: the nREPL server closed the connection${e ? `: ${e.message}` : ''}`);
|
|
117
|
+
for (const { reject } of this.#pending.values()) reject(this.#closed);
|
|
118
|
+
this.#pending.clear();
|
|
119
|
+
};
|
|
120
|
+
// an error is followed by close
|
|
121
|
+
socket.on('error', fail);
|
|
122
|
+
socket.on('close', () => fail());
|
|
110
123
|
const decoder = new Decoder();
|
|
111
124
|
socket.on('data', chunk => {
|
|
112
125
|
for (const msg of decoder.push(chunk)) {
|
|
@@ -132,8 +145,12 @@ export class Connection {
|
|
|
132
145
|
*/
|
|
133
146
|
request(msg, onResponse = () => {}) {
|
|
134
147
|
const id = msg.id ?? this.newId();
|
|
135
|
-
return new Promise(resolve => {
|
|
136
|
-
this.#
|
|
148
|
+
return new Promise((resolve, reject) => {
|
|
149
|
+
if (this.#closed) {
|
|
150
|
+
reject(this.#closed);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
this.#pending.set(id, { onResponse, resolve, reject });
|
|
137
154
|
this.#socket.write(bencode({ ...msg, id }));
|
|
138
155
|
});
|
|
139
156
|
}
|
|
@@ -247,7 +264,7 @@ export async function repl({
|
|
|
247
264
|
rl.close();
|
|
248
265
|
// the server forgets the session, unless it doesn't answer
|
|
249
266
|
const timeout = new Promise(r => setTimeout(r, 1000).unref());
|
|
250
|
-
Promise.race([conn.request({ op: 'close', session }), timeout]).finally(() => {
|
|
267
|
+
Promise.race([conn.request({ op: 'close', session }), timeout]).catch(() => {}).finally(() => {
|
|
251
268
|
conn.close();
|
|
252
269
|
resolve(code);
|
|
253
270
|
});
|
|
@@ -262,7 +279,7 @@ export async function repl({
|
|
|
262
279
|
|
|
263
280
|
rl.on('SIGINT', () => {
|
|
264
281
|
if (evaluating) {
|
|
265
|
-
conn.request({ op: 'interrupt', session, 'interrupt-id': evaluating });
|
|
282
|
+
conn.request({ op: 'interrupt', session, 'interrupt-id': evaluating }).catch(() => {});
|
|
266
283
|
} else if (pending || rl.line) {
|
|
267
284
|
pending = '';
|
|
268
285
|
interrupted = false;
|
|
@@ -307,12 +324,13 @@ export async function repl({
|
|
|
307
324
|
return;
|
|
308
325
|
}
|
|
309
326
|
evaluating = conn.newId();
|
|
327
|
+
// a lost connection rejects, closed (above) reports it
|
|
310
328
|
await conn.request({ op: 'eval', session, code, ns, id: evaluating }, msg => {
|
|
311
329
|
write(output, msg.out);
|
|
312
330
|
write(errorOutput, msg.err);
|
|
313
331
|
if (msg.value !== undefined) output.write(`${msg.value}\n`);
|
|
314
332
|
if (msg.ns) ns = msg.ns;
|
|
315
|
-
});
|
|
333
|
+
}).catch(() => {});
|
|
316
334
|
evaluating = null;
|
|
317
335
|
if (closing) return;
|
|
318
336
|
prompt();
|