@expressive/mvc 0.73.0 → 0.78.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.
Files changed (53) hide show
  1. package/README.md +137 -0
  2. package/dist/component.d.ts +87 -0
  3. package/dist/component.js +111 -0
  4. package/dist/component.js.map +1 -0
  5. package/dist/context.d.ts +56 -0
  6. package/dist/context.js +201 -0
  7. package/dist/context.js.map +1 -0
  8. package/dist/field/def.d.ts +17 -0
  9. package/dist/field/def.js +29 -0
  10. package/dist/field/def.js.map +1 -0
  11. package/dist/field/get.d.ts +57 -0
  12. package/dist/field/get.js +90 -0
  13. package/dist/field/get.js.map +1 -0
  14. package/dist/field/hot.d.ts +16 -0
  15. package/dist/field/hot.js +98 -0
  16. package/dist/field/hot.js.map +1 -0
  17. package/dist/field/ref.d.ts +78 -0
  18. package/dist/field/ref.js +85 -0
  19. package/dist/field/ref.js.map +1 -0
  20. package/dist/field/set.d.ts +59 -0
  21. package/dist/field/set.js +84 -0
  22. package/dist/field/set.js.map +1 -0
  23. package/dist/index.d.ts +10 -502
  24. package/dist/index.js +11 -872
  25. package/dist/jsx-dev-runtime.d.ts +2 -0
  26. package/dist/jsx-dev-runtime.js +3 -0
  27. package/dist/jsx-runtime.d.ts +90 -0
  28. package/dist/jsx-runtime.js +57 -0
  29. package/dist/jsx-runtime.js.map +1 -0
  30. package/dist/observable.d.ts +58 -0
  31. package/dist/observable.js +184 -0
  32. package/dist/observable.js.map +1 -0
  33. package/dist/state.d.ts +311 -0
  34. package/dist/state.js +424 -0
  35. package/dist/state.js.map +1 -0
  36. package/package.json +35 -18
  37. package/dist/esm/context.d.ts +0 -62
  38. package/dist/esm/context.js +0 -158
  39. package/dist/esm/index.d.ts +0 -8
  40. package/dist/esm/index.js +0 -9
  41. package/dist/esm/instruction/get.d.ts +0 -36
  42. package/dist/esm/instruction/get.js +0 -77
  43. package/dist/esm/instruction/ref.d.ts +0 -71
  44. package/dist/esm/instruction/ref.js +0 -68
  45. package/dist/esm/instruction/set.d.ts +0 -69
  46. package/dist/esm/instruction/set.js +0 -118
  47. package/dist/esm/instruction/use.d.ts +0 -23
  48. package/dist/esm/instruction/use.js +0 -56
  49. package/dist/esm/observable.d.ts +0 -42
  50. package/dist/esm/observable.js +0 -121
  51. package/dist/esm/state.d.ts +0 -234
  52. package/dist/esm/state.js +0 -293
  53. package/dist/index.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,872 +1,11 @@
