| 'use strict'; | 
|   | 
| var GetIntrinsic = require('get-intrinsic'); | 
|   | 
| var $TypeError = GetIntrinsic('%TypeError%'); | 
|   | 
| var DefineOwnProperty = require('../helpers/DefineOwnProperty'); | 
| var isFullyPopulatedPropertyDescriptor = require('../helpers/isFullyPopulatedPropertyDescriptor'); | 
| var isPropertyDescriptor = require('../helpers/isPropertyDescriptor'); | 
|   | 
| 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://262.ecma-international.org/13.0/#sec-validateandapplypropertydescriptor | 
|   | 
| // see https://github.com/tc39/ecma262/pull/2468 for ES2022 changes | 
|   | 
| // eslint-disable-next-line max-lines-per-function, max-statements, max-params | 
| module.exports = function ValidateAndApplyPropertyDescriptor(O, P, extensible, Desc, current) { | 
|     var oType = Type(O); | 
|     if (oType !== 'Undefined' && oType !== 'Object') { | 
|         throw new $TypeError('Assertion failed: O must be undefined or an Object'); | 
|     } | 
|     if (!IsPropertyKey(P)) { | 
|         throw new $TypeError('Assertion failed: P must be a Property Key'); | 
|     } | 
|     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 (Type(current) === 'Undefined') { // step 2 | 
|         if (!extensible) { | 
|             return false; // step 2.a | 
|         } | 
|         if (oType === 'Undefined') { | 
|             return true; // step 2.b | 
|         } | 
|         if (IsAccessorDescriptor(Desc)) { // step 2.c | 
|             return DefineOwnProperty( | 
|                 IsDataDescriptor, | 
|                 SameValue, | 
|                 FromPropertyDescriptor, | 
|                 O, | 
|                 P, | 
|                 Desc | 
|             ); | 
|         } | 
|         // step 2.d | 
|         return DefineOwnProperty( | 
|             IsDataDescriptor, | 
|             SameValue, | 
|             FromPropertyDescriptor, | 
|             O, | 
|             P, | 
|             { | 
|                 '[[Configurable]]': !!Desc['[[Configurable]]'], | 
|                 '[[Enumerable]]': !!Desc['[[Enumerable]]'], | 
|                 '[[Value]]': Desc['[[Value]]'], | 
|                 '[[Writable]]': !!Desc['[[Writable]]'] | 
|             } | 
|         ); | 
|     } | 
|   | 
|     // 3. Assert: current is a fully populated Property Descriptor. | 
|     if (!isFullyPopulatedPropertyDescriptor({ | 
|         IsAccessorDescriptor: IsAccessorDescriptor, | 
|         IsDataDescriptor: IsDataDescriptor | 
|     }, current)) { | 
|         throw new $TypeError('`current`, when present, must be a fully populated and valid Property Descriptor'); | 
|     } | 
|   | 
|     // 4. If every field in Desc is absent, return true. | 
|     // this can't really match the assertion that it's a Property Descriptor in our JS implementation | 
|   | 
|     // 5. If current.[[Configurable]] is false, then | 
|     if (!current['[[Configurable]]']) { | 
|         if ('[[Configurable]]' in Desc && Desc['[[Configurable]]']) { | 
|             // step 5.a | 
|             return false; | 
|         } | 
|         if ('[[Enumerable]]' in Desc && !SameValue(Desc['[[Enumerable]]'], current['[[Enumerable]]'])) { | 
|             // step 5.b | 
|             return false; | 
|         } | 
|         if (!IsGenericDescriptor(Desc) && !SameValue(IsAccessorDescriptor(Desc), IsAccessorDescriptor(current))) { | 
|             // step 5.c | 
|             return false; | 
|         } | 
|         if (IsAccessorDescriptor(current)) { // step 5.d | 
|             if ('[[Get]]' in Desc && !SameValue(Desc['[[Get]]'], current['[[Get]]'])) { | 
|                 return false; | 
|             } | 
|             if ('[[Set]]' in Desc && !SameValue(Desc['[[Set]]'], current['[[Set]]'])) { | 
|                 return false; | 
|             } | 
|         } else if (!current['[[Writable]]']) { // step 5.e | 
|             if ('[[Writable]]' in Desc && Desc['[[Writable]]']) { | 
|                 return false; | 
|             } | 
|             if ('[[Value]]' in Desc && !SameValue(Desc['[[Value]]'], current['[[Value]]'])) { | 
|                 return false; | 
|             } | 
|         } | 
|     } | 
|   | 
|     // 6. If O is not undefined, then | 
|     if (oType !== 'Undefined') { | 
|         var configurable; | 
|         var enumerable; | 
|         if (IsDataDescriptor(current) && IsAccessorDescriptor(Desc)) { // step 6.a | 
|             configurable = ('[[Configurable]]' in Desc ? Desc : current)['[[Configurable]]']; | 
|             enumerable = ('[[Enumerable]]' in Desc ? Desc : current)['[[Enumerable]]']; | 
|             // Replace the property named P of object O with an accessor property having [[Configurable]] and [[Enumerable]] attributes as described by current and each other attribute set to its default value. | 
|             return DefineOwnProperty( | 
|                 IsDataDescriptor, | 
|                 SameValue, | 
|                 FromPropertyDescriptor, | 
|                 O, | 
|                 P, | 
|                 { | 
|                     '[[Configurable]]': !!configurable, | 
|                     '[[Enumerable]]': !!enumerable, | 
|                     '[[Get]]': ('[[Get]]' in Desc ? Desc : current)['[[Get]]'], | 
|                     '[[Set]]': ('[[Set]]' in Desc ? Desc : current)['[[Set]]'] | 
|                 } | 
|             ); | 
|         } else if (IsAccessorDescriptor(current) && IsDataDescriptor(Desc)) { | 
|             configurable = ('[[Configurable]]' in Desc ? Desc : current)['[[Configurable]]']; | 
|             enumerable = ('[[Enumerable]]' in Desc ? Desc : current)['[[Enumerable]]']; | 
|             // i. Replace the property named P of object O with a data property having [[Configurable]] and [[Enumerable]] attributes as described by current and each other attribute set to its default value. | 
|             return DefineOwnProperty( | 
|                 IsDataDescriptor, | 
|                 SameValue, | 
|                 FromPropertyDescriptor, | 
|                 O, | 
|                 P, | 
|                 { | 
|                     '[[Configurable]]': !!configurable, | 
|                     '[[Enumerable]]': !!enumerable, | 
|                     '[[Value]]': ('[[Value]]' in Desc ? Desc : current)['[[Value]]'], | 
|                     '[[Writable]]': !!('[[Writable]]' in Desc ? Desc : current)['[[Writable]]'] | 
|                 } | 
|             ); | 
|         } | 
|   | 
|         // For each field of Desc that is present, set the corresponding attribute of the property named P of object O to the value of the field. | 
|         return DefineOwnProperty( | 
|             IsDataDescriptor, | 
|             SameValue, | 
|             FromPropertyDescriptor, | 
|             O, | 
|             P, | 
|             Desc | 
|         ); | 
|     } | 
|   | 
|     return true; // step 7 | 
| }; |