reactronic 0.24.305 → 0.24.307

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.
@@ -50,7 +50,7 @@ export type Operation<T> = {
50
50
  readonly result: T;
51
51
  readonly error: any;
52
52
  readonly stamp: number;
53
- readonly isUpToDate: boolean;
53
+ readonly isReusable: boolean;
54
54
  configure(options: Partial<MemberOptions>): MemberOptions;
55
55
  markObsolete(): void;
56
56
  pullLastResult(args?: any[]): T | undefined;
@@ -26,7 +26,10 @@ export declare class Changeset implements AbstractChangeset {
26
26
  static edit: () => Changeset;
27
27
  static markUsed: (fv: FieldVersion, ov: ObjectVersion, fk: FieldKey, h: ObjectHandle, kind: Kind, weak: boolean) => void;
28
28
  static markEdited: (oldValue: any, newValue: any, edited: boolean, ov: ObjectVersion, fk: FieldKey, h: ObjectHandle) => void;
29
- static isConflicting: (oldValue: any, newValue: any) => boolean;
29
+ static tryResolveConflict: (theirValue: any, ourFormerValue: any, ourValue: any) => {
30
+ isResolved: boolean;
31
+ resolvedValue: any;
32
+ };
30
33
  static propagateAllChangesThroughSubscriptions: (changeset: Changeset) => void;
31
34
  static revokeAllSubscriptions: (changeset: Changeset) => void;
32
35
  static enqueueReactiveFunctionsToRun: (reactive: Array<Observer>) => void;
@@ -157,7 +157,7 @@ export class Changeset {
157
157
  let conflicts = undefined;
158
158
  if (this.items.size > 0) {
159
159
  this.items.forEach((ov, h) => {
160
- const theirs = this.parent ? this.parent.lookupObjectVersion(h, Meta.Handle, false) : h.applied;
160
+ const theirs = this.parent ? this.parent.lookupObjectVersion(h, Meta.Handle, true) : h.applied;
161
161
  if (ov.former.objectVersion !== theirs) {
162
162
  const merged = this.merge(h, ov, theirs);
163
163
  if (ov.conflicts.size > 0) {
@@ -202,11 +202,15 @@ export class Changeset {
202
202
  }
203
203
  }
204
204
  else {
205
- const conflict = Changeset.isConflicting(theirs.data[fk], ours.former.objectVersion.data[fk]);
206
- if (conflict)
205
+ const theirValue = theirs.data[fk];
206
+ const ourFormerValue = ours.former.objectVersion.data[fk];
207
+ const { isResolved, resolvedValue } = Changeset.tryResolveConflict(theirValue, ourFormerValue, ourFieldVersion);
208
+ if (!isResolved)
207
209
  ours.conflicts.set(fk, theirs);
210
+ else if (resolvedValue.isLaunch)
211
+ merged[fk] = resolvedValue;
208
212
  if (Log.isOn && Log.opt.change)
209
- Log.write("║╠", "", `${Dump.snapshot2(h, ours.changeset, fk)} ${conflict ? "<>" : "=="} ${Dump.snapshot2(h, theirs.changeset, fk)}`, 0, conflict ? " *** CONFLICT ***" : undefined);
213
+ Log.write("║╠", "", `${Dump.snapshot2(h, ours.changeset, fk)} ${!isResolved ? "<>" : "=="} ${Dump.snapshot2(h, theirs.changeset, fk)}`, 0, !isResolved ? " *** CONFLICT ***" : undefined);
210
214
  }
211
215
  });
212
216
  Utils.copyAllMembers(merged, ours.data);
@@ -311,7 +315,7 @@ Changeset.current = UNDEF;
311
315
  Changeset.edit = UNDEF;
312
316
  Changeset.markUsed = UNDEF;
313
317
  Changeset.markEdited = UNDEF;
314
- Changeset.isConflicting = UNDEF;
318
+ Changeset.tryResolveConflict = UNDEF;
315
319
  Changeset.propagateAllChangesThroughSubscriptions = (changeset) => { };
316
320
  Changeset.revokeAllSubscriptions = (changeset) => { };
317
321
  Changeset.enqueueReactiveFunctionsToRun = (reactive) => { };
@@ -131,13 +131,13 @@ export class IndicatorImpl extends Indicator {
131
131
  }
132
132
  static tick(mon) {
133
133
  if (mon.internals.started !== 0) {
134
- Transaction.run(INDICATOR_TICK_OPTIONS, () => {
135
- const resolution = mon.internals.durationResolution;
136
- mon.busyDuration = Math.round(resolution * (performance.now() - mon.internals.started)) / resolution;
137
- });
134
+ const resolution = mon.internals.durationResolution;
135
+ mon.busyDuration = Math.round(resolution * (performance.now() - mon.internals.started)) / resolution;
138
136
  const t = globalThis !== null && globalThis !== void 0 ? globalThis : global;
139
137
  if (t.requestAnimationFrame)
140
- requestAnimationFrame(() => IndicatorImpl.tick(mon));
138
+ requestAnimationFrame(() => {
139
+ Transaction.run(INDICATOR_TICK_OPTIONS, () => IndicatorImpl.tick(mon));
140
+ });
141
141
  }
142
142
  }
143
143
  }
@@ -13,7 +13,7 @@ export declare class OperationImpl implements Operation<any> {
13
13
  get result(): any;
14
14
  get error(): boolean;
15
15
  get stamp(): number;
16
- get isUpToDate(): boolean;
16
+ get isReusable(): boolean;
17
17
  markObsolete(): void;
18
18
  pullLastResult(args?: any[]): any;
19
19
  constructor(h: ObjectHandle, fk: FieldKey);
@@ -74,7 +74,7 @@ declare class Launch extends FieldVersion implements Observer {
74
74
  private static processDeferredReactiveFunctions;
75
75
  private static markUsed;
76
76
  private static markEdited;
77
- private static isConflicting;
77
+ private static tryResolveConflict;
78
78
  private static propagateAllChangesThroughSubscriptions;
79
79
  private static revokeAllSubscriptions;
80
80
  private static propagateFieldChangeThroughSubscriptions;
@@ -17,7 +17,7 @@ export class OperationImpl {
17
17
  get result() { return this.reuseOrRelaunch(true, undefined).content; }
18
18
  get error() { return this.use().launch.error; }
19
19
  get stamp() { return this.use().objectVersion.changeset.timestamp; }
20
- get isUpToDate() { return this.use().isUpToDate; }
20
+ get isReusable() { return this.use().isReusable; }
21
21
  markObsolete() { Transaction.run({ hint: Log.isOn ? `markObsolete(${Dump.obj(this.ownerHandle, this.fieldKey)})` : "markObsolete()" }, OperationImpl.markObsolete, this); }
22
22
  pullLastResult(args) { return this.reuseOrRelaunch(true, args).content; }
23
23
  constructor(h, fk) {
@@ -29,7 +29,7 @@ export class OperationImpl {
29
29
  const ctx = ror.changeset;
30
30
  const launch = ror.launch;
31
31
  const opts = launch.options;
32
- if (!ror.isUpToDate && !ror.objectVersion.disposed
32
+ if (!ror.isReusable && !ror.objectVersion.disposed
33
33
  && (!weak || launch.cause === BOOT_CAUSE || !launch.successor ||
34
34
  launch.successor.transaction.isFinished)) {
35
35
  const isolation = !weak ? opts.isolation : Isolation.disjoinFromOuterTransaction;
@@ -98,11 +98,12 @@ export class OperationImpl {
98
98
  const ctx = Changeset.current();
99
99
  const ov = ctx.lookupObjectVersion(this.ownerHandle, this.fieldKey, false);
100
100
  const launch = this.acquireFromObjectVersion(ov, args);
101
- const isValid = launch.options.kind !== Kind.transactional && launch.cause !== BOOT_CAUSE &&
102
- (ctx === launch.changeset || ctx.timestamp < launch.obsoleteSince) &&
101
+ const applied = this.ownerHandle.applied.data[this.fieldKey];
102
+ const isReusable = launch.options.kind !== Kind.transactional && launch.cause !== BOOT_CAUSE &&
103
+ (ctx === launch.changeset || ctx.timestamp < launch.obsoleteSince || applied.obsoleteDueTo === undefined) &&
103
104
  (!launch.options.triggeringArgs || args === undefined ||
104
105
  launch.args.length === args.length && launch.args.every((t, i) => t === args[i])) || ov.disposed;
105
- return { launch, isUpToDate: isValid, changeset: ctx, objectVersion: ov };
106
+ return { launch, isReusable, changeset: ctx, objectVersion: ov };
106
107
  }
107
108
  use() {
108
109
  const ror = this.peek(undefined);
@@ -122,7 +123,7 @@ export class OperationImpl {
122
123
  Changeset.markEdited(launch, relaunch, true, ov, fk, h);
123
124
  launch = relaunch;
124
125
  }
125
- return { launch, isUpToDate: true, changeset: ctx, objectVersion: ov };
126
+ return { launch, isReusable: true, changeset: ctx, objectVersion: ov };
126
127
  }
127
128
  acquireFromObjectVersion(ov, args) {
128
129
  const fk = this.fieldKey;
@@ -174,7 +175,7 @@ export class OperationImpl {
174
175
  }
175
176
  else {
176
177
  ror = this.peek(argsx);
177
- if (ror.launch.options.kind === Kind.transactional || !ror.isUpToDate) {
178
+ if (ror.launch.options.kind === Kind.transactional || !ror.isReusable) {
178
179
  ror = this.edit();
179
180
  if (Log.isOn && Log.opt.operation)
180
181
  Log.write("║", " o", `${ror.launch.why()}`);
@@ -486,11 +487,20 @@ class Launch extends FieldVersion {
486
487
  if (Log.isOn && Log.opt.write)
487
488
  edited ? Log.write("║", " =", `${Dump.snapshot2(h, ov.changeset, fk)} is changed: ${valueHint(oldValue)} ▸▸ ${valueHint(newValue)}`) : Log.write("║", " =", `${Dump.snapshot2(h, ov.changeset, fk)} is changed: ${valueHint(oldValue)} ▸▸ ${valueHint(newValue)}`, undefined, " (same as previous)");
488
489
  }
489
- static isConflicting(oldValue, newValue) {
490
- let result = oldValue !== newValue;
491
- if (result)
492
- result = oldValue instanceof Launch && oldValue.cause !== BOOT_CAUSE;
493
- return result;
490
+ static tryResolveConflict(theirValue, ourFormerValue, ourValue) {
491
+ let isResolved = theirValue === ourFormerValue;
492
+ let resolvedValue = ourValue;
493
+ if (!isResolved) {
494
+ if (ourValue instanceof Launch && ourValue.obsoleteDueTo === undefined) {
495
+ isResolved = true;
496
+ resolvedValue = ourValue;
497
+ }
498
+ else if (theirValue instanceof Launch && (theirValue.obsoleteDueTo === undefined || theirValue.cause === BOOT_CAUSE)) {
499
+ isResolved = true;
500
+ resolvedValue = theirValue;
501
+ }
502
+ }
503
+ return { isResolved, resolvedValue };
494
504
  }
495
505
  static propagateAllChangesThroughSubscriptions(changeset) {
496
506
  var _a;
@@ -658,7 +668,7 @@ class Launch extends FieldVersion {
658
668
  Dump.valueHint = valueHint;
659
669
  Changeset.markUsed = Launch.markUsed;
660
670
  Changeset.markEdited = Launch.markEdited;
661
- Changeset.isConflicting = Launch.isConflicting;
671
+ Changeset.tryResolveConflict = Launch.tryResolveConflict;
662
672
  Changeset.propagateAllChangesThroughSubscriptions = Launch.propagateAllChangesThroughSubscriptions;
663
673
  Changeset.revokeAllSubscriptions = Launch.revokeAllSubscriptions;
664
674
  Changeset.enqueueReactiveFunctionsToRun = Launch.enqueueReactiveFunctionsToRun;
@@ -36,7 +36,9 @@ export declare abstract class RxNode<E = unknown> {
36
36
  static readonly longFrameDuration = 300;
37
37
  static currentUpdatePriority: Priority;
38
38
  static frameDuration: number;
39
- static declare<E = void>(driver: RxNodeDriver<E>, declaration?: RxNodeDecl<E>, basis?: RxNodeDecl<E>): RxNode<E>;
39
+ static declare<E = void>(driver: RxNodeDriver<E>, script?: Script<E>, scriptAsync?: ScriptAsync<E>, key?: string, mode?: Mode, creation?: Script<E>, creationAsync?: ScriptAsync<E>, destruction?: Script<E>, triggers?: unknown, basis?: RxNodeDecl<E>): RxNode<E>;
40
+ static declare<E = void>(driver: RxNodeDriver<E>, declaration?: RxNodeDecl<E>): RxNode<E>;
41
+ static rebased<E = void>(declaration?: RxNodeDecl<E>, basis?: RxNodeDecl<E>): RxNodeDecl<E>;
40
42
  static get isFirstUpdate(): boolean;
41
43
  static get key(): string;
42
44
  static get stamp(): number;
@@ -36,18 +36,23 @@ export var Priority;
36
36
  Priority[Priority["background"] = 2] = "background";
37
37
  })(Priority || (Priority = {}));
38
38
  export class RxNode {
39
- static declare(driver, declaration, basis) {
39
+ static declare(driver, scriptOrDeclaration, scriptAsync, key, mode, creation, creationAsync, destruction, triggers, basis) {
40
40
  let result;
41
- if (declaration)
42
- declaration.basis = basis;
41
+ let declaration;
42
+ if (scriptOrDeclaration instanceof Function) {
43
+ declaration = {
44
+ script: scriptOrDeclaration, scriptAsync, key, mode,
45
+ creation, creationAsync, destruction, triggers, basis,
46
+ };
47
+ }
43
48
  else
44
- declaration = basis !== null && basis !== void 0 ? basis : {};
45
- let key = declaration.key;
49
+ declaration = scriptOrDeclaration !== null && scriptOrDeclaration !== void 0 ? scriptOrDeclaration : {};
50
+ let effectiveKey = declaration.key;
46
51
  const owner = gOwnSeat === null || gOwnSeat === void 0 ? void 0 : gOwnSeat.instance;
47
52
  if (owner) {
48
- let existing = owner.driver.child(owner, driver, declaration, basis);
53
+ let existing = owner.driver.child(owner, driver, declaration, declaration.basis);
49
54
  const children = owner.children;
50
- existing !== null && existing !== void 0 ? existing : (existing = children.tryMergeAsExisting(key = key || generateKey(owner), undefined, "nested elements can be declared inside update function only"));
55
+ existing !== null && existing !== void 0 ? existing : (existing = children.tryMergeAsExisting(effectiveKey = effectiveKey || generateKey(owner), undefined, "nested elements can be declared inside update function only"));
51
56
  if (existing) {
52
57
  result = existing.instance;
53
58
  if (result.driver !== driver && driver !== undefined)
@@ -58,17 +63,24 @@ export class RxNode {
58
63
  result.declaration = declaration;
59
64
  }
60
65
  else {
61
- result = new RxNodeImpl(key || generateKey(owner), driver, declaration, owner);
66
+ result = new RxNodeImpl(effectiveKey || generateKey(owner), driver, declaration, owner);
62
67
  result.seat = children.mergeAsAdded(result);
63
68
  }
64
69
  }
65
70
  else {
66
- result = new RxNodeImpl(key || "", driver, declaration, owner);
71
+ result = new RxNodeImpl(effectiveKey || "", driver, declaration, owner);
67
72
  result.seat = MergeList.createItem(result);
68
73
  triggerUpdateViaSeat(result.seat);
69
74
  }
70
75
  return result;
71
76
  }
77
+ static rebased(declaration, basis) {
78
+ if (declaration)
79
+ declaration.basis = basis;
80
+ else
81
+ declaration = basis !== null && basis !== void 0 ? basis : {};
82
+ return declaration;
83
+ }
72
84
  static get isFirstUpdate() {
73
85
  return RxNodeImpl.ownSeat.instance.stamp === 1;
74
86
  }
@@ -354,7 +366,7 @@ RxNodeImpl.disposableNodeCount = 0;
354
366
  __decorate([
355
367
  reactive,
356
368
  options({
357
- reentrance: Reentrance.cancelPrevious,
369
+ reentrance: Reentrance.cancelAndWaitPrevious,
358
370
  allowObsoleteToFinish: true,
359
371
  triggeringArgs: true,
360
372
  noSideEffects: false,
@@ -12,6 +12,7 @@ export declare abstract class Transaction implements Worker {
12
12
  abstract readonly error: Error | undefined;
13
13
  abstract readonly changeset: Changeset;
14
14
  abstract readonly margin: number;
15
+ abstract readonly parent?: Transaction;
15
16
  abstract run<T>(func: F<T>, ...args: any[]): T;
16
17
  abstract inspect<T>(func: F<T>, ...args: any[]): T;
17
18
  abstract apply(): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reactronic",
3
- "version": "0.24.305",
3
+ "version": "0.24.307",
4
4
  "description": "Reactronic - Transactional Reactive State Management",
5
5
  "publisher": "Nezaboodka Software",
6
6
  "license": "Apache-2.0",