From 72bc480663b6071b07b9e5d3c69765851b9d5beb Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Tue, 13 Dec 2022 12:04:07 -0800 Subject: [PATCH] [New] `ES2015`+ (`ObjectCreate`) and `ES2020`+ (`OrdinaryObjectCreate`): use `internal-slot` to support additional slots --- 2015/ObjectCreate.js | 37 +++++++++++++++++++---------- 2016/ObjectCreate.js | 37 +++++++++++++++++++---------- 2017/ObjectCreate.js | 37 +++++++++++++++++++---------- 2018/ObjectCreate.js | 37 +++++++++++++++++++---------- 2019/ObjectCreate.js | 37 +++++++++++++++++++---------- 2020/OrdinaryObjectCreate.js | 46 ++++++++++++++++++++++-------------- 2021/OrdinaryObjectCreate.js | 46 ++++++++++++++++++++++-------------- 2022/OrdinaryObjectCreate.js | 46 ++++++++++++++++++++++-------------- test/tests.js | 43 ++++++++++++++++++++++++++------- 9 files changed, 243 insertions(+), 123 deletions(-) diff --git a/2015/ObjectCreate.js b/2015/ObjectCreate.js index 932ed369..1f4bb16a 100644 --- a/2015/ObjectCreate.js +++ b/2015/ObjectCreate.js @@ -6,8 +6,13 @@ var $ObjectCreate = GetIntrinsic('%Object.create%', true); var $TypeError = GetIntrinsic('%TypeError%'); var $SyntaxError = GetIntrinsic('%SyntaxError%'); +var IsArray = require('./IsArray'); var Type = require('./Type'); +var forEach = require('../helpers/forEach'); + +var SLOT = require('internal-slot'); + var hasProto = require('has-proto')(); // https://ecma-international.org/ecma-262/6.0/#sec-objectcreate @@ -16,22 +21,30 @@ module.exports = function ObjectCreate(proto, internalSlotsList) { if (proto !== null && Type(proto) !== 'Object') { throw new $TypeError('Assertion failed: `proto` must be null or an object'); } - var slots = arguments.length < 2 ? [] : internalSlotsList; - if (slots.length > 0) { - throw new $SyntaxError('es-abstract does not yet support internal slots'); + var slots = arguments.length < 2 ? [] : internalSlotsList; // step 1 + if (arguments.length >= 2 && !IsArray(slots)) { + throw new $TypeError('Assertion failed: `internalSlotsList` must be an Array'); } + var O; if ($ObjectCreate) { - return $ObjectCreate(proto); - } - if (hasProto) { - return { __proto__: proto }; + O = $ObjectCreate(proto); + } else if (hasProto) { + O = { __proto__: proto }; + } else { + if (proto === null) { + throw new $SyntaxError('native Object.create support is required to create null objects'); + } + var T = function T() {}; + T.prototype = proto; + O = new T(); } - if (proto === null) { - throw new $SyntaxError('native Object.create support is required to create null objects'); + if (slots.length > 0) { + forEach(slots, function (slot) { + SLOT.set(O, slot, void undefined); + }); } - var T = function T() {}; - T.prototype = proto; - return new T(); + + return O; // step 6 }; diff --git a/2016/ObjectCreate.js b/2016/ObjectCreate.js index 932ed369..1f4bb16a 100644 --- a/2016/ObjectCreate.js +++ b/2016/ObjectCreate.js @@ -6,8 +6,13 @@ var $ObjectCreate = GetIntrinsic('%Object.create%', true); var $TypeError = GetIntrinsic('%TypeError%'); var $SyntaxError = GetIntrinsic('%SyntaxError%'); +var IsArray = require('./IsArray'); var Type = require('./Type'); +var forEach = require('../helpers/forEach'); + +var SLOT = require('internal-slot'); + var hasProto = require('has-proto')(); // https://ecma-international.org/ecma-262/6.0/#sec-objectcreate @@ -16,22 +21,30 @@ module.exports = function ObjectCreate(proto, internalSlotsList) { if (proto !== null && Type(proto) !== 'Object') { throw new $TypeError('Assertion failed: `proto` must be null or an object'); } - var slots = arguments.length < 2 ? [] : internalSlotsList; - if (slots.length > 0) { - throw new $SyntaxError('es-abstract does not yet support internal slots'); + var slots = arguments.length < 2 ? [] : internalSlotsList; // step 1 + if (arguments.length >= 2 && !IsArray(slots)) { + throw new $TypeError('Assertion failed: `internalSlotsList` must be an Array'); } + var O; if ($ObjectCreate) { - return $ObjectCreate(proto); - } - if (hasProto) { - return { __proto__: proto }; + O = $ObjectCreate(proto); + } else if (hasProto) { + O = { __proto__: proto }; + } else { + if (proto === null) { + throw new $SyntaxError('native Object.create support is required to create null objects'); + } + var T = function T() {}; + T.prototype = proto; + O = new T(); } - if (proto === null) { - throw new $SyntaxError('native Object.create support is required to create null objects'); + if (slots.length > 0) { + forEach(slots, function (slot) { + SLOT.set(O, slot, void undefined); + }); } - var T = function T() {}; - T.prototype = proto; - return new T(); + + return O; // step 6 }; diff --git a/2017/ObjectCreate.js b/2017/ObjectCreate.js index 932ed369..1f4bb16a 100644 --- a/2017/ObjectCreate.js +++ b/2017/ObjectCreate.js @@ -6,8 +6,13 @@ var $ObjectCreate = GetIntrinsic('%Object.create%', true); var $TypeError = GetIntrinsic('%TypeError%'); var $SyntaxError = GetIntrinsic('%SyntaxError%'); +var IsArray = require('./IsArray'); var Type = require('./Type'); +var forEach = require('../helpers/forEach'); + +var SLOT = require('internal-slot'); + var hasProto = require('has-proto')(); // https://ecma-international.org/ecma-262/6.0/#sec-objectcreate @@ -16,22 +21,30 @@ module.exports = function ObjectCreate(proto, internalSlotsList) { if (proto !== null && Type(proto) !== 'Object') { throw new $TypeError('Assertion failed: `proto` must be null or an object'); } - var slots = arguments.length < 2 ? [] : internalSlotsList; - if (slots.length > 0) { - throw new $SyntaxError('es-abstract does not yet support internal slots'); + var slots = arguments.length < 2 ? [] : internalSlotsList; // step 1 + if (arguments.length >= 2 && !IsArray(slots)) { + throw new $TypeError('Assertion failed: `internalSlotsList` must be an Array'); } + var O; if ($ObjectCreate) { - return $ObjectCreate(proto); - } - if (hasProto) { - return { __proto__: proto }; + O = $ObjectCreate(proto); + } else if (hasProto) { + O = { __proto__: proto }; + } else { + if (proto === null) { + throw new $SyntaxError('native Object.create support is required to create null objects'); + } + var T = function T() {}; + T.prototype = proto; + O = new T(); } - if (proto === null) { - throw new $SyntaxError('native Object.create support is required to create null objects'); + if (slots.length > 0) { + forEach(slots, function (slot) { + SLOT.set(O, slot, void undefined); + }); } - var T = function T() {}; - T.prototype = proto; - return new T(); + + return O; // step 6 }; diff --git a/2018/ObjectCreate.js b/2018/ObjectCreate.js index 932ed369..1f4bb16a 100644 --- a/2018/ObjectCreate.js +++ b/2018/ObjectCreate.js @@ -6,8 +6,13 @@ var $ObjectCreate = GetIntrinsic('%Object.create%', true); var $TypeError = GetIntrinsic('%TypeError%'); var $SyntaxError = GetIntrinsic('%SyntaxError%'); +var IsArray = require('./IsArray'); var Type = require('./Type'); +var forEach = require('../helpers/forEach'); + +var SLOT = require('internal-slot'); + var hasProto = require('has-proto')(); // https://ecma-international.org/ecma-262/6.0/#sec-objectcreate @@ -16,22 +21,30 @@ module.exports = function ObjectCreate(proto, internalSlotsList) { if (proto !== null && Type(proto) !== 'Object') { throw new $TypeError('Assertion failed: `proto` must be null or an object'); } - var slots = arguments.length < 2 ? [] : internalSlotsList; - if (slots.length > 0) { - throw new $SyntaxError('es-abstract does not yet support internal slots'); + var slots = arguments.length < 2 ? [] : internalSlotsList; // step 1 + if (arguments.length >= 2 && !IsArray(slots)) { + throw new $TypeError('Assertion failed: `internalSlotsList` must be an Array'); } + var O; if ($ObjectCreate) { - return $ObjectCreate(proto); - } - if (hasProto) { - return { __proto__: proto }; + O = $ObjectCreate(proto); + } else if (hasProto) { + O = { __proto__: proto }; + } else { + if (proto === null) { + throw new $SyntaxError('native Object.create support is required to create null objects'); + } + var T = function T() {}; + T.prototype = proto; + O = new T(); } - if (proto === null) { - throw new $SyntaxError('native Object.create support is required to create null objects'); + if (slots.length > 0) { + forEach(slots, function (slot) { + SLOT.set(O, slot, void undefined); + }); } - var T = function T() {}; - T.prototype = proto; - return new T(); + + return O; // step 6 }; diff --git a/2019/ObjectCreate.js b/2019/ObjectCreate.js index 932ed369..1f4bb16a 100644 --- a/2019/ObjectCreate.js +++ b/2019/ObjectCreate.js @@ -6,8 +6,13 @@ var $ObjectCreate = GetIntrinsic('%Object.create%', true); var $TypeError = GetIntrinsic('%TypeError%'); var $SyntaxError = GetIntrinsic('%SyntaxError%'); +var IsArray = require('./IsArray'); var Type = require('./Type'); +var forEach = require('../helpers/forEach'); + +var SLOT = require('internal-slot'); + var hasProto = require('has-proto')(); // https://ecma-international.org/ecma-262/6.0/#sec-objectcreate @@ -16,22 +21,30 @@ module.exports = function ObjectCreate(proto, internalSlotsList) { if (proto !== null && Type(proto) !== 'Object') { throw new $TypeError('Assertion failed: `proto` must be null or an object'); } - var slots = arguments.length < 2 ? [] : internalSlotsList; - if (slots.length > 0) { - throw new $SyntaxError('es-abstract does not yet support internal slots'); + var slots = arguments.length < 2 ? [] : internalSlotsList; // step 1 + if (arguments.length >= 2 && !IsArray(slots)) { + throw new $TypeError('Assertion failed: `internalSlotsList` must be an Array'); } + var O; if ($ObjectCreate) { - return $ObjectCreate(proto); - } - if (hasProto) { - return { __proto__: proto }; + O = $ObjectCreate(proto); + } else if (hasProto) { + O = { __proto__: proto }; + } else { + if (proto === null) { + throw new $SyntaxError('native Object.create support is required to create null objects'); + } + var T = function T() {}; + T.prototype = proto; + O = new T(); } - if (proto === null) { - throw new $SyntaxError('native Object.create support is required to create null objects'); + if (slots.length > 0) { + forEach(slots, function (slot) { + SLOT.set(O, slot, void undefined); + }); } - var T = function T() {}; - T.prototype = proto; - return new T(); + + return O; // step 6 }; diff --git a/2020/OrdinaryObjectCreate.js b/2020/OrdinaryObjectCreate.js index 5fb57f21..14053408 100644 --- a/2020/OrdinaryObjectCreate.js +++ b/2020/OrdinaryObjectCreate.js @@ -9,9 +9,13 @@ var $SyntaxError = GetIntrinsic('%SyntaxError%'); var IsArray = require('./IsArray'); var Type = require('./Type'); +var forEach = require('../helpers/forEach'); + +var SLOT = require('internal-slot'); + var hasProto = require('has-proto')(); -// https://262.ecma-international.org/6.0/#sec-objectcreate +// https://262.ecma-international.org/11.0/#sec-objectcreate module.exports = function OrdinaryObjectCreate(proto) { if (proto !== null && Type(proto) !== 'Object') { @@ -21,26 +25,32 @@ module.exports = function OrdinaryObjectCreate(proto) { if (!IsArray(additionalInternalSlotsList)) { throw new $TypeError('Assertion failed: `additionalInternalSlotsList` must be an Array'); } - // var internalSlotsList = ['[[Prototype]]', '[[Extensible]]']; - if (additionalInternalSlotsList.length > 0) { - throw new $SyntaxError('es-abstract does not yet support internal slots'); - // internalSlotsList.push(...additionalInternalSlotsList); - } - // var O = MakeBasicObject(internalSlotsList); - // setProto(O, proto); - // return O; + // var internalSlotsList = ['[[Prototype]]', '[[Extensible]]']; // step 1 + // internalSlotsList.push(...additionalInternalSlotsList); // step 2 + // var O = MakeBasicObject(internalSlotsList); // step 3 + // setProto(O, proto); // step 4 + // return O; // step 5 + + var O; if ($ObjectCreate) { - return $ObjectCreate(proto); - } - if (hasProto) { - return { __proto__: proto }; + O = $ObjectCreate(proto); + } else if (hasProto) { + O = { __proto__: proto }; + } else { + if (proto === null) { + throw new $SyntaxError('native Object.create support is required to create null objects'); + } + var T = function T() {}; + T.prototype = proto; + O = new T(); } - if (proto === null) { - throw new $SyntaxError('native Object.create support is required to create null objects'); + if (additionalInternalSlotsList.length > 0) { + forEach(additionalInternalSlotsList, function (slot) { + SLOT.set(O, slot, void undefined); + }); } - var T = function T() {}; - T.prototype = proto; - return new T(); + + return O; }; diff --git a/2021/OrdinaryObjectCreate.js b/2021/OrdinaryObjectCreate.js index 5fb57f21..14053408 100644 --- a/2021/OrdinaryObjectCreate.js +++ b/2021/OrdinaryObjectCreate.js @@ -9,9 +9,13 @@ var $SyntaxError = GetIntrinsic('%SyntaxError%'); var IsArray = require('./IsArray'); var Type = require('./Type'); +var forEach = require('../helpers/forEach'); + +var SLOT = require('internal-slot'); + var hasProto = require('has-proto')(); -// https://262.ecma-international.org/6.0/#sec-objectcreate +// https://262.ecma-international.org/11.0/#sec-objectcreate module.exports = function OrdinaryObjectCreate(proto) { if (proto !== null && Type(proto) !== 'Object') { @@ -21,26 +25,32 @@ module.exports = function OrdinaryObjectCreate(proto) { if (!IsArray(additionalInternalSlotsList)) { throw new $TypeError('Assertion failed: `additionalInternalSlotsList` must be an Array'); } - // var internalSlotsList = ['[[Prototype]]', '[[Extensible]]']; - if (additionalInternalSlotsList.length > 0) { - throw new $SyntaxError('es-abstract does not yet support internal slots'); - // internalSlotsList.push(...additionalInternalSlotsList); - } - // var O = MakeBasicObject(internalSlotsList); - // setProto(O, proto); - // return O; + // var internalSlotsList = ['[[Prototype]]', '[[Extensible]]']; // step 1 + // internalSlotsList.push(...additionalInternalSlotsList); // step 2 + // var O = MakeBasicObject(internalSlotsList); // step 3 + // setProto(O, proto); // step 4 + // return O; // step 5 + + var O; if ($ObjectCreate) { - return $ObjectCreate(proto); - } - if (hasProto) { - return { __proto__: proto }; + O = $ObjectCreate(proto); + } else if (hasProto) { + O = { __proto__: proto }; + } else { + if (proto === null) { + throw new $SyntaxError('native Object.create support is required to create null objects'); + } + var T = function T() {}; + T.prototype = proto; + O = new T(); } - if (proto === null) { - throw new $SyntaxError('native Object.create support is required to create null objects'); + if (additionalInternalSlotsList.length > 0) { + forEach(additionalInternalSlotsList, function (slot) { + SLOT.set(O, slot, void undefined); + }); } - var T = function T() {}; - T.prototype = proto; - return new T(); + + return O; }; diff --git a/2022/OrdinaryObjectCreate.js b/2022/OrdinaryObjectCreate.js index 5fb57f21..14053408 100644 --- a/2022/OrdinaryObjectCreate.js +++ b/2022/OrdinaryObjectCreate.js @@ -9,9 +9,13 @@ var $SyntaxError = GetIntrinsic('%SyntaxError%'); var IsArray = require('./IsArray'); var Type = require('./Type'); +var forEach = require('../helpers/forEach'); + +var SLOT = require('internal-slot'); + var hasProto = require('has-proto')(); -// https://262.ecma-international.org/6.0/#sec-objectcreate +// https://262.ecma-international.org/11.0/#sec-objectcreate module.exports = function OrdinaryObjectCreate(proto) { if (proto !== null && Type(proto) !== 'Object') { @@ -21,26 +25,32 @@ module.exports = function OrdinaryObjectCreate(proto) { if (!IsArray(additionalInternalSlotsList)) { throw new $TypeError('Assertion failed: `additionalInternalSlotsList` must be an Array'); } - // var internalSlotsList = ['[[Prototype]]', '[[Extensible]]']; - if (additionalInternalSlotsList.length > 0) { - throw new $SyntaxError('es-abstract does not yet support internal slots'); - // internalSlotsList.push(...additionalInternalSlotsList); - } - // var O = MakeBasicObject(internalSlotsList); - // setProto(O, proto); - // return O; + // var internalSlotsList = ['[[Prototype]]', '[[Extensible]]']; // step 1 + // internalSlotsList.push(...additionalInternalSlotsList); // step 2 + // var O = MakeBasicObject(internalSlotsList); // step 3 + // setProto(O, proto); // step 4 + // return O; // step 5 + + var O; if ($ObjectCreate) { - return $ObjectCreate(proto); - } - if (hasProto) { - return { __proto__: proto }; + O = $ObjectCreate(proto); + } else if (hasProto) { + O = { __proto__: proto }; + } else { + if (proto === null) { + throw new $SyntaxError('native Object.create support is required to create null objects'); + } + var T = function T() {}; + T.prototype = proto; + O = new T(); } - if (proto === null) { - throw new $SyntaxError('native Object.create support is required to create null objects'); + if (additionalInternalSlotsList.length > 0) { + forEach(additionalInternalSlotsList, function (slot) { + SLOT.set(O, slot, void undefined); + }); } - var T = function T() {}; - T.prototype = proto; - return new T(); + + return O; }; diff --git a/test/tests.js b/test/tests.js index 140ea9a5..9e41f478 100644 --- a/test/tests.js +++ b/test/tests.js @@ -15,6 +15,7 @@ var functionsHaveConfigurableNames = require('functions-have-names').functionsHa var boundFunctionsHaveNames = require('functions-have-names').boundFunctionsHaveNames(); var hasBigInts = require('has-bigints')(); var getOwnPropertyDescriptor = require('gopd'); +var SLOT = require('internal-slot'); var $getProto = require('../helpers/getProto'); var $setProto = require('../helpers/setProto'); @@ -3105,10 +3106,18 @@ var es2015 = function ES2015(ES, ops, expectedMissing, skips) { t.test('internal slots arg', function (st) { st.doesNotThrow(function () { ES.ObjectCreate({}, []); }, 'an empty slot list is valid'); + var O = ES.ObjectCreate({}, ['a', 'b']); + st.doesNotThrow( + function () { + SLOT.assert(O, 'a'); + SLOT.assert(O, 'b'); + }, + 'expected internal slots exist' + ); st['throws']( - function () { ES.ObjectCreate({}, ['a']); }, - SyntaxError, - 'internal slots are not supported' + function () { SLOT.assert(O, 'c'); }, + TypeError, + 'internal slots that should not exist throw' ); st.end(); @@ -3229,10 +3238,18 @@ var es2015 = function ES2015(ES, ops, expectedMissing, skips) { 'an empty slot list is valid' ); + var O = ES.OrdinaryCreateFromConstructor(function () {}, '%Array.prototype%', ['a', 'b']); + st.doesNotThrow( + function () { + SLOT.assert(O, 'a'); + SLOT.assert(O, 'b'); + }, + 'expected internal slots exist' + ); st['throws']( - function () { ES.OrdinaryCreateFromConstructor(function () {}, '%Array.prototype%', ['a']); }, - SyntaxError, - 'internal slots are not supported' + function () { SLOT.assert(O, 'c'); }, + TypeError, + 'internal slots that should not exist throw' ); st.end(); @@ -7585,10 +7602,18 @@ var es2020 = function ES2020(ES, ops, expectedMissing, skips) { t.test('internal slots arg', function (st) { st.doesNotThrow(function () { ES.OrdinaryObjectCreate({}, []); }, 'an empty slot list is valid'); + var O = ES.OrdinaryObjectCreate({}, ['a', 'b']); + st.doesNotThrow( + function () { + SLOT.assert(O, 'a'); + SLOT.assert(O, 'b'); + }, + 'expected internal slots exist' + ); st['throws']( - function () { ES.OrdinaryObjectCreate({}, ['a']); }, - SyntaxError, - 'internal slots are not supported' + function () { SLOT.assert(O, 'c'); }, + TypeError, + 'internal slots that should not exist throw' ); st.end();