You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1466 lines
47 KiB
1466 lines
47 KiB
'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]]']; |
|
// eslint-disable-next-line no-param-reassign |
|
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) { |
|
/* eslint no-param-reassign: 0 */ |
|
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;
|
|
|