Browse Source

repl: don’t complete expressions when eval fails

Instead of changing the way “simple” expressions are detected,
switch to ignoring errors when completing. This approach is more
generic than the previous one from 0b66b8f2d, but also changes
the way errors are thrown when completing.

This reverts the code changes from commit 0b66b8f2d2.
The test case is left intact.

Fixes: https://github.com/nodejs/node/issues/6325
PR-URL: https://github.com/nodejs/node/pull/6328
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
process-exit-stdio-flushing
Anna Henningsen 9 years ago
committed by James M Snell
parent
commit
3ee68f794f
  1. 5
      lib/repl.js
  2. 57
      test/parallel/test-repl-tab-complete.js

5
lib/repl.js

@ -628,7 +628,7 @@ ArrayStream.prototype.write = function() {};
const requireRE = /\brequire\s*\(['"](([\w\.\/-]+\/)?([\w\.\/-]*))/; const requireRE = /\brequire\s*\(['"](([\w\.\/-]+\/)?([\w\.\/-]*))/;
const simpleExpressionRE = const simpleExpressionRE =
/^\s*(([a-zA-Z_$](?:\w|\$)*)\.)*([a-zA-Z_$](?:\w|\$)*)\.?$/; /(([a-zA-Z_$](?:\w|\$)*)\.)*([a-zA-Z_$](?:\w|\$)*)\.?$/;
function intFilter(item) { function intFilter(item) {
// filters out anything not starting with A-Z, a-z, $ or _ // filters out anything not starting with A-Z, a-z, $ or _
@ -806,7 +806,8 @@ REPLServer.prototype.complete = function(line, callback) {
}); });
} }
} else { } else {
this.eval(expr, this.context, 'repl', function(e, obj) { const evalExpr = `try { ${expr} } catch (e) {}`;
this.eval(evalExpr, this.context, 'repl', function(e, obj) {
// if (e) console.log(e); // if (e) console.log(e);
if (obj != null) { if (obj != null) {

57
test/parallel/test-repl-tab-complete.js

@ -3,19 +3,13 @@
var common = require('../common'); var common = require('../common');
var assert = require('assert'); var assert = require('assert');
var repl = require('repl'); var repl = require('repl');
var referenceErrors = 0;
var expectedReferenceErrors = 0;
function getDoNotCallFunction() {
expectedReferenceErrors += 1;
return function() {
assert(false);
};
}
process.on('exit', function() { function getNoResultsFunction() {
assert.strictEqual(referenceErrors, expectedReferenceErrors); return common.mustCall((err, data) => {
}); assert.ifError(err);
assert.deepStrictEqual(data[0], []);
});
}
var works = [['inner.one'], 'inner.o']; var works = [['inner.one'], 'inner.o'];
const putIn = new common.ArrayStream(); const putIn = new common.ArrayStream();
@ -23,13 +17,7 @@ var testMe = repl.start('', putIn);
// Some errors are passed to the domain, but do not callback // Some errors are passed to the domain, but do not callback
testMe._domain.on('error', function(err) { testMe._domain.on('error', function(err) {
// Errors come from another context, so instanceof doesn't work assert.ifError(err);
var str = err.toString();
if (/^ReferenceError:/.test(str))
referenceErrors++;
else
assert(false);
}); });
// Tab Complete will not break in an object literal // Tab Complete will not break in an object literal
@ -38,7 +26,7 @@ putIn.run([
'var inner = {', 'var inner = {',
'one:1' 'one:1'
]); ]);
testMe.complete('inner.o', getDoNotCallFunction()); testMe.complete('inner.o', getNoResultsFunction());
testMe.complete('console.lo', common.mustCall(function(error, data) { testMe.complete('console.lo', common.mustCall(function(error, data) {
assert.deepStrictEqual(data, [['console.log'], 'console.lo']); assert.deepStrictEqual(data, [['console.log'], 'console.lo']);
@ -58,7 +46,7 @@ putIn.run([
'?', '?',
'{one: 1} : ' '{one: 1} : '
]); ]);
testMe.complete('inner.o', getDoNotCallFunction()); testMe.complete('inner.o', getNoResultsFunction());
putIn.run(['.clear']); putIn.run(['.clear']);
@ -74,7 +62,7 @@ testMe.complete('inner.o', common.mustCall(function(error, data) {
// When you close the function scope tab complete will not return the // When you close the function scope tab complete will not return the
// locally scoped variable // locally scoped variable
putIn.run(['};']); putIn.run(['};']);
testMe.complete('inner.o', getDoNotCallFunction()); testMe.complete('inner.o', getNoResultsFunction());
putIn.run(['.clear']); putIn.run(['.clear']);
@ -129,7 +117,7 @@ putIn.run([
' one:1', ' one:1',
'};' '};'
]); ]);
testMe.complete('inner.o', getDoNotCallFunction()); testMe.complete('inner.o', getNoResultsFunction());
putIn.run(['.clear']); putIn.run(['.clear']);
@ -142,7 +130,7 @@ putIn.run([
' one:1', ' one:1',
'};' '};'
]); ]);
testMe.complete('inner.o', getDoNotCallFunction()); testMe.complete('inner.o', getNoResultsFunction());
putIn.run(['.clear']); putIn.run(['.clear']);
@ -156,7 +144,7 @@ putIn.run([
' one:1', ' one:1',
'};' '};'
]); ]);
testMe.complete('inner.o', getDoNotCallFunction()); testMe.complete('inner.o', getNoResultsFunction());
putIn.run(['.clear']); putIn.run(['.clear']);
@ -254,6 +242,21 @@ testMe.complete('obj.', common.mustCall(function(error, data) {
putIn.run(['.clear']); putIn.run(['.clear']);
putIn.run(['function a() {}']); putIn.run(['function a() {}']);
testMe.complete('a().b.', common.mustCall((error, data) => { testMe.complete('a().b.', getNoResultsFunction());
assert.deepStrictEqual(data, [[], undefined]);
// Works when prefixed with spaces
putIn.run(['.clear']);
putIn.run(['var obj = {1:"a","1a":"b",a:"b"};']);
testMe.complete(' obj.', common.mustCall((error, data) => {
assert.strictEqual(data[0].indexOf('obj.1'), -1);
assert.strictEqual(data[0].indexOf('obj.1a'), -1);
assert.notStrictEqual(data[0].indexOf('obj.a'), -1);
}));
// Works inside assignments
putIn.run(['.clear']);
testMe.complete('var log = console.lo', common.mustCall((error, data) => {
assert.deepStrictEqual(data, [['console.log'], 'console.lo']);
})); }));

Loading…
Cancel
Save