reactronic 0.24.125 → 0.24.127
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 +15 -190
- package/build/dist/source/Options.d.ts +10 -10
- package/build/dist/source/Options.js +10 -10
- package/build/dist/source/RxSystem.js +3 -3
- package/build/dist/source/core/Mvcc.js +3 -3
- package/build/dist/source/core/Reaction.d.ts +1 -1
- package/build/dist/source/core/Reaction.js +21 -21
- package/build/dist/source/core/RxNode.d.ts +7 -6
- package/build/dist/source/core/RxNode.js +27 -23
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -253,11 +253,11 @@ of recurring changes:
|
|
|
253
253
|
**Reentrance** option defines how to handle reentrant calls of transactional
|
|
254
254
|
and reactive functions:
|
|
255
255
|
|
|
256
|
-
- `
|
|
257
|
-
- `
|
|
258
|
-
- `
|
|
259
|
-
- `
|
|
260
|
-
- `
|
|
256
|
+
- `preventWithError` - fail with error if there is an existing call in progress;
|
|
257
|
+
- `waitAndRestart` - wait for previous call to finish and then restart current one;
|
|
258
|
+
- `cancelPrevious` - cancel previous call in favor of recent one;
|
|
259
|
+
- `cancelAndWaitPrevious` - cancel previous call in favor of recent one (but wait until canceling is completed)
|
|
260
|
+
- `runSideBySide` - multiple simultaneous calls are allowed.
|
|
261
261
|
|
|
262
262
|
**Monitor** is an object that maintains status of running functions,
|
|
263
263
|
which it is attached to. A single monitor object can be shared between
|
|
@@ -330,19 +330,19 @@ type MemberOptions = {
|
|
|
330
330
|
}
|
|
331
331
|
|
|
332
332
|
enum Kind {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
333
|
+
plain = 0,
|
|
334
|
+
transactional = 1,
|
|
335
|
+
reactive = 2,
|
|
336
|
+
cached = 3
|
|
337
337
|
}
|
|
338
338
|
|
|
339
339
|
enum Reentrance {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
340
|
+
preventWithError = 1, // fail with error if there is an existing call in progress (default)
|
|
341
|
+
waitAndRestart = 0, // wait for existing call to finish and then restart current one
|
|
342
|
+
cancelPrevious = -1, // cancel previous call in favor of recent one
|
|
343
|
+
cancelAndWaitPrevious = -2, // cancel previous call in favor of recent one (but wait until canceling is completed)
|
|
344
|
+
overwritePrevious = -2, // allow previous to complete, but overwrite it with ignoring any conflicts
|
|
345
|
+
runSideBySide = -3 // multiple simultaneous calls are allowed
|
|
346
346
|
}
|
|
347
347
|
|
|
348
348
|
class Monitor {
|
|
@@ -446,181 +446,6 @@ class Reactronic {
|
|
|
446
446
|
|
|
447
447
|
```
|
|
448
448
|
|
|
449
|
-
## API (Artel)
|
|
450
|
-
|
|
451
|
-
```артель
|
|
452
|
-
// Classes
|
|
453
|
-
|
|
454
|
-
тип ТранзакционныйОбъект = объект { }
|
|
455
|
-
тип НаблюдаемыйОбъект = объект на основе ТранзакционныйОбъект { }
|
|
456
|
-
|
|
457
|
-
// Decorators & Operators
|
|
458
|
-
|
|
459
|
-
// function raw(proto, prop) // field only
|
|
460
|
-
// function transaction(proto, prop, pd) // method only
|
|
461
|
-
// function reactive(proto, prop, pd) // method only
|
|
462
|
-
// function cached(proto, prop, pd) // method only
|
|
463
|
-
// function options(value: Partial<MemberOptions>): F<any>
|
|
464
|
-
|
|
465
|
-
// function unobs<T>(func: F<T>, ...args: any[]): T
|
|
466
|
-
// function sensitive<T>(sensitivity: Sensitivity, func: F<T>, ...args: any[]): T
|
|
467
|
-
|
|
468
|
-
// SnapshotOptions, MemberOptions, Kind, Reentrance, Monitor, LoggingOptions, ProfilingOptions
|
|
469
|
-
|
|
470
|
-
тип НастройкиТранзакции = интерфейс
|
|
471
|
-
{
|
|
472
|
-
постоянная подсказка: Текст?
|
|
473
|
-
постоянное раздельно?: РежимРазделения
|
|
474
|
-
постоянный журнал: Журнал?
|
|
475
|
-
постоянное журнализация: Выборочно<НастройкиЖурнализации>
|
|
476
|
-
постоянный ключ: Нечто?
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
тип НастройкиЧленаОбъекта = интерфейс
|
|
480
|
-
{
|
|
481
|
-
постоянный разновидность: Разновидность
|
|
482
|
-
постоянное раздельно?: РежимРазделения
|
|
483
|
-
постоянный порядок: Целое
|
|
484
|
-
постоянный безПобочныхЭффектов: Булево
|
|
485
|
-
постоянный триггерныеАргументы: Булево
|
|
486
|
-
постоянный дроссель: Целое // миллисекунды, -1 немедленно, Целое.Макс никогда
|
|
487
|
-
постоянный рецидив: Рецидив
|
|
488
|
-
постоянный журнал: Журнал?
|
|
489
|
-
постоянный монитор: Монитор?
|
|
490
|
-
постоянная журнализация: Выборочно<НастройкиЖурнализации>
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
тип Разновидность = вариант
|
|
494
|
-
{
|
|
495
|
-
Plain = 0
|
|
496
|
-
Транзакционное = 1
|
|
497
|
-
Реактивное = 2
|
|
498
|
-
Кэшируемое = 3
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
тип Рецидив = вариант
|
|
502
|
-
{
|
|
503
|
-
PreventWithError = 1, // fail with error if there is an existing call in progress (default)
|
|
504
|
-
WaitAndRestart = 0, // wait for existing call to finish and then restart current one
|
|
505
|
-
CancelPrevious = -1, // cancel previous call in favor of recent one
|
|
506
|
-
CancelAndWaitPrevious = -2, // cancel previous call in favor of recent one (but wait until canceling is completed)
|
|
507
|
-
OverwritePrevious = -2, // allow previous to complete, but overwrite it with ignoring any conflicts
|
|
508
|
-
RunSideBySide = -3 // multiple simultaneous calls are allowed
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
тип Монитор = объект
|
|
512
|
-
{
|
|
513
|
-
постоянное активно: Булево
|
|
514
|
-
постоянный счетчик: Целое
|
|
515
|
-
постоянные работы: ЧитаемоеМножество<Работа>
|
|
516
|
-
при создании(подсказка: Текст,
|
|
517
|
-
задержкаАктивации: Целое, задержкаДеактивации: Целое)
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
тип Работа = интерфейс
|
|
521
|
-
{
|
|
522
|
-
постоянный код: Целое
|
|
523
|
-
постоянная подсказка: Текст
|
|
524
|
-
отменено: Булево
|
|
525
|
-
завершено: Булево
|
|
526
|
-
операция отменить(о: Ошибка?, повторПосле: Транзакция?)
|
|
527
|
-
параллельная операция ожидание-окончания()
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
тип НастройкиЖурнализации = интерфейс
|
|
531
|
-
{
|
|
532
|
-
постоянный выключено: Булево
|
|
533
|
-
постоянный транзакция: Булево
|
|
534
|
-
постоянный операция: Булево
|
|
535
|
-
постоянный шаг: Булево
|
|
536
|
-
постоянный монитор: Булево
|
|
537
|
-
постоянный чтение: Булево
|
|
538
|
-
постоянный запись: Булево
|
|
539
|
-
постоянный изменение: Булево
|
|
540
|
-
постоянный аннулирование: Булево
|
|
541
|
-
постоянный ошибка: Булево
|
|
542
|
-
постоянный предупреждение: Булево
|
|
543
|
-
постоянный уборка-мусора: Булево
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
тип НастройкиПрофилирования =
|
|
547
|
-
{
|
|
548
|
-
порогПредупрежденияПриМногократномИспользовании: Целое // 10 раз
|
|
549
|
-
порогПредупрежденияПриБлокировкеГлавногоПотока: Целое // 16.6 мс
|
|
550
|
-
порогПредупрежденияПриДлительномПараллельномВыполнении: Целое // 150 мс
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
// Транзакция
|
|
554
|
-
|
|
555
|
-
тип Ф<Т> = операция(арг: Элементы<Нечто>): Т
|
|
556
|
-
|
|
557
|
-
тип Транзакция = объект на основе Работа
|
|
558
|
-
{
|
|
559
|
-
общая охраняемая типом текущая: Транзакция
|
|
560
|
-
|
|
561
|
-
охраняемый типом код: Целое
|
|
562
|
-
охраняемая типом подсказка: Текст
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
исполнить<Т>(ф: Ф<Т>, арг: Элементы<Нечто>): Т
|
|
566
|
-
wrap<T>(func: F<T>): F<T>
|
|
567
|
-
зафиксировать()
|
|
568
|
-
опечатать() // a1.seal().whenFinished().then(fulfill, reject)
|
|
569
|
-
отменить(о: Ошибка?, повтор-после: Транзакция? = пусто)
|
|
570
|
-
отменено: Булево
|
|
571
|
-
завершено: Булево
|
|
572
|
-
whenFinished(): Promise<void>
|
|
573
|
-
join<T>(p: Promise<T>): Promise<T>
|
|
574
|
-
|
|
575
|
-
общая операция создать(настройки: НастройкиСнимка?): Транзакция
|
|
576
|
-
общая операция исполнить<Т>(настройки: НастройкиСнимка?, ф: Ф<Т>, арг: Элементы<Т>): Т
|
|
577
|
-
общая операция вне-транзакции<Т>(ф: Ф<Т>, арг: Элементы<Нечто>): Т
|
|
578
|
-
|
|
579
|
-
общая операция фрейм-окончен(шаг: Целое, лимит-времени: Целое): Булево
|
|
580
|
-
общая параллельная операция запросить-следующий-фрейм(время-сна: Целое)
|
|
581
|
-
общее отменено: Булево
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
// Контролер
|
|
585
|
-
|
|
586
|
-
тип Контролер = объект
|
|
587
|
-
{
|
|
588
|
-
охраняемое типом options: Options
|
|
589
|
-
охраняемое типом args: ReadonlyArray<any>
|
|
590
|
-
охраняемое типом value: T
|
|
591
|
-
охраняемое типом error: any
|
|
592
|
-
охраняемое типом stamp: number
|
|
593
|
-
охраняемое типом isUpToDate: boolean
|
|
594
|
-
|
|
595
|
-
настроить(настройки: Выборочно<Настройки>): Настройки
|
|
596
|
-
аннулировать(): Булево
|
|
597
|
-
взять-последний-результат<Т>(арг: Элементы<Нечто>): Т?
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
// Реактроник
|
|
601
|
-
|
|
602
|
-
тип Реактроник = объект
|
|
603
|
-
{
|
|
604
|
-
общая операция почему(кратко: Булево = нет): Текст
|
|
605
|
-
общая операция взятьКэшОперации<Т>(о: Оп<Т>): Кэш<Т>
|
|
606
|
-
общая операция configureCurrentOperation(options: Partial<Options>): Options
|
|
607
|
-
общая операция взятьРевизию(о: Нечто): Целое
|
|
608
|
-
общая операция взятьСнимок<Т>(о: Т): Т
|
|
609
|
-
общая операция dispose(obj: Нечто)
|
|
610
|
-
общая операция reactivityAutoStartDisabled: boolean
|
|
611
|
-
общее охраняемое журнализация-включена: Булево
|
|
612
|
-
общая охраняемое настройки-журнализации: НастройкиЖурнализации
|
|
613
|
-
общая операция пустьРежимЖурнализации(
|
|
614
|
-
вкл: Булево, настройки: НастройкиЖурнализации? = пусто)
|
|
615
|
-
общая операция пустьПодсказкаЖурнализации<Т extends Объект>(
|
|
616
|
-
о: Т, подсказка: Текст?)
|
|
617
|
-
общая операция взятьПодсказкуЖурнализации<Т extends Объект>(о: Т): Текст?
|
|
618
|
-
общая операция пустьРежимПрофилирования(
|
|
619
|
-
вкл: Булево, настройки: Выборочно<НастройкиЖурнализации>? = пусто)
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
```
|
|
623
|
-
|
|
624
449
|
## Contribution
|
|
625
450
|
|
|
626
451
|
By contributing, you agree that your contributions will be
|
|
@@ -24,18 +24,18 @@ export type MemberOptions = {
|
|
|
24
24
|
readonly logging?: Partial<LoggingOptions>;
|
|
25
25
|
};
|
|
26
26
|
export declare enum Kind {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
plain = 0,
|
|
28
|
+
transactional = 1,
|
|
29
|
+
reactive = 2,
|
|
30
|
+
cached = 3
|
|
31
31
|
}
|
|
32
32
|
export declare enum Reentrance {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
preventWithError = 1,
|
|
34
|
+
waitAndRestart = 0,
|
|
35
|
+
cancelPrevious = -1,
|
|
36
|
+
cancelAndWaitPrevious = -2,
|
|
37
|
+
overwritePrevious = -3,
|
|
38
|
+
runSideBySide = -4
|
|
39
39
|
}
|
|
40
40
|
export type AbstractReaction<T> = {
|
|
41
41
|
readonly options: MemberOptions;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
export { LoggingLevel } from "./Logging.js";
|
|
2
2
|
export var Kind;
|
|
3
3
|
(function (Kind) {
|
|
4
|
-
Kind[Kind["
|
|
5
|
-
Kind[Kind["
|
|
6
|
-
Kind[Kind["
|
|
7
|
-
Kind[Kind["
|
|
4
|
+
Kind[Kind["plain"] = 0] = "plain";
|
|
5
|
+
Kind[Kind["transactional"] = 1] = "transactional";
|
|
6
|
+
Kind[Kind["reactive"] = 2] = "reactive";
|
|
7
|
+
Kind[Kind["cached"] = 3] = "cached";
|
|
8
8
|
})(Kind || (Kind = {}));
|
|
9
9
|
export var Reentrance;
|
|
10
10
|
(function (Reentrance) {
|
|
11
|
-
Reentrance[Reentrance["
|
|
12
|
-
Reentrance[Reentrance["
|
|
13
|
-
Reentrance[Reentrance["
|
|
14
|
-
Reentrance[Reentrance["
|
|
15
|
-
Reentrance[Reentrance["
|
|
16
|
-
Reentrance[Reentrance["
|
|
11
|
+
Reentrance[Reentrance["preventWithError"] = 1] = "preventWithError";
|
|
12
|
+
Reentrance[Reentrance["waitAndRestart"] = 0] = "waitAndRestart";
|
|
13
|
+
Reentrance[Reentrance["cancelPrevious"] = -1] = "cancelPrevious";
|
|
14
|
+
Reentrance[Reentrance["cancelAndWaitPrevious"] = -2] = "cancelAndWaitPrevious";
|
|
15
|
+
Reentrance[Reentrance["overwritePrevious"] = -3] = "overwritePrevious";
|
|
16
|
+
Reentrance[Reentrance["runSideBySide"] = -4] = "runSideBySide";
|
|
17
17
|
})(Reentrance || (Reentrance = {}));
|
|
@@ -38,15 +38,15 @@ export function obs(proto, prop) {
|
|
|
38
38
|
return Mvcc.decorateData(true, proto, prop);
|
|
39
39
|
}
|
|
40
40
|
export function transactional(proto, prop, pd) {
|
|
41
|
-
const opts = { kind: Kind.
|
|
41
|
+
const opts = { kind: Kind.transactional };
|
|
42
42
|
return Mvcc.decorateOperation(true, transactional, opts, proto, prop, pd);
|
|
43
43
|
}
|
|
44
44
|
export function reactive(proto, prop, pd) {
|
|
45
|
-
const opts = { kind: Kind.
|
|
45
|
+
const opts = { kind: Kind.reactive, throttling: -1 };
|
|
46
46
|
return Mvcc.decorateOperation(true, reactive, opts, proto, prop, pd);
|
|
47
47
|
}
|
|
48
48
|
export function cached(proto, prop, pd) {
|
|
49
|
-
const opts = { kind: Kind.
|
|
49
|
+
const opts = { kind: Kind.cached, noSideEffects: true };
|
|
50
50
|
return Mvcc.decorateOperation(true, cached, opts, proto, prop, pd);
|
|
51
51
|
}
|
|
52
52
|
export function options(value) {
|
|
@@ -26,13 +26,13 @@ export class ObservableObject extends MvccObject {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
const DEFAULT_OPTIONS = Object.freeze({
|
|
29
|
-
kind: Kind.
|
|
29
|
+
kind: Kind.plain,
|
|
30
30
|
separation: false,
|
|
31
31
|
order: 0,
|
|
32
32
|
noSideEffects: false,
|
|
33
33
|
triggeringArgs: false,
|
|
34
34
|
throttling: Number.MAX_SAFE_INTEGER,
|
|
35
|
-
reentrance: Reentrance.
|
|
35
|
+
reentrance: Reentrance.preventWithError,
|
|
36
36
|
journal: undefined,
|
|
37
37
|
monitor: null,
|
|
38
38
|
logging: undefined,
|
|
@@ -74,7 +74,7 @@ export class Mvcc {
|
|
|
74
74
|
result = os.data[m];
|
|
75
75
|
if (result instanceof ValueSnapshot && !result.isOperation) {
|
|
76
76
|
if (this.isObservable)
|
|
77
|
-
Changeset.markUsed(result, os, m, h, Kind.
|
|
77
|
+
Changeset.markUsed(result, os, m, h, Kind.plain, false);
|
|
78
78
|
result = result.content;
|
|
79
79
|
}
|
|
80
80
|
else
|
|
@@ -79,7 +79,7 @@ declare class Launch extends ValueSnapshot implements Observer {
|
|
|
79
79
|
private static revokeAllSubscriptions;
|
|
80
80
|
private static propagateMemberChangeThroughSubscriptions;
|
|
81
81
|
private static enqueueReactiveFunctionsToRun;
|
|
82
|
-
private static
|
|
82
|
+
private static processQueuedReactiveFunctions;
|
|
83
83
|
private unsubscribeFromAllObservables;
|
|
84
84
|
private subscribeTo;
|
|
85
85
|
private static canSubscribeTo;
|
|
@@ -34,9 +34,9 @@ export class ReactionImpl {
|
|
|
34
34
|
&& (!weak || launch.cause === BOOT_CAUSE || !launch.successor ||
|
|
35
35
|
launch.successor.transaction.isFinished)) {
|
|
36
36
|
const outerOpts = (_a = Launch.current) === null || _a === void 0 ? void 0 : _a.options;
|
|
37
|
-
const separation = weak || opts.separation !== false || opts.kind === Kind.
|
|
38
|
-
(opts.kind === Kind.
|
|
39
|
-
(opts.kind === Kind.
|
|
37
|
+
const separation = weak || opts.separation !== false || opts.kind === Kind.reactive ||
|
|
38
|
+
(opts.kind === Kind.transactional && outerOpts && (outerOpts.noSideEffects || outerOpts.kind === Kind.cached)) ||
|
|
39
|
+
(opts.kind === Kind.cached && (ror.snapshot.changeset.sealed ||
|
|
40
40
|
ror.snapshot.former.snapshot !== EMPTY_SNAPSHOT));
|
|
41
41
|
const token = opts.noSideEffects ? this : undefined;
|
|
42
42
|
const ror2 = this.relaunch(ror, separation, opts, token, args);
|
|
@@ -103,7 +103,7 @@ export class ReactionImpl {
|
|
|
103
103
|
const ctx = Changeset.current();
|
|
104
104
|
const os = ctx.lookupObjectSnapshot(this.objectHandle, this.memberName);
|
|
105
105
|
const launch = this.acquireFromSnapshot(os, args);
|
|
106
|
-
const isValid = launch.options.kind !== Kind.
|
|
106
|
+
const isValid = launch.options.kind !== Kind.transactional && launch.cause !== BOOT_CAUSE &&
|
|
107
107
|
(ctx === launch.changeset || ctx.timestamp < launch.obsoleteSince) &&
|
|
108
108
|
(!launch.options.triggeringArgs || args === undefined ||
|
|
109
109
|
launch.args.length === args.length && launch.args.every((t, i) => t === args[i])) || os.disposed;
|
|
@@ -179,7 +179,7 @@ export class ReactionImpl {
|
|
|
179
179
|
}
|
|
180
180
|
else {
|
|
181
181
|
ror = this.peek(argsx);
|
|
182
|
-
if (ror.launch.options.kind === Kind.
|
|
182
|
+
if (ror.launch.options.kind === Kind.transactional || !ror.isUpToDate) {
|
|
183
183
|
ror = this.edit();
|
|
184
184
|
if (Log.isOn && Log.opt.operation)
|
|
185
185
|
Log.write("║", " o", `${ror.launch.why()}`);
|
|
@@ -231,7 +231,7 @@ class Launch extends ValueSnapshot {
|
|
|
231
231
|
let cause;
|
|
232
232
|
if (this.cause)
|
|
233
233
|
cause = ` ◀◀ ${this.cause}`;
|
|
234
|
-
else if (this.reaction.options.kind === Kind.
|
|
234
|
+
else if (this.reaction.options.kind === Kind.transactional)
|
|
235
235
|
cause = " ◀◀ operation";
|
|
236
236
|
else
|
|
237
237
|
cause = ` ◀◀ T${this.changeset.id}[${this.changeset.hint}]`;
|
|
@@ -274,7 +274,7 @@ class Launch extends ValueSnapshot {
|
|
|
274
274
|
changeset === this.changeset;
|
|
275
275
|
if (!skip) {
|
|
276
276
|
const why = `${Dump.snapshot2(h, changeset, m, observable)} ◀◀ ${outer}`;
|
|
277
|
-
const isReactive = this.options.kind === Kind.
|
|
277
|
+
const isReactive = this.options.kind === Kind.reactive;
|
|
278
278
|
this.obsoleteDueTo = why;
|
|
279
279
|
this.obsoleteSince = since;
|
|
280
280
|
if (Log.isOn && (Log.opt.obsolete || ((_a = this.options.logging) === null || _a === void 0 ? void 0 : _a.obsolete)))
|
|
@@ -306,14 +306,14 @@ class Launch extends ValueSnapshot {
|
|
|
306
306
|
const launch = this.reaction.reuseOrRelaunch(false, undefined);
|
|
307
307
|
if (launch.result instanceof Promise)
|
|
308
308
|
launch.result.catch(error => {
|
|
309
|
-
if (launch.options.kind === Kind.
|
|
309
|
+
if (launch.options.kind === Kind.reactive)
|
|
310
310
|
misuse(`reactive function ${launch.hint()} failed and will not run anymore: ${error}`, error);
|
|
311
311
|
});
|
|
312
312
|
}
|
|
313
313
|
catch (e) {
|
|
314
314
|
if (!nothrow)
|
|
315
315
|
throw e;
|
|
316
|
-
else if (this.options.kind === Kind.
|
|
316
|
+
else if (this.options.kind === Kind.reactive)
|
|
317
317
|
misuse(`reactive ${this.hint()} failed and will not run anymore: ${e}`, e);
|
|
318
318
|
}
|
|
319
319
|
}
|
|
@@ -326,7 +326,7 @@ class Launch extends ValueSnapshot {
|
|
|
326
326
|
}
|
|
327
327
|
}
|
|
328
328
|
isNotUpToDate() {
|
|
329
|
-
return !this.error && (this.options.kind === Kind.
|
|
329
|
+
return !this.error && (this.options.kind === Kind.transactional ||
|
|
330
330
|
!this.successor || this.successor.transaction.isCanceled);
|
|
331
331
|
}
|
|
332
332
|
reenterOver(head) {
|
|
@@ -336,25 +336,25 @@ class Launch extends ValueSnapshot {
|
|
|
336
336
|
if (Log.isOn && Log.opt.obsolete)
|
|
337
337
|
Log.write("║", " [!]", `${this.hint()} is trying to re-enter over ${opponent.hint()}`);
|
|
338
338
|
switch (head.options.reentrance) {
|
|
339
|
-
case Reentrance.
|
|
339
|
+
case Reentrance.preventWithError:
|
|
340
340
|
if (!opponent.transaction.isCanceled)
|
|
341
341
|
throw misuse(`${head.hint()} (${head.why()}) is not reentrant over ${opponent.hint()} (${opponent.why()})`);
|
|
342
342
|
error = new Error(`T${this.transaction.id}[${this.transaction.hint}] is on hold/PreventWithError due to canceled T${opponent.transaction.id}[${opponent.transaction.hint}]`);
|
|
343
343
|
this.transaction.cancel(error, opponent.transaction);
|
|
344
344
|
break;
|
|
345
|
-
case Reentrance.
|
|
345
|
+
case Reentrance.waitAndRestart:
|
|
346
346
|
error = new Error(`T${this.transaction.id}[${this.transaction.hint}] is on hold/WaitAndRestart due to active T${opponent.transaction.id}[${opponent.transaction.hint}]`);
|
|
347
347
|
this.transaction.cancel(error, opponent.transaction);
|
|
348
348
|
break;
|
|
349
|
-
case Reentrance.
|
|
349
|
+
case Reentrance.cancelAndWaitPrevious:
|
|
350
350
|
error = new Error(`T${this.transaction.id}[${this.transaction.hint}] is on hold/CancelAndWaitPrevious due to active T${opponent.transaction.id}[${opponent.transaction.hint}]`);
|
|
351
351
|
this.transaction.cancel(error, opponent.transaction);
|
|
352
352
|
opponent.transaction.cancel(new Error(`T${opponent.transaction.id}[${opponent.transaction.hint}] is canceled due to re-entering T${this.transaction.id}[${this.transaction.hint}]`), null);
|
|
353
353
|
break;
|
|
354
|
-
case Reentrance.
|
|
354
|
+
case Reentrance.cancelPrevious:
|
|
355
355
|
opponent.transaction.cancel(new Error(`T${opponent.transaction.id}[${opponent.transaction.hint}] is canceled due to re-entering T${this.transaction.id}[${this.transaction.hint}]`), null);
|
|
356
356
|
break;
|
|
357
|
-
case Reentrance.
|
|
357
|
+
case Reentrance.runSideBySide:
|
|
358
358
|
break;
|
|
359
359
|
}
|
|
360
360
|
}
|
|
@@ -447,9 +447,9 @@ class Launch extends ValueSnapshot {
|
|
|
447
447
|
x.relaunchIfNotUpToDate(true, true);
|
|
448
448
|
}
|
|
449
449
|
static markUsed(observable, os, m, h, kind, weak) {
|
|
450
|
-
if (kind !== Kind.
|
|
450
|
+
if (kind !== Kind.transactional) {
|
|
451
451
|
const launch = Launch.current;
|
|
452
|
-
if (launch && launch.options.kind !== Kind.
|
|
452
|
+
if (launch && launch.options.kind !== Kind.transactional &&
|
|
453
453
|
launch.transaction === Transaction.current && m !== Meta.Handle) {
|
|
454
454
|
const ctx = Changeset.current();
|
|
455
455
|
if (ctx !== os.changeset)
|
|
@@ -537,9 +537,9 @@ class Launch extends ValueSnapshot {
|
|
|
537
537
|
for (const r of reactive)
|
|
538
538
|
queue.push(r);
|
|
539
539
|
if (isReactiveLoopRequired)
|
|
540
|
-
ReactionImpl.proceedWithinGivenLaunch(undefined, Launch.
|
|
540
|
+
ReactionImpl.proceedWithinGivenLaunch(undefined, Launch.processQueuedReactiveFunctions);
|
|
541
541
|
}
|
|
542
|
-
static
|
|
542
|
+
static processQueuedReactiveFunctions() {
|
|
543
543
|
const queue = Launch.queuedReactiveFunctions;
|
|
544
544
|
let i = 0;
|
|
545
545
|
while (i < queue.length) {
|
|
@@ -607,11 +607,11 @@ class Launch extends ValueSnapshot {
|
|
|
607
607
|
const rx = launch ? launch.reaction : new ReactionImpl(EMPTY_HANDLE, m);
|
|
608
608
|
const opts = launch ? launch.options : OptionsImpl.INITIAL;
|
|
609
609
|
initial[m] = launch = new Launch(rx, EMPTY_SNAPSHOT.changeset, new OptionsImpl(getter, setter, opts, options, implicit));
|
|
610
|
-
if (launch.options.kind === Kind.
|
|
610
|
+
if (launch.options.kind === Kind.reactive && launch.options.throttling < Number.MAX_SAFE_INTEGER) {
|
|
611
611
|
const reactive = Meta.acquire(proto, Meta.Reactive);
|
|
612
612
|
reactive[m] = launch;
|
|
613
613
|
}
|
|
614
|
-
else if (launch.options.kind === Kind.
|
|
614
|
+
else if (launch.options.kind === Kind.reactive && launch.options.throttling >= Number.MAX_SAFE_INTEGER) {
|
|
615
615
|
const reactive = Meta.getFrom(proto, Meta.Reactive);
|
|
616
616
|
delete reactive[m];
|
|
617
617
|
}
|
|
@@ -4,14 +4,14 @@ import { MemberOptions } from "../Options.js";
|
|
|
4
4
|
export type Delegate<T> = (element: T, base: () => void) => void;
|
|
5
5
|
export type SimpleDelegate<T = unknown, R = void> = (element: T) => R;
|
|
6
6
|
export declare enum Mode {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
default = 0,
|
|
8
|
+
independentUpdate = 1,
|
|
9
|
+
manualMount = 2
|
|
10
10
|
}
|
|
11
11
|
export declare const enum Priority {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
realtime = 0,
|
|
13
|
+
normal = 1,
|
|
14
|
+
background = 2
|
|
15
15
|
}
|
|
16
16
|
export declare abstract class RxNode<E = unknown> {
|
|
17
17
|
abstract readonly key: string;
|
|
@@ -45,6 +45,7 @@ export declare abstract class RxNode<E = unknown> {
|
|
|
45
45
|
static get childrenShuffling(): boolean;
|
|
46
46
|
static set childrenShuffling(value: boolean);
|
|
47
47
|
static triggerUpdate(node: RxNode<any>, triggers: unknown): void;
|
|
48
|
+
static triggerFinalize(node: RxNode<any>): void;
|
|
48
49
|
static updateNestedNodesThenDo(action: (error: unknown) => void): void;
|
|
49
50
|
static markAsMounted(node: RxNode<any>, yes: boolean): void;
|
|
50
51
|
static findMatchingHost<E = unknown, R = unknown>(node: RxNode<E>, match: SimpleDelegate<RxNode<E>, boolean>): RxNode<R> | undefined;
|
|
@@ -24,15 +24,15 @@ import { Transaction } from "../core/Transaction.js";
|
|
|
24
24
|
import { RxSystem, options, raw, reactive, unobs } from "../RxSystem.js";
|
|
25
25
|
export var Mode;
|
|
26
26
|
(function (Mode) {
|
|
27
|
-
Mode[Mode["
|
|
28
|
-
Mode[Mode["
|
|
29
|
-
Mode[Mode["
|
|
27
|
+
Mode[Mode["default"] = 0] = "default";
|
|
28
|
+
Mode[Mode["independentUpdate"] = 1] = "independentUpdate";
|
|
29
|
+
Mode[Mode["manualMount"] = 2] = "manualMount";
|
|
30
30
|
})(Mode || (Mode = {}));
|
|
31
31
|
export var Priority;
|
|
32
32
|
(function (Priority) {
|
|
33
|
-
Priority[Priority["
|
|
34
|
-
Priority[Priority["
|
|
35
|
-
Priority[Priority["
|
|
33
|
+
Priority[Priority["realtime"] = 0] = "realtime";
|
|
34
|
+
Priority[Priority["normal"] = 1] = "normal";
|
|
35
|
+
Priority[Priority["background"] = 2] = "background";
|
|
36
36
|
})(Priority || (Priority = {}));
|
|
37
37
|
export class RxNode {
|
|
38
38
|
static acquire(driver, declaration, preset) {
|
|
@@ -106,6 +106,10 @@ export class RxNode {
|
|
|
106
106
|
triggerUpdateViaSeat(impl.seat);
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
|
+
static triggerFinalize(node) {
|
|
110
|
+
const impl = node;
|
|
111
|
+
triggerFinalization(impl.seat, true, true);
|
|
112
|
+
}
|
|
109
113
|
static updateNestedNodesThenDo(action) {
|
|
110
114
|
runUpdateNestedNodesThenDo(undefined, action);
|
|
111
115
|
}
|
|
@@ -143,7 +147,7 @@ export class RxNode {
|
|
|
143
147
|
}
|
|
144
148
|
RxNode.shortFrameDuration = 16;
|
|
145
149
|
RxNode.longFrameDuration = 300;
|
|
146
|
-
RxNode.currentUpdatePriority = Priority.
|
|
150
|
+
RxNode.currentUpdatePriority = Priority.realtime;
|
|
147
151
|
RxNode.frameDuration = RxNode.longFrameDuration;
|
|
148
152
|
export class BaseDriver {
|
|
149
153
|
constructor(name, isPartitionSeparator, predefine) {
|
|
@@ -192,7 +196,7 @@ function generateKey(owner) {
|
|
|
192
196
|
}
|
|
193
197
|
function getModeViaPresetChain(declaration) {
|
|
194
198
|
var _a;
|
|
195
|
-
return (_a = declaration === null || declaration === void 0 ? void 0 : declaration.mode) !== null && _a !== void 0 ? _a : ((declaration === null || declaration === void 0 ? void 0 : declaration.preset) ? getModeViaPresetChain(declaration === null || declaration === void 0 ? void 0 : declaration.preset) : Mode.
|
|
199
|
+
return (_a = declaration === null || declaration === void 0 ? void 0 : declaration.mode) !== null && _a !== void 0 ? _a : ((declaration === null || declaration === void 0 ? void 0 : declaration.preset) ? getModeViaPresetChain(declaration === null || declaration === void 0 ? void 0 : declaration.preset) : Mode.default);
|
|
196
200
|
}
|
|
197
201
|
function initializeViaPresetChain(element, declaration) {
|
|
198
202
|
const preset = declaration.preset;
|
|
@@ -259,10 +263,10 @@ class RxNodeImpl extends RxNode {
|
|
|
259
263
|
this.stamp = Number.MAX_SAFE_INTEGER;
|
|
260
264
|
this.context = undefined;
|
|
261
265
|
this.numerator = 0;
|
|
262
|
-
this.priority = Priority.
|
|
266
|
+
this.priority = Priority.realtime;
|
|
263
267
|
this.childrenShuffling = false;
|
|
264
268
|
RxNodeImpl.grandNodeCount++;
|
|
265
|
-
if (this.has(Mode.
|
|
269
|
+
if (this.has(Mode.independentUpdate))
|
|
266
270
|
RxNodeImpl.disposableNodeCount++;
|
|
267
271
|
}
|
|
268
272
|
get strictOrder() { return this.children.isStrict; }
|
|
@@ -275,7 +279,7 @@ class RxNodeImpl extends RxNode {
|
|
|
275
279
|
updateNow(this.seat);
|
|
276
280
|
}
|
|
277
281
|
configureReactronic(options) {
|
|
278
|
-
if (this.stamp < Number.MAX_SAFE_INTEGER - 1 || !this.has(Mode.
|
|
282
|
+
if (this.stamp < Number.MAX_SAFE_INTEGER - 1 || !this.has(Mode.independentUpdate))
|
|
279
283
|
throw new Error("reactronic can be configured only for elements with independent update mode and only inside initialize");
|
|
280
284
|
return RxSystem.getReaction(this.update).configure(options);
|
|
281
285
|
}
|
|
@@ -329,7 +333,7 @@ RxNodeImpl.disposableNodeCount = 0;
|
|
|
329
333
|
__decorate([
|
|
330
334
|
reactive,
|
|
331
335
|
options({
|
|
332
|
-
reentrance: Reentrance.
|
|
336
|
+
reentrance: Reentrance.cancelPrevious,
|
|
333
337
|
triggeringArgs: true,
|
|
334
338
|
noSideEffects: false,
|
|
335
339
|
}),
|
|
@@ -363,11 +367,11 @@ function runUpdateNestedNodesThenDo(error, action) {
|
|
|
363
367
|
const childNode = child.instance;
|
|
364
368
|
const isPart = childNode.driver.isPartitionSeparator;
|
|
365
369
|
const host = isPart ? owner : partition;
|
|
366
|
-
const p = (_a = childNode.priority) !== null && _a !== void 0 ? _a : Priority.
|
|
370
|
+
const p = (_a = childNode.priority) !== null && _a !== void 0 ? _a : Priority.realtime;
|
|
367
371
|
mounting = markToMountIfNecessary(mounting, host, child, children, sequential);
|
|
368
|
-
if (p === Priority.
|
|
372
|
+
if (p === Priority.realtime)
|
|
369
373
|
triggerUpdateViaSeat(child);
|
|
370
|
-
else if (p === Priority.
|
|
374
|
+
else if (p === Priority.normal)
|
|
371
375
|
p1 = push(child, p1);
|
|
372
376
|
else
|
|
373
377
|
p2 = push(child, p2);
|
|
@@ -386,7 +390,7 @@ function runUpdateNestedNodesThenDo(error, action) {
|
|
|
386
390
|
}
|
|
387
391
|
function markToMountIfNecessary(mounting, host, seat, children, sequential) {
|
|
388
392
|
const node = seat.instance;
|
|
389
|
-
if (node.element.native && !node.has(Mode.
|
|
393
|
+
if (node.element.native && !node.has(Mode.manualMount)) {
|
|
390
394
|
if (mounting || node.host !== host) {
|
|
391
395
|
children.markAsMoved(seat);
|
|
392
396
|
mounting = false;
|
|
@@ -401,9 +405,9 @@ function startIncrementalUpdate(ownerSeat, allChildren, priority1, priority2) {
|
|
|
401
405
|
return __awaiter(this, void 0, void 0, function* () {
|
|
402
406
|
const stamp = ownerSeat.instance.stamp;
|
|
403
407
|
if (priority1)
|
|
404
|
-
yield updateIncrementally(ownerSeat, stamp, allChildren, priority1, Priority.
|
|
408
|
+
yield updateIncrementally(ownerSeat, stamp, allChildren, priority1, Priority.normal);
|
|
405
409
|
if (priority2)
|
|
406
|
-
yield updateIncrementally(ownerSeat, stamp, allChildren, priority2, Priority.
|
|
410
|
+
yield updateIncrementally(ownerSeat, stamp, allChildren, priority2, Priority.background);
|
|
407
411
|
});
|
|
408
412
|
}
|
|
409
413
|
function updateIncrementally(owner, stamp, allChildren, items, priority) {
|
|
@@ -416,7 +420,7 @@ function updateIncrementally(owner, stamp, allChildren, items, priority) {
|
|
|
416
420
|
try {
|
|
417
421
|
if (node.childrenShuffling)
|
|
418
422
|
shuffle(items);
|
|
419
|
-
const frameDurationLimit = priority === Priority.
|
|
423
|
+
const frameDurationLimit = priority === Priority.background ? RxNode.shortFrameDuration : Infinity;
|
|
420
424
|
let frameDuration = Math.min(frameDurationLimit, Math.max(RxNode.frameDuration / 4, RxNode.shortFrameDuration));
|
|
421
425
|
for (const child of items) {
|
|
422
426
|
triggerUpdateViaSeat(child);
|
|
@@ -440,7 +444,7 @@ function updateIncrementally(owner, stamp, allChildren, items, priority) {
|
|
|
440
444
|
function triggerUpdateViaSeat(seat) {
|
|
441
445
|
const node = seat.instance;
|
|
442
446
|
if (node.stamp >= 0) {
|
|
443
|
-
if (node.has(Mode.
|
|
447
|
+
if (node.has(Mode.independentUpdate)) {
|
|
444
448
|
if (node.stamp === Number.MAX_SAFE_INTEGER) {
|
|
445
449
|
Transaction.outside(() => {
|
|
446
450
|
if (RxSystem.isLogging)
|
|
@@ -462,14 +466,14 @@ function mountOrRemountIfNecessary(node) {
|
|
|
462
466
|
unobs(() => {
|
|
463
467
|
node.stamp = Number.MAX_SAFE_INTEGER - 1;
|
|
464
468
|
driver.initialize(node);
|
|
465
|
-
if (!node.has(Mode.
|
|
469
|
+
if (!node.has(Mode.manualMount)) {
|
|
466
470
|
node.stamp = 0;
|
|
467
471
|
if (node.host !== node)
|
|
468
472
|
driver.mount(node);
|
|
469
473
|
}
|
|
470
474
|
});
|
|
471
475
|
}
|
|
472
|
-
else if (node.isMoved && !node.has(Mode.
|
|
476
|
+
else if (node.isMoved && !node.has(Mode.manualMount) && node.host !== node)
|
|
473
477
|
unobs(() => driver.mount(node));
|
|
474
478
|
}
|
|
475
479
|
function updateNow(seat) {
|
|
@@ -507,7 +511,7 @@ function triggerFinalization(seat, isLeader, individual) {
|
|
|
507
511
|
console.log(`WARNING: it is recommended to assign explicit key for conditional element in order to avoid unexpected side effects: ${node.key}`);
|
|
508
512
|
node.stamp = ~node.stamp;
|
|
509
513
|
const childrenAreLeaders = unobs(() => driver.finalize(node, isLeader));
|
|
510
|
-
if (node.has(Mode.
|
|
514
|
+
if (node.has(Mode.independentUpdate)) {
|
|
511
515
|
seat.aux = undefined;
|
|
512
516
|
const last = gLastToDispose;
|
|
513
517
|
if (last)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reactronic",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.127",
|
|
4
4
|
"description": "Reactronic - Transactional Reactive State Management",
|
|
5
5
|
"publisher": "Nezaboodka Software",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -31,16 +31,16 @@
|
|
|
31
31
|
},
|
|
32
32
|
"homepage": "https://github.com/nezaboodka/reactronic/blob/master/README.md#readme",
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@types/node": "20.
|
|
35
|
-
"@types/react": "18.2.
|
|
36
|
-
"@typescript-eslint/eslint-plugin": "6.
|
|
37
|
-
"@typescript-eslint/parser": "6.
|
|
38
|
-
"ava": "
|
|
39
|
-
"c8": "
|
|
40
|
-
"eslint": "8.
|
|
34
|
+
"@types/node": "20.11.16",
|
|
35
|
+
"@types/react": "18.2.52",
|
|
36
|
+
"@typescript-eslint/eslint-plugin": "6.20.0",
|
|
37
|
+
"@typescript-eslint/parser": "6.20.0",
|
|
38
|
+
"ava": "6.1.1",
|
|
39
|
+
"c8": "9.1.0",
|
|
40
|
+
"eslint": "8.56.0",
|
|
41
41
|
"react": "18.2.0",
|
|
42
|
-
"ts-node": "10.9.
|
|
43
|
-
"typescript": "5.
|
|
42
|
+
"ts-node": "10.9.2",
|
|
43
|
+
"typescript": "5.3.2"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"build": "eslint source/**.ts test/**.test.ts react/**.tsx && tsc",
|