reactronic 0.21.602 → 0.22.102

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 Transaction_1.Transaction.off(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
  }
@@ -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;
@@ -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,34 +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
268
  const skip = !observable.isOperation &&
273
- cause.revision.snapshot === this.revision.snapshot &&
274
- cause.revision.changes.has(cause.memberName);
269
+ snapshot === this.snapshot;
275
270
  if (!skip) {
271
+ const why = `${Snapshot_1.Dump.rev2(holder, snapshot, memberName)} << ${outer}`;
276
272
  this.unsubscribeFromAllObservables();
277
- this.obsoleteDueTo = cause;
273
+ this.obsoleteDueTo = why;
278
274
  this.obsoleteSince = since;
279
275
  const isReaction = this.options.kind === Options_1.Kind.Reaction;
280
276
  if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.obsolete || ((_a = this.options.trace) === null || _a === void 0 ? void 0 : _a.obsolete)))
281
- 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
282
278
  ? `${this.hint()} is a reaction and will run automatically (order ${this.options.order})`
283
- : `${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})` : ''}`);
284
280
  if (isReaction)
285
281
  reactions.push(this);
286
282
  else
287
- (_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));
288
284
  const tran = this.transaction;
289
- if (tran.snapshot === cause.revision.snapshot) {
290
- (0, Dbg_1.misuse)('not implemented: running reactions within original transaction');
285
+ if (tran.snapshot === snapshot) {
291
286
  }
292
287
  else if (!tran.isFinished && this !== observable)
293
- 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);
294
289
  }
295
290
  else if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.obsolete || ((_c = this.options.trace) === null || _c === void 0 ? void 0 : _c.obsolete)))
296
- 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)}`);
297
292
  }
298
293
  }
299
294
  runIfNotUpToDate(now, nothrow) {
@@ -423,7 +418,7 @@ class Operation extends Data_1.Observable {
423
418
  OperationController.runWithin(undefined, Transaction_1.Transaction.runAs, options, Monitor_1.MonitorImpl.enter, mon, this.transaction);
424
419
  }
425
420
  monitorLeave(mon) {
426
- Transaction_1.Transaction.standalone(() => {
421
+ Transaction_1.Transaction.off(() => {
427
422
  const leave = () => {
428
423
  const options = {
429
424
  hint: 'Monitor.leave',
@@ -449,25 +444,26 @@ class Operation extends Data_1.Observable {
449
444
  static markUsed(observable, r, m, h, kind, weak) {
450
445
  if (kind !== Options_1.Kind.Transaction) {
451
446
  const op = Operation.current;
452
- 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) {
453
449
  const ctx = Snapshot_1.Snapshot.current();
454
450
  if (ctx !== r.snapshot)
455
451
  ctx.bumpBy(r.snapshot.timestamp);
456
452
  const t = weak ? -1 : ctx.timestamp;
457
453
  if (!op.subscribeTo(observable, r, m, h, t))
458
- 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);
459
455
  }
460
456
  }
461
457
  }
462
458
  static markEdited(oldValue, newValue, edited, r, m, h) {
463
459
  edited ? r.changes.add(m) : r.changes.delete(m);
464
460
  if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.write)
465
- 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)');
466
462
  }
467
463
  static isConflicting(oldValue, newValue) {
468
464
  let result = oldValue !== newValue;
469
465
  if (result)
470
- result = oldValue instanceof Operation && oldValue.cause !== ROOT_TRIGGER;
466
+ result = oldValue instanceof Operation && oldValue.cause !== INITIAL_CAUSE;
471
467
  return result;
472
468
  }
473
469
  static propagateAllChangesThroughSubscriptions(snapshot) {
@@ -493,26 +489,30 @@ class Operation extends Data_1.Observable {
493
489
  if (reactions) {
494
490
  const prev = r.prev.revision.data[m];
495
491
  if (prev !== undefined && prev instanceof Data_1.Observable) {
496
- const cause = { revision: r, memberName: m, usageCount: 0 };
492
+ const why = `T${r.snapshot.id}[${r.snapshot.hint}]`;
497
493
  if (prev instanceof Operation) {
498
494
  if ((prev.obsoleteSince === Snapshot_1.MAX_TIMESTAMP || prev.obsoleteSince <= 0)) {
499
- prev.obsoleteDueTo = cause;
495
+ prev.obsoleteDueTo = why;
500
496
  prev.obsoleteSince = timestamp;
501
497
  prev.unsubscribeFromAllObservables();
502
498
  }
503
- const opponent = prev.successor;
504
- if (opponent !== curr && opponent && !opponent.transaction.isFinished)
505
- 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;
506
506
  }
507
- (_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));
508
508
  }
509
509
  }
510
510
  if (curr instanceof Operation) {
511
- if (curr.revision === r && curr.observables !== undefined) {
511
+ if (curr.snapshot === r.snapshot && curr.observables !== undefined) {
512
512
  if (Hooks_1.Hooks.repetitiveUsageWarningThreshold < Number.MAX_SAFE_INTEGER) {
513
513
  curr.observables.forEach((hint, v) => {
514
514
  if (hint.usageCount > Hooks_1.Hooks.repetitiveUsageWarningThreshold)
515
- 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 ***');
516
516
  });
517
517
  }
518
518
  if (unsubscribe)
@@ -552,7 +552,7 @@ class Operation extends Data_1.Observable {
552
552
  var _a;
553
553
  value.observers.delete(this);
554
554
  if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_a = this.options.trace) === null || _a === void 0 ? void 0 : _a.read)))
555
- 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)}`);
556
556
  });
557
557
  this.observables = undefined;
558
558
  }
@@ -568,18 +568,18 @@ class Operation extends Data_1.Observable {
568
568
  if (this.observables !== undefined) {
569
569
  if (!observable.observers)
570
570
  observable.observers = new Set();
571
- const info = { revision: r, memberName: m, usageCount: times };
571
+ const info = { holder: h, snapshot: r.snapshot, memberName: m, usageCount: times };
572
572
  observable.observers.add(this);
573
573
  this.observables.set(observable, info);
574
574
  if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_a = this.options.trace) === null || _a === void 0 ? void 0 : _a.read)))
575
- 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)` : ''}`);
576
576
  }
577
577
  else if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_b = this.options.trace) === null || _b === void 0 ? void 0 : _b.read)))
578
- 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)}`);
579
579
  }
580
580
  else {
581
581
  if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_c = this.options.trace) === null || _c === void 0 ? void 0 : _c.read)))
