@katn30/trakr 2.2.0 → 3.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.
@@ -176,8 +176,38 @@ var DependencyTracker = {
176
176
 
177
177
  // src/Registry.ts
178
178
  var VALIDATORS = /* @__PURE__ */ Symbol("validators");
179
+ function hasOwnValidators(proto) {
180
+ return Object.prototype.hasOwnProperty.call(proto, VALIDATORS);
181
+ }
182
+ function ownValidators(proto) {
183
+ return hasOwnValidators(proto) ? proto[VALIDATORS] : void 0;
184
+ }
185
+ function mergeInheritedValidators(proto) {
186
+ const merged = /* @__PURE__ */ new Map();
187
+ let current = proto;
188
+ while (current) {
189
+ const own = ownValidators(current);
190
+ if (own) {
191
+ own.forEach((validator, property) => {
192
+ if (!merged.has(property)) merged.set(property, validator);
193
+ });
194
+ }
195
+ current = Object.getPrototypeOf(current);
196
+ }
197
+ return merged;
198
+ }
199
+ function findInheritedValidator(proto, property) {
200
+ let current = proto;
201
+ while (current) {
202
+ const own = ownValidators(current);
203
+ const validator = own?.get(property);
204
+ if (validator) return validator;
205
+ current = Object.getPrototypeOf(current);
206
+ }
207
+ return void 0;
208
+ }
179
209
  function registerPropertyValidator(proto, property, validator) {
180
- if (!(VALIDATORS in proto)) {
210
+ if (!hasOwnValidators(proto)) {
181
211
  Object.defineProperty(proto, VALIDATORS, {
182
212
  value: /* @__PURE__ */ new Map(),
183
213
  configurable: true
@@ -190,8 +220,8 @@ function registerPropertyValidator(proto, property, validator) {
190
220
  }
191
221
  function validate(tracked) {
192
222
  const proto = Object.getPrototypeOf(tracked);
193
- if (!(VALIDATORS in proto)) return;
194
- const validators = proto[VALIDATORS];
223
+ const validators = mergeInheritedValidators(proto);
224
+ if (validators.size === 0) return;
195
225
  const messages = /* @__PURE__ */ new Map();
196
226
  validators.forEach((validatorFn, property) => {
197
227
  const deps = DependencyTracker.collect(() => {
@@ -204,9 +234,7 @@ function validate(tracked) {
204
234
  }
205
235
  function validateSingleProperty(tracked, property) {
206
236
  const proto = Object.getPrototypeOf(tracked);
207
- if (!(VALIDATORS in proto)) return void 0;
208
- const validators = proto[VALIDATORS];
209
- const validatorFn = validators.get(property);
237
+ const validatorFn = findInheritedValidator(proto, property);
210
238
  if (!validatorFn) return void 0;
211
239
  let error;
212
240
  const deps = DependencyTracker.collect(() => {
@@ -1300,8 +1328,229 @@ var TrackedCollectionChanged = class {
1300
1328
  this.newCollection = newCollection;
1301
1329
  }
1302
1330
  };
1331
+
1332
+ // src/EventRegistry.ts
1333
+ var EVENT_METADATA = /* @__PURE__ */ Symbol("eventMetadata");
1334
+ var instanceState = /* @__PURE__ */ new WeakMap();
1335
+ var subscribedInstances = /* @__PURE__ */ new WeakSet();
1336
+ var itemOriginCollection = /* @__PURE__ */ new WeakMap();
1337
+ function hasOwnEventMetadata(proto) {
1338
+ return Object.prototype.hasOwnProperty.call(proto, EVENT_METADATA);
1339
+ }
1340
+ function ownEventMetadata(proto) {
1341
+ return hasOwnEventMetadata(proto) ? proto[EVENT_METADATA] : void 0;
1342
+ }
1343
+ function registerEventProperty(proto, property, eventType) {
1344
+ if (!hasOwnEventMetadata(proto)) {
1345
+ Object.defineProperty(proto, EVENT_METADATA, {
1346
+ value: /* @__PURE__ */ new Map(),
1347
+ configurable: true
1348
+ });
1349
+ }
1350
+ const map = proto[EVENT_METADATA];
1351
+ if (!map.has(property)) {
1352
+ map.set(property, eventType);
1353
+ }
1354
+ }
1355
+ function getEventMetadata(proto) {
1356
+ const chain = [];
1357
+ let current = proto;
1358
+ while (current) {
1359
+ chain.push(current);
1360
+ current = Object.getPrototypeOf(current);
1361
+ }
1362
+ const merged = /* @__PURE__ */ new Map();
1363
+ for (let i = chain.length - 1; i >= 0; i--) {
1364
+ const own = ownEventMetadata(chain[i]);
1365
+ if (!own) continue;
1366
+ own.forEach((eventType, property) => {
1367
+ if (!merged.has(property)) merged.set(property, eventType);
1368
+ });
1369
+ }
1370
+ return merged;
1371
+ }
1372
+ function ensureEventStateSubscription(target) {
1373
+ if (subscribedInstances.has(target)) return;
1374
+ subscribedInstances.add(target);
1375
+ target.changed.subscribe((evt) => {
1376
+ const meta = getEventMetadata(Object.getPrototypeOf(target));
1377
+ if (!meta.has(evt.property)) return;
1378
+ const state = getOrCreateEventState(target);
1379
+ let entry = state.get(evt.property);
1380
+ if (!entry) {
1381
+ entry = { originalValue: evt.oldValue, currentValue: evt.newValue };
1382
+ state.set(evt.property, entry);
1383
+ } else {
1384
+ entry.currentValue = evt.newValue;
1385
+ }
1386
+ if (entry.currentValue === entry.originalValue) {
1387
+ state.delete(evt.property);
1388
+ }
1389
+ });
1390
+ }
1391
+ function getOrCreateEventState(target) {
1392
+ let state = instanceState.get(target);
1393
+ if (!state) {
1394
+ state = /* @__PURE__ */ new Map();
1395
+ instanceState.set(target, state);
1396
+ }
1397
+ return state;
1398
+ }
1399
+ function getEventState(target) {
1400
+ return instanceState.get(target) ?? /* @__PURE__ */ new Map();
1401
+ }
1402
+ function clearEventState(target) {
1403
+ instanceState.delete(target);
1404
+ }
1405
+ function recordItemOrigin(item, collection) {
1406
+ itemOriginCollection.set(item, collection);
1407
+ }
1408
+ function getItemOrigin(item) {
1409
+ return itemOriginCollection.get(item);
1410
+ }
1411
+
1412
+ // src/EventTracker.ts
1413
+ var EventTracker = class extends Tracker {
1414
+ onCommit(keys) {
1415
+ super.onCommit(keys);
1416
+ for (const obj of this.trackedObjects) {
1417
+ clearEventState(obj);
1418
+ }
1419
+ }
1420
+ generateEvents() {
1421
+ const events = [];
1422
+ for (const obj of this.trackedObjects) {
1423
+ const meta = getEventMetadata(Object.getPrototypeOf(obj));
1424
+ const origin = getItemOrigin(obj);
1425
+ const lifecycle = origin?._lifecycleOptions;
1426
+ switch (obj.state) {
1427
+ case "Insert" /* Insert */:
1428
+ if (lifecycle?.itemAdded) {
1429
+ events.push(buildItemAddedEvent(obj, meta, lifecycle.itemAdded));
1430
+ }
1431
+ break;
1432
+ case "Deleted" /* Deleted */:
1433
+ if (lifecycle?.itemRemoved) {
1434
+ events.push(buildItemRemovedEvent(obj, lifecycle.itemRemoved));
1435
+ }
1436
+ break;
1437
+ case "Changed" /* Changed */:
1438
+ pushFieldClusterEvents(obj, meta, events);
1439
+ break;
1440
+ case "Unchanged" /* Unchanged */:
1441
+ default:
1442
+ break;
1443
+ }
1444
+ }
1445
+ return events;
1446
+ }
1447
+ };
1448
+ function buildItemAddedEvent(obj, meta, eventType) {
1449
+ const payload = {};
1450
+ for (const [propertyName] of meta) {
1451
+ const value = obj[propertyName];
1452
+ payload[propertyName] = normalizeValue(value);
1453
+ }
1454
+ return {
1455
+ eventType,
1456
+ payload,
1457
+ trackingId: obj.trackingId
1458
+ };
1459
+ }
1460
+ function buildItemRemovedEvent(obj, eventType) {
1461
+ const autoIdProp = getAutoIdProperty(Object.getPrototypeOf(obj));
1462
+ const targetId = autoIdProp ? obj[autoIdProp] : void 0;
1463
+ const event = {
1464
+ eventType,
1465
+ payload: {}
1466
+ };
1467
+ if (typeof targetId === "number") {
1468
+ event.targetId = targetId;
1469
+ }
1470
+ return event;
1471
+ }
1472
+ function pushFieldClusterEvents(obj, meta, events) {
1473
+ const state = getEventState(obj);
1474
+ if (state.size === 0) return;
1475
+ const grouped = /* @__PURE__ */ new Map();
1476
+ for (const [propertyName, eventType] of meta) {
1477
+ if (!state.has(propertyName)) continue;
1478
+ let bucket = grouped.get(eventType);
1479
+ if (!bucket) {
1480
+ bucket = [];
1481
+ grouped.set(eventType, bucket);
1482
+ }
1483
+ bucket.push(propertyName);
1484
+ }
1485
+ const autoIdProp = getAutoIdProperty(Object.getPrototypeOf(obj));
1486
+ const targetIdRaw = autoIdProp ? obj[autoIdProp] : void 0;
1487
+ for (const [eventType, propertyNames] of grouped) {
1488
+ const payload = {};
1489
+ for (const propertyName of propertyNames) {
1490
+ payload[propertyName] = normalizeValue(state.get(propertyName).currentValue);
1491
+ }
1492
+ const event = {
1493
+ eventType,
1494
+ payload,
1495
+ trackingId: obj.trackingId
1496
+ };
1497
+ if (typeof targetIdRaw === "number") {
1498
+ event.targetId = targetIdRaw;
1499
+ }
1500
+ events.push(event);
1501
+ }
1502
+ }
1503
+ function normalizeValue(value) {
1504
+ return value === void 0 ? null : value;
1505
+ }
1506
+
1507
+ // src/EventTracked.ts
1508
+ function EventTracked(eventType, validator, onChange, options) {
1509
+ const trackedDecorator = Tracked(validator, onChange, options);
1510
+ function decorator(target, context) {
1511
+ const result = trackedDecorator(target, context);
1512
+ const propertyName = String(context.name);
1513
+ context.addInitializer(function() {
1514
+ registerEventProperty(
1515
+ Object.getPrototypeOf(this),
1516
+ propertyName,
1517
+ eventType
1518
+ );
1519
+ ensureEventStateSubscription(this);
1520
+ });
1521
+ return result;
1522
+ }
1523
+ return decorator;
1524
+ }
1525
+
1526
+ // src/EventTrackedCollection.ts
1527
+ var EventTrackedCollection = class extends TrackedCollection {
1528
+ constructor(tracker, items, validator, eventOptions) {
1529
+ super(tracker, items, validator);
1530
+ this._eventOptions = eventOptions;
1531
+ for (const item of this.collection) {
1532
+ if (item instanceof TrackedObject) {
1533
+ recordItemOrigin(item, this);
1534
+ }
1535
+ }
1536
+ this.changed.subscribe((evt) => {
1537
+ for (const item of evt.added) {
1538
+ if (item instanceof TrackedObject) {
1539
+ recordItemOrigin(item, this);
1540
+ }
1541
+ }
1542
+ });
1543
+ }
1544
+ /** @internal */
1545
+ get _lifecycleOptions() {
1546
+ return this._eventOptions;
1547
+ }
1548
+ };
1303
1549
  export {
1304
1550
  AutoId,
1551
+ EventTracked,
1552
+ EventTrackedCollection,
1553
+ EventTracker,
1305
1554
  State,
1306
1555
  Tracked,
1307
1556
  TrackedCollection,