@katn30/trakr 1.1.1 → 2.0.0

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/dist/dev/index.js CHANGED
@@ -216,6 +216,242 @@ function validateSingleProperty(tracked, property) {
216
216
  return error;
217
217
  }
218
218
 
219
+ // src/OperationProperties.ts
220
+ var OperationProperties = class {
221
+ constructor(trackedObject, property, type, validator, coalesceWithin) {
222
+ this.trackedObject = trackedObject;
223
+ this.property = property;
224
+ this.type = type;
225
+ this.validator = validator;
226
+ this.coalesceWithin = coalesceWithin;
227
+ }
228
+ };
229
+
230
+ // src/ExternallyAssigned.ts
231
+ var AUTO_ID = /* @__PURE__ */ Symbol("autoId");
232
+ function AutoId(_target, context) {
233
+ context.addInitializer(function() {
234
+ Object.defineProperty(Object.getPrototypeOf(this), AUTO_ID, {
235
+ value: String(context.name),
236
+ configurable: true
237
+ });
238
+ });
239
+ }
240
+ function getAutoIdProperty(proto) {
241
+ return AUTO_ID in proto ? proto[AUTO_ID] : void 0;
242
+ }
243
+
244
+ // src/TrackedObjectStateMachine.ts
245
+ function applyStateTransition(obj, event, direction, context) {
246
+ if (event === "added") {
247
+ applyAdded(obj, direction);
248
+ } else if (event === "removed") {
249
+ applyRemoved(obj, direction, context);
250
+ } else {
251
+ applyCommitted(obj, direction, context);
252
+ }
253
+ }
254
+ function applyAdded(obj, direction) {
255
+ if (direction === "undo") {
256
+ obj._setState("Unchanged" /* Unchanged */);
257
+ } else {
258
+ obj._setState("Insert" /* Insert */);
259
+ }
260
+ }
261
+ function applyRemoved(obj, direction, context) {
262
+ if (direction === "undo") {
263
+ const prev = context?.prevState ?? "Unchanged" /* Unchanged */;
264
+ obj._setState(prev);
265
+ if (prev === "Insert" /* Insert */) {
266
+ if (context?.prevDirtyCounter !== void 0) {
267
+ obj._setDirtyCounter(context.prevDirtyCounter);
268
+ }
269
+ }
270
+ } else {
271
+ if (obj.state === "Insert" /* Insert */) {
272
+ obj._setState("Unchanged" /* Unchanged */);
273
+ obj._setDirtyCounter(0);
274
+ } else {
275
+ obj._setState("Deleted" /* Deleted */);
276
+ }
277
+ }
278
+ }
279
+ function applyCommitted(obj, direction, context) {
280
+ if (direction === "undo") {
281
+ const prev = context?.prevState ?? "Unchanged" /* Unchanged */;
282
+ if (prev === "Insert" /* Insert */) {
283
+ obj._setState("Deleted" /* Deleted */);
284
+ } else if (prev === "Deleted" /* Deleted */) {
285
+ obj._setState("Insert" /* Insert */);
286
+ } else if (prev === "Changed" /* Changed */) {
287
+ obj._setState("Changed" /* Changed */);
288
+ }
289
+ } else {
290
+ if ((context?.prevState === "Insert" /* Insert */ || context?.prevState === "Changed" /* Changed */) && context.autoIdProp && context.realId !== void 0) {
291
+ obj[context.autoIdProp] = context.realId;
292
+ }
293
+ obj._setState("Unchanged" /* Unchanged */);
294
+ obj._setDirtyCounter(0);
295
+ }
296
+ }
297
+ function buildCommittedContext(obj, autoIdProp, keys) {
298
+ const prevState = obj.state;
299
+ let realId;
300
+ if ((prevState === "Insert" /* Insert */ || prevState === "Changed" /* Changed */) && keys) {
301
+ realId = keys.find((k) => k.trackingId === obj.trackingId)?.value;
302
+ }
303
+ return { prevState, autoIdProp, realId };
304
+ }
305
+
306
+ // src/TrackedObject.ts
307
+ var TrackedObject = class {
308
+ constructor(tracker) {
309
+ this.tracker = tracker;
310
+ this._dirtyCounter = 0;
311
+ this._isValid = true;
312
+ this._state = "Unchanged" /* Unchanged */;
313
+ this.changed = new TypedEvent();
314
+ this.trackedChanged = new TypedEvent();
315
+ if (!tracker._isConstructing) {
316
+ throw new Error(`${this.constructor.name} must be created inside tracker.construct()`);
317
+ }
318
+ this.trackingId = tracker._nextTrackingId();
319
+ this.validationMessages = /* @__PURE__ */ new Map();
320
+ tracker._trackObject(this);
321
+ }
322
+ // ---- StateTarget interface (internal) ----
323
+ /** @internal */
324
+ get state() {
325
+ return this._state;
326
+ }
327
+ /** @internal */
328
+ _setState(value) {
329
+ this._state = value;
330
+ }
331
+ /** @internal */
332
+ _getDirtyCounter() {
333
+ return this._dirtyCounter;
334
+ }
335
+ /** @internal */
336
+ _setDirtyCounter(value) {
337
+ this._dirtyCounter = value;
338
+ }
339
+ // ---- Public API ----
340
+ get validationMessages() {
341
+ return this._validationMessages ?? /* @__PURE__ */ new Map();
342
+ }
343
+ set validationMessages(value) {
344
+ this._validationMessages = value;
345
+ }
346
+ get isValid() {
347
+ return this._isValid;
348
+ }
349
+ set isValid(value) {
350
+ const wasValid = this._isValid;
351
+ this._isValid = value;
352
+ if (wasValid !== value) {
353
+ this.tracker._onValidityChanged(wasValid, value);
354
+ }
355
+ }
356
+ get isDirty() {
357
+ return this._dirtyCounter !== 0;
358
+ }
359
+ get dirtyCounter() {
360
+ return this._dirtyCounter;
361
+ }
362
+ set dirtyCounter(value) {
363
+ this._dirtyCounter = value;
364
+ }
365
+ /** @internal */
366
+ _onCommitted(lastOp, keys) {
367
+ const autoIdProp = getAutoIdProperty(Object.getPrototypeOf(this));
368
+ const context = buildCommittedContext(this, autoIdProp, keys);
369
+ const redoFn = () => applyStateTransition(this, "committed", "do", context);
370
+ const undoFn = () => applyStateTransition(this, "committed", "undo", context);
371
+ if (lastOp) {
372
+ lastOp.updateOrAdd(redoFn, undoFn, new OperationProperties(this, "__state__", 4 /* Object */));
373
+ }
374
+ redoFn();
375
+ }
376
+ /** @internal */
377
+ _markRemoved() {
378
+ const prevState = this._state;
379
+ const prevDirtyCounter = this._dirtyCounter;
380
+ this.tracker._doAndTrack(
381
+ () => applyStateTransition(this, "removed", "do"),
382
+ () => applyStateTransition(this, "removed", "undo", { prevState, prevDirtyCounter }),
383
+ new OperationProperties(this, "__state__", 4 /* Object */)
384
+ );
385
+ }
386
+ /** @internal */
387
+ _markAdded() {
388
+ if (this._state !== "Unchanged" /* Unchanged */) return;
389
+ if (this.tracker._isTrackingSuppressed) return;
390
+ this.tracker._doAndTrack(
391
+ () => applyStateTransition(this, "added", "do"),
392
+ () => applyStateTransition(this, "added", "undo"),
393
+ new OperationProperties(this, "__state__", 4 /* Object */)
394
+ );
395
+ }
396
+ /** @internal */
397
+ _validate(property, errorMessage) {
398
+ if (errorMessage) {
399
+ this.validationMessages.set(property, errorMessage);
400
+ } else {
401
+ this.validationMessages.delete(property);
402
+ }
403
+ this.validationMessages = new Map(this.validationMessages);
404
+ this.isValid = this.validationMessages.size === 0;
405
+ }
406
+ /** @internal */
407
+ _applyValidation(messages) {
408
+ this.validationMessages = messages;
409
+ this.isValid = messages.size === 0;
410
+ }
411
+ destroy() {
412
+ DependencyTracker.clearDeps(this);
413
+ this.tracker._untrackObject(this);
414
+ }
415
+ };
416
+
417
+ // src/TrackerSession.ts
418
+ var TrackerSession = class {
419
+ constructor(scope, _end, _rollback) {
420
+ this._end = _end;
421
+ this._rollback = _rollback;
422
+ this._isDirty = false;
423
+ if (scope && scope.length > 0) {
424
+ this._scope = new Map(scope.map(([obj, props]) => [obj, new Set(props)]));
425
+ }
426
+ }
427
+ /** @internal */
428
+ _onWrite(obj, property) {
429
+ if (this._scope === void 0) return;
430
+ const declaredProps = this._scope.get(obj);
431
+ if (declaredProps === void 0 || !declaredProps.has(property)) return;
432
+ this._isDirty = true;
433
+ }
434
+ get isDirty() {
435
+ if (this._scope === void 0) return void 0;
436
+ return this._isDirty;
437
+ }
438
+ get isValid() {
439
+ if (this._scope === void 0) return void 0;
440
+ for (const [obj, props] of this._scope) {
441
+ for (const prop of props) {
442
+ if (obj.validationMessages.has(prop)) return false;
443
+ }
444
+ }
445
+ return true;
446
+ }
447
+ end() {
448
+ this._end();
449
+ }
450
+ rollback() {
451
+ this._rollback();
452
+ }
453
+ };
454
+
219
455
  // src/Tracker.ts
