From bec930dd4470f730ec8d87f2bd3131de39892858 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Mon, 4 Mar 2024 18:43:11 -0800 Subject: [PATCH] [New] `ES2015`+: add `InternalizeJSONProperty` --- .gitattributes | 5 ++ 2015/InternalizeJSONProperty.js | 68 ++++++++++++++++++++ 2016/InternalizeJSONProperty.js | 68 ++++++++++++++++++++ 2017/InternalizeJSONProperty.js | 68 ++++++++++++++++++++ 2018/InternalizeJSONProperty.js | 68 ++++++++++++++++++++ 2019/InternalizeJSONProperty.js | 68 ++++++++++++++++++++ 2020/InternalizeJSONProperty.js | 66 ++++++++++++++++++++ 2021/InternalizeJSONProperty.js | 66 ++++++++++++++++++++ 2022/InternalizeJSONProperty.js | 66 ++++++++++++++++++++ 2023/InternalizeJSONProperty.js | 68 ++++++++++++++++++++ 2024/InternalizeJSONProperty.js | 68 ++++++++++++++++++++ es2015.js | 1 + es2016.js | 1 + es2017.js | 1 + es2018.js | 1 + es2019.js | 1 + es2020.js | 1 + es2021.js | 1 + es2022.js | 1 + es2023.js | 1 + es2024.js | 1 + test/es2015.js | 1 - test/es2016.js | 1 - test/es2017.js | 1 - test/es2018.js | 1 - test/es2019.js | 1 - test/es2020.js | 1 - test/es2021.js | 1 - test/es2022.js | 1 - test/es2023.js | 1 - test/es2024.js | 1 - test/tests.js | 106 ++++++++++++++++++++++---------- 32 files changed, 763 insertions(+), 42 deletions(-) create mode 100644 2015/InternalizeJSONProperty.js create mode 100644 2016/InternalizeJSONProperty.js create mode 100644 2017/InternalizeJSONProperty.js create mode 100644 2018/InternalizeJSONProperty.js create mode 100644 2019/InternalizeJSONProperty.js create mode 100644 2020/InternalizeJSONProperty.js create mode 100644 2021/InternalizeJSONProperty.js create mode 100644 2022/InternalizeJSONProperty.js create mode 100644 2023/InternalizeJSONProperty.js create mode 100644 2024/InternalizeJSONProperty.js diff --git a/.gitattributes b/.gitattributes index 253658bd..8f8dec40 100644 --- a/.gitattributes +++ b/.gitattributes @@ -86,6 +86,7 @@ /2016/InstanceofOperator.js spackled linguist-generated=true /2016/IntegerIndexedElementGet.js spackled linguist-generated=true /2016/IntegerIndexedElementSet.js spackled linguist-generated=true +/2016/InternalizeJSONProperty.js spackled linguist-generated=true /2016/Invoke.js spackled linguist-generated=true /2016/IsAccessorDescriptor.js spackled linguist-generated=true /2016/IsArray.js spackled linguist-generated=true @@ -496,6 +497,7 @@ /2019/InstanceofOperator.js spackled linguist-generated=true /2019/IntegerIndexedElementGet.js spackled linguist-generated=true /2019/IntegerIndexedElementSet.js spackled linguist-generated=true +/2019/InternalizeJSONProperty.js spackled linguist-generated=true /2019/Invoke.js spackled linguist-generated=true /2019/IsAccessorDescriptor.js spackled linguist-generated=true /2019/IsArray.js spackled linguist-generated=true @@ -807,6 +809,7 @@ /2021/HourFromTime.js spackled linguist-generated=true /2021/InLeapYear.js spackled linguist-generated=true /2021/InstanceofOperator.js spackled linguist-generated=true +/2021/InternalizeJSONProperty.js spackled linguist-generated=true /2021/Invoke.js spackled linguist-generated=true /2021/IsAccessorDescriptor.js spackled linguist-generated=true /2021/IsArray.js spackled linguist-generated=true @@ -1009,6 +1012,7 @@ /2022/HourFromTime.js spackled linguist-generated=true /2022/InLeapYear.js spackled linguist-generated=true /2022/InstanceofOperator.js spackled linguist-generated=true +/2022/InternalizeJSONProperty.js spackled linguist-generated=true /2022/Invoke.js spackled linguist-generated=true /2022/IsAccessorDescriptor.js spackled linguist-generated=true /2022/IsArray.js spackled linguist-generated=true @@ -1454,6 +1458,7 @@ /2024/InLeapYear.js spackled linguist-generated=true /2024/InstallErrorCause.js spackled linguist-generated=true /2024/InstanceofOperator.js spackled linguist-generated=true +/2024/InternalizeJSONProperty.js spackled linguist-generated=true /2024/Invoke.js spackled linguist-generated=true /2024/IsAccessorDescriptor.js spackled linguist-generated=true /2024/IsArray.js spackled linguist-generated=true diff --git a/2015/InternalizeJSONProperty.js b/2015/InternalizeJSONProperty.js new file mode 100644 index 00000000..beaadc7d --- /dev/null +++ b/2015/InternalizeJSONProperty.js @@ -0,0 +1,68 @@ +'use strict'; + +var $TypeError = require('es-errors/type'); + +var Call = require('./Call'); +var CreateDataProperty = require('./CreateDataProperty'); +var EnumerableOwnNames = require('./EnumerableOwnNames'); +var Get = require('./Get'); +var IsArray = require('./IsArray'); +var ToLength = require('./ToLength'); +var ToString = require('./ToString'); +var Type = require('./Type'); + +var forEach = require('../helpers/forEach'); + +// https://262.ecma-international.org/6.0/#sec-internalizejsonproperty + +// note: `reviver` was implicitly closed-over until ES2020, where it becomes a third argument + +module.exports = function InternalizeJSONProperty(holder, name, reviver) { + if (Type(holder) !== 'Object') { + throw new $TypeError('Assertion failed: `holder` is not an Object'); + } + if (typeof name !== 'string') { + throw new $TypeError('Assertion failed: `name` is not a String'); + } + if (typeof reviver !== 'function') { + throw new $TypeError('Assertion failed: `reviver` is not a Function'); + } + + var val = Get(holder, name); // step 1 + + if (Type(val) === 'Object') { // step 3 + var isArray = IsArray(val); // step 3.a + if (isArray) { // step 3.c + var I = 0; // step 3.c.i + + var len = ToLength(Get(val, 'length')); // step 3.b.ii + + while (I < len) { // step 3.b.iv + var newElement = InternalizeJSONProperty(val, ToString(I), reviver); // step 3.b.iv.1 + + if (typeof newElement === 'undefined') { // step 3.b.iv.3 + delete val[ToString(I)]; // step 3.b.iv.3.a + } else { // step 3.b.iv.4 + CreateDataProperty(val, ToString(I), newElement); // step 3.b.iv.4.a + } + + I += 1; // step 3.b.iv.6 + } + } else { + var keys = EnumerableOwnNames(val); // step 3.d.i + + forEach(keys, function (P) { // step 3.d.iii + // eslint-disable-next-line no-shadow + var newElement = InternalizeJSONProperty(val, P, reviver); // step 3.d.iii.1 + + if (typeof newElement === 'undefined') { // step 3.d.iii.3 + delete val[P]; // step 3.d.iii.3.a + } else { // step 3.d.iii.4 + CreateDataProperty(val, P, newElement); // step 3.d.iii.4.a + } + }); + } + } + + return Call(reviver, holder, [name, val]); // step 4 +}; diff --git a/2016/InternalizeJSONProperty.js b/2016/InternalizeJSONProperty.js new file mode 100644 index 00000000..beaadc7d --- /dev/null +++ b/2016/InternalizeJSONProperty.js @@ -0,0 +1,68 @@ +'use strict'; + +var $TypeError = require('es-errors/type'); + +var Call = require('./Call'); +var CreateDataProperty = require('./CreateDataProperty'); +var EnumerableOwnNames = require('./EnumerableOwnNames'); +var Get = require('./Get'); +var IsArray = require('./IsArray'); +var ToLength = require('./ToLength'); +var ToString = require('./ToString'); +var Type = require('./Type'); + +var forEach = require('../helpers/forEach'); + +// https://262.ecma-international.org/6.0/#sec-internalizejsonproperty + +// note: `reviver` was implicitly closed-over until ES2020, where it becomes a third argument + +module.exports = function InternalizeJSONProperty(holder, name, reviver) { + if (Type(holder) !== 'Object') { + throw new $TypeError('Assertion failed: `holder` is not an Object'); + } + if (typeof name !== 'string') { + throw new $TypeError('Assertion failed: `name` is not a String'); + } + if (typeof reviver !== 'function') { + throw new $TypeError('Assertion failed: `reviver` is not a Function'); + } + + var val = Get(holder, name); // step 1 + + if (Type(val) === 'Object') { // step 3 + var isArray = IsArray(val); // step 3.a + if (isArray) { // step 3.c + var I = 0; // step 3.c.i + + var len = ToLength(Get(val, 'length')); // step 3.b.ii + + while (I < len) { // step 3.b.iv + var newElement = InternalizeJSONProperty(val, ToString(I), reviver); // step 3.b.iv.1 + + if (typeof newElement === 'undefined') { // step 3.b.iv.3 + delete val[ToString(I)]; // step 3.b.iv.3.a + } else { // step 3.b.iv.4 + CreateDataProperty(val, ToString(I), newElement); // step 3.b.iv.4.a + } + + I += 1; // step 3.b.iv.6 + } + } else { + var keys = EnumerableOwnNames(val); // step 3.d.i + + forEach(keys, function (P) { // step 3.d.iii + // eslint-disable-next-line no-shadow + var newElement = InternalizeJSONProperty(val, P, reviver); // step 3.d.iii.1 + + if (typeof newElement === 'undefined') { // step 3.d.iii.3 + delete val[P]; // step 3.d.iii.3.a + } else { // step 3.d.iii.4 + CreateDataProperty(val, P, newElement); // step 3.d.iii.4.a + } + }); + } + } + + return Call(reviver, holder, [name, val]); // step 4 +}; diff --git a/2017/InternalizeJSONProperty.js b/2017/InternalizeJSONProperty.js new file mode 100644 index 00000000..5c327c83 --- /dev/null +++ b/2017/InternalizeJSONProperty.js @@ -0,0 +1,68 @@ +'use strict'; + +var $TypeError = require('es-errors/type'); + +var Call = require('./Call'); +var CreateDataProperty = require('./CreateDataProperty'); +var EnumerableOwnProperties = require('./EnumerableOwnProperties'); +var Get = require('./Get'); +var IsArray = require('./IsArray'); +var ToLength = require('./ToLength'); +var ToString = require('./ToString'); +var Type = require('./Type'); + +var forEach = require('../helpers/forEach'); + +// https://262.ecma-international.org/8.0/#sec-internalizejsonproperty + +// note: `reviver` was implicitly closed-over until ES2020, where it becomes a third argument + +module.exports = function InternalizeJSONProperty(holder, name, reviver) { + if (Type(holder) !== 'Object') { + throw new $TypeError('Assertion failed: `holder` is not an Object'); + } + if (typeof name !== 'string') { + throw new $TypeError('Assertion failed: `name` is not a String'); + } + if (typeof reviver !== 'function') { + throw new $TypeError('Assertion failed: `reviver` is not a Function'); + } + + var val = Get(holder, name); // step 1 + + if (Type(val) === 'Object') { // step 2 + var isArray = IsArray(val); // step 2.a + if (isArray) { // step 2.b + var I = 0; // step 2.b.i + + var len = ToLength(Get(val, 'length')); // step 2.b.ii + + while (I < len) { // step 2.b.iii + var newElement = InternalizeJSONProperty(val, ToString(I), reviver); // step 2.b.iv.1 + + if (typeof newElement === 'undefined') { // step 2.b.iii.2 + delete val[ToString(I)]; // step 2.b.iii.2.a + } else { // step 2.b.iii.3 + CreateDataProperty(val, ToString(I), newElement); // step 2.b.iii.3.a + } + + I += 1; // step 2.b.iii.4 + } + } else { // step 2.c + var keys = EnumerableOwnProperties(val, 'key'); // step 2.c.i + + forEach(keys, function (P) { // step 2.c.ii + // eslint-disable-next-line no-shadow + var newElement = InternalizeJSONProperty(val, P, reviver); // step 2.c.ii.1 + + if (typeof newElement === 'undefined') { // step 2.c.ii.2 + delete val[P]; // step 2.c.ii.2.a + } else { // step 2.c.ii.3 + CreateDataProperty(val, P, newElement); // step 2.c.ii.3.a + } + }); + } + } + + return Call(reviver, holder, [name, val]); // step 3 +}; diff --git a/2018/InternalizeJSONProperty.js b/2018/InternalizeJSONProperty.js new file mode 100644 index 00000000..6ce12dec --- /dev/null +++ b/2018/InternalizeJSONProperty.js @@ -0,0 +1,68 @@ +'use strict'; + +var $TypeError = require('es-errors/type'); + +var Call = require('./Call'); +var CreateDataProperty = require('./CreateDataProperty'); +var EnumerableOwnPropertyNames = require('./EnumerableOwnPropertyNames'); +var Get = require('./Get'); +var IsArray = require('./IsArray'); +var ToLength = require('./ToLength'); +var ToString = require('./ToString'); +var Type = require('./Type'); + +var forEach = require('../helpers/forEach'); + +// https://262.ecma-international.org/9.0/#sec-internalizejsonproperty + +// note: `reviver` was implicitly closed-over until ES2020, where it becomes a third argument + +module.exports = function InternalizeJSONProperty(holder, name, reviver) { + if (Type(holder) !== 'Object') { + throw new $TypeError('Assertion failed: `holder` is not an Object'); + } + if (typeof name !== 'string') { + throw new $TypeError('Assertion failed: `name` is not a String'); + } + if (typeof reviver !== 'function') { + throw new $TypeError('Assertion failed: `reviver` is not a Function'); + } + + var val = Get(holder, name); // step 1 + + if (Type(val) === 'Object') { // step 2 + var isArray = IsArray(val); // step 2.a + if (isArray) { // step 2.b + var I = 0; // step 2.b.i + + var len = ToLength(Get(val, 'length')); // step 2.b.ii + + while (I < len) { // step 2.b.iii + var newElement = InternalizeJSONProperty(val, ToString(I), reviver); // step 2.b.iv.1 + + if (typeof newElement === 'undefined') { // step 2.b.iii.2 + delete val[ToString(I)]; // step 2.b.iii.2.a + } else { // step 2.b.iii.3 + CreateDataProperty(val, ToString(I), newElement); // step 2.b.iii.3.a + } + + I += 1; // step 2.b.iii.4 + } + } else { // step 2.c + var keys = EnumerableOwnPropertyNames(val, 'key'); // step 2.c.i + + forEach(keys, function (P) { // step 2.c.ii + // eslint-disable-next-line no-shadow + var newElement = InternalizeJSONProperty(val, P, reviver); // step 2.c.ii.1 + + if (typeof newElement === 'undefined') { // step 2.c.ii.2 + delete val[P]; // step 2.c.ii.2.a + } else { // step 2.c.ii.3 + CreateDataProperty(val, P, newElement); // step 2.c.ii.3.a + } + }); + } + } + + return Call(reviver, holder, [name, val]); // step 3 +}; diff --git a/2019/InternalizeJSONProperty.js b/2019/InternalizeJSONProperty.js new file mode 100644 index 00000000..6ce12dec --- /dev/null +++ b/2019/InternalizeJSONProperty.js @@ -0,0 +1,68 @@ +'use strict'; + +var $TypeError = require('es-errors/type'); + +var Call = require('./Call'); +var CreateDataProperty = require('./CreateDataProperty'); +var EnumerableOwnPropertyNames = require('./EnumerableOwnPropertyNames'); +var Get = require('./Get'); +var IsArray = require('./IsArray'); +var ToLength = require('./ToLength'); +var ToString = require('./ToString'); +var Type = require('./Type'); + +var forEach = require('../helpers/forEach'); + +// https://262.ecma-international.org/9.0/#sec-internalizejsonproperty + +// note: `reviver` was implicitly closed-over until ES2020, where it becomes a third argument + +module.exports = function InternalizeJSONProperty(holder, name, reviver) { + if (Type(holder) !== 'Object') { + throw new $TypeError('Assertion failed: `holder` is not an Object'); + } + if (typeof name !== 'string') { + throw new $TypeError('Assertion failed: `name` is not a String'); + } + if (typeof reviver !== 'function') { + throw new $TypeError('Assertion failed: `reviver` is not a Function'); + } + + var val = Get(holder, name); // step 1 + + if (Type(val) === 'Object') { // step 2 + var isArray = IsArray(val); // step 2.a + if (isArray) { // step 2.b + var I = 0; // step 2.b.i + + var len = ToLength(Get(val, 'length')); // step 2.b.ii + + while (I < len) { // step 2.b.iii + var newElement = InternalizeJSONProperty(val, ToString(I), reviver); // step 2.b.iv.1 + + if (typeof newElement === 'undefined') { // step 2.b.iii.2 + delete val[ToString(I)]; // step 2.b.iii.2.a + } else { // step 2.b.iii.3 + CreateDataProperty(val, ToString(I), newElement); // step 2.b.iii.3.a + } + + I += 1; // step 2.b.iii.4 + } + } else { // step 2.c + var keys = EnumerableOwnPropertyNames(val, 'key'); // step 2.c.i + + forEach(keys, function (P) { // step 2.c.ii + // eslint-disable-next-line no-shadow + var newElement = InternalizeJSONProperty(val, P, reviver); // step 2.c.ii.1 + + if (typeof newElement === 'undefined') { // step 2.c.ii.2 + delete val[P]; // step 2.c.ii.2.a + } else { // step 2.c.ii.3 + CreateDataProperty(val, P, newElement); // step 2.c.ii.3.a + } + }); + } + } + + return Call(reviver, holder, [name, val]); // step 3 +}; diff --git a/2020/InternalizeJSONProperty.js b/2020/InternalizeJSONProperty.js new file mode 100644 index 00000000..d710e061 --- /dev/null +++ b/2020/InternalizeJSONProperty.js @@ -0,0 +1,66 @@ +'use strict'; + +var $TypeError = require('es-errors/type'); + +var Call = require('./Call'); +var CreateDataProperty = require('./CreateDataProperty'); +var EnumerableOwnPropertyNames = require('./EnumerableOwnPropertyNames'); +var Get = require('./Get'); +var IsArray = require('./IsArray'); +var LengthOfArrayLike = require('./LengthOfArrayLike'); +var ToString = require('./ToString'); +var Type = require('./Type'); + +var forEach = require('../helpers/forEach'); + +// https://262.ecma-international.org/11.0/#sec-internalizejsonproperty + +module.exports = function InternalizeJSONProperty(holder, name, reviver) { + if (Type(holder) !== 'Object') { + throw new $TypeError('Assertion failed: `holder` is not an Object'); + } + if (typeof name !== 'string') { + throw new $TypeError('Assertion failed: `name` is not a String'); + } + if (typeof reviver !== 'function') { + throw new $TypeError('Assertion failed: `reviver` is not a Function'); + } + + var val = Get(holder, name); // step 1 + + if (Type(val) === 'Object') { // step 2 + var isArray = IsArray(val); // step 2.a + if (isArray) { // step 2.b + var I = 0; // step 2.b.i + + var len = LengthOfArrayLike(val, 'length'); // step 2.b.ii + + while (I < len) { // step 2.b.iii + var newElement = InternalizeJSONProperty(val, ToString(I), reviver); // step 2.b.iv.1 + + if (typeof newElement === 'undefined') { // step 2.b.iii.2 + delete val[ToString(I)]; // step 2.b.iii.2.a + } else { // step 2.b.iii.3 + CreateDataProperty(val, ToString(I), newElement); // step 2.b.iii.3.a + } + + I += 1; // step 2.b.iii.4 + } + } else { // step 2.c + var keys = EnumerableOwnPropertyNames(val, 'key'); // step 2.c.i + + forEach(keys, function (P) { // step 2.c.ii + // eslint-disable-next-line no-shadow + var newElement = InternalizeJSONProperty(val, P, reviver); // step 2.c.ii.1 + + if (typeof newElement === 'undefined') { // step 2.c.ii.2 + delete val[P]; // step 2.c.ii.2.a + } else { // step 2.c.ii.3 + CreateDataProperty(val, P, newElement); // step 2.c.ii.3.a + } + }); + } + } + + return Call(reviver, holder, [name, val]); // step 3 +}; diff --git a/2021/InternalizeJSONProperty.js b/2021/InternalizeJSONProperty.js new file mode 100644 index 00000000..d710e061 --- /dev/null +++ b/2021/InternalizeJSONProperty.js @@ -0,0 +1,66 @@ +'use strict'; + +var $TypeError = require('es-errors/type'); + +var Call = require('./Call'); +var CreateDataProperty = require('./CreateDataProperty'); +var EnumerableOwnPropertyNames = require('./EnumerableOwnPropertyNames'); +var Get = require('./Get'); +var IsArray = require('./IsArray'); +var LengthOfArrayLike = require('./LengthOfArrayLike'); +var ToString = require('./ToString'); +var Type = require('./Type'); + +var forEach = require('../helpers/forEach'); + +// https://262.ecma-international.org/11.0/#sec-internalizejsonproperty + +module.exports = function InternalizeJSONProperty(holder, name, reviver) { + if (Type(holder) !== 'Object') { + throw new $TypeError('Assertion failed: `holder` is not an Object'); + } + if (typeof name !== 'string') { + throw new $TypeError('Assertion failed: `name` is not a String'); + } + if (typeof reviver !== 'function') { + throw new $TypeError('Assertion failed: `reviver` is not a Function'); + } + + var val = Get(holder, name); // step 1 + + if (Type(val) === 'Object') { // step 2 + var isArray = IsArray(val); // step 2.a + if (isArray) { // step 2.b + var I = 0; // step 2.b.i + + var len = LengthOfArrayLike(val, 'length'); // step 2.b.ii + + while (I < len) { // step 2.b.iii + var newElement = InternalizeJSONProperty(val, ToString(I), reviver); // step 2.b.iv.1 + + if (typeof newElement === 'undefined') { // step 2.b.iii.2 + delete val[ToString(I)]; // step 2.b.iii.2.a + } else { // step 2.b.iii.3 + CreateDataProperty(val, ToString(I), newElement); // step 2.b.iii.3.a + } + + I += 1; // step 2.b.iii.4 + } + } else { // step 2.c + var keys = EnumerableOwnPropertyNames(val, 'key'); // step 2.c.i + + forEach(keys, function (P) { // step 2.c.ii + // eslint-disable-next-line no-shadow + var newElement = InternalizeJSONProperty(val, P, reviver); // step 2.c.ii.1 + + if (typeof newElement === 'undefined') { // step 2.c.ii.2 + delete val[P]; // step 2.c.ii.2.a + } else { // step 2.c.ii.3 + CreateDataProperty(val, P, newElement); // step 2.c.ii.3.a + } + }); + } + } + + return Call(reviver, holder, [name, val]); // step 3 +}; diff --git a/2022/InternalizeJSONProperty.js b/2022/InternalizeJSONProperty.js new file mode 100644 index 00000000..d710e061 --- /dev/null +++ b/2022/InternalizeJSONProperty.js @@ -0,0 +1,66 @@ +'use strict'; + +var $TypeError = require('es-errors/type'); + +var Call = require('./Call'); +var CreateDataProperty = require('./CreateDataProperty'); +var EnumerableOwnPropertyNames = require('./EnumerableOwnPropertyNames'); +var Get = require('./Get'); +var IsArray = require('./IsArray'); +var LengthOfArrayLike = require('./LengthOfArrayLike'); +var ToString = require('./ToString'); +var Type = require('./Type'); + +var forEach = require('../helpers/forEach'); + +// https://262.ecma-international.org/11.0/#sec-internalizejsonproperty + +module.exports = function InternalizeJSONProperty(holder, name, reviver) { + if (Type(holder) !== 'Object') { + throw new $TypeError('Assertion failed: `holder` is not an Object'); + } + if (typeof name !== 'string') { + throw new $TypeError('Assertion failed: `name` is not a String'); + } + if (typeof reviver !== 'function') { + throw new $TypeError('Assertion failed: `reviver` is not a Function'); + } + + var val = Get(holder, name); // step 1 + + if (Type(val) === 'Object') { // step 2 + var isArray = IsArray(val); // step 2.a + if (isArray) { // step 2.b + var I = 0; // step 2.b.i + + var len = LengthOfArrayLike(val, 'length'); // step 2.b.ii + + while (I < len) { // step 2.b.iii + var newElement = InternalizeJSONProperty(val, ToString(I), reviver); // step 2.b.iv.1 + + if (typeof newElement === 'undefined') { // step 2.b.iii.2 + delete val[ToString(I)]; // step 2.b.iii.2.a + } else { // step 2.b.iii.3 + CreateDataProperty(val, ToString(I), newElement); // step 2.b.iii.3.a + } + + I += 1; // step 2.b.iii.4 + } + } else { // step 2.c + var keys = EnumerableOwnPropertyNames(val, 'key'); // step 2.c.i + + forEach(keys, function (P) { // step 2.c.ii + // eslint-disable-next-line no-shadow + var newElement = InternalizeJSONProperty(val, P, reviver); // step 2.c.ii.1 + + if (typeof newElement === 'undefined') { // step 2.c.ii.2 + delete val[P]; // step 2.c.ii.2.a + } else { // step 2.c.ii.3 + CreateDataProperty(val, P, newElement); // step 2.c.ii.3.a + } + }); + } + } + + return Call(reviver, holder, [name, val]); // step 3 +}; diff --git a/2023/InternalizeJSONProperty.js b/2023/InternalizeJSONProperty.js new file mode 100644 index 00000000..cd3ee95e --- /dev/null +++ b/2023/InternalizeJSONProperty.js @@ -0,0 +1,68 @@ +'use strict'; + +var $TypeError = require('es-errors/type'); + +var Call = require('./Call'); +var CreateDataProperty = require('./CreateDataProperty'); +var EnumerableOwnProperties = require('./EnumerableOwnProperties'); +var Get = require('./Get'); +var IsArray = require('./IsArray'); +var LengthOfArrayLike = require('./LengthOfArrayLike'); +var ToString = require('./ToString'); +var Type = require('./Type'); + +var forEach = require('../helpers/forEach'); + +// https://262.ecma-international.org/14.0/#sec-internalizejsonproperty + +// note: `reviver` was implicitly closed-over until ES2020, where it becomes a third argument + +module.exports = function InternalizeJSONProperty(holder, name, reviver) { + if (Type(holder) !== 'Object') { + throw new $TypeError('Assertion failed: `holder` is not an Object'); + } + if (typeof name !== 'string') { + throw new $TypeError('Assertion failed: `name` is not a String'); + } + if (typeof reviver !== 'function') { + throw new $TypeError('Assertion failed: `reviver` is not a Function'); + } + + var val = Get(holder, name); // step 1 + + if (Type(val) === 'Object') { // step 2 + var isArray = IsArray(val); // step 2.a + if (isArray) { // step 2.b + var I = 0; // step 2.b.i + + var len = LengthOfArrayLike(val, 'length'); // step 2.b.ii + + while (I < len) { // step 2.b.iii + var newElement = InternalizeJSONProperty(val, ToString(I), reviver); // step 2.b.iv.1 + + if (typeof newElement === 'undefined') { // step 2.b.iii.2 + delete val[ToString(I)]; // step 2.b.iii.2.a + } else { // step 2.b.iii.3 + CreateDataProperty(val, ToString(I), newElement); // step 2.b.iii.3.a + } + + I += 1; // step 2.b.iii.4 + } + } else { // step 2.c + var keys = EnumerableOwnProperties(val, 'key'); // step 2.c.i + + forEach(keys, function (P) { // step 2.c.ii + // eslint-disable-next-line no-shadow + var newElement = InternalizeJSONProperty(val, P, reviver); // step 2.c.ii.1 + + if (typeof newElement === 'undefined') { // step 2.c.ii.2 + delete val[P]; // step 2.c.ii.2.a + } else { // step 2.c.ii.3 + CreateDataProperty(val, P, newElement); // step 2.c.ii.3.a + } + }); + } + } + + return Call(reviver, holder, [name, val]); // step 3 +}; diff --git a/2024/InternalizeJSONProperty.js b/2024/InternalizeJSONProperty.js new file mode 100644 index 00000000..cd3ee95e --- /dev/null +++ b/2024/InternalizeJSONProperty.js @@ -0,0 +1,68 @@ +'use strict'; + +var $TypeError = require('es-errors/type'); + +var Call = require('./Call'); +var CreateDataProperty = require('./CreateDataProperty'); +var EnumerableOwnProperties = require('./EnumerableOwnProperties'); +var Get = require('./Get'); +var IsArray = require('./IsArray'); +var LengthOfArrayLike = require('./LengthOfArrayLike'); +var ToString = require('./ToString'); +var Type = require('./Type'); + +var forEach = require('../helpers/forEach'); + +// https://262.ecma-international.org/14.0/#sec-internalizejsonproperty + +// note: `reviver` was implicitly closed-over until ES2020, where it becomes a third argument + +module.exports = function InternalizeJSONProperty(holder, name, reviver) { + if (Type(holder) !== 'Object') { + throw new $TypeError('Assertion failed: `holder` is not an Object'); + } + if (typeof name !== 'string') { + throw new $TypeError('Assertion failed: `name` is not a String'); + } + if (typeof reviver !== 'function') { + throw new $TypeError('Assertion failed: `reviver` is not a Function'); + } + + var val = Get(holder, name); // step 1 + + if (Type(val) === 'Object') { // step 2 + var isArray = IsArray(val); // step 2.a + if (isArray) { // step 2.b + var I = 0; // step 2.b.i + + var len = LengthOfArrayLike(val, 'length'); // step 2.b.ii + + while (I < len) { // step 2.b.iii + var newElement = InternalizeJSONProperty(val, ToString(I), reviver); // step 2.b.iv.1 + + if (typeof newElement === 'undefined') { // step 2.b.iii.2 + delete val[ToString(I)]; // step 2.b.iii.2.a + } else { // step 2.b.iii.3 + CreateDataProperty(val, ToString(I), newElement); // step 2.b.iii.3.a + } + + I += 1; // step 2.b.iii.4 + } + } else { // step 2.c + var keys = EnumerableOwnProperties(val, 'key'); // step 2.c.i + + forEach(keys, function (P) { // step 2.c.ii + // eslint-disable-next-line no-shadow + var newElement = InternalizeJSONProperty(val, P, reviver); // step 2.c.ii.1 + + if (typeof newElement === 'undefined') { // step 2.c.ii.2 + delete val[P]; // step 2.c.ii.2.a + } else { // step 2.c.ii.3 + CreateDataProperty(val, P, newElement); // step 2.c.ii.3.a + } + }); + } + } + + return Call(reviver, holder, [name, val]); // step 3 +}; diff --git a/es2015.js b/es2015.js index f98ffd7d..20dc258f 100644 --- a/es2015.js +++ b/es2015.js @@ -50,6 +50,7 @@ var ES2015 = { InstanceofOperator: require('./2015/InstanceofOperator'), IntegerIndexedElementGet: require('./2015/IntegerIndexedElementGet'), IntegerIndexedElementSet: require('./2015/IntegerIndexedElementSet'), + InternalizeJSONProperty: require('./2015/InternalizeJSONProperty'), Invoke: require('./2015/Invoke'), IsAccessorDescriptor: require('./2015/IsAccessorDescriptor'), IsArray: require('./2015/IsArray'), diff --git a/es2016.js b/es2016.js index 74630fba..0c530ff9 100644 --- a/es2016.js +++ b/es2016.js @@ -50,6 +50,7 @@ var ES2016 = { InstanceofOperator: require('./2016/InstanceofOperator'), IntegerIndexedElementGet: require('./2016/IntegerIndexedElementGet'), IntegerIndexedElementSet: require('./2016/IntegerIndexedElementSet'), + InternalizeJSONProperty: require('./2016/InternalizeJSONProperty'), Invoke: require('./2016/Invoke'), IsAccessorDescriptor: require('./2016/IsAccessorDescriptor'), IsArray: require('./2016/IsArray'), diff --git a/es2017.js b/es2017.js index ad2bf782..8de405b1 100644 --- a/es2017.js +++ b/es2017.js @@ -50,6 +50,7 @@ var ES2017 = { InstanceofOperator: require('./2017/InstanceofOperator'), IntegerIndexedElementGet: require('./2017/IntegerIndexedElementGet'), IntegerIndexedElementSet: require('./2017/IntegerIndexedElementSet'), + InternalizeJSONProperty: require('./2017/InternalizeJSONProperty'), Invoke: require('./2017/Invoke'), IsAccessorDescriptor: require('./2017/IsAccessorDescriptor'), IsArray: require('./2017/IsArray'), diff --git a/es2018.js b/es2018.js index 5e02a748..e723401e 100644 --- a/es2018.js +++ b/es2018.js @@ -54,6 +54,7 @@ var ES2018 = { InstanceofOperator: require('./2018/InstanceofOperator'), IntegerIndexedElementGet: require('./2018/IntegerIndexedElementGet'), IntegerIndexedElementSet: require('./2018/IntegerIndexedElementSet'), + InternalizeJSONProperty: require('./2018/InternalizeJSONProperty'), Invoke: require('./2018/Invoke'), IsAccessorDescriptor: require('./2018/IsAccessorDescriptor'), IsArray: require('./2018/IsArray'), diff --git a/es2019.js b/es2019.js index 7b84154e..25ae3c80 100644 --- a/es2019.js +++ b/es2019.js @@ -57,6 +57,7 @@ var ES2019 = { InstanceofOperator: require('./2019/InstanceofOperator'), IntegerIndexedElementGet: require('./2019/IntegerIndexedElementGet'), IntegerIndexedElementSet: require('./2019/IntegerIndexedElementSet'), + InternalizeJSONProperty: require('./2019/InternalizeJSONProperty'), Invoke: require('./2019/Invoke'), IsAccessorDescriptor: require('./2019/IsAccessorDescriptor'), IsArray: require('./2019/IsArray'), diff --git a/es2020.js b/es2020.js index 88cf05b7..dbac3ac2 100644 --- a/es2020.js +++ b/es2020.js @@ -64,6 +64,7 @@ var ES2020 = { InstanceofOperator: require('./2020/InstanceofOperator'), IntegerIndexedElementGet: require('./2020/IntegerIndexedElementGet'), IntegerIndexedElementSet: require('./2020/IntegerIndexedElementSet'), + InternalizeJSONProperty: require('./2020/InternalizeJSONProperty'), Invoke: require('./2020/Invoke'), IsAccessorDescriptor: require('./2020/IsAccessorDescriptor'), IsArray: require('./2020/IsArray'), diff --git a/es2021.js b/es2021.js index aeb9c533..a7698e0f 100644 --- a/es2021.js +++ b/es2021.js @@ -73,6 +73,7 @@ var ES2021 = { InstanceofOperator: require('./2021/InstanceofOperator'), IntegerIndexedElementGet: require('./2021/IntegerIndexedElementGet'), IntegerIndexedElementSet: require('./2021/IntegerIndexedElementSet'), + InternalizeJSONProperty: require('./2021/InternalizeJSONProperty'), Invoke: require('./2021/Invoke'), IsAccessorDescriptor: require('./2021/IsAccessorDescriptor'), IsArray: require('./2021/IsArray'), diff --git a/es2022.js b/es2022.js index 5548a936..2d0f4708 100644 --- a/es2022.js +++ b/es2022.js @@ -76,6 +76,7 @@ var ES2022 = { InstanceofOperator: require('./2022/InstanceofOperator'), IntegerIndexedElementGet: require('./2022/IntegerIndexedElementGet'), IntegerIndexedElementSet: require('./2022/IntegerIndexedElementSet'), + InternalizeJSONProperty: require('./2022/InternalizeJSONProperty'), Invoke: require('./2022/Invoke'), IsAccessorDescriptor: require('./2022/IsAccessorDescriptor'), IsArray: require('./2022/IsArray'), diff --git a/es2023.js b/es2023.js index 258896fd..c900d85f 100644 --- a/es2023.js +++ b/es2023.js @@ -82,6 +82,7 @@ var ES2023 = { InstanceofOperator: require('./2023/InstanceofOperator'), IntegerIndexedElementGet: require('./2023/IntegerIndexedElementGet'), IntegerIndexedElementSet: require('./2023/IntegerIndexedElementSet'), + InternalizeJSONProperty: require('./2023/InternalizeJSONProperty'), Invoke: require('./2023/Invoke'), IsAccessorDescriptor: require('./2023/IsAccessorDescriptor'), IsArray: require('./2023/IsArray'), diff --git a/es2024.js b/es2024.js index b9369141..e6e5b776 100644 --- a/es2024.js +++ b/es2024.js @@ -85,6 +85,7 @@ var ES2024 = { InLeapYear: require('./2024/InLeapYear'), InstallErrorCause: require('./2024/InstallErrorCause'), InstanceofOperator: require('./2024/InstanceofOperator'), + InternalizeJSONProperty: require('./2024/InternalizeJSONProperty'), Invoke: require('./2024/Invoke'), IsAccessorDescriptor: require('./2024/IsAccessorDescriptor'), IsArray: require('./2024/IsArray'), diff --git a/test/es2015.js b/test/es2015.js index 0dd4e4ff..1adba7e4 100644 --- a/test/es2015.js +++ b/test/es2015.js @@ -67,7 +67,6 @@ var expectedMissing = [ 'InitializeHostDefinedRealm', 'InitializeReferencedBinding', 'IntegerIndexedObjectCreate', - 'InternalizeJSONProperty', 'IsAnonymousFunctionDefinition', 'IsInTailPosition', 'IsLabelledFunction', diff --git a/test/es2016.js b/test/es2016.js index 15b860ec..123f7f10 100644 --- a/test/es2016.js +++ b/test/es2016.js @@ -75,7 +75,6 @@ var expectedMissing = [ 'InitializeHostDefinedRealm', 'InitializeReferencedBinding', 'IntegerIndexedObjectCreate', - 'InternalizeJSONProperty', 'IsAnonymousFunctionDefinition', 'IsInTailPosition', 'IsLabelledFunction', diff --git a/test/es2017.js b/test/es2017.js index 63d39543..1ba5c802 100644 --- a/test/es2017.js +++ b/test/es2017.js @@ -96,7 +96,6 @@ var expectedMissing = [ 'InitializeHostDefinedRealm', 'InitializeReferencedBinding', 'IntegerIndexedObjectCreate', - 'InternalizeJSONProperty', 'IsAnonymousFunctionDefinition', 'IsInTailPosition', 'IsLabelledFunction', diff --git a/test/es2018.js b/test/es2018.js index d7d88484..32f144be 100644 --- a/test/es2018.js +++ b/test/es2018.js @@ -107,7 +107,6 @@ var expectedMissing = [ 'InnerModuleEvaluation', 'InnerModuleInstantiation', 'IntegerIndexedObjectCreate', - 'InternalizeJSONProperty', 'IsAnonymousFunctionDefinition', 'IsInTailPosition', 'IsLabelledFunction', diff --git a/test/es2019.js b/test/es2019.js index aabab017..c995455f 100644 --- a/test/es2019.js +++ b/test/es2019.js @@ -109,7 +109,6 @@ var expectedMissing = [ 'InnerModuleEvaluation', 'InnerModuleInstantiation', 'IntegerIndexedObjectCreate', - 'InternalizeJSONProperty', 'IsAnonymousFunctionDefinition', 'IsInTailPosition', 'IsLabelledFunction', diff --git a/test/es2020.js b/test/es2020.js index 6da921b6..e636140d 100644 --- a/test/es2020.js +++ b/test/es2020.js @@ -106,7 +106,6 @@ var expectedMissing = [ 'InnerModuleEvaluation', 'InnerModuleLinking', 'IntegerIndexedObjectCreate', - 'InternalizeJSONProperty', 'IsAnonymousFunctionDefinition', 'IsInTailPosition', 'IsLabelledFunction', diff --git a/test/es2021.js b/test/es2021.js index e1d87f6f..c9c60e92 100644 --- a/test/es2021.js +++ b/test/es2021.js @@ -109,7 +109,6 @@ var expectedMissing = [ 'InnerModuleEvaluation', 'InnerModuleLinking', 'IntegerIndexedObjectCreate', - 'InternalizeJSONProperty', 'IsAnonymousFunctionDefinition', 'IsInTailPosition', 'IsLabelledFunction', diff --git a/test/es2022.js b/test/es2022.js index 89597e57..c41c9fcd 100644 --- a/test/es2022.js +++ b/test/es2022.js @@ -104,7 +104,6 @@ var expectedMissing = [ 'InnerModuleEvaluation', 'InnerModuleLinking', 'IntegerIndexedObjectCreate', - 'InternalizeJSONProperty', 'IsAnonymousFunctionDefinition', 'IsInTailPosition', 'IsLabelledFunction', diff --git a/test/es2023.js b/test/es2023.js index b72e93ad..09122ca9 100644 --- a/test/es2023.js +++ b/test/es2023.js @@ -109,7 +109,6 @@ var expectedMissing = [ 'InnerModuleEvaluation', 'InnerModuleLinking', 'IntegerIndexedObjectCreate', - 'InternalizeJSONProperty', 'IsAnonymousFunctionDefinition', 'IsInTailPosition', 'IsLabelledFunction', diff --git a/test/es2024.js b/test/es2024.js index 6ccd299d..f03dc863 100644 --- a/test/es2024.js +++ b/test/es2024.js @@ -107,7 +107,6 @@ var expectedMissing = [ 'InitializeTypedArrayFromTypedArray', // TypedArray initialization 'InnerModuleEvaluation', 'InnerModuleLinking', - 'InternalizeJSONProperty', 'IsAnonymousFunctionDefinition', 'IsInTailPosition', 'IsLabelledFunction', diff --git a/test/tests.js b/test/tests.js index 425a49f5..0256e0c9 100644 --- a/test/tests.js +++ b/test/tests.js @@ -59,38 +59,6 @@ var reProtoIsRegex = isRegex(RegExp.prototype); var twoSixtyFour = hasBigInts && safeBigInt(Math.pow(2, 64)); var twoSixtyThree = hasBigInts && safeBigInt(Math.pow(2, 63)); -var float32TestCases = [ - [0, 0, [0, 0, 0, 0]], - [-0, 1.793662034335766e-43, [0, 0, 0, 128]], - [1, 4.600602988224807e-41, [0, 0, 128, 63]], - [0.75, 2.3047155842750266e-41, [0, 0, 64, 63]], - [0.5, 8.828180325246348e-44, [0, 0, 0, 63]], - [-1.5, 6.914427012517945e-41, [0, 0, 192, 191]], - [-3.5, 3.470736036439707e-41, [0, 0, 96, 192]], - [16777216, 4.602284546381997e-41, [0, 0, 128, 75]], // max safe float32 - [4294967296, 4.602845065767727e-41, [0, 0, 128, 79]], // max float32 - [2147483648, 1.1070257868166055e-43, [0, 0, 0, 79]], // 2147483647 isn't representable as a float32 - [Infinity, 4.609571298396486e-41, [0, 0, 128, 127]], - [-Infinity, 4.627507918739843e-41, [0, 0, 128, 255]], - [NaN, 6.905458702346266e-41, [0, 0, 192, 127]], - [4.602845065767727e-41, 4294967296, [79, 128, 0, 0]] -]; - -var float64TestCases = [ - [0, 0, [0, 0, 0, 0, 0, 0, 0, 0]], - [-0, 6.3e-322, [0, 0, 0, 0, 0, 0, 0, 128]], - [1, 3.03865e-319, [0, 0, 0, 0, 0, 0, 240, 63]], - [0.75, 2.93747e-319, [0, 0, 0, 0, 0, 0, 232, 63]], - [0.5, 2.8363e-319, [0, 0, 0, 0, 0, 0, 224, 63]], - [-1.5, 3.14616e-319, [0, 0, 0, 0, 0, 0, 248, 191]], - [-3.5, 1.6126e-320, [0, 0, 0, 0, 0, 0, 12, 192]], - [2147483647, 1.048435680358704e-309, [0, 0, 192, 255, 255, 255, 223, 65]], - [9007199254740992, 8.128e-320, [0, 0, 0, 0, 0, 0, 64, 67]], - [Infinity, 3.0418e-319, [0, 0, 0, 0, 0, 0, 240, 127]], - [-Infinity, 3.04814e-319, [0, 0, 0, 0, 0, 0, 240, 255]], - [NaN, 3.143e-319, [0, 0, 0, 0, 0, 0, 248, 127]], - [6.97011957458363e-310, 6.589791616e-315, [0, 0, 0, 0, 79, 128, 0, 0]] -]; var elementSizes = { __proto__: null, $Int8Array: 1, @@ -3215,6 +3183,80 @@ var es2015 = function ES2015(ES, ops, expectedMissing, skips) { t.end(); }); + test('InternalizeJSONProperty', function (t) { + forEach(v.primitives, function (primitive) { + t['throws']( + function () { ES.InternalizeJSONProperty(primitive, '', function () {}); }, + TypeError, + debug(primitive) + ' is not an Object' + ); + }); + + forEach(v.nonStrings, function (nonString) { + t['throws']( + function () { ES.InternalizeJSONProperty({}, nonString, function () {}); }, + TypeError, + debug(nonString) + ' is not a String' + ); + }); + + forEach(v.nonFunctions, function (nonFunction) { + t['throws']( + function () { ES.InternalizeJSONProperty({}, 'a', nonFunction); }, + TypeError, + debug(nonFunction) + ' is not a function' + ); + }); + + t.deepEqual( + ES.InternalizeJSONProperty({ a: { b: { c: 1 } } }, 'a', function (name, val) { return val; }), + { b: { c: 1 } } + ); + + t.deepEqual( + ES.InternalizeJSONProperty({ a: [{ b: { c: 1 } }, { d: 2 }] }, 'a', function (name, val) { return val; }), + [{ b: { c: 1 } }, { d: 2 }] + ); + + // eslint-disable-next-line consistent-return + var noD = function (name, val) { if (name !== 'd') { return val; } }; + + t.deepEqual( + ES.InternalizeJSONProperty({ a: [{ b: { c: 1 } }, { d: 2, e: 3 }] }, 'a', noD), + [{ b: { c: 1 } }, { e: 3 }], + 'reviver drops a nested property in an array' + ); + + // eslint-disable-next-line consistent-return + var noZero = function (name, val) { if (name !== '0') { return val; } }; + t.deepEqual( + ES.InternalizeJSONProperty({ a: [{ b: { c: 1 } }, { d: 2, e: 3 }] }, 'a', noZero), + [, { d: 2, e: 3 }], // eslint-disable-line no-sparse-arrays + 'reviver drops a nested index in an array' + ); + + t.deepEqual( + ES.InternalizeJSONProperty({ a: { d: 2, e: 3 } }, 'a', noD), + { e: 3 }, + 'reviver drops a nested property in an object' + ); + + t.deepEqual( + ES.InternalizeJSONProperty({ d: [{ b: { c: 1 } }, { d: 2, e: 3 }] }, 'd', noD), + undefined, + 'reviver drops a top-level property' + ); + + t.deepEqual( + ES.InternalizeJSONProperty({ a: 1, b: 2 }, 'a', function (name, val) { return val; }), + 1 + ); + + // stuff with the reviver + + t.end(); + }); + test('Invoke', function (t) { forEach(v.nonPropertyKeys, function (nonKey) { t['throws'](