| 'use strict'; | |
| var has = require('has'); | |
| var toPrimitive = require('es-to-primitive/es6'); | |
| var keys = require('object-keys'); | |
| var inspect = require('object-inspect'); | |
| var GetIntrinsic = require('./GetIntrinsic'); | |
| var $TypeError = GetIntrinsic('%TypeError%'); | |
| var $RangeError = GetIntrinsic('%RangeError%'); | |
| var $SyntaxError = GetIntrinsic('%SyntaxError%'); | |
| var $Array = GetIntrinsic('%Array%'); | |
| var $ArrayPrototype = $Array.prototype; | |
| var $String = GetIntrinsic('%String%'); | |
| var $Object = GetIntrinsic('%Object%'); | |
| var $Number = GetIntrinsic('%Number%'); | |
| var $Symbol = GetIntrinsic('%Symbol%', true); | |
| var $RegExp = GetIntrinsic('%RegExp%'); | |
| var $Date = GetIntrinsic('%Date%'); | |
| var $Function = GetIntrinsic('%Function%'); | |
| var $preventExtensions = $Object.preventExtensions; | |
| var hasSymbols = require('has-symbols')(); | |
| var assertRecord = require('./helpers/assertRecord'); | |
| var $isNaN = require('./helpers/isNaN'); | |
| var $isFinite = require('./helpers/isFinite'); | |
| var MAX_ARRAY_LENGTH = Math.pow(2, 32) - 1; | |
| var MAX_SAFE_INTEGER = require('./helpers/maxSafeInteger'); | |
| var assign = require('./helpers/assign'); | |
| var sign = require('./helpers/sign'); | |
| var mod = require('./helpers/mod'); | |
| var isPrimitive = require('./helpers/isPrimitive'); | |
| var forEach = require('./helpers/forEach'); | |
| var every = require('./helpers/every'); | |
| var isSamePropertyDescriptor = require('./helpers/isSamePropertyDescriptor'); | |
| var isPropertyDescriptor = require('./helpers/isPropertyDescriptor'); | |
| var parseInteger = parseInt; | |
| var callBound = require('./helpers/callBound'); | |
| var regexTester = require('./helpers/regexTester'); | |
| var getIteratorMethod = require('./helpers/getIteratorMethod'); | |
| var getSymbolDescription = require('./helpers/getSymbolDescription'); | |
| var $PromiseThen = callBound('Promise.prototype.then', true); | |
| var arraySlice = callBound('Array.prototype.slice'); | |
| var strSlice = callBound('String.prototype.slice'); | |
| var $indexOf = callBound('Array.prototype.indexOf'); | |
| var $push = callBound('Array.prototype.push'); | |
| var isBinary = regexTester(/^0b[01]+$/i); | |
| var isOctal = regexTester(/^0o[0-7]+$/i); | |
| var isDigit = regexTester(/^[0-9]$/); | |
| var regexExec = callBound('RegExp.prototype.exec'); | |
| var nonWS = ['\u0085', '\u200b', '\ufffe'].join(''); | |
| var nonWSregex = new $RegExp('[' + nonWS + ']', 'g'); | |
| var hasNonWS = regexTester(nonWSregex); | |
| var isInvalidHexLiteral = regexTester(/^[-+]0x[0-9a-f]+$/i); | |
| var $charCodeAt = callBound('String.prototype.charCodeAt'); | |
| var $isEnumerable = callBound('Object.prototype.propertyIsEnumerable'); | |
| var toStr = callBound('Object.prototype.toString'); | |
| var $NumberValueOf = callBound('Number.prototype.valueOf'); | |
| var $BooleanValueOf = callBound('Boolean.prototype.valueOf'); | |
| var $StringValueOf = callBound('String.prototype.valueOf'); | |
| var $DateValueOf = callBound('Date.prototype.valueOf'); | |
| var $SymbolToString = callBound('Symbol.prototype.toString', true); | |
| var $floor = Math.floor; | |
| var $abs = Math.abs; | |
| var $ObjectCreate = $Object.create; | |
| var $gOPD = $Object.getOwnPropertyDescriptor; | |
| var $gOPN = $Object.getOwnPropertyNames; | |
| var $gOPS = $Object.getOwnPropertySymbols; | |
| var $isExtensible = $Object.isExtensible; | |
| var $defineProperty = $Object.defineProperty; | |
| var $setProto = require('./helpers/setProto'); | |
| var DefineOwnProperty = function DefineOwnProperty(ES, O, P, desc) { | |
| if (!$defineProperty) { | |
| if (!ES.IsDataDescriptor(desc)) { | |
| // ES3 does not support getters/setters | |
| return false; | |
| } | |
| if (!desc['[[Configurable]]'] || !desc['[[Writable]]']) { | |
| return false; | |
| } | |
| // fallback for ES3 | |
| if (P in O && $isEnumerable(O, P) !== !!desc['[[Enumerable]]']) { | |
| // a non-enumerable existing property | |
| return false; | |
| } | |
| // property does not exist at all, or exists but is enumerable | |
| var V = desc['[[Value]]']; | |
| O[P] = V; // will use [[Define]] | |
| return ES.SameValue(O[P], V); | |
| } | |
| $defineProperty(O, P, ES.FromPropertyDescriptor(desc)); | |
| return true; | |
| }; | |
| // whitespace from: https://es5.github.io/#x15.5.4.20 | |
| // implementation from https://github.com/es-shims/es5-shim/blob/v3.4.0/es5-shim.js#L1304-L1324 | |
| var ws = [ | |
| '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003', | |
| '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028', | |
| '\u2029\uFEFF' | |
| ].join(''); | |
| var trimRegex = new RegExp('(^[' + ws + ']+)|([' + ws + ']+$)', 'g'); | |
| var $replace = callBound('String.prototype.replace'); | |
| var trim = function (value) { | |
| return $replace(value, trimRegex, ''); | |
| }; | |
| var ES5 = require('./es5'); | |
| var hasRegExpMatcher = require('is-regex'); | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-abstract-operations | |
| var ES6 = assign(assign({}, ES5), { | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-call-f-v-args | |
| Call: function Call(F, V) { | |
| var args = arguments.length > 2 ? arguments[2] : []; | |
| if (!this.IsCallable(F)) { | |
| throw new $TypeError(inspect(F) + ' is not a function'); | |
| } | |
| return F.apply(V, args); | |
| }, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-toprimitive | |
| ToPrimitive: toPrimitive, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-toboolean | |
| // ToBoolean: ES5.ToBoolean, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-tonumber | |
| ToNumber: function ToNumber(argument) { | |
| var value = isPrimitive(argument) ? argument : toPrimitive(argument, $Number); | |
| if (typeof value === 'symbol') { | |
| throw new $TypeError('Cannot convert a Symbol value to a number'); | |
| } | |
| if (typeof value === 'string') { | |
| if (isBinary(value)) { | |
| return this.ToNumber(parseInteger(strSlice(value, 2), 2)); | |
| } else if (isOctal(value)) { | |
| return this.ToNumber(parseInteger(strSlice(value, 2), 8)); | |
| } else if (hasNonWS(value) || isInvalidHexLiteral(value)) { | |
| return NaN; | |
| } else { | |
| var trimmed = trim(value); | |
| if (trimmed !== value) { | |
| return this.ToNumber(trimmed); | |
| } | |
| } | |
| } | |
| return $Number(value); | |
| }, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tointeger | |
| // ToInteger: ES5.ToNumber, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-toint32 | |
| // ToInt32: ES5.ToInt32, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-touint32 | |
| // ToUint32: ES5.ToUint32, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-toint16 | |
| ToInt16: function ToInt16(argument) { | |
| var int16bit = this.ToUint16(argument); | |
| return int16bit >= 0x8000 ? int16bit - 0x10000 : int16bit; | |
| }, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-touint16 | |
| // ToUint16: ES5.ToUint16, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-toint8 | |
| ToInt8: function ToInt8(argument) { | |
| var int8bit = this.ToUint8(argument); | |
| return int8bit >= 0x80 ? int8bit - 0x100 : int8bit; | |
| }, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-touint8 | |
| ToUint8: function ToUint8(argument) { | |
| var number = this.ToNumber(argument); | |
| if ($isNaN(number) || number === 0 || !$isFinite(number)) { return 0; } | |
| var posInt = sign(number) * $floor($abs(number)); | |
| return mod(posInt, 0x100); | |
| }, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-touint8clamp | |
| ToUint8Clamp: function ToUint8Clamp(argument) { | |
| var number = this.ToNumber(argument); | |
| if ($isNaN(number) || number <= 0) { return 0; } | |
| if (number >= 0xFF) { return 0xFF; } | |
| var f = $floor(argument); | |
| if (f + 0.5 < number) { return f + 1; } | |
| if (number < f + 0.5) { return f; } | |
| if (f % 2 !== 0) { return f + 1; } | |
| return f; | |
| }, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tostring | |
| ToString: function ToString(argument) { | |
| if (typeof argument === 'symbol') { | |
| throw new $TypeError('Cannot convert a Symbol value to a string'); | |
| } | |
| return $String(argument); | |
| }, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-toobject | |
| ToObject: function ToObject(value) { | |
| this.RequireObjectCoercible(value); | |
| return $Object(value); | |
| }, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-topropertykey | |
| ToPropertyKey: function ToPropertyKey(argument) { | |
| var key = this.ToPrimitive(argument, $String); | |
| return typeof key === 'symbol' ? key : this.ToString(key); | |
| }, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength | |
| ToLength: function ToLength(argument) { | |
| var len = this.ToInteger(argument); | |
| if (len <= 0) { return 0; } // includes converting -0 to +0 | |
| if (len > MAX_SAFE_INTEGER) { return MAX_SAFE_INTEGER; } | |
| return len; | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-canonicalnumericindexstring | |
| CanonicalNumericIndexString: function CanonicalNumericIndexString(argument) { | |
| if (toStr(argument) !== '[object String]') { | |
| throw new $TypeError('must be a string'); | |
| } | |
| if (argument === '-0') { return -0; } | |
| var n = this.ToNumber(argument); | |
| if (this.SameValue(this.ToString(n), argument)) { return n; } | |
| return void 0; | |
| }, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-requireobjectcoercible | |
| RequireObjectCoercible: ES5.CheckObjectCoercible, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-isarray | |
| IsArray: $Array.isArray || function IsArray(argument) { | |
| return toStr(argument) === '[object Array]'; | |
| }, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-iscallable | |
| // IsCallable: ES5.IsCallable, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-isconstructor | |
| IsConstructor: function IsConstructor(argument) { | |
| return typeof argument === 'function' && !!argument.prototype; // unfortunately there's no way to truly check this without try/catch `new argument` or Proxy | |
| }, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-isextensible-o | |
| IsExtensible: $preventExtensions | |
| ? function IsExtensible(obj) { | |
| if (isPrimitive(obj)) { | |
| return false; | |
| } | |
| return $isExtensible(obj); | |
| } | |
| : function isExtensible(obj) { return true; }, // eslint-disable-line no-unused-vars | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-isinteger | |
| IsInteger: function IsInteger(argument) { | |
| if (typeof argument !== 'number' || $isNaN(argument) || !$isFinite(argument)) { | |
| return false; | |
| } | |
| var abs = $abs(argument); | |
| return $floor(abs) === abs; | |
| }, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-ispropertykey | |
| IsPropertyKey: function IsPropertyKey(argument) { | |
| return typeof argument === 'string' || typeof argument === 'symbol'; | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-isregexp | |
| IsRegExp: function IsRegExp(argument) { | |
| if (!argument || typeof argument !== 'object') { | |
| return false; | |
| } | |
| if (hasSymbols) { | |
| var isRegExp = argument[$Symbol.match]; | |
| if (typeof isRegExp !== 'undefined') { | |
| return ES5.ToBoolean(isRegExp); | |
| } | |
| } | |
| return hasRegExpMatcher(argument); | |
| }, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevalue | |
| // SameValue: ES5.SameValue, | |
| // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero | |
| SameValueZero: function SameValueZero(x, y) { | |
| return (x === y) || ($isNaN(x) && $isNaN(y)); | |
| }, | |
| /** | |
| * 7.3.2 GetV (V, P) | |
| * 1. Assert: IsPropertyKey(P) is true. | |
| * 2. Let O be ToObject(V). | |
| * 3. ReturnIfAbrupt(O). | |
| * 4. Return O.[[Get]](P, V). | |
| */ | |
| GetV: function GetV(V, P) { | |
| // 7.3.2.1 | |
| if (!this.IsPropertyKey(P)) { | |
| throw new $TypeError('Assertion failed: IsPropertyKey(P) is not true'); | |
| } | |
| // 7.3.2.2-3 | |
| var O = this.ToObject(V); | |
| // 7.3.2.4 | |
| return O[P]; | |
| }, | |
| /** | |
| * 7.3.9 - https://ecma-international.org/ecma-262/6.0/#sec-getmethod | |
| * 1. Assert: IsPropertyKey(P) is true. | |
| * 2. Let func be GetV(O, P). | |
| * 3. ReturnIfAbrupt(func). | |
| * 4. If func is either undefined or null, return undefined. | |
| * 5. If IsCallable(func) is false, throw a TypeError exception. | |
| * 6. Return func. | |
| */ | |
| GetMethod: function GetMethod(O, P) { | |
| // 7.3.9.1 | |
| if (!this.IsPropertyKey(P)) { | |
| throw new $TypeError('Assertion failed: IsPropertyKey(P) is not true'); | |
| } | |
| // 7.3.9.2 | |
| var func = this.GetV(O, P); | |
| // 7.3.9.4 | |
| if (func == null) { | |
| return void 0; | |
| } | |
| // 7.3.9.5 | |
| if (!this.IsCallable(func)) { | |
| throw new $TypeError(P + 'is not a function'); | |
| } | |
| // 7.3.9.6 | |
| return func; | |
| }, | |
| /** | |
| * 7.3.1 Get (O, P) - https://ecma-international.org/ecma-262/6.0/#sec-get-o-p | |
| * 1. Assert: Type(O) is Object. | |
| * 2. Assert: IsPropertyKey(P) is true. | |
| * 3. Return O.[[Get]](P, O). | |
| */ | |
| Get: function Get(O, P) { | |
| // 7.3.1.1 | |
| if (this.Type(O) !== 'Object') { | |
| throw new $TypeError('Assertion failed: Type(O) is not Object'); | |
| } | |
| // 7.3.1.2 | |
| if (!this.IsPropertyKey(P)) { | |
| throw new $TypeError('Assertion failed: IsPropertyKey(P) is not true, got ' + inspect(P)); | |
| } | |
| // 7.3.1.3 | |
| return O[P]; | |
| }, | |
| Type: function Type(x) { | |
| if (typeof x === 'symbol') { | |
| return 'Symbol'; | |
| } | |
| return ES5.Type(x); | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-speciesconstructor | |
| SpeciesConstructor: function SpeciesConstructor(O, defaultConstructor) { | |
| if (this.Type(O) !== 'Object') { | |
| throw new $TypeError('Assertion failed: Type(O) is not Object'); | |
| } | |
| var C = O.constructor; | |
| if (typeof C === 'undefined') { | |
| return defaultConstructor; | |
| } | |
| if (this.Type(C) !== 'Object') { | |
| throw new $TypeError('O.constructor is not an Object'); | |
| } | |
| var S = hasSymbols && $Symbol.species ? C[$Symbol.species] : void 0; | |
| if (S == null) { | |
| return defaultConstructor; | |
| } | |
| if (this.IsConstructor(S)) { | |
| return S; | |
| } | |
| throw new $TypeError('no constructor found'); | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-frompropertydescriptor | |
| FromPropertyDescriptor: function FromPropertyDescriptor(Desc) { | |
| if (typeof Desc === 'undefined') { | |
| return Desc; | |
| } | |
| assertRecord(this, 'Property Descriptor', 'Desc', Desc); | |
| var obj = {}; | |
| if ('[[Value]]' in Desc) { | |
| obj.value = Desc['[[Value]]']; | |
| } | |
| if ('[[Writable]]' in Desc) { | |
| obj.writable = Desc['[[Writable]]']; | |
| } | |
| if ('[[Get]]' in Desc) { | |
| obj.get = Desc['[[Get]]']; | |
| } | |
| if ('[[Set]]' in Desc) { | |
| obj.set = Desc['[[Set]]']; | |
| } | |
| if ('[[Enumerable]]' in Desc) { | |
| obj.enumerable = Desc['[[Enumerable]]']; | |
| } | |
| if ('[[Configurable]]' in Desc) { | |
| obj.configurable = Desc['[[Configurable]]']; | |
| } | |
| return obj; | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-completepropertydescriptor | |
| CompletePropertyDescriptor: function CompletePropertyDescriptor(Desc) { | |
| assertRecord(this, 'Property Descriptor', 'Desc', Desc); | |
| if (this.IsGenericDescriptor(Desc) || this.IsDataDescriptor(Desc)) { | |
| if (!has(Desc, '[[Value]]')) { | |
| Desc['[[Value]]'] = void 0; | |
| } | |
| if (!has(Desc, '[[Writable]]')) { | |
| Desc['[[Writable]]'] = false; | |
| } | |
| } else { | |
| if (!has(Desc, '[[Get]]')) { | |
| Desc['[[Get]]'] = void 0; | |
| } | |
| if (!has(Desc, '[[Set]]')) { | |
| Desc['[[Set]]'] = void 0; | |
| } | |
| } | |
| if (!has(Desc, '[[Enumerable]]')) { | |
| Desc['[[Enumerable]]'] = false; | |
| } | |
| if (!has(Desc, '[[Configurable]]')) { | |
| Desc['[[Configurable]]'] = false; | |
| } | |
| return Desc; | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-set-o-p-v-throw | |
| Set: function Set(O, P, V, Throw) { | |
| if (this.Type(O) !== 'Object') { | |
| throw new $TypeError('O must be an Object'); | |
| } | |
| if (!this.IsPropertyKey(P)) { | |
| throw new $TypeError('P must be a Property Key'); | |
| } | |
| if (this.Type(Throw) !== 'Boolean') { | |
| throw new $TypeError('Throw must be a Boolean'); | |
| } | |
| if (Throw) { | |
| O[P] = V; | |
| return true; | |
| } else { | |
| try { | |
| O[P] = V; | |
| } catch (e) { | |
| return false; | |
| } | |
| } | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-hasownproperty | |
| HasOwnProperty: function HasOwnProperty(O, P) { | |
| if (this.Type(O) !== 'Object') { | |
| throw new $TypeError('O must be an Object'); | |
| } | |
| if (!this.IsPropertyKey(P)) { | |
| throw new $TypeError('P must be a Property Key'); | |
| } | |
| return has(O, P); | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-hasproperty | |
| HasProperty: function HasProperty(O, P) { | |
| if (this.Type(O) !== 'Object') { | |
| throw new $TypeError('O must be an Object'); | |
| } | |
| if (!this.IsPropertyKey(P)) { | |
| throw new $TypeError('P must be a Property Key'); | |
| } | |
| return P in O; | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-isconcatspreadable | |
| IsConcatSpreadable: function IsConcatSpreadable(O) { | |
| if (this.Type(O) !== 'Object') { | |
| return false; | |
| } | |
| if (hasSymbols && typeof $Symbol.isConcatSpreadable === 'symbol') { | |
| var spreadable = this.Get(O, Symbol.isConcatSpreadable); | |
| if (typeof spreadable !== 'undefined') { | |
| return this.ToBoolean(spreadable); | |
| } | |
| } | |
| return this.IsArray(O); | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-invoke | |
| Invoke: function Invoke(O, P) { | |
| if (!this.IsPropertyKey(P)) { | |
| throw new $TypeError('P must be a Property Key'); | |
| } | |
| var argumentsList = arraySlice(arguments, 2); | |
| var func = this.GetV(O, P); | |
| return this.Call(func, O, argumentsList); | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-getiterator | |
| GetIterator: function GetIterator(obj, method) { | |
| var actualMethod = method; | |
| if (arguments.length < 2) { | |
| actualMethod = getIteratorMethod(this, obj); | |
| } | |
| var iterator = this.Call(actualMethod, obj); | |
| if (this.Type(iterator) !== 'Object') { | |
| throw new $TypeError('iterator must return an object'); | |
| } | |
| return iterator; | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-iteratornext | |
| IteratorNext: function IteratorNext(iterator, value) { | |
| var result = this.Invoke(iterator, 'next', arguments.length < 2 ? [] : [value]); | |
| if (this.Type(result) !== 'Object') { | |
| throw new $TypeError('iterator next must return an object'); | |
| } | |
| return result; | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-iteratorcomplete | |
| IteratorComplete: function IteratorComplete(iterResult) { | |
| if (this.Type(iterResult) !== 'Object') { | |
| throw new $TypeError('Assertion failed: Type(iterResult) is not Object'); | |
| } | |
| return this.ToBoolean(this.Get(iterResult, 'done')); | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-iteratorvalue | |
| IteratorValue: function IteratorValue(iterResult) { | |
| if (this.Type(iterResult) !== 'Object') { | |
| throw new $TypeError('Assertion failed: Type(iterResult) is not Object'); | |
| } | |
| return this.Get(iterResult, 'value'); | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-iteratorstep | |
| IteratorStep: function IteratorStep(iterator) { | |
| var result = this.IteratorNext(iterator); | |
| var done = this.IteratorComplete(result); | |
| return done === true ? false : result; | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-iteratorclose | |
| IteratorClose: function IteratorClose(iterator, completion) { | |
| if (this.Type(iterator) !== 'Object') { | |
| throw new $TypeError('Assertion failed: Type(iterator) is not Object'); | |
| } | |
| if (!this.IsCallable(completion)) { | |
| throw new $TypeError('Assertion failed: completion is not a thunk for a Completion Record'); | |
| } | |
| var completionThunk = completion; | |
| var iteratorReturn = this.GetMethod(iterator, 'return'); | |
| if (typeof iteratorReturn === 'undefined') { | |
| return completionThunk(); | |
| } | |
| var completionRecord; | |
| try { | |
| var innerResult = this.Call(iteratorReturn, iterator, []); | |
| } catch (e) { | |
| // if we hit here, then "e" is the innerResult completion that needs re-throwing | |
| // if the completion is of type "throw", this will throw. | |
| completionRecord = completionThunk(); | |
| completionThunk = null; // ensure it's not called twice. | |
| // if not, then return the innerResult completion | |
| throw e; | |
| } | |
| completionRecord = completionThunk(); // if innerResult worked, then throw if the completion does | |
| completionThunk = null; // ensure it's not called twice. | |
| if (this.Type(innerResult) !== 'Object') { | |
| throw new $TypeError('iterator .return must return an object'); | |
| } | |
| return completionRecord; | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-createiterresultobject | |
| CreateIterResultObject: function CreateIterResultObject(value, done) { | |
| if (this.Type(done) !== 'Boolean') { | |
| throw new $TypeError('Assertion failed: Type(done) is not Boolean'); | |
| } | |
| return { | |
| value: value, | |
| done: done | |
| }; | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-regexpexec | |
| RegExpExec: function RegExpExec(R, S) { | |
| if (this.Type(R) !== 'Object') { | |
| throw new $TypeError('R must be an Object'); | |
| } | |
| if (this.Type(S) !== 'String') { | |
| throw new $TypeError('S must be a String'); | |
| } | |
| var exec = this.Get(R, 'exec'); | |
| if (this.IsCallable(exec)) { | |
| var result = this.Call(exec, R, [S]); | |
| if (result === null || this.Type(result) === 'Object') { | |
| return result; | |
| } | |
| throw new $TypeError('"exec" method must return `null` or an Object'); | |
| } | |
| return regexExec(R, S); | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-arrayspeciescreate | |
| ArraySpeciesCreate: function ArraySpeciesCreate(originalArray, length) { | |
| if (!this.IsInteger(length) || length < 0) { | |
| throw new $TypeError('Assertion failed: length must be an integer >= 0'); | |
| } | |
| var len = length === 0 ? 0 : length; | |
| var C; | |
| var isArray = this.IsArray(originalArray); | |
| if (isArray) { | |
| C = this.Get(originalArray, 'constructor'); | |
| // TODO: figure out how to make a cross-realm normal Array, a same-realm Array | |
| // if (this.IsConstructor(C)) { | |
| // if C is another realm's Array, C = undefined | |
| // Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(Array))) === null ? | |
| // } | |
| if (this.Type(C) === 'Object' && hasSymbols && $Symbol.species) { | |
| C = this.Get(C, $Symbol.species); | |
| if (C === null) { | |
| C = void 0; | |
| } | |
| } | |
| } | |
| if (typeof C === 'undefined') { | |
| return $Array(len); | |
| } | |
| if (!this.IsConstructor(C)) { | |
| throw new $TypeError('C must be a constructor'); | |
| } | |
| return new C(len); // this.Construct(C, len); | |
| }, | |
| CreateDataProperty: function CreateDataProperty(O, P, V) { | |
| if (this.Type(O) !== 'Object') { | |
| throw new $TypeError('Assertion failed: Type(O) is not Object'); | |
| } | |
| if (!this.IsPropertyKey(P)) { | |
| throw new $TypeError('Assertion failed: IsPropertyKey(P) is not true'); | |
| } | |
| var oldDesc = $gOPD(O, P); | |
| var extensible = oldDesc || this.IsExtensible(O); | |
| var immutable = oldDesc && (!oldDesc.writable || !oldDesc.configurable); | |
| if (immutable || !extensible) { | |
| return false; | |
| } | |
| return DefineOwnProperty(this, O, P, { | |
| '[[Configurable]]': true, | |
| '[[Enumerable]]': true, | |
| '[[Value]]': V, | |
| '[[Writable]]': true | |
| }); | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-createdatapropertyorthrow | |
| CreateDataPropertyOrThrow: function CreateDataPropertyOrThrow(O, P, V) { | |
| if (this.Type(O) !== 'Object') { | |
| throw new $TypeError('Assertion failed: Type(O) is not Object'); | |
| } | |
| if (!this.IsPropertyKey(P)) { | |
| throw new $TypeError('Assertion failed: IsPropertyKey(P) is not true'); | |
| } | |
| var success = this.CreateDataProperty(O, P, V); | |
| if (!success) { | |
| throw new $TypeError('unable to create data property'); | |
| } | |
| return success; | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-objectcreate | |
| ObjectCreate: function ObjectCreate(proto, internalSlotsList) { | |
| if (proto !== null && this.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'); | |
| } | |
| if (proto === null && !$ObjectCreate) { | |
| throw new $SyntaxError('native Object.create support is required to create null objects'); | |
| } | |
| return $ObjectCreate(proto); | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-advancestringindex | |
| AdvanceStringIndex: function AdvanceStringIndex(S, index, unicode) { | |
| if (this.Type(S) !== 'String') { | |
| throw new $TypeError('S must be a String'); | |
| } | |
| if (!this.IsInteger(index) || index < 0 || index > MAX_SAFE_INTEGER) { | |
| throw new $TypeError('Assertion failed: length must be an integer >= 0 and <= 2**53'); | |
| } | |
| if (this.Type(unicode) !== 'Boolean') { | |
| throw new $TypeError('Assertion failed: unicode must be a Boolean'); | |
| } | |
| if (!unicode) { | |
| return index + 1; | |
| } | |
| var length = S.length; | |
| if ((index + 1) >= length) { | |
| return index + 1; | |
| } | |
| var first = $charCodeAt(S, index); | |
| if (first < 0xD800 || first > 0xDBFF) { | |
| return index + 1; | |
| } | |
| var second = $charCodeAt(S, index + 1); | |
| if (second < 0xDC00 || second > 0xDFFF) { | |
| return index + 1; | |
| } | |
| return index + 2; | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-createmethodproperty | |
| CreateMethodProperty: function CreateMethodProperty(O, P, V) { | |
| if (this.Type(O) !== 'Object') { | |
| throw new $TypeError('Assertion failed: Type(O) is not Object'); | |
| } | |
| if (!this.IsPropertyKey(P)) { | |
| throw new $TypeError('Assertion failed: IsPropertyKey(P) is not true'); | |
| } | |
| var newDesc = { | |
| '[[Configurable]]': true, | |
| '[[Enumerable]]': false, | |
| '[[Value]]': V, | |
| '[[Writable]]': true | |
| }; | |
| return DefineOwnProperty(this, O, P, newDesc); | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-definepropertyorthrow | |
| DefinePropertyOrThrow: function DefinePropertyOrThrow(O, P, desc) { | |
| if (this.Type(O) !== 'Object') { | |
| throw new $TypeError('Assertion failed: Type(O) is not Object'); | |
| } | |
| if (!this.IsPropertyKey(P)) { | |
| throw new $TypeError('Assertion failed: IsPropertyKey(P) is not true'); | |
| } | |
| var Desc = isPropertyDescriptor(this, desc) ? desc : this.ToPropertyDescriptor(desc); | |
| if (!isPropertyDescriptor(this, Desc)) { | |
| throw new $TypeError('Assertion failed: Desc is not a valid Property Descriptor'); | |
| } | |
| return DefineOwnProperty(this, O, P, Desc); | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-deletepropertyorthrow | |
| DeletePropertyOrThrow: function DeletePropertyOrThrow(O, P) { | |
| if (this.Type(O) !== 'Object') { | |
| throw new $TypeError('Assertion failed: Type(O) is not Object'); | |
| } | |
| if (!this.IsPropertyKey(P)) { | |
| throw new $TypeError('Assertion failed: IsPropertyKey(P) is not true'); | |
| } | |
| var success = delete O[P]; | |
| if (!success) { | |
| throw new TypeError('Attempt to delete property failed.'); | |
| } | |
| return success; | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-enumerableownnames | |
| EnumerableOwnNames: function EnumerableOwnNames(O) { | |
| if (this.Type(O) !== 'Object') { | |
| throw new $TypeError('Assertion failed: Type(O) is not Object'); | |
| } | |
| return keys(O); | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-properties-of-the-number-prototype-object | |
| thisNumberValue: function thisNumberValue(value) { | |
| if (this.Type(value) === 'Number') { | |
| return value; | |
| } | |
| return $NumberValueOf(value); | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-properties-of-the-boolean-prototype-object | |
| thisBooleanValue: function thisBooleanValue(value) { | |
| if (this.Type(value) === 'Boolean') { | |
| return value; | |
| } | |
| return $BooleanValueOf(value); | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-properties-of-the-string-prototype-object | |
| thisStringValue: function thisStringValue(value) { | |
| if (this.Type(value) === 'String') { | |
| return value; | |
| } | |
| return $StringValueOf(value); | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-properties-of-the-date-prototype-object | |
| thisTimeValue: function thisTimeValue(value) { | |
| return $DateValueOf(value); | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-setintegritylevel | |
| SetIntegrityLevel: function SetIntegrityLevel(O, level) { | |
| if (this.Type(O) !== 'Object') { | |
| throw new $TypeError('Assertion failed: Type(O) is not Object'); | |
| } | |
| if (level !== 'sealed' && level !== 'frozen') { | |
| throw new $TypeError('Assertion failed: `level` must be `"sealed"` or `"frozen"`'); | |
| } | |
| if (!$preventExtensions) { | |
| throw new $SyntaxError('SetIntegrityLevel requires native `Object.preventExtensions` support'); | |
| } | |
| var status = $preventExtensions(O); | |
| if (!status) { | |
| return false; | |
| } | |
| if (!$gOPN) { | |
| throw new $SyntaxError('SetIntegrityLevel requires native `Object.getOwnPropertyNames` support'); | |
| } | |
| var theKeys = $gOPN(O); | |
| var ES = this; | |
| if (level === 'sealed') { | |
| forEach(theKeys, function (k) { | |
| ES.DefinePropertyOrThrow(O, k, { configurable: false }); | |
| }); | |
| } else if (level === 'frozen') { | |
| forEach(theKeys, function (k) { | |
| var currentDesc = $gOPD(O, k); | |
| if (typeof currentDesc !== 'undefined') { | |
| var desc; | |
| if (ES.IsAccessorDescriptor(ES.ToPropertyDescriptor(currentDesc))) { | |
| desc = { configurable: false }; | |
| } else { | |
| desc = { configurable: false, writable: false }; | |
| } | |
| ES.DefinePropertyOrThrow(O, k, desc); | |
| } | |
| }); | |
| } | |
| return true; | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-testintegritylevel | |
| TestIntegrityLevel: function TestIntegrityLevel(O, level) { | |
| if (this.Type(O) !== 'Object') { | |
| throw new $TypeError('Assertion failed: Type(O) is not Object'); | |
| } | |
| if (level !== 'sealed' && level !== 'frozen') { | |
| throw new $TypeError('Assertion failed: `level` must be `"sealed"` or `"frozen"`'); | |
| } | |
| var status = this.IsExtensible(O); | |
| if (status) { | |
| return false; | |
| } | |
| var theKeys = $gOPN(O); | |
| var ES = this; | |
| return theKeys.length === 0 || every(theKeys, function (k) { | |
| var currentDesc = $gOPD(O, k); | |
| if (typeof currentDesc !== 'undefined') { | |
| if (currentDesc.configurable) { | |
| return false; | |
| } | |
| if (level === 'frozen' && ES.IsDataDescriptor(ES.ToPropertyDescriptor(currentDesc)) && currentDesc.writable) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| }); | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-ordinaryhasinstance | |
| OrdinaryHasInstance: function OrdinaryHasInstance(C, O) { | |
| if (this.IsCallable(C) === false) { | |
| return false; | |
| } | |
| if (this.Type(O) !== 'Object') { | |
| return false; | |
| } | |
| var P = this.Get(C, 'prototype'); | |
| if (this.Type(P) !== 'Object') { | |
| throw new $TypeError('OrdinaryHasInstance called on an object with an invalid prototype property.'); | |
| } | |
| return O instanceof C; | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-ordinaryhasproperty | |
| OrdinaryHasProperty: function OrdinaryHasProperty(O, P) { | |
| if (this.Type(O) !== 'Object') { | |
| throw new $TypeError('Assertion failed: Type(O) is not Object'); | |
| } | |
| if (!this.IsPropertyKey(P)) { | |
| throw new $TypeError('Assertion failed: P must be a Property Key'); | |
| } | |
| return P in O; | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-instanceofoperator | |
| InstanceofOperator: function InstanceofOperator(O, C) { | |
| if (this.Type(O) !== 'Object') { | |
| throw new $TypeError('Assertion failed: Type(O) is not Object'); | |
| } | |
| var instOfHandler = hasSymbols && $Symbol.hasInstance ? this.GetMethod(C, $Symbol.hasInstance) : void 0; | |
| if (typeof instOfHandler !== 'undefined') { | |
| return this.ToBoolean(this.Call(instOfHandler, C, [O])); | |
| } | |
| if (!this.IsCallable(C)) { | |
| throw new $TypeError('`C` is not Callable'); | |
| } | |
| return this.OrdinaryHasInstance(C, O); | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-ispromise | |
| IsPromise: function IsPromise(x) { | |
| if (this.Type(x) !== 'Object') { | |
| return false; | |
| } | |
| if (!$PromiseThen) { // Promises are not supported | |
| return false; | |
| } | |
| try { | |
| $PromiseThen(x); // throws if not a promise | |
| } catch (e) { | |
| return false; | |
| } | |
| return true; | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-abstract-equality-comparison | |
| 'Abstract Equality Comparison': function AbstractEqualityComparison(x, y) { | |
| var xType = this.Type(x); | |
| var yType = this.Type(y); | |
| if (xType === yType) { | |
| return x === y; // ES6+ specified this shortcut anyways. | |
| } | |
| if (x == null && y == null) { | |
| return true; | |
| } | |
| if (xType === 'Number' && yType === 'String') { | |
| return this['Abstract Equality Comparison'](x, this.ToNumber(y)); | |
| } | |
| if (xType === 'String' && yType === 'Number') { | |
| return this['Abstract Equality Comparison'](this.ToNumber(x), y); | |
| } | |
| if (xType === 'Boolean') { | |
| return this['Abstract Equality Comparison'](this.ToNumber(x), y); | |
| } | |
| if (yType === 'Boolean') { | |
| return this['Abstract Equality Comparison'](x, this.ToNumber(y)); | |
| } | |
| if ((xType === 'String' || xType === 'Number' || xType === 'Symbol') && yType === 'Object') { | |
| return this['Abstract Equality Comparison'](x, this.ToPrimitive(y)); | |
| } | |
| if (xType === 'Object' && (yType === 'String' || yType === 'Number' || yType === 'Symbol')) { | |
| return this['Abstract Equality Comparison'](this.ToPrimitive(x), y); | |
| } | |
| return false; | |
| }, | |
| // eslint-disable-next-line max-lines-per-function, max-statements, id-length, max-params | |
| ValidateAndApplyPropertyDescriptor: function ValidateAndApplyPropertyDescriptor(O, P, extensible, Desc, current) { | |
| // this uses the ES2017+ logic, since it fixes a number of bugs in the ES2015 logic. | |
| var oType = this.Type(O); | |
| if (oType !== 'Undefined' && oType !== 'Object') { | |
| throw new $TypeError('Assertion failed: O must be undefined or an Object'); | |
| } | |
| if (this.Type(extensible) !== 'Boolean') { | |
| throw new $TypeError('Assertion failed: extensible must be a Boolean'); | |
| } | |
| if (!isPropertyDescriptor(this, Desc)) { | |
| throw new $TypeError('Assertion failed: Desc must be a Property Descriptor'); | |
| } | |
| if (this.Type(current) !== 'Undefined' && !isPropertyDescriptor(this, current)) { | |
| throw new $TypeError('Assertion failed: current must be a Property Descriptor, or undefined'); | |
| } | |
| if (oType !== 'Undefined' && !this.IsPropertyKey(P)) { | |
| throw new $TypeError('Assertion failed: if O is not undefined, P must be a Property Key'); | |
| } | |
| if (this.Type(current) === 'Undefined') { | |
| if (!extensible) { | |
| return false; | |
| } | |
| if (this.IsGenericDescriptor(Desc) || this.IsDataDescriptor(Desc)) { | |
| if (oType !== 'Undefined') { | |
| DefineOwnProperty(this, O, P, { | |
| '[[Configurable]]': Desc['[[Configurable]]'], | |
| '[[Enumerable]]': Desc['[[Enumerable]]'], | |
| '[[Value]]': Desc['[[Value]]'], | |
| '[[Writable]]': Desc['[[Writable]]'] | |
| }); | |
| } | |
| } else { | |
| if (!this.IsAccessorDescriptor(Desc)) { | |
| throw new $TypeError('Assertion failed: Desc is not an accessor descriptor'); | |
| } | |
| if (oType !== 'Undefined') { | |
| return DefineOwnProperty(this, O, P, Desc); | |
| } | |
| } | |
| return true; | |
| } | |
| if (this.IsGenericDescriptor(Desc) && !('[[Configurable]]' in Desc) && !('[[Enumerable]]' in Desc)) { | |
| return true; | |
| } | |
| if (isSamePropertyDescriptor(this, Desc, current)) { | |
| return true; // removed by ES2017, but should still be correct | |
| } | |
| // "if every field in Desc is absent, return true" can't really match the assertion that it's a Property Descriptor | |
| if (!current['[[Configurable]]']) { | |
| if (Desc['[[Configurable]]']) { | |
| return false; | |
| } | |
| if ('[[Enumerable]]' in Desc && !Desc['[[Enumerable]]'] === !!current['[[Enumerable]]']) { | |
| return false; | |
| } | |
| } | |
| if (this.IsGenericDescriptor(Desc)) { | |
| // no further validation is required. | |
| } else if (this.IsDataDescriptor(current) !== this.IsDataDescriptor(Desc)) { | |
| if (!current['[[Configurable]]']) { | |
| return false; | |
| } | |
| if (this.IsDataDescriptor(current)) { | |
| if (oType !== 'Undefined') { | |
| DefineOwnProperty(this, O, P, { | |
| '[[Configurable]]': current['[[Configurable]]'], | |
| '[[Enumerable]]': current['[[Enumerable]]'], | |
| '[[Get]]': undefined | |
| }); | |
| } | |
| } else if (oType !== 'Undefined') { | |
| DefineOwnProperty(this, O, P, { | |
| '[[Configurable]]': current['[[Configurable]]'], | |
| '[[Enumerable]]': current['[[Enumerable]]'], | |
| '[[Value]]': undefined | |
| }); | |
| } | |
| } else if (this.IsDataDescriptor(current) && this.IsDataDescriptor(Desc)) { | |
| if (!current['[[Configurable]]'] && !current['[[Writable]]']) { | |
| if ('[[Writable]]' in Desc && Desc['[[Writable]]']) { | |
| return false; | |
| } | |
| if ('[[Value]]' in Desc && !this.SameValue(Desc['[[Value]]'], current['[[Value]]'])) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| } else if (this.IsAccessorDescriptor(current) && this.IsAccessorDescriptor(Desc)) { | |
| if (!current['[[Configurable]]']) { | |
| if ('[[Set]]' in Desc && !this.SameValue(Desc['[[Set]]'], current['[[Set]]'])) { | |
| return false; | |
| } | |
| if ('[[Get]]' in Desc && !this.SameValue(Desc['[[Get]]'], current['[[Get]]'])) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| } else { | |
| throw new $TypeError('Assertion failed: current and Desc are not both data, both accessors, or one accessor and one data.'); | |
| } | |
| if (oType !== 'Undefined') { | |
| return DefineOwnProperty(this, O, P, Desc); | |
| } | |
| return true; | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-ordinarydefineownproperty | |
| OrdinaryDefineOwnProperty: function OrdinaryDefineOwnProperty(O, P, Desc) { | |
| if (this.Type(O) !== 'Object') { | |
| throw new $TypeError('Assertion failed: O must be an Object'); | |
| } | |
| if (!this.IsPropertyKey(P)) { | |
| throw new $TypeError('Assertion failed: P must be a Property Key'); | |
| } | |
| if (!isPropertyDescriptor(this, Desc)) { | |
| throw new $TypeError('Assertion failed: Desc must be a Property Descriptor'); | |
| } | |
| var desc = $gOPD(O, P); | |
| var current = desc && this.ToPropertyDescriptor(desc); | |
| var extensible = this.IsExtensible(O); | |
| return this.ValidateAndApplyPropertyDescriptor(O, P, extensible, Desc, current); | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-ordinarygetownproperty | |
| OrdinaryGetOwnProperty: function OrdinaryGetOwnProperty(O, P) { | |
| if (this.Type(O) !== 'Object') { | |
| throw new $TypeError('Assertion failed: O must be an Object'); | |
| } | |
| if (!this.IsPropertyKey(P)) { | |
| throw new $TypeError('Assertion failed: P must be a Property Key'); | |
| } | |
| if (!has(O, P)) { | |
| return void 0; | |
| } | |
| if (!$gOPD) { | |
| // ES3 fallback | |
| var arrayLength = this.IsArray(O) && P === 'length'; | |
| var regexLastIndex = this.IsRegExp(O) && P === 'lastIndex'; | |
| return { | |
| '[[Configurable]]': !(arrayLength || regexLastIndex), | |
| '[[Enumerable]]': $isEnumerable(O, P), | |
| '[[Value]]': O[P], | |
| '[[Writable]]': true | |
| }; | |
| } | |
| return this.ToPropertyDescriptor($gOPD(O, P)); | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-arraycreate | |
| ArrayCreate: function ArrayCreate(length) { | |
| if (!this.IsInteger(length) || length < 0) { | |
| throw new $TypeError('Assertion failed: `length` must be an integer Number >= 0'); | |
| } | |
| if (length > MAX_ARRAY_LENGTH) { | |
| throw new $RangeError('length is greater than (2**32 - 1)'); | |
| } | |
| var proto = arguments.length > 1 ? arguments[1] : $ArrayPrototype; | |
| var A = []; // steps 5 - 7, and 9 | |
| if (proto !== $ArrayPrototype) { // step 8 | |
| if (!$setProto) { | |
| throw new $SyntaxError('ArrayCreate: a `proto` argument that is not `Array.prototype` is not supported in an environment that does not support setting the [[Prototype]]'); | |
| } | |
| $setProto(A, proto); | |
| } | |
| if (length !== 0) { // bypasses the need for step 2 | |
| A.length = length; | |
| } | |
| /* step 10, the above as a shortcut for the below | |
| this.OrdinaryDefineOwnProperty(A, 'length', { | |
| '[[Configurable]]': false, | |
| '[[Enumerable]]': false, | |
| '[[Value]]': length, | |
| '[[Writable]]': true | |
| }); | |
| */ | |
| return A; | |
| }, | |
| // eslint-disable-next-line max-statements, max-lines-per-function | |
| ArraySetLength: function ArraySetLength(A, Desc) { | |
| if (!this.IsArray(A)) { | |
| throw new $TypeError('Assertion failed: A must be an Array'); | |
| } | |
| if (!isPropertyDescriptor(this, Desc)) { | |
| throw new $TypeError('Assertion failed: Desc must be a Property Descriptor'); | |
| } | |
| if (!('[[Value]]' in Desc)) { | |
| return this.OrdinaryDefineOwnProperty(A, 'length', Desc); | |
| } | |
| var newLenDesc = assign({}, Desc); | |
| var newLen = this.ToUint32(Desc['[[Value]]']); | |
| var numberLen = this.ToNumber(Desc['[[Value]]']); | |
| if (newLen !== numberLen) { | |
| throw new $RangeError('Invalid array length'); | |
| } | |
| newLenDesc['[[Value]]'] = newLen; | |
| var oldLenDesc = this.OrdinaryGetOwnProperty(A, 'length'); | |
| if (!this.IsDataDescriptor(oldLenDesc)) { | |
| throw new $TypeError('Assertion failed: an array had a non-data descriptor on `length`'); | |
| } | |
| var oldLen = oldLenDesc['[[Value]]']; | |
| if (newLen >= oldLen) { | |
| return this.OrdinaryDefineOwnProperty(A, 'length', newLenDesc); | |
| } | |
| if (!oldLenDesc['[[Writable]]']) { | |
| return false; | |
| } | |
| var newWritable; | |
| if (!('[[Writable]]' in newLenDesc) || newLenDesc['[[Writable]]']) { | |
| newWritable = true; | |
| } else { | |
| newWritable = false; | |
| newLenDesc['[[Writable]]'] = true; | |
| } | |
| var succeeded = this.OrdinaryDefineOwnProperty(A, 'length', newLenDesc); | |
| if (!succeeded) { | |
| return false; | |
| } | |
| while (newLen < oldLen) { | |
| oldLen -= 1; | |
| var deleteSucceeded = delete A[this.ToString(oldLen)]; | |
| if (!deleteSucceeded) { | |
| newLenDesc['[[Value]]'] = oldLen + 1; | |
| if (!newWritable) { | |
| newLenDesc['[[Writable]]'] = false; | |
| this.OrdinaryDefineOwnProperty(A, 'length', newLenDesc); | |
| return false; | |
| } | |
| } | |
| } | |
| if (!newWritable) { | |
| return this.OrdinaryDefineOwnProperty(A, 'length', { '[[Writable]]': false }); | |
| } | |
| return true; | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-createhtml | |
| CreateHTML: function CreateHTML(string, tag, attribute, value) { | |
| if (this.Type(tag) !== 'String' || this.Type(attribute) !== 'String') { | |
| throw new $TypeError('Assertion failed: `tag` and `attribute` must be strings'); | |
| } | |
| var str = this.RequireObjectCoercible(string); | |
| var S = this.ToString(str); | |
| var p1 = '<' + tag; | |
| if (attribute !== '') { | |
| var V = this.ToString(value); | |
| var escapedV = $replace(V, /\x22/g, '"'); | |
| p1 += '\x20' + attribute + '\x3D\x22' + escapedV + '\x22'; | |
| } | |
| return p1 + '>' + S + '</' + tag + '>'; | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-getownpropertykeys | |
| GetOwnPropertyKeys: function GetOwnPropertyKeys(O, Type) { | |
| if (this.Type(O) !== 'Object') { | |
| throw new $TypeError('Assertion failed: Type(O) is not Object'); | |
| } | |
| if (Type === 'Symbol') { | |
| return hasSymbols && $gOPS ? $gOPS(O) : []; | |
| } | |
| if (Type === 'String') { | |
| if (!$gOPN) { | |
| return keys(O); | |
| } | |
| return $gOPN(O); | |
| } | |
| throw new $TypeError('Assertion failed: `Type` must be `"String"` or `"Symbol"`'); | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-symboldescriptivestring | |
| SymbolDescriptiveString: function SymbolDescriptiveString(sym) { | |
| if (this.Type(sym) !== 'Symbol') { | |
| throw new $TypeError('Assertion failed: `sym` must be a Symbol'); | |
| } | |
| return $SymbolToString(sym); | |
| }, | |
| // https://www.ecma-international.org/ecma-262/6.0/#sec-getsubstitution | |
| // eslint-disable-next-line max-statements, max-params, max-lines-per-function | |
| GetSubstitution: function GetSubstitution(matched, str, position, captures, replacement) { | |
| if (this.Type(matched) !== 'String') { | |
| throw new $TypeError('Assertion failed: `matched` must be a String'); | |
| } | |
| var matchLength = matched.length; | |
| if (this.Type(str) !== 'String') { | |
| throw new $TypeError('Assertion failed: `str` must be a String'); | |
| } | |
| var stringLength = str.length; | |
| if (!this.IsInteger(position) || position < 0 || position > stringLength) { | |
| throw new $TypeError('Assertion failed: `position` must be a nonnegative integer, and less than or equal to the length of `string`, got ' + inspect(position)); | |
| } | |
| var ES = this; | |
| var isStringOrHole = function (capture, index, arr) { return ES.Type(capture) === 'String' || !(index in arr); }; | |
| if (!this.IsArray(captures) || !every(captures, isStringOrHole)) { | |
| throw new $TypeError('Assertion failed: `captures` must be a List of Strings, got ' + inspect(captures)); | |
| } | |
| if (this.Type(replacement) !== 'String') { | |
| throw new $TypeError('Assertion failed: `replacement` must be a String'); | |
| } | |
| var tailPos = position + matchLength; | |
| var m = captures.length; | |
| var result = ''; | |
| for (var i = 0; i < replacement.length; i += 1) { | |
| // if this is a $, and it's not the end of the replacement | |
| var current = replacement[i]; | |
| var isLast = (i + 1) >= replacement.length; | |
| var nextIsLast = (i + 2) >= replacement.length; | |
| if (current === '$' && !isLast) { | |
| var next = replacement[i + 1]; | |
| if (next === '$') { | |
| result += '$'; | |
| i += 1; | |
| } else if (next === '&') { | |
| result += matched; | |
| i += 1; | |
| } else if (next === '`') { | |
| result += position === 0 ? '' : strSlice(str, 0, position - 1); | |
| i += 1; | |
| } else if (next === "'") { | |
| result += tailPos >= stringLength ? '' : strSlice(str, tailPos); | |
| i += 1; | |
| } else { | |
| var nextNext = nextIsLast ? null : replacement[i + 2]; | |
| if (isDigit(next) && next !== '0' && (nextIsLast || !isDigit(nextNext))) { | |
| // $1 through $9, and not followed by a digit | |
| var n = parseInteger(next, 10); | |
| // if (n > m, impl-defined) | |
| result += (n <= m && this.Type(captures[n - 1]) === 'Undefined') ? '' : captures[n - 1]; | |
| i += 1; | |
| } else if (isDigit(next) && (nextIsLast || isDigit(nextNext))) { | |
| // $00 through $99 | |
| var nn = next + nextNext; | |
| var nnI = parseInteger(nn, 10) - 1; | |
| // if nn === '00' or nn > m, impl-defined | |
| result += (nn <= m && this.Type(captures[nnI]) === 'Undefined') ? '' : captures[nnI]; | |
| i += 2; | |
| } else { | |
| result += '$'; | |
| } | |
| } | |
| } else { | |
| // the final $, or else not a $ | |
| result += replacement[i]; | |
| } | |
| } | |
| return result; | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-todatestring | |
| ToDateString: function ToDateString(tv) { | |
| if (this.Type(tv) !== 'Number') { | |
| throw new $TypeError('Assertion failed: `tv` must be a Number'); | |
| } | |
| if ($isNaN(tv)) { | |
| return 'Invalid Date'; | |
| } | |
| return $Date(tv); | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-createlistfromarraylike | |
| CreateListFromArrayLike: function CreateListFromArrayLike(obj) { | |
| var elementTypes = arguments.length > 1 | |
| ? arguments[1] | |
| : ['Undefined', 'Null', 'Boolean', 'String', 'Symbol', 'Number', 'Object']; | |
| if (this.Type(obj) !== 'Object') { | |
| throw new $TypeError('Assertion failed: `obj` must be an Object'); | |
| } | |
| if (!this.IsArray(elementTypes)) { | |
| throw new $TypeError('Assertion failed: `elementTypes`, if provided, must be an array'); | |
| } | |
| var len = this.ToLength(this.Get(obj, 'length')); | |
| var list = []; | |
| var index = 0; | |
| while (index < len) { | |
| var indexName = this.ToString(index); | |
| var next = this.Get(obj, indexName); | |
| var nextType = this.Type(next); | |
| if ($indexOf(elementTypes, nextType) < 0) { | |
| throw new $TypeError('item type ' + nextType + ' is not a valid elementType'); | |
| } | |
| $push(list, next); | |
| index += 1; | |
| } | |
| return list; | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-getprototypefromconstructor | |
| GetPrototypeFromConstructor: function GetPrototypeFromConstructor(constructor, intrinsicDefaultProto) { | |
| var intrinsic = GetIntrinsic(intrinsicDefaultProto); // throws if not a valid intrinsic | |
| if (!this.IsConstructor(constructor)) { | |
| throw new $TypeError('Assertion failed: `constructor` must be a constructor'); | |
| } | |
| var proto = this.Get(constructor, 'prototype'); | |
| if (this.Type(proto) !== 'Object') { | |
| if (!(constructor instanceof $Function)) { | |
| // ignore other realms, for now | |
| throw new $TypeError('cross-realm constructors not currently supported'); | |
| } | |
| proto = intrinsic; | |
| } | |
| return proto; | |
| }, | |
| // https://ecma-international.org/ecma-262/6.0/#sec-setfunctionname | |
| SetFunctionName: function SetFunctionName(F, name) { | |
| if (typeof F !== 'function') { | |
| throw new $TypeError('Assertion failed: `F` must be a function'); | |
| } | |
| if (!this.IsExtensible(F) || has(F, 'name')) { | |
| throw new $TypeError('Assertion failed: `F` must be extensible, and must not have a `name` own property'); | |
| } | |
| var nameType = this.Type(name); | |
| if (nameType !== 'Symbol' && nameType !== 'String') { | |
| throw new $TypeError('Assertion failed: `name` must be a Symbol or a String'); | |
| } | |
| if (nameType === 'Symbol') { | |
| var description = getSymbolDescription(name); | |
| // eslint-disable-next-line no-param-reassign | |
| name = typeof description === 'undefined' ? '' : '[' + description + ']'; | |
| } | |
| if (arguments.length > 2) { | |
| var prefix = arguments[2]; | |
| // eslint-disable-next-line no-param-reassign | |
| name = prefix + ' ' + name; | |
| } | |
| return this.DefinePropertyOrThrow(F, 'name', { | |
| '[[Value]]': name, | |
| '[[Writable]]': false, | |
| '[[Enumerable]]': false, | |
| '[[Configurable]]': true | |
| }); | |
| } | |
| }); | |
| delete ES6.CheckObjectCoercible; // renamed in ES6 to RequireObjectCoercible | |
| module.exports = ES6; |