reactronic 0.95.25040 → 0.95.25045

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.
package/README.md CHANGED
@@ -187,8 +187,8 @@ in response to changes in signalling objects made by
187
187
  transactional functions. Cached function is called on-demand
188
188
  to renew the result if it was marked as obsolete due to
189
189
  changes made by an transactional functions. Reactive and cached
190
- functions are instrumented with hooks to seamlessly
191
- subscribe to those signalling objects and other cached
190
+ functions are instrumented with hooks to seamless
191
+ listening of those signalling objects and other cached
192
192
  functions (dependencies), which are used during their
193
193
  execution.
194
194
 
@@ -202,7 +202,7 @@ class MyView extends Component<{model: MyModel}> {
202
202
  <div>{this.props.model.content}</div>
203
203
  </div>
204
204
  )
205
- } // render is subscribed to "url" and "content"
205
+ } // render is listening to "url" and "content"
206
206
  }
207
207
  ```
208
208
 
@@ -219,15 +219,15 @@ class Component<P> extends React.Component<P> {
219
219
  // Ask React to re-render
220
220
  Transaction.outside(() => this.setState({}))
221
221
  }
222
- } // EnsureUpToDate is subscribed to render
222
+ } // EnsureUpToDate is listening to render
223
223
 
224
224
  shouldComponentUpdate(): boolean {
225
- const r = ReactiveSystem.getDescriptor(this.render)
225
+ const r = manageReaction(this.render)
226
226
  return !r.isUpToDate
227
227
  }
228
228
 
229
229
  componentDidMount(): void {
230
- // Run to subscribe for the first time
230
+ // Run for the first time to start listening
231
231
  this.ensureUpToDate()
232
232
  }
233
233
 
@@ -237,9 +237,9 @@ class Component<P> extends React.Component<P> {
237
237
  }
238
238
  ```
239
239
 
240
- In the example above, reactive function `refresh` is
241
- transparently subscribed to the cached function `render`.
242
- In turn, cached function `render` is subscribed to the
240
+ In the example above, reactive function `refresh`
241
+ transparently listens to the cached function `render`.
242
+ In turn, cached function `render` listens to the
243
243
  properties `url` and `content` of a corresponding `MyModel`
244
244
  object. Once `url` or `content` values are changed, the
245
245
  cached function `render` becomes obsolete and causes the
@@ -260,7 +260,7 @@ reactive functions) or on-demand (for cached functions).
260
260
  Reactronic takes full care of tracking dependencies
261
261
  between all the signalling objects and reactive/cached
262
262
  functions. With Reactronic, you no longer need to create
263
- data change events in one set of objects, subscribe to
263
+ data change events in one set of objects, listen to
264
264
  these events in other objects, and manually maintain
265
265
  switching from the previous object version to a new one.
266
266
 
@@ -324,8 +324,8 @@ NPM: `npm install reactronic`
324
324
 
325
325
  // Classes
326
326
 
327
- class TransactionalObject { }
328
- class SignallingObject { }
327
+ class TxObject { } // transactional object
328
+ class SxObject { } // signalling object
329
329
 
330
330
  // Decorators & Operators
331
331
 
@@ -447,9 +447,9 @@ class Transaction implements Worker {
447
447
  static isCanceled: boolean
448
448
  }
449
449
 
450
- // Operation
450
+ // Reaction
451
451
 
