| '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; | 
| }; |