1
- Object.defineProperty(exports, '__esModule', { value: true });
2
-
3
- //#region src/observable.ts
4
- const Observable = Symbol("observe");
5
- /** Placeholder event determines if state is initialized or not. */
6
- const onReady = () => null;
7
- const LISTENERS = /* @__PURE__ */ new WeakMap();
8
- /** Events pending for a given object. */
9
- const PENDING = /* @__PURE__ */ new WeakMap();
10
- /** Update register. */
11
- const PENDING_KEYS = /* @__PURE__ */ new WeakMap();
12
- /** Central event dispatch. Bunches all updates to occur at same time. */
13
- const DISPATCH = /* @__PURE__ */ new Set();
14
- function addListener(subject, callback, select) {
15
- let listeners = LISTENERS.get(subject);
16
- if (!listeners) LISTENERS.set(subject, listeners = new Map([[onReady, void 0]]));
17
- if (select !== void 0 && !(select instanceof Set)) select = new Set([select]);
18
- if (!listeners.has(onReady) && !select) callback.call(subject, true, subject);
19
- listeners.set(callback, select);
20
- return () => listeners.delete(callback);
21
- }
22
- function emit(state, key) {
23
- const listeners = LISTENERS.get(state);
24
- const notReady = listeners.has(onReady);
25
- if (key === true && !notReady) return;
26
- let pending = PENDING.get(state);
27
- if (pending) {
28
- pending.add(key);
29
- return;
30
- }
31
- PENDING.set(state, pending = new Set(notReady ? [true, key] : [key]));
32
- for (const key of pending) for (const [callback, filter] of listeners) if (!filter || filter.has(key)) {
33
- const after = callback.call(state, key, state);
34
- if (after) enqueue(after);
35
- else if (after === null) listeners.delete(callback);
36
- }
37
- if (key === null) listeners.clear();
38
- PENDING.delete(state);
39
- }
40
- function event(subject, key, silent) {
41
- if (key === null) return emit(subject, key);
42
- if (!key) return emit(subject, true);
43
- let pending = PENDING_KEYS.get(subject);
44
- if (!pending) {
45
- PENDING_KEYS.set(subject, pending = /* @__PURE__ */ new Set());
46
- if (!silent) enqueue(() => {
47
- emit(subject, false);
48
- PENDING_KEYS.delete(subject);
49
- });
50
- }
51
- pending.add(key);
52
- if (!silent) emit(subject, key);
53
- }
54
- function enqueue(eventHandler) {
55
- if (!DISPATCH.size) setTimeout(() => {
56
- DISPATCH.forEach((event) => {
57
- try {
58
- event();
59
- } catch (err) {
60
- console.error(err);
61
- }
62
- });
63
- DISPATCH.clear();
64
- }, 0);
65
- DISPATCH.add(eventHandler);
66
- }
67
- function watch(target, callback, argument) {
68
- let unset;
69
- let reset;
70
- function invoke() {
71
- let ignore = true;
72
- function onUpdate() {
73
- if (ignore || reset === null) return;
74
- ignore = true;
75
- if (reset && unset) {
76
- unset(true);
77
- unset = void 0;
78
- }
79
- enqueue(invoke);
80
- return { then: enqueue };
81
- }
82
- try {
83
- const exit = argument === false ? void 0 : scope();
84
- const output = callback(target[Observable](onUpdate, argument === true));
85
- const flush = exit ? exit() : () => {};
86
- ignore = false;
87
- reset = output === null ? null : invoke;
88
- unset = (key) => {
89
- if (typeof output == "function") output(key);
90
- flush();
91
- };
92
- } catch (err) {
93
- if (err instanceof Promise) {
94
- reset = void 0;
95
- err.then(invoke);
96
- } else throw err;
97
- }
98
- }
99
- function cleanup() {
100
- if (unset) unset(false);
101
- reset = null;
102
- }
103
- if (EffectContext && argument !== false) EffectContext.add(cleanup);
104
- addListener(target, (key) => {
105
- if (key === true) invoke();
106
- else if (!reset) return reset;
107
- if (key === null && unset) unset(null);
108
- });
109
- return cleanup;
110
- }
111
- let EffectContext;
112
- function scope() {
113
- const last = EffectContext;
114
- const context = EffectContext = /* @__PURE__ */ new Set();
115
- return () => {
116
- EffectContext = last;
117
- return () => context.forEach((fn) => fn());
118
- };
119
- }
120
-
121
- //#endregion
122
- //#region src/state.ts
123
- const define = Object.defineProperty;
124
- /** Register for all active states via string identifiers (usually unique). */
125
- const ID = /* @__PURE__ */ new WeakMap();
126
- /** Internal state assigned to states. */
127
- const STATE = /* @__PURE__ */ new WeakMap();
128
- /** External listeners for any given State. */
129
- const NOTIFY = /* @__PURE__ */ new WeakMap();
130
- /** Parent-child relationships. */
131
- const PARENT = /* @__PURE__ */ new WeakMap();
132
- /** List of methods defined by a given type. */
133
- const METHODS = /* @__PURE__ */ new WeakMap();
134
- /** Reference bound instance methods to real ones. */
135
- const METHOD = /* @__PURE__ */ new WeakMap();
136
- /** Currently accumulating export. Stores real values of placeholder properties such as ref() or child states. */
137
- let EXPORT;
138
- var State = class {
139
- constructor(...args) {
140
- prepare(this);
141
- define(this, "is", { value: this });
142
- init$1(this, ...args, (x) => x.new && x.new());
143
- }
144
- [Observable](callback, required) {
145
- const watch = /* @__PURE__ */ new Set();
146
- const proxy = Object.create(this);
147
- addListener(this, (key) => {
148
- if (watch.has(key)) callback();
149
- });
150
- OBSERVER.set(proxy, (key, value) => {
151
- if (value === void 0 && required) throw new Error(`${this}.${key} is required in this context.`);
152
- watch.add(key);
153
- if (value instanceof Object && Observable in value) return value[Observable](callback, required) || value;
154
- return value;
155
- });
156
- return proxy;
157
- }
158
- get(arg1, arg2) {
159
- const self = this.is;
160
- if (arg1 === void 0) return values(self);
161
- if (typeof arg1 == "function") return effect(self, arg1);
162
- if (typeof arg2 == "function") return addListener(self, arg2, arg1);
163
- if (arg1 === null) return Object.isFrozen(STATE.get(self));
164
- return access(self, arg1, arg2);
165
- }
166
- set(arg1, arg2, arg3) {
167
- const self = this.is;
168
- if (typeof arg1 == "function") return addListener(self, (key) => {
169
- if (arg2 === key || arg2 === void 0 && typeof key == "string") return arg1.call(self, key, self);
170
- });
171
- if (arg1 && typeof arg1 == "object") assign(self, arg1, arg2 === true);
172
- else if (!arg2) event(self, arg1);
173
- else if (arg3) manage(self, arg1, arg2);
174
- else update(self, arg1, arg2);
175
- const pending = PENDING_KEYS.get(this);
176
- if (pending) return { then: (resolve) => new Promise((res) => {
177
- const remove = addListener(this, (key) => {
178
- if (key !== true) {
179
- remove();
180
- return () => res(Array.from(pending));
181
- }
182
- });
183
- }).then(resolve) };
184
- }
185
- /**
186
- * Iterate over managed properties in this instance of State.
187
- * Yeilds the key and current value for each property.
188
- */
189
- [Symbol.iterator]() {
190
- return Object.entries(STATE.get(this.is))[Symbol.iterator]();
191
- }
192
- /**
193
- * Create and activate a new instance of this state.
194
- *
195
- * **Important** - Unlike `new this(...)` - this method also activates state.
196
- *
197
- * @param args - arguments sent to constructor
198
- */
199
- static new(...args) {
200
- const instance = new this(...args);
201
- event(instance);
202
- return instance;
203
- }
204
- /**
205
- * Static equivalent of `x instanceof this`.
206
- * Determines if provided class is a subtype of this one.
207
- * If so, language server will make available all static
208
- * methods and properties of this class.
209
- */
210
- static is(maybe) {
211
- return maybe === this || typeof maybe == "function" && maybe.prototype instanceof this;
212
- }
213
- /**
214
- * Register a callback to run when any instance of this State is updated.
215
- */
216
- static on(listener) {
217
- let notify = NOTIFY.get(this);
218
- if (!notify) NOTIFY.set(this, notify = /* @__PURE__ */ new Set());
219
- notify.add(listener);
220
- return () => notify.delete(listener);
221
- }
222
- };
223
- define(State.prototype, "toString", { value() {
224
- return ID.get(this.is);
225
- } });
226
- define(State, "toString", { value() {
227
- return this.name;
228
- } });
229
- function assign(subject, data, silent) {
230
- const methods = METHODS.get(subject.constructor);
231
- for (const key in data) {
232
- const bind = methods.get(key);
233
- if (bind) bind.call(subject, data[key]);
234
- else if (key in subject && key !== "is") {
235
- const desc = Object.getOwnPropertyDescriptor(subject, key);
236
- const set = desc && desc.set;
237
- if (set) set.call(subject, data[key], silent);
238
- else subject[key] = data[key];
239
- }
240
- }
241
- }
242
- /** Apply instructions and inherited event listeners. Ensure class metadata is ready. */
243
- function prepare(state) {
244
- let T = state.constructor;
245
- if (T === State) throw new Error("Cannot create base State.");
246
- const chain = [];
247
- let keys = /* @__PURE__ */ new Map();
248
- ID.set(state, `${T}-${uid()}`);
249
- while (T.name) {
250
- for (const cb of NOTIFY.get(T) || []) addListener(state, cb);
251
- if (T === State) break;
252
- else chain.unshift(T);
253
- T = Object.getPrototypeOf(T);
254
- }
255
- for (const type of chain) {
256
- if (METHODS.has(type)) {
257
- keys = METHODS.get(type);
258
- continue;
259
- }
260
- METHODS.set(type, keys = new Map(keys));
261
- for (const [key, { value }] of Object.entries(Object.getOwnPropertyDescriptors(type.prototype))) {
262
- if (!value || key == "constructor") continue;
263
- function bind(original) {
264
- const { is } = this;
265
- if (is.hasOwnProperty(key) && !original) return value;
266
- const fn = original || value;
267
- const bound = fn.bind(is);
268
- METHOD.set(bound, fn);
269
- define(is, key, {
270
- value: bound,
271
- writable: true
272
- });
273
- return bound;
274
- }
275
- keys.set(key, bind);
276
- define(type.prototype, key, {
277
- get: bind,
278
- set: bind
279
- });
280
- }
281
- }
282
- }
283
- /**
284
- * Apply state arguemnts, run callbacks and observe properties.
285
- * Accumulate and handle cleanup events.
286
- **/
287
- function init$1(self, ...args) {
288
- const state = {};
289
- STATE.set(self, state);
290
- args = args.flat().filter((arg) => {
291
- if (typeof arg == "string") ID.set(self, arg);
292
- else return true;
293
- });
294
- addListener(self, () => {
295
- if (!PARENT.has(self)) PARENT.set(self, null);
296
- for (const key in self) {
297
- const desc = Object.getOwnPropertyDescriptor(self, key);
298
- if ("value" in desc) manage(self, key, desc.value, true);
299
- }
300
- for (const arg of args) {
301
- const use = typeof arg == "function" ? arg.call(self, self) : arg;
302
- if (use instanceof Promise) use.catch((err) => {
303
- console.error(`Async error in constructor for ${self}:`);
304
- console.error(err);
305
- });
306
- else if (Array.isArray(use)) args.push(...use);
307
- else if (typeof use == "function") addListener(self, use, null);
308
- else if (typeof use == "object") assign(self, use, true);
309
- }
310
- addListener(self, () => {
311
- for (const [_, value] of self) if (value instanceof State && PARENT.get(value) === self) value.set(null);
312
- Object.freeze(state);
313
- }, null);
314
- return null;
315
- });
316
- }
317
- function manage(target, key, value, silent) {
318
- const state = STATE.get(target);
319
- function get() {
320
- return follow(this, key, state[key]);
321
- }
322
- function set(value, silent) {
323
- update(target, key, value, silent);
324
- if (value instanceof State && !PARENT.has(value)) {
325
- PARENT.set(value, target);
326
- event(value);
327
- }
328
- }
329
- define(target, key, {
330
- set,
331
- get
332
- });
333
- set(value, silent);
334
- }
335
- function effect(target, fn) {
336
- const effect = METHOD.get(fn) || fn;
337
- let pending = /* @__PURE__ */ new Set();
338
- return watch(target, (proxy) => {
339
- const cb = effect.call(proxy, proxy, pending);
340
- if (cb === null) return cb;
341
- return (update) => {
342
- pending = PENDING_KEYS.get(target);
343
- if (typeof cb == "function") cb(update);
344
- };
345
- });
346
- }
347
- function values(target) {
348
- const values = {};
349
- let isNotRecursive;
350
- if (!EXPORT) {
351
- isNotRecursive = true;
352
- EXPORT = new Map([[target, values]]);
353
- }
354
- for (let [key, value] of target) {
355
- if (EXPORT.has(value)) value = EXPORT.get(value);
356
- else if (value && typeof value == "object" && "get" in value && typeof value.get === "function") EXPORT.set(value, value = value.get());
357
- values[key] = value;
358
- }
359
- if (isNotRecursive) EXPORT = void 0;
360
- return Object.freeze(values);
361
- }
362
- const OBSERVER = /* @__PURE__ */ new WeakMap();
363
- function follow(from, key, value) {
364
- const observe = OBSERVER.get(from);
365
- return observe ? observe(key, value) : value;
366
- }
367
- function access(subject, property, required) {
368
- const state = STATE.get(subject);
369
- if (property in state || required === false) {
370
- const value = state[property];
371
- if (value !== void 0 || !required) return value;
372
- }
373
- if (METHODS.get(subject.constructor).has(property)) return METHOD.get(subject[property]);
374
- const error = /* @__PURE__ */ new Error(`${subject}.${property} is not yet available.`);
375
- const promise = new Promise((resolve, reject) => {
376
- addListener(subject, (key) => {
377
- if (key === property) {
378
- resolve(state[key]);
379
- return null;
380
- }
381
- if (key === null) reject(/* @__PURE__ */ new Error(`${subject} is destroyed.`));
382
- });
383
- });
384
- throw Object.assign(promise, {
385
- toString: () => String(error),
386
- name: "Suspense",
387
- message: error.message,
388
- stack: error.stack
389
- });
390
- }
391
- function update(subject, key, value, arg) {
392
- const state = STATE.get(subject);
393
- if (Object.isFrozen(state)) throw new Error(`Tried to update ${subject}.${String(key)} but state is destroyed.`);
394
- const previous = state[key];
395
- if (typeof arg == "function") {
396
- const out = arg.call(subject, value, previous);
397
- if (out === false) return false;
398
- if (typeof out == "function") value = out();
399
- }
400
- if (value === previous && key in state) return;
401
- state[key] = value;
402
- if (arg !== true) event(subject, key);
403
- return true;
404
- }
405
- /** Random alphanumberic of length 6; always starts with a letter. */
406
- function uid() {
407
- return (.278 + Math.random() * .722).toString(36).substring(2, 8).toUpperCase();
408
- }
409
-
410
- //#endregion
411
- //#region src/instruction/use.ts
412
- const INSTRUCTION = /* @__PURE__ */ new Map();
413
- function use(arg1, arg2) {
414
- if (State.is(arg1)) arg1 = childInstruction(arg1, arg2);
415
- const token = Symbol("instruction-" + uid());
416
- INSTRUCTION.set(token, arg1);
417
- return token;
418
- }
419
- function childInstruction(type, arg2) {
420
- return (key, subject) => {
421
- function set(next) {
422
- if (next ? !(next instanceof type) : arg2 !== false) throw new Error(`${subject}.${key} expected State of type ${type} but got ${next && next.constructor}.`);
423
- update(subject, key, next);
424
- if (next && typeof arg2 == "function") arg2(next);
425
- return false;
426
- }
427
- const value = new type();
428
- set(value);
429
- PARENT.set(value, subject);
430
- value.set();
431
- return { set };
432
- };
433
- }
434
- function init() {
435
- const state = STATE.get(this);
436
- for (const key in this) {
437
- const { value } = Object.getOwnPropertyDescriptor(this, key);
438
- const instruction = INSTRUCTION.get(value);
439
- if (!instruction) continue;
440
- INSTRUCTION.delete(value);
441
- delete this[key];
442
- const output = instruction.call(this, key, this, state);
443
- if (!output) continue;
444
- const desc = typeof output == "object" ? output : { get: output };
445
- if ("value" in desc) state[key] = desc.value;
446
- const self = this;
447
- Object.defineProperty(self, key, {
448
- enumerable: desc.enumerable !== false,
449
- get() {
450
- return follow(this, key, typeof desc.get == "function" ? desc.get(this) : access(self, key, desc.get));
451
- },
452
- set(next) {
453
- if (desc.set === false) throw new Error(`${self}.${key} is read-only.`);
454
- update(self, key, next, desc.set);
455
- }
456
- });
457
- }
458
- return null;
459
- }
460
- State.on(init);
461
-
462
- //#endregion
463
- //#region src/context.ts
464
- const LOOKUP = /* @__PURE__ */ new WeakMap();
465
- const KEYS = /* @__PURE__ */ new Map();
466
- function key(T, upstream) {
467
- let K = KEYS.get(T);
468
- if (!K) {
469
- K = Symbol(typeof T == "symbol" ? "get " + T.description : String(T));
470
- KEYS.set(T, K);
471
- }
472
- return upstream ? key(K) : K;
473
- }
474
- function keys(from, upstream) {
475
- const keys = /* @__PURE__ */ new Set();
476
- do {
477
- keys.add(key(from, upstream));
478
- from = Object.getPrototypeOf(from);
479
- } while (from !== State);
480
- return keys;
481
- }
482
- var Context = class Context {
483
- static get({ is }, callback) {
484
- const context = LOOKUP.get(is);
485
- if (context instanceof Context) {
486
- if (callback) callback(context);
487
- return context;
488
- }
489
- if (callback) if (context) context.push(callback);
490
- else LOOKUP.set(is, [callback]);
491
- }
492
- constructor(inputs) {
493
- this.id = uid();
494
- this.inputs = {};
495
- this.cleanup = /* @__PURE__ */ new Set();
496
- if (inputs) this.use(inputs);
497
- }
498
- get(Type, arg2) {
499
- if (typeof arg2 == "function") {
500
- const k = key(Type, true);
501
- Object.defineProperty(this, k, {
502
- value: arg2,
503
- configurable: true
504
- });
505
- return () => {
506
- delete this[k];
507
- };
508
- }
509
- const result = this[key(Type)];
510
- if (result === null) throw new Error(`Did find ${Type} in context, but multiple were defined.`);
511
- if (result) return result;
512
- if (arg2) throw new Error(`Could not find ${Type} in context.`);
513
- }
514
- /**
515
- * Adds a State to this context.
516
- */
517
- add(input, implicit) {
518
- const cleanup = /* @__PURE__ */ new Set();
519
- let T;
520
- let I;
521
- if (typeof input == "function") {
522
- T = input;
523
- I = new input();
524
- } else {
525
- T = input.constructor;
526
- I = input;
527
- }
528
- keys(T, true).forEach((K) => {
529
- const expects = this[K];
530
- if (expects) addListener(I, (event) => {
531
- if (event === true) {
532
- const cb = expects(I);
533
- if (cb) cleanup.add(cb);
534
- }
535
- return null;
536
- });
537
- });
538
- keys(T).forEach((K) => {
539
- const value = this.hasOwnProperty(K) ? null : I;
540
- if (value || this[K] !== I && !implicit) Object.defineProperty(this, K, {
541
- configurable: true,
542
- value
543
- });
544
- });
545
- this.cleanup.add(() => {
546
- cleanup.forEach((cb) => cb());
547
- if (I !== input) event(I, null);
548
- });
549
- const waiting = LOOKUP.get(I);
550
- if (waiting instanceof Array) waiting.forEach((cb) => cb(this));
551
- LOOKUP.set(I, this);
552
- return I;
553
- }
554
- /**
555
- * Register one or more States to this context.
556
- *
557
- * Context will add or remove States as needed to keep with provided input.
558
- *
559
- * @param inputs State, State class, or map of States / State classes to register.
560
- * @param forEach Optional callback to run for each State registered.
561
- */
562
- use(inputs, forEach) {
563
- const init = /* @__PURE__ */ new Map();
564
- if (typeof inputs == "function" || inputs instanceof State) inputs = { [0]: inputs };
565
- for (const [K, V] of Object.entries(inputs)) {
566
- if (!(State.is(V) || V instanceof State)) throw new Error(`Context may only include instance or class \`extends State\` but got ${K == "0" || K == String(V) ? V : `${V} (as '${K}')`}.`);
567
- const exists = this.inputs[K];
568
- if (!exists) init.set(this.add(V), true);
569
- else if (exists !== V) {
570
- this.pop();
571
- this.use(inputs);
572
- this.id = uid();
573
- return;
574
- }
575
- }
576
- for (const [state, explicit] of init) {
577
- state.set();
578
- if (explicit && forEach) forEach(state);
579
- for (const [_key, value] of state) if (PARENT.get(value) === state) {
580
- this.add(value, true);
581
- init.set(value, false);
582
- }
583
- }
584
- this.inputs = inputs;
585
- }
586
- /**
587
- * Create a child context, optionally registering one or more States to it.
588
- *
589
- * @param inputs State, State class, or map of States / State classes to register.
590
- */
591
- push(inputs) {
592
- const next = Object.create(this);
593
- this.cleanup = new Set([() => next.pop(), ...this.cleanup]);
594
- next.inputs = {};
595
- next.cleanup = /* @__PURE__ */ new Set();
596
- if (inputs) next.use(inputs);
597
- return next;
598
- }
599
- /**
600
- * Remove all States from this context.
601
- *
602
- * Will also run any cleanup callbacks registered when States were added.
603
- */
604
- pop() {
605
- for (const key of Object.getOwnPropertySymbols(this)) delete this[key];
606
- this.cleanup.forEach((cb) => cb());
607
- this.cleanup.clear();
608
- this.inputs = {};
609
- }
610
- };
611
- Object.defineProperty(Context.prototype, "toString", { value() {
612
- return `Context-${this.id}`;
613
- } });
614
-
615
- //#endregion
616
- //#region src/instruction/get.ts
617
- function get(Type, arg1, arg2) {
618
- const isDownstream = arg1 === true;
619
- const isOptional = arg1 === false;
620
- return use((key, subject) => {
621
- if (isDownstream) {
622
- const callback = typeof arg2 === "function" ? arg2 : void 0;
623
- const applied = /* @__PURE__ */ new Set();
624
- const reset = () => {
625
- update(subject, key, Object.freeze(Array.from(applied)));
626
- };
627
- Context.get(subject, (context) => {
628
- context.get(Type, (state) => {
629
- let remove;
630
- let flush;
631
- if (applied.has(state)) return;
632
- if (callback) {
633
- const exit = scope();
634
- try {
635
- const done = callback(state, subject);
636
- if (done === false) return false;
637
- if (typeof done == "function") remove = done;
638
- } finally {
639
- flush = exit();
640
- }
641
- }
642
- applied.add(state);
643
- reset();
644
- const done = () => {
645
- if (flush) flush();
646
- ignore();
647
- applied.delete(state);
648
- reset();
649
- if (typeof remove == "function") remove();
650
- remove = void 0;
651
- };
652
- const ignore = state.set(done, null);
653
- return done;
654
- });
655
- });
656
- return {
657
- value: [],
658
- enumerable: false
659
- };
660
- }
661
- const hasParent = PARENT.get(subject);
662
- function assign(value) {
663
- if (typeof arg1 === "function") {
664
- const result = arg1(value, subject);
665
- if (typeof result === "function") subject.set(result, null);
666
- }
667
- update(subject, key, value);
668
- }
669
- if (hasParent && hasParent instanceof Type) {
670
- assign(hasParent);
671
- return {};
672
- }
673
- Context.get(subject, (context) => {
674
- const self = context.get(Type);
675
- if (self) assign(self);
676
- else if (!isOptional) throw new Error(`Required ${Type} not found in context for ${subject}.`);
677
- });
678
- return {
679
- get: !isOptional,
680
- enumerable: false
681
- };
682
- });
683
- }
684
-
685
- //#endregion
686
- //#region src/instruction/set.ts
687
- const STALE = /* @__PURE__ */ new WeakSet();
688
- function set(value, argument) {
689
- return use((key, subject, state) => {
690
- if (typeof value == "symbol") throw new Error(`Attempted to use an instruction result (probably use or get) as computed source for ${subject}.${key}. This is not allowed.`);
691
- const property = {};
692
- if (value instanceof State || value === true) {
693
- let from = subject;
694
- let getter;
695
- if (value instanceof State) {
696
- from = value;
697
- getter = argument;
698
- } else {
699
- const fn = METHOD.get(argument) || argument;
700
- getter = ((p, k) => fn.call(p, k, p));
701
- }
702
- const source = (resolve) => resolve(from);
703
- let reset;
704
- let isAsync;
705
- let proxy;
706
- function connect(self) {
707
- reset = watch(self, (current) => {
708
- proxy = current;
709
- if (!(key in state) || STALE.delete(compute)) compute(!reset);
710
- return (didUpdate) => {
711
- if (didUpdate) {
712
- STALE.add(compute);
713
- event(subject, key, true);
714
- }
715
- };
716
- }, false);
717
- }
718
- function compute(initial) {
719
- let next;
720
- try {
721
- next = getter.call(proxy, proxy, key);
722
- } catch (err) {
723
- console.warn(`An exception was thrown while ${initial ? "initializing" : "refreshing"} ${subject}.${key}.`);
724
- if (initial) throw err;
725
- console.error(err);
726
- }
727
- update(subject, key, next, !isAsync);
728
- }
729
- return () => {
730
- if (!proxy) {
731
- source(connect);
732
- isAsync = true;
733
- }
734
- if (STALE.delete(compute)) compute();
735
- return access(subject, key, !proxy);
736
- };
737
- }
738
- if (typeof value == "function" || value instanceof Promise) {
739
- function init() {
740
- if (typeof value == "function") try {
741
- value = attempt(value.bind(subject, key));
742
- } catch (err) {
743
- console.warn(`Generating initial value for ${subject}.${key} failed.`);
744
- throw err;
745
- }
746
- property.get = argument !== false;
747
- const set = (value) => subject[key] = value;
748
- if (value instanceof Promise) value.then(set, (error) => {
749
- event(subject, key);
750
- property.get = () => {
751
- throw error;
752
- };
753
- });
754
- else set(value);
755
- if (argument) return null;
756
- return subject[key];
757
- }
758
- if (argument) addListener(subject, init, true);
759
- else property.get = init;
760
- } else if (value !== void 0) property.value = value;
761
- if (typeof argument == "function") {
762
- let unset;
763
- property.set = function(value, previous) {
764
- const exit = scope();
765
- const returns = argument.call(this, value, previous);
766
- const flush = exit();
767
- if (returns === false) return false;
768
- if (typeof unset == "function") unset(value);
769
- unset = (next) => {
770
- if (typeof returns == "function") returns(next);
771
- flush();
772
- };
773
- };
774
- } else property.set = (value) => {
775
- property.get = void 0;
776
- update(subject, key, value);
777
- };
778
- return property;
779
- });
780
- }
781
- function attempt(fn) {
782
- function retry(err) {
783
- if (err instanceof Promise) return err.then(compute);
784
- else throw err;
785
- }
786
- function compute() {
787
- try {
788
- const output = fn();
789
- return output instanceof Promise ? output.catch(retry) : output;
790
- } catch (err) {
791
- return retry(err);
792
- }
793
- }
794
- return compute();
795
- }
796
-
797
- //#endregion
798
- //#region src/instruction/ref.ts
799
- const { defineProperty, defineProperties } = Object;
800
- function ref(arg, arg2) {
801
- return use((key, subject, state) => {
802
- let value = {};
803
- const method = (key, from) => (callback) => callback ? addListener(subject, () => callback(from[key]), key) : from[key];
804
- if (arg === subject) addListener(subject, () => {
805
- for (const key in subject) if (typeof arg2 == "function") defineProperty(value, key, {
806
- configurable: true,
807
- get() {
808
- const out = arg2(key);
809
- defineProperty(value, key, { value: out });
810
- return out;
811
- }
812
- });
813
- else {
814
- const get = method(key, subject);
815
- const set = (x) => subject[key] = x;
816
- defineProperties(set, {
817
- current: {
818
- get,
819
- set
820
- },
821
- get: { value: get },
822
- is: { value: subject },
823
- key: { value: key }
824
- });
825
- defineProperty(value, key, { value: set });
826
- }
827
- return null;
828
- }, true);
829
- else if (typeof arg == "object") throw new Error("ref instruction does not support object which is not 'this'");
830
- else {
831
- let unset;
832
- const get = method(key, state);
833
- const set = (value) => {
834
- if (!update(subject, key, value) || !arg) return;
835
- if (unset) unset = void unset(value);
836
- if (value === null && arg2 !== false) return;
837
- const exit = scope();
838
- const out = arg.call(subject, value);
839
- const flush = exit();
840
- unset = (key) => {
841
- if (typeof out == "function") out(key);
842
- flush();
843
- };
844
- };
845
- state[key] = null;
846
- value = defineProperty({
847
- get,
848
- key,
849
- is: subject
850
- }, "current", {
851
- get,
852
- set
853
- });
854
- }
855
- defineProperty(subject, key, { value });
856
- });
857
- }
858
-
859
- //#endregion
860
- exports.Context = Context;
861
- exports.METHOD = METHOD;
862
- exports.Observable = Observable;
863
- exports.State = State;
864
- exports.addListener = addListener;
865
- exports.default = State;
866
- exports.event = event;
867
- exports.get = get;
868
- exports.ref = ref;
869
- exports.set = set;
870
- exports.use = use;
871
- exports.watch = watch;
872
- //# sourceMappingURL=index.js.map
1
+ import { Observer, event, listener, observer, touch, watch } from "./observable.js";
2
+ import { State, unbind } from "./state.js";
3
+ import { Context } from "./context.js";
4
+ import { def } from "./field/def.js";
5
+ import { set } from "./field/set.js";
6
+ import { Component } from "./component.js";
7
+ import { get } from "./field/get.js";
8
+ import { hot } from "./field/hot.js";
9
+ import { ref } from "./field/ref.js";
10
+
11
+ export { Component, Context, Observer, State, def, State as default, event, get, hot, listener, observer, ref, set, touch, unbind, watch };