1 | import { observe, isObservableMap, isObservableObject, isObservableArray, values, entries, } from "mobx";
|
2 | function buildPath(entry) {
|
3 | if (!entry)
|
4 | return "ROOT";
|
5 | var res = [];
|
6 | while (entry.parent) {
|
7 | res.push(entry.path);
|
8 | entry = entry.parent;
|
9 | }
|
10 | return res.reverse().join("/");
|
11 | }
|
12 | function isRecursivelyObservable(thing) {
|
13 | return isObservableObject(thing) || isObservableArray(thing) || isObservableMap(thing);
|
14 | }
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 | export function deepObserve(target, listener) {
|
34 | var entrySet = new WeakMap();
|
35 | function genericListener(change) {
|
36 | var entry = entrySet.get(change.object);
|
37 | processChange(change, entry);
|
38 | listener(change, buildPath(entry), target);
|
39 | }
|
40 | function processChange(change, parent) {
|
41 | switch (change.type) {
|
42 |
|
43 | case "add":
|
44 | observeRecursively(change.newValue, parent, change.name);
|
45 | break;
|
46 | case "update":
|
47 | unobserveRecursively(change.oldValue);
|
48 | observeRecursively(change.newValue, parent, change.name || "" + change.index);
|
49 | break;
|
50 | case "remove":
|
51 | case "delete":
|
52 | unobserveRecursively(change.oldValue);
|
53 | break;
|
54 |
|
55 | case "splice":
|
56 | change.removed.map(unobserveRecursively);
|
57 | change.added.forEach(function (value, idx) {
|
58 | return observeRecursively(value, parent, "" + (change.index + idx));
|
59 | });
|
60 |
|
61 | for (var i = change.index + change.addedCount; i < change.object.length; i++) {
|
62 | if (isRecursivelyObservable(change.object[i])) {
|
63 | var entry = entrySet.get(change.object[i]);
|
64 | if (entry)
|
65 | entry.path = "" + i;
|
66 | }
|
67 | }
|
68 | break;
|
69 | }
|
70 | }
|
71 | function observeRecursively(thing, parent, path) {
|
72 | if (isRecursivelyObservable(thing)) {
|
73 | var entry = entrySet.get(thing);
|
74 | if (entry) {
|
75 | if (entry.parent !== parent || entry.path !== path)
|
76 |
|
77 |
|
78 |
|
79 | throw new Error("The same observable object cannot appear twice in the same tree," +
|
80 | (" trying to assign it to '" + buildPath(parent) + "/" + path + "',") +
|
81 | (" but it already exists at '" + buildPath(entry.parent) + "/" + entry.path + "'"));
|
82 | }
|
83 | else {
|
84 | var entry_1 = {
|
85 | parent: parent,
|
86 | path: path,
|
87 | dispose: observe(thing, genericListener),
|
88 | };
|
89 | entrySet.set(thing, entry_1);
|
90 | entries(thing).forEach(function (_a) {
|
91 | var key = _a[0], value = _a[1];
|
92 | return observeRecursively(value, entry_1, key);
|
93 | });
|
94 | }
|
95 | }
|
96 | }
|
97 | function unobserveRecursively(thing) {
|
98 | if (isRecursivelyObservable(thing)) {
|
99 | var entry = entrySet.get(thing);
|
100 | if (!entry)
|
101 | return;
|
102 | entrySet.delete(thing);
|
103 | entry.dispose();
|
104 | values(thing).forEach(unobserveRecursively);
|
105 | }
|
106 | }
|
107 | observeRecursively(target, undefined, "");
|
108 | return function () {
|
109 | unobserveRecursively(target);
|
110 | };
|
111 | }
|