ValidateAndApplyPropertyDescriptor.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. 'use strict';
  2. var GetIntrinsic = require('get-intrinsic');
  3. var $TypeError = GetIntrinsic('%TypeError%');
  4. var DefineOwnProperty = require('../helpers/DefineOwnProperty');
  5. var isPropertyDescriptor = require('../helpers/isPropertyDescriptor');
  6. var isSamePropertyDescriptor = require('../helpers/isSamePropertyDescriptor');
  7. var FromPropertyDescriptor = require('./FromPropertyDescriptor');
  8. var IsAccessorDescriptor = require('./IsAccessorDescriptor');
  9. var IsDataDescriptor = require('./IsDataDescriptor');
  10. var IsGenericDescriptor = require('./IsGenericDescriptor');
  11. var IsPropertyKey = require('./IsPropertyKey');
  12. var SameValue = require('./SameValue');
  13. var Type = require('./Type');
  14. // https://ecma-international.org/ecma-262/6.0/#sec-validateandapplypropertydescriptor
  15. // https://ecma-international.org/ecma-262/8.0/#sec-validateandapplypropertydescriptor
  16. // eslint-disable-next-line max-lines-per-function, max-statements, max-params
  17. module.exports = function ValidateAndApplyPropertyDescriptor(O, P, extensible, Desc, current) {
  18. // this uses the ES2017+ logic, since it fixes a number of bugs in the ES2015 logic.
  19. var oType = Type(O);
  20. if (oType !== 'Undefined' && oType !== 'Object') {
  21. throw new $TypeError('Assertion failed: O must be undefined or an Object');
  22. }
  23. if (Type(extensible) !== 'Boolean') {
  24. throw new $TypeError('Assertion failed: extensible must be a Boolean');
  25. }
  26. if (!isPropertyDescriptor({
  27. Type: Type,
  28. IsDataDescriptor: IsDataDescriptor,
  29. IsAccessorDescriptor: IsAccessorDescriptor
  30. }, Desc)) {
  31. throw new $TypeError('Assertion failed: Desc must be a Property Descriptor');
  32. }
  33. if (Type(current) !== 'Undefined' && !isPropertyDescriptor({
  34. Type: Type,
  35. IsDataDescriptor: IsDataDescriptor,
  36. IsAccessorDescriptor: IsAccessorDescriptor
  37. }, current)) {
  38. throw new $TypeError('Assertion failed: current must be a Property Descriptor, or undefined');
  39. }
  40. if (oType !== 'Undefined' && !IsPropertyKey(P)) {
  41. throw new $TypeError('Assertion failed: if O is not undefined, P must be a Property Key');
  42. }
  43. if (Type(current) === 'Undefined') {
  44. if (!extensible) {
  45. return false;
  46. }
  47. if (IsGenericDescriptor(Desc) || IsDataDescriptor(Desc)) {
  48. if (oType !== 'Undefined') {
  49. DefineOwnProperty(
  50. IsDataDescriptor,
  51. SameValue,
  52. FromPropertyDescriptor,
  53. O,
  54. P,
  55. {
  56. '[[Configurable]]': Desc['[[Configurable]]'],
  57. '[[Enumerable]]': Desc['[[Enumerable]]'],
  58. '[[Value]]': Desc['[[Value]]'],
  59. '[[Writable]]': Desc['[[Writable]]']
  60. }
  61. );
  62. }
  63. } else {
  64. if (!IsAccessorDescriptor(Desc)) {
  65. throw new $TypeError('Assertion failed: Desc is not an accessor descriptor');
  66. }
  67. if (oType !== 'Undefined') {
  68. return DefineOwnProperty(
  69. IsDataDescriptor,
  70. SameValue,
  71. FromPropertyDescriptor,
  72. O,
  73. P,
  74. Desc
  75. );
  76. }
  77. }
  78. return true;
  79. }
  80. if (IsGenericDescriptor(Desc) && !('[[Configurable]]' in Desc) && !('[[Enumerable]]' in Desc)) {
  81. return true;
  82. }
  83. if (isSamePropertyDescriptor({ SameValue: SameValue }, Desc, current)) {
  84. return true; // removed by ES2017, but should still be correct
  85. }
  86. // "if every field in Desc is absent, return true" can't really match the assertion that it's a Property Descriptor
  87. if (!current['[[Configurable]]']) {
  88. if (Desc['[[Configurable]]']) {
  89. return false;
  90. }
  91. if ('[[Enumerable]]' in Desc && !Desc['[[Enumerable]]'] === !!current['[[Enumerable]]']) {
  92. return false;
  93. }
  94. }
  95. if (IsGenericDescriptor(Desc)) {
  96. // no further validation is required.
  97. } else if (IsDataDescriptor(current) !== IsDataDescriptor(Desc)) {
  98. if (!current['[[Configurable]]']) {
  99. return false;
  100. }
  101. if (IsDataDescriptor(current)) {
  102. if (oType !== 'Undefined') {
  103. DefineOwnProperty(
  104. IsDataDescriptor,
  105. SameValue,
  106. FromPropertyDescriptor,
  107. O,
  108. P,
  109. {
  110. '[[Configurable]]': current['[[Configurable]]'],
  111. '[[Enumerable]]': current['[[Enumerable]]'],
  112. '[[Get]]': undefined
  113. }
  114. );
  115. }
  116. } else if (oType !== 'Undefined') {
  117. DefineOwnProperty(
  118. IsDataDescriptor,
  119. SameValue,
  120. FromPropertyDescriptor,
  121. O,
  122. P,
  123. {
  124. '[[Configurable]]': current['[[Configurable]]'],
  125. '[[Enumerable]]': current['[[Enumerable]]'],
  126. '[[Value]]': undefined
  127. }
  128. );
  129. }
  130. } else if (IsDataDescriptor(current) && IsDataDescriptor(Desc)) {
  131. if (!current['[[Configurable]]'] && !current['[[Writable]]']) {
  132. if ('[[Writable]]' in Desc && Desc['[[Writable]]']) {
  133. return false;
  134. }
  135. if ('[[Value]]' in Desc && !SameValue(Desc['[[Value]]'], current['[[Value]]'])) {
  136. return false;
  137. }
  138. return true;
  139. }
  140. } else if (IsAccessorDescriptor(current) && IsAccessorDescriptor(Desc)) {
  141. if (!current['[[Configurable]]']) {
  142. if ('[[Set]]' in Desc && !SameValue(Desc['[[Set]]'], current['[[Set]]'])) {
  143. return false;
  144. }
  145. if ('[[Get]]' in Desc && !SameValue(Desc['[[Get]]'], current['[[Get]]'])) {
  146. return false;
  147. }
  148. return true;
  149. }
  150. } else {
  151. throw new $TypeError('Assertion failed: current and Desc are not both data, both accessors, or one accessor and one data.');
  152. }
  153. if (oType !== 'Undefined') {
  154. return DefineOwnProperty(
  155. IsDataDescriptor,
  156. SameValue,
  157. FromPropertyDescriptor,
  158. O,
  159. P,
  160. Desc
  161. );
  162. }
  163. return true;
  164. };