Browse Source

repl: exports `Recoverable`

Allow REPL consumers to callback with a `Recoverable` error instance
and trigger multi-line REPL prompts.

Fixes: https://github.com/nodejs/node/issues/2939
PR-URL: https://github.com/nodejs/node/pull/3488
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
v6.x
Blake Embrey 9 years ago
committed by Evan Lucas
parent
commit
ce2d5be4a1
  1. 29
      doc/api/repl.md
  2. 1
      lib/repl.js
  3. 40
      test/parallel/test-repl-recoverable.js

29
doc/api/repl.md

@ -262,8 +262,10 @@ the following values:
have ANSI/VT100 escape codes written to it. Defaults to checking `isTTY`
on the `output` stream upon instantiation.
- `eval` - function that will be used to eval each given line. Defaults to
an async wrapper for `eval()`. See below for an example of a custom `eval`.
- `eval` - a function that will be used to eval each given line. Defaults to
an async wrapper for `eval()`. An `eval` function can error with
`repl.Recoverable` to indicate the code was incomplete and prompt for more
lines. See below for an example of a custom `eval`.
- `useColors` - a boolean which specifies whether or not the `writer` function
should output colors. If a different `writer` function is set then this does
@ -287,11 +289,28 @@ the following values:
* `repl.REPL_MODE_MAGIC` - attempt to run commands in default mode. If they
fail to parse, re-try in strict mode.
You can use your own `eval` function if it has following signature:
It is possible to use a custom `eval` function as illustrated below:
function eval(cmd, context, filename, callback) {
callback(null, result);
```js
function eval(cmd, context, filename, callback) {
var result;
try {
result = vm.runInThisContext(cmd);
} catch (e) {
if (isRecoverableError(e)) {
return callback(new repl.Recoverable(e));
}
}
callback(null, result);
}
function isRecoverableError(error) {
if (error.name === 'SyntaxError') {
return /^(Unexpected end of input|Unexpected token)/.test(error.message);
}
return false;
}
```
On tab completion, `eval` will be called with `.scope` as an input string. It
is expected to return an array of scope names to be used for the auto-completion.

1
lib/repl.js

@ -1177,3 +1177,4 @@ function Recoverable(err) {
this.err = err;
}
inherits(Recoverable, SyntaxError);
exports.Recoverable = Recoverable;

40
test/parallel/test-repl-recoverable.js

@ -0,0 +1,40 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const repl = require('repl');
let evalCount = 0;
let recovered = false;
let rendered = false;
function customEval(code, context, file, cb) {
evalCount++;
return cb(evalCount === 1 ? new repl.Recoverable() : null, true);
}
const putIn = new common.ArrayStream();
putIn.write = function(msg) {
if (msg === '... ') {
recovered = true;
}
if (msg === 'true\n') {
rendered = true;
}
};
repl.start('', putIn, customEval);
// https://github.com/nodejs/node/issues/2939
// Expose recoverable errors to the consumer.
putIn.emit('data', '1\n');
putIn.emit('data', '2\n');
process.on('exit', function() {
assert(recovered, 'REPL never recovered');
assert(rendered, 'REPL never rendered the result');
assert.strictEqual(evalCount, 2);
});
Loading…
Cancel
Save