220
456
  var Tracker = class {
221
457
  constructor() {
@@ -389,6 +625,9 @@ var Tracker = class {
389
625
  properties
390
626
  );
391
627
  redoAction();
628
+ if (this._currentSession !== void 0 && properties.property !== void 0 && properties.trackedObject instanceof TrackedObject) {
629
+ this._currentSession._onWrite(properties.trackedObject, properties.property);
630
+ }
392
631
  if (this.isEndingCurrentOperation(properties)) {
393
632
  this._currentOperation = void 0;
394
633
  this._currentOperationOwner = void 0;
@@ -451,13 +690,20 @@ var Tracker = class {
451
690
  this.canRedo = this._redoOperations.length > 0;
452
691
  this.isDirty = CollectionUtilities.getLast(this._undoOperations) !== this._commitStateOperation;
453
692
  }
454
- startComposing() {
455
- if (this._composingBaseIndex !== void 0) return;
693
+ startSession(scope) {
694
+ if (this._currentSession !== void 0) return this._currentSession;
456
695
  this._composingBaseIndex = this._undoOperations.length;
457
696
  this._composingRedoLength = this._redoOperations.length;
697
+ this._currentSession = new TrackerSession(
698
+ scope,
699
+ () => this.endComposing(),
700
+ () => this.rollbackComposing()
701
+ );
702
+ return this._currentSession;
458
703
  }
459
704
  endComposing() {
460
705
  if (this._composingBaseIndex === void 0) return;
706
+ this._currentSession = void 0;
461
707
  const composed = this._undoOperations.splice(this._composingBaseIndex);
462
708
  this._redoOperations.splice(this._composingRedoLength);
463
709
  this._composingBaseIndex = void 0;
@@ -482,6 +728,7 @@ var Tracker = class {
482
728
  }
483
729
  rollbackComposing() {
484
730
  if (this._composingBaseIndex === void 0) return;
731
+ this._currentSession = void 0;
485
732
  const toRevert = this._undoOperations.splice(this._composingBaseIndex);
486
733
  this._redoOperations.splice(this._composingRedoLength);
487
734
  this._composingBaseIndex = void 0;
@@ -533,204 +780,6 @@ var Tracker = class {
533
780
  }
534
781
  };
535
782
 
536
- // src/OperationProperties.ts
537
- var OperationProperties = class {
538
- constructor(trackedObject, property, type, validator, coalesceWithin) {
539
- this.trackedObject = trackedObject;
540
- this.property = property;
541
- this.type = type;
542
- this.validator = validator;
543
- this.coalesceWithin = coalesceWithin;
544
- }
545
- };
546
-
547
- // src/ExternallyAssigned.ts
548
- var AUTO_ID = /* @__PURE__ */ Symbol("autoId");
549
- function AutoId(_target, context) {
550
- context.addInitializer(function() {
551
- Object.defineProperty(Object.getPrototypeOf(this), AUTO_ID, {
552
- value: String(context.name),
553
- configurable: true
554
- });
555
- });
556
- }
557
- function getAutoIdProperty(proto) {
558
- return AUTO_ID in proto ? proto[AUTO_ID] : void 0;
559
- }
560
-
561
- // src/TrackedObjectStateMachine.ts
562
- function applyStateTransition(obj, event, direction, context) {
563
- if (event === "added") {
564
- applyAdded(obj, direction);
565
- } else if (event === "removed") {
566
- applyRemoved(obj, direction, context);
567
- } else {
568
- applyCommitted(obj, direction, context);
569
- }
570
- }
571
- function applyAdded(obj, direction) {
572
- if (direction === "undo") {
573
- obj._setState("Unchanged" /* Unchanged */);
574
- } else {
575
- obj._setState("Insert" /* Insert */);
576
- }
577
- }
578
- function applyRemoved(obj, direction, context) {
579
- if (direction === "undo") {
580
- const prev = context?.prevState ?? "Unchanged" /* Unchanged */;
581
- obj._setState(prev);
582
- if (prev === "Insert" /* Insert */) {
583
- if (context?.prevDirtyCounter !== void 0) {
584
- obj._setDirtyCounter(context.prevDirtyCounter);
585
- }
586
- }
587
- } else {
588
- if (obj.state === "Insert" /* Insert */) {
589
- obj._setState("Unchanged" /* Unchanged */);
590
- obj._setDirtyCounter(0);
591
- } else {
592
- obj._setState("Deleted" /* Deleted */);
593
- }
594
- }
595
- }
596
- function applyCommitted(obj, direction, context) {
597
- if (direction === "undo") {
598
- const prev = context?.prevState ?? "Unchanged" /* Unchanged */;
599
- if (prev === "Insert" /* Insert */) {
600
- obj._setState("Deleted" /* Deleted */);
601
- } else if (prev === "Deleted" /* Deleted */) {
602
- obj._setState("Insert" /* Insert */);
603
- } else if (prev === "Changed" /* Changed */) {
604
- obj._setState("Changed" /* Changed */);
605
- }
606
- } else {
607
- if ((context?.prevState === "Insert" /* Insert */ || context?.prevState === "Changed" /* Changed */) && context.autoIdProp && context.realId !== void 0) {
608
- obj[context.autoIdProp] = context.realId;
609
- }
610
- obj._setState("Unchanged" /* Unchanged */);
611
- obj._setDirtyCounter(0);
612
- }
613
- }
614
- function buildCommittedContext(obj, autoIdProp, keys) {
615
- const prevState = obj.state;
616
- let realId;
617
- if ((prevState === "Insert" /* Insert */ || prevState === "Changed" /* Changed */) && keys) {
618
- realId = keys.find((k) => k.trackingId === obj.trackingId)?.value;
619
- }
620
- return { prevState, autoIdProp, realId };
621
- }
622
-
623
- // src/TrackedObject.ts
624
- var TrackedObject = class {
625
- constructor(tracker) {
626
- this.tracker = tracker;
627
- this._dirtyCounter = 0;
628
- this._isValid = true;
629
- this._state = "Unchanged" /* Unchanged */;
630
- this.changed = new TypedEvent();
631
- this.trackedChanged = new TypedEvent();
632
- if (!tracker._isConstructing) {
633
- throw new Error(`${this.constructor.name} must be created inside tracker.construct()`);
634
- }
635
- this.trackingId = tracker._nextTrackingId();
636
- this.validationMessages = /* @__PURE__ */ new Map();
637
- tracker._trackObject(this);
638
- }
639
- // ---- StateTarget interface (internal) ----
640
- /** @internal */
641
- get state() {
642
- return this._state;
643
- }
644
- /** @internal */
645
- _setState(value) {
646
- this._state = value;
647
- }
648
- /** @internal */
649
- _getDirtyCounter() {
650
- return this._dirtyCounter;
651
- }
652
- /** @internal */
653
- _setDirtyCounter(value) {
654
- this._dirtyCounter = value;
655
- }
656
- // ---- Public API ----
657
- get validationMessages() {
658
- return this._validationMessages ?? /* @__PURE__ */ new Map();
659
- }
660
- set validationMessages(value) {
661
- this._validationMessages = value;
662
- }
663
- get isValid() {
664
- return this._isValid;
665
- }
666
- set isValid(value) {
667
- const wasValid = this._isValid;
668
- this._isValid = value;
669
- if (wasValid !== value) {
670
- this.tracker._onValidityChanged(wasValid, value);
671
- }
672
- }
673
- get isDirty() {
674
- return this._dirtyCounter !== 0;
675
- }
676
- get dirtyCounter() {
677
- return this._dirtyCounter;
678
- }
679
- set dirtyCounter(value) {
680
- this._dirtyCounter = value;
681
- }
682
- /** @internal */
683
- _onCommitted(lastOp, keys) {
684
- const autoIdProp = getAutoIdProperty(Object.getPrototypeOf(this));
685
- const context = buildCommittedContext(this, autoIdProp, keys);
686
- const redoFn = () => applyStateTransition(this, "committed", "do", context);
687
- const undoFn = () => applyStateTransition(this, "committed", "undo", context);
688
- if (lastOp) {
689
- lastOp.updateOrAdd(redoFn, undoFn, new OperationProperties(this, "__state__", 4 /* Object */));
690
- }
691
- redoFn();
692
- }
693
- /** @internal */
694
- _markRemoved() {
695
- const prevState = this._state;
696
- const prevDirtyCounter = this._dirtyCounter;
697
- this.tracker._doAndTrack(
698
- () => applyStateTransition(this, "removed", "do"),
699
- () => applyStateTransition(this, "removed", "undo", { prevState, prevDirtyCounter }),
700
- new OperationProperties(this, "__state__", 4 /* Object */)
701
- );
702
- }
703
- /** @internal */
704
- _markAdded() {
705
- if (this._state !== "Unchanged" /* Unchanged */) return;
706
- if (this.tracker._isTrackingSuppressed) return;
707
- this.tracker._doAndTrack(
708
- () => applyStateTransition(this, "added", "do"),
709
- () => applyStateTransition(this, "added", "undo"),
710
- new OperationProperties(this, "__state__", 4 /* Object */)
711
- );
712
- }
713
- /** @internal */
714
- _validate(property, errorMessage) {
715
- if (errorMessage) {
716
- this.validationMessages.set(property, errorMessage);
717
- } else {
718
- this.validationMessages.delete(property);
719
- }
720
- this.validationMessages = new Map(this.validationMessages);
721
- this.isValid = this.validationMessages.size === 0;
722
- }
723
- /** @internal */
724
- _applyValidation(messages) {
725
- this.validationMessages = messages;
726
- this.isValid = messages.size === 0;
727
- }
728
- destroy() {
729
- DependencyTracker.clearDeps(this);
730
- this.tracker._untrackObject(this);
731
- }
732
- };
733
-
734
783
  // src/Tracked.ts
735
784
  function Tracked(validator, onChange, options) {
736
785
  function decorator(target, context) {
@@ -1226,6 +1275,7 @@ export {
1226
1275
  TrackedCollectionChanged,
1227
1276
  TrackedObject,
1228
1277
  Tracker,
1278
+ TrackerSession,
1229
1279
  TypedEvent
1230
1280
  };
1231
1281
  //# sourceMappingURL=index.js.map