@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.
- package/README.md +224 -0
- package/dist/dev/index.cjs +258 -6
- package/dist/dev/index.cjs.map +1 -1
- package/dist/dev/index.d.cts +32 -1
- package/dist/dev/index.d.ts +32 -1
- package/dist/dev/index.js +255 -6
- package/dist/dev/index.js.map +1 -1
- package/dist/prod/index.cjs +258 -6
- package/dist/prod/index.cjs.map +1 -1
- package/dist/prod/index.js +255 -6
- package/dist/prod/index.js.map +1 -1
- package/package.json +1 -1
package/dist/prod/index.cjs
CHANGED
|
@@ -21,6 +21,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
AutoId: () => AutoId,
|
|
24
|
+
EventTracked: () => EventTracked,
|
|
25
|
+
EventTrackedCollection: () => EventTrackedCollection,
|
|
26
|
+
EventTracker: () => EventTracker,
|
|
24
27
|
State: () => State,
|
|
25
28
|
Tracked: () => Tracked,
|
|
26
29
|
TrackedCollection: () => TrackedCollection,
|
|
@@ -210,8 +213,38 @@ var DependencyTracker = {
|
|
|
210
213
|
|
|
211
214
|
// src/Registry.ts
|
|
212
215
|
var VALIDATORS = /* @__PURE__ */ Symbol("validators");
|
|
216
|
+
function hasOwnValidators(proto) {
|
|
217
|
+
return Object.prototype.hasOwnProperty.call(proto, VALIDATORS);
|
|
218
|
+
}
|
|
219
|
+
function ownValidators(proto) {
|
|
220
|
+
return hasOwnValidators(proto) ? proto[VALIDATORS] : void 0;
|
|
221
|
+
}
|
|
222
|
+
function mergeInheritedValidators(proto) {
|
|
223
|
+
const merged = /* @__PURE__ */ new Map();
|
|
224
|
+
let current = proto;
|
|
225
|
+
while (current) {
|
|
226
|
+
const own = ownValidators(current);
|
|
227
|
+
if (own) {
|
|
228
|
+
own.forEach((validator, property) => {
|
|
229
|
+
if (!merged.has(property)) merged.set(property, validator);
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
current = Object.getPrototypeOf(current);
|
|
233
|
+
}
|
|
234
|
+
return merged;
|
|
235
|
+
}
|
|
236
|
+
function findInheritedValidator(proto, property) {
|
|
237
|
+
let current = proto;
|
|
238
|
+
while (current) {
|
|
239
|
+
const own = ownValidators(current);
|
|
240
|
+
const validator = own?.get(property);
|
|
241
|
+
if (validator) return validator;
|
|
242
|
+
current = Object.getPrototypeOf(current);
|
|
243
|
+
}
|
|
244
|
+
return void 0;
|
|
245
|
+
}
|
|
213
246
|
function registerPropertyValidator(proto, property, validator) {
|
|
214
|
-
if (!(
|
|
247
|
+
if (!hasOwnValidators(proto)) {
|
|
215
248
|
Object.defineProperty(proto, VALIDATORS, {
|
|
216
249
|
value: /* @__PURE__ */ new Map(),
|
|
217
250
|
configurable: true
|
|
@@ -224,8 +257,8 @@ function registerPropertyValidator(proto, property, validator) {
|
|
|
224
257
|
}
|
|
225
258
|
function validate(tracked) {
|
|
226
259
|
const proto = Object.getPrototypeOf(tracked);
|
|
227
|
-
|
|
228
|
-
|
|
260
|
+
const validators = mergeInheritedValidators(proto);
|
|
261
|
+
if (validators.size === 0) return;
|
|
229
262
|
const messages = /* @__PURE__ */ new Map();
|
|
230
263
|
validators.forEach((validatorFn, property) => {
|
|
231
264
|
const deps = DependencyTracker.collect(() => {
|
|
@@ -238,9 +271,7 @@ function validate(tracked) {
|
|
|
238
271
|
}
|
|
239
272
|
function validateSingleProperty(tracked, property) {
|
|
240
273
|
const proto = Object.getPrototypeOf(tracked);
|
|
241
|
-
|
|
242
|
-
const validators = proto[VALIDATORS];
|
|
243
|
-
const validatorFn = validators.get(property);
|
|
274
|
+
const validatorFn = findInheritedValidator(proto, property);
|
|
244
275
|
if (!validatorFn) return void 0;
|
|
245
276
|
let error;
|
|
246
277
|
const deps = DependencyTracker.collect(() => {
|
|
@@ -1334,9 +1365,230 @@ var TrackedCollectionChanged = class {
|
|
|
1334
1365
|
this.newCollection = newCollection;
|
|
1335
1366
|
}
|
|
1336
1367
|
};
|
|
1368
|
+
|
|
1369
|
+
// src/EventRegistry.ts
|
|
1370
|
+
var EVENT_METADATA = /* @__PURE__ */ Symbol("eventMetadata");
|
|
1371
|
+
var instanceState = /* @__PURE__ */ new WeakMap();
|
|
1372
|
+
var subscribedInstances = /* @__PURE__ */ new WeakSet();
|
|
1373
|
+
var itemOriginCollection = /* @__PURE__ */ new WeakMap();
|
|
1374
|
+
function hasOwnEventMetadata(proto) {
|
|
1375
|
+
return Object.prototype.hasOwnProperty.call(proto, EVENT_METADATA);
|
|
1376
|
+
}
|
|
1377
|
+
function ownEventMetadata(proto) {
|
|
1378
|
+
return hasOwnEventMetadata(proto) ? proto[EVENT_METADATA] : void 0;
|
|
1379
|
+
}
|
|
1380
|
+
function registerEventProperty(proto, property, eventType) {
|
|
1381
|
+
if (!hasOwnEventMetadata(proto)) {
|
|
1382
|
+
Object.defineProperty(proto, EVENT_METADATA, {
|
|
1383
|
+
value: /* @__PURE__ */ new Map(),
|
|
1384
|
+
configurable: true
|
|
1385
|
+
});
|
|
1386
|
+
}
|
|
1387
|
+
const map = proto[EVENT_METADATA];
|
|
1388
|
+
if (!map.has(property)) {
|
|
1389
|
+
map.set(property, eventType);
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
function getEventMetadata(proto) {
|
|
1393
|
+
const chain = [];
|
|
1394
|
+
let current = proto;
|
|
1395
|
+
while (current) {
|
|
1396
|
+
chain.push(current);
|
|
1397
|
+
current = Object.getPrototypeOf(current);
|
|
1398
|
+
}
|
|
1399
|
+
const merged = /* @__PURE__ */ new Map();
|
|
1400
|
+
for (let i = chain.length - 1; i >= 0; i--) {
|
|
1401
|
+
const own = ownEventMetadata(chain[i]);
|
|
1402
|
+
if (!own) continue;
|
|
1403
|
+
own.forEach((eventType, property) => {
|
|
1404
|
+
if (!merged.has(property)) merged.set(property, eventType);
|
|
1405
|
+
});
|
|
1406
|
+
}
|
|
1407
|
+
return merged;
|
|
1408
|
+
}
|
|
1409
|
+
function ensureEventStateSubscription(target) {
|
|
1410
|
+
if (subscribedInstances.has(target)) return;
|
|
1411
|
+
subscribedInstances.add(target);
|
|
1412
|
+
target.changed.subscribe((evt) => {
|
|
1413
|
+
const meta = getEventMetadata(Object.getPrototypeOf(target));
|
|
1414
|
+
if (!meta.has(evt.property)) return;
|
|
1415
|
+
const state = getOrCreateEventState(target);
|
|
1416
|
+
let entry = state.get(evt.property);
|
|
1417
|
+
if (!entry) {
|
|
1418
|
+
entry = { originalValue: evt.oldValue, currentValue: evt.newValue };
|
|
1419
|
+
state.set(evt.property, entry);
|
|
1420
|
+
} else {
|
|
1421
|
+
entry.currentValue = evt.newValue;
|
|
1422
|
+
}
|
|
1423
|
+
if (entry.currentValue === entry.originalValue) {
|
|
1424
|
+
state.delete(evt.property);
|
|
1425
|
+
}
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1428
|
+
function getOrCreateEventState(target) {
|
|
1429
|
+
let state = instanceState.get(target);
|
|
1430
|
+
if (!state) {
|
|
1431
|
+
state = /* @__PURE__ */ new Map();
|
|
1432
|
+
instanceState.set(target, state);
|
|
1433
|
+
}
|
|
1434
|
+
return state;
|
|
1435
|
+
}
|
|
1436
|
+
function getEventState(target) {
|
|
1437
|
+
return instanceState.get(target) ?? /* @__PURE__ */ new Map();
|
|
1438
|
+
}
|
|
1439
|
+
function clearEventState(target) {
|
|
1440
|
+
instanceState.delete(target);
|
|
1441
|
+
}
|
|
1442
|
+
function recordItemOrigin(item, collection) {
|
|
1443
|
+
itemOriginCollection.set(item, collection);
|
|
1444
|
+
}
|
|
1445
|
+
function getItemOrigin(item) {
|
|
1446
|
+
return itemOriginCollection.get(item);
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
// src/EventTracker.ts
|
|
1450
|
+
var EventTracker = class extends Tracker {
|
|
1451
|
+
onCommit(keys) {
|
|
1452
|
+
super.onCommit(keys);
|
|
1453
|
+
for (const obj of this.trackedObjects) {
|
|
1454
|
+
clearEventState(obj);
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
generateEvents() {
|
|
1458
|
+
const events = [];
|
|
1459
|
+
for (const obj of this.trackedObjects) {
|
|
1460
|
+
const meta = getEventMetadata(Object.getPrototypeOf(obj));
|
|
1461
|
+
const origin = getItemOrigin(obj);
|
|
1462
|
+
const lifecycle = origin?._lifecycleOptions;
|
|
1463
|
+
switch (obj.state) {
|
|
1464
|
+
case "Insert" /* Insert */:
|
|
1465
|
+
if (lifecycle?.itemAdded) {
|
|
1466
|
+
events.push(buildItemAddedEvent(obj, meta, lifecycle.itemAdded));
|
|
1467
|
+
}
|
|
1468
|
+
break;
|
|
1469
|
+
case "Deleted" /* Deleted */:
|
|
1470
|
+
if (lifecycle?.itemRemoved) {
|
|
1471
|
+
events.push(buildItemRemovedEvent(obj, lifecycle.itemRemoved));
|
|
1472
|
+
}
|
|
1473
|
+
break;
|
|
1474
|
+
case "Changed" /* Changed */:
|
|
1475
|
+
pushFieldClusterEvents(obj, meta, events);
|
|
1476
|
+
break;
|
|
1477
|
+
case "Unchanged" /* Unchanged */:
|
|
1478
|
+
default:
|
|
1479
|
+
break;
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
return events;
|
|
1483
|
+
}
|
|
1484
|
+
};
|
|
1485
|
+
function buildItemAddedEvent(obj, meta, eventType) {
|
|
1486
|
+
const payload = {};
|
|
1487
|
+
for (const [propertyName] of meta) {
|
|
1488
|
+
const value = obj[propertyName];
|
|
1489
|
+
payload[propertyName] = normalizeValue(value);
|
|
1490
|
+
}
|
|
1491
|
+
return {
|
|
1492
|
+
eventType,
|
|
1493
|
+
payload,
|
|
1494
|
+
trackingId: obj.trackingId
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1497
|
+
function buildItemRemovedEvent(obj, eventType) {
|
|
1498
|
+
const autoIdProp = getAutoIdProperty(Object.getPrototypeOf(obj));
|
|
1499
|
+
const targetId = autoIdProp ? obj[autoIdProp] : void 0;
|
|
1500
|
+
const event = {
|
|
1501
|
+
eventType,
|
|
1502
|
+
payload: {}
|
|
1503
|
+
};
|
|
1504
|
+
if (typeof targetId === "number") {
|
|
1505
|
+
event.targetId = targetId;
|
|
1506
|
+
}
|
|
1507
|
+
return event;
|
|
1508
|
+
}
|
|
1509
|
+
function pushFieldClusterEvents(obj, meta, events) {
|
|
1510
|
+
const state = getEventState(obj);
|
|
1511
|
+
if (state.size === 0) return;
|
|
1512
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
1513
|
+
for (const [propertyName, eventType] of meta) {
|
|
1514
|
+
if (!state.has(propertyName)) continue;
|
|
1515
|
+
let bucket = grouped.get(eventType);
|
|
1516
|
+
if (!bucket) {
|
|
1517
|
+
bucket = [];
|
|
1518
|
+
grouped.set(eventType, bucket);
|
|
1519
|
+
}
|
|
1520
|
+
bucket.push(propertyName);
|
|
1521
|
+
}
|
|
1522
|
+
const autoIdProp = getAutoIdProperty(Object.getPrototypeOf(obj));
|
|
1523
|
+
const targetIdRaw = autoIdProp ? obj[autoIdProp] : void 0;
|
|
1524
|
+
for (const [eventType, propertyNames] of grouped) {
|
|
1525
|
+
const payload = {};
|
|
1526
|
+
for (const propertyName of propertyNames) {
|
|
1527
|
+
payload[propertyName] = normalizeValue(state.get(propertyName).currentValue);
|
|
1528
|
+
}
|
|
1529
|
+
const event = {
|
|
1530
|
+
eventType,
|
|
1531
|
+
payload,
|
|
1532
|
+
trackingId: obj.trackingId
|
|
1533
|
+
};
|
|
1534
|
+
if (typeof targetIdRaw === "number") {
|
|
1535
|
+
event.targetId = targetIdRaw;
|
|
1536
|
+
}
|
|
1537
|
+
events.push(event);
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
function normalizeValue(value) {
|
|
1541
|
+
return value === void 0 ? null : value;
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
// src/EventTracked.ts
|
|
1545
|
+
function EventTracked(eventType, validator, onChange, options) {
|
|
1546
|
+
const trackedDecorator = Tracked(validator, onChange, options);
|
|
1547
|
+
function decorator(target, context) {
|
|
1548
|
+
const result = trackedDecorator(target, context);
|
|
1549
|
+
const propertyName = String(context.name);
|
|
1550
|
+
context.addInitializer(function() {
|
|
1551
|
+
registerEventProperty(
|
|
1552
|
+
Object.getPrototypeOf(this),
|
|
1553
|
+
propertyName,
|
|
1554
|
+
eventType
|
|
1555
|
+
);
|
|
1556
|
+
ensureEventStateSubscription(this);
|
|
1557
|
+
});
|
|
1558
|
+
return result;
|
|
1559
|
+
}
|
|
1560
|
+
return decorator;
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
// src/EventTrackedCollection.ts
|
|
1564
|
+
var EventTrackedCollection = class extends TrackedCollection {
|
|
1565
|
+
constructor(tracker, items, validator, eventOptions) {
|
|
1566
|
+
super(tracker, items, validator);
|
|
1567
|
+
this._eventOptions = eventOptions;
|
|
1568
|
+
for (const item of this.collection) {
|
|
1569
|
+
if (item instanceof TrackedObject) {
|
|
1570
|
+
recordItemOrigin(item, this);
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
this.changed.subscribe((evt) => {
|
|
1574
|
+
for (const item of evt.added) {
|
|
1575
|
+
if (item instanceof TrackedObject) {
|
|
1576
|
+
recordItemOrigin(item, this);
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
});
|
|
1580
|
+
}
|
|
1581
|
+
/** @internal */
|
|
1582
|
+
get _lifecycleOptions() {
|
|
1583
|
+
return this._eventOptions;
|
|
1584
|
+
}
|
|
1585
|
+
};
|
|
1337
1586
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1338
1587
|
0 && (module.exports = {
|
|
1339
1588
|
AutoId,
|
|
1589
|
+
EventTracked,
|
|
1590
|
+
EventTrackedCollection,
|
|
1591
|
+
EventTracker,
|
|
1340
1592
|
State,
|
|
1341
1593
|
Tracked,
|
|
1342
1594
|
TrackedCollection,
|