Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 8dfdee3

Browse filesBrowse files
evanlucasjasnell
authored andcommitted
util: correctly inspect Map/Set Iterators
Previously, a MapIterator or SetIterator would not be inspected properly. This change makes it possible to inspect them by creating a Debug Mirror and previewing the iterators to not consume the actual iterator that we are trying to inspect. This change also adds a node_util binding that uses v8's Value::IsSetIterator and Value::IsMapIterator to verify that the values passed in are actual iterators. Fixes: #3107 PR-URL: #3119 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
1 parent b5c51fd commit 8dfdee3
Copy full SHA for 8dfdee3

File tree

Expand file treeCollapse file tree

4 files changed

+89
-5
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

4 files changed

+89
-5
lines changed
Open diff view settings
Collapse file

‎lib/util.js‎

Copy file name to clipboardExpand all lines: lib/util.js
+30-5Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const uv = process.binding('uv');
44
const Buffer = require('buffer').Buffer;
55
const internalUtil = require('internal/util');
6+
const binding = process.binding('util');
67

78
var Debug;
89
var ObjectIsPromise;
@@ -323,11 +324,23 @@ function formatValue(ctx, value, recurseTimes) {
323324
braces = ['{', '}'];
324325
formatter = formatPromise;
325326
} else {
326-
if (constructor === Object)
327-
constructor = null;
328-
braces = ['{', '}'];
329-
empty = true; // No other data than keys.
330-
formatter = formatObject;
327+
if (binding.isMapIterator(value)) {
328+
constructor = { name: 'MapIterator' };
329+
braces = ['{', '}'];
330+
empty = false;
331+
formatter = formatCollectionIterator;
332+
} else if (binding.isSetIterator(value)) {
333+
constructor = { name: 'SetIterator' };
334+
braces = ['{', '}'];
335+
empty = false;
336+
formatter = formatCollectionIterator;
337+
} else {
338+
if (constructor === Object)
339+
constructor = null;
340+
braces = ['{', '}'];
341+
empty = true; // No other data than keys.
342+
formatter = formatObject;
343+
}
331344
}
332345
}
333346

@@ -501,6 +514,18 @@ function formatMap(ctx, value, recurseTimes, visibleKeys, keys) {
501514
return output;
502515
}
503516

517+
function formatCollectionIterator(ctx, value, recurseTimes, visibleKeys, keys) {
518+
ensureDebugIsInitialized();
519+
const mirror = Debug.MakeMirror(value, true);
520+
var nextRecurseTimes = recurseTimes === null ? null : recurseTimes - 1;
521+
var vals = mirror.preview();
522+
var output = [];
523+
for (let o of vals) {
524+
output.push(formatValue(ctx, o, nextRecurseTimes));
525+
}
526+
return output;
527+
}
528+
504529
function formatPromise(ctx, value, recurseTimes, visibleKeys, keys) {
505530
var output = [];
506531
var internals = inspectPromise(value);
Collapse file

‎node.gyp‎

Copy file name to clipboardExpand all lines: node.gyp
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
'src/node_javascript.cc',
116116
'src/node_main.cc',
117117
'src/node_os.cc',
118+
'src/node_util.cc',
118119
'src/node_v8.cc',
119120
'src/node_stat_watcher.cc',
120121
'src/node_watchdog.cc',
Collapse file

‎src/node_util.cc‎

Copy file name to clipboard
+38Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include "node.h"
2+
#include "v8.h"
3+
#include "env.h"
4+
#include "env-inl.h"
5+
6+
namespace node {
7+
namespace util {
8+
9+
using v8::Context;
10+
using v8::FunctionCallbackInfo;
11+
using v8::Local;
12+
using v8::Object;
13+
using v8::Value;
14+
15+
static void IsMapIterator(const FunctionCallbackInfo<Value>& args) {
16+
CHECK_EQ(1, args.Length());
17+
args.GetReturnValue().Set(args[0]->IsMapIterator());
18+
}
19+
20+
21+
static void IsSetIterator(const FunctionCallbackInfo<Value>& args) {
22+
CHECK_EQ(1, args.Length());
23+
args.GetReturnValue().Set(args[0]->IsSetIterator());
24+
}
25+
26+
27+
void Initialize(Local<Object> target,
28+
Local<Value> unused,
29+
Local<Context> context) {
30+
Environment* env = Environment::GetCurrent(context);
31+
env->SetMethod(target, "isMapIterator", IsMapIterator);
32+
env->SetMethod(target, "isSetIterator", IsSetIterator);
33+
}
34+
35+
} // namespace util
36+
} // namespace node
37+
38+
NODE_MODULE_CONTEXT_AWARE_BUILTIN(util, node::util::Initialize)
Collapse file

‎test/parallel/test-util-inspect.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-util-inspect.js
+20Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,26 @@ global.Promise = function() { this.bar = 42; };
287287
assert.equal(util.inspect(new Promise()), '{ bar: 42 }');
288288
global.Promise = oldPromise;
289289

290+
// Map/Set Iterators
291+
var m = new Map([['foo', 'bar']]);
292+
assert.strictEqual(util.inspect(m.keys()), 'MapIterator { \'foo\' }');
293+
assert.strictEqual(util.inspect(m.values()), 'MapIterator { \'bar\' }');
294+
assert.strictEqual(util.inspect(m.entries()),
295+
'MapIterator { [ \'foo\', \'bar\' ] }');
296+
// make sure the iterator doesn't get consumed
297+
var keys = m.keys();
298+
assert.strictEqual(util.inspect(keys), 'MapIterator { \'foo\' }');
299+
assert.strictEqual(util.inspect(keys), 'MapIterator { \'foo\' }');
300+
301+
var s = new Set([1, 3]);
302+
assert.strictEqual(util.inspect(s.keys()), 'SetIterator { 1, 3 }');
303+
assert.strictEqual(util.inspect(s.values()), 'SetIterator { 1, 3 }');
304+
assert.strictEqual(util.inspect(s.entries()),
305+
'SetIterator { [ 1, 1 ], [ 3, 3 ] }');
306+
// make sure the iterator doesn't get consumed
307+
keys = s.keys();
308+
assert.strictEqual(util.inspect(keys), 'SetIterator { 1, 3 }');
309+
assert.strictEqual(util.inspect(keys), 'SetIterator { 1, 3 }');
290310

291311
// Test alignment of items in container
292312
// Assumes that the first numeric character is the start of an item.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.