reactronic 0.23.115 → 0.24.101

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,59 @@
1
+ import { MergeListReader, MergedItem } from './util/MergeList.js';
2
+ import { MemberOptions } from './Options.js';
3
+ export type Delegate<T> = (element: T, base: () => void) => void;
4
+ export type SimpleDelegate<T = unknown, R = void> = (element: T) => R;
5
+ export declare enum Mode {
6
+ Default = 0,
7
+ PinpointUpdate = 1,
8
+ ManualMount = 2
9
+ }
10
+ export declare const enum Priority {
11
+ Realtime = 0,
12
+ Normal = 1,
13
+ Background = 2
14
+ }
15
+ export declare abstract class RxNode<T = any> {
16
+ abstract readonly key: string;
17
+ abstract readonly driver: RxNodeDriver<T>;
18
+ abstract readonly declaration: Readonly<RxNodeDecl<T>>;
19
+ abstract readonly level: number;
20
+ abstract readonly owner: RxNode;
21
+ abstract readonly element: T;
22
+ abstract readonly host: RxNode;
23
+ abstract readonly children: MergeListReader<RxNode>;
24
+ abstract readonly slot: MergedItem<RxNode<T>> | undefined;
25
+ abstract readonly stamp: number;
26
+ abstract readonly outer: RxNode;
27
+ abstract readonly context: RxNodeContext | undefined;
28
+ abstract readonly isInitialUpdate: boolean;
29
+ abstract priority?: Priority;
30
+ abstract childrenShuffling: boolean;
31
+ abstract strictOrder: boolean;
32
+ abstract has(mode: Mode): boolean;
33
+ abstract configureReactronic(options: Partial<MemberOptions>): MemberOptions;
34
+ }
35
+ export interface RxNodeDecl<T = unknown> {
36
+ preset?: RxNodeDecl<T>;
37
+ key?: string;
38
+ mode?: Mode;
39
+ triggers?: unknown;
40
+ specify?: Delegate<T>;
41
+ create?: Delegate<T>;
42
+ initialize?: Delegate<T>;
43
+ update?: Delegate<T>;
44
+ finalize?: Delegate<T>;
45
+ }
46
+ export interface RxNodeDriver<T> {
47
+ readonly name: string;
48
+ readonly isPartitionSeparator: boolean;
49
+ readonly predefine?: SimpleDelegate<T>;
50
+ allocate(node: RxNode<T>): T;
51
+ assign(element: T): void;
52
+ initialize(element: T): void;
53
+ mount(element: T): void;
54
+ update(element: T): void | Promise<void>;
55
+ finalize(element: T, isLeader: boolean): boolean;
56
+ }
57
+ export interface RxNodeContext<T extends Object = Object> {
58
+ value: T;
59
+ }
@@ -0,0 +1,14 @@
1
+ export var Mode;
2
+ (function (Mode) {
3
+ Mode[Mode["Default"] = 0] = "Default";
4
+ Mode[Mode["PinpointUpdate"] = 1] = "PinpointUpdate";
5
+ Mode[Mode["ManualMount"] = 2] = "ManualMount";
6
+ })(Mode || (Mode = {}));
7
+ export var Priority;
8
+ (function (Priority) {
9
+ Priority[Priority["Realtime"] = 0] = "Realtime";
10
+ Priority[Priority["Normal"] = 1] = "Normal";
11
+ Priority[Priority["Background"] = 2] = "Background";
12
+ })(Priority || (Priority = {}));
13
+ export class RxNode {
14
+ }
@@ -0,0 +1,39 @@
1
+ import { LoggingOptions } from './Logging.js';
2
+ import { Priority, RxNodeDecl, RxNodeDriver, SimpleDelegate, RxNode } from './RxNode.js';
3
+ export declare class RxTree {
4
+ static readonly shortFrameDuration = 16;
5
+ static readonly longFrameDuration = 300;
6
+ static currentUpdatePriority: Priority;
7
+ static frameDuration: number;
8
+ static declare<T = undefined>(driver: RxNodeDriver<T>, declaration?: RxNodeDecl<T>, preset?: RxNodeDecl<T>): T;
9
+ static triggerUpdate(element: {
10
+ node: RxNode;
11
+ }, triggers: unknown): void;
12
+ static updateNestedTreesThenDo(action: (error: unknown) => void): void;
13
+ static findMatchingHost<T, R>(node: RxNode<T>, match: SimpleDelegate<RxNode<T>, boolean>): RxNode<R> | undefined;
14
+ static findMatchingPrevSibling<T, R>(node: RxNode<T>, match: SimpleDelegate<RxNode<T>, boolean>): RxNode<R> | undefined;
15
+ static forEachChildRecursively<T>(node: RxNode<T>, action: SimpleDelegate<RxNode<T>>): void;
16
+ static getDefaultLoggingOptions(): LoggingOptions | undefined;
17
+ static setDefaultLoggingOptions(logging?: LoggingOptions): void;
18
+ }
19
+ export declare abstract class BaseDriver<T extends {
20
+ node: RxNode;
21
+ }> implements RxNodeDriver<T> {
22
+ readonly name: string;
23
+ readonly isPartitionSeparator: boolean;
24
+ readonly predefine?: SimpleDelegate<T> | undefined;
25
+ constructor(name: string, isPartitionSeparator: boolean, predefine?: SimpleDelegate<T> | undefined);
26
+ abstract allocate(node: RxNode<T>): T;
27
+ assign(element: T): void;
28
+ initialize(element: T): void;
29
+ mount(element: T): void;
30
+ update(element: T): void | Promise<void>;
31
+ finalize(element: T, isLeader: boolean): boolean;
32
+ }
33
+ export declare class RxNodeVariable<T extends Object = Object> {
34
+ readonly defaultValue: T | undefined;
35
+ constructor(defaultValue?: T);
36
+ set value(value: T);
37
+ get value(): T;
38
+ get valueOrUndefined(): T | undefined;
39
+ }
@@ -0,0 +1,594 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
11
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
12
+ return new (P || (P = Promise))(function (resolve, reject) {
13
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
14
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
15
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
16
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
17
+ });
18
+ };
19
+ import { MergeList } from './util/MergeList.js';
20
+ import { Priority, Mode } from './RxNode.js';
21
+ import { emitLetters, getCallerInfo } from './util/RxNodeUtils.js';
22
+ import { Reentrance } from './Options.js';
23
+ import { ObservableObject } from './impl/Mvcc.js';
24
+ import { Transaction } from './impl/Transaction.js';
25
+ import { Rx, options, raw, reactive, unobs } from './Rx.js';
26
+ export class RxTree {
27
+ static declare(driver, declaration, preset) {
28
+ var _a;
29
+ let result;
30
+ if (declaration)
31
+ declaration.preset = preset;
32
+ else
33
+ declaration = preset !== null && preset !== void 0 ? preset : {};
34
+ let key = declaration.key;
35
+ const owner = gCurrent === null || gCurrent === void 0 ? void 0 : gCurrent.instance;
36
+ if (owner) {
37
+ let existing = undefined;
38
+ const children = owner.children;
39
+ if (driver.isPartitionSeparator) {
40
+ const last = children.lastMergedItem();
41
+ if (((_a = last === null || last === void 0 ? void 0 : last.instance) === null || _a === void 0 ? void 0 : _a.driver) === driver)
42
+ existing = last;
43
+ }
44
+ existing !== null && existing !== void 0 ? existing : (existing = children.tryMergeAsExisting(key = key || generateKey(owner), undefined, 'nested elements can be declared inside update function only'));
45
+ if (existing) {
46
+ const node = existing.instance;
47
+ result = node.element;
48
+ if (node.driver !== driver && driver !== undefined)
49
+ throw new Error(`changing element driver is not yet supported: "${node.driver.name}" -> "${driver === null || driver === void 0 ? void 0 : driver.name}"`);
50
+ const exTriggers = node.declaration.triggers;
51
+ if (triggersAreEqual(declaration.triggers, exTriggers))
52
+ declaration.triggers = exTriggers;
53
+ node.declaration = declaration;
54
+ }
55
+ else {
56
+ const node = new RxNodeImpl(key || generateKey(owner), driver, declaration, owner);
57
+ node.slot = children.mergeAsAdded(node);
58
+ result = node.element;
59
+ }
60
+ }
61
+ else {
62
+ const node = new RxNodeImpl(key || '', driver, declaration, owner);
63
+ node.slot = MergeList.createItem(node);
64
+ result = node.element;
65
+ triggerUpdate(node.slot);
66
+ }
67
+ return result;
68
+ }
69
+ static triggerUpdate(element, triggers) {
70
+ const el = element;
71
+ const declaration = el.node.declaration;
72
+ if (!triggersAreEqual(triggers, declaration.triggers)) {
73
+ declaration.triggers = triggers;
74
+ triggerUpdate(el.node.slot);
75
+ }
76
+ }
77
+ static updateNestedTreesThenDo(action) {
78
+ runUpdateNestedTreesThenDo(undefined, action);
79
+ }
80
+ static findMatchingHost(node, match) {
81
+ let p = node.host;
82
+ while (p !== p.host && !match(p))
83
+ p = p.host;
84
+ return p;
85
+ }
86
+ static findMatchingPrevSibling(node, match) {
87
+ let p = node.slot.prev;
88
+ while (p && !match(p.instance))
89
+ p = p.prev;
90
+ return p === null || p === void 0 ? void 0 : p.instance;
91
+ }
92
+ static forEachChildRecursively(node, action) {
93
+ action(node);
94
+ for (const child of node.children.items())
95
+ RxTree.forEachChildRecursively(child.instance, action);
96
+ }
97
+ static getDefaultLoggingOptions() {
98
+ return RxNodeImpl.logging;
99
+ }
100
+ static setDefaultLoggingOptions(logging) {
101
+ RxNodeImpl.logging = logging;
102
+ }
103
+ }
104
+ RxTree.shortFrameDuration = 16;
105
+ RxTree.longFrameDuration = 300;
106
+ RxTree.currentUpdatePriority = Priority.Realtime;
107
+ RxTree.frameDuration = RxTree.longFrameDuration;
108
+ export class BaseDriver {
109
+ constructor(name, isPartitionSeparator, predefine) {
110
+ this.name = name;
111
+ this.isPartitionSeparator = isPartitionSeparator;
112
+ this.predefine = predefine;
113
+ }
114
+ assign(element) {
115
+ assignViaPresetChain(element, element.node.declaration);
116
+ }
117
+ initialize(element) {
118
+ var _a;
119
+ (_a = this.predefine) === null || _a === void 0 ? void 0 : _a.call(this, element);
120
+ initializeViaPresetChain(element, element.node.declaration);
121
+ }
122
+ mount(element) {
123
+ }
124
+ update(element) {
125
+ updateViaPresetChain(element, element.node.declaration);
126
+ }
127
+ finalize(element, isLeader) {
128
+ finalizeViaPresetChain(element, element.node.declaration);
129
+ return isLeader;
130
+ }
131
+ }
132
+ export class RxNodeVariable {
133
+ constructor(defaultValue) {
134
+ this.defaultValue = defaultValue;
135
+ }
136
+ set value(value) {
137
+ RxNodeImpl.setNodeVariableValue(this, value);
138
+ }
139
+ get value() {
140
+ return RxNodeImpl.useNodeVariableValue(this);
141
+ }
142
+ get valueOrUndefined() {
143
+ return RxNodeImpl.tryUseNodeVariableValue(this);
144
+ }
145
+ }
146
+ function generateKey(owner) {
147
+ const n = owner.numerator++;
148
+ const lettered = emitLetters(n);
149
+ let result;
150
+ if (Rx.isLogging)
151
+ result = `·${getCallerInfo(lettered)}`;
152
+ else
153
+ result = `·${lettered}`;
154
+ return result;
155
+ }
156
+ function getModeViaPresetChain(declaration) {
157
+ var _a;
158
+ 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);
159
+ }
160
+ function assignViaPresetChain(element, declaration) {
161
+ const preset = declaration.preset;
162
+ const create = declaration.create;
163
+ if (create)
164
+ create(element, preset ? () => assignViaPresetChain(element, preset) : NOP);
165
+ else if (preset)
166
+ assignViaPresetChain(element, preset);
167
+ }
168
+ function initializeViaPresetChain(element, declaration) {
169
+ const preset = declaration.preset;
170
+ const initialize = declaration.initialize;
171
+ if (initialize)
172
+ initialize(element, preset ? () => initializeViaPresetChain(element, preset) : NOP);
173
+ else if (preset)
174
+ initializeViaPresetChain(element, preset);
175
+ }
176
+ function updateViaPresetChain(element, declaration) {
177
+ const preset = declaration.preset;
178
+ const update = declaration.update;
179
+ if (update)
180
+ update(element, preset ? () => updateViaPresetChain(element, preset) : NOP);
181
+ else if (preset)
182
+ updateViaPresetChain(element, preset);
183
+ }
184
+ function finalizeViaPresetChain(element, declaration) {
185
+ const preset = declaration.preset;
186
+ const finalize = declaration.finalize;
187
+ if (finalize)
188
+ finalize(element, preset ? () => finalizeViaPresetChain(element, preset) : NOP);
189
+ else if (preset)
190
+ finalizeViaPresetChain(element, preset);
191
+ }
192
+ class RxNodeContextImpl extends ObservableObject {
193
+ constructor(variable, value) {
194
+ super();
195
+ this.next = undefined;
196
+ this.variable = variable;
197
+ this.value = value;
198
+ }
199
+ }
200
+ __decorate([
201
+ raw,
202
+ __metadata("design:type", Object)
203
+ ], RxNodeContextImpl.prototype, "next", void 0);
204
+ __decorate([
205
+ raw,
206
+ __metadata("design:type", RxNodeVariable)
207
+ ], RxNodeContextImpl.prototype, "variable", void 0);
208
+ class RxNodeImpl {
209
+ constructor(key, driver, declaration, owner) {
210
+ this.key = key;
211
+ this.driver = driver;
212
+ this.declaration = declaration;
213
+ if (owner) {
214
+ const node = owner;
215
+ this.level = node.level + 1;
216
+ this.owner = owner;
217
+ this.outer = node.context ? owner : node.outer;
218
+ }
219
+ else {
220
+ this.level = 1;
221
+ this.owner = owner = this;
222
+ this.outer = this;
223
+ }
224
+ this.element = driver.allocate(this);
225
+ this.host = this;
226
+ this.children = new MergeList(getNodeKey, true);
227
+ this.slot = undefined;
228
+ this.stamp = Number.MAX_SAFE_INTEGER;
229
+ this.context = undefined;
230
+ this.numerator = 0;
231
+ this.priority = Priority.Realtime;
232
+ this.childrenShuffling = false;
233
+ RxNodeImpl.grandNodeCount++;
234
+ if (this.has(Mode.PinpointUpdate))
235
+ RxNodeImpl.disposableNodeCount++;
236
+ }
237
+ get isInitialUpdate() { return this.stamp === 1; }
238
+ get strictOrder() { return this.children.isStrict; }
239
+ set strictOrder(value) { this.children.isStrict = value; }
240
+ get isMoved() { return this.owner.children.isMoved(this.slot); }
241
+ has(mode) {
242
+ return (getModeViaPresetChain(this.declaration) & mode) === mode;
243
+ }
244
+ update(_triggers) {
245
+ updateNow(this.slot);
246
+ }
247
+ configureReactronic(options) {
248
+ if (this.stamp < Number.MAX_SAFE_INTEGER - 1 || !this.has(Mode.PinpointUpdate))
249
+ throw new Error('reactronic can be configured only for elements with pinpoint update mode and only inside initialize');
250
+ return Rx.getReaction(this.update).configure(options);
251
+ }
252
+ static get current() {
253
+ if (!gCurrent)
254
+ throw new Error('current element is undefined');
255
+ return gCurrent;
256
+ }
257
+ static tryUseNodeVariableValue(variable) {
258
+ var _a, _b;
259
+ let node = RxNodeImpl.current.instance;
260
+ while (((_a = node.context) === null || _a === void 0 ? void 0 : _a.variable) !== variable && node.owner !== node)
261
+ node = node.outer.slot.instance;
262
+ return (_b = node.context) === null || _b === void 0 ? void 0 : _b.value;
263
+ }
264
+ static useNodeVariableValue(variable) {
265
+ var _a;
266
+ const result = (_a = RxNodeImpl.tryUseNodeVariableValue(variable)) !== null && _a !== void 0 ? _a : variable.defaultValue;
267
+ if (!result)
268
+ throw new Error('unknown node variable');
269
+ return result;
270
+ }
271
+ static setNodeVariableValue(variable, value) {
272
+ const node = RxNodeImpl.current.instance;
273
+ const owner = node.owner;
274
+ const hostCtx = unobs(() => { var _a; return (_a = owner.context) === null || _a === void 0 ? void 0 : _a.value; });
275
+ if (value && value !== hostCtx) {
276
+ if (hostCtx)
277
+ node.outer = owner;
278
+ else
279
+ node.outer = owner.outer;
280
+ Transaction.run({ separation: true }, () => {
281
+ const ctx = node.context;
282
+ if (ctx) {
283
+ ctx.variable = variable;
284
+ ctx.value = value;
285
+ }
286
+ else
287
+ node.context = new RxNodeContextImpl(variable, value);
288
+ });
289
+ }
290
+ else if (hostCtx)
291
+ node.outer = owner;
292
+ else
293
+ node.outer = owner.outer;
294
+ }
295
+ }
296
+ RxNodeImpl.logging = undefined;
297
+ RxNodeImpl.grandNodeCount = 0;
298
+ RxNodeImpl.disposableNodeCount = 0;
299
+ __decorate([
300
+ reactive,
301
+ options({
302
+ reentrance: Reentrance.CancelPrevious,
303
+ triggeringArgs: true,
304
+ noSideEffects: false,
305
+ }),
306
+ __metadata("design:type", Function),
307
+ __metadata("design:paramtypes", [Object]),
308
+ __metadata("design:returntype", void 0)
309
+ ], RxNodeImpl.prototype, "update", null);
310
+ function getNodeKey(node) {
311
+ return node.stamp >= 0 ? node.key : undefined;
312
+ }
313
+ function runUpdateNestedTreesThenDo(error, action) {
314
+ var _a;
315
+ const curr = RxNodeImpl.current;
316
+ const owner = curr.instance;
317
+ const children = owner.children;
318
+ if (children.isMergeInProgress) {
319
+ let promised = undefined;
320
+ try {
321
+ children.endMerge(error);
322
+ for (const slot of children.removedItems(true))
323
+ triggerFinalization(slot, true, true);
324
+ if (!error) {
325
+ const sequential = children.isStrict;
326
+ let p1 = undefined;
327
+ let p2 = undefined;
328
+ let mounting = false;
329
+ let partition = owner;
330
+ for (const child of children.items()) {
331
+ if (Transaction.isCanceled)
332
+ break;
333
+ const node = child.instance;
334
+ const el = node.element;
335
+ const isPart = node.driver.isPartitionSeparator;
336
+ const host = isPart ? owner : partition;
337
+ const p = (_a = el.node.priority) !== null && _a !== void 0 ? _a : Priority.Realtime;
338
+ mounting = markToMountIfNecessary(mounting, host, child, children, sequential);
339
+ if (p === Priority.Realtime)
340
+ triggerUpdate(child);
341
+ else if (p === Priority.Normal)
342
+ p1 = push(child, p1);
343
+ else
344
+ p2 = push(child, p2);
345
+ if (isPart)
346
+ partition = node;
347
+ }
348
+ if (!Transaction.isCanceled && (p1 !== undefined || p2 !== undefined))
349
+ promised = startIncrementalUpdate(curr, children, p1, p2).then(() => action(error), e => action(e));
350
+ }
351
+ }
352
+ finally {
353
+ if (!promised)
354
+ action(error);
355
+ }
356
+ }
357
+ }
358
+ function markToMountIfNecessary(mounting, host, slot, children, sequential) {
359
+ const node = slot.instance;
360
+ const el = node.element;
361
+ if (el.native && !node.has(Mode.ManualMount)) {
362
+ if (mounting || node.host !== host) {
363
+ children.markAsMoved(slot);
364
+ mounting = false;
365
+ }
366
+ }
367
+ else if (sequential && children.isMoved(slot))
368
+ mounting = true;
369
+ node.host = host;
370
+ return mounting;
371
+ }
372
+ function startIncrementalUpdate(ownerSlot, allChildren, priority1, priority2) {
373
+ return __awaiter(this, void 0, void 0, function* () {
374
+ const stamp = ownerSlot.instance.stamp;
375
+ if (priority1)
376
+ yield updateIncrementally(ownerSlot, stamp, allChildren, priority1, Priority.Normal);
377
+ if (priority2)
378
+ yield updateIncrementally(ownerSlot, stamp, allChildren, priority2, Priority.Background);
379
+ });
380
+ }
381
+ function updateIncrementally(owner, stamp, allChildren, items, priority) {
382
+ return __awaiter(this, void 0, void 0, function* () {
383
+ yield Transaction.requestNextFrame();
384
+ const node = owner.instance;
385
+ if (!Transaction.isCanceled || !Transaction.isFrameOver(1, RxTree.shortFrameDuration / 3)) {
386
+ let outerPriority = RxTree.currentUpdatePriority;
387
+ RxTree.currentUpdatePriority = priority;
388
+ try {
389
+ if (node.childrenShuffling)
390
+ shuffle(items);
391
+ const frameDurationLimit = priority === Priority.Background ? RxTree.shortFrameDuration : Infinity;
392
+ let frameDuration = Math.min(frameDurationLimit, Math.max(RxTree.frameDuration / 4, RxTree.shortFrameDuration));
393
+ for (const child of items) {
394
+ triggerUpdate(child);
395
+ if (Transaction.isFrameOver(1, frameDuration)) {
396
+ RxTree.currentUpdatePriority = outerPriority;
397
+ yield Transaction.requestNextFrame(0);
398
+ outerPriority = RxTree.currentUpdatePriority;
399
+ RxTree.currentUpdatePriority = priority;
400
+ frameDuration = Math.min(4 * frameDuration, Math.min(frameDurationLimit, RxTree.frameDuration));
401
+ }
402
+ if (Transaction.isCanceled && Transaction.isFrameOver(1, RxTree.shortFrameDuration / 3))
403
+ break;
404
+ }
405
+ }
406
+ finally {
407
+ RxTree.currentUpdatePriority = outerPriority;
408
+ }
409
+ }
410
+ });
411
+ }
412
+ function triggerUpdate(slot) {
413
+ const node = slot.instance;
414
+ if (node.stamp >= 0) {
415
+ if (node.has(Mode.PinpointUpdate)) {
416
+ if (node.stamp === Number.MAX_SAFE_INTEGER) {
417
+ Transaction.outside(() => {
418
+ if (Rx.isLogging)
419
+ Rx.setLoggingHint(node.element, node.key);
420
+ Rx.getReaction(node.update).configure({
421
+ order: node.level,
422
+ });
423
+ });
424
+ }
425
+ unobs(node.update, node.declaration.triggers);
426
+ }
427
+ else
428
+ updateNow(slot);
429
+ }
430
+ }
431
+ function mountOrRemountIfNecessary(node) {
432
+ const element = node.element;
433
+ const driver = node.driver;
434
+ if (node.stamp === Number.MAX_SAFE_INTEGER) {
435
+ node.stamp = Number.MAX_SAFE_INTEGER - 1;
436
+ unobs(() => {
437
+ driver.assign(element);
438
+ driver.initialize(element);
439
+ if (!node.has(Mode.ManualMount)) {
440
+ node.stamp = 0;
441
+ if (element.node.host !== element.node)
442
+ driver.mount(element);
443
+ }
444
+ node.stamp = 0;
445
+ });
446
+ }
447
+ else if (node.isMoved && !node.has(Mode.ManualMount) && element.node.host !== element.node)
448
+ unobs(() => driver.mount(element));
449
+ }
450
+ function updateNow(slot) {
451
+ const node = slot.instance;
452
+ const el = node.element;
453
+ if (node.stamp >= 0) {
454
+ let result = undefined;
455
+ runInside(slot, () => {
456
+ mountOrRemountIfNecessary(node);
457
+ if (node.stamp < Number.MAX_SAFE_INTEGER - 1) {
458
+ try {
459
+ node.stamp++;
460
+ node.numerator = 0;
461
+ el.prepareForUpdate();
462
+ node.children.beginMerge();
463
+ const driver = node.driver;
464
+ result = driver.update(el);
465
+ if (result instanceof Promise)
466
+ result.then(v => { runUpdateNestedTreesThenDo(undefined, NOP); return v; }, e => { console.log(e); runUpdateNestedTreesThenDo(e !== null && e !== void 0 ? e : new Error('unknown error'), NOP); });
467
+ else
468
+ runUpdateNestedTreesThenDo(undefined, NOP);
469
+ }
470
+ catch (e) {
471
+ runUpdateNestedTreesThenDo(e, NOP);
472
+ console.log(`Update failed: ${node.key}`);
473
+ console.log(`${e}`);
474
+ }
475
+ }
476
+ });
477
+ }
478
+ }
479
+ function triggerFinalization(slot, isLeader, individual) {
480
+ const node = slot.instance;
481
+ const el = node.element;
482
+ if (node.stamp >= 0) {
483
+ const driver = node.driver;
484
+ if (individual && node.key !== node.declaration.key && !driver.isPartitionSeparator)
485
+ console.log(`WARNING: it is recommended to assign explicit key for conditional element in order to avoid unexpected side effects: ${node.key}`);
486
+ node.stamp = ~node.stamp;
487
+ const childrenAreLeaders = unobs(() => driver.finalize(el, isLeader));
488
+ el.native = null;
489
+ el.controller = null;
490
+ if (node.has(Mode.PinpointUpdate)) {
491
+ slot.aux = undefined;
492
+ const last = gLastToDispose;
493
+ if (last)
494
+ gLastToDispose = last.aux = slot;
495
+ else
496
+ gFirstToDispose = gLastToDispose = slot;
497
+ if (gFirstToDispose === slot)
498
+ Transaction.run({ separation: 'disposal', hint: `runDisposalLoop(initiator=${slot.instance.key})` }, () => {
499
+ void runDisposalLoop().then(NOP, error => console.log(error));
500
+ });
501
+ }
502
+ for (const child of node.children.items())
503
+ triggerFinalization(child, childrenAreLeaders, false);
504
+ RxNodeImpl.grandNodeCount--;
505
+ }
506
+ }
507
+ function runDisposalLoop() {
508
+ return __awaiter(this, void 0, void 0, function* () {
509
+ yield Transaction.requestNextFrame();
510
+ let slot = gFirstToDispose;
511
+ while (slot !== undefined) {
512
+ if (Transaction.isFrameOver(500, 5))
513
+ yield Transaction.requestNextFrame();
514
+ Rx.dispose(slot.instance);
515
+ slot = slot.aux;
516
+ RxNodeImpl.disposableNodeCount--;
517
+ }
518
+ gFirstToDispose = gLastToDispose = undefined;
519
+ });
520
+ }
521
+ function wrapToRunInside(func) {
522
+ let wrappedToRunInside;
523
+ const current = gCurrent;
524
+ if (current)
525
+ wrappedToRunInside = (...args) => {
526
+ return runInside(current, func, ...args);
527
+ };
528
+ else
529
+ wrappedToRunInside = func;
530
+ return wrappedToRunInside;
531
+ }
532
+ function runInside(slot, func, ...args) {
533
+ const outer = gCurrent;
534
+ try {
535
+ gCurrent = slot;
536
+ return func(...args);
537
+ }
538
+ finally {
539
+ gCurrent = outer;
540
+ }
541
+ }
542
+ function triggersAreEqual(a1, a2) {
543
+ let result = a1 === a2;
544
+ if (!result) {
545
+ if (Array.isArray(a1)) {
546
+ result = Array.isArray(a2) &&
547
+ a1.length === a2.length &&
548
+ a1.every((t, i) => t === a2[i]);
549
+ }
550
+ else if (a1 === Object(a1) && a2 === Object(a2)) {
551
+ for (const p in a1) {
552
+ result = a1[p] === a2[p];
553
+ if (!result)
554
+ break;
555
+ }
556
+ }
557
+ }
558
+ return result;
559
+ }
560
+ function push(item, array) {
561
+ if (array == undefined)
562
+ array = new Array();
563
+ array.push(item);
564
+ return array;
565
+ }
566
+ function shuffle(array) {
567
+ const n = array.length - 1;
568
+ let i = n;
569
+ while (i >= 0) {
570
+ const j = Math.floor(Math.random() * n);
571
+ const t = array[i];
572
+ array[i] = array[j];
573
+ array[j] = t;
574
+ i--;
575
+ }
576
+ return array;
577
+ }
578
+ const ORIGINAL_PROMISE_THEN = Promise.prototype.then;
579
+ function reactronicDomHookedThen(resolve, reject) {
580
+ resolve = resolve ? wrapToRunInside(resolve) : defaultResolve;
581
+ reject = reject ? wrapToRunInside(reject) : defaultReject;
582
+ return ORIGINAL_PROMISE_THEN.call(this, resolve, reject);
583
+ }
584
+ function defaultResolve(value) {
585
+ return value;
586
+ }
587
+ function defaultReject(error) {
588
+ throw error;
589
+ }
590
+ Promise.prototype.then = reactronicDomHookedThen;
591
+ const NOP = (...args) => { };
592
+ let gCurrent = undefined;
593
+ let gFirstToDispose = undefined;
594
+ let gLastToDispose = undefined;
@@ -0,0 +1,3 @@
1
+ export declare function emitLetters(n: number): string;
2
+ export declare function objectHasMember<T>(obj: any, member: string): obj is T;
3
+ export declare function getCallerInfo(prefix: string): string;
@@ -0,0 +1,46 @@
1
+ export function emitLetters(n) {
2
+ if (n < 0)
3
+ throw new Error(`emitLetters: argument (${n}) should not be negative or zero`);
4
+ let result = '';
5
+ while (n >= 0) {
6
+ const r = n % 26;
7
+ n = Math.floor(n / 26) - 1;
8
+ result = String.fromCharCode(65 + r) + result;
9
+ }
10
+ return result;
11
+ }
12
+ export function objectHasMember(obj, member) {
13
+ return obj === Object(obj) && !Array.isArray(obj) && member in obj;
14
+ }
15
+ export function getCallerInfo(prefix) {
16
+ const restore = Error.stackTraceLimit = 20;
17
+ const error = new Error();
18
+ const stack = error.stack || '';
19
+ Error.stackTraceLimit = restore;
20
+ const lines = stack.split('\n');
21
+ let i = lines.findIndex(x => x.indexOf('.declare') >= 0);
22
+ i = i >= 0 ? i + 2 : 5;
23
+ let caller = extractFunctionAndLocation(lines[i]);
24
+ let location = caller;
25
+ if (caller.func.endsWith('.update')) {
26
+ i = i - 1;
27
+ caller = extractFunctionAndLocation(lines[i]);
28
+ location = extractFunctionAndLocation(lines[i + 1]);
29
+ }
30
+ else {
31
+ while (!caller.func && i > 0) {
32
+ i = i - 1;
33
+ caller = extractFunctionAndLocation(lines[i]);
34
+ }
35
+ location = extractFunctionAndLocation(lines[i + 1]);
36
+ }
37
+ const result = `${prefix}·${caller.func}@${location.file}`;
38
+ return result;
39
+ }
40
+ function extractFunctionAndLocation(s) {
41
+ const match = s.match(/(?:\s*at\s+)?(?:(\S+)\s\()?(?:.*?)([^\/\(\):]+)(?:(:|\d)*\)?)$/);
42
+ return {
43
+ func: (match === null || match === void 0 ? void 0 : match[1]) || '',
44
+ file: (match === null || match === void 0 ? void 0 : match[2]) || '',
45
+ };
46
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reactronic",
3
- "version": "0.23.115",
3
+ "version": "0.24.101",
4
4
  "description": "Reactronic - Transactional Reactive State Management",
5
5
  "publisher": "Nezaboodka Software",
6
6
  "license": "Apache-2.0",