define-property.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /**
  2. * @license
  3. * Copyright Google Inc. All Rights Reserved.
  4. *
  5. * Use of this source code is governed by an MIT-style license that can be
  6. * found in the LICENSE file at https://angular.io/license
  7. */
  8. /*
  9. * This is necessary for Chrome and Chrome mobile, to enable
  10. * things like redefining `createdCallback` on an element.
  11. */
  12. const zoneSymbol = Zone.__symbol__;
  13. const _defineProperty = (Object as any)[zoneSymbol('defineProperty')] = Object.defineProperty;
  14. const _getOwnPropertyDescriptor = (Object as any)[zoneSymbol('getOwnPropertyDescriptor')] =
  15. Object.getOwnPropertyDescriptor;
  16. const _create = Object.create;
  17. const unconfigurablesKey = zoneSymbol('unconfigurables');
  18. export function propertyPatch() {
  19. Object.defineProperty = function(obj: any, prop: string, desc: any) {
  20. if (isUnconfigurable(obj, prop)) {
  21. throw new TypeError('Cannot assign to read only property \'' + prop + '\' of ' + obj);
  22. }
  23. const originalConfigurableFlag = desc.configurable;
  24. if (prop !== 'prototype') {
  25. desc = rewriteDescriptor(obj, prop, desc);
  26. }
  27. return _tryDefineProperty(obj, prop, desc, originalConfigurableFlag);
  28. };
  29. Object.defineProperties = function(obj, props) {
  30. Object.keys(props).forEach(function(prop) {
  31. Object.defineProperty(obj, prop, props[prop]);
  32. });
  33. return obj;
  34. };
  35. Object.create = <any>function(obj: any, proto: any) {
  36. if (typeof proto === 'object' && !Object.isFrozen(proto)) {
  37. Object.keys(proto).forEach(function(prop) {
  38. proto[prop] = rewriteDescriptor(obj, prop, proto[prop]);
  39. });
  40. }
  41. return _create(obj, proto);
  42. };
  43. Object.getOwnPropertyDescriptor = function(obj, prop) {
  44. const desc = _getOwnPropertyDescriptor(obj, prop);
  45. if (desc && isUnconfigurable(obj, prop)) {
  46. desc.configurable = false;
  47. }
  48. return desc;
  49. };
  50. }
  51. export function _redefineProperty(obj: any, prop: string, desc: any) {
  52. const originalConfigurableFlag = desc.configurable;
  53. desc = rewriteDescriptor(obj, prop, desc);
  54. return _tryDefineProperty(obj, prop, desc, originalConfigurableFlag);
  55. }
  56. function isUnconfigurable(obj: any, prop: any) {
  57. return obj && obj[unconfigurablesKey] && obj[unconfigurablesKey][prop];
  58. }
  59. function rewriteDescriptor(obj: any, prop: string, desc: any) {
  60. // issue-927, if the desc is frozen, don't try to change the desc
  61. if (!Object.isFrozen(desc)) {
  62. desc.configurable = true;
  63. }
  64. if (!desc.configurable) {
  65. // issue-927, if the obj is frozen, don't try to set the desc to obj
  66. if (!obj[unconfigurablesKey] && !Object.isFrozen(obj)) {
  67. _defineProperty(obj, unconfigurablesKey, {writable: true, value: {}});
  68. }
  69. if (obj[unconfigurablesKey]) {
  70. obj[unconfigurablesKey][prop] = true;
  71. }
  72. }
  73. return desc;
  74. }
  75. function _tryDefineProperty(obj: any, prop: string, desc: any, originalConfigurableFlag: any) {
  76. try {
  77. return _defineProperty(obj, prop, desc);
  78. } catch (error) {
  79. if (desc.configurable) {
  80. // In case of errors, when the configurable flag was likely set by rewriteDescriptor(), let's
  81. // retry with the original flag value
  82. if (typeof originalConfigurableFlag == 'undefined') {
  83. delete desc.configurable;
  84. } else {
  85. desc.configurable = originalConfigurableFlag;
  86. }
  87. try {
  88. return _defineProperty(obj, prop, desc);
  89. } catch (error) {
  90. let descJson: string|null = null;
  91. try {
  92. descJson = JSON.stringify(desc);
  93. } catch (error) {
  94. descJson = desc.toString();
  95. }
  96. console.log(`Attempting to configure '${prop}' with descriptor '${descJson}' on object '${
  97. obj}' and got error, giving up: ${error}`);
  98. }
  99. } else {
  100. throw error;
  101. }
  102. }
  103. }