-
Notifications
You must be signed in to change notification settings - Fork 0
/
repl.js
129 lines (104 loc) · 3.31 KB
/
repl.js
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
'use strict';
var repl = require('repl');
var _ = require('highland');
var rl = require('readline');
var isAnsiReadlineOK = 'stripVTControlCharacters' in rl;
var promptText = isAnsiReadlineOK ? '\x1b[96m › \x1b[39m' : ' › ';
var replServer;
var isPromptSet = false;
module.exports.print = function (msg, withPrompt) {
rl.clearLine(process.stdout, 0);
console.log(msg || '');
if (withPrompt) {
this.showPrompt();
}
};
module.exports.showPrompt = function () {
if (replServer) {
if (!isPromptSet && typeof replServer.setPrompt === 'function') {
replServer.setPrompt(promptText);
}
if (typeof replServer.prompt === 'function') {
replServer.prompt();
}
}
};
module.exports.start = function start(config) {
var that = this;
return _(function (push, next) {
replServer = repl.start({
prompt: promptText,
eval: function (cmd, ctx, file, fn) {
var hasData = (cmd && !!cmd.trim());
if (!hasData) {
return that.showPrompt();
}
// the REPL doesn't go back to 'prompt mode' until `fn` is called, so we
// keep it around as `print` for the response from the client to use.
push(null, {
data: cmd,
print: function (err, res) {
var data = err ? formatError(err) : formatData(res);
fn(data);
}
});
}
});
replServer.on('exit', function () {
try {
push(null, _.nil);
} catch (e) {
// consumers may have already been destroyed
}
});
});
};
function formatData(data) {
return (typeof data === 'object') ? JSON.stringify(data) : data;
}
function formatError(err) {
// Credit: https://github.com/Automattic/browser-repl/blob/1b7adf204583efeb165726164d3d22d6b25c277b/repl.js#L161
// we have to create a synthetic SyntaxError if one occurred in the
// browser because the REPL special-cases that error
// to display the "more" prompt
if (
// most browsers set the `name` to "SyntaxError"
('SyntaxError' === err.name &&
// firefox
('syntax error' === err.message ||
'function statement requires a name' === err.message ||
// iOS
'Parse error' === err.message ||
// opera
/syntax error$/.test(err.message) ||
/expected (.*), got (.*)$/.test(err.message) ||
// safari
/^Unexpected token (.*)$/.test(err.message)
)
) ||
// old IE doens't even have a "name" property :\
('Syntax error' === err.message || /^expected /i.test(err.message))
) {
err = new SyntaxError('Unexpected end of input');
} else {
// any other `err` needs to be converted to an `Error` object
// with the given `err`s properties copied over
var e = new Error();
// force an empty stack trace on the server-side... in the case where
// the client-side didn't send us a `stack` property (old IE, safari),
// it's confusing to see a server-side stack trace.
e.stack = '';
for (var i in err) {
e[i] = err[i];
}
// firefox and opera, in particular, doesn't include the "name"
// or "message" in the stack trace
var prefix = e.name;
if (e.message) prefix += ': ' + e.message;
if (e.stack.substring(0, prefix.length) !== prefix) {
e.stack = prefix + '\n' + e.stack;
}
err = e;
}
return err;
}