Skip to content

Commit

Permalink
add a workaround for FF26- bug where ArrayBuffers are non-extensibl…
Browse files Browse the repository at this point in the history
…e, but `Object.isExtensible` does not report it
  • Loading branch information
zloirock committed Nov 1, 2021
1 parent 50da74b commit 55b232c
Show file tree
Hide file tree
Showing 17 changed files with 92 additions and 27 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
## Changelog
##### Unreleased
- Added a workaround for FF26- bug where `ArrayBuffer`s are non-extensible, but `Object.isExtensible` does not report it:
- Fixed in `Object.{ isExtensible, isSealed, isFrozen }` and `Reflect.isExtensible`
- Fixed handling of `ArrayBuffer`s as collections keys
- Fixed `Object#toString` on `AggregateError` in IE10-
- Fixed possible lack of dependencies of `WeakMap` in IE8-
- `.findLast` methods family marked as supported [from Chrome 97](https://chromestatus.com/features#milestone%3D97)
- Fixed inheritance of Electron compat data `web.` modules
- Fixed Safari 15.1 compat data (some features were not added)
Expand Down
10 changes: 10 additions & 0 deletions packages/core-js/internals/array-buffer-non-extensible.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// FF26- bug: ArrayBuffers are non-extensible, but Object.isExtensible does not report it
var fails = require('../internals/fails');

module.exports = fails(function () {
if (typeof ArrayBuffer == 'function') {
var buffer = new ArrayBuffer(8);
// eslint-disable-next-line es/no-object-isextensible, es/no-object-defineproperty -- safe
if (Object.isExtensible(buffer)) Object.defineProperty(buffer, 'a', { value: 8 });
}
});
6 changes: 1 addition & 5 deletions packages/core-js/internals/internal-metadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,14 @@ var hasOwn = require('../internals/has-own-property');
var defineProperty = require('../internals/object-define-property').f;
var getOwnPropertyNamesModule = require('../internals/object-get-own-property-names');
var getOwnPropertyNamesExternalModule = require('../internals/object-get-own-property-names-external');
var isExtensible = require('../internals/object-is-extensible');
var uid = require('../internals/uid');
var FREEZING = require('../internals/freezing');

var REQUIRED = false;
var METADATA = uid('meta');
var id = 0;

// eslint-disable-next-line es/no-object-isextensible -- safe
var isExtensible = Object.isExtensible || function () {
return true;
};

var setMetadata = function (it) {
defineProperty(it, METADATA, { value: {
objectID: 'O' + id++, // object ID
Expand Down
16 changes: 16 additions & 0 deletions packages/core-js/internals/object-is-extensible.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
var fails = require('../internals/fails');
var isObject = require('../internals/is-object');
var classof = require('../internals/classof-raw');
var ARRAY_BUFFER_NON_EXTENSIBLE = require('../internals/array-buffer-non-extensible');

// eslint-disable-next-line es/no-object-isextensible -- safe
var $isExtensible = Object.isExtensible;
var FAILS_ON_PRIMITIVES = fails(function () { $isExtensible(1); });

// `Object.isExtensible` method
// https://tc39.es/ecma262/#sec-object.isextensible
module.exports = (FAILS_ON_PRIMITIVES || ARRAY_BUFFER_NON_EXTENSIBLE) ? function isExtensible(it) {
if (!isObject(it)) return false;
if (ARRAY_BUFFER_NON_EXTENSIBLE && classof(it) == 'ArrayBuffer') return false;
return $isExtensible ? $isExtensible(it) : true;
} : $isExtensible;
14 changes: 4 additions & 10 deletions packages/core-js/modules/es.object.is-extensible.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
var $ = require('../internals/export');
var fails = require('../internals/fails');
var isObject = require('../internals/is-object');

// eslint-disable-next-line es/no-object-isextensible -- safe
var $isExtensible = Object.isExtensible;
var FAILS_ON_PRIMITIVES = fails(function () { $isExtensible(1); });
var $isExtensible = require('../internals/object-is-extensible');

// `Object.isExtensible` method
// https://tc39.es/ecma262/#sec-object.isextensible
$({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES }, {
isExtensible: function isExtensible(it) {
return isObject(it) ? $isExtensible ? $isExtensible(it) : true : false;
}
// eslint-disable-next-line es/no-object-isextensible -- safe
$({ target: 'Object', stat: true, forced: Object.isExtensible !== $isExtensible }, {
isExtensible: $isExtensible
});
8 changes: 6 additions & 2 deletions packages/core-js/modules/es.object.is-frozen.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
var $ = require('../internals/export');
var fails = require('../internals/fails');
var isObject = require('../internals/is-object');
var classof = require('../internals/classof-raw');
var ARRAY_BUFFER_NON_EXTENSIBLE = require('../internals/array-buffer-non-extensible');

// eslint-disable-next-line es/no-object-isfrozen -- safe
var $isFrozen = Object.isFrozen;
var FAILS_ON_PRIMITIVES = fails(function () { $isFrozen(1); });

// `Object.isFrozen` method
// https://tc39.es/ecma262/#sec-object.isfrozen
$({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES }, {
$({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES || ARRAY_BUFFER_NON_EXTENSIBLE }, {
isFrozen: function isFrozen(it) {
return isObject(it) ? $isFrozen ? $isFrozen(it) : false : true;
if (!isObject(it)) return true;
if (ARRAY_BUFFER_NON_EXTENSIBLE && classof(it) == 'ArrayBuffer') return true;
return $isFrozen ? $isFrozen(it) : false;
}
});
8 changes: 6 additions & 2 deletions packages/core-js/modules/es.object.is-sealed.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
var $ = require('../internals/export');
var fails = require('../internals/fails');
var isObject = require('../internals/is-object');
var classof = require('../internals/classof-raw');
var ARRAY_BUFFER_NON_EXTENSIBLE = require('../internals/array-buffer-non-extensible');

// eslint-disable-next-line es/no-object-issealed -- safe
var $isSealed = Object.isSealed;
var FAILS_ON_PRIMITIVES = fails(function () { $isSealed(1); });

// `Object.isSealed` method
// https://tc39.es/ecma262/#sec-object.issealed
$({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES }, {
$({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES || ARRAY_BUFFER_NON_EXTENSIBLE }, {
isSealed: function isSealed(it) {
return isObject(it) ? $isSealed ? $isSealed(it) : false : true;
if (!isObject(it)) return true;
if (ARRAY_BUFFER_NON_EXTENSIBLE && classof(it) == 'ArrayBuffer') return true;
return $isSealed ? $isSealed(it) : false;
}
});
6 changes: 2 additions & 4 deletions packages/core-js/modules/es.reflect.is-extensible.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
var $ = require('../internals/export');
var anObject = require('../internals/an-object');

// eslint-disable-next-line es/no-object-isextensible -- safe
var objectIsExtensible = Object.isExtensible;
var $isExtensible = require('../internals/object-is-extensible');

// `Reflect.isExtensible` method
// https://tc39.es/ecma262/#sec-reflect.isextensible
$({ target: 'Reflect', stat: true }, {
isExtensible: function isExtensible(target) {
anObject(target);
return objectIsExtensible ? objectIsExtensible(target) : true;
return $isExtensible(target);
}
});
3 changes: 1 addition & 2 deletions packages/core-js/modules/es.weak-map.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ var InternalMetadataModule = require('../internals/internal-metadata');
var collection = require('../internals/collection');
var collectionWeak = require('../internals/collection-weak');
var isObject = require('../internals/is-object');
var isExtensible = require('../internals/object-is-extensible');
var enforceIternalState = require('../internals/internal-state').enforce;
var NATIVE_WEAK_MAP = require('../internals/native-weak-map');

var IS_IE11 = !global.ActiveXObject && 'ActiveXObject' in global;
// eslint-disable-next-line es/no-object-isextensible -- safe
var isExtensible = Object.isExtensible;
var InternalWeakMap;

var wrapper = function (init) {
Expand Down
6 changes: 6 additions & 0 deletions tests/pure/es.map.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ QUnit.test('Map', assert => {
assert.ok(new Subclass() instanceof Map, 'correct subclassing with native classes #2');
assert.strictEqual(new Subclass().set(1, 2).get(1), 2, 'correct subclassing with native classes #3');
}

if (typeof ArrayBuffer == 'function') {
const buffer = new ArrayBuffer(8);
const map = new Map([[buffer, 8]]);
assert.ok(map.has(buffer), 'works with ArrayBuffer keys');
}
});

QUnit.test('Map#clear', assert => {
Expand Down
8 changes: 7 additions & 1 deletion tests/pure/es.set.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ QUnit.test('Set', assert => {
assert.ok('forEach' in Set.prototype, 'forEach in Set.prototype');
assert.ok('has' in Set.prototype, 'has in Set.prototype');
assert.ok(new Set() instanceof Set, 'new Set instanceof Set');
const set = new Set();
let set = new Set();
set.add(1);
set.add(2);
set.add(3);
Expand Down Expand Up @@ -74,6 +74,12 @@ QUnit.test('Set', assert => {
assert.ok(new Subclass() instanceof Set, 'correct subclassing with native classes #2');
assert.ok(new Subclass().add(2).has(2), 'correct subclassing with native classes #3');
}

if (typeof ArrayBuffer == 'function') {
const buffer = new ArrayBuffer(8);
set = new Set([buffer]);
assert.ok(set.has(buffer), 'works with ArrayBuffer keys');
}
});

QUnit.test('Set#add', assert => {
Expand Down
6 changes: 6 additions & 0 deletions tests/pure/es.weak-map.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ QUnit.test('WeakMap', assert => {
object = {};
assert.same(new Subclass().set(object, 2).get(object), 2, 'correct subclassing with native classes #3');
}

if (typeof ArrayBuffer == 'function') {
const buffer = new ArrayBuffer(8);
const map = new WeakMap([[buffer, 8]]);
assert.ok(map.has(buffer), 'works with ArrayBuffer keys');
}
});

QUnit.test('WeakMap#delete', assert => {
Expand Down
6 changes: 6 additions & 0 deletions tests/pure/es.weak-set.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ QUnit.test('WeakSet', assert => {
object = {};
assert.ok(new Subclass().add(object).has(object), 'correct subclassing with native classes #3');
}

if (typeof ArrayBuffer == 'function') {
const buffer = new ArrayBuffer(8);
const set = new WeakSet([buffer]);
assert.ok(set.has(buffer), 'works with ArrayBuffer keys');
}
});

QUnit.test('WeakSet#add', assert => {
Expand Down
4 changes: 4 additions & 0 deletions tests/tests/es.map.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ QUnit.test('Map', assert => {
assert.ok(new Subclass() instanceof Map, 'correct subclassing with native classes #2');
assert.strictEqual(new Subclass().set(1, 2).get(1), 2, 'correct subclassing with native classes #3');
}

const buffer = new ArrayBuffer(8);
const map = new Map([[buffer, 8]]);
assert.ok(map.has(buffer), 'works with ArrayBuffer keys');
});

QUnit.test('Map#clear', assert => {
Expand Down
6 changes: 5 additions & 1 deletion tests/tests/es.set.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ QUnit.test('Set', assert => {
assert.ok('forEach' in Set.prototype, 'forEach in Set.prototype');
assert.ok('has' in Set.prototype, 'has in Set.prototype');
assert.ok(new Set() instanceof Set, 'new Set instanceof Set');
const set = new Set();
let set = new Set();
set.add(1);
set.add(2);
set.add(3);
Expand Down Expand Up @@ -77,6 +77,10 @@ QUnit.test('Set', assert => {
assert.ok(new Subclass() instanceof Set, 'correct subclassing with native classes #2');
assert.ok(new Subclass().add(2).has(2), 'correct subclassing with native classes #3');
}

const buffer = new ArrayBuffer(8);
set = new Set([buffer]);
assert.ok(set.has(buffer), 'works with ArrayBuffer keys');
});

QUnit.test('Set#add', assert => {
Expand Down
4 changes: 4 additions & 0 deletions tests/tests/es.weak-map.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ QUnit.test('WeakMap', assert => {
object = {};
assert.same(new Subclass().set(object, 2).get(object), 2, 'correct subclassing with native classes #3');
}

const buffer = new ArrayBuffer(8);
const map = new WeakMap([[buffer, 8]]);
assert.ok(map.has(buffer), 'works with ArrayBuffer keys');
});

QUnit.test('WeakMap#delete', assert => {
Expand Down
4 changes: 4 additions & 0 deletions tests/tests/es.weak-set.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ QUnit.test('WeakSet', assert => {
object = {};
assert.ok(new Subclass().add(object).has(object), 'correct subclassing with native classes #3');
}

const buffer = new ArrayBuffer(8);
const set = new WeakSet([buffer]);
assert.ok(set.has(buffer), 'works with ArrayBuffer keys');
});

QUnit.test('WeakSet#add', assert => {
Expand Down

0 comments on commit 55b232c

Please sign in to comment.