UNPKG

12.6 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.TreeState = void 0;
4var tslib_1 = require("tslib");
5var util_value_1 = require("@platform/util.value");
6var rxjs_1 = require("rxjs");
7var operators_1 = require("rxjs/operators");
8var common_1 = require("../common");
9var StateObject_1 = require("../StateObject");
10var TreeIdentity_1 = require("../TreeIdentity");
11var TreeQuery_1 = require("../TreeQuery");
12var helpers_1 = require("./helpers");
13var events = require("./TreeState.events");
14var path = require("./TreeState.path");
15var sync = require("./TreeState.sync");
16var Identity = TreeIdentity_1.TreeIdentity;
17var TreeState = (function () {
18 function TreeState(args) {
19 var _this = this;
20 this._children = [];
21 this._kind = 'TreeState';
22 this._dispose$ = new rxjs_1.Subject();
23 this.dispose$ = this._dispose$.pipe(operators_1.share());
24 this._event$ = new rxjs_1.Subject();
25 this.change = function (fn, options) { return _this._change(fn, options); };
26 this.add = function (args) {
27 if (TreeState.isInstance(args)) {
28 args = { parent: _this.id, root: args };
29 }
30 var self = _this;
31 var child = _this.getOrCreateInstance(args);
32 if (_this.childExists(child)) {
33 var err = "Cannot add child '" + child.id + "' as it already exists within the parent '" + _this.state.id + "'.";
34 throw new Error(err);
35 }
36 _this._children.push(child);
37 _this.change(function (draft, ctx) {
38 var root = args.parent && args.parent !== draft.id ? ctx.findById(args.parent) : draft;
39 if (!root) {
40 var err = "Cannot add child-state because the parent sub-node '" + args.parent + "' within '" + draft.id + "' does not exist.";
41 throw new Error(err);
42 }
43 TreeState.children(root).push(child.state);
44 });
45 _this.listen(child);
46 child.dispose$
47 .pipe(operators_1.take(1))
48 .pipe(operators_1.filter(function () { return _this.childExists(child); }))
49 .subscribe(function () { return _this.remove(child); });
50 _this.fire({ type: 'TreeState/child/added', payload: { parent: self, child: child } });
51 return child;
52 };
53 this.remove = function (input) {
54 var child = _this.child(input);
55 if (!child) {
56 var err = "Cannot remove child-state as it does not exist in the parent '" + _this.state.id + "'.";
57 throw new Error(err);
58 }
59 _this._children = _this._children.filter(function (item) { return item.state.id !== child.state.id; });
60 var self = _this;
61 _this.fire({ type: 'TreeState/child/removed', payload: { parent: self, child: child } });
62 return child;
63 };
64 this.clear = function () {
65 _this.children.forEach(function (child) { return _this.remove(child); });
66 return _this;
67 };
68 this.contains = function (match) {
69 return Boolean(_this.find(match));
70 };
71 this.find = function (input) {
72 if (!input) {
73 return undefined;
74 }
75 var match = typeof input === 'function'
76 ? input
77 : function (e) {
78 var id = TreeIdentity_1.TreeIdentity.toNodeId(input);
79 return e.id === id ? true : Boolean(e.tree.query.findById(id));
80 };
81 var result;
82 _this.walkDown(function (e) {
83 if (e.level > 0) {
84 if (match(e) === true) {
85 e.stop();
86 result = e.tree;
87 }
88 }
89 });
90 return result;
91 };
92 this.walkDown = function (visit) {
93 var inner = function (level, index, tree, parent, state) {
94 if (state.stopped) {
95 return;
96 }
97 var skipped = false;
98 var args = {
99 level: level,
100 id: tree.id,
101 key: Identity.key(tree.id),
102 namespace: tree.namespace,
103 index: index,
104 tree: tree,
105 parent: parent,
106 stop: function () { return (state.stopped = true); },
107 skip: function () { return (skipped = true); },
108 toString: function () { return tree.id; },
109 };
110 visit(args);
111 if (state.stopped) {
112 return;
113 }
114 if (!skipped && tree.children.length) {
115 tree.children.forEach(function (child, i) {
116 inner(level + 1, i, child, tree, state);
117 });
118 }
119 };
120 return inner(0, -1, _this, undefined, {});
121 };
122 this.syncFrom = function (args) {
123 var until$ = args.until$;
124 var isObservable = common_1.is.observable(args.source.event$);
125 var source$ = isObservable
126 ? args.source.event$
127 : args.source.event.$;
128 var parent = isObservable
129 ? args.source.parent
130 : args.source.parent;
131 var initial = isObservable ? undefined : args.source.state;
132 return sync.syncFrom({ target: _this, parent: parent, initial: initial, source$: source$, until$: until$ });
133 };
134 this.fire = function (e) { return _this._event$.next(e); };
135 var root = (typeof args.root === 'string' ? { id: args.root } : args.root);
136 if (root.id.includes('/')) {
137 var err = "Tree node IDs cannot contain the \"/\" character";
138 throw new Error(err);
139 }
140 this.key = Identity.key(root.id);
141 this.namespace = Identity.namespace(root.id) || util_value_1.id.cuid();
142 this.parent = args.parent;
143 var store = (this._store = StateObject_1.StateObject.create(root));
144 this.event = events.create({
145 event$: this._event$,
146 until$: this.dispose$,
147 });
148 this._change(function (draft) { return helpers_1.helpers.ensureNamespace(draft, _this.namespace); }, {
149 ensureNamespace: false,
150 });
151 store.event.changed$.pipe(operators_1.takeUntil(this.dispose$)).subscribe(function (e) {
152 _this.fire({ type: 'TreeState/changed', payload: e });
153 });
154 store.event.patched$.pipe(operators_1.takeUntil(this.dispose$)).subscribe(function (e) {
155 _this.fire({ type: 'TreeState/patched', payload: e });
156 });
157 if (args.dispose$) {
158 args.dispose$.subscribe(function () { return _this.dispose(); });
159 }
160 }
161 TreeState.create = function (args) {
162 var root = (args === null || args === void 0 ? void 0 : args.root) || 'node';
163 var e = tslib_1.__assign(tslib_1.__assign({}, args), { root: root });
164 return new TreeState(e);
165 };
166 TreeState.prototype.dispose = function () {
167 if (!this.isDisposed) {
168 this.children.forEach(function (child) { return child.dispose(); });
169 this._store.dispose();
170 this.fire({
171 type: 'TreeState/disposed',
172 payload: { final: this.state },
173 });
174 this._dispose$.next();
175 this._dispose$.complete();
176 }
177 };
178 Object.defineProperty(TreeState.prototype, "isDisposed", {
179 get: function () {
180 return this._dispose$.isStopped;
181 },
182 enumerable: false,
183 configurable: true
184 });
185 Object.defineProperty(TreeState.prototype, "readonly", {
186 get: function () {
187 return this;
188 },
189 enumerable: false,
190 configurable: true
191 });
192 Object.defineProperty(TreeState.prototype, "state", {
193 get: function () {
194 return this._store.state;
195 },
196 enumerable: false,
197 configurable: true
198 });
199 Object.defineProperty(TreeState.prototype, "id", {
200 get: function () {
201 return this.state.id;
202 },
203 enumerable: false,
204 configurable: true
205 });
206 Object.defineProperty(TreeState.prototype, "children", {
207 get: function () {
208 return this._children;
209 },
210 enumerable: false,
211 configurable: true
212 });
213 Object.defineProperty(TreeState.prototype, "query", {
214 get: function () {
215 var root = this.state;
216 var namespace = this.namespace;
217 return TreeQuery_1.TreeQuery.create({ root: root, namespace: namespace });
218 },
219 enumerable: false,
220 configurable: true
221 });
222 Object.defineProperty(TreeState.prototype, "path", {
223 get: function () {
224 return path.create(this);
225 },
226 enumerable: false,
227 configurable: true
228 });
229 TreeState.prototype._change = function (fn, options) {
230 var _this = this;
231 if (options === void 0) { options = {}; }
232 var action = options.action;
233 var res = this._store.change(function (draft) {
234 var ctx = _this.ctx(draft);
235 fn(draft, ctx);
236 if (options.ensureNamespace !== false) {
237 helpers_1.helpers.ensureNamespace(draft, _this.namespace);
238 }
239 }, { action: action });
240 return res;
241 };
242 TreeState.prototype.ctx = function (root) {
243 var namespace = this.namespace;
244 var query = TreeQuery_1.TreeQuery.create({ root: root, namespace: namespace });
245 var ctx = tslib_1.__assign(tslib_1.__assign({}, query), { props: TreeState.props, children: TreeState.children, toObject: function (draft) { return StateObject_1.StateObject.toObject(draft); }, query: function (node, namespace) {
246 return TreeQuery_1.TreeQuery.create({ root: node || root, namespace: namespace });
247 } });
248 return ctx;
249 };
250 TreeState.prototype.child = function (id) {
251 id = typeof id === 'string' ? id : id.state.id;
252 return this.children.find(function (item) { return item.id === id; });
253 };
254 TreeState.prototype.childExists = function (input) {
255 return Boolean(this.child(input));
256 };
257 TreeState.prototype.getOrCreateInstance = function (args) {
258 var root = (typeof args.root === 'string' ? { id: args.root } : args.root);
259 if (TreeState.isInstance(root)) {
260 return args.root;
261 }
262 var parent = Identity.toString(args.parent);
263 parent = parent ? parent : Identity.stripNamespace(this.id);
264 if (!this.query.exists(function (e) { return e.key === parent; })) {
265 var err = "Cannot add child-state because the parent node '" + parent + "' does not exist.";
266 throw new Error(err);
267 }
268 parent = Identity.format(this.namespace, parent);
269 return TreeState.create({ parent: parent, root: root });
270 };
271 TreeState.prototype.listen = function (child) {
272 var _this = this;
273 var removed$ = this.event
274 .payload('TreeState/child/removed')
275 .pipe(operators_1.filter(function (e) { return e.child.id === child.id; }));
276 removed$.subscribe(function (e) {
277 _this.change(function (draft, ctx) {
278 draft.children = TreeState.children(draft).filter(function (_a) {
279 var id = _a.id;
280 return id !== child.id;
281 });
282 });
283 });
284 child.event
285 .payload('TreeState/changed')
286 .pipe(operators_1.takeUntil(child.dispose$), operators_1.takeUntil(removed$))
287 .subscribe(function (e) {
288 _this.change(function (draft, ctx) {
289 var children = TreeState.children(draft);
290 var index = children.findIndex(function (_a) {
291 var id = _a.id;
292 return id === child.id;
293 });
294 if (index > -1) {
295 children[index] = e.to;
296 }
297 });
298 });
299 };
300 TreeState.identity = Identity;
301 TreeState.props = helpers_1.helpers.props;
302 TreeState.children = helpers_1.helpers.children;
303 TreeState.isInstance = helpers_1.helpers.isInstance;
304 return TreeState;
305}());
306exports.TreeState = TreeState;