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