582
- 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)}`);
583
583
  }
584
584
  return ok;
585
585
  }
@@ -602,7 +602,7 @@ class Operation extends Data_1.Observable {
602
602
  let op = initial[m];
603
603
  const ctl = op ? op.controller : new OperationController(ROOT_HOLDER, m);
604
604
  const opts = op ? op.options : Hooks_1.OptionsImpl.INITIAL;
605
- 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));
606
606
  if (op.options.kind === Options_1.Kind.Reaction && op.options.throttling < Number.MAX_SAFE_INTEGER) {
607
607
  const reactions = Data_1.Meta.acquire(proto, Data_1.Meta.Reactions);
608
608
  reactions[m] = op;
@@ -615,7 +615,6 @@ class Operation extends Data_1.Observable {
615
615
  }
616
616
  static init() {
617
617
  Object.freeze(ROOT_ARGS);
618
- Object.freeze(ROOT_TRIGGER);
619
618
  Dbg_1.Dbg.getMergedTraceOptions = getMergedTraceOptions;
620
619
  Snapshot_1.Snapshot.markUsed = Operation.markUsed;
621
620
  Snapshot_1.Snapshot.markEdited = Operation.markEdited;
@@ -651,18 +650,6 @@ class Operation extends Data_1.Observable {
651
650
  Operation.current = undefined;
652
651
  Operation.queuedReactions = [];
653
652
  Operation.deferredReactions = [];
654
- function propagationHint(cause, full) {
655
- const result = [];
656
- let observable = cause.revision.data[cause.memberName];
657
- while (observable instanceof Operation && observable.obsoleteDueTo) {
658
- full && result.push(Snapshot_1.Dump.rev(cause.revision, cause.memberName));
659
- cause = observable.obsoleteDueTo;
660
- observable = cause.revision.data[cause.memberName];
661
- }
662
- result.push(Snapshot_1.Dump.rev(cause.revision, cause.memberName));
663
- full && result.push(cause.revision.snapshot.hint);
664
- return result;
665
- }
666
653
  function valueHint(value, m) {
667
654
  let result = '';
668
655
  if (Array.isArray(value))
@@ -672,7 +659,7 @@ function valueHint(value, m) {
672
659
  else if (value instanceof Map)
673
660
  result = `Map(${value.size})`;
674
661
  else if (value instanceof Operation)
675
- result = `${Snapshot_1.Dump.rev(value.revision, m)}`;
662
+ result = `${Snapshot_1.Dump.rev2(value.controller.ownHolder, value.snapshot, m)}`;
676
663
  else if (value === Data_1.Meta.Disposed)
677
664
  result = '<disposed>';
678
665
  else if (value !== undefined && value !== null)
@@ -43,14 +43,14 @@ export declare class Snapshot implements AbstractSnapshot {
43
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;
@@ -130,14 +130,14 @@ class Snapshot {
130
130
  if (this.changeset.size > 0) {
131
131
  this.changeset.forEach((r, h) => {
132
132
  if (r.prev.revision !== h.head) {
133
- const merged = Snapshot.merge(r, h.head);
133
+ const merged = Snapshot.merge(h, r);
134
134
  if (r.conflicts.size > 0) {
135
135
  if (!conflicts)
136
136
  conflicts = [];
137
137
  conflicts.push(r);
138
138
  }
139
139
  if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.transaction)
140
- 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.`);
141
141
  }
142
142
  });
143
143
  if (this.options.token === undefined) {
@@ -154,8 +154,9 @@ class Snapshot {
154
154
  }
155
155
  return conflicts;
156
156
  }
