reactronic 0.21.601 → 0.22.101

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
@@ -196,7 +196,7 @@ class Component<P> extends React.Component<P> {
196
196
  @reaction // called immediately in response to changes
197
197
  ensureUpToDate(): void {
198
198
  if (this.shouldComponentUpdate())
199
- standalone(() => this.setState({})) // ask React to re-render
199
+ nontransactional(() => this.setState({})) // ask React to re-render
200
200
  } // ensureUpToDate is subscribed to render
201
201
 
202
202
  shouldComponentUpdate(): boolean {
@@ -208,7 +208,7 @@ class Component<P> extends React.Component<P> {
208
208
  }
209
209
 
210
210
  componentWillUnmount(): void {
211
- standalone(Rx.dispose, this)
211
+ Transaction.runAs({ standalone: true }, Rx.dispose, this)
212
212
  }
213
213
  }
214
214
  ```
@@ -310,7 +310,7 @@ function monitor(value: Monitor | null)
310
310
  function trace(value: Partial<TraceOptions>)
311
311
 
312
312
  function nonreactive<T>(func: F<T>, ...args: any[]): T
313
- function standalone<T>(func: F<T>, ...args: any[]): T
313
+ function nontransactional<T>(func: F<T>, ...args: any[]): T
314
314
  function sensitive<T>(sensitivity: Sensitivity, func: F<T>, ...args: any[]): T
315
315
 
316
316
  // Options, ObjectOptions, Kind, Reentrance, Monitor, TraceOptions, ProfilingOptions
@@ -421,7 +421,7 @@ class Transaction implements Worker {
421
421
  static run<T>(hint: string, func: F<T>, ...args: any[]): T
422
422
  static runEx<T>(hint: string, standalone: boolean, sidebyside: boolean,
423
423
  trace: Partial<TraceOptions | undefined>, func: F<T>, ...args: any[]): T
424
- static standalone<T>(func: F<T>, ...args: any[]): T
424
+ static nontransactional<T>(func: F<T>, ...args: any[]): T
425
425
  }
426
426
 
427
427
  // Controller
@@ -18,7 +18,7 @@ export declare class Rx {
18
18
  static setProfilingMode(enabled: boolean, options?: Partial<ProfilingOptions>): void;
19
19
  }
20
20
  export declare function nonreactive<T>(func: F<T>, ...args: any[]): T;
21
- export declare function standalone<T>(func: F<T>, ...args: any[]): T;
21
+ export declare function nontransactional<T>(func: F<T>, ...args: any[]): T;
22
22
  export declare function sensitive<T>(sensitivity: boolean, func: F<T>, ...args: any[]): T;
23
23
  export declare function unobservable(proto: object, prop: PropertyKey): any;
24
24
  export declare function transaction(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.options = exports.cached = exports.reaction = exports.transaction = exports.unobservable = exports.sensitive = exports.standalone = exports.nonreactive = exports.Rx = void 0;
3
+ exports.options = exports.cached = exports.reaction = exports.transaction = exports.unobservable = exports.sensitive = exports.nontransactional = exports.nonreactive = exports.Rx = void 0;
4
4
  const Dbg_1 = require("./util/Dbg");
5
5
  const Options_1 = require("./Options");
6
6
  const Data_1 = require("./impl/Data");
@@ -29,10 +29,10 @@ function nonreactive(func, ...args) {
29
29
  return Operation_1.OperationController.runWithin(undefined, func, ...args);
30
30
  }
31
31
  exports.nonreactive = nonreactive;
32
- function standalone(func, ...args) {
33
- return Operation_1.OperationController.runWithin(undefined, Transaction_1.Transaction.standalone, func, ...args);
32
+ function nontransactional(func, ...args) {
33
+ return Operation_1.OperationController.runWithin(undefined, Transaction_1.Transaction.nontransactional, func, ...args);
34
34
  }
35
- exports.standalone = standalone;
35
+ exports.nontransactional = nontransactional;
36
36
  function sensitive(sensitivity, func, ...args) {
37
37
  return Hooks_1.Hooks.sensitive(sensitivity, func, ...args);
38
38
  }
@@ -24,6 +24,7 @@ export interface ProfilingOptions {
24
24
  }
25
25
  export declare const TraceLevel: {
26
26
  ErrorsOnly: TraceOptions;
27
+ Reactions: TraceOptions;
27
28
  Transactions: TraceOptions;
28
29
  Operations: TraceOptions;
29
30
  Debug: TraceOptions;
@@ -20,6 +20,24 @@ exports.TraceLevel = {
20
20
  margin1: 0,
21
21
  margin2: 0,
22
22
  },
23
+ Reactions: {
24
+ silent: false,
25
+ transaction: false,
26
+ operation: false,
27
+ step: false,
28
+ monitor: false,
29
+ read: false,
30
+ write: false,
31
+ change: false,
32
+ obsolete: true,
33
+ error: true,
34
+ warning: true,
35
+ gc: false,
36
+ color: 37,
37
+ prefix: '',
38
+ margin1: 0,
39
+ margin2: 0,
40
+ },
23
41
  Transactions: {
24
42
  silent: false,
25
43
  transaction: true,
@@ -11,4 +11,4 @@ export { Snapshot } from './impl/Snapshot';
11
11
  export { Transaction } from './impl/Transaction';
12
12
  export { Monitor } from './impl/Monitor';
13
13
  export { TransactionJournal } from './impl/TransactionJournal';
14
- export { Rx, nonreactive, standalone, sensitive, unobservable, transaction, reaction, cached, options } from './Rx';
14
+ export { Rx, nonreactive, nontransactional, sensitive, unobservable, transaction, reaction, cached, options } from './Rx';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.options = exports.cached = exports.reaction = exports.transaction = exports.unobservable = exports.sensitive = exports.standalone = exports.nonreactive = exports.Rx = exports.TransactionJournal = exports.Monitor = exports.Transaction = exports.Snapshot = exports.ObservableObject = exports.ToggleRef = exports.Ref = exports.Controller = exports.TraceLevel = exports.Reentrance = exports.Kind = exports.SealedSet = exports.SealedMap = exports.SealedArray = exports.pause = exports.all = void 0;
3
+ exports.options = exports.cached = exports.reaction = exports.transaction = exports.unobservable = exports.sensitive = exports.nontransactional = exports.nonreactive = exports.Rx = exports.TransactionJournal = exports.Monitor = exports.Transaction = exports.Snapshot = exports.ObservableObject = exports.ToggleRef = exports.Ref = exports.Controller = exports.TraceLevel = exports.Reentrance = exports.Kind = exports.SealedSet = exports.SealedMap = exports.SealedArray = exports.pause = exports.all = void 0;
4
4
  var Utils_1 = require("./util/Utils");
5
5
  Object.defineProperty(exports, "all", { enumerable: true, get: function () { return Utils_1.all; } });
6
6
  Object.defineProperty(exports, "pause", { enumerable: true, get: function () { return Utils_1.pause; } });
@@ -32,7 +32,7 @@ Object.defineProperty(exports, "TransactionJournal", { enumerable: true, get: fu
32
32
  var Rx_1 = require("./Rx");
33
33
  Object.defineProperty(exports, "Rx", { enumerable: true, get: function () { return Rx_1.Rx; } });
34
34
  Object.defineProperty(exports, "nonreactive", { enumerable: true, get: function () { return Rx_1.nonreactive; } });
35
- Object.defineProperty(exports, "standalone", { enumerable: true, get: function () { return Rx_1.standalone; } });
35
+ Object.defineProperty(exports, "nontransactional", { enumerable: true, get: function () { return Rx_1.nontransactional; } });
36
36
  Object.defineProperty(exports, "sensitive", { enumerable: true, get: function () { return Rx_1.sensitive; } });
37
37
  Object.defineProperty(exports, "unobservable", { enumerable: true, get: function () { return Rx_1.unobservable; } });
38
38
  Object.defineProperty(exports, "transaction", { enumerable: true, get: function () { return Rx_1.transaction; } });
@@ -18,12 +18,13 @@ export interface Observer {
18
18
  readonly observables: Map<Observable, MemberInfo> | undefined;
19
19
  readonly obsoleteSince: number;
20
20
  hint(nop?: boolean): string;
21
- markObsoleteDueTo(observable: Observable, cause: MemberInfo, since: number, reactions: Observer[]): void;
21
+ markObsoleteDueTo(observable: Observable, memberName: MemberName, snapshot: AbstractSnapshot, holder: ObjectHolder, outer: string, since: number, reactions: Observer[]): void;
22
22
  runIfNotUpToDate(now: boolean, nothrow: boolean): void;
23
23
  }
24
24
  export declare type MemberName = PropertyKey;
25
25
  export interface MemberInfo {
26
- readonly revision: ObjectRevision;
26
+ readonly holder: ObjectHolder;
27
+ readonly snapshot: AbstractSnapshot;
27
28
  readonly memberName: MemberName;
28
29
  readonly usageCount: number;
29
30
  }
@@ -33,7 +34,7 @@ export declare class ObjectRevision {
33
34
  revision: ObjectRevision;
34
35
  };
35
36
  readonly data: any;
36
- readonly changes: Map<MemberName, Observer>;
37
+ readonly changes: Set<MemberName>;
37
38
  readonly conflicts: Map<MemberName, ObjectRevision>;
38
39
  constructor(snapshot: AbstractSnapshot, prev: ObjectRevision | undefined, data: object);
39
40
  }
@@ -16,7 +16,7 @@ class ObjectRevision {
16
16
  this.snapshot = snapshot;
17
17
  this.prev = { revision: prev || this };
18
18
  this.data = data;
19
- this.changes = new Map();
19
+ this.changes = new Set();
20
20
  this.conflicts = new Map();
21
21
  if (Dbg_1.Dbg.isOn)
22
22
  Object.freeze(this);
@@ -1,7 +1,7 @@
1
1
  import { F } from '../util/Utils';
2
2
  import { MemberOptions } from '../Options';
3
3
  import { Controller } from '../Controller';
4
- import { ObjectRevision, MemberName, ObjectHolder, Observable, Observer, MemberInfo } from './Data';
4
+ import { MemberName, ObjectHolder, Observable, Observer, MemberInfo, AbstractSnapshot } from './Data';
5
5
  import { Transaction } from './Transaction';
6
6
  import { OptionsImpl } from './Hooks';
7
7
  export declare class OperationController extends Controller<any> {
@@ -39,18 +39,18 @@ declare class Operation extends Observable implements Observer {
39
39
  readonly margin: number;
40
40
  readonly transaction: Transaction;
41
41
  readonly controller: OperationController;
42
- readonly revision: ObjectRevision;
42
+ readonly snapshot: AbstractSnapshot;
43
43
  observables: Map<Observable, MemberInfo> | undefined;
44
44
  options: OptionsImpl;
45
- cause: MemberInfo | undefined;
45
+ cause: string | undefined;
46
46
  args: any[];
47
47
  result: any;
48
48
  error: any;
49
49
  started: number;
50
- obsoleteDueTo: MemberInfo | undefined;
50
+ obsoleteDueTo: string | undefined;
51
51
  obsoleteSince: number;
52
52
  successor: Operation | undefined;
53
- constructor(controller: OperationController, revision: ObjectRevision, prev: Operation | OptionsImpl);
53
+ constructor(controller: OperationController, snapshot: AbstractSnapshot, prev: Operation | OptionsImpl);
54
54
  get isOperation(): boolean;
55
55
  get selfSnapshotId(): number;
56
56
  hint(): string;
@@ -61,7 +61,7 @@ declare class Operation extends Observable implements Observer {
61
61
  dependencies(): string[];
62
62
  wrap<T>(func: F<T>): F<T>;
63
63
  run(proxy: any, args: any[] | undefined): void;
64
- markObsoleteDueTo(observable: Observable, cause: MemberInfo, since: number, reactions: Observer[]): void;
64
+ markObsoleteDueTo(observable: Observable, memberName: MemberName, snapshot: AbstractSnapshot, holder: ObjectHolder, outer: string, since: number, reactions: Observer[]): void;
65
65
  runIfNotUpToDate(now: boolean, nothrow: boolean): void;
66
66
  isNotUpToDate(): boolean;
67
67
  reenterOver(head: Operation): this;
@@ -79,7 +79,7 @@ declare class Operation extends Observable implements Observer {
79
79
  private static propagateAllChangesThroughSubscriptions;
80
80
  private static revokeAllSubscriptions;
81
81
  private static propagateMemberChangeThroughSubscriptions;
82
- private static enqueueDetectedReactions;
82
+ private static enqueueReactionsToRun;
83
83
  private static runQueuedReactionsLoop;
84
84
  private unsubscribeFromAllObservables;
85
85
  private subscribeTo;
@@ -12,7 +12,7 @@ const Hooks_1 = require("./Hooks");
12
12
  const TransactionJournal_1 = require("./TransactionJournal");
13
13
  const ROOT_ARGS = [];
14
14
  const ROOT_HOLDER = new Data_1.ObjectHolder(undefined, undefined, Hooks_1.Hooks.proxy, Snapshot_1.ROOT_REV, 'root-holder');
15
- const ROOT_TRIGGER = { revision: Snapshot_1.ROOT_REV, memberName: 'root-trigger', usageCount: 0 };
15
+ const INITIAL_CAUSE = 'initial';
16
16
  class OperationController extends Controller_1.Controller {
17
17
  constructor(ownHolder, memberName) {
18
18
  super();
@@ -36,7 +36,7 @@ class OperationController extends Controller_1.Controller {
36
36
  const op = oc.operation;
37
37
  const opts = op.options;
38
38
  if (!oc.isUpToDate && oc.revision.data[Data_1.Meta.Disposed] === undefined
39
- && (!weak || op.cause === ROOT_TRIGGER || !op.successor ||
39
+ && (!weak || op.cause === INITIAL_CAUSE || !op.successor ||
40
40
  op.successor.transaction.isFinished)) {
41
41
  const outerOpts = (_a = Operation.current) === null || _a === void 0 ? void 0 : _a.options;
42
42
  const standalone = weak || opts.standalone || opts.kind === Options_1.Kind.Reaction ||
@@ -45,13 +45,13 @@ class OperationController extends Controller_1.Controller {
45
45
  oc.revision.prev.revision !== Snapshot_1.ROOT_REV));
46
46
  const token = opts.noSideEffects ? this : undefined;
47
47
  const oc2 = this.run(oc, standalone, opts, token, args);
48
- const ctx2 = oc2.operation.revision.snapshot;
48
+ const ctx2 = oc2.operation.snapshot;
49
49
  if (!weak || ctx === ctx2 || (ctx2.sealed && ctx.timestamp >= ctx2.timestamp))
50
50
  oc = oc2;
51
51
  }
52
52
  else if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.operation && (opts.trace === undefined ||
53
53
  opts.trace.operation === undefined || opts.trace.operation === true))
54
- Dbg_1.Dbg.log(Transaction_1.Transaction.current.isFinished ? '' : '║', ' (=)', `${Snapshot_1.Dump.rev(oc.revision, this.memberName)} result is reused from T${oc.operation.transaction.id}[${oc.operation.transaction.hint}]`);
54
+ Dbg_1.Dbg.log(Transaction_1.Transaction.current.isFinished ? '' : '║', ' (=)', `${Snapshot_1.Dump.rev2(oc.operation.controller.ownHolder, oc.snapshot, this.memberName)} result is reused from T${oc.operation.transaction.id}[${oc.operation.transaction.hint}]`);
55
55
  const t = oc.operation;
56
56
  Snapshot_1.Snapshot.markUsed(t, oc.revision, this.memberName, this.ownHolder, t.options.kind, weak);
57
57
  return t;
@@ -108,8 +108,8 @@ class OperationController extends Controller_1.Controller {
108
108
  const ctx = Snapshot_1.Snapshot.current();
109
109
  const r = ctx.seekRevision(this.ownHolder, this.memberName);
110
110
  const op = this.peekFromRevision(r, args);
111
- const isValid = op.options.kind !== Options_1.Kind.Transaction && op.cause !== ROOT_TRIGGER &&
112
- (ctx === op.revision.snapshot || ctx.timestamp < op.obsoleteSince) &&
111
+ const isValid = op.options.kind !== Options_1.Kind.Transaction && op.cause !== INITIAL_CAUSE &&
112
+ (ctx === op.snapshot || ctx.timestamp < op.obsoleteSince) &&
113
113
  (!op.options.sensitiveArgs || args === undefined ||
114
114
  op.args.length === args.length && op.args.every((t, i) => t === args[i])) ||
115
115
  r.data[Data_1.Meta.Disposed] !== undefined;
@@ -126,8 +126,8 @@ class OperationController extends Controller_1.Controller {
126
126
  const ctx = Snapshot_1.Snapshot.edit();
127
127
  const r = ctx.getEditableRevision(h, m, Data_1.Meta.Holder, this);
128
128
  let op = this.peekFromRevision(r, undefined);
129
- if (op.revision !== r) {
130
- const op2 = new Operation(this, r, op);
129
+ if (op.snapshot !== r.snapshot) {
130
+ const op2 = new Operation(this, r.snapshot, op);
131
131
  r.data[m] = op2.reenterOver(op);
132
132
  ctx.bumpBy(r.prev.revision.snapshot.timestamp);
133
133
  Snapshot_1.Snapshot.markEdited(op, op2, true, r, m, h);
@@ -147,10 +147,10 @@ class OperationController extends Controller_1.Controller {
147
147
  let op2 = r2.data[m];
148
148
  if (op2.controller !== this) {
149
149
  r2 = Snapshot_1.Snapshot.edit().getEditableRevision(h, m, Data_1.Meta.Holder, this);
150
- const t = new Operation(this, r2, op2);
150
+ const t = new Operation(this, r2.snapshot, op2);
151
151
  if (args)
152
152
  t.args = args;
153
- t.cause = ROOT_TRIGGER;
153
+ t.cause = INITIAL_CAUSE;
154
154
  r2.data[m] = t;
155
155
  Snapshot_1.Snapshot.markEdited(op2, t, true, r2, m, h);
156
156
  op2 = t;
@@ -188,17 +188,17 @@ class OperationController extends Controller_1.Controller {
188
188
  static markObsolete(self) {
189
189
  const oc = self.peek(undefined);
190
190
  const ctx = oc.snapshot;
191
- oc.operation.markObsoleteDueTo(oc.operation, { revision: Snapshot_1.ROOT_REV, memberName: self.memberName, usageCount: 0 }, ctx.timestamp, ctx.reactions);
191
+ oc.operation.markObsoleteDueTo(oc.operation, self.memberName, Snapshot_1.ROOT_REV.snapshot, ROOT_HOLDER, INITIAL_CAUSE, ctx.timestamp, ctx.reactions);
192
192
  }
193
193
  }
194
194
  exports.OperationController = OperationController;
195
195
  class Operation extends Data_1.Observable {
196
- constructor(controller, revision, prev) {
196
+ constructor(controller, snapshot, prev) {
197
197
  super(undefined);
198
198
  this.margin = Operation.current ? Operation.current.margin + 1 : 1;
199
199
  this.transaction = Transaction_1.Transaction.current;
200
200
  this.controller = controller;
201
- this.revision = revision;
201
+ this.snapshot = snapshot;
202
202
  this.observables = new Map();
203
203
  if (prev instanceof Operation) {
204
204
  this.options = prev.options;
@@ -216,28 +216,24 @@ class Operation extends Data_1.Observable {
216
216
  this.successor = undefined;
217
217
  }
218
218
  get isOperation() { return true; }
219
- get selfSnapshotId() { return this.revision.snapshot.id; }
220
- hint() { return `${Snapshot_1.Dump.rev(this.revision, this.controller.memberName)}`; }
219
+ get selfSnapshotId() { return this.snapshot.id; }
220
+ hint() { return `${Snapshot_1.Dump.rev2(this.controller.ownHolder, this.snapshot, this.controller.memberName)}`; }
221
221
  get order() { return this.options.order; }
222
222
  get ['#this']() {
223
223
  return `Operation: ${this.why()}`;
224
224
  }
225
225
  why() {
226
- let ms = Date.now();
227
- const prev = this.revision.prev.revision.data[this.controller.memberName];
228
- if (prev instanceof Operation)
229
- ms = prev.started !== 0 ? Math.abs(this.started || ms) - Math.abs(prev.started) : Infinity;
230
- let trigger;
226
+ let cause;
231
227
  if (this.cause)
232
- trigger = ` << ${propagationHint(this.cause, true).join(' << ')}`;
228
+ cause = ` << ${this.cause}`;
233
229
  else if (this.controller.options.kind === Options_1.Kind.Transaction)
234
- trigger = ' << operation';
230
+ cause = ' << operation';
235
231
  else
236
- trigger = ` << T${this.revision.snapshot.id}[${this.revision.snapshot.hint}]`;
237
- return `${this.hint()}${trigger} (${ms !== Infinity ? `${ms}ms since previous run` : 'initial run'})`;
232
+ cause = ` << T${this.snapshot.id}[${this.snapshot.hint}]`;
233
+ return `${this.hint()}${cause}`;
238
234
  }
239
235
  briefWhy() {
240
- return this.cause ? propagationHint(this.cause, false)[0] : ROOT_HOLDER.hint;
236
+ return this.why();
241
237
  }
242
238
  dependencies() {
243
239
  throw (0, Dbg_1.misuse)('not implemented yet');
@@ -266,31 +262,33 @@ class Operation extends Data_1.Observable {
266
262
  else
267
263
  this.result = Promise.reject(this.error);
268
264
  }
269
- markObsoleteDueTo(observable, cause, since, reactions) {
265
+ markObsoleteDueTo(observable, memberName, snapshot, holder, outer, since, reactions) {
270
266
  var _a, _b, _c;
271
267
  if (this.observables !== undefined) {
272
- if (observable.isOperation || this !== cause.revision.changes.get(cause.memberName)) {
268
+ const skip = !observable.isOperation &&
269
+ snapshot === this.snapshot;
270
+ if (!skip) {
271
+ const why = `${Snapshot_1.Dump.rev2(holder, snapshot, memberName)} << ${outer}`;
273
272
  this.unsubscribeFromAllObservables();
274
- this.obsoleteDueTo = cause;
273
+ this.obsoleteDueTo = why;
275
274
  this.obsoleteSince = since;
276
275
  const isReaction = this.options.kind === Options_1.Kind.Reaction;
277
276
  if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.obsolete || ((_a = this.options.trace) === null || _a === void 0 ? void 0 : _a.obsolete)))
278
- Dbg_1.Dbg.log(Dbg_1.Dbg.trace.transaction && !Snapshot_1.Snapshot.current().sealed ? '║' : ' ', isReaction ? '█' : '▒', isReaction && cause.revision === Snapshot_1.ROOT_REV
277
+ Dbg_1.Dbg.log(Dbg_1.Dbg.trace.transaction && !Snapshot_1.Snapshot.current().sealed ? '║' : ' ', isReaction ? '█' : '▒', isReaction && snapshot === Snapshot_1.ROOT_REV.snapshot
279
278
  ? `${this.hint()} is a reaction and will run automatically (order ${this.options.order})`
280
- : `${this.hint()} is obsolete due to ${Snapshot_1.Dump.rev(cause.revision, cause.memberName)} since v${since}${isReaction ? ` and will run automatically (order ${this.options.order})` : ''}`);
279
+ : `${this.hint()} is obsolete due to ${Snapshot_1.Dump.rev2(holder, snapshot, memberName)} since v${since}${isReaction ? ` and will run automatically (order ${this.options.order})` : ''}`);
281
280
  if (isReaction)
282
281
  reactions.push(this);
283
282
  else
284
- (_b = this.observers) === null || _b === void 0 ? void 0 : _b.forEach(c => c.markObsoleteDueTo(this, { revision: this.revision, memberName: this.controller.memberName, usageCount: 0 }, since, reactions));
283
+ (_b = this.observers) === null || _b === void 0 ? void 0 : _b.forEach(c => c.markObsoleteDueTo(this, this.controller.memberName, this.snapshot, this.controller.ownHolder, why, since, reactions));
285
284
  const tran = this.transaction;
286
- if (tran.snapshot === cause.revision.snapshot) {
287
- (0, Dbg_1.misuse)('not implemented: running reactions within original transaction');
285
+ if (tran.snapshot === snapshot) {
288
286
  }
289
287
  else if (!tran.isFinished && this !== observable)
290
- tran.cancel(new Error(`T${tran.id}[${tran.hint}] is canceled due to obsolete ${Snapshot_1.Dump.rev(cause.revision, cause.memberName)} changed by T${cause.revision.snapshot.id}[${cause.revision.snapshot.hint}]`), null);
288
+ tran.cancel(new Error(`T${tran.id}[${tran.hint}] is canceled due to obsolete ${Snapshot_1.Dump.rev2(holder, snapshot, memberName)} changed by T${snapshot.id}[${snapshot.hint}]`), null);
291
289
  }
292
290
  else if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.obsolete || ((_c = this.options.trace) === null || _c === void 0 ? void 0 : _c.obsolete)))
293
- Dbg_1.Dbg.log(' ', 'x', `${this.hint()} is not obsolete due to its own change to ${Snapshot_1.Dump.rev(cause.revision, cause.memberName)}`);
291
+ Dbg_1.Dbg.log(' ', 'x', `${this.hint()} is not obsolete due to its own change to ${Snapshot_1.Dump.rev2(holder, snapshot, memberName)}`);
294
292
  }
295
293
  }
296
294
  runIfNotUpToDate(now, nothrow) {
@@ -407,6 +405,7 @@ class Operation extends Data_1.Observable {
407
405
  Dbg_1.Dbg.log('║', `${op}`, `${this.hint()} ${message}`, ms, highlight);
408
406
  if (ms > (main ? Hooks_1.Hooks.mainThreadBlockingWarningThreshold : Hooks_1.Hooks.asyncActionDurationWarningThreshold))
409
407
  Dbg_1.Dbg.log('', '[!]', this.why(), ms, main ? ' *** main thread is too busy ***' : ' *** async is too long ***');
408
+ this.cause = undefined;
410
409
  if (this.options.monitor)
411
410
  this.monitorLeave(this.options.monitor);
412
411
  }
@@ -419,7 +418,7 @@ class Operation extends Data_1.Observable {
419
418
  OperationController.runWithin(undefined, Transaction_1.Transaction.runAs, options, Monitor_1.MonitorImpl.enter, mon, this.transaction);
420
419
  }
421
420
  monitorLeave(mon) {
422
- Transaction_1.Transaction.standalone(() => {
421
+ Transaction_1.Transaction.nontransactional(() => {
423
422
  const leave = () => {
424
423
  const options = {
425
424
  hint: 'Monitor.leave',
@@ -445,25 +444,26 @@ class Operation extends Data_1.Observable {
445
444
  static markUsed(observable, r, m, h, kind, weak) {
446
445
  if (kind !== Options_1.Kind.Transaction) {
447
446
  const op = Operation.current;
448
- if (op && op.options.kind !== Options_1.Kind.Transaction && m !== Data_1.Meta.Holder) {
447
+ if (op && op.options.kind !== Options_1.Kind.Transaction &&
448
+ op.transaction === Transaction_1.Transaction.current && m !== Data_1.Meta.Holder) {
449
449
  const ctx = Snapshot_1.Snapshot.current();
450
450
  if (ctx !== r.snapshot)
451
451
  ctx.bumpBy(r.snapshot.timestamp);
452
452
  const t = weak ? -1 : ctx.timestamp;
453
453
  if (!op.subscribeTo(observable, r, m, h, t))
454
- op.markObsoleteDueTo(observable, { revision: r, memberName: m, usageCount: 0 }, ctx.timestamp, ctx.reactions);
454
+ op.markObsoleteDueTo(observable, m, r.snapshot, h, INITIAL_CAUSE, ctx.timestamp, ctx.reactions);
455
455
  }
456
456
  }
457
457
  }
458
458
  static markEdited(oldValue, newValue, edited, r, m, h) {
459
- edited ? r.changes.set(m, Operation.current) : r.changes.delete(m);
459
+ edited ? r.changes.add(m) : r.changes.delete(m);
460
460
  if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.write)
461
- edited ? Dbg_1.Dbg.log('║', ' ✎', `${Snapshot_1.Dump.rev(r, m)} is changed from ${valueHint(oldValue, m)} to ${valueHint(newValue, m)}`) : Dbg_1.Dbg.log('║', ' ✎', `${Snapshot_1.Dump.rev(r, m)} is changed from ${valueHint(oldValue, m)} to ${valueHint(newValue, m)}`, undefined, ' (same as previous)');
461
+ edited ? Dbg_1.Dbg.log('║', ' ✎', `${Snapshot_1.Dump.rev2(h, r.snapshot, m)} is changed from ${valueHint(oldValue, m)} to ${valueHint(newValue, m)}`) : Dbg_1.Dbg.log('║', ' ✎', `${Snapshot_1.Dump.rev2(h, r.snapshot, m)} is changed from ${valueHint(oldValue, m)} to ${valueHint(newValue, m)}`, undefined, ' (same as previous)');
462
462
  }
463
463
  static isConflicting(oldValue, newValue) {
464
464
  let result = oldValue !== newValue;
465
465
  if (result)
466
- result = oldValue instanceof Operation && oldValue.cause !== ROOT_TRIGGER;
466
+ result = oldValue instanceof Operation && oldValue.cause !== INITIAL_CAUSE;
467
467
  return result;
468
468
  }
469
469
  static propagateAllChangesThroughSubscriptions(snapshot) {
@@ -489,26 +489,30 @@ class Operation extends Data_1.Observable {
489
489
  if (reactions) {
490
490
  const prev = r.prev.revision.data[m];
491
491
  if (prev !== undefined && prev instanceof Data_1.Observable) {
492
- const cause = { revision: r, memberName: m, usageCount: 0 };
492
+ const why = `T${r.snapshot.id}[${r.snapshot.hint}]`;
493
493
  if (prev instanceof Operation) {
494
494
  if ((prev.obsoleteSince === Snapshot_1.MAX_TIMESTAMP || prev.obsoleteSince <= 0)) {
495
- prev.obsoleteDueTo = cause;
495
+ prev.obsoleteDueTo = why;
496
496
  prev.obsoleteSince = timestamp;
497
497
  prev.unsubscribeFromAllObservables();
498
498
  }
499
- const opponent = prev.successor;
500
- if (opponent !== curr && opponent && !opponent.transaction.isFinished)
501
- opponent.transaction.cancel(new Error(`T${opponent.transaction.id}[${opponent.transaction.hint}] is canceled by T${r.snapshot.id}[${r.snapshot.hint}] and will not run anymore`), null);
499
+ const prevSuccessor = prev.successor;
500
+ if (prevSuccessor !== curr) {
501
+ if (prevSuccessor && !prevSuccessor.transaction.isFinished)
502
+ prevSuccessor.transaction.cancel(new Error(`T${prevSuccessor.transaction.id}[${prevSuccessor.transaction.hint}] is canceled by T${r.snapshot.id}[${r.snapshot.hint}] and will not run anymore`), null);
503
+ }
504
+ else
505
+ prev.successor = undefined;
502
506
  }
503
- (_a = prev.observers) === null || _a === void 0 ? void 0 : _a.forEach(c => c.markObsoleteDueTo(prev, cause, timestamp, reactions));
507
+ (_a = prev.observers) === null || _a === void 0 ? void 0 : _a.forEach(c => c.markObsoleteDueTo(prev, m, r.snapshot, h, why, timestamp, reactions));
504
508
  }
505
509
  }
506
510
  if (curr instanceof Operation) {
507
- if (curr.revision === r && curr.observables !== undefined) {
511
+ if (curr.snapshot === r.snapshot && curr.observables !== undefined) {
508
512
  if (Hooks_1.Hooks.repetitiveUsageWarningThreshold < Number.MAX_SAFE_INTEGER) {
509
513
  curr.observables.forEach((hint, v) => {
510
514
  if (hint.usageCount > Hooks_1.Hooks.repetitiveUsageWarningThreshold)
511
- Dbg_1.Dbg.log('', '[!]', `${curr.hint()} uses ${Snapshot_1.Dump.rev(hint.revision, hint.memberName)} ${hint.usageCount} times (consider remembering it in a local variable)`, 0, ' *** WARNING ***');
515
+ Dbg_1.Dbg.log('', '[!]', `${curr.hint()} uses ${Snapshot_1.Dump.rev2(hint.holder, hint.snapshot, hint.memberName)} ${hint.usageCount} times (consider remembering it in a local variable)`, 0, ' *** WARNING ***');
512
516
  });
513
517
  }
514
518
  if (unsubscribe)
@@ -524,10 +528,10 @@ class Operation extends Data_1.Observable {
524
528
  curr.observers = undefined;
525
529
  }
526
530
  }
527
- static enqueueDetectedReactions(snapshot) {
531
+ static enqueueReactionsToRun(reactions) {
528
532
  const queue = Operation.queuedReactions;
529
533
  const isReactionLoopRequired = queue.length === 0;
530
- for (const r of snapshot.reactions)
534
+ for (const r of reactions)
531
535
  queue.push(r);
532
536
  if (isReactionLoopRequired)
533
537
  OperationController.runWithin(undefined, Operation.runQueuedReactionsLoop);
@@ -548,7 +552,7 @@ class Operation extends Data_1.Observable {
548
552
  var _a;
549
553
  value.observers.delete(this);
550
554
  if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_a = this.options.trace) === null || _a === void 0 ? void 0 : _a.read)))
551
- Dbg_1.Dbg.log(Dbg_1.Dbg.trace.transaction && !Snapshot_1.Snapshot.current().sealed ? '║' : ' ', '-', `${this.hint()} is unsubscribed from ${Snapshot_1.Dump.rev(hint.revision, hint.memberName)}`);
555
+ Dbg_1.Dbg.log(Dbg_1.Dbg.trace.transaction && !Snapshot_1.Snapshot.current().sealed ? '║' : ' ', '-', `${this.hint()} is unsubscribed from ${Snapshot_1.Dump.rev2(hint.holder, hint.snapshot, hint.memberName)}`);
552
556
  });
553
557
  this.observables = undefined;
554
558
  }
@@ -564,18 +568,18 @@ class Operation extends Data_1.Observable {
564
568
  if (this.observables !== undefined) {
565
569
  if (!observable.observers)
566
570
  observable.observers = new Set();
567
- const info = { revision: r, memberName: m, usageCount: times };
571
+ const info = { holder: h, snapshot: r.snapshot, memberName: m, usageCount: times };
568
572
  observable.observers.add(this);
569
573
  this.observables.set(observable, info);
570
574
  if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_a = this.options.trace) === null || _a === void 0 ? void 0 : _a.read)))
571
- Dbg_1.Dbg.log('║', ' ∞ ', `${this.hint()} is subscribed to ${Snapshot_1.Dump.rev(r, m)}${info.usageCount > 1 ? ` (${info.usageCount} times)` : ''}`);
575
+ Dbg_1.Dbg.log('║', ' ∞ ', `${this.hint()} is subscribed to ${Snapshot_1.Dump.rev2(h, r.snapshot, m)}${info.usageCount > 1 ? ` (${info.usageCount} times)` : ''}`);
572
576
  }
573
577
  else if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_b = this.options.trace) === null || _b === void 0 ? void 0 : _b.read)))
574
- Dbg_1.Dbg.log('║', ' x ', `${this.hint()} is obsolete and is NOT subscribed to ${Snapshot_1.Dump.rev(r, m)}`);
578
+ Dbg_1.Dbg.log('║', ' x ', `${this.hint()} is obsolete and is NOT subscribed to ${Snapshot_1.Dump.rev2(h, r.snapshot, m)}`);
575
579
  }
576
580
  else {
577
581
  if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_c = this.options.trace) === null || _c === void 0 ? void 0 : _c.read)))
578
- Dbg_1.Dbg.log('║', ' x ', `${this.hint()} is NOT subscribed to already obsolete ${Snapshot_1.Dump.rev(r, m)}`);
582
+ Dbg_1.Dbg.log('║', ' x ', `${this.hint()} is NOT subscribed to already obsolete ${Snapshot_1.Dump.rev2(h, r.snapshot, m)}`);
579
583
  }
580
584
  return ok;
581
585
  }
@@ -598,7 +602,7 @@ class Operation extends Data_1.Observable {
598
602
  let op = initial[m];
599
603
  const ctl = op ? op.controller : new OperationController(ROOT_HOLDER, m);
600
604
  const opts = op ? op.options : Hooks_1.OptionsImpl.INITIAL;
601
- initial[m] = op = new Operation(ctl, Snapshot_1.ROOT_REV, new Hooks_1.OptionsImpl(getter, setter, opts, options, implicit));
605
+ initial[m] = op = new Operation(ctl, Snapshot_1.ROOT_REV.snapshot, new Hooks_1.OptionsImpl(getter, setter, opts, options, implicit));
602
606
  if (op.options.kind === Options_1.Kind.Reaction && op.options.throttling < Number.MAX_SAFE_INTEGER) {
603
607
  const reactions = Data_1.Meta.acquire(proto, Data_1.Meta.Reactions);
604
608
  reactions[m] = op;
@@ -611,14 +615,13 @@ class Operation extends Data_1.Observable {
611
615
  }
612
616
  static init() {
613
617
  Object.freeze(ROOT_ARGS);
614
- Object.freeze(ROOT_TRIGGER);
615
618
  Dbg_1.Dbg.getMergedTraceOptions = getMergedTraceOptions;
616
619
  Snapshot_1.Snapshot.markUsed = Operation.markUsed;
617
620
  Snapshot_1.Snapshot.markEdited = Operation.markEdited;
618
621
  Snapshot_1.Snapshot.isConflicting = Operation.isConflicting;
619
622
  Snapshot_1.Snapshot.propagateAllChangesThroughSubscriptions = Operation.propagateAllChangesThroughSubscriptions;
620
623
  Snapshot_1.Snapshot.revokeAllSubscriptions = Operation.revokeAllSubscriptions;
621
- Snapshot_1.Snapshot.enqueueDetectedReactions = Operation.enqueueDetectedReactions;
624
+ Snapshot_1.Snapshot.enqueueReactionsToRun = Operation.enqueueReactionsToRun;
622
625
  Hooks_1.Hooks.createControllerAndGetHook = Operation.createControllerAndGetHook;
623
626
  Hooks_1.Hooks.rememberOperationOptions = Operation.rememberOperationOptions;
624
627
  Promise.prototype.then = reactronicHookedThen;
@@ -647,18 +650,6 @@ class Operation extends Data_1.Observable {
647
650
  Operation.current = undefined;
648
651
  Operation.queuedReactions = [];
649
652
  Operation.deferredReactions = [];
650
- function propagationHint(cause, full) {
651
- const result = [];
652
- let observable = cause.revision.data[cause.memberName];
653
- while (observable instanceof Operation && observable.obsoleteDueTo) {
654
- full && result.push(Snapshot_1.Dump.rev(cause.revision, cause.memberName));
655
- cause = observable.obsoleteDueTo;
656
- observable = cause.revision.data[cause.memberName];
657
- }
658
- result.push(Snapshot_1.Dump.rev(cause.revision, cause.memberName));
659
- full && result.push(cause.revision.snapshot.hint);
660
- return result;
661
- }
662
653
  function valueHint(value, m) {
663
654
  let result = '';
664
655
  if (Array.isArray(value))
@@ -668,7 +659,7 @@ function valueHint(value, m) {
668
659
  else if (value instanceof Map)
669
660
  result = `Map(${value.size})`;
670
661
  else if (value instanceof Operation)
671
- result = `${Snapshot_1.Dump.rev(value.revision, m)}`;
662
+ result = `${Snapshot_1.Dump.rev2(value.controller.ownHolder, value.snapshot, m)}`;
672
663
  else if (value === Data_1.Meta.Disposed)
673
664
  result = '<disposed>';
674
665
  else if (value !== undefined && value !== null)
@@ -17,8 +17,8 @@ export declare class Snapshot implements AbstractSnapshot {
17
17
  get timestamp(): number;
18
18
  private stamp;
19
19
  private bumper;
20
- readonly changeset: Map<ObjectHolder, ObjectRevision>;
21
- readonly reactions: Observer[];
20
+ changeset: Map<ObjectHolder, ObjectRevision>;
21
+ reactions: Observer[];
22
22
  sealed: boolean;
23
23
  constructor(options: SnapshotOptions | null);
24
24
  static current: () => Snapshot;
@@ -28,7 +28,7 @@ export declare class Snapshot implements AbstractSnapshot {
28
28
  static isConflicting: (oldValue: any, newValue: any) => boolean;
29
29
  static propagateAllChangesThroughSubscriptions: (snapshot: Snapshot) => void;
30
30
  static revokeAllSubscriptions: (snapshot: Snapshot) => void;
31
- static enqueueDetectedReactions: (snapshot: Snapshot) => void;
31
+ static enqueueReactionsToRun: (reactions: Array<Observer>) => void;
32
32
  seekRevision(h: ObjectHolder, m: MemberName): ObjectRevision;
33
33
  getCurrentRevision(h: ObjectHolder, m: MemberName): ObjectRevision;
34
34
  getEditableRevision(h: ObjectHolder, m: MemberName, value: any, token?: any): ObjectRevision;
@@ -40,17 +40,17 @@ export declare class Snapshot implements AbstractSnapshot {
40
40
  bumpBy(timestamp: number): void;
41
41
  rebase(): ObjectRevision[] | undefined;
42
42
  private static merge;
43
- applyOrDiscard(error?: any): void;
43
+ applyOrDiscard(error?: any): Array<Observer>;
44
44
  static sealObjectRevision(h: ObjectHolder, r: ObjectRevision): void;
45
45
  static sealObservable(observable: Observable | symbol, m: MemberName, typeName: string): void;
46
- collectGarbage(): void;
47
46
  static freezeObjectRevision(r: ObjectRevision): ObjectRevision;
48
- private triggerGarbageCollection;
47
+ triggerGarbageCollection(): void;
49
48
  private unlinkHistory;
50
49
  static _init(): void;
51
50
  }
52
51
  export declare class Dump {
53
52
  static obj(h: ObjectHolder | undefined, m?: MemberName | undefined, stamp?: number, op?: number, xop?: number, typeless?: boolean): string;
53
+ static rev2(h: ObjectHolder, s: AbstractSnapshot, m?: MemberName, value?: Observable): string;
54
54
  static rev(r: ObjectRevision, m?: MemberName): string;
55
55
  static conflicts(conflicts: ObjectRevision[]): string;
56
56
  static conflictingMemberHint(m: MemberName, ours: ObjectRevision, theirs: ObjectRevision): string;
@@ -27,6 +27,8 @@ Object.defineProperty(Data_1.ObjectHolder.prototype, '#this', {
27
27
  return result;
28
28
  },
29
29
  });
30
+ const EMPTY_ARRAY = Object.freeze([]);
31
+ const EMPTY_MAP = Utils_1.Utils.freezeMap(new Map());
30
32
  class Snapshot {
31
33
  constructor(options) {
32
34
  this.id = ++Snapshot.idGen;
@@ -128,14 +130,14 @@ class Snapshot {
128
130
  if (this.changeset.size > 0) {
129
131
  this.changeset.forEach((r, h) => {
130
132
  if (r.prev.revision !== h.head) {
131
- const merged = Snapshot.merge(r, h.head);
133
+ const merged = Snapshot.merge(h, r);
132
134
  if (r.conflicts.size > 0) {
133
135
  if (!conflicts)
134
136
  conflicts = [];
135
137
  conflicts.push(r);
136
138
  }
137
139
  if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.transaction)
138
- Dbg_1.Dbg.log('╠╝', '', `${Dump.rev(r)} is merged with ${Dump.rev(h.head)} among ${merged} properties with ${r.conflicts.size} conflicts.`);
140
+ Dbg_1.Dbg.log('╠╝', '', `${Dump.rev2(h, r.snapshot)} is merged with ${Dump.rev2(h, h.head.snapshot)} among ${merged} properties with ${r.conflicts.size} conflicts.`);
139
141
  }
140
142
  });
141
143
  if (this.options.token === undefined) {
@@ -152,8 +154,9 @@ class Snapshot {
152
154
  }
153
155
  return conflicts;
154
156
  }
155
- static merge(ours, head) {
157
+ static merge(h, ours) {
156
158
  let counter = 0;
159
+ const head = h.head;
157
160
  const disposed = head.changes.has(Data_1.Meta.Disposed);
158
161
  const merged = Object.assign({}, head.data);
159
162
  ours.changes.forEach((o, m) => {
@@ -162,7 +165,7 @@ class Snapshot {
162
165
  if (disposed || m === Data_1.Meta.Disposed) {
163
166
  if (disposed !== (m === Data_1.Meta.Disposed)) {
164
167
  if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.change)
165
- Dbg_1.Dbg.log('║╠', '', `${Dump.rev(ours, m)} <> ${Dump.rev(head, m)}`, 0, ' *** CONFLICT ***');
168
+ Dbg_1.Dbg.log('║╠', '', `${Dump.rev2(h, ours.snapshot, m)} <> ${Dump.rev2(h, head.snapshot, m)}`, 0, ' *** CONFLICT ***');
166
169
  ours.conflicts.set(m, head);
167
170
  }
168
171
  }
@@ -171,7 +174,7 @@ class Snapshot {
171
174
  if (conflict)
172
175
  ours.conflicts.set(m, head);
173
176
  if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.change)
174
- Dbg_1.Dbg.log('║╠', '', `${Dump.rev(ours, m)} ${conflict ? '<>' : '=='} ${Dump.rev(head, m)}`, 0, conflict ? ' *** CONFLICT ***' : undefined);
177
+ Dbg_1.Dbg.log('║╠', '', `${Dump.rev2(h, ours.snapshot, m)} ${conflict ? '<>' : '=='} ${Dump.rev2(h, head.snapshot, m)}`, 0, conflict ? ' *** CONFLICT ***' : undefined);
175
178
  }
176
179
  });
177
180
  Utils_1.Utils.copyAllMembers(merged, ours.data);
@@ -200,7 +203,7 @@ class Snapshot {
200
203
  const members = [];
201
204
  r.changes.forEach((o, m) => members.push(m.toString()));
202
205
  const s = members.join(', ');
203
- Dbg_1.Dbg.log('║', '√', `${Dump.rev(r)} (${s}) is ${r.prev.revision === exports.ROOT_REV ? 'constructed' : `applied on top of ${Dump.rev(r.prev.revision)}`}`);
206
+ Dbg_1.Dbg.log('║', '√', `${Dump.rev2(h, r.snapshot)} (${s}) is ${r.prev.revision === exports.ROOT_REV ? 'constructed' : `applied on top of ${Dump.rev2(h, r.prev.revision.snapshot)}`}`);
204
207
  });
205
208
  }
206
209
  if (Dbg_1.Dbg.trace.transaction)
@@ -208,6 +211,7 @@ class Snapshot {
208
211
  }
209
212
  if (!error)
210
213
  Snapshot.propagateAllChangesThroughSubscriptions(this);
214
+ return this.reactions;
211
215
  }
212
216
  static sealObjectRevision(h, r) {
213
217
  if (!r.changes.has(Data_1.Meta.Disposed))
@@ -228,17 +232,9 @@ class Snapshot {
228
232
  }
229
233
  }
230
234
  }
231
- collectGarbage() {
232
- if (Dbg_1.Dbg.isOn) {
233
- Utils_1.Utils.freezeMap(this.changeset);
234
- Object.freeze(this.reactions);
235
- Object.freeze(this);
236
- }
237
- this.triggerGarbageCollection();
238
- }
239
235
  static freezeObjectRevision(r) {
240
236
  Object.freeze(r.data);
241
- Utils_1.Utils.freezeMap(r.changes);
237
+ Utils_1.Utils.freezeSet(r.changes);
242
238
  Utils_1.Utils.freezeMap(r.conflicts);
243
239
  return r;
244
240
  }
@@ -267,23 +263,25 @@ class Snapshot {
267
263
  Dbg_1.Dbg.log('', '[G]', `Dismiss history below v${this.stamp}t${this.id} (${this.hint})`);
268
264
  this.changeset.forEach((r, h) => {
269
265
  if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.gc && r.prev.revision !== exports.ROOT_REV)
270
- Dbg_1.Dbg.log(' ', ' ', `${Dump.rev(r.prev.revision)} is ready for GC because overwritten by ${Dump.rev(r)}`);
266
+ Dbg_1.Dbg.log(' ', ' ', `${Dump.rev2(h, r.prev.revision.snapshot)} is ready for GC because overwritten by ${Dump.rev2(h, r.snapshot)}`);
271
267
  if (Snapshot.garbageCollectionSummaryInterval < Number.MAX_SAFE_INTEGER) {
272
- if (r.prev.revision !== exports.ROOT_REV) {
268
+ if (r.prev.revision !== exports.ROOT_REV)
273
269
  Snapshot.totalObjectRevisionCount--;
274
- }
275
- if (r.changes.has(Data_1.Meta.Disposed)) {
270
+ if (r.changes.has(Data_1.Meta.Disposed))
276
271
  Snapshot.totalObjectHolderCount--;
277
- }
278
272
  }
279
273
  r.prev.revision = exports.ROOT_REV;
280
274
  });
275
+ this.changeset = EMPTY_MAP;
276
+ this.reactions = EMPTY_ARRAY;
277
+ if (Dbg_1.Dbg.isOn)
278
+ Object.freeze(this);
281
279
  }
282
280
  static _init() {
283
281
  const root = exports.ROOT_REV.snapshot;
284
282
  root.acquire(root);
285
283
  root.applyOrDiscard();
286
- root.collectGarbage();
284
+ root.triggerGarbageCollection();
287
285
  Snapshot.freezeObjectRevision(exports.ROOT_REV);
288
286
  Snapshot.idGen = 100;
289
287
  Snapshot.stampGen = 101;
@@ -309,7 +307,7 @@ Snapshot.markEdited = Utils_1.UNDEF;
309
307
  Snapshot.isConflicting = Utils_1.UNDEF;
310
308
  Snapshot.propagateAllChangesThroughSubscriptions = (snapshot) => { };
311
309
  Snapshot.revokeAllSubscriptions = (snapshot) => { };
312
- Snapshot.enqueueDetectedReactions = (snapshot) => { };
310
+ Snapshot.enqueueReactionsToRun = (reactions) => { };
313
311
  class Dump {
314
312
  static obj(h, m, stamp, op, xop, typeless) {
315
313
  const member = m !== undefined ? `.${m.toString()}` : '';
@@ -317,6 +315,9 @@ class Dump {
317
315
  ? `root${member}`
318
316
  : stamp === undefined ? `${h.hint}${member} #${h.id}` : `${h.hint}${member} #${h.id}t${op}v${stamp}${xop !== undefined && xop !== 0 ? `t${xop}` : ''}`;
319
317
  }
