/** * @license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /* * This is necessary for Chrome and Chrome mobile, to enable * things like redefining `createdCallback` on an element. */ let zoneSymbol: any; let _defineProperty: any; let _getOwnPropertyDescriptor: any; let _create: any; let unconfigurablesKey: any; export function propertyPatch() { zoneSymbol = Zone.__symbol__; _defineProperty = (Object as any)[zoneSymbol('defineProperty')] = Object.defineProperty; _getOwnPropertyDescriptor = (Object as any)[zoneSymbol('getOwnPropertyDescriptor')] = Object.getOwnPropertyDescriptor; _create = Object.create; unconfigurablesKey = zoneSymbol('unconfigurables'); Object.defineProperty = function(obj: any, prop: string, desc: any) { if (isUnconfigurable(obj, prop)) { throw new TypeError('Cannot assign to read only property \'' + prop + '\' of ' + obj); } const originalConfigurableFlag = desc.configurable; if (prop !== 'prototype') { desc = rewriteDescriptor(obj, prop, desc); } return _tryDefineProperty(obj, prop, desc, originalConfigurableFlag); }; Object.defineProperties = function(obj, props) { Object.keys(props).forEach(function(prop) { Object.defineProperty(obj, prop, props[prop]); }); return obj; }; Object.create = function(obj: any, proto: any) { if (typeof proto === 'object' && !Object.isFrozen(proto)) { Object.keys(proto).forEach(function(prop) { proto[prop] = rewriteDescriptor(obj, prop, proto[prop]); }); } return _create(obj, proto); }; Object.getOwnPropertyDescriptor = function(obj, prop) { const desc = _getOwnPropertyDescriptor(obj, prop); if (desc && isUnconfigurable(obj, prop)) { desc.configurable = false; } return desc; }; } export function _redefineProperty(obj: any, prop: string, desc: any) { const originalConfigurableFlag = desc.configurable; desc = rewriteDescriptor(obj, prop, desc); return _tryDefineProperty(obj, prop, desc, originalConfigurableFlag); } function isUnconfigurable(obj: any, prop: any) { return obj && obj[unconfigurablesKey] && obj[unconfigurablesKey][prop]; } function rewriteDescriptor(obj: any, prop: string, desc: any) { // issue-927, if the desc is frozen, don't try to change the desc if (!Object.isFrozen(desc)) { desc.configurable = true; } if (!desc.configurable) { // issue-927, if the obj is frozen, don't try to set the desc to obj if (!obj[unconfigurablesKey] && !Object.isFrozen(obj)) { _defineProperty(obj, unconfigurablesKey, {writable: true, value: {}}); } if (obj[unconfigurablesKey]) { obj[unconfigurablesKey][prop] = true; } } return desc; } function _tryDefineProperty(obj: any, prop: string, desc: any, originalConfigurableFlag: any) { try { return _defineProperty(obj, prop, desc); } catch (error) { if (desc.configurable) { // In case of errors, when the configurable flag was likely set by rewriteDescriptor(), let's // retry with the original flag value if (typeof originalConfigurableFlag == 'undefined') { delete desc.configurable; } else { desc.configurable = originalConfigurableFlag; } try { return _defineProperty(obj, prop, desc); } catch (error) { let descJson: string|null = null; try { descJson = JSON.stringify(desc); } catch (error) { descJson = desc.toString(); } console.log(`Attempting to configure '${prop}' with descriptor '${descJson}' on object '${ obj}' and got error, giving up: ${error}`); } } else { throw error; } } }