epos-unit 1.17.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,15 +1,22 @@
1
- import * as mobx from 'mobx';
2
- import { Cls, Obj, Arr } from 'dropcap/types';
1
+ import type { Arr, Cls, Obj } from 'dropcap/types';
3
2
  import { createLog } from 'dropcap/utils';
4
-
5
- declare const _root_: unique symbol;
6
- declare const _parent_: unique symbol;
7
- declare const _attached_: unique symbol;
8
- declare const _disposers_: unique symbol;
9
- declare const _ancestors_: unique symbol;
10
- declare const _pendingAttachHooks_: unique symbol;
11
- type Node<T> = Unit<T> | Obj | Arr;
12
- declare class Unit<TRoot = unknown> {
3
+ import 'epos';
4
+ declare global {
5
+ interface ErrorConstructor {
6
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
7
+ }
8
+ }
9
+ export declare const _root_: unique symbol;
10
+ export declare const _parent_: unique symbol;
11
+ export declare const _attached_: unique symbol;
12
+ export declare const _disposers_: unique symbol;
13
+ export declare const _ancestors_: unique symbol;
14
+ export declare const _attachQueue_: unique symbol;
15
+ export type Node<T> = Unit<T> | Obj | Arr;
16
+ export type Versioner<T> = {
17
+ [version: number]: (this: T) => void;
18
+ };
19
+ export declare class Unit<TRoot = unknown> {
13
20
  /**
14
21
  * Lifecycle method called when the unit is attached to the state tree.
15
22
  */
@@ -27,42 +34,37 @@ declare class Unit<TRoot = unknown> {
27
34
  [_attached_]?: boolean;
28
35
  [_disposers_]?: Set<() => void>;
29
36
  [_ancestors_]?: Map<Cls, unknown>;
30
- [_pendingAttachHooks_]?: (() => void)[];
37
+ [_attachQueue_]?: (() => void)[];
38
+ static defineVersioner<T extends Unit>(this: Cls<T>, versioner: Versioner<T>): Versioner<T>;
31
39
  constructor(parent: Unit<TRoot> | null);
32
40
  /**
33
- * Gets the root unit of the current unit's tree.
41
+ * Get the root unit of the current unit's tree.
34
42
  * The result is cached for subsequent calls.
35
43
  */
36
44
  get $(): TRoot | (undefined & TRoot);
37
45
  /**
38
- * A wrapper around MobX's `autorun` that automatically disposes
39
- * the reaction when the unit is detached.
46
+ * A wrapper around MobX's `autorun` that automatically disposes the reaction when the unit is detached.
40
47
  */
41
- autorun(...args: Parameters<typeof epos.libs.mobx.autorun>): mobx.IReactionDisposer;
48
+ autorun(...args: Parameters<typeof epos.libs.mobx.autorun>): import("mobx").IReactionDisposer;
42
49
  /**
43
- * A wrapper around MobX's `reaction` that automatically disposes
44
- * the reaction when the unit is detached.
50
+ * A wrapper around MobX's `reaction` that automatically disposes the reaction when the unit is detached.
45
51
  */
46
- reaction(...args: Parameters<typeof epos.libs.mobx.reaction>): mobx.IReactionDisposer;
52
+ reaction(...args: Parameters<typeof epos.libs.mobx.reaction>): import("mobx").IReactionDisposer;
47
53
  /**
48
- * A wrapper around `setTimeout` that automatically clears the timeout
49
- * when the unit is detached.
54
+ * A wrapper around `setTimeout` that automatically clears the timeout when the unit is detached.
50
55
  */
51
- setTimeout(...args: Parameters<typeof self.setTimeout>): number;
56
+ setTimeout(...args: Parameters<typeof setTimeout>): NodeJS.Timeout;
52
57
  /**
53
- * A wrapper around `setInterval` that automatically clears the interval
54
- * when the unit is detached.
58
+ * A wrapper around `setInterval` that automatically clears the interval when the unit is detached.
55
59
  */
56
- setInterval(...args: Parameters<typeof self.setInterval>): number;
60
+ setInterval(...args: Parameters<typeof setInterval>): NodeJS.Timeout;
57
61
  /**
58
- * Creates an error for an unreachable code path.
62
+ * Create an error for code paths that are logically unreachable.
59
63
  */
60
64
  never(message?: string): Error;
61
65
  /**
62
- * Finds the closest ancestor unit of a given type.
66
+ * Find the closest ancestor unit of a given type.
63
67
  * The result is cached for subsequent calls.
64
68
  */
65
69
  closest<T extends Unit>(Ancestor: Cls<T>): T | null;
66
70
  }
67
-
68
- export { type Node, Unit, _ancestors_, _attached_, _disposers_, _parent_, _pendingAttachHooks_, _root_ };
package/dist/epos-unit.js CHANGED
@@ -1,239 +1,313 @@
1
- // src/epos-unit.ts
2
- import { createLog, is } from "dropcap/utils";
3
- import "epos";
4
- import { customAlphabet } from "nanoid";
5
- var _root_ = /* @__PURE__ */ Symbol("root");
6
- var _parent_ = /* @__PURE__ */ Symbol("parent");
7
- var _attached_ = /* @__PURE__ */ Symbol("attached");
8
- var _disposers_ = /* @__PURE__ */ Symbol("disposers");
9
- var _ancestors_ = /* @__PURE__ */ Symbol("ancestors");
10
- var _pendingAttachHooks_ = /* @__PURE__ */ Symbol("pendingAttachHooks");
11
- var nanoid = customAlphabet("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 8);
12
- var Unit = class {
13
- constructor(parent) {
14
- this.id = nanoid();
15
- this[_parent_] = parent;
16
- const versioner = getVersioner(this);
17
- const versions = getVersions(versioner);
18
- if (versions.length > 0) this[":version"] = versions.at(-1);
19
- }
20
- // ---------------------------------------------------------------------------
21
- // ATTACH / DETACH
22
- // ---------------------------------------------------------------------------
23
- /**
24
- * Lifecycle method called when the unit is attached to the state tree.
25
- */
26
- [epos.state.ATTACH]() {
27
- epos.state.transaction(() => {
28
- const versioner = getVersioner(this);
29
- const versions = getVersions(versioner);
30
- for (const version of versions) {
31
- if (is.number(this[":version"]) && this[":version"] >= version) continue;
32
- const versionFn = versioner[version];
33
- if (!is.function(versionFn)) continue;
34
- versionFn.call(this, this);
35
- this[":version"] = version;
36
- }
37
- });
38
- let log = createLog(this["@"]);
39
- Reflect.defineProperty(this, "log", {
40
- configurable: true,
41
- get: () => log,
42
- set: (v) => log = v
43
- });
44
- const stateDescriptor = Reflect.getOwnPropertyDescriptor(this.constructor.prototype, "state");
45
- if (stateDescriptor && stateDescriptor.get) {
46
- const value = stateDescriptor.get.call(this);
47
- const state = epos.state.local(value, { deep: false });
48
- Reflect.defineProperty(this, "state", { get: () => state });
1
+ import { createLog, is } from 'dropcap/utils';
2
+ import 'epos';
3
+ import { customAlphabet } from 'nanoid';
4
+ export const _root_ = Symbol('root');
5
+ export const _parent_ = Symbol('parent');
6
+ export const _attached_ = Symbol('attached');
7
+ export const _disposers_ = Symbol('disposers');
8
+ export const _ancestors_ = Symbol('ancestors');
9
+ export const _attachQueue_ = Symbol('pendingAttachHooks');
10
+ const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz0123456789', 10);
11
+ export class Unit {
12
+ static defineVersioner(versioner) {
13
+ return versioner;
14
+ }
15
+ constructor(parent) {
16
+ this.id = nanoid();
17
+ this[_parent_] = parent;
49
18
  }
50
- for (const prototype of getPrototypes(this)) {
51
- const descriptors = Object.getOwnPropertyDescriptors(prototype);
52
- for (const [key, descriptor] of Object.entries(descriptors)) {
53
- if (key === "constructor") continue;
54
- if (this.hasOwnProperty(key)) continue;
55
- if (is.function(descriptor.value) && key.endsWith("View")) {
56
- let Component = epos.component(descriptor.value.bind(this));
57
- Component.displayName = `${this.constructor.name}.${key}`;
58
- Reflect.defineProperty(this, key, {
59
- configurable: true,
60
- get: () => Component,
61
- set: (v) => Component = v
62
- });
63
- } else if (is.function(descriptor.value)) {
64
- let method = descriptor.value.bind(this);
65
- Reflect.defineProperty(this, key, {
66
- configurable: true,
67
- get: () => method,
68
- set: (v) => method = v
69
- });
70
- } else if (descriptor.get) {
71
- const getter = descriptor.get;
72
- const computed = epos.libs.mobx.computed(() => getter.call(this));
73
- Reflect.defineProperty(this, key, {
74
- configurable: true,
75
- get: () => computed.get(),
76
- set: descriptor.set
77
- });
19
+ // ---------------------------------------------------------------------------
20
+ // ATTACH
21
+ // ---------------------------------------------------------------------------
22
+ /**
23
+ * Lifecycle method called when the unit is attached to the state tree.
24
+ */
25
+ [epos.state.ATTACH]() {
26
+ // Setup logger
27
+ let log = createLog(this['@']);
28
+ Reflect.defineProperty(this, 'log', { configurable: true, get: () => log, set: v => (log = v) });
29
+ // Apply versioner
30
+ void (() => {
31
+ const versioner = Reflect.get(this.constructor, 'versioner');
32
+ if (!is.object(versioner))
33
+ return;
34
+ const asc = (v1, v2) => v1 - v2;
35
+ const versions = Object.keys(versioner).filter(is.numeric).map(Number).sort(asc);
36
+ if (versions.length === 0)
37
+ return;
38
+ epos.state.transaction(() => {
39
+ for (const version of versions) {
40
+ if (is.number(this[':version']) && this[':version'] >= version)
41
+ continue;
42
+ const versionFn = versioner[version];
43
+ if (!is.function(versionFn))
44
+ continue;
45
+ versionFn.call(this);
46
+ this[':version'] = version;
47
+ }
48
+ });
49
+ })();
50
+ // Setup state
51
+ void (() => {
52
+ const descriptor = Reflect.getOwnPropertyDescriptor(this.constructor.prototype, 'state');
53
+ if (!descriptor || !descriptor.get)
54
+ return;
55
+ const value = descriptor.get.call(this);
56
+ if (!is.object(value))
57
+ throw new Error(`'state' getter return an object`);
58
+ const state = epos.state.create(value);
59
+ Reflect.defineProperty(state, epos.state.PARENT, { configurable: true, value: this });
60
+ Reflect.defineProperty(this, 'state', { enumerable: true, get: () => state });
61
+ })();
62
+ // Setup inert
63
+ void (() => {
64
+ const descriptor = Reflect.getOwnPropertyDescriptor(this.constructor.prototype, 'inert');
65
+ if (!descriptor || !descriptor.get)
66
+ return;
67
+ const value = descriptor.get.call(this);
68
+ if (!is.object(value))
69
+ throw new Error(`'inert' getter return an object`);
70
+ Reflect.defineProperty(this, 'inert', { enumerable: true, get: () => value });
71
+ })();
72
+ // Prepare properties for the whole prototype chain:
73
+ // - Create components for methods ending with `View`
74
+ // - Bind all other methods to the unit instance
75
+ // - Turn getters into MobX computed properties
76
+ for (const prototype of getPrototypes(this)) {
77
+ const descriptors = Object.getOwnPropertyDescriptors(prototype);
78
+ for (const [key, descriptor] of Object.entries(descriptors)) {
79
+ // Skip constructor and already defined properties
80
+ if (key === 'constructor')
81
+ continue;
82
+ if (this.hasOwnProperty(key))
83
+ continue;
84
+ // Create components for methods ending with `View`
85
+ if (is.function(descriptor.value) && key.endsWith('View')) {
86
+ let View = createView(this, key, descriptor.value.bind(this));
87
+ Reflect.defineProperty(this, key, { configurable: true, get: () => View, set: v => (View = v) });
88
+ }
89
+ // Bind all other methods to the unit instance
90
+ else if (is.function(descriptor.value)) {
91
+ let method = descriptor.value.bind(this);
92
+ Reflect.defineProperty(this, key, {
93
+ configurable: true,
94
+ get: () => method,
95
+ set: v => (method = v),
96
+ });
97
+ }
98
+ // Turn getters into MobX computed properties
99
+ else if (descriptor.get) {
100
+ const getter = descriptor.get;
101
+ const computed = epos.libs.mobx.computed(() => getter.call(this));
102
+ Reflect.defineProperty(this, key, {
103
+ configurable: true,
104
+ get: () => computed.get(),
105
+ set: descriptor.set,
106
+ });
107
+ }
108
+ }
78
109
  }
79
- }
110
+ // Queue attach method.
111
+ // Do not execute `attach` methods immediately, but rather queue them on the highest unattached ancestor.
112
+ // This way `attach` methods are called after all versioners have been applied in the entire subtree.
113
+ const attach = Reflect.get(this, 'attach');
114
+ if (is.function(attach)) {
115
+ const head = findUnattachedRoot(this);
116
+ if (!head)
117
+ throw this.never();
118
+ ensure(head, _attachQueue_, () => []);
119
+ head[_attachQueue_].push(() => attach.call(this));
120
+ }
121
+ // Release attach queue
122
+ if (this[_attachQueue_]) {
123
+ this[_attachQueue_].forEach(attach => attach());
124
+ delete this[_attachQueue_];
125
+ }
126
+ // Mark as attached
127
+ Reflect.defineProperty(this, _attached_, { configurable: true, get: () => true });
80
128
  }
81
- const attach = Reflect.get(this, "attach");
82
- if (is.function(attach)) {
83
- const unattachedRoot = findUnattachedRoot(this);
84
- if (!unattachedRoot) throw this.never();
85
- ensure(unattachedRoot, _pendingAttachHooks_, () => []);
86
- unattachedRoot[_pendingAttachHooks_].push(() => attach());
129
+ // ---------------------------------------------------------------------------
130
+ // DETACH
131
+ // ---------------------------------------------------------------------------
132
+ /**
133
+ * Lifecycle method called when the unit is detached from the state tree.
134
+ */
135
+ [epos.state.DETACH]() {
136
+ // Run and clear disposers
137
+ if (this[_disposers_]) {
138
+ this[_disposers_].forEach(disposer => disposer());
139
+ this[_disposers_].clear();
140
+ }
141
+ // Clear ancestors cache
142
+ if (this[_ancestors_]) {
143
+ this[_ancestors_].clear();
144
+ }
145
+ // Call detach method
146
+ const detach = Reflect.get(this, 'detach');
147
+ if (is.function(detach))
148
+ detach();
87
149
  }
88
- if (this[_pendingAttachHooks_]) {
89
- this[_pendingAttachHooks_].forEach((attach2) => attach2());
90
- delete this[_pendingAttachHooks_];
150
+ // ---------------------------------------------------------------------------
151
+ // ROOT GETTER
152
+ // ---------------------------------------------------------------------------
153
+ /**
154
+ * Get the root unit of the current unit's tree.
155
+ * The result is cached for subsequent calls.
156
+ */
157
+ get $() {
158
+ ensure(this, _root_, () => findRoot(this));
159
+ return this[_root_];
91
160
  }
92
- Reflect.defineProperty(this, _attached_, { configurable: true, get: () => true });
93
- }
94
- /**
95
- * Lifecycle method called when the unit is detached from the state tree.
96
- */
97
- [epos.state.DETACH]() {
98
- if (this[_disposers_]) {
99
- this[_disposers_].forEach((disposer) => disposer());
100
- this[_disposers_].clear();
161
+ // ---------------------------------------------------------------------------
162
+ // METHODS
163
+ // ---------------------------------------------------------------------------
164
+ /**
165
+ * A wrapper around MobX's `autorun` that automatically disposes the reaction when the unit is detached.
166
+ */
167
+ autorun(...args) {
168
+ const disposer = epos.libs.mobx.autorun(...args);
169
+ ensure(this, _disposers_, () => new Set());
170
+ this[_disposers_].add(disposer);
171
+ return disposer;
101
172
  }
102
- if (this[_ancestors_]) {
103
- this[_ancestors_].clear();
173
+ /**
174
+ * A wrapper around MobX's `reaction` that automatically disposes the reaction when the unit is detached.
175
+ */
176
+ reaction(...args) {
177
+ const disposer = epos.libs.mobx.reaction(...args);
178
+ ensure(this, _disposers_, () => new Set());
179
+ this[_disposers_].add(disposer);
180
+ return disposer;
104
181
  }
105
- const detach = Reflect.get(this, "detach");
106
- if (is.function(detach)) detach();
107
- }
108
- // ---------------------------------------------------------------------------
109
- // ROOT GETTER
110
- // ---------------------------------------------------------------------------
111
- /**
112
- * Gets the root unit of the current unit's tree.
113
- * The result is cached for subsequent calls.
114
- */
115
- get $() {
116
- ensure(this, _root_, () => findRoot(this));
117
- return this[_root_];
118
- }
119
- // ---------------------------------------------------------------------------
120
- // METHODS
121
- // ---------------------------------------------------------------------------
122
- /**
123
- * A wrapper around MobX's `autorun` that automatically disposes
124
- * the reaction when the unit is detached.
125
- */
126
- autorun(...args) {
127
- const disposer = epos.libs.mobx.autorun(...args);
128
- ensure(this, _disposers_, () => /* @__PURE__ */ new Set());
129
- this[_disposers_].add(disposer);
130
- return disposer;
131
- }
132
- /**
133
- * A wrapper around MobX's `reaction` that automatically disposes
134
- * the reaction when the unit is detached.
135
- */
136
- reaction(...args) {
137
- const disposer = epos.libs.mobx.reaction(...args);
138
- ensure(this, _disposers_, () => /* @__PURE__ */ new Set());
139
- this[_disposers_].add(disposer);
140
- return disposer;
141
- }
142
- /**
143
- * A wrapper around `setTimeout` that automatically clears the timeout
144
- * when the unit is detached.
145
- */
146
- setTimeout(...args) {
147
- const id = self.setTimeout(...args);
148
- ensure(this, _disposers_, () => /* @__PURE__ */ new Set());
149
- this[_disposers_].add(() => self.clearTimeout(id));
150
- return id;
151
- }
152
- /**
153
- * A wrapper around `setInterval` that automatically clears the interval
154
- * when the unit is detached.
155
- */
156
- setInterval(...args) {
157
- const id = self.setInterval(...args);
158
- ensure(this, _disposers_, () => /* @__PURE__ */ new Set());
159
- this[_disposers_].add(() => self.clearInterval(id));
160
- return id;
161
- }
162
- /**
163
- * Creates an error for an unreachable code path.
164
- */
165
- never(message = "This should never happen") {
166
- const details = message ? `: ${message}` : "";
167
- const error = new Error(`[${this.constructor.name}] This should never happen${details}`);
168
- Error.captureStackTrace(error, this.never);
169
- return error;
170
- }
171
- /**
172
- * Finds the closest ancestor unit of a given type.
173
- * The result is cached for subsequent calls.
174
- */
175
- closest(Ancestor) {
176
- ensure(this, _ancestors_, () => /* @__PURE__ */ new Map());
177
- if (this[_ancestors_].has(Ancestor)) return this[_ancestors_].get(Ancestor);
178
- let cursor = this;
179
- while (cursor) {
180
- if (cursor instanceof Ancestor) {
181
- this[_ancestors_].set(Ancestor, cursor);
182
- return cursor;
183
- }
184
- cursor = getParent(cursor);
182
+ /**
183
+ * A wrapper around `setTimeout` that automatically clears the timeout when the unit is detached.
184
+ */
185
+ setTimeout(...args) {
186
+ const id = setTimeout(...args);
187
+ ensure(this, _disposers_, () => new Set());
188
+ this[_disposers_].add(() => clearTimeout(id));
189
+ return id;
190
+ }
191
+ /**
192
+ * A wrapper around `setInterval` that automatically clears the interval when the unit is detached.
193
+ */
194
+ setInterval(...args) {
195
+ const id = setInterval(...args);
196
+ ensure(this, _disposers_, () => new Set());
197
+ this[_disposers_].add(() => clearInterval(id));
198
+ return id;
185
199
  }
186
- return null;
187
- }
188
- };
200
+ /**
201
+ * Create an error for code paths that are logically unreachable.
202
+ */
203
+ never(message = 'This should never happen') {
204
+ const details = message ? `: ${message}` : '';
205
+ const error = new Error(`[${this['@']}] This should never happen${details}`);
206
+ Error.captureStackTrace(error, this.never);
207
+ return error;
208
+ }
209
+ /**
210
+ * Find the closest ancestor unit of a given type.
211
+ * The result is cached for subsequent calls.
212
+ */
213
+ closest(Ancestor) {
214
+ // Has cached value? -> Return it
215
+ ensure(this, _ancestors_, () => new Map());
216
+ if (this[_ancestors_].has(Ancestor))
217
+ return this[_ancestors_].get(Ancestor);
218
+ // Find the closest ancestor and cache it
219
+ let cursor = this;
220
+ while (cursor) {
221
+ if (cursor instanceof Ancestor) {
222
+ this[_ancestors_].set(Ancestor, cursor);
223
+ return cursor;
224
+ }
225
+ cursor = getParent(cursor);
226
+ }
227
+ return null;
228
+ }
229
+ }
230
+ // ---------------------------------------------------------------------------
231
+ // HELPERS
232
+ // ---------------------------------------------------------------------------
233
+ /**
234
+ * Ensure a property exists on an object, initialize it if it doesn't.
235
+ */
189
236
  function ensure(object, key, getInitialValue) {
190
- if (key in object) return;
191
- const value = getInitialValue();
192
- Reflect.defineProperty(object, key, { configurable: true, get: () => value });
237
+ if (key in object)
238
+ return;
239
+ const value = getInitialValue();
240
+ Reflect.defineProperty(object, key, { configurable: true, get: () => value });
193
241
  }
242
+ /**
243
+ * Get all prototypes of an object up to `Object.prototype`.
244
+ */
194
245
  function getPrototypes(object) {
195
- const prototype = Reflect.getPrototypeOf(object);
196
- if (!prototype || prototype === Object.prototype) return [];
197
- return [prototype, ...getPrototypes(prototype)];
246
+ const prototype = Reflect.getPrototypeOf(object);
247
+ if (!prototype || prototype === Object.prototype)
248
+ return [];
249
+ return [prototype, ...getPrototypes(prototype)];
198
250
  }
251
+ /**
252
+ * Find the root `Unit` in the hierarchy for a given unit.
253
+ */
199
254
  function findRoot(unit) {
200
- let root = null;
201
- let cursor = unit;
202
- while (cursor) {
203
- if (cursor instanceof Unit) root = cursor;
204
- cursor = getParent(cursor);
205
- }
206
- return root;
255
+ let root = null;
256
+ let cursor = unit;
257
+ while (cursor) {
258
+ if (cursor instanceof Unit)
259
+ root = cursor;
260
+ cursor = getParent(cursor);
261
+ }
262
+ return root;
207
263
  }
264
+ /**
265
+ * Find the highest unattached `Unit` in the hierarchy for a given unit.
266
+ */
208
267
  function findUnattachedRoot(unit) {
209
- let unattachedRoot = null;
210
- let cursor = unit;
211
- while (cursor) {
212
- if (cursor instanceof Unit && !cursor[_attached_]) unattachedRoot = cursor;
213
- cursor = getParent(cursor);
214
- }
215
- return unattachedRoot;
268
+ let unattachedRoot = null;
269
+ let cursor = unit;
270
+ while (cursor) {
271
+ if (cursor instanceof Unit && !cursor[_attached_])
272
+ unattachedRoot = cursor;
273
+ cursor = getParent(cursor);
274
+ }
275
+ return unattachedRoot;
216
276
  }
277
+ /**
278
+ * Get the parent of a node, which can be a `Unit`, an object, or an array.
279
+ */
217
280
  function getParent(node) {
218
- const parent = Reflect.get(node, _parent_) ?? Reflect.get(node, epos.state.PARENT) ?? null;
219
- return parent;
220
- }
221
- function getVersioner(unit) {
222
- const versioner = Reflect.get(unit.constructor, "versioner");
223
- if (!is.object(versioner)) return {};
224
- return versioner;
281
+ const parent = Reflect.get(node, _parent_) ?? Reflect.get(node, epos.state.PARENT) ?? null;
282
+ return parent;
225
283
  }
226
- function getVersions(versioner) {
227
- const numericKeys = Object.keys(versioner).filter((key) => is.numeric(key));
228
- return numericKeys.map(Number).sort((v1, v2) => v1 - v2);
284
+ /**
285
+ * Create view component for the unit.
286
+ */
287
+ function createView(unit, name, render) {
288
+ const fullName = `${unit['@']}.${name}`;
289
+ const View = epos.component((props) => {
290
+ try {
291
+ return render(props);
292
+ }
293
+ catch (error) {
294
+ unit.log.error(error);
295
+ const message = is.error(error) ? error.message : String(error);
296
+ return epos.libs.reactJsxRuntime.jsx('div', {
297
+ children: `[${fullName}] ${message}`,
298
+ style: {
299
+ width: 'fit-content',
300
+ padding: '4px 6px 4px 4px',
301
+ color: '#f00',
302
+ border: '1px solid #f00',
303
+ background: 'rgba(255, 0, 0, 0.1)',
304
+ fontSize: 12,
305
+ fontWeight: 400,
306
+ },
307
+ });
308
+ }
309
+ });
310
+ View.displayName = fullName;
311
+ return View;
229
312
  }
230
- export {
231
- Unit,
232
- _ancestors_,
233
- _attached_,
234
- _disposers_,
235
- _parent_,
236
- _pendingAttachHooks_,
237
- _root_
238
- };
239
313
  //# sourceMappingURL=epos-unit.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/epos-unit.ts"],"sourcesContent":["import type { Arr, Cls, Obj } from 'dropcap/types'\nimport { createLog, is } from 'dropcap/utils'\nimport 'epos'\nimport { customAlphabet } from 'nanoid'\n\nexport const _root_ = Symbol('root')\nexport const _parent_ = Symbol('parent')\nexport const _attached_ = Symbol('attached')\nexport const _disposers_ = Symbol('disposers')\nexport const _ancestors_ = Symbol('ancestors')\nexport const _pendingAttachHooks_ = Symbol('pendingAttachHooks')\nconst nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 8)\n\nexport type Node<T> = Unit<T> | Obj | Arr\n\nexport class Unit<TRoot = unknown> {\n declare '@': string\n declare id: string\n declare log: ReturnType<typeof createLog>;\n declare [':version']?: number;\n declare [_root_]?: TRoot;\n declare [_parent_]?: Unit<TRoot> | null; // Parent reference for a not-yet-attached units\n declare [_attached_]?: boolean;\n declare [_disposers_]?: Set<() => void>;\n declare [_ancestors_]?: Map<Cls, unknown>;\n declare [_pendingAttachHooks_]?: (() => void)[]\n\n constructor(parent: Unit<TRoot> | null) {\n this.id = nanoid()\n this[_parent_] = parent\n const versioner = getVersioner(this)\n const versions = getVersions(versioner)\n if (versions.length > 0) this[':version'] = versions.at(-1)!\n }\n\n // ---------------------------------------------------------------------------\n // ATTACH / DETACH\n // ---------------------------------------------------------------------------\n\n /**\n * Lifecycle method called when the unit is attached to the state tree.\n */\n [epos.state.ATTACH]() {\n // Apply versioner\n epos.state.transaction(() => {\n const versioner = getVersioner(this)\n const versions = getVersions(versioner)\n for (const version of versions) {\n if (is.number(this[':version']) && this[':version'] >= version) continue\n const versionFn = versioner[version]\n if (!is.function(versionFn)) continue\n versionFn.call(this, this)\n this[':version'] = version\n }\n })\n\n // Setup logger\n let log = createLog(this['@'])\n Reflect.defineProperty(this, 'log', {\n configurable: true,\n get: () => log,\n set: v => (log = v),\n })\n\n // Setup state\n const stateDescriptor = Reflect.getOwnPropertyDescriptor(this.constructor.prototype, 'state')\n if (stateDescriptor && stateDescriptor.get) {\n const value = stateDescriptor.get.call(this)\n const state = epos.state.local(value, { deep: false })\n Reflect.defineProperty(this, 'state', { get: () => state })\n }\n\n // Prepare properties for the whole prototype chain:\n // - Create components for methods ending with `View`\n // - Bind all other methods to the unit instance\n // - Turn getters into MobX computed properties\n for (const prototype of getPrototypes(this)) {\n const descriptors = Object.getOwnPropertyDescriptors(prototype)\n for (const [key, descriptor] of Object.entries(descriptors)) {\n // Skip constructor and already defined properties\n if (key === 'constructor') continue\n if (this.hasOwnProperty(key)) continue\n\n // Create components for methods ending with `View`\n if (is.function(descriptor.value) && key.endsWith('View')) {\n let Component = epos.component(descriptor.value.bind(this))\n Component.displayName = `${this.constructor.name}.${key}`\n Reflect.defineProperty(this, key, {\n configurable: true,\n get: () => Component,\n set: v => (Component = v),\n })\n }\n\n // Bind all other methods to the unit instance\n else if (is.function(descriptor.value)) {\n let method = descriptor.value.bind(this)\n Reflect.defineProperty(this, key, {\n configurable: true,\n get: () => method,\n set: v => (method = v),\n })\n }\n\n // Turn getters into MobX computed properties\n else if (descriptor.get) {\n const getter = descriptor.get\n const computed = epos.libs.mobx.computed(() => getter.call(this))\n Reflect.defineProperty(this, key, {\n configurable: true,\n get: () => computed.get(),\n set: descriptor.set,\n })\n }\n }\n }\n\n // Queue attach hook.\n // Do not execute `attach` hooks immediately, but rather queue them on the highest unattached ancestor.\n // This way `attach` hooks are called after all versioners have been applied in the entire subtree.\n const attach = Reflect.get(this, 'attach')\n if (is.function(attach)) {\n const unattachedRoot = findUnattachedRoot(this)\n if (!unattachedRoot) throw this.never()\n ensure(unattachedRoot, _pendingAttachHooks_, () => [])\n unattachedRoot[_pendingAttachHooks_].push(() => attach())\n }\n\n // Release attach hooks\n if (this[_pendingAttachHooks_]) {\n this[_pendingAttachHooks_].forEach(attach => attach())\n delete this[_pendingAttachHooks_]\n }\n\n // Mark as attached\n Reflect.defineProperty(this, _attached_, { configurable: true, get: () => true })\n }\n\n /**\n * Lifecycle method called when the unit is detached from the state tree.\n */\n [epos.state.DETACH]() {\n // Run and clear disposers\n if (this[_disposers_]) {\n this[_disposers_].forEach(disposer => disposer())\n this[_disposers_].clear()\n }\n\n // Clear ancestors cache\n if (this[_ancestors_]) {\n this[_ancestors_].clear()\n }\n\n // Call detach method\n const detach = Reflect.get(this, 'detach')\n if (is.function(detach)) detach()\n }\n\n // ---------------------------------------------------------------------------\n // ROOT GETTER\n // ---------------------------------------------------------------------------\n\n /**\n * Gets the root unit of the current unit's tree.\n * The result is cached for subsequent calls.\n */\n get $() {\n ensure(this, _root_, () => findRoot(this))\n return this[_root_]\n }\n\n // ---------------------------------------------------------------------------\n // METHODS\n // ---------------------------------------------------------------------------\n\n /**\n * A wrapper around MobX's `autorun` that automatically disposes\n * the reaction when the unit is detached.\n */\n autorun(...args: Parameters<typeof epos.libs.mobx.autorun>) {\n const disposer = epos.libs.mobx.autorun(...args)\n ensure(this, _disposers_, () => new Set())\n this[_disposers_].add(disposer)\n return disposer\n }\n\n /**\n * A wrapper around MobX's `reaction` that automatically disposes\n * the reaction when the unit is detached.\n */\n reaction(...args: Parameters<typeof epos.libs.mobx.reaction>) {\n const disposer = epos.libs.mobx.reaction(...args)\n ensure(this, _disposers_, () => new Set())\n this[_disposers_].add(disposer)\n return disposer\n }\n\n /**\n * A wrapper around `setTimeout` that automatically clears the timeout\n * when the unit is detached.\n */\n setTimeout(...args: Parameters<typeof self.setTimeout>) {\n const id = self.setTimeout(...args)\n ensure(this, _disposers_, () => new Set())\n this[_disposers_].add(() => self.clearTimeout(id))\n return id\n }\n\n /**\n * A wrapper around `setInterval` that automatically clears the interval\n * when the unit is detached.\n */\n setInterval(...args: Parameters<typeof self.setInterval>) {\n const id = self.setInterval(...args)\n ensure(this, _disposers_, () => new Set())\n this[_disposers_].add(() => self.clearInterval(id))\n return id\n }\n\n /**\n * Creates an error for an unreachable code path.\n */\n never(message = 'This should never happen') {\n const details = message ? `: ${message}` : ''\n const error = new Error(`[${this.constructor.name}] This should never happen${details}`)\n Error.captureStackTrace(error, this.never)\n return error\n }\n\n /**\n * Finds the closest ancestor unit of a given type.\n * The result is cached for subsequent calls.\n */\n closest<T extends Unit>(Ancestor: Cls<T>) {\n // Has cached value? -> Return it\n ensure(this, _ancestors_, () => new Map())\n if (this[_ancestors_].has(Ancestor)) return this[_ancestors_].get(Ancestor) as T\n\n // Find the closest ancestor and cache it\n let cursor: Node<TRoot> | null = this\n while (cursor) {\n if (cursor instanceof Ancestor) {\n this[_ancestors_].set(Ancestor, cursor)\n return cursor\n }\n cursor = getParent(cursor)\n }\n\n return null\n }\n}\n\n// ---------------------------------------------------------------------------\n// HELPERS\n// ---------------------------------------------------------------------------\n\n/**\n * Ensures a property exists on an object, initializing it if it doesn't.\n */\nfunction ensure<T extends object, K extends PropertyKey, V>(\n object: T,\n key: K,\n getInitialValue: () => V,\n): asserts object is T & { [key in K]: V } {\n if (key in object) return\n const value = getInitialValue()\n Reflect.defineProperty(object, key, { configurable: true, get: () => value })\n}\n\n/**\n * Gets all prototypes of an object up to `Object.prototype`.\n */\nfunction getPrototypes(object: object): object[] {\n const prototype = Reflect.getPrototypeOf(object)\n if (!prototype || prototype === Object.prototype) return []\n return [prototype, ...getPrototypes(prototype)]\n}\n\n/**\n * Finds the root `Unit` in the hierarchy for a given unit.\n */\nfunction findRoot<T>(unit: Unit<T>) {\n let root: Unit<T> | null = null\n let cursor: Node<T> | null = unit\n\n while (cursor) {\n if (cursor instanceof Unit) root = cursor\n cursor = getParent(cursor)\n }\n\n return root as T\n}\n\n/**\n * Finds the highest unattached `Unit` in the hierarchy for a given unit.\n */\nfunction findUnattachedRoot<T>(unit: Unit<T>) {\n let unattachedRoot: Unit<T> | null = null\n let cursor: Node<T> | null = unit\n\n while (cursor) {\n if (cursor instanceof Unit && !cursor[_attached_]) unattachedRoot = cursor\n cursor = getParent(cursor)\n }\n\n return unattachedRoot\n}\n\n/**\n * Gets the parent of a node, which can be a `Unit`, an object, or an array.\n */\nfunction getParent<T>(node: Node<T>) {\n const parent: Node<T> | null = Reflect.get(node, _parent_) ?? Reflect.get(node, epos.state.PARENT) ?? null\n return parent\n}\n\n/**\n * Gets the versioner object from a unit's constructor.\n */\nfunction getVersioner<T>(unit: Unit<T>) {\n const versioner: unknown = Reflect.get(unit.constructor, 'versioner')\n if (!is.object(versioner)) return {}\n return versioner\n}\n\n/**\n * Gets a sorted list of numeric version keys from a unit's versioner.\n */\nfunction getVersions(versioner: Obj) {\n const numericKeys = Object.keys(versioner).filter(key => is.numeric(key))\n return numericKeys.map(Number).sort((v1, v2) => v1 - v2)\n}\n"],"mappings":";AACA,SAAS,WAAW,UAAU;AAC9B,OAAO;AACP,SAAS,sBAAsB;AAExB,IAAM,SAAS,uBAAO,MAAM;AAC5B,IAAM,WAAW,uBAAO,QAAQ;AAChC,IAAM,aAAa,uBAAO,UAAU;AACpC,IAAM,cAAc,uBAAO,WAAW;AACtC,IAAM,cAAc,uBAAO,WAAW;AACtC,IAAM,uBAAuB,uBAAO,oBAAoB;AAC/D,IAAM,SAAS,eAAe,kEAAkE,CAAC;AAI1F,IAAM,OAAN,MAA4B;AAAA,EAYjC,YAAY,QAA4B;AACtC,SAAK,KAAK,OAAO;AACjB,SAAK,QAAQ,IAAI;AACjB,UAAM,YAAY,aAAa,IAAI;AACnC,UAAM,WAAW,YAAY,SAAS;AACtC,QAAI,SAAS,SAAS,EAAG,MAAK,UAAU,IAAI,SAAS,GAAG,EAAE;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,CAAC,KAAK,MAAM,MAAM,IAAI;AAEpB,SAAK,MAAM,YAAY,MAAM;AAC3B,YAAM,YAAY,aAAa,IAAI;AACnC,YAAM,WAAW,YAAY,SAAS;AACtC,iBAAW,WAAW,UAAU;AAC9B,YAAI,GAAG,OAAO,KAAK,UAAU,CAAC,KAAK,KAAK,UAAU,KAAK,QAAS;AAChE,cAAM,YAAY,UAAU,OAAO;AACnC,YAAI,CAAC,GAAG,SAAS,SAAS,EAAG;AAC7B,kBAAU,KAAK,MAAM,IAAI;AACzB,aAAK,UAAU,IAAI;AAAA,MACrB;AAAA,IACF,CAAC;AAGD,QAAI,MAAM,UAAU,KAAK,GAAG,CAAC;AAC7B,YAAQ,eAAe,MAAM,OAAO;AAAA,MAClC,cAAc;AAAA,MACd,KAAK,MAAM;AAAA,MACX,KAAK,OAAM,MAAM;AAAA,IACnB,CAAC;AAGD,UAAM,kBAAkB,QAAQ,yBAAyB,KAAK,YAAY,WAAW,OAAO;AAC5F,QAAI,mBAAmB,gBAAgB,KAAK;AAC1C,YAAM,QAAQ,gBAAgB,IAAI,KAAK,IAAI;AAC3C,YAAM,QAAQ,KAAK,MAAM,MAAM,OAAO,EAAE,MAAM,MAAM,CAAC;AACrD,cAAQ,eAAe,MAAM,SAAS,EAAE,KAAK,MAAM,MAAM,CAAC;AAAA,IAC5D;AAMA,eAAW,aAAa,cAAc,IAAI,GAAG;AAC3C,YAAM,cAAc,OAAO,0BAA0B,SAAS;AAC9D,iBAAW,CAAC,KAAK,UAAU,KAAK,OAAO,QAAQ,WAAW,GAAG;AAE3D,YAAI,QAAQ,cAAe;AAC3B,YAAI,KAAK,eAAe,GAAG,EAAG;AAG9B,YAAI,GAAG,SAAS,WAAW,KAAK,KAAK,IAAI,SAAS,MAAM,GAAG;AACzD,cAAI,YAAY,KAAK,UAAU,WAAW,MAAM,KAAK,IAAI,CAAC;AAC1D,oBAAU,cAAc,GAAG,KAAK,YAAY,IAAI,IAAI,GAAG;AACvD,kBAAQ,eAAe,MAAM,KAAK;AAAA,YAChC,cAAc;AAAA,YACd,KAAK,MAAM;AAAA,YACX,KAAK,OAAM,YAAY;AAAA,UACzB,CAAC;AAAA,QACH,WAGS,GAAG,SAAS,WAAW,KAAK,GAAG;AACtC,cAAI,SAAS,WAAW,MAAM,KAAK,IAAI;AACvC,kBAAQ,eAAe,MAAM,KAAK;AAAA,YAChC,cAAc;AAAA,YACd,KAAK,MAAM;AAAA,YACX,KAAK,OAAM,SAAS;AAAA,UACtB,CAAC;AAAA,QACH,WAGS,WAAW,KAAK;AACvB,gBAAM,SAAS,WAAW;AAC1B,gBAAM,WAAW,KAAK,KAAK,KAAK,SAAS,MAAM,OAAO,KAAK,IAAI,CAAC;AAChE,kBAAQ,eAAe,MAAM,KAAK;AAAA,YAChC,cAAc;AAAA,YACd,KAAK,MAAM,SAAS,IAAI;AAAA,YACxB,KAAK,WAAW;AAAA,UAClB,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAKA,UAAM,SAAS,QAAQ,IAAI,MAAM,QAAQ;AACzC,QAAI,GAAG,SAAS,MAAM,GAAG;AACvB,YAAM,iBAAiB,mBAAmB,IAAI;AAC9C,UAAI,CAAC,eAAgB,OAAM,KAAK,MAAM;AACtC,aAAO,gBAAgB,sBAAsB,MAAM,CAAC,CAAC;AACrD,qBAAe,oBAAoB,EAAE,KAAK,MAAM,OAAO,CAAC;AAAA,IAC1D;AAGA,QAAI,KAAK,oBAAoB,GAAG;AAC9B,WAAK,oBAAoB,EAAE,QAAQ,CAAAA,YAAUA,QAAO,CAAC;AACrD,aAAO,KAAK,oBAAoB;AAAA,IAClC;AAGA,YAAQ,eAAe,MAAM,YAAY,EAAE,cAAc,MAAM,KAAK,MAAM,KAAK,CAAC;AAAA,EAClF;AAAA;AAAA;AAAA;AAAA,EAKA,CAAC,KAAK,MAAM,MAAM,IAAI;AAEpB,QAAI,KAAK,WAAW,GAAG;AACrB,WAAK,WAAW,EAAE,QAAQ,cAAY,SAAS,CAAC;AAChD,WAAK,WAAW,EAAE,MAAM;AAAA,IAC1B;AAGA,QAAI,KAAK,WAAW,GAAG;AACrB,WAAK,WAAW,EAAE,MAAM;AAAA,IAC1B;AAGA,UAAM,SAAS,QAAQ,IAAI,MAAM,QAAQ;AACzC,QAAI,GAAG,SAAS,MAAM,EAAG,QAAO;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,IAAI,IAAI;AACN,WAAO,MAAM,QAAQ,MAAM,SAAS,IAAI,CAAC;AACzC,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,WAAW,MAAiD;AAC1D,UAAM,WAAW,KAAK,KAAK,KAAK,QAAQ,GAAG,IAAI;AAC/C,WAAO,MAAM,aAAa,MAAM,oBAAI,IAAI,CAAC;AACzC,SAAK,WAAW,EAAE,IAAI,QAAQ;AAC9B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,MAAkD;AAC5D,UAAM,WAAW,KAAK,KAAK,KAAK,SAAS,GAAG,IAAI;AAChD,WAAO,MAAM,aAAa,MAAM,oBAAI,IAAI,CAAC;AACzC,SAAK,WAAW,EAAE,IAAI,QAAQ;AAC9B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAc,MAA0C;AACtD,UAAM,KAAK,KAAK,WAAW,GAAG,IAAI;AAClC,WAAO,MAAM,aAAa,MAAM,oBAAI,IAAI,CAAC;AACzC,SAAK,WAAW,EAAE,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;AACjD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,eAAe,MAA2C;AACxD,UAAM,KAAK,KAAK,YAAY,GAAG,IAAI;AACnC,WAAO,MAAM,aAAa,MAAM,oBAAI,IAAI,CAAC;AACzC,SAAK,WAAW,EAAE,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;AAClD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU,4BAA4B;AAC1C,UAAM,UAAU,UAAU,KAAK,OAAO,KAAK;AAC3C,UAAM,QAAQ,IAAI,MAAM,IAAI,KAAK,YAAY,IAAI,6BAA6B,OAAO,EAAE;AACvF,UAAM,kBAAkB,OAAO,KAAK,KAAK;AACzC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAwB,UAAkB;AAExC,WAAO,MAAM,aAAa,MAAM,oBAAI,IAAI,CAAC;AACzC,QAAI,KAAK,WAAW,EAAE,IAAI,QAAQ,EAAG,QAAO,KAAK,WAAW,EAAE,IAAI,QAAQ;AAG1E,QAAI,SAA6B;AACjC,WAAO,QAAQ;AACb,UAAI,kBAAkB,UAAU;AAC9B,aAAK,WAAW,EAAE,IAAI,UAAU,MAAM;AACtC,eAAO;AAAA,MACT;AACA,eAAS,UAAU,MAAM;AAAA,IAC3B;AAEA,WAAO;AAAA,EACT;AACF;AASA,SAAS,OACP,QACA,KACA,iBACyC;AACzC,MAAI,OAAO,OAAQ;AACnB,QAAM,QAAQ,gBAAgB;AAC9B,UAAQ,eAAe,QAAQ,KAAK,EAAE,cAAc,MAAM,KAAK,MAAM,MAAM,CAAC;AAC9E;AAKA,SAAS,cAAc,QAA0B;AAC/C,QAAM,YAAY,QAAQ,eAAe,MAAM;AAC/C,MAAI,CAAC,aAAa,cAAc,OAAO,UAAW,QAAO,CAAC;AAC1D,SAAO,CAAC,WAAW,GAAG,cAAc,SAAS,CAAC;AAChD;AAKA,SAAS,SAAY,MAAe;AAClC,MAAI,OAAuB;AAC3B,MAAI,SAAyB;AAE7B,SAAO,QAAQ;AACb,QAAI,kBAAkB,KAAM,QAAO;AACnC,aAAS,UAAU,MAAM;AAAA,EAC3B;AAEA,SAAO;AACT;AAKA,SAAS,mBAAsB,MAAe;AAC5C,MAAI,iBAAiC;AACrC,MAAI,SAAyB;AAE7B,SAAO,QAAQ;AACb,QAAI,kBAAkB,QAAQ,CAAC,OAAO,UAAU,EAAG,kBAAiB;AACpE,aAAS,UAAU,MAAM;AAAA,EAC3B;AAEA,SAAO;AACT;AAKA,SAAS,UAAa,MAAe;AACnC,QAAM,SAAyB,QAAQ,IAAI,MAAM,QAAQ,KAAK,QAAQ,IAAI,MAAM,KAAK,MAAM,MAAM,KAAK;AACtG,SAAO;AACT;AAKA,SAAS,aAAgB,MAAe;AACtC,QAAM,YAAqB,QAAQ,IAAI,KAAK,aAAa,WAAW;AACpE,MAAI,CAAC,GAAG,OAAO,SAAS,EAAG,QAAO,CAAC;AACnC,SAAO;AACT;AAKA,SAAS,YAAY,WAAgB;AACnC,QAAM,cAAc,OAAO,KAAK,SAAS,EAAE,OAAO,SAAO,GAAG,QAAQ,GAAG,CAAC;AACxE,SAAO,YAAY,IAAI,MAAM,EAAE,KAAK,CAAC,IAAI,OAAO,KAAK,EAAE;AACzD;","names":["attach"]}
1
+ {"version":3,"file":"epos-unit.js","sourceRoot":"","sources":["../src/epos-unit.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "epos-unit",
3
- "version": "1.17.0",
3
+ "version": "1.18.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "author": "imkost",
7
7
  "description": "",
8
8
  "keywords": [],
9
9
  "scripts": {
10
- "dev": "tsup --config ../../tsup.config.ts --watch",
11
- "build": "tsup --config ../../tsup.config.ts",
12
- "lint": "tsc --noEmit",
10
+ "dev": "rimraf dist && tsgo --watch",
11
+ "build": "rimraf dist && tsgo",
12
+ "lint": "tsgo --noEmit",
13
13
  "release": "sh -c 'npm version ${1:-minor} && npm run build && npm publish' --"
14
14
  },
15
15
  "exports": {
@@ -20,8 +20,8 @@
20
20
  "src"
21
21
  ],
22
22
  "dependencies": {
23
- "dropcap": "^1.4.0",
24
- "epos": "^1.32.0",
25
- "nanoid": "^3.3.11"
23
+ "dropcap": "^1.5.0",
24
+ "epos": "^1.35.0",
25
+ "nanoid": "^5.1.6"
26
26
  }
27
27
  }
package/src/epos-unit.ts CHANGED
@@ -2,16 +2,24 @@ import type { Arr, Cls, Obj } from 'dropcap/types'
2
2
  import { createLog, is } from 'dropcap/utils'
3
3
  import 'epos'
4
4
  import { customAlphabet } from 'nanoid'
5
+ import type { FC } from 'react'
6
+
7
+ declare global {
8
+ interface ErrorConstructor {
9
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void
10
+ }
11
+ }
5
12
 
6
13
  export const _root_ = Symbol('root')
7
14
  export const _parent_ = Symbol('parent')
8
15
  export const _attached_ = Symbol('attached')
9
16
  export const _disposers_ = Symbol('disposers')
10
17
  export const _ancestors_ = Symbol('ancestors')
11
- export const _pendingAttachHooks_ = Symbol('pendingAttachHooks')
12
- const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 8)
18
+ export const _attachQueue_ = Symbol('pendingAttachHooks')
19
+ const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz0123456789', 10)
13
20
 
14
21
  export type Node<T> = Unit<T> | Obj | Arr
22
+ export type Versioner<T> = { [version: number]: (this: T) => void }
15
23
 
16
24
  export class Unit<TRoot = unknown> {
17
25
  declare '@': string
@@ -23,52 +31,68 @@ export class Unit<TRoot = unknown> {
23
31
  declare [_attached_]?: boolean;
24
32
  declare [_disposers_]?: Set<() => void>;
25
33
  declare [_ancestors_]?: Map<Cls, unknown>;
26
- declare [_pendingAttachHooks_]?: (() => void)[]
34
+ declare [_attachQueue_]?: (() => void)[]
35
+
36
+ static defineVersioner<T extends Unit>(this: Cls<T>, versioner: Versioner<T>) {
37
+ return versioner
38
+ }
27
39
 
28
40
  constructor(parent: Unit<TRoot> | null) {
29
41
  this.id = nanoid()
30
42
  this[_parent_] = parent
31
- const versioner = getVersioner(this)
32
- const versions = getVersions(versioner)
33
- if (versions.length > 0) this[':version'] = versions.at(-1)!
34
43
  }
35
44
 
36
45
  // ---------------------------------------------------------------------------
37
- // ATTACH / DETACH
46
+ // ATTACH
38
47
  // ---------------------------------------------------------------------------
39
48
 
40
49
  /**
41
50
  * Lifecycle method called when the unit is attached to the state tree.
42
51
  */
43
52
  [epos.state.ATTACH]() {
44
- // Apply versioner
45
- epos.state.transaction(() => {
46
- const versioner = getVersioner(this)
47
- const versions = getVersions(versioner)
48
- for (const version of versions) {
49
- if (is.number(this[':version']) && this[':version'] >= version) continue
50
- const versionFn = versioner[version]
51
- if (!is.function(versionFn)) continue
52
- versionFn.call(this, this)
53
- this[':version'] = version
54
- }
55
- })
56
-
57
53
  // Setup logger
58
54
  let log = createLog(this['@'])
59
- Reflect.defineProperty(this, 'log', {
60
- configurable: true,
61
- get: () => log,
62
- set: v => (log = v),
63
- })
55
+ Reflect.defineProperty(this, 'log', { configurable: true, get: () => log, set: v => (log = v) })
56
+
57
+ // Apply versioner
58
+ void (() => {
59
+ const versioner: unknown = Reflect.get(this.constructor, 'versioner')
60
+ if (!is.object(versioner)) return
61
+
62
+ const asc = (v1: number, v2: number) => v1 - v2
63
+ const versions = Object.keys(versioner).filter(is.numeric).map(Number).sort(asc)
64
+ if (versions.length === 0) return
65
+
66
+ epos.state.transaction(() => {
67
+ for (const version of versions) {
68
+ if (is.number(this[':version']) && this[':version'] >= version) continue
69
+ const versionFn = versioner[version]
70
+ if (!is.function(versionFn)) continue
71
+ versionFn.call(this)
72
+ this[':version'] = version
73
+ }
74
+ })
75
+ })()
64
76
 
65
77
  // Setup state
66
- const stateDescriptor = Reflect.getOwnPropertyDescriptor(this.constructor.prototype, 'state')
67
- if (stateDescriptor && stateDescriptor.get) {
68
- const value = stateDescriptor.get.call(this)
69
- const state = epos.state.local(value, { deep: false })
70
- Reflect.defineProperty(this, 'state', { get: () => state })
71
- }
78
+ void (() => {
79
+ const descriptor = Reflect.getOwnPropertyDescriptor(this.constructor.prototype, 'state')
80
+ if (!descriptor || !descriptor.get) return
81
+ const value: unknown = descriptor.get.call(this)
82
+ if (!is.object(value)) throw new Error(`'state' getter return an object`)
83
+ const state = epos.state.create(value)
84
+ Reflect.defineProperty(state, epos.state.PARENT, { configurable: true, value: this })
85
+ Reflect.defineProperty(this, 'state', { enumerable: true, get: () => state })
86
+ })()
87
+
88
+ // Setup inert
89
+ void (() => {
90
+ const descriptor = Reflect.getOwnPropertyDescriptor(this.constructor.prototype, 'inert')
91
+ if (!descriptor || !descriptor.get) return
92
+ const value: unknown = descriptor.get.call(this)
93
+ if (!is.object(value)) throw new Error(`'inert' getter return an object`)
94
+ Reflect.defineProperty(this, 'inert', { enumerable: true, get: () => value })
95
+ })()
72
96
 
73
97
  // Prepare properties for the whole prototype chain:
74
98
  // - Create components for methods ending with `View`
@@ -83,13 +107,8 @@ export class Unit<TRoot = unknown> {
83
107
 
84
108
  // Create components for methods ending with `View`
85
109
  if (is.function(descriptor.value) && key.endsWith('View')) {
86
- let Component = epos.component(descriptor.value.bind(this))
87
- Component.displayName = `${this.constructor.name}.${key}`
88
- Reflect.defineProperty(this, key, {
89
- configurable: true,
90
- get: () => Component,
91
- set: v => (Component = v),
92
- })
110
+ let View = createView(this, key, descriptor.value.bind(this) as FC<unknown>)
111
+ Reflect.defineProperty(this, key, { configurable: true, get: () => View, set: v => (View = v) })
93
112
  }
94
113
 
95
114
  // Bind all other methods to the unit instance
@@ -115,27 +134,31 @@ export class Unit<TRoot = unknown> {
115
134
  }
116
135
  }
117
136
 
118
- // Queue attach hook.
119
- // Do not execute `attach` hooks immediately, but rather queue them on the highest unattached ancestor.
120
- // This way `attach` hooks are called after all versioners have been applied in the entire subtree.
137
+ // Queue attach method.
138
+ // Do not execute `attach` methods immediately, but rather queue them on the highest unattached ancestor.
139
+ // This way `attach` methods are called after all versioners have been applied in the entire subtree.
121
140
  const attach = Reflect.get(this, 'attach')
122
141
  if (is.function(attach)) {
123
- const unattachedRoot = findUnattachedRoot(this)
124
- if (!unattachedRoot) throw this.never()
125
- ensure(unattachedRoot, _pendingAttachHooks_, () => [])
126
- unattachedRoot[_pendingAttachHooks_].push(() => attach())
142
+ const head = findUnattachedRoot(this)
143
+ if (!head) throw this.never()
144
+ ensure(head, _attachQueue_, () => [])
145
+ head[_attachQueue_].push(() => attach.call(this))
127
146
  }
128
147
 
129
- // Release attach hooks
130
- if (this[_pendingAttachHooks_]) {
131
- this[_pendingAttachHooks_].forEach(attach => attach())
132
- delete this[_pendingAttachHooks_]
148
+ // Release attach queue
149
+ if (this[_attachQueue_]) {
150
+ this[_attachQueue_].forEach(attach => attach())
151
+ delete this[_attachQueue_]
133
152
  }
134
153
 
135
154
  // Mark as attached
136
155
  Reflect.defineProperty(this, _attached_, { configurable: true, get: () => true })
137
156
  }
138
157
 
158
+ // ---------------------------------------------------------------------------
159
+ // DETACH
160
+ // ---------------------------------------------------------------------------
161
+
139
162
  /**
140
163
  * Lifecycle method called when the unit is detached from the state tree.
141
164
  */
@@ -161,7 +184,7 @@ export class Unit<TRoot = unknown> {
161
184
  // ---------------------------------------------------------------------------
162
185
 
163
186
  /**
164
- * Gets the root unit of the current unit's tree.
187
+ * Get the root unit of the current unit's tree.
165
188
  * The result is cached for subsequent calls.
166
189
  */
167
190
  get $() {
@@ -174,8 +197,7 @@ export class Unit<TRoot = unknown> {
174
197
  // ---------------------------------------------------------------------------
175
198
 
176
199
  /**
177
- * A wrapper around MobX's `autorun` that automatically disposes
178
- * the reaction when the unit is detached.
200
+ * A wrapper around MobX's `autorun` that automatically disposes the reaction when the unit is detached.
179
201
  */
180
202
  autorun(...args: Parameters<typeof epos.libs.mobx.autorun>) {
181
203
  const disposer = epos.libs.mobx.autorun(...args)
@@ -185,8 +207,7 @@ export class Unit<TRoot = unknown> {
185
207
  }
186
208
 
187
209
  /**
188
- * A wrapper around MobX's `reaction` that automatically disposes
189
- * the reaction when the unit is detached.
210
+ * A wrapper around MobX's `reaction` that automatically disposes the reaction when the unit is detached.
190
211
  */
191
212
  reaction(...args: Parameters<typeof epos.libs.mobx.reaction>) {
192
213
  const disposer = epos.libs.mobx.reaction(...args)
@@ -196,39 +217,37 @@ export class Unit<TRoot = unknown> {
196
217
  }
197
218
 
198
219
  /**
199
- * A wrapper around `setTimeout` that automatically clears the timeout
200
- * when the unit is detached.
220
+ * A wrapper around `setTimeout` that automatically clears the timeout when the unit is detached.
201
221
  */
202
- setTimeout(...args: Parameters<typeof self.setTimeout>) {
203
- const id = self.setTimeout(...args)
222
+ setTimeout(...args: Parameters<typeof setTimeout>) {
223
+ const id = setTimeout(...args)
204
224
  ensure(this, _disposers_, () => new Set())
205
- this[_disposers_].add(() => self.clearTimeout(id))
225
+ this[_disposers_].add(() => clearTimeout(id))
206
226
  return id
207
227
  }
208
228
 
209
229
  /**
210
- * A wrapper around `setInterval` that automatically clears the interval
211
- * when the unit is detached.
230
+ * A wrapper around `setInterval` that automatically clears the interval when the unit is detached.
212
231
  */
213
- setInterval(...args: Parameters<typeof self.setInterval>) {
214
- const id = self.setInterval(...args)
232
+ setInterval(...args: Parameters<typeof setInterval>) {
233
+ const id = setInterval(...args)
215
234
  ensure(this, _disposers_, () => new Set())
216
- this[_disposers_].add(() => self.clearInterval(id))
235
+ this[_disposers_].add(() => clearInterval(id))
217
236
  return id
218
237
  }
219
238
 
220
239
  /**
221
- * Creates an error for an unreachable code path.
240
+ * Create an error for code paths that are logically unreachable.
222
241
  */
223
242
  never(message = 'This should never happen') {
224
243
  const details = message ? `: ${message}` : ''
225
- const error = new Error(`[${this.constructor.name}] This should never happen${details}`)
244
+ const error = new Error(`[${this['@']}] This should never happen${details}`)
226
245
  Error.captureStackTrace(error, this.never)
227
246
  return error
228
247
  }
229
248
 
230
249
  /**
231
- * Finds the closest ancestor unit of a given type.
250
+ * Find the closest ancestor unit of a given type.
232
251
  * The result is cached for subsequent calls.
233
252
  */
234
253
  closest<T extends Unit>(Ancestor: Cls<T>) {
@@ -255,7 +274,7 @@ export class Unit<TRoot = unknown> {
255
274
  // ---------------------------------------------------------------------------
256
275
 
257
276
  /**
258
- * Ensures a property exists on an object, initializing it if it doesn't.
277
+ * Ensure a property exists on an object, initialize it if it doesn't.
259
278
  */
260
279
  function ensure<T extends object, K extends PropertyKey, V>(
261
280
  object: T,
@@ -268,7 +287,7 @@ function ensure<T extends object, K extends PropertyKey, V>(
268
287
  }
269
288
 
270
289
  /**
271
- * Gets all prototypes of an object up to `Object.prototype`.
290
+ * Get all prototypes of an object up to `Object.prototype`.
272
291
  */
273
292
  function getPrototypes(object: object): object[] {
274
293
  const prototype = Reflect.getPrototypeOf(object)
@@ -277,7 +296,7 @@ function getPrototypes(object: object): object[] {
277
296
  }
278
297
 
279
298
  /**
280
- * Finds the root `Unit` in the hierarchy for a given unit.
299
+ * Find the root `Unit` in the hierarchy for a given unit.
281
300
  */
282
301
  function findRoot<T>(unit: Unit<T>) {
283
302
  let root: Unit<T> | null = null
@@ -292,7 +311,7 @@ function findRoot<T>(unit: Unit<T>) {
292
311
  }
293
312
 
294
313
  /**
295
- * Finds the highest unattached `Unit` in the hierarchy for a given unit.
314
+ * Find the highest unattached `Unit` in the hierarchy for a given unit.
296
315
  */
297
316
  function findUnattachedRoot<T>(unit: Unit<T>) {
298
317
  let unattachedRoot: Unit<T> | null = null
@@ -307,7 +326,7 @@ function findUnattachedRoot<T>(unit: Unit<T>) {
307
326
  }
308
327
 
309
328
  /**
310
- * Gets the parent of a node, which can be a `Unit`, an object, or an array.
329
+ * Get the parent of a node, which can be a `Unit`, an object, or an array.
311
330
  */
312
331
  function getParent<T>(node: Node<T>) {
313
332
  const parent: Node<T> | null = Reflect.get(node, _parent_) ?? Reflect.get(node, epos.state.PARENT) ?? null
@@ -315,18 +334,33 @@ function getParent<T>(node: Node<T>) {
315
334
  }
316
335
 
317
336
  /**
318
- * Gets the versioner object from a unit's constructor.
337
+ * Create view component for the unit.
319
338
  */
320
- function getVersioner<T>(unit: Unit<T>) {
321
- const versioner: unknown = Reflect.get(unit.constructor, 'versioner')
322
- if (!is.object(versioner)) return {}
323
- return versioner
324
- }
339
+ function createView<T>(unit: Unit<T>, name: string, render: FC<unknown>) {
340
+ const fullName = `${unit['@']}.${name}`
341
+
342
+ const View = epos.component((props: unknown) => {
343
+ try {
344
+ return render(props)
345
+ } catch (error) {
346
+ unit.log.error(error)
347
+ const message = is.error(error) ? error.message : String(error)
348
+ return epos.libs.reactJsxRuntime.jsx('div', {
349
+ children: `[${fullName}] ${message}`,
350
+ style: {
351
+ width: 'fit-content',
352
+ padding: '4px 6px 4px 4px',
353
+ color: '#f00',
354
+ border: '1px solid #f00',
355
+ background: 'rgba(255, 0, 0, 0.1)',
356
+ fontSize: 12,
357
+ fontWeight: 400,
358
+ },
359
+ })
360
+ }
361
+ })
325
362
 
326
- /**
327
- * Gets a sorted list of numeric version keys from a unit's versioner.
328
- */
329
- function getVersions(versioner: Obj) {
330
- const numericKeys = Object.keys(versioner).filter(key => is.numeric(key))
331
- return numericKeys.map(Number).sort((v1, v2) => v1 - v2)
363
+ View.displayName = fullName
364
+
365
+ return View
332
366
  }