reactronic 0.94.25036 → 0.95.25040

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +67 -66
  2. package/build/dist/source/Enums.d.ts +3 -3
  3. package/build/dist/source/Enums.js +3 -3
  4. package/build/dist/source/OperationEx.d.ts +2 -2
  5. package/build/dist/source/OperationEx.js +5 -5
  6. package/build/dist/source/Options.d.ts +2 -2
  7. package/build/dist/source/Pipe.d.ts +2 -2
  8. package/build/dist/source/Pipe.js +2 -2
  9. package/build/dist/source/Ref.d.ts +2 -2
  10. package/build/dist/source/Ref.js +5 -5
  11. package/build/dist/source/System.d.ts +14 -14
  12. package/build/dist/source/System.js +22 -22
  13. package/build/dist/source/api.d.ts +9 -9
  14. package/build/dist/source/api.js +7 -7
  15. package/build/dist/source/core/Changeset.js +1 -1
  16. package/build/dist/source/core/Data.d.ts +1 -1
  17. package/build/dist/source/core/Indicator.d.ts +2 -2
  18. package/build/dist/source/core/Indicator.js +2 -2
  19. package/build/dist/source/core/Journal.d.ts +2 -2
  20. package/build/dist/source/core/Journal.js +2 -2
  21. package/build/dist/source/core/Mvcc.d.ts +10 -10
  22. package/build/dist/source/core/Mvcc.js +19 -19
  23. package/build/dist/source/core/MvccArray.d.ts +3 -3
  24. package/build/dist/source/core/MvccArray.js +4 -4
  25. package/build/dist/source/core/MvccMap.d.ts +3 -3
  26. package/build/dist/source/core/MvccMap.js +4 -4
  27. package/build/dist/source/core/MvccReconciliationList.d.ts +28 -0
  28. package/build/dist/source/core/MvccReconciliationList.js +26 -0
  29. package/build/dist/source/core/Operation.d.ts +8 -8
  30. package/build/dist/source/core/Operation.js +41 -41
  31. package/build/dist/source/core/Transaction.js +28 -28
  32. package/build/dist/source/core/TreeNode.d.ts +19 -19
  33. package/build/dist/source/core/TreeNode.js +58 -58
  34. package/build/dist/source/util/LinkedList.d.ts +52 -0
  35. package/build/dist/source/util/LinkedList.js +177 -0
  36. package/build/dist/source/util/LinkedListRenovation.d.ts +20 -0
  37. package/build/dist/source/util/LinkedListRenovation.js +134 -0
  38. package/build/dist/source/util/{ScriptedList.d.ts → ReconciliationList.d.ts} +17 -15
  39. package/build/dist/source/util/{ScriptedList.js → ReconciliationList.js} +91 -90
  40. package/package.json +10 -9
  41. package/build/dist/source/core/MvccMergeList.d.ts +0 -27
  42. package/build/dist/source/core/MvccMergeList.js +0 -25
@@ -18,12 +18,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
18
18
  };
19
19
  import { misuse } from "../util/Dbg.js";
20
20
  import { Uri } from "../util/Uri.js";
21
- import { ScriptedList } from "../util/ScriptedList.js";
21
+ import { ReconciliationList } from "../util/ReconciliationList.js";
22
22
  import { emitLetters, flags, getCallerInfo, proceedSyncOrAsync } from "../util/Utils.js";
23
23
  import { Priority, Mode, Isolation, Reentrance } from "../Enums.js";
24
- import { ObservableObject } from "../core/Mvcc.js";
24
+ import { SxObject } from "../core/Mvcc.js";
25
25
  import { Transaction } from "../core/Transaction.js";
