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:
parent
c35ce5635c
commit
68b07ded9c
@ -366,7 +366,6 @@ function isInsideNodeModules() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
assertCrypto,
|
assertCrypto,
|
||||||
cachedResult,
|
cachedResult,
|
||||||
|
@ -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);
|
||||||
|
36
lib/repl.js
36
lib/repl.js
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user