forked from angular/angular
-
Notifications
You must be signed in to change notification settings - Fork 1
/
define-property.ts
132 lines (122 loc) · 4.43 KB
/
define-property.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/**
* @license
* Copyright Google LLC 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 = <any>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 swallowError = false;
if (prop === 'createdCallback' || prop === 'attachedCallback' ||
prop === 'detachedCallback' || prop === 'attributeChangedCallback') {
// We only swallow the error in registerElement patch
// this is the work around since some applications
// fail if we throw the error
swallowError = true;
}
if (!swallowError) {
throw error;
}
// TODO: @JiaLiPassion, Some application such as `registerElement` patch
// still need to swallow the error, in the future after these applications
// are updated, the following logic can be removed.
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;
}
}
}