452
- abstract class Operation<T> {
452
+ abstract class Reaction<T> {
453
453
  readonly options: Options
454
454
  readonly args: ReadonlyArray<any>
455
455
  readonly value: T
@@ -467,7 +467,7 @@ abstract class Operation<T> {
467
467
  class ReactiveSystem {
468
468
  static why(short: boolean = false): string
469
469
  static getMethodCache<T>(method: F<T>): Cache<T>
470
- static configureCurrentOperation(options: Partial<Options>): Options
470
+ static configureCurrentReaction(options: Partial<Options>): Options
471
471
  static getRevisionOf(obj: any): number
472
472
  static takeSnapshot<T>(obj: T): T
473
473
  static dispose(obj: any): void
@@ -31,8 +31,8 @@ export declare class Changeset implements AbstractChangeset {
31
31
  isResolved: boolean;
32
32
  resolvedValue: any;
33
33
  };
34
- static propagateAllChangesThroughSubscriptions: (changeset: Changeset) => void;
35
- static revokeAllSubscriptions: (changeset: Changeset) => void;
34
+ static propagateAllChangesToListeners: (changeset: Changeset) => void;
35
+ static discardAllListeners: (changeset: Changeset) => void;
36
36
  static enqueueReactionsToRun: (reactions: Array<OperationFootprint>) => void;
37
37
  lookupObjectVersion(h: ObjectHandle, fk: FieldKey, editing: boolean): ObjectVersion;
38
38
  getObjectVersion(h: ObjectHandle, fk: FieldKey): ObjectVersion;
@@ -316,8 +316,8 @@ Changeset.edit = UNDEF;
316
316
  Changeset.markUsed = UNDEF;
317
317
  Changeset.markEdited = UNDEF;
318
318
  Changeset.tryResolveConflict = UNDEF;
319
- Changeset.propagateAllChangesThroughSubscriptions = (changeset) => { };
320
- Changeset.revokeAllSubscriptions = (changeset) => { };
319
+ Changeset.propagateAllChangesToListeners = (changeset) => { };
320
+ Changeset.discardAllListeners = (changeset) => { };
321
321
  Changeset.enqueueReactionsToRun = (reactions) => { };
322
322
  export class Dump {
323
323
  static obj(h, fk, stamp, changesetId, lastEditorChangesetId, value) {
@@ -7,21 +7,21 @@ export type AbstractChangeset = {
7
7
  };
8
8
  export declare class ContentFootprint<T = any> {
9
9
  content: T;
10
- subscribers?: Set<OperationFootprint>;
10
+ listeners?: Set<OperationFootprint>;
11
11
  lastEditorChangesetId: number;
12
12
  get isComputed(): boolean;
13
13
  constructor(content: T, lastEditorChangesetId: number);
14
14
  }
15
15
  export type OperationFootprint = {
16
16
  readonly order: number;
17
- readonly signals: Map<ContentFootprint, Subscription> | undefined;
17
+ readonly signals: Map<ContentFootprint, ListeningInfo> | undefined;
18
18
  readonly obsoleteSince: number;
19
19
  hint(nop?: boolean): string;
20
20
  markObsoleteDueTo(footprint: ContentFootprint, fk: FieldKey, changeset: AbstractChangeset, h: ObjectHandle, outer: string, since: number, collector: Array<OperationFootprint>): void;
21
21
  relaunchIfNotUpToDate(now: boolean, nothrow: boolean): void;
22
22
  };
23
23
  export type FieldKey = PropertyKey;
24
- export type Subscription = {
24
+ export type ListeningInfo = {
25
25
  readonly memberHint: string;
26
26
  readonly usageCount: number;
27
27
  };
@@ -100,10 +100,8 @@ export class Mvcc {
100
100
  return fk in ov.data || fk in h.data;
101
101
  }
102
102
  defineProperty(h, name, attributes) {
103
- const result = attributes.get !== undefined && attributes.set !== undefined;
104
- if (result)
105
- Object.defineProperty(h.data, name, attributes);
106
- return result;
103
+ Object.defineProperty(h.data, name, attributes);
104
+ return true;
107
105
  }
108
106
  getOwnPropertyDescriptor(h, fk) {
109
107
  const ov = Changeset.current().getObjectVersion(h, fk);
@@ -1,6 +1,6 @@
1
1
  import { F } from "../util/Utils.js";
2
2
  import { Reaction, ReactivityOptions } from "../Options.js";
3
- import { FieldKey, ObjectHandle, ContentFootprint, OperationFootprint, Subscription, AbstractChangeset } from "./Data.js";
3
+ import { FieldKey, ObjectHandle, ContentFootprint, OperationFootprint, ListeningInfo, AbstractChangeset } from "./Data.js";
4
4
  import { Transaction } from "./Transaction.js";
5
5
  import { OptionsImpl } from "./Mvcc.js";
6
6
  export declare class ReactionImpl implements Reaction<any> {
@@ -39,7 +39,7 @@ declare class OperationFootprintImpl extends ContentFootprint implements Operati
39
39
  readonly transaction: Transaction;
40
40
  readonly descriptor: ReactionImpl;
41
41
  readonly changeset: AbstractChangeset;
42
- signals: Map<ContentFootprint, Subscription> | undefined;
42
+ signals: Map<ContentFootprint, ListeningInfo> | undefined;
43
43
  options: OptionsImpl;
44
44
  cause: string | undefined;
45
45
  args: any[];
@@ -75,15 +75,15 @@ declare class OperationFootprintImpl extends ContentFootprint implements Operati
75
75
  private static markUsed;
76
76
  private static markEdited;
77
77
  private static tryResolveConflict;
78
- private static propagateAllChangesThroughSubscriptions;
79
- private static revokeAllSubscriptions;
80
- private static propagateFieldChangeThroughSubscriptions;
78
+ private static propagateAllChangesToListeners;
79
+ private static discardAllListeners;
80
+ private static propagateFieldChangeToListeners;
81
81
  private static enqueueReactionsToRun;
82
82
  private static migrateContentFootprint;
83
83
  private static processQueuedReactions;
84
- private unsubscribeFromAllSignals;
85
- private subscribeTo;
86
- private static canSubscribeTo;
84
+ private stopListeningAllSignals;
85
+ private listenTo;
86
+ private static canListenTo;
87
87
  private static createOperationDescriptor;
88
88
  private static rememberOperationOptions;
89
89
  static init(): void;
@@ -301,11 +301,11 @@ class OperationFootprintImpl extends ContentFootprint {
301
301
  Log.write(Log.opt.transaction && !Changeset.current().sealed ? "║" : " ", isReactive ? "█" : "▒", isReactive && changeset === EMPTY_OBJECT_VERSION.changeset
302
302
  ? `${this.hint()} is reactive and will run automatically (order ${this.options.order})`
303
303
  : `${this.hint()} is obsolete due to ${Dump.snapshot2(h, changeset, fk)} since s${since}${isReactive ? ` and will run automatically (order ${this.options.order})` : ""}`);
304
- this.unsubscribeFromAllSignals();
304
+ this.stopListeningAllSignals();
305
305
  if (isReactive)
306
306
  collector.push(this);
307
307
  else
308
- (_b = this.subscribers) === null || _b === void 0 ? void 0 : _b.forEach(s => s.markObsoleteDueTo(this, this.descriptor.fieldKey, this.changeset, this.descriptor.ownerHandle, why, since, collector));
308
+ (_b = this.listeners) === null || _b === void 0 ? void 0 : _b.forEach(s => s.markObsoleteDueTo(this, this.descriptor.fieldKey, this.changeset, this.descriptor.ownerHandle, why, since, collector));
309
309
  const tran = this.transaction;
310
310
  if (tran.changeset === changeset) {
311
311
  }
@@ -470,15 +470,15 @@ class OperationFootprintImpl extends ContentFootprint {
470
470
  }
471
471
  static markUsed(footprint, ov, fk, h, kind, weak) {
472
472
  if (kind !== Kind.transaction) {
473
- const subscriber = OperationFootprintImpl.current;
474
- if (subscriber && subscriber.options.kind !== Kind.transaction &&
475
- subscriber.transaction === Transaction.current && fk !== Meta.Handle) {
473
+ const listener = OperationFootprintImpl.current;
474
+ if (listener && listener.options.kind !== Kind.transaction &&
475
+ listener.transaction === Transaction.current && fk !== Meta.Handle) {
476
476
  const ctx = Changeset.current();
477
477
  if (ctx !== ov.changeset)
478
478
  ctx.bumpBy(ov.changeset.timestamp);
479
479
  const t = weak ? -1 : ctx.timestamp;
480
- if (!subscriber.subscribeTo(footprint, ov, fk, h, t))
481
- subscriber.markObsoleteDueTo(footprint, fk, h.applied.changeset, h, BOOT_CAUSE, ctx.timestamp, ctx.obsolete);
480
+ if (!listener.listenTo(footprint, ov, fk, h, t))
481
+ listener.markObsoleteDueTo(footprint, fk, h.applied.changeset, h, BOOT_CAUSE, ctx.timestamp, ctx.obsolete);
482
482
  }
483
483
  }
484
484
  }
@@ -502,28 +502,28 @@ class OperationFootprintImpl extends ContentFootprint {
502
502
  }
503
503
  return { isResolved, resolvedValue };
504
504
  }
505
- static propagateAllChangesThroughSubscriptions(changeset) {
505
+ static propagateAllChangesToListeners(changeset) {
506
506
  var _a;
507
507
  const since = changeset.timestamp;
508
508
  const obsolete = changeset.obsolete;
509
509
  changeset.items.forEach((ov, h) => {
510
- OperationFootprintImpl.propagateFieldChangeThroughSubscriptions(false, since, ov, Meta.Revision, h, obsolete);
510
+ OperationFootprintImpl.propagateFieldChangeToListeners(false, since, ov, Meta.Revision, h, obsolete);
511
511
  if (!ov.disposed)
512
- ov.changes.forEach((o, fk) => OperationFootprintImpl.propagateFieldChangeThroughSubscriptions(false, since, ov, fk, h, obsolete));
512
+ ov.changes.forEach((o, fk) => OperationFootprintImpl.propagateFieldChangeToListeners(false, since, ov, fk, h, obsolete));
513
513
  else
514
514
  for (const fk in ov.former.objectVersion.data)
515
- OperationFootprintImpl.propagateFieldChangeThroughSubscriptions(true, since, ov, fk, h, obsolete);
515
+ OperationFootprintImpl.propagateFieldChangeToListeners(true, since, ov, fk, h, obsolete);
516
516
  });
517
517
  obsolete.sort(compareReactionsByOrder);
518
518
  (_a = changeset.options.journal) === null || _a === void 0 ? void 0 : _a.edited(JournalImpl.buildPatch(changeset.hint, changeset.items));
519
519
  }
520
- static revokeAllSubscriptions(changeset) {
520
+ static discardAllListeners(changeset) {
521
521
  changeset.items.forEach((ov, h) => {
522
- OperationFootprintImpl.propagateFieldChangeThroughSubscriptions(true, changeset.timestamp, ov, Meta.Revision, h, undefined);
523
- ov.changes.forEach((o, fk) => OperationFootprintImpl.propagateFieldChangeThroughSubscriptions(true, changeset.timestamp, ov, fk, h, undefined));
522
+ OperationFootprintImpl.propagateFieldChangeToListeners(true, changeset.timestamp, ov, Meta.Revision, h, undefined);
523
+ ov.changes.forEach((o, fk) => OperationFootprintImpl.propagateFieldChangeToListeners(true, changeset.timestamp, ov, fk, h, undefined));
524
524
  });
525
525
  }
526
- static propagateFieldChangeThroughSubscriptions(unsubscribe, timestamp, ov, fk, h, collector) {
526
+ static propagateFieldChangeToListeners(stopListening, timestamp, ov, fk, h, collector) {
527
527
  var _a;
528
528
  const curr = ov.data[fk];
529
529
  if (collector !== undefined) {
@@ -534,7 +534,7 @@ class OperationFootprintImpl extends ContentFootprint {
534
534
  if ((former.obsoleteSince === MAX_REVISION || former.obsoleteSince <= 0)) {
535
535
  former.obsoleteDueTo = why;
536
536
  former.obsoleteSince = timestamp;
537
- former.unsubscribeFromAllSignals();
537
+ former.stopListeningAllSignals();
538
538
  }
539
539
  const formerSuccessor = former.successor;
540
540
  if (formerSuccessor !== curr) {
@@ -544,7 +544,7 @@ class OperationFootprintImpl extends ContentFootprint {
544
544
  else
545
545
  former.successor = undefined;
546
546
  }
547
- (_a = former.subscribers) === null || _a === void 0 ? void 0 : _a.forEach(s => {
547
+ (_a = former.listeners) === null || _a === void 0 ? void 0 : _a.forEach(s => {
548
548
  const t = s.transaction;
549
549
  const o = t.isFinished ? collector : t.changeset.obsolete;
550
550
  return s.markObsoleteDueTo(former, fk, ov.changeset, h, why, timestamp, o);
@@ -559,11 +559,11 @@ class OperationFootprintImpl extends ContentFootprint {
559
559
  Log.write("", "[!]", `${curr.hint()} uses ${info.memberHint} ${info.usageCount} times (consider remembering it in a local variable)`, 0, " *** WARNING ***");
560
560
  });
561
561
  }
562
- if (unsubscribe)
563
- curr.unsubscribeFromAllSignals();
562
+ if (stopListening)
563
+ curr.stopListeningAllSignals();
564
564
  }
565
565
  }
566
- else if (curr instanceof ContentFootprint && curr.subscribers) {
566
+ else if (curr instanceof ContentFootprint && curr.listeners) {
567
567
  }
568
568
  }
569
569
  static enqueueReactionsToRun(reactions) {
@@ -592,20 +592,20 @@ class OperationFootprintImpl extends ContentFootprint {
592
592
  }
593
593
  OperationFootprintImpl.queuedReactions = [];
594
594
  }
595
- unsubscribeFromAllSignals() {
595
+ stopListeningAllSignals() {
596
596
  var _a;
597
597
  (_a = this.signals) === null || _a === void 0 ? void 0 : _a.forEach((info, value) => {
598
598
  var _a;
599
- value.subscribers.delete(this);
599
+ value.listeners.delete(this);
600
600
  if (Log.isOn && (Log.opt.read || ((_a = this.options.logging) === null || _a === void 0 ? void 0 : _a.read)))
601
- Log.write(Log.opt.transaction && !Changeset.current().sealed ? "║" : " ", "-", `${this.hint()} is unsubscribed from ${info.memberHint}`);
601
+ Log.write(Log.opt.transaction && !Changeset.current().sealed ? "║" : " ", "-", `${this.hint()} is no longer listening to ${info.memberHint}`);
602
602
  });
603
603
  this.signals = undefined;
604
604
  }
605
- subscribeTo(footprint, ov, fk, h, timestamp) {
605
+ listenTo(footprint, ov, fk, h, timestamp) {
606
606
  var _a, _b, _c;
607
607
  const parent = this.transaction.changeset.parent;
608
- const ok = OperationFootprintImpl.canSubscribeTo(footprint, ov, parent, fk, h, timestamp);
608
+ const ok = OperationFootprintImpl.canListenTo(footprint, ov, parent, fk, h, timestamp);
609
609
  if (ok) {
610
610
  let times = 0;
611
611
  if (Mvcc.repetitiveUsageWarningThreshold < Number.MAX_SAFE_INTEGER) {
@@ -613,24 +613,24 @@ class OperationFootprintImpl extends ContentFootprint {
613
613
  times = existing ? existing.usageCount + 1 : 1;
614
614
  }
615
615
  if (this.signals !== undefined) {
616
- if (!footprint.subscribers)
617
- footprint.subscribers = new Set();
618
- const subscription = { memberHint: Dump.snapshot2(h, ov.changeset, fk), usageCount: times };
619
- footprint.subscribers.add(this);
620
- this.signals.set(footprint, subscription);
616
+ if (!footprint.listeners)
617
+ footprint.listeners = new Set();
618
+ const listening = { memberHint: Dump.snapshot2(h, ov.changeset, fk), usageCount: times };
619
+ footprint.listeners.add(this);
620
+ this.signals.set(footprint, listening);
621
621
  if (Log.isOn && (Log.opt.read || ((_a = this.options.logging) === null || _a === void 0 ? void 0 : _a.read)))
622
- Log.write("║", " ∞", `${this.hint()} is subscribed to ${Dump.snapshot2(h, ov.changeset, fk, footprint)}${subscription.usageCount > 1 ? ` (${subscription.usageCount} times)` : ""}`);
622
+ Log.write("║", " ∞", `${this.hint()} now listens to ${Dump.snapshot2(h, ov.changeset, fk, footprint)}${listening.usageCount > 1 ? ` (${listening.usageCount} times)` : ""}`);
623
623
  }
624
624
  else if (Log.isOn && (Log.opt.read || ((_b = this.options.logging) === null || _b === void 0 ? void 0 : _b.read)))
625
- Log.write("║", " x", `${this.hint()} is obsolete and is NOT subscribed to ${Dump.snapshot2(h, ov.changeset, fk, footprint)}`);
625
+ Log.write("║", " x", `${this.hint()} is obsolete and is not listening to ${Dump.snapshot2(h, ov.changeset, fk, footprint)}`);
626
626
  }
627
627
  else {
628
628
  if (Log.isOn && (Log.opt.read || ((_c = this.options.logging) === null || _c === void 0 ? void 0 : _c.read)))
629
- Log.write("║", " x", `${this.hint()} is NOT subscribed to already obsolete ${Dump.snapshot2(h, ov.changeset, fk, footprint)}`);
629
+ Log.write("║", " x", `${this.hint()} is not listening to already obsolete ${Dump.snapshot2(h, ov.changeset, fk, footprint)}`);
630
630
  }
631
631
  return ok;
632
632
  }
633
- static canSubscribeTo(footprint, ov, parent, fk, h, timestamp) {
633
+ static canListenTo(footprint, ov, parent, fk, h, timestamp) {
634
634
  const parentSnapshot = parent ? parent.lookupObjectVersion(h, fk, false) : h.applied;
635
635
  const parentFootprint = parentSnapshot.data[fk];
636
636
  let result = footprint === parentFootprint || (!ov.changeset.sealed && ov.former.objectVersion.data[fk] === parentFootprint);
@@ -669,8 +669,8 @@ class OperationFootprintImpl extends ContentFootprint {
669
669
  Changeset.markUsed = OperationFootprintImpl.markUsed;
670
670
  Changeset.markEdited = OperationFootprintImpl.markEdited;
671
671
  Changeset.tryResolveConflict = OperationFootprintImpl.tryResolveConflict;
672
- Changeset.propagateAllChangesThroughSubscriptions = OperationFootprintImpl.propagateAllChangesThroughSubscriptions;
673
- Changeset.revokeAllSubscriptions = OperationFootprintImpl.revokeAllSubscriptions;
672
+ Changeset.propagateAllChangesToListeners = OperationFootprintImpl.propagateAllChangesToListeners;
673
+ Changeset.discardAllListeners = OperationFootprintImpl.discardAllListeners;
674
674
  Changeset.enqueueReactionsToRun = OperationFootprintImpl.enqueueReactionsToRun;
675
675
  TransactionImpl.migrateContentFootprint = OperationFootprintImpl.migrateContentFootprint;
676
676
  Mvcc.createOperationDescriptor = OperationFootprintImpl.createOperationDescriptor;
@@ -258,7 +258,7 @@ export class TransactionImpl extends Transaction {
258
258
  if (after && after !== TransactionImpl.none)
259
259
  Log.write("║", " [!]", `T${t.id}[${t.hint}] will be restarted${t !== after ? ` after T${after.id}[${after.hint}]` : ""}`);
260
260
  }
261
- Changeset.revokeAllSubscriptions(t.changeset);
261
+ Changeset.discardAllListeners(t.changeset);
262
262
  }
263
263
  t.sealed = true;
264
264
  }
@@ -328,7 +328,7 @@ export class TransactionImpl extends Transaction {
328
328
  }
329
329
  }
330
330
  else if (!error)
331
- Changeset.propagateAllChangesThroughSubscriptions(changeset);
331
+ Changeset.propagateAllChangesToListeners(changeset);
332
332
  return obsolete;
333
333
  }
334
334
  applyObjectChanges(h, ov) {
@@ -359,39 +359,39 @@ export class TransactionImpl extends Transaction {
359
359
  if (cf.isComputed) {
360
360
  const migrated = TransactionImpl.migrateContentFootprint(cf, tParent);
361
361
  if (ovParent.former.objectVersion.data[fk] !== cfParent) {
362
- let subscribers = cfParent.subscribers;
363
- if (subscribers) {
364
- const migratedSubscribers = migrated.subscribers = new Set();
365
- subscribers.forEach(o => {
362
+ let listeners = cfParent.listeners;
363
+ if (listeners) {
364
+ const migratedListeners = migrated.listeners = new Set();
365
+ listeners.forEach(o => {
366
366
  const conformingSignals = o.signals;
367
367
  const sub = conformingSignals.get(cfParent);
368
368
  conformingSignals.delete(cfParent);
369
369
  conformingSignals.set(migrated, sub);
370
- migratedSubscribers.add(o);
370
+ migratedListeners.add(o);
371
371
  });
372
- cfParent.subscribers = undefined;
372
+ cfParent.listeners = undefined;
373
373
  }
374
- subscribers = cf.subscribers;
375
- if (subscribers) {
376
- let migratedSubscribers = migrated.subscribers;
377
- if (migratedSubscribers === undefined)
378
- migratedSubscribers = migrated.subscribers = new Set();
379
- subscribers.forEach(o => {
374
+ listeners = cf.listeners;
375
+ if (listeners) {
376
+ let migratedListeners = migrated.listeners;
377
+ if (migratedListeners === undefined)
378
+ migratedListeners = migrated.listeners = new Set();
379
+ listeners.forEach(o => {
380
380
  const conformingSignals = o.signals;
381
381
  const sub = conformingSignals.get(cf);
382
382
  conformingSignals.delete(cf);
383
383
  conformingSignals.set(migrated, sub);
384
- migratedSubscribers.add(o);
384
+ migratedListeners.add(o);
385
385
  });
386
- cf.subscribers = undefined;
386
+ cf.listeners = undefined;
387
387
  }
388
388
  const signals = cf.signals;
389
389
  const migratedSignals = migrated.signals;
390
390
  if (signals) {
391
391
  signals.forEach((s, o) => {
392
- const conformingSubscribers = o.subscribers;
393
- conformingSubscribers.delete(cf);
394
- conformingSubscribers.add(migrated);
392
+ const conformingListeners = o.listeners;
393
+ conformingListeners.delete(cf);
394
+ conformingListeners.add(migrated);
395
395
  migratedSignals.set(o, s);
396
396
  });
397
397
  signals.clear();
@@ -399,25 +399,25 @@ export class TransactionImpl extends Transaction {
399
399
  ovParent.data[fk] = migrated;
400
400
  }
401
401
  else {
402
- const subscribers = cf.subscribers;
403
- if (subscribers) {
404
- const migratedReactions = migrated.subscribers = new Set();
405
- subscribers.forEach(o => {
402
+ const listeners = cf.listeners;
403
+ if (listeners) {
404
+ const migratedReactions = migrated.listeners = new Set();
405
+ listeners.forEach(o => {
406
406
  const conformingSignals = o.signals;
407
407
  const sub = conformingSignals.get(cf);
408
408
  conformingSignals.delete(cf);
409
409
  conformingSignals.set(migrated, sub);
410
410
  migratedReactions.add(o);
411
411
  });
412
- cf.subscribers = undefined;
412
+ cf.listeners = undefined;
413
413
  }
414
414
  const signals = cf.signals;
415
415
  const migratedSignals = migrated.signals;
416
416
  if (signals) {
417
417
  signals.forEach((s, o) => {
418
- const conformingSubscribers = o.subscribers;
419
- conformingSubscribers.delete(cf);
420
- conformingSubscribers.add(migrated);
418
+ const conformingListeners = o.listeners;
419
+ conformingListeners.delete(cf);
420
+ conformingListeners.add(migrated);
421
421
  migratedSignals.set(o, s);
422
422
  });
423
423
  signals.clear();
@@ -431,16 +431,16 @@ export class TransactionImpl extends Transaction {
431
431
  const parentContent = cfParent === null || cfParent === void 0 ? void 0 : cfParent.content;
432
432
  if (ovParent.former.objectVersion.data[fk] !== cfParent) {
433
433
  cfParent.content = cf.content;
434
- const subscribers = cf.subscribers;
435
- if (subscribers) {
436
- if (cfParent.subscribers === undefined)
437
- cfParent.subscribers = new Set();
438
- subscribers.forEach(o => {
434
+ const listeners = cf.listeners;
435
+ if (listeners) {
436
+ if (cfParent.listeners === undefined)
437
+ cfParent.listeners = new Set();
438
+ listeners.forEach(o => {
439
439
  const conformingSignals = o.signals;
440
440
  const sub = conformingSignals.get(cf);
441
441
  conformingSignals.delete(cf);
442
442
  conformingSignals.set(cfParent, sub);
443
- cfParent.subscribers.add(o);
443
+ cfParent.listeners.add(o);
444
444
  });
445
445
  }
446
446
  }
@@ -23,7 +23,7 @@ import { emitLetters, flags, getCallerInfo, proceedSyncOrAsync } from "../util/U
23
23
  import { Priority, Mode, Isolation, Reentrance } from "../Enums.js";
24
24
  import { SxObject } from "../core/Mvcc.js";
25
25
  import { Transaction } from "../core/Transaction.js";
26
- import { ReactiveSystem, options, signal, reaction, runTransactional, runNonReactive, manageReaction, disposeSignallingObject as disposeSignallingObject } from "../System.js";
26
+ import { ReactiveSystem, options, signal, reaction, runTransactional, runNonReactive, manageReaction, disposeSignallingObject } from "../System.js";
27
27
  export function declare(driver, scriptOrDeclaration, scriptAsync, key, mode, preparation, preparationAsync, finalization, triggers, basis) {
28
28
  let result;
29
29
  let declaration;
@@ -5,7 +5,7 @@ export declare class LinkedList<T extends LinkedItem<T>> {
5
5
  private isStrictOrder$;
6
6
  private map;
7
7
  items$: LinkedSubList<T>;
8
- former$: LinkedSubList<T> | undefined;
8
+ private renovation;
9
9
  constructor(keyExtractor: KeyExtractor<T>, isStrictOrder?: boolean);
10
10
  get isStrictOrder(): boolean;
11
11
  set isStrictOrder(value: boolean);
@@ -16,6 +16,8 @@ export declare class LinkedList<T extends LinkedItem<T>> {
16
16
  add(item: T, before?: T): void;
17
17
  move(item: T, before: T | undefined): void;
18
18
  remove(item: T): void;
19
+ beginRenovation(diff?: Array<T>): LinkedListRenovation<T>;
20
+ endRenovation(error?: unknown): void;
19
21
  static move$<T extends LinkedItem<T>>(list: LinkedList<T>, item: T, before: T | undefined): void;
20
22
  static remove$<T extends LinkedItem<T>>(list: LinkedList<T>, item: T): void;
21
23
  static removeKey$<T extends LinkedItem<T>>(list: LinkedList<T>, key: string | undefined): void;
@@ -50,3 +52,21 @@ export declare class LinkedSubList<T extends LinkedItem<T>> {
50
52
  clear(): void;
51
53
  grab(from: LinkedSubList<T>, join: boolean): void;
52
54
  }
55
+ export declare class LinkedListRenovation<T extends LinkedItem<T>> {
56
+ readonly list: LinkedList<T>;
57
+ readonly diff: Array<T> | undefined;
58
+ private former;
59
+ private expected;
60
+ private absent;
61
+ constructor(list: LinkedList<T>, former: LinkedSubList<T>, diff?: Array<T>);
62
+ lookup(key: string | undefined): T | undefined;
63
+ tryToProlong(key: string, resolution?: {
64
+ isDuplicate: boolean;
65
+ }, error?: string): T | undefined;
66
+ thisIsAdded(item: T, before?: T): T;
67
+ thisIsModified(item: T): void;
68
+ thisIsMoved(item: T, before: T | undefined): void;
69
+ thisIsRemoved(item: T): void;
70
+ get lostItemCount(): number;
71
+ lostItems(): Generator<T>;
72
+ }
@@ -5,20 +5,20 @@ export class LinkedList {
5
5
  this.isStrictOrder$ = isStrictOrder;
6
6
  this.map = new Map();
7
7
  this.items$ = new LinkedSubList();
8
- this.former$ = undefined;
8
+ this.renovation = undefined;
9
9
  }
10
10
  get isStrictOrder() { return this.isStrictOrder$; }
11
11
  set isStrictOrder(value) {
12
- if (this.former$ !== undefined)
12
+ if (this.renovation !== undefined)
13
13
  throw misuse("cannot change strict mode in the middle of renovation");
14
14
  this.isStrictOrder$ = value;
15
15
  }
16
16
  get isRenovationInProgress() {
17
- return this.former$ !== undefined;
17
+ return this.renovation !== undefined;
18
18
  }
19
19
  get count() {
20
20
  var _a, _b;
21
- return this.items$.count + ((_b = (_a = this.former$) === null || _a === void 0 ? void 0 : _a.count) !== null && _b !== void 0 ? _b : 0);
21
+ return this.items$.count + ((_b = (_a = this.renovation) === null || _a === void 0 ? void 0 : _a.lostItemCount) !== null && _b !== void 0 ? _b : 0);
22
22
  }
23
23
  items() {
24
24
  return this.items$.items();
@@ -47,6 +47,38 @@ export class LinkedList {
47
47
  throw misuse("cannot remove given item outside of renovation cycle");
48
48
  LinkedList.remove$(this, item);
49
49
  }
50
+ beginRenovation(diff) {
51
+ if (this.renovation !== undefined)
52
+ throw misuse("renovation is in progress already");
53
+ const former = this.items$;
54
+ const renovation = new LinkedListRenovation(this, former, diff);
55
+ this.items$ = new LinkedSubList();
56
+ this.renovation = renovation;
57
+ return renovation;
58
+ }
59
+ endRenovation(error) {
60
+ const renovation = this.renovation;
61
+ if (renovation === undefined)
62
+ throw misuse("renovation is ended already");
63
+ const items = this.items$;
64
+ if (error === undefined) {
65
+ for (const x of renovation.lostItems()) {
66
+ if (!x.isManagedExternally) {
67
+ LinkedList.removeKey$(this, this.keyOf(x));
68
+ LinkedItem.setStatus$(x, Mark.removed, 0);
69
+ }
70
+ else
71
+ LinkedItem.link$(items, x, undefined);
72
+ }
73
+ }
74
+ else {
75
+ for (const x of renovation.lostItems()) {
76
+ LinkedItem.link$(items, x, undefined);
77
+ LinkedItem.setStatus$(x, Mark.prolonged, items.count);
78
+ }
79
+ }
80
+ this.renovation = undefined;
81
+ }
50
82
  static move$(list, item, before) {
51
83
  LinkedItem.link$(list.items$, item, before);
52
84
  }
@@ -175,3 +207,106 @@ export class LinkedSubList {
175
207
  from.clear();
176
208
  }
177
209
  }
210
+ export class LinkedListRenovation {
211
+ constructor(list, former, diff) {
212
+ this.list = list;
213
+ this.diff = diff;
214
+ this.former = former;
215
+ this.expected = former.first;
216
+ this.absent = undefined;
217
+ }
218
+ lookup(key) {
219
+ let result = undefined;
220
+ if (key !== undefined && key !== this.absent) {
221
+ result = this.list.lookup(key);
222
+ if (result !== undefined) {
223
+ if (this.list.keyOf(result) !== key) {
224
+ this.absent = key;
225
+ result = undefined;
226
+ }
227
+ }
228
+ else
229
+ this.absent = key;
230
+ }
231
+ return result;
232
+ }
233
+ tryToProlong(key, resolution, error) {
234
+ var _a, _b;
235
+ const list = this.list;
236
+ if (!list.isRenovationInProgress)
237
+ throw misuse(error !== null && error !== void 0 ? error : "renovation is no longer in progress");
238
+ let x = this.expected;
239
+ if (key !== (x ? list.keyOf(x) : undefined))
240
+ x = this.lookup(key);
241
+ if (x !== undefined) {
242
+ const result = this.list.items$;
243
+ if (x.list !== result) {
244
+ const next = x.next;
245
+ const expected = (_a = grabExternalIfAny(result, x)) !== null && _a !== void 0 ? _a : x;
246
+ LinkedItem.link$(result, x, undefined);
247
+ if (list.isStrictOrder && expected !== this.expected) {
248
+ LinkedItem.setStatus$(x, Mark.modified, result.count);
249
+ (_b = this.diff) === null || _b === void 0 ? void 0 : _b.push(x);
250
+ }
251
+ else
252
+ LinkedItem.setStatus$(x, Mark.prolonged, result.count);
253
+ this.expected = next;
254
+ if (resolution)
255
+ resolution.isDuplicate = false;
256
+ }
257
+ else if (resolution)
258
+ resolution.isDuplicate = true;
259
+ else
260
+ throw misuse(`duplicate linked item key: ${key}`);
261
+ }
262
+ else if (resolution)
263
+ resolution.isDuplicate = false;
264
+ return x;
265
+ }
266
+ thisIsAdded(item, before) {
267
+ var _a;
268
+ this.list.add(item, before);
269
+ LinkedItem.setStatus$(item, Mark.added, this.list.items$.count);
270
+ this.absent = undefined;
271
+ this.expected = undefined;
272
+ (_a = this.diff) === null || _a === void 0 ? void 0 : _a.push(item);
273
+ return item;
274
+ }
275
+ thisIsModified(item) {
276
+ if (item.list !== this.list.items$)
277
+ throw misuse("only prolonged items can be marked as modified");
278
+ const m = item.mark;
279
+ if (m === Mark.prolonged)
280
+ LinkedItem.setStatus$(item, Mark.modified, item.rank);
281
+ else if (m !== Mark.modified)
282
+ throw misuse("item is renovated already and cannot be marked as modified");
283
+ }
284
+ thisIsMoved(item, before) {
285
+ var _a;
286
+ if (item.list !== this.former)
287
+ throw misuse("cannot move item which doesn't belong to former list");
288
+ LinkedList.move$(this.list, item, before);
289
+ LinkedItem.setStatus$(item, Mark.modified, 0);
290
+ (_a = this.diff) === null || _a === void 0 ? void 0 : _a.push(item);
291
+ }
292
+ thisIsRemoved(item) {
293
+ var _a;
294
+ if (item.list !== this.former)
295
+ throw misuse("cannot remove item which doesn't belong to former list");
296
+ LinkedList.remove$(this.list, item);
297
+ LinkedItem.setStatus$(item, Mark.removed, 0);
298
+ (_a = this.diff) === null || _a === void 0 ? void 0 : _a.push(item);
299
+ }
300
+ get lostItemCount() { return this.former.count; }
301
+ lostItems() { return this.former.items(); }
302
+ }
303
+ function grabExternalIfAny(list, item) {
304
+ let x = item.prev;
305
+ let before = undefined;
306
+ while (x !== undefined && x.isManagedExternally) {
307
+ LinkedItem.link$(list, x, before);
308
+ before = x;
309
+ x = x.prev;
310
+ }
311
+ return before;
312
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reactronic",
3
- "version": "0.95.25040",
3
+ "version": "0.95.25045",
4
4
  "description": "Reactronic - Transactional Reactive State Management",
5
5
  "publisher": "Nezaboodka Software",
6
6
  "license": "Apache-2.0",
@@ -1,20 +0,0 @@
1
- import { LinkedList, LinkedItem } from "./LinkedList.js";
2
- export declare class LinkedListRenovation<T extends LinkedItem<T>> {
3
- readonly list: LinkedList<T>;
4
- readonly diff: Array<T> | undefined;
5
- private lost$;
6
- private expected;
7
- private absent;
8
- constructor(list: LinkedList<T>, diff?: Array<T>);
9
- lookup(key: string | undefined): T | undefined;
10
- tryToProlonge(key: string, resolution?: {
11
- isDuplicate: boolean;
12
- }, error?: string): T | undefined;
13
- thisIsAdded(item: T, before?: T): T;
14
- thisIsModified(item: T): void;
15
- thisIsMoved(item: T, before: T | undefined): void;
16
- thisIsRemoved(item: T): void;
17
- get lostItemCount(): number;
18
- lostItems(): Generator<T>;
19
- done(error?: unknown): void;
20
- }
@@ -1,134 +0,0 @@
1
- import { misuse } from "./Dbg.js";
2
- import { LinkedList, LinkedItem, LinkedSubList, Mark } from "./LinkedList.js";
3
- export class LinkedListRenovation {
4
- constructor(list, diff) {
5
- if (list.former$ !== undefined)
6
- throw misuse("renovation is in progress already");
7
- const former = list.items$;
8
- this.list = list;
9
- this.diff = diff;
10
- this.lost$ = former;
11
- this.expected = former.first;
12
- this.absent = undefined;
13
- list.former$ = former;
14
- list.items$ = new LinkedSubList();
15
- }
16
- lookup(key) {
17
- let result = undefined;
18
- if (key !== undefined && key !== this.absent) {
19
- result = this.list.lookup(key);
20
- if (result !== undefined) {
21
- if (this.list.keyOf(result) !== key) {
22
- this.absent = key;
23
- result = undefined;
24
- }
25
- }
26
- else
27
- this.absent = key;
28
- }
29
- return result;
30
- }
31
- tryToProlonge(key, resolution, error) {
32
- var _a, _b;
33
- const list = this.list;
34
- if (!list.isRenovationInProgress)
35
- throw misuse(error !== null && error !== void 0 ? error : "renovation is no longer in progress");
36
- let x = this.expected;
37
- if (key !== (x ? list.keyOf(x) : undefined))
38
- x = this.lookup(key);
39
- if (x !== undefined) {
40
- const result = this.list.items$;
41
- if (x.list !== result) {
42
- const next = x.next;
43
- const expected = (_a = grabExternalIfAny(result, x)) !== null && _a !== void 0 ? _a : x;
44
- LinkedItem.link$(result, x, undefined);
45
- if (list.isStrictOrder && expected !== this.expected) {
46
- LinkedItem.setStatus$(x, Mark.modified, result.count);
47
- (_b = this.diff) === null || _b === void 0 ? void 0 : _b.push(x);
48
- }
49
- else
50
- LinkedItem.setStatus$(x, Mark.prolonged, result.count);
51
- this.expected = next;
52
- if (resolution)
53
- resolution.isDuplicate = false;
54
- }
55
- else if (resolution)
56
- resolution.isDuplicate = true;
57
- else
58
- throw misuse(`duplicate linked item key: ${key}`);
59
- }
60
- else if (resolution)
61
- resolution.isDuplicate = false;
62
- return x;
63
- }
64
- thisIsAdded(item, before) {
65
- var _a;
66
- this.list.add(item, before);
67
- LinkedItem.setStatus$(item, Mark.added, this.list.items$.count);
68
- this.absent = undefined;
69
- this.expected = undefined;
70
- (_a = this.diff) === null || _a === void 0 ? void 0 : _a.push(item);
71
- return item;
72
- }
73
- thisIsModified(item) {
74
- if (item.list !== this.list.items$)
75
- throw misuse("only prolonged items can be marked as modified");
76
- const m = item.mark;
77
- if (m === Mark.prolonged)
78
- LinkedItem.setStatus$(item, Mark.modified, item.rank);
79
- else if (m !== Mark.modified)
80
- throw misuse("item is renovated already and cannot be marked as modified");
81
- }
82
- thisIsMoved(item, before) {
83
- var _a;
84
- if (item.list !== this.list.former$)
85
- throw misuse("cannot move item which doesn't belong to former list");
86
- LinkedList.move$(this.list, item, before);
87
- LinkedItem.setStatus$(item, Mark.modified, 0);
88
- (_a = this.diff) === null || _a === void 0 ? void 0 : _a.push(item);
89
- }
90
- thisIsRemoved(item) {
91
- var _a;
92
- if (item.list !== this.list.former$)
93
- throw misuse("cannot remove item which doesn't belong to former list");
94
- LinkedList.remove$(this.list, item);
95
- LinkedItem.setStatus$(item, Mark.removed, 0);
96
- (_a = this.diff) === null || _a === void 0 ? void 0 : _a.push(item);
97
- }
98
- get lostItemCount() { return this.lost$.count; }
99
- lostItems() { return this.lost$.items(); }
100
- done(error) {
101
- const list = this.list;
102
- if (!list.isRenovationInProgress)
103
- throw misuse("renovation is ended already");
104
- const items = this.list.items$;
105
- const lost = this.lost$;
106
- if (error === undefined) {
107
- for (const x of lost.items()) {
108
- if (!x.isManagedExternally) {
109
- LinkedList.removeKey$(list, list.keyOf(x));
110
- LinkedItem.setStatus$(x, Mark.removed, 0);
111
- }
112
- else
113
- LinkedItem.link$(items, x, undefined);
114
- }
115
- }
116
- else {
117
- for (const x of lost.items()) {
118
- LinkedItem.link$(items, x, undefined);
119
- LinkedItem.setStatus$(x, Mark.prolonged, items.count);
120
- }
121
- }
122
- list.former$ = undefined;
123
- }
124
- }
125
- function grabExternalIfAny(list, item) {
126
- let x = item.prev;
127
- let before = undefined;
128
- while (x !== undefined && x.isManagedExternally) {
129
- LinkedItem.link$(list, x, before);
130
- before = x;
131
- x = x.prev;
132
- }
133
- return before;
134
- }