26
- import { ReactiveSystem, options, observable, reactive, runAtomically, runNonReactively, manageReactiveOperation, disposeObservableObject } from "../System.js";
26
+ import { ReactiveSystem, options, signal, reaction, runTransactional, runNonReactive, manageReaction, disposeSignallingObject as disposeSignallingObject } from "../System.js";
27
27
  export function declare(driver, scriptOrDeclaration, scriptAsync, key, mode, preparation, preparationAsync, finalization, triggers, basis) {
28
28
  let result;
29
29
  let declaration;
@@ -46,18 +46,18 @@ export function declare(driver, scriptOrDeclaration, scriptAsync, key, mode, pre
46
46
  if (result.driver !== driver && driver !== undefined)
47
47
  throw misuse(`changing element driver is not yet supported: "${result.driver.name}" -> "${driver === null || driver === void 0 ? void 0 : driver.name}"`);
48
48
  const exTriggers = result.declaration.triggers;
49
- if (observablesAreEqual(declaration.triggers, exTriggers))
49
+ if (signalsAreEqual(declaration.triggers, exTriggers))
50
50
  declaration.triggers = exTriggers;
51
51
  result.declaration = declaration;
52
52
  }
53
53
  else {
54
- result = new ReactiveTreeNodeImpl(effectiveKey || generateKey(owner), driver, declaration, owner);
54
+ result = new ReactiveTreeNode$(effectiveKey || generateKey(owner), driver, declaration, owner);
55
55
  result.slot = children.add(result);
56
56
  }
57
57
  }
58
58
  else {
59
- result = new ReactiveTreeNodeImpl(effectiveKey || generateKey(owner), driver, declaration, owner);
60
- result.slot = ScriptedList.createItem(result);
59
+ result = new ReactiveTreeNode$(effectiveKey || generateKey(owner), driver, declaration, owner);
60
+ result.slot = ReconciliationList.createItem(result);
61
61
  }
62
62
  return result;
63
63
  }
@@ -74,7 +74,7 @@ export function launch(node, triggers) {
74
74
  }
