forked from mobxjs/mobx
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdecorators.ts
More file actions
119 lines (107 loc) · 4.16 KB
/
Copy pathdecorators.ts
File metadata and controls
119 lines (107 loc) · 4.16 KB
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
import { EMPTY_ARRAY, addHiddenProp, fail } from "../internal"
export const mobxDidRunLazyInitializersSymbol = Symbol("mobx did run lazy initializers")
export const mobxPendingDecorators = Symbol("mobx pending decorators")
type DecoratorTarget = {
[mobxDidRunLazyInitializersSymbol]?: boolean
[mobxPendingDecorators]?: { [prop: string]: DecoratorInvocationDescription }
}
export type BabelDescriptor = PropertyDescriptor & { initializer?: () => any }
export type PropertyCreator = (
instance: any,
propertyName: string,
descriptor: BabelDescriptor | undefined,
decoratorTarget: any,
decoratorArgs: any[]
) => void
type DecoratorInvocationDescription = {
prop: string
propertyCreator: PropertyCreator
descriptor: BabelDescriptor | undefined
decoratorTarget: any
decoratorArguments: any[]
}
const enumerableDescriptorCache: { [prop: string]: PropertyDescriptor } = {}
const nonEnumerableDescriptorCache: { [prop: string]: PropertyDescriptor } = {}
function createPropertyInitializerDescriptor(
prop: string,
enumerable: boolean
): PropertyDescriptor {
const cache = enumerable ? enumerableDescriptorCache : nonEnumerableDescriptorCache
return (
cache[prop] ||
(cache[prop] = {
configurable: true,
enumerable: enumerable,
get() {
initializeInstance(this)
return this[prop]
},
set(value) {
initializeInstance(this)
this[prop] = value
}
})
)
}
export function initializeInstance(target: any)
export function initializeInstance(target: DecoratorTarget) {
if (target[mobxDidRunLazyInitializersSymbol] === true) return
const decorators = target[mobxPendingDecorators]
if (decorators) {
addHiddenProp(target, mobxDidRunLazyInitializersSymbol, true)
for (let key in decorators) {
const d = decorators[key]
d.propertyCreator(target, d.prop, d.descriptor, d.decoratorTarget, d.decoratorArguments)
}
}
}
export function createPropDecorator(
propertyInitiallyEnumerable: boolean,
propertyCreator: PropertyCreator
) {
return function decoratorFactory() {
let decoratorArguments: any[]
const decorator = function decorate(
target: DecoratorTarget,
prop: string,
descriptor: BabelDescriptor | undefined,
applyImmediately?: any
// This is a special parameter to signal the direct application of a decorator, allow extendObservable to skip the entire type decoration part,
// as the instance to apply the decorator to equals the target
) {
if (applyImmediately === true) {
propertyCreator(target, prop, descriptor, target, decoratorArguments)
return null
}
if (process.env.NODE_ENV !== "production" && !quacksLikeADecorator(arguments))
fail("This function is a decorator, but it wasn't invoked like a decorator")
if (!Object.prototype.hasOwnProperty.call(target, mobxPendingDecorators)) {
const inheritedDecorators = target[mobxPendingDecorators]
addHiddenProp(target, mobxPendingDecorators, { ...inheritedDecorators })
}
target[mobxPendingDecorators]![prop] = {
prop,
propertyCreator,
descriptor,
decoratorTarget: target,
decoratorArguments
}
return createPropertyInitializerDescriptor(prop, propertyInitiallyEnumerable)
}
if (quacksLikeADecorator(arguments)) {
// @decorator
decoratorArguments = EMPTY_ARRAY
return decorator.apply(null, arguments as any)
} else {
// @decorator(args)
decoratorArguments = Array.prototype.slice.call(arguments)
return decorator
}
} as Function
}
export function quacksLikeADecorator(args: IArguments): boolean {
return (
((args.length === 2 || args.length === 3) && typeof args[1] === "string") ||
(args.length === 4 && args[3] === true)
)
}