157
- static merge(ours, head) {
157
+ static merge(h, ours) {
158
158
  let counter = 0;
159
+ const head = h.head;
159
160
  const disposed = head.changes.has(Data_1.Meta.Disposed);
160
161
  const merged = Object.assign({}, head.data);
161
162
  ours.changes.forEach((o, m) => {
@@ -164,7 +165,7 @@ class Snapshot {
164
165
  if (disposed || m === Data_1.Meta.Disposed) {
165
166
  if (disposed !== (m === Data_1.Meta.Disposed)) {
166
167
  if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.change)
167
- 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 ***');
168
169
  ours.conflicts.set(m, head);
169
170
  }
170
171
  }
@@ -173,7 +174,7 @@ class Snapshot {
173
174
  if (conflict)
174
175
  ours.conflicts.set(m, head);
175
176
  if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.change)
176
- 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);
177
178
  }
178
179
  });
179
180
  Utils_1.Utils.copyAllMembers(merged, ours.data);
@@ -202,7 +203,7 @@ class Snapshot {
202
203
  const members = [];
203
204
  r.changes.forEach((o, m) => members.push(m.toString()));
204
205
  const s = members.join(', ');
205
- 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)}`}`);
206
207
  });
207
208
  }
208
209
  if (Dbg_1.Dbg.trace.transaction)
@@ -231,16 +232,6 @@ class Snapshot {
231
232
  }
232
233
  }
233
234
  }
234
- collectGarbage() {
235
- this.changeset = EMPTY_MAP;
236
- this.reactions = EMPTY_ARRAY;
237
- if (Dbg_1.Dbg.isOn) {
238
- Utils_1.Utils.freezeMap(this.changeset);
239
- Object.freeze(this.reactions);
240
- Object.freeze(this);
241
- }
242
- this.triggerGarbageCollection();
243
- }
244
235
  static freezeObjectRevision(r) {
245
236
  Object.freeze(r.data);
246
237
  Utils_1.Utils.freezeSet(r.changes);
@@ -272,7 +263,7 @@ class Snapshot {
272
263
  Dbg_1.Dbg.log('', '[G]', `Dismiss history below v${this.stamp}t${this.id} (${this.hint})`);
273
264
  this.changeset.forEach((r, h) => {
274
265
  if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.gc && r.prev.revision !== exports.ROOT_REV)
275
- 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)}`);
276
267
  if (Snapshot.garbageCollectionSummaryInterval < Number.MAX_SAFE_INTEGER) {
277
268
  if (r.prev.revision !== exports.ROOT_REV)
278
269
  Snapshot.totalObjectRevisionCount--;
@@ -281,12 +272,16 @@ class Snapshot {
281
272
  }
282
273
  r.prev.revision = exports.ROOT_REV;
283
274
  });
275
+ this.changeset = EMPTY_MAP;
276
+ this.reactions = EMPTY_ARRAY;
277
+ if (Dbg_1.Dbg.isOn)
278
+ Object.freeze(this);
284
279
  }
285
280
  static _init() {
286
281
  const root = exports.ROOT_REV.snapshot;
287
282
  root.acquire(root);
288
283
  root.applyOrDiscard();
289
- root.collectGarbage();
284
+ root.triggerGarbageCollection();
290
285
  Snapshot.freezeObjectRevision(exports.ROOT_REV);
291
286
  Snapshot.idGen = 100;
292
287
  Snapshot.stampGen = 101;
@@ -320,6 +315,9 @@ class Dump {
320
315
  ? `root${member}`
321
316
  : stamp === undefined ? `${h.hint}${member} #${h.id}` : `${h.hint}${member} #${h.id}t${op}v${stamp}${xop !== undefined && xop !== 0 ? `t${xop}` : ''}`;
322
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
+ }
323
321
  static rev(r, m) {
324
322
  const h = Data_1.Meta.get(r.data, Data_1.Meta.Holder);
325
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 off<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 off(func, ...args) { return TransactionImpl.off(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.off(() => {
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 off(func, ...args) {
137
137
  const outer = TransactionImpl.curr;
138
138
  try {
139
139
  TransactionImpl.curr = TransactionImpl.none;
@@ -230,7 +230,7 @@ class TransactionImpl extends Transaction {
230
230
  if (this.sealed && this.pending === 0) {
231
231
  const reactions = this.applyOrDiscard();
232
232
  TransactionImpl.curr = outer;
233
- TransactionImpl.standalone(Snapshot_1.Snapshot.enqueueReactionsToRun, reactions);
233
+ TransactionImpl.off(Snapshot_1.Snapshot.enqueueReactionsToRun, reactions);
234
234
  }
235
235
  else
236
236
  TransactionImpl.curr = outer;
@@ -264,7 +264,7 @@ class TransactionImpl extends Transaction {
264
264
  if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.change)
265
265
  Dbg_1.Dbg.log('╠═', '', '', undefined, 'changes');
266
266
  reactions = this.snapshot.applyOrDiscard(this.canceled);
267
- this.snapshot.collectGarbage();
267
+ this.snapshot.triggerGarbageCollection();
268
268
  if (this.promise) {
269
269
  if (this.canceled && !this.after)
270
270
  this.reject(this.canceled);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reactronic",
3
- "version": "0.21.602",
3
+ "version": "0.22.102",
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",