repl: tab auto complete big arrays

Due to a new API it's possible to skip the indices. That allows to
use auto completion with big (typed) arrays.

PR-URL: https://github.com/nodejs/node/pull/22408
Fixes: https://github.com/nodejs/node/issues/21446
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
Ruben Bridgewater 2018-08-20 03:26:27 +02:00
parent c35ce5635c
commit 68b07ded9c
No known key found for this signature in database
GPG Key ID: F07496B3EB3C1762
5 changed files with 51 additions and 54 deletions

View File

@ -366,7 +366,6 @@ function isInsideNodeModules() {
return false; return false;
} }
module.exports = { module.exports = {
assertCrypto, assertCrypto,
cachedResult, cachedResult,

View File

@ -10,7 +10,12 @@ const {
isRegExp, isRegExp,
isSet isSet
} = internalBinding('types'); } = internalBinding('types');
const { getOwnNonIndexProperties } = process.binding('util'); const {
getOwnNonIndexProperties,
propertyFilter: {
ONLY_ENUMERABLE
}
} = process.binding('util');
const ReflectApply = Reflect.apply; const ReflectApply = Reflect.apply;
@ -118,8 +123,9 @@ function strictDeepEqual(val1, val2, memos) {
if (val1.length !== val2.length) { if (val1.length !== val2.length) {
return false; return false;
} }
const keys1 = getOwnNonIndexProperties(val1); const keys1 = getOwnNonIndexProperties(val1, ONLY_ENUMERABLE);
if (keys1.length !== getOwnNonIndexProperties(val2).length) { const keys2 = getOwnNonIndexProperties(val2, ONLY_ENUMERABLE);
if (keys1.length !== keys2.length) {
return false; return false;
} }
return keyCheck(val1, val2, kStrict, memos, kIsArray, keys1); return keyCheck(val1, val2, kStrict, memos, kIsArray, keys1);
@ -150,8 +156,9 @@ function strictDeepEqual(val1, val2, memos) {
// Buffer.compare returns true, so val1.length === val2.length. If they both // Buffer.compare returns true, so val1.length === val2.length. If they both
// only contain numeric keys, we don't need to exam further than checking // only contain numeric keys, we don't need to exam further than checking
// the symbols. // the symbols.
const keys1 = getOwnNonIndexProperties(val1); const keys1 = getOwnNonIndexProperties(val1, ONLY_ENUMERABLE);
if (keys1.length !== getOwnNonIndexProperties(val2).length) { const keys2 = getOwnNonIndexProperties(val2, ONLY_ENUMERABLE);
if (keys1.length !== keys2.length) {
return false; return false;
} }
return keyCheck(val1, val2, kStrict, memos, kNoIterator, keys1); return keyCheck(val1, val2, kStrict, memos, kNoIterator, keys1);

View File

@ -52,7 +52,6 @@ const {
isIdentifierChar isIdentifierChar
} = require('internal/deps/acorn/dist/acorn'); } = require('internal/deps/acorn/dist/acorn');
const internalUtil = require('internal/util'); const internalUtil = require('internal/util');
const { isTypedArray } = require('internal/util/types');
const util = require('util'); const util = require('util');
const utilBinding = process.binding('util'); const utilBinding = process.binding('util');
const { inherits } = util; const { inherits } = util;
@ -74,6 +73,13 @@ const {
const { sendInspectorCommand } = require('internal/util/inspector'); const { sendInspectorCommand } = require('internal/util/inspector');
const { experimentalREPLAwait } = process.binding('config'); const { experimentalREPLAwait } = process.binding('config');
const { isRecoverableError } = require('internal/repl/recoverable'); const { isRecoverableError } = require('internal/repl/recoverable');
const {
getOwnNonIndexProperties,
propertyFilter: {
ALL_PROPERTIES,
SKIP_SYMBOLS
}
} = process.binding('util');
// Lazy-loaded. // Lazy-loaded.
let processTopLevelAwait; let processTopLevelAwait;
@ -927,34 +933,10 @@ function isIdentifier(str) {
return true; return true;
} }
const ARRAY_LENGTH_THRESHOLD = 1e6;
function mayBeLargeObject(obj) {
if (Array.isArray(obj)) {
return obj.length > ARRAY_LENGTH_THRESHOLD ? ['length'] : null;
} else if (isTypedArray(obj)) {
return obj.length > ARRAY_LENGTH_THRESHOLD ? [] : null;
}
return null;
}
function filteredOwnPropertyNames(obj) { function filteredOwnPropertyNames(obj) {
if (!obj) return []; if (!obj) return [];
const fakeProperties = mayBeLargeObject(obj); const filter = ALL_PROPERTIES | SKIP_SYMBOLS;
if (fakeProperties !== null) { return getOwnNonIndexProperties(obj, filter).filter(isIdentifier);
this.outputStream.write('\r\n');
process.emitWarning(
'The current array, Buffer or TypedArray has too many entries. ' +
'Certain properties may be missing from completion output.',
'REPLWarning',
undefined,
undefined,
true);
return fakeProperties;
}
return Object.getOwnPropertyNames(obj).filter(isIdentifier);
} }
function getGlobalLexicalScopeNames(contextId) { function getGlobalLexicalScopeNames(contextId) {

View File

@ -4,16 +4,23 @@
namespace node { namespace node {
namespace util { namespace util {
using v8::ALL_PROPERTIES;
using v8::Array; using v8::Array;
using v8::Context; using v8::Context;
using v8::FunctionCallbackInfo; using v8::FunctionCallbackInfo;
using v8::Integer; using v8::Integer;
using v8::Local; using v8::Local;
using v8::Object; using v8::Object;
using v8::ONLY_CONFIGURABLE;
using v8::ONLY_ENUMERABLE;
using v8::ONLY_WRITABLE;
using v8::Private; using v8::Private;
using v8::Promise; using v8::Promise;
using v8::Proxy; using v8::Proxy;
using v8::SKIP_STRINGS;
using v8::SKIP_SYMBOLS;
using v8::String; using v8::String;
using v8::Uint32;
using v8::Value; using v8::Value;
static void GetOwnNonIndexProperties( static void GetOwnNonIndexProperties(
@ -21,17 +28,19 @@ static void GetOwnNonIndexProperties(
Environment* env = Environment::GetCurrent(args); Environment* env = Environment::GetCurrent(args);
Local<Context> context = env->context(); Local<Context> context = env->context();
if (!args[0]->IsObject()) CHECK(args[0]->IsObject());
return; CHECK(args[1]->IsUint32());
v8::Local<v8::Object> object = args[0].As<v8::Object>(); Local<Object> object = args[0].As<Object>();
// Return only non-enumerable properties by default. Local<Array> properties;
v8::Local<v8::Array> properties;
v8::PropertyFilter filter =
static_cast<v8::PropertyFilter>(args[1].As<Uint32>()->Value());
if (!object->GetPropertyNames( if (!object->GetPropertyNames(
context, v8::KeyCollectionMode::kOwnOnly, context, v8::KeyCollectionMode::kOwnOnly,
v8::ONLY_ENUMERABLE, filter,
v8::IndexFilter::kSkipIndices) v8::IndexFilter::kSkipIndices)
.ToLocal(&properties)) { .ToLocal(&properties)) {
return; return;
@ -209,6 +218,17 @@ void Initialize(Local<Object> target,
WatchdogHasPendingSigint); WatchdogHasPendingSigint);
env->SetMethod(target, "safeGetenv", SafeGetenv); env->SetMethod(target, "safeGetenv", SafeGetenv);
Local<Object> constants = Object::New(env->isolate());
NODE_DEFINE_CONSTANT(constants, ALL_PROPERTIES);
NODE_DEFINE_CONSTANT(constants, ONLY_WRITABLE);
NODE_DEFINE_CONSTANT(constants, ONLY_ENUMERABLE);
NODE_DEFINE_CONSTANT(constants, ONLY_CONFIGURABLE);
NODE_DEFINE_CONSTANT(constants, SKIP_STRINGS);
NODE_DEFINE_CONSTANT(constants, SKIP_SYMBOLS);
target->Set(context,
FIXED_ONE_BYTE_STRING(env->isolate(), "propertyFilter"),
constants).FromJust();
} }
} // namespace util } // namespace util

View File

@ -393,12 +393,6 @@ testMe.complete('obj.', common.mustCall((error, data) => {
assert(data[0].includes('obj.key')); assert(data[0].includes('obj.key'));
})); }));
// tab completion for large buffer
const warningRegEx = new RegExp(
'\\(node:\\d+\\) REPLWarning: The current array, Buffer or TypedArray has ' +
'too many entries\\. Certain properties may be missing from completion ' +
'output\\.');
[ [
Array, Array,
Buffer, Buffer,
@ -428,11 +422,7 @@ const warningRegEx = new RegExp(
putIn.run([`var ele = new ${type.name}(1e6 + 1); ele.biu = 1;`]); putIn.run([`var ele = new ${type.name}(1e6 + 1); ele.biu = 1;`]);
} }
common.hijackStderr(common.mustCall((err) => { common.hijackStderr(common.mustNotCall());
process.nextTick(() => {
assert.ok(warningRegEx.test(err));
});
}));
testMe.complete('ele.', common.mustCall((err, data) => { testMe.complete('ele.', common.mustCall((err, data) => {
common.restoreStderr(); common.restoreStderr();
assert.ifError(err); assert.ifError(err);
@ -443,13 +433,12 @@ const warningRegEx = new RegExp(
Buffer.alloc(0) : Buffer.alloc(0) :
new type(0)); new type(0));
assert.strictEqual(data[0].includes('ele.biu'), true);
data[0].forEach((key) => { data[0].forEach((key) => {
if (!key) return; if (!key || key === 'ele.biu') return;
assert.notStrictEqual(ele[key.substr(4)], undefined); assert.notStrictEqual(ele[key.substr(4)], undefined);
}); });
// no `biu`
assert.strictEqual(data.includes('ele.biu'), false);
})); }));
}); });