75
75
  export class ReactiveTreeNode {
76
76
  static get current() {
77
- return ReactiveTreeNodeImpl.nodeSlot.instance;
77
+ return ReactiveTreeNode$.nodeSlot.instance;
78
78
  }
79
79
  static get isFirstScriptRun() {
80
80
  return ReactiveTreeNode.current.stamp === 1;
@@ -82,7 +82,7 @@ export class ReactiveTreeNode {
82
82
  static launchScript(node, triggers) {
83
83
  const impl = node;
84
84
  const declaration = impl.declaration;
85
- if (node.stamp >= Number.MAX_SAFE_INTEGER || !observablesAreEqual(triggers, declaration.triggers)) {
85
+ if (node.stamp >= Number.MAX_SAFE_INTEGER || !signalsAreEqual(triggers, declaration.triggers)) {
86
86
  declaration.triggers = triggers;
87
87
  launchScriptViaSlot(impl.slot);
88
88
  }
@@ -92,7 +92,7 @@ export class ReactiveTreeNode {
92
92
  launchFinalizationViaSlot(impl.slot, true, true);
93
93
  }
94
94
  static launchNestedNodesThenDo(action) {
95
- launchNestedNodesThenDoImpl(ReactiveTreeNodeImpl.nodeSlot, undefined, action);
95
+ launchNestedNodesThenDoImpl(ReactiveTreeNode$.nodeSlot, undefined, action);
96
96
  }
97
97
  static markAsMounted(node, yes) {
98
98
  const n = node;
@@ -131,10 +131,10 @@ export class ReactiveTreeNode {
131
131
  ReactiveTreeNode.forEachChildRecursively(child.instance, action);
132
132
  }
133
133
  static getDefaultLoggingOptions() {
134
- return ReactiveTreeNodeImpl.logging;
134
+ return ReactiveTreeNode$.logging;
135
135
  }
136
136
  static setDefaultLoggingOptions(logging) {
137
- ReactiveTreeNodeImpl.logging = logging;
137
+ ReactiveTreeNode$.logging = logging;
138
138
  }
139
139
  }
140
140
  ReactiveTreeNode.shortFrameDuration = 16;
@@ -173,13 +173,13 @@ export class ReactiveTreeVariable {
173
173
  this.defaultValue = defaultValue;
174
174
  }
175
175
  set value(value) {
176
- ReactiveTreeNodeImpl.setTreeVariableValue(this, value);
176
+ ReactiveTreeNode$.setTreeVariableValue(this, value);
177
177
  }
178
178
  get value() {
179
- return ReactiveTreeNodeImpl.useTreeVariableValue(this);
179
+ return ReactiveTreeNode$.useTreeVariableValue(this);
180
180
  }
181
181
  get valueOrUndefined() {
182
- return ReactiveTreeNodeImpl.tryUseTreeVariableValue(this);
182
+ return ReactiveTreeNode$.tryUseTreeVariableValue(this);
183
183
  }
184
184
  }
185
185
  export function generateKey(owner) {
@@ -234,7 +234,7 @@ function invokeFinalizationUsingBasisChain(element, declaration) {
234
234
  else if (basis)
235
235
  invokeFinalizationUsingBasisChain(element, basis);
236
236
  }
237
- class ReactiveTreeNodeContextImpl extends ObservableObject {
237
+ class ReactiveTreeNodeContext$ extends SxObject {
238
238
  constructor(variable, value) {
239
239
  super();
240
240
  this.next = undefined;
@@ -243,14 +243,14 @@ class ReactiveTreeNodeContextImpl extends ObservableObject {
243
243
  }
244
244
  }
245
245
  __decorate([
246
- observable(false),
246
+ signal(false),
247
247
  __metadata("design:type", Object)
248
- ], ReactiveTreeNodeContextImpl.prototype, "next", void 0);
248
+ ], ReactiveTreeNodeContext$.prototype, "next", void 0);
249
249
  __decorate([
250
- observable(false),
250
+ signal(false),
251
251
  __metadata("design:type", ReactiveTreeVariable)
252
- ], ReactiveTreeNodeContextImpl.prototype, "variable", void 0);
253
- class ReactiveTreeNodeImpl extends ReactiveTreeNode {
252
+ ], ReactiveTreeNodeContext$.prototype, "variable", void 0);
253
+ class ReactiveTreeNode$ extends ReactiveTreeNode {
254
254
  constructor(key, driver, declaration, owner) {
255
255
  super();
256
256
  const thisAsUnknown = this;
@@ -270,16 +270,16 @@ class ReactiveTreeNodeImpl extends ReactiveTreeNode {
270
270
  }
271
271
  this.element = driver.create(this);
272
272
  this.host = thisAsUnknown;
273
- this.children = new ScriptedList(getNodeKey, true);
273
+ this.children = new ReconciliationList(getNodeKey, true);
274
274
  this.slot = undefined;
275
275
  this.stamp = Number.MAX_SAFE_INTEGER;
276
276
  this.context = undefined;
277
277
  this.numerator = 0;
278
278
  this.priority = Priority.realtime;
279
279
  this.childrenShuffling = false;
280
- ReactiveTreeNodeImpl.grandNodeCount++;
280
+ ReactiveTreeNode$.grandNodeCount++;
281
281
  if (this.has(Mode.autonomous))
282
- ReactiveTreeNodeImpl.disposableNodeCount++;
282
+ ReactiveTreeNode$.disposableNodeCount++;
283
283
  }
284
284
  getUri(relativeTo) {
285
285
  const path = [];
@@ -309,7 +309,7 @@ class ReactiveTreeNodeImpl extends ReactiveTreeNode {
309
309
  configureReactivity(options) {
310
310
  if (this.stamp < Number.MAX_SAFE_INTEGER - 1 || !this.has(Mode.autonomous))
311
311
  throw misuse("reactronic can be configured only for elements with autonomous mode and only during preparation");
312
- return manageReactiveOperation(this.script).configure(options);
312
+ return manageReaction(this.script).configure(options);
313
313
  }
314
314
  static get nodeSlot() {
315
315
  if (!gNodeSlot)
@@ -318,35 +318,35 @@ class ReactiveTreeNodeImpl extends ReactiveTreeNode {
318
318
  }
319
319
  static tryUseTreeVariableValue(variable) {
320
320
  var _a, _b;
321
- let node = ReactiveTreeNodeImpl.nodeSlot.instance;
321
+ let node = ReactiveTreeNode$.nodeSlot.instance;
322
322
  while (((_a = node.context) === null || _a === void 0 ? void 0 : _a.variable) !== variable && node.owner !== node)
323
323
  node = node.outer.slot.instance;
324
324
  return (_b = node.context) === null || _b === void 0 ? void 0 : _b.value;
325
325
  }
326
326
  static useTreeVariableValue(variable) {
327
327
  var _a;
328
- const result = (_a = ReactiveTreeNodeImpl.tryUseTreeVariableValue(variable)) !== null && _a !== void 0 ? _a : variable.defaultValue;
328
+ const result = (_a = ReactiveTreeNode$.tryUseTreeVariableValue(variable)) !== null && _a !== void 0 ? _a : variable.defaultValue;
329
329
  if (!result)
330
330
  throw misuse("unknown node variable");
331
331
  return result;
332
332
  }
333
333
  static setTreeVariableValue(variable, value) {
334
- const node = ReactiveTreeNodeImpl.nodeSlot.instance;
334
+ const node = ReactiveTreeNode$.nodeSlot.instance;
335
335
  const owner = node.owner;
336
- const hostCtx = runNonReactively(() => { var _a; return (_a = owner.context) === null || _a === void 0 ? void 0 : _a.value; });
336
+ const hostCtx = runNonReactive(() => { var _a; return (_a = owner.context) === null || _a === void 0 ? void 0 : _a.value; });
337
337
  if (value && value !== hostCtx) {
338
338
  if (hostCtx)
339
339
  node.outer = owner;
340
340
  else
341
341
  node.outer = owner.outer;
342
- runAtomically({ isolation: Isolation.joinAsNestedTransaction }, () => {
342
+ runTransactional({ isolation: Isolation.joinAsNestedTransaction }, () => {
343
343
  const ctx = node.context;
344
344
  if (ctx) {
345
345
  ctx.variable = variable;
346
346
  ctx.value = value;
347
347
  }
348
348
  else
349
- node.context = new ReactiveTreeNodeContextImpl(variable, value);
349
+ node.context = new ReactiveTreeNodeContext$(variable, value);
350
350
  });
351
351
  }
352
352
  else if (hostCtx)
@@ -355,21 +355,21 @@ class ReactiveTreeNodeImpl extends ReactiveTreeNode {
355
355
  node.outer = owner.outer;
356
356
  }
357
357
  }
358
- ReactiveTreeNodeImpl.logging = undefined;
359
- ReactiveTreeNodeImpl.grandNodeCount = 0;
360
- ReactiveTreeNodeImpl.disposableNodeCount = 0;
358
+ ReactiveTreeNode$.logging = undefined;
359
+ ReactiveTreeNode$.grandNodeCount = 0;
360
+ ReactiveTreeNode$.disposableNodeCount = 0;
361
361
  __decorate([
362
- reactive,
362
+ reaction,
363
363
  options({
364
364
  reentrance: Reentrance.cancelAndWaitPrevious,
365
365
  allowObsoleteToFinish: true,
366
- observableArgs: true,
366
+ signalArgs: true,
367
367
  noSideEffects: false,
368
368
  }),
369
369
  __metadata("design:type", Function),
370
370
  __metadata("design:paramtypes", [Object]),
371
371
  __metadata("design:returntype", void 0)
372
- ], ReactiveTreeNodeImpl.prototype, "script", null);
372
+ ], ReactiveTreeNode$.prototype, "script", null);
373
373
  function gatherAuthorityAndPath(node, path, relativeTo) {
374
374
  let authority;
375
375
  if (node.owner !== node && node.owner !== relativeTo) {
@@ -388,10 +388,10 @@ function launchNestedNodesThenDoImpl(nodeSlot, error, action) {
388
388
  var _a;
389
389
  const owner = nodeSlot.instance;
390
390
  const children = owner.children;
391
- if (children.isScriptingInProgress) {
391
+ if (children.isReconciliationInProgress) {
392
392
  let promised = undefined;
393
393
  try {
394
- children.endScriptExecution(error);
394
+ children.endReconciliation(error);
395
395
  for (const child of children.itemsRemoved(true))
396
396
  launchFinalizationViaSlot(child, true, true);
397
397
  if (!error) {
@@ -454,9 +454,9 @@ function runNestedScriptsIncrementally(owner, stamp, allChildren, items, priorit
454
454
  return __awaiter(this, void 0, void 0, function* () {
455
455
  yield Transaction.requestNextFrame();
456
456
  const node = owner.instance;
457
- if (!Transaction.isCanceled || !Transaction.isFrameOver(1, ReactiveTreeNodeImpl.shortFrameDuration / 3)) {
458
- let outerPriority = ReactiveTreeNodeImpl.currentScriptPriority;
459
- ReactiveTreeNodeImpl.currentScriptPriority = priority;
457
+ if (!Transaction.isCanceled || !Transaction.isFrameOver(1, ReactiveTreeNode$.shortFrameDuration / 3)) {
458
+ let outerPriority = ReactiveTreeNode$.currentScriptPriority;
459
+ ReactiveTreeNode$.currentScriptPriority = priority;
460
460
  try {
461
461
  if (node.childrenShuffling)
462
462
  shuffle(items);
@@ -465,10 +465,10 @@ function runNestedScriptsIncrementally(owner, stamp, allChildren, items, priorit
465
465
  for (const child of items) {
466
466
  launchScriptViaSlot(child);
467
467
  if (Transaction.isFrameOver(1, frameDuration)) {
468
- ReactiveTreeNodeImpl.currentScriptPriority = outerPriority;
468
+ ReactiveTreeNode$.currentScriptPriority = outerPriority;
469
469
  yield Transaction.requestNextFrame(0);
470
- outerPriority = ReactiveTreeNodeImpl.currentScriptPriority;
471
- ReactiveTreeNodeImpl.currentScriptPriority = priority;
470
+ outerPriority = ReactiveTreeNode$.currentScriptPriority;
471
+ ReactiveTreeNode$.currentScriptPriority = priority;
472
472
  frameDuration = Math.min(4 * frameDuration, Math.min(frameDurationLimit, ReactiveTreeNode.frameDuration));
473
473
  }
474
474
  if (Transaction.isCanceled && Transaction.isFrameOver(1, ReactiveTreeNode.shortFrameDuration / 3))
@@ -476,7 +476,7 @@ function runNestedScriptsIncrementally(owner, stamp, allChildren, items, priorit
476
476
  }
477
477
  }
478
478
  finally {
479
- ReactiveTreeNodeImpl.currentScriptPriority = outerPriority;
479
+ ReactiveTreeNode$.currentScriptPriority = outerPriority;
480
480
  }
481
481
  }
482
482
  });
@@ -489,23 +489,23 @@ function launchScriptViaSlot(nodeSlot) {
489
489
  Transaction.outside(() => {
490
490
  if (ReactiveSystem.isLogging)
491
491
  ReactiveSystem.setLoggingHint(node.element, node.key);
492
- manageReactiveOperation(node.script).configure({
492
+ manageReaction(node.script).configure({
493
493
  order: node.level,
494
494
  });
495
495
  });
496
496
  }
497
- runNonReactively(node.script, node.declaration.triggers);
497
+ runNonReactive(node.script, node.declaration.triggers);
498
498
  }
499
499
  else if (node.owner !== node)
500
500
  runScriptNow(nodeSlot);
501
501
  else
502
- runAtomically(() => runScriptNow(nodeSlot));
502
+ runTransactional(() => runScriptNow(nodeSlot));
503
503
  }
504
504
  }
505
505
  function mountOrRemountIfNecessary(node) {
506
506
  const driver = node.driver;
507
507
  if (node.stamp === Number.MAX_SAFE_INTEGER) {
508
- runNonReactively(() => {
508
+ runNonReactive(() => {
509
509
  node.stamp = Number.MAX_SAFE_INTEGER - 1;
510
510
  driver.runPreparation(node);
511
511
  if (!node.has(Mode.external)) {
@@ -516,7 +516,7 @@ function mountOrRemountIfNecessary(node) {
516
516
  });
517
517
  }
518
518
  else if (node.isMoved && !node.has(Mode.external) && node.host !== node)
519
- runNonReactively(() => driver.runMount(node));
519
+ runNonReactive(() => driver.runMount(node));
520
520
  }
521
521
  function runScriptNow(nodeSlot) {
522
522
  const node = nodeSlot.instance;
@@ -528,7 +528,7 @@ function runScriptNow(nodeSlot) {
528
528
  try {
529
529
  node.stamp++;
530
530
  node.numerator = 0;
531
- node.children.beginScriptExecution();
531
+ node.children.beginReconciliation();
532
532
  const driver = node.driver;
533
533
  result = driver.runScript(node);
534
534
  result = proceedSyncOrAsync(result, v => { launchNestedNodesThenDoImpl(nodeSlot, undefined, NOP); return v; }, e => { console.log(e); launchNestedNodesThenDoImpl(nodeSlot, e !== null && e !== void 0 ? e : new Error("unknown error"), NOP); });
@@ -549,7 +549,7 @@ function launchFinalizationViaSlot(nodeSlot, isLeader, individual) {
549
549
  if (individual && node.key !== node.declaration.key && !driver.isPartition)
550
550
  console.log(`WARNING: it is recommended to assign explicit key for conditional element in order to avoid unexpected side effects: ${node.key}`);
551
551
  node.stamp = ~node.stamp;
552
- const childrenAreLeaders = runNonReactively(() => driver.runFinalization(node, isLeader));
552
+ const childrenAreLeaders = runNonReactive(() => driver.runFinalization(node, isLeader));
553
553
  if (node.has(Mode.autonomous)) {
554
554
  nodeSlot.aux = undefined;
555
555
  const last = gLastToDispose;
@@ -558,13 +558,13 @@ function launchFinalizationViaSlot(nodeSlot, isLeader, individual) {
558
558
  else
559
559
  gFirstToDispose = gLastToDispose = nodeSlot;
560
560
  if (gFirstToDispose === nodeSlot)
561
- runAtomically({ isolation: Isolation.disjoinForInternalDisposal, hint: `runDisposalLoop(initiator=${nodeSlot.instance.key})` }, () => {
561
+ runTransactional({ isolation: Isolation.disjoinForInternalDisposal, hint: `runDisposalLoop(initiator=${nodeSlot.instance.key})` }, () => {
562
562
  void runDisposalLoop().then(NOP, error => console.log(error));
563
563
  });
564
564
  }
565
565
  for (const child of node.children.items())
566
566
  launchFinalizationViaSlot(child, childrenAreLeaders, false);
567
- ReactiveTreeNodeImpl.grandNodeCount--;
567
+ ReactiveTreeNode$.grandNodeCount--;
568
568
  }
569
569
  }
570
570
  function runDisposalLoop() {
@@ -574,9 +574,9 @@ function runDisposalLoop() {
574
574
  while (slot !== undefined) {
575
575
  if (Transaction.isFrameOver(500, 5))
576
576
  yield Transaction.requestNextFrame();
577
- disposeObservableObject(slot.instance);
577
+ disposeSignallingObject(slot.instance);
578
578
  slot = slot.aux;
579
- ReactiveTreeNodeImpl.disposableNodeCount--;
579
+ ReactiveTreeNode$.disposableNodeCount--;
580
580
  }
581
581
  gFirstToDispose = gLastToDispose = undefined;
582
582
  });
@@ -602,7 +602,7 @@ function runInsideContextOfNode(nodeSlot, func, ...args) {
602
602
  gNodeSlot = outer;
603
603
  }
604
604
  }
605
- export function observablesAreEqual(a1, a2) {
605
+ export function signalsAreEqual(a1, a2) {
606
606
  let result = a1 === a2;
607
607
  if (!result) {
608
608
  if (Array.isArray(a1)) {
@@ -0,0 +1,52 @@
1
+ export type Extractor<T, Result> = (item: T) => Result;
2
+ export type KeyExtractor<T> = Extractor<T, string | undefined>;
3
+ export declare class LinkedList<T extends LinkedItem<T>> {
4
+ readonly keyOf: KeyExtractor<T>;
5
+ private isStrictOrder$;
6
+ private map;
7
+ items$: LinkedSubList<T>;
8
+ former$: LinkedSubList<T> | undefined;
9
+ constructor(keyExtractor: KeyExtractor<T>, isStrictOrder?: boolean);
10
+ get isStrictOrder(): boolean;
11
+ set isStrictOrder(value: boolean);
12
+ get isRenovationInProgress(): boolean;
13
+ get count(): number;
14
+ items(): Generator<T>;
15
+ lookup(key: string | undefined): T | undefined;
16
+ add(item: T, before?: T): void;
17
+ move(item: T, before: T | undefined): void;
18
+ remove(item: T): void;
19
+ static move$<T extends LinkedItem<T>>(list: LinkedList<T>, item: T, before: T | undefined): void;
20
+ static remove$<T extends LinkedItem<T>>(list: LinkedList<T>, item: T): void;
21
+ static removeKey$<T extends LinkedItem<T>>(list: LinkedList<T>, key: string | undefined): void;
22
+ }
23
+ export declare enum Mark {
24
+ prolonged = 0,
25
+ added = 1,
26
+ modified = 2,
27
+ removed = 3
28
+ }
29
+ export declare class LinkedItem<T extends LinkedItem<T>> {
30
+ private list$;
31
+ private next$;
32
+ private prev$;
33
+ private status;
34
+ constructor();
35
+ get list(): LinkedSubList<T> | undefined;
36
+ get next(): T | undefined;
37
+ get prev(): T | undefined;
38
+ get mark(): Mark;
39
+ get rank(): number;
40
+ get isManagedExternally(): boolean;
41
+ static setStatus$<T extends LinkedItem<T>>(item: T, mark: Mark, rank: number): void;
42
+ static link$<T extends LinkedItem<T>>(list: LinkedSubList<T> | undefined, item: T, before: T | undefined): void;
43
+ private static unlink;
44
+ }
45
+ export declare class LinkedSubList<T extends LinkedItem<T>> {
46
+ count: number;
47
+ first?: T;
48
+ last?: T;
49
+ items(): Generator<T>;
50
+ clear(): void;
51
+ grab(from: LinkedSubList<T>, join: boolean): void;
52
+ }
@@ -0,0 +1,177 @@
1
+ import { misuse } from "./Dbg.js";
2
+ export class LinkedList {
3
+ constructor(keyExtractor, isStrictOrder = false) {
4
+ this.keyOf = keyExtractor;
5
+ this.isStrictOrder$ = isStrictOrder;
6
+ this.map = new Map();
7
+ this.items$ = new LinkedSubList();
8
+ this.former$ = undefined;
9
+ }
10
+ get isStrictOrder() { return this.isStrictOrder$; }
11
+ set isStrictOrder(value) {
12
+ if (this.former$ !== undefined)
13
+ throw misuse("cannot change strict mode in the middle of renovation");
14
+ this.isStrictOrder$ = value;
15
+ }
16
+ get isRenovationInProgress() {
17
+ return this.former$ !== undefined;
18
+ }
19
+ get count() {
20
+ var _a, _b;
21
+ return this.items$.count + ((_b = (_a = this.former$) === null || _a === void 0 ? void 0 : _a.count) !== null && _b !== void 0 ? _b : 0);
22
+ }
23
+ items() {
24
+ return this.items$.items();
25
+ }
26
+ lookup(key) {
27
+ return this.map.get(key);
28
+ }
29
+ add(item, before) {
30
+ const key = this.keyOf(item);
31
+ if (this.map.get(key) !== undefined)
32
+ throw misuse(`item with given key already exists: ${key}`);
33
+ this.map.set(key, item);
34
+ LinkedItem.link$(this.items$, item, before);
35
+ }
36
+ move(item, before) {
37
+ if (item.list !== this.items$)
38
+ throw misuse("cannot move item that belongs to another list");
39
+ if (!item.isManagedExternally)
40
+ throw misuse("cannot move given item outside of renovation cycle");
41
+ LinkedList.move$(this, item, before);
42
+ }
43
+ remove(item) {
44
+ if (item.list !== this.items$)
45
+ throw misuse("cannot remove item that belongs to another list");
46
+ if (!item.isManagedExternally)
47
+ throw misuse("cannot remove given item outside of renovation cycle");
48
+ LinkedList.remove$(this, item);
49
+ }
50
+ static move$(list, item, before) {
51
+ LinkedItem.link$(list.items$, item, before);
52
+ }
53
+ static remove$(list, item) {
54
+ LinkedList.removeKey$(list, list.keyOf(item));
55
+ LinkedItem.link$(undefined, item, undefined);
56
+ }
57
+ static removeKey$(list, key) {
58
+ list.map.delete(key);
59
+ }
60
+ }
61
+ export var Mark;
62
+ (function (Mark) {
63
+ Mark[Mark["prolonged"] = 0] = "prolonged";
64
+ Mark[Mark["added"] = 1] = "added";
65
+ Mark[Mark["modified"] = 2] = "modified";
66
+ Mark[Mark["removed"] = 3] = "removed";
67
+ })(Mark || (Mark = {}));
68
+ const MARK_MOD = 4;
69
+ export class LinkedItem {
70
+ constructor() {
71
+ this.list$ = undefined;
72
+ this.next$ = undefined;
73
+ this.prev$ = undefined;
74
+ this.status = 0;
75
+ }
76
+ get list() { return this.list$; }
77
+ get next() { return this.next$; }
78
+ get prev() { return this.prev$; }
79
+ get mark() { return this.status % MARK_MOD; }
80
+ get rank() { return Math.trunc(this.status / MARK_MOD); }
81
+ get isManagedExternally() { return this.status === 0; }
82
+ static setStatus$(item, mark, rank) {
83
+ item.status = rank * MARK_MOD + mark;
84
+ }
85
+ static link$(list, item, before) {
86
+ if (before === undefined) {
87
+ LinkedItem.unlink(item);
88
+ if (list !== undefined) {
89
+ item.list$ = list;
90
+ const last = list.last;
91
+ item.prev$ = last;
92
+ item.next$ = undefined;
93
+ if (last !== undefined)
94
+ list.last = last.next$ = item;
95
+ else
96
+ list.first = list.last = item;
97
+ list.count++;
98
+ }
99
+ else {
100
+ item.list$ = undefined;
101
+ item.next$ = undefined;
102
+ item.prev$ = undefined;
103
+ }
104
+ }
105
+ else {
106
+ if (list === before.list && list !== undefined) {
107
+ LinkedItem.unlink(item);
108
+ const after = before.prev$;
109
+ item.prev$ = after;
110
+ item.next$ = before;
111
+ before.prev$ = item;
112
+ if (after !== undefined)
113
+ after.next$ = item;
114
+ if (before == list.first)
115
+ list.first = item;
116
+ item.list$ = list;
117
+ list.count++;
118
+ }
119
+ else {
120
+ if (list !== before.list)
121
+ throw misuse("sibling is not in the given list");
122
+ else if (before.list === undefined)
123
+ throw misuse("cannot link to sibling that is not in a list");
124
+ else
125
+ throw misuse("linked list invariant is broken");
126
+ }
127
+ }
128
+ }
129
+ static unlink(item) {
130
+ const list = item.list;
131
+ if (list) {
132
+ const prev = item.prev$;
133
+ if (prev !== undefined)
134
+ prev.next$ = item.next$;
135
+ const next = item.next$;
136
+ if (next !== undefined)
137
+ next.prev$ = item.prev$;
138
+ if (item === list.first)
139
+ list.first = item.next$;
140
+ if (item === list.last)
141
+ list.last = undefined;
142
+ list.count--;
143
+ }
144
+ }
145
+ }
146
+ export class LinkedSubList {
147
+ constructor() {
148
+ this.count = 0;
149
+ this.first = undefined;
150
+ this.last = undefined;
151
+ }
152
+ *items() {
153
+ let x = this.first;
154
+ while (x !== undefined) {
155
+ const next = x.next;
156
+ yield x;
157
+ x = next;
158
+ }
159
+ }
160
+ clear() {
161
+ this.count = 0;
162
+ this.first = undefined;
163
+ this.last = undefined;
164
+ }
165
+ grab(from, join) {
166
+ const head = from.first;
167
+ if (join !== undefined && head !== undefined) {
168
+ this.count += from.count;
169
+ }
170
+ else {
171
+ this.count = from.count;
172
+ this.first = head;
173
+ this.last = from.last;
174
+ }
175
+ from.clear();
176
+ }
177
+ }
@@ -0,0 +1,20 @@
1
+ import { LinkedList, LinkedItem } from "./LinkedList.js";
2
+ export declare class LinkedListRenovation<T extends LinkedItem<T>> {
3
+ readonly list: LinkedList<T>;
4
+ readonly diff: Array<T> | undefined;
5
+ private lost$;
6
+ private expected;
7
+ private absent;
8
+ constructor(list: LinkedList<T>, diff?: Array<T>);
9
+ lookup(key: string | undefined): T | undefined;
10
+ tryToProlonge(key: string, resolution?: {
11
+ isDuplicate: boolean;
12
+ }, error?: string): T | undefined;
13
+ thisIsAdded(item: T, before?: T): T;
14
+ thisIsModified(item: T): void;
15
+ thisIsMoved(item: T, before: T | undefined): void;
16
+ thisIsRemoved(item: T): void;
17
+ get lostItemCount(): number;
18
+ lostItems(): Generator<T>;
19
+ done(error?: unknown): void;
20
+ }