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.
170 lines
5.1 KiB
170 lines
5.1 KiB
'use strict'; |
|
|
|
var GetIntrinsic = require('get-intrinsic'); |
|
|
|
var $TypeError = GetIntrinsic('%TypeError%'); |
|
|
|
var DefineOwnProperty = require('../helpers/DefineOwnProperty'); |
|
var isPropertyDescriptor = require('../helpers/isPropertyDescriptor'); |
|
var isSamePropertyDescriptor = require('../helpers/isSamePropertyDescriptor'); |
|
|
|
var FromPropertyDescriptor = require('./FromPropertyDescriptor'); |
|
var IsAccessorDescriptor = require('./IsAccessorDescriptor'); |
|
var IsDataDescriptor = require('./IsDataDescriptor'); |
|
var IsGenericDescriptor = require('./IsGenericDescriptor'); |
|
var IsPropertyKey = require('./IsPropertyKey'); |
|
var SameValue = require('./SameValue'); |
|
var Type = require('./Type'); |
|
|
|
// https://ecma-international.org/ecma-262/6.0/#sec-validateandapplypropertydescriptor |
|
// https://ecma-international.org/ecma-262/8.0/#sec-validateandapplypropertydescriptor |
|
|
|
// eslint-disable-next-line max-lines-per-function, max-statements, max-params |
|
module.exports = 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 = Type(O); |
|
if (oType !== 'Undefined' && oType !== 'Object') { |
|
throw new $TypeError('Assertion failed: O must be undefined or an Object'); |
|
} |
|
if (Type(extensible) !== 'Boolean') { |
|
throw new $TypeError('Assertion failed: extensible must be a Boolean'); |
|
} |
|
if (!isPropertyDescriptor({ |
|
Type: Type, |
|
IsDataDescriptor: IsDataDescriptor, |
|
IsAccessorDescriptor: IsAccessorDescriptor |
|
}, Desc)) { |
|
throw new $TypeError('Assertion failed: Desc must be a Property Descriptor'); |
|
} |
|
if (Type(current) !== 'Undefined' && !isPropertyDescriptor({ |
|
Type: Type, |
|
IsDataDescriptor: IsDataDescriptor, |
|
IsAccessorDescriptor: IsAccessorDescriptor |
|
}, current)) { |
|
throw new $TypeError('Assertion failed: current must be a Property Descriptor, or undefined'); |
|
} |
|
if (oType !== 'Undefined' && !IsPropertyKey(P)) { |
|
throw new $TypeError('Assertion failed: if O is not undefined, P must be a Property Key'); |
|
} |
|
if (Type(current) === 'Undefined') { |
|
if (!extensible) { |
|
return false; |
|
} |
|
if (IsGenericDescriptor(Desc) || IsDataDescriptor(Desc)) { |
|
if (oType !== 'Undefined') { |
|
DefineOwnProperty( |
|
IsDataDescriptor, |
|
SameValue, |
|
FromPropertyDescriptor, |
|
O, |
|
P, |
|
{ |
|
'[[Configurable]]': Desc['[[Configurable]]'], |
|
'[[Enumerable]]': Desc['[[Enumerable]]'], |
|
'[[Value]]': Desc['[[Value]]'], |
|
'[[Writable]]': Desc['[[Writable]]'] |
|
} |
|
); |
|
} |
|
} else { |
|
if (!IsAccessorDescriptor(Desc)) { |
|
throw new $TypeError('Assertion failed: Desc is not an accessor descriptor'); |
|
} |
|
if (oType !== 'Undefined') { |
|
return DefineOwnProperty( |
|
IsDataDescriptor, |
|
SameValue, |
|
FromPropertyDescriptor, |
|
O, |
|
P, |
|
Desc |
|
); |
|
} |
|
} |
|
return true; |
|
} |
|
if (IsGenericDescriptor(Desc) && !('[[Configurable]]' in Desc) && !('[[Enumerable]]' in Desc)) { |
|
return true; |
|
} |
|
if (isSamePropertyDescriptor({ SameValue: SameValue }, 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 (IsGenericDescriptor(Desc)) { |
|
// no further validation is required. |
|
} else if (IsDataDescriptor(current) !== IsDataDescriptor(Desc)) { |
|
if (!current['[[Configurable]]']) { |
|
return false; |
|
} |
|
if (IsDataDescriptor(current)) { |
|
if (oType !== 'Undefined') { |
|
DefineOwnProperty( |
|
IsDataDescriptor, |
|
SameValue, |
|
FromPropertyDescriptor, |
|
O, |
|
P, |
|
{ |
|
'[[Configurable]]': current['[[Configurable]]'], |
|
'[[Enumerable]]': current['[[Enumerable]]'], |
|
'[[Get]]': undefined |
|
} |
|
); |
|
} |
|
} else if (oType !== 'Undefined') { |
|
DefineOwnProperty( |
|
IsDataDescriptor, |
|
SameValue, |
|
FromPropertyDescriptor, |
|
O, |
|
P, |
|
{ |
|
'[[Configurable]]': current['[[Configurable]]'], |
|
'[[Enumerable]]': current['[[Enumerable]]'], |
|
'[[Value]]': undefined |
|
} |
|
); |
|
} |
|
} else if (IsDataDescriptor(current) && IsDataDescriptor(Desc)) { |
|
if (!current['[[Configurable]]'] && !current['[[Writable]]']) { |
|
if ('[[Writable]]' in Desc && Desc['[[Writable]]']) { |
|
return false; |
|
} |
|
if ('[[Value]]' in Desc && !SameValue(Desc['[[Value]]'], current['[[Value]]'])) { |
|
return false; |
|
} |
|
return true; |
|
} |
|
} else if (IsAccessorDescriptor(current) && IsAccessorDescriptor(Desc)) { |
|
if (!current['[[Configurable]]']) { |
|
if ('[[Set]]' in Desc && !SameValue(Desc['[[Set]]'], current['[[Set]]'])) { |
|
return false; |
|
} |
|
if ('[[Get]]' in Desc && !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( |
|
IsDataDescriptor, |
|
SameValue, |
|
FromPropertyDescriptor, |
|
O, |
|
P, |
|
Desc |
|
); |
|
} |
|
return true; |
|
};
|
|
|