UNPKG

3.06 kBPlain TextView Raw
1import {
2 ObservableObjectAdministration,
3 Annotation,
4 defineProperty,
5 die,
6 flow,
7 isFlow,
8 isFunction,
9 globalState,
10 MakeResult
11} from "../internal"
12
13export function createFlowAnnotation(name: string, options?: object): Annotation {
14 return {
15 annotationType_: name,
16 options_: options,
17 make_,
18 extend_
19 }
20}
21
22function make_(
23 adm: ObservableObjectAdministration,
24 key: PropertyKey,
25 descriptor: PropertyDescriptor,
26 source: object
27): MakeResult {
28 // own
29 if (source === adm.target_) {
30 return this.extend_(adm, key, descriptor, false) === null
31 ? MakeResult.Cancel
32 : MakeResult.Continue
33 }
34 // prototype
35 // bound - must annotate protos to support super.flow()
36 if (this.options_?.bound && !isFlow(adm.target_[key])) {
37 if (this.extend_(adm, key, descriptor, false) === null) return MakeResult.Cancel
38 }
39 if (isFlow(descriptor.value)) {
40 // A prototype could have been annotated already by other constructor,
41 // rest of the proto chain must be annotated already
42 return MakeResult.Break
43 }
44 const flowDescriptor = createFlowDescriptor(adm, this, key, descriptor, false, false)
45 defineProperty(source, key, flowDescriptor)
46 return MakeResult.Continue
47}
48
49function extend_(
50 adm: ObservableObjectAdministration,
51 key: PropertyKey,
52 descriptor: PropertyDescriptor,
53 proxyTrap: boolean
54): boolean | null {
55 const flowDescriptor = createFlowDescriptor(adm, this, key, descriptor, this.options_?.bound)
56 return adm.defineProperty_(key, flowDescriptor, proxyTrap)
57}
58
59function assertFlowDescriptor(
60 adm: ObservableObjectAdministration,
61 { annotationType_ }: Annotation,
62 key: PropertyKey,
63 { value }: PropertyDescriptor
64) {
65 if (__DEV__ && !isFunction(value)) {
66 die(
67 `Cannot apply '${annotationType_}' to '${adm.name_}.${key.toString()}':` +
68 `\n'${annotationType_}' can only be used on properties with a generator function value.`
69 )
70 }
71}
72
73function createFlowDescriptor(
74 adm: ObservableObjectAdministration,
75 annotation: Annotation,
76 key: PropertyKey,
77 descriptor: PropertyDescriptor,
78 bound: boolean,
79 // provides ability to disable safeDescriptors for prototypes
80 safeDescriptors: boolean = globalState.safeDescriptors
81): PropertyDescriptor {
82 assertFlowDescriptor(adm, annotation, key, descriptor)
83 let { value } = descriptor
84 if (bound) {
85 value = value.bind(adm.proxy_ ?? adm.target_)
86 }
87 return {
88 value: flow(value),
89 // Non-configurable for classes
90 // prevents accidental field redefinition in subclass
91 configurable: safeDescriptors ? adm.isPlainObject_ : true,
92 // https://github.com/mobxjs/mobx/pull/2641#issuecomment-737292058
93 enumerable: false,
94 // Non-obsevable, therefore non-writable
95 // Also prevents rewriting in subclass constructor
96 writable: safeDescriptors ? false : true
97 }
98}