171 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			171 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| var GetIntrinsic = require('../GetIntrinsic');
 | |
| 
 | |
| 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://www.ecma-international.org/ecma-262/6.0/#sec-validateandapplypropertydescriptor
 | |
| // https://www.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;
 | |
| };
 |