Skip to content

Commit 4c14f5f

Browse files
committed
Fix for "__proto__" in Object.create(null).
Blech.
1 parent 9bcc57c commit 4c14f5f

File tree

4 files changed

+219
-75
lines changed

4 files changed

+219
-75
lines changed

d3.js

Lines changed: 97 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,9 @@
234234
ctor.prototype = properties;
235235
}
236236
}
237+
function d3_identity(d) {
238+
return d;
239+
}
237240
d3.map = function(object) {
238241
var map = new d3_Map();
239242
if (object instanceof d3_Map) object.forEach(function(key, value) {
@@ -244,41 +247,67 @@
244247
function d3_Map() {
245248
this._ = Object.create(null);
246249
}
247-
d3_class(d3_Map, {
250+
var d3_map_proto = "__proto__", d3_map_zero = "\x00", d3_map_prototype = {
248251
has: d3_map_has,
249-
get: function(key) {
250-
return this._[key];
251-
},
252-
set: function(key, value) {
253-
return this._[key] = value;
254-
},
252+
get: d3_map_get,
253+
set: d3_map_set,
255254
remove: d3_map_remove,
256255
keys: d3_map_keys,
257-
values: function() {
258-
var values = [];
256+
values: d3_map_values,
257+
entries: d3_map_entries,
258+
size: d3_map_size,
259+
empty: d3_map_empty,
260+
forEach: d3_map_forEach
261+
};
262+
if (d3_map_proto in Object.create(null)) {
263+
d3_map_prototype.get = function(key) {
264+
return this._[d3_map_escape(key)];
265+
};
266+
d3_map_prototype.set = function(key, value) {
267+
return this._[d3_map_escape(key)] = value;
268+
};
269+
d3_map_prototype.has = function(key) {
270+
return d3_map_escape(key) in this._;
271+
};
272+
d3_map_prototype.remove = function(key) {
273+
return (key = d3_map_escape(key)) in this._ && delete this._[key];
274+
};
275+
d3_map_prototype.keys = function() {
276+
var keys = [];
259277
for (var key in this._) {
260-
values.push(this._[key]);
278+
keys.push(d3_map_unescape(key));
261279
}
262-
return values;
263-
},
264-
entries: function() {
280+
return keys;
281+
};
282+
d3_map_prototype.entries = function() {
265283
var entries = [];
266284
for (var key in this._) {
267285
entries.push({
268-
key: key,
286+
key: d3_map_unescape(key),
269287
value: this._[key]
270288
});
271289
}
272290
return entries;
273-
},
274-
size: d3_map_size,
275-
empty: d3_map_empty,
276-
forEach: function(f) {
291+
};
292+
d3_map_prototype.forEach = function(f) {
277293
for (var key in this._) {
278-
f.call(this, key, this._[key]);
294+
f.call(this, d3_map_unescape(key), this._[key]);
279295
}
280-
}
281-
});
296+
};
297+
}
298+
d3_class(d3_Map, d3_map_prototype);
299+
function d3_map_escape(key) {
300+
return (key += "") === d3_map_proto || key[0] === d3_map_zero ? d3_map_zero + key : key;
301+
}
302+
function d3_map_unescape(key) {
303+
return (key += "")[0] === d3_map_zero ? key.slice(1) : key;
304+
}
305+
function d3_map_get(key) {
306+
return this._[key];
307+
}
308+
function d3_map_set(key, value) {
309+
return this._[key] = value;
310+
}
282311
function d3_map_has(key) {
283312
return key in this._;
284313
}
@@ -292,6 +321,23 @@
292321
}
293322
return keys;
294323
}
324+
function d3_map_values() {
325+
var values = [];
326+
for (var key in this._) {
327+
values.push(this._[key]);
328+
}
329+
return values;
330+
}
331+
function d3_map_entries() {
332+
var entries = [];
333+
for (var key in this._) {
334+
entries.push({
335+
key: key,
336+
value: this._[key]
337+
});
338+
}
339+
return entries;
340+
}
295341
function d3_map_size() {
296342
var size = 0;
297343
for (var key in this._) {
@@ -305,6 +351,11 @@
305351
}
306352
return true;
307353
}
354+
function d3_map_forEach(f) {
355+
for (var key in this._) {
356+
f.call(this, key, this._[key]);
357+
}
358+
}
308359
d3.nest = function() {
309360
var nest = {}, keys = [], sortKeys = [], sortValues, rollup;
310361
function map(mapType, array, depth) {
@@ -376,22 +427,36 @@
376427
function d3_Set() {
377428
this._ = Object.create(null);
378429
}
379-
d3_class(d3_Set, {
380-
has: d3_map_has,
381-
add: function(key) {
382-
this._[key] = true;
383-
return key;
384-
},
385-
remove: d3_map_remove,
386-
values: d3_map_keys,
430+
var d3_set_prototype = {
431+
has: d3_map_prototype.has,
432+
add: d3_set_add,
433+
remove: d3_map_prototype.remove,
434+
values: d3_map_prototype.keys,
387435
size: d3_map_size,
388436
empty: d3_map_empty,
389-
forEach: function(f) {
437+
forEach: d3_set_forEach
438+
};
439+
if (d3_map_proto in Object.create(null)) {
440+
d3_set_prototype.add = function(key) {
441+
this._[d3_map_escape(key)] = true;
442+
return key;
443+
};
444+
d3_set_prototype.forEach = function(f) {
390445
for (var key in this._) {
391-
f.call(this, key);
446+
f.call(this, d3_map_unescape(key));
392447
}
448+
};
449+
}
450+
d3_class(d3_Set, d3_set_prototype);
451+
function d3_set_add(key) {
452+
this._[key] = true;
453+
return key;
454+
}
455+
function d3_set_forEach(f) {
456+
for (var key in this._) {
457+
f.call(this, key);
393458
}
394-
});
459+
}
395460
d3.behavior = {};
396461
d3.rebind = function(target, source) {
397462
var i = 1, n = arguments.length, method;
@@ -1837,9 +1902,6 @@
18371902
};
18381903
}
18391904
d3.functor = d3_functor;
1840-
function d3_identity(d) {
1841-
return d;
1842-
}
18431905
d3.xhr = d3_xhrType(d3_identity);
18441906
function d3_xhrType(response) {
18451907
return function(url, mimeType, callback) {

d3.min.js

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/arrays/map.js

Lines changed: 87 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import "../core/class";
2+
import "../core/identity";
23

34
d3.map = function(object) {
45
var map = new d3_Map;
@@ -11,38 +12,78 @@ function d3_Map() {
1112
this._ = Object.create(null);
1213
}
1314

14-
d3_class(d3_Map, {
15-
has: d3_map_has,
16-
get: function(key) {
17-
return this._[key];
18-
},
19-
set: function(key, value) {
20-
return this._[key] = value;
21-
},
22-
remove: d3_map_remove,
23-
keys: d3_map_keys,
24-
values: function() {
25-
var values = [];
15+
var d3_map_proto = "__proto__",
16+
d3_map_zero = "\0",
17+
d3_map_prototype = {
18+
has: d3_map_has,
19+
get: d3_map_get,
20+
set: d3_map_set,
21+
remove: d3_map_remove,
22+
keys: d3_map_keys,
23+
values: d3_map_values,
24+
entries: d3_map_entries,
25+
size: d3_map_size,
26+
empty: d3_map_empty,
27+
forEach: d3_map_forEach
28+
};
29+
30+
if (d3_map_proto in Object.create(null)) {
31+
d3_map_prototype.get = function(key) {
32+
return this._[d3_map_escape(key)];
33+
};
34+
35+
d3_map_prototype.set = function(key, value) {
36+
return this._[d3_map_escape(key)] = value;
37+
};
38+
39+
d3_map_prototype.has = function(key) {
40+
return d3_map_escape(key) in this._;
41+
};
42+
43+
d3_map_prototype.remove = function(key) {
44+
return (key = d3_map_escape(key)) in this._ && delete this._[key];
45+
};
46+
47+
d3_map_prototype.keys = function() {
48+
var keys = [];
2649
for (var key in this._) {
27-
values.push(this._[key]);
50+
keys.push(d3_map_unescape(key));
2851
}
29-
return values;
30-
},
31-
entries: function() {
52+
return keys;
53+
};
54+
55+
d3_map_prototype.entries = function() {
3256
var entries = [];
3357
for (var key in this._) {
34-
entries.push({key: key, value: this._[key]});
58+
entries.push({key: d3_map_unescape(key), value: this._[key]});
3559
}
3660
return entries;
37-
},
38-
size: d3_map_size,
39-
empty: d3_map_empty,
40-
forEach: function(f) {
61+
};
62+
63+
d3_map_prototype.forEach = function(f) {
4164
for (var key in this._) {
42-
f.call(this, key, this._[key]);
65+
f.call(this, d3_map_unescape(key), this._[key]);
4366
}
44-
}
45-
});
67+
};
68+
}
69+
70+
d3_class(d3_Map, d3_map_prototype);
71+
72+
function d3_map_escape(key) {
73+
return (key += "") === d3_map_proto || key[0] === d3_map_zero ? d3_map_zero + key : key;
74+
}
75+
76+
function d3_map_unescape(key) {
77+
return (key += "")[0] === d3_map_zero ? key.slice(1) : key;
78+
}
79+
80+
function d3_map_get(key) {
81+
return this._[key];
82+
}
83+
84+
function d3_map_set(key, value) {
85+
return this._[key] = value;
86+
}
4687

4788
function d3_map_has(key) {
4889
return key in this._;
@@ -60,6 +101,22 @@ function d3_map_keys() {
60101
return keys;
61102
}
62103

104+
function d3_map_values() {
105+
var values = [];
106+
for (var key in this._) {
107+
values.push(this._[key]);
108+
}
109+
return values;
110+
}
111+
112+
function d3_map_entries() {
113+
var entries = [];
114+
for (var key in this._) {
115+
entries.push({key: key, value: this._[key]});
116+
}
117+
return entries;
118+
}
119+
63120
function d3_map_size() {
64121
var size = 0;
65122
for (var key in this._) {
@@ -74,3 +131,9 @@ function d3_map_empty() {
74131
}
75132
return true;
76133
}
134+
135+
function d3_map_forEach(f) {
136+
for (var key in this._) {
137+
f.call(this, key, this._[key]);
138+
}
139+
}

src/arrays/set.js

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,38 @@ function d3_Set() {
1111
this._ = Object.create(null);
1212
}
1313

14-
d3_class(d3_Set, {
15-
has: d3_map_has,
16-
add: function(key) {
17-
this._[key] = true;
18-
return key;
19-
},
20-
remove: d3_map_remove,
21-
values: d3_map_keys,
14+
var d3_set_prototype = {
15+
has: d3_map_prototype.has,
16+
add: d3_set_add,
17+
remove: d3_map_prototype.remove,
18+
values: d3_map_prototype.keys,
2219
size: d3_map_size,
2320
empty: d3_map_empty,
24-
forEach: function(f) {
21+
forEach: d3_set_forEach
22+
};
23+
24+
if (d3_map_proto in Object.create(null)) {
25+
d3_set_prototype.add = function(key) {
26+
this._[d3_map_escape(key)] = true;
27+
return key;
28+
};
29+
30+
d3_set_prototype.forEach = function(f) {
2531
for (var key in this._) {
26-
f.call(this, key);
32+
f.call(this, d3_map_unescape(key));
2733
}
34+
};
35+
}
36+
37+
d3_class(d3_Set, d3_set_prototype);
38+
39+
function d3_set_add(key) {
40+
this._[key] = true;
41+
return key;
42+
}
43+
44+
function d3_set_forEach(f) {
45+
for (var key in this._) {
46+
f.call(this, key);
2847
}
29-
});
48+
}

0 commit comments

Comments
 (0)