318
+ static rev2(h, s, m, value) {
319
+ return Dump.obj(h, m, s.timestamp, s.id, value === null || value === void 0 ? void 0 : value.selfSnapshotId);
320
+ }
320
321
  static rev(r, m) {
321
322
  const h = Data_1.Meta.get(r.data, Data_1.Meta.Holder);
322
323
  const value = m !== undefined ? r.data[m] : undefined;
@@ -23,7 +23,7 @@ export declare abstract class Transaction implements Worker {
23
23
  static create(options: SnapshotOptions | null): Transaction;
24
24
  static run<T>(func: F<T>, ...args: any[]): T;
25
25
  static runAs<T>(options: SnapshotOptions | null, func: F<T>, ...args: any[]): T;
26
- static standalone<T>(func: F<T>, ...args: any[]): T;
26
+ static nontransactional<T>(func: F<T>, ...args: any[]): T;
27
27
  static isFrameOver(everyN?: number, timeLimit?: number): boolean;
28
28
  static requestNextFrame(sleepTime?: number): Promise<void>;
29
29
  static get isCanceled(): boolean;
@@ -21,7 +21,7 @@ class Transaction {
21
21
  static create(options) { return new TransactionImpl(options); }
22
22
  static run(func, ...args) { return TransactionImpl.run(func, ...args); }
23
23
  static runAs(options, func, ...args) { return TransactionImpl.runAs(options, func, ...args); }
24
- static standalone(func, ...args) { return TransactionImpl.standalone(func, ...args); }
24
+ static nontransactional(func, ...args) { return TransactionImpl.nontransactional(func, ...args); }
25
25
  static isFrameOver(everyN = 1, timeLimit = 14) { return TransactionImpl.isFrameOver(everyN, timeLimit); }
26
26
  static requestNextFrame(sleepTime = 0) { return TransactionImpl.requestNextFrame(sleepTime); }
27
27
  static get isCanceled() { return TransactionImpl.current.isCanceled; }
@@ -125,7 +125,7 @@ class TransactionImpl extends Transaction {
125
125
  let result = t.runImpl(options === null || options === void 0 ? void 0 : options.trace, func, ...args);
126
126
  if (root) {
127
127
  if (result instanceof Promise) {
128
- result = TransactionImpl.standalone(() => {
128
+ result = TransactionImpl.nontransactional(() => {
129
129
  return t.wrapToRetry(t.wrapToWaitUntilFinish(result), func, ...args);
130
130
  });
131
131
  }
@@ -133,7 +133,7 @@ class TransactionImpl extends Transaction {
133
133
  }
134
134
  return result;
135
135
  }
136
- static standalone(func, ...args) {
136
+ static nontransactional(func, ...args) {
137
137
  const outer = TransactionImpl.curr;
138
138
  try {
139
139
  TransactionImpl.curr = TransactionImpl.none;
@@ -228,9 +228,9 @@ class TransactionImpl extends Transaction {
228
228
  finally {
229
229
  this.pending--;
230
230
  if (this.sealed && this.pending === 0) {
231
- this.applyOrDiscard();
231
+ const reactions = this.applyOrDiscard();
232
232
  TransactionImpl.curr = outer;
233
- TransactionImpl.standalone(Snapshot_1.Snapshot.enqueueDetectedReactions, this.snapshot);
233
+ TransactionImpl.nontransactional(Snapshot_1.Snapshot.enqueueReactionsToRun, reactions);
234
234
  }
235
235
  else
236
236
  TransactionImpl.curr = outer;
@@ -259,11 +259,12 @@ class TransactionImpl extends Transaction {
259
259
  throw (0, Dbg_1.error)(`T${this.id}[${this.hint}] conflicts with: ${Snapshot_1.Dump.conflicts(conflicts)}`, undefined);
260
260
  }
261
261
  applyOrDiscard() {
262
+ let reactions;
262
263
  try {
263
264
  if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.change)
264
265
  Dbg_1.Dbg.log('╠═', '', '', undefined, 'changes');
265
- this.snapshot.applyOrDiscard(this.canceled);
266
- this.snapshot.collectGarbage();
266
+ reactions = this.snapshot.applyOrDiscard(this.canceled);
267
+ this.snapshot.triggerGarbageCollection();
267
268
  if (this.promise) {
268
269
  if (this.canceled && !this.after)
269
270
  this.reject(this.canceled);
@@ -277,6 +278,7 @@ class TransactionImpl extends Transaction {
277
278
  (0, Dbg_1.fatal)(e);
278
279
  throw e;
279
280
  }
281
+ return reactions;
280
282
  }
281
283
  acquirePromise() {
282
284
  if (!this.promise) {
@@ -1,7 +1,7 @@
1
1
  export declare type F<T> = (...args: any[]) => T;
2
2
  export declare class Utils {
3
- static freezeSet<T>(obj?: Set<T>): void;
4
- static freezeMap<K, V>(obj?: Map<K, V>): void;
3
+ static freezeSet<T>(obj?: Set<T>): Set<T> | undefined;
4
+ static freezeMap<K, V>(obj?: Map<K, V>): Map<K, V> | undefined;
5
5
  static copyAllMembers(source: any, target: any): any;
6
6
  }
7
7
  export declare function UNDEF(...args: any[]): never;
@@ -19,6 +19,7 @@ class Utils {
19
19
  Object.defineProperty(obj, 'clear', pd);
20
20
  Object.freeze(obj);
21
21
  }
22
+ return obj;
22
23
  }
23
24
  static freezeMap(obj) {
24
25
  if (obj instanceof Map) {
@@ -28,6 +29,7 @@ class Utils {
28
29
  Object.defineProperty(obj, 'clear', pd);
29
30
  Object.freeze(obj);
30
31
  }
32
+ return obj;
31
33
  }
32
34
  static copyAllMembers(source, target) {
33
35
  for (const m of Object.getOwnPropertyNames(source))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reactronic",
3
- "version": "0.21.601",
3
+ "version": "0.22.101",
4
4
  "description": "Reactronic - Transactional Reactive State Management",
5
5
  "main": "build/dist/source/api.js",
6
6
  "types": "build/dist/source/api.d.ts",