@prometheus-ags/entity-graph-core 3.0.1 → 3.0.3
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/CHANGELOG.md +8 -0
- package/dist/index.cjs +245 -134
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +159 -92
- package/dist/index.d.ts +159 -92
- package/dist/index.mjs +245 -134
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -426,6 +426,135 @@ function hasMergeStrategy(type) {
|
|
|
426
426
|
return byType.has(type) || globalDefault !== null;
|
|
427
427
|
}
|
|
428
428
|
|
|
429
|
+
// src/view/evaluator.ts
|
|
430
|
+
function matchesFilter(entity, filter) {
|
|
431
|
+
if (Array.isArray(filter)) return filter.every((clause) => matchesClause(entity, clause));
|
|
432
|
+
return matchesGroup(entity, filter);
|
|
433
|
+
}
|
|
434
|
+
function matchesGroup(entity, group) {
|
|
435
|
+
const { logic, clauses } = group;
|
|
436
|
+
if (logic === "and") return clauses.every((c) => "logic" in c ? matchesGroup(entity, c) : matchesClause(entity, c));
|
|
437
|
+
return clauses.some((c) => "logic" in c ? matchesGroup(entity, c) : matchesClause(entity, c));
|
|
438
|
+
}
|
|
439
|
+
function matchesClause(entity, clause) {
|
|
440
|
+
const { field, op, value, predicate } = clause;
|
|
441
|
+
const fv = getNestedValue(entity, field);
|
|
442
|
+
switch (op) {
|
|
443
|
+
case "eq":
|
|
444
|
+
return fv === value;
|
|
445
|
+
case "neq":
|
|
446
|
+
return fv !== value;
|
|
447
|
+
case "gt":
|
|
448
|
+
return fv > value;
|
|
449
|
+
case "gte":
|
|
450
|
+
return fv >= value;
|
|
451
|
+
case "lt":
|
|
452
|
+
return fv < value;
|
|
453
|
+
case "lte":
|
|
454
|
+
return fv <= value;
|
|
455
|
+
case "in":
|
|
456
|
+
return Array.isArray(value) && value.includes(fv);
|
|
457
|
+
case "nin":
|
|
458
|
+
return Array.isArray(value) && !value.includes(fv);
|
|
459
|
+
case "isNull":
|
|
460
|
+
return fv == null;
|
|
461
|
+
case "isNotNull":
|
|
462
|
+
return fv != null;
|
|
463
|
+
case "contains":
|
|
464
|
+
return typeof fv === "string" && typeof value === "string" && fv.toLowerCase().includes(value.toLowerCase());
|
|
465
|
+
case "startsWith":
|
|
466
|
+
return typeof fv === "string" && typeof value === "string" && fv.toLowerCase().startsWith(value.toLowerCase());
|
|
467
|
+
case "endsWith":
|
|
468
|
+
return typeof fv === "string" && typeof value === "string" && fv.toLowerCase().endsWith(value.toLowerCase());
|
|
469
|
+
case "between": {
|
|
470
|
+
const [lo, hi] = value;
|
|
471
|
+
return fv >= lo && fv <= hi;
|
|
472
|
+
}
|
|
473
|
+
case "arrayContains":
|
|
474
|
+
return Array.isArray(fv) && fv.includes(value);
|
|
475
|
+
case "arrayOverlaps":
|
|
476
|
+
return Array.isArray(fv) && Array.isArray(value) && value.some((v) => fv.includes(v));
|
|
477
|
+
case "matches":
|
|
478
|
+
return typeof fv === "string" && new RegExp(value).test(fv);
|
|
479
|
+
case "custom":
|
|
480
|
+
return predicate ? predicate(fv, entity) : true;
|
|
481
|
+
default:
|
|
482
|
+
return true;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
function matchesSearch(entity, query, fields) {
|
|
486
|
+
if (!query.trim()) return true;
|
|
487
|
+
const lq = query.toLowerCase();
|
|
488
|
+
return fields.some((field) => {
|
|
489
|
+
const v = getNestedValue(entity, field);
|
|
490
|
+
return typeof v === "string" && v.toLowerCase().includes(lq);
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
function compareEntities(a, b, sort) {
|
|
494
|
+
for (const clause of sort) {
|
|
495
|
+
const r = compareByClause(a, b, clause);
|
|
496
|
+
if (r !== 0) return r;
|
|
497
|
+
}
|
|
498
|
+
return 0;
|
|
499
|
+
}
|
|
500
|
+
function compareByClause(a, b, clause) {
|
|
501
|
+
const { field, direction, nulls = "last", comparator } = clause;
|
|
502
|
+
const av = getNestedValue(a, field);
|
|
503
|
+
const bv = getNestedValue(b, field);
|
|
504
|
+
const aNull = av == null;
|
|
505
|
+
const bNull = bv == null;
|
|
506
|
+
if (aNull && bNull) return 0;
|
|
507
|
+
if (aNull) return nulls === "first" ? -1 : 1;
|
|
508
|
+
if (bNull) return nulls === "first" ? 1 : -1;
|
|
509
|
+
let cmp;
|
|
510
|
+
if (comparator) cmp = comparator(av, bv);
|
|
511
|
+
else if (typeof av === "string" && typeof bv === "string") cmp = av.localeCompare(bv, void 0, { sensitivity: "base", numeric: true });
|
|
512
|
+
else if (typeof av === "number" && typeof bv === "number") cmp = av - bv;
|
|
513
|
+
else cmp = String(av).localeCompare(String(bv));
|
|
514
|
+
return direction === "desc" ? -cmp : cmp;
|
|
515
|
+
}
|
|
516
|
+
function findInsertionIndex(entity, sortedIds, getEntity, sort) {
|
|
517
|
+
let lo = 0;
|
|
518
|
+
let hi = sortedIds.length;
|
|
519
|
+
while (lo < hi) {
|
|
520
|
+
const mid = lo + hi >>> 1;
|
|
521
|
+
const me = getEntity(sortedIds[mid]);
|
|
522
|
+
if (!me) {
|
|
523
|
+
lo = mid + 1;
|
|
524
|
+
continue;
|
|
525
|
+
}
|
|
526
|
+
if (compareEntities(entity, me, sort) <= 0) hi = mid;
|
|
527
|
+
else lo = mid + 1;
|
|
528
|
+
}
|
|
529
|
+
return lo;
|
|
530
|
+
}
|
|
531
|
+
function applyView(ids, getEntity, filter, sort, search) {
|
|
532
|
+
let entries = [];
|
|
533
|
+
for (const id of ids) {
|
|
534
|
+
const entity = getEntity(id);
|
|
535
|
+
if (!entity) continue;
|
|
536
|
+
entries.push({ id, entity });
|
|
537
|
+
}
|
|
538
|
+
if (filter && entries.length > 0) entries = entries.filter(({ entity }) => matchesFilter(entity, filter));
|
|
539
|
+
if (search?.query) entries = entries.filter(({ entity }) => matchesSearch(entity, search.query, search.fields));
|
|
540
|
+
if (sort && sort.length > 0) entries.sort((a, b) => compareEntities(a.entity, b.entity, sort));
|
|
541
|
+
return entries.map((e) => e.id);
|
|
542
|
+
}
|
|
543
|
+
function checkCompleteness(loadedCount, total, hasNextPage) {
|
|
544
|
+
if (!hasNextPage && total !== null && loadedCount >= total) return { isComplete: true, reason: "all-loaded" };
|
|
545
|
+
if (hasNextPage) return { isComplete: false, reason: "has-more-pages" };
|
|
546
|
+
return { isComplete: true, reason: "no-more-pages" };
|
|
547
|
+
}
|
|
548
|
+
function getNestedValue(obj, path) {
|
|
549
|
+
const parts = path.replace(/\[(\d+)\]/g, ".$1").split(".");
|
|
550
|
+
let current = obj;
|
|
551
|
+
for (const part of parts) {
|
|
552
|
+
if (current == null || typeof current !== "object") return void 0;
|
|
553
|
+
current = current[part];
|
|
554
|
+
}
|
|
555
|
+
return current;
|
|
556
|
+
}
|
|
557
|
+
|
|
429
558
|
// src/graph.ts
|
|
430
559
|
var EMPTY_IDS = [];
|
|
431
560
|
var EMPTY_ENTITY_STATE = {
|
|
@@ -510,6 +639,117 @@ function createGraphStore() {
|
|
|
510
639
|
if (!s.syncMetadata[key]) s.syncMetadata[key] = defaultSyncMetadata();
|
|
511
640
|
}
|
|
512
641
|
}),
|
|
642
|
+
ingestFetchedList: (type, entries, options = {}) => set((s) => {
|
|
643
|
+
const fetchedAt = Date.now();
|
|
644
|
+
const ids = entries.map(({ id }) => id);
|
|
645
|
+
const batches = [
|
|
646
|
+
{ type, entries },
|
|
647
|
+
...options.sideBatches ?? []
|
|
648
|
+
];
|
|
649
|
+
const origins = /* @__PURE__ */ new Map();
|
|
650
|
+
for (const batch of batches) {
|
|
651
|
+
if (!s.entities[batch.type]) s.entities[batch.type] = {};
|
|
652
|
+
for (const { id } of batch.entries) {
|
|
653
|
+
const key = ek(batch.type, id);
|
|
654
|
+
if (!origins.has(key)) {
|
|
655
|
+
origins.set(key, s.syncMetadata[key]?.origin ?? "server");
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
for (const batch of batches) {
|
|
660
|
+
const strategy = getMergeStrategy(batch.type);
|
|
661
|
+
for (const { id, data } of batch.entries) {
|
|
662
|
+
const key = ek(batch.type, id);
|
|
663
|
+
const ctx = {
|
|
664
|
+
type: batch.type,
|
|
665
|
+
id,
|
|
666
|
+
origin: origins.get(key) ?? "server",
|
|
667
|
+
updatedAt: fetchedAt
|
|
668
|
+
};
|
|
669
|
+
s.entities[batch.type][id] = strategy(s.entities[batch.type][id], data, ctx);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
const completed = /* @__PURE__ */ new Set();
|
|
673
|
+
for (const batch of batches) {
|
|
674
|
+
for (const { id } of batch.entries) {
|
|
675
|
+
const key = ek(batch.type, id);
|
|
676
|
+
if (completed.has(key)) continue;
|
|
677
|
+
completed.add(key);
|
|
678
|
+
if (!s.entityStates[key]) s.entityStates[key] = defaultEntityState();
|
|
679
|
+
s.entityStates[key].lastFetched = fetchedAt;
|
|
680
|
+
s.entityStates[key].isFetching = false;
|
|
681
|
+
s.entityStates[key].error = null;
|
|
682
|
+
s.entityStates[key].stale = false;
|
|
683
|
+
s.syncMetadata[key] = {
|
|
684
|
+
...s.syncMetadata[key] ?? defaultSyncMetadata(),
|
|
685
|
+
synced: true,
|
|
686
|
+
origin: "server",
|
|
687
|
+
updatedAt: fetchedAt
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
const readDraftEntity = (id) => {
|
|
692
|
+
const base = s.entities[type]?.[id];
|
|
693
|
+
if (!base) return null;
|
|
694
|
+
const patch = s.patches[type]?.[id];
|
|
695
|
+
const metadata = s.syncMetadata[ek(type, id)] ?? defaultSyncMetadata();
|
|
696
|
+
return {
|
|
697
|
+
...base,
|
|
698
|
+
...patch ?? {},
|
|
699
|
+
$synced: metadata.synced,
|
|
700
|
+
$origin: metadata.origin,
|
|
701
|
+
$updatedAt: metadata.updatedAt
|
|
702
|
+
};
|
|
703
|
+
};
|
|
704
|
+
for (const target of options.lists ?? []) {
|
|
705
|
+
const existing = s.lists[target.key] ?? defaultListState();
|
|
706
|
+
const targetIds = target.ids ?? ids;
|
|
707
|
+
const nextIds = target.mode === "append" ? Array.from(/* @__PURE__ */ new Set([...existing.ids, ...targetIds])) : targetIds;
|
|
708
|
+
s.lists[target.key] = {
|
|
709
|
+
...existing,
|
|
710
|
+
...target.meta ?? {},
|
|
711
|
+
ids: nextIds,
|
|
712
|
+
isFetching: false,
|
|
713
|
+
isFetchingMore: false,
|
|
714
|
+
error: null,
|
|
715
|
+
lastError: null,
|
|
716
|
+
stale: false,
|
|
717
|
+
lastFetched: fetchedAt
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
for (const projection of options.projections ?? []) {
|
|
721
|
+
const existing = s.lists[projection.key] ?? defaultListState();
|
|
722
|
+
const nextIds = [...existing.ids];
|
|
723
|
+
const { filter, sort, search } = projection.view;
|
|
724
|
+
for (const id of new Set(ids)) {
|
|
725
|
+
if (nextIds.includes(id)) continue;
|
|
726
|
+
const entity = readDraftEntity(id);
|
|
727
|
+
if (!entity) continue;
|
|
728
|
+
const matches = (!filter || matchesFilter(entity, filter)) && (!search?.query || matchesSearch(entity, search.query, search.fields));
|
|
729
|
+
if (!matches) continue;
|
|
730
|
+
if (sort && sort.length > 0) {
|
|
731
|
+
const index = findInsertionIndex(entity, nextIds, readDraftEntity, sort);
|
|
732
|
+
nextIds.splice(index, 0, id);
|
|
733
|
+
} else {
|
|
734
|
+
nextIds.unshift(id);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
s.lists[projection.key] = projection.completeFetch ? {
|
|
738
|
+
...existing,
|
|
739
|
+
ids: nextIds,
|
|
740
|
+
isFetching: false,
|
|
741
|
+
isFetchingMore: false,
|
|
742
|
+
error: null,
|
|
743
|
+
lastError: null,
|
|
744
|
+
stale: false,
|
|
745
|
+
lastFetched: fetchedAt
|
|
746
|
+
} : { ...existing, ids: nextIds };
|
|
747
|
+
}
|
|
748
|
+
for (const key of options.finishListFetches ?? []) {
|
|
749
|
+
if (!s.lists[key]) s.lists[key] = defaultListState();
|
|
750
|
+
s.lists[key].isFetching = false;
|
|
751
|
+
}
|
|
752
|
+
}),
|
|
513
753
|
replaceEntity: (type, id, data) => set((s) => {
|
|
514
754
|
if (!s.entities[type]) s.entities[type] = {};
|
|
515
755
|
s.entities[type][id] = data;
|
|
@@ -1004,12 +1244,12 @@ async function fetchList(opts, params, engineOpts, isLoadMore = false, storeApi
|
|
|
1004
1244
|
try {
|
|
1005
1245
|
const response = await fetch(params);
|
|
1006
1246
|
const normalized = response.items.map(normalize);
|
|
1007
|
-
storeApi.getState().upsertEntities(type, normalized.map(({ id, data }) => ({ id, data })));
|
|
1008
|
-
for (const { id } of normalized) storeApi.getState().setEntityFetched(type, id);
|
|
1009
|
-
const ids = normalized.map(({ id }) => id);
|
|
1010
1247
|
const meta = { total: response.total ?? null, nextCursor: response.nextCursor ?? null, prevCursor: response.prevCursor ?? null, hasNextPage: response.hasNextPage ?? !!response.nextCursor, hasPrevPage: response.hasPrevPage ?? !!response.prevCursor, currentPage: response.page ?? null, pageSize: response.pageSize ?? null };
|
|
1011
|
-
|
|
1012
|
-
|
|
1248
|
+
storeApi.getState().ingestFetchedList(
|
|
1249
|
+
type,
|
|
1250
|
+
normalized.map(({ id, data }) => ({ id, data })),
|
|
1251
|
+
{ lists: [{ key, mode: mode === "append" && isLoadMore ? "append" : "replace", meta }] }
|
|
1252
|
+
);
|
|
1013
1253
|
if (sideEffects) sideEffects(response.items, storeApi);
|
|
1014
1254
|
opts.onSuccess?.(response);
|
|
1015
1255
|
} catch (err) {
|
|
@@ -1870,135 +2110,6 @@ function subscribeTimeTravel(cb) {
|
|
|
1870
2110
|
return () => listeners.delete(cb);
|
|
1871
2111
|
}
|
|
1872
2112
|
|
|
1873
|
-
// src/view/evaluator.ts
|
|
1874
|
-
function matchesFilter(entity, filter) {
|
|
1875
|
-
if (Array.isArray(filter)) return filter.every((clause) => matchesClause(entity, clause));
|
|
1876
|
-
return matchesGroup(entity, filter);
|
|
1877
|
-
}
|
|
1878
|
-
function matchesGroup(entity, group) {
|
|
1879
|
-
const { logic, clauses } = group;
|
|
1880
|
-
if (logic === "and") return clauses.every((c) => "logic" in c ? matchesGroup(entity, c) : matchesClause(entity, c));
|
|
1881
|
-
return clauses.some((c) => "logic" in c ? matchesGroup(entity, c) : matchesClause(entity, c));
|
|
1882
|
-
}
|
|
1883
|
-
function matchesClause(entity, clause) {
|
|
1884
|
-
const { field, op, value, predicate } = clause;
|
|
1885
|
-
const fv = getNestedValue(entity, field);
|
|
1886
|
-
switch (op) {
|
|
1887
|
-
case "eq":
|
|
1888
|
-
return fv === value;
|
|
1889
|
-
case "neq":
|
|
1890
|
-
return fv !== value;
|
|
1891
|
-
case "gt":
|
|
1892
|
-
return fv > value;
|
|
1893
|
-
case "gte":
|
|
1894
|
-
return fv >= value;
|
|
1895
|
-
case "lt":
|
|
1896
|
-
return fv < value;
|
|
1897
|
-
case "lte":
|
|
1898
|
-
return fv <= value;
|
|
1899
|
-
case "in":
|
|
1900
|
-
return Array.isArray(value) && value.includes(fv);
|
|
1901
|
-
case "nin":
|
|
1902
|
-
return Array.isArray(value) && !value.includes(fv);
|
|
1903
|
-
case "isNull":
|
|
1904
|
-
return fv == null;
|
|
1905
|
-
case "isNotNull":
|
|
1906
|
-
return fv != null;
|
|
1907
|
-
case "contains":
|
|
1908
|
-
return typeof fv === "string" && typeof value === "string" && fv.toLowerCase().includes(value.toLowerCase());
|
|
1909
|
-
case "startsWith":
|
|
1910
|
-
return typeof fv === "string" && typeof value === "string" && fv.toLowerCase().startsWith(value.toLowerCase());
|
|
1911
|
-
case "endsWith":
|
|
1912
|
-
return typeof fv === "string" && typeof value === "string" && fv.toLowerCase().endsWith(value.toLowerCase());
|
|
1913
|
-
case "between": {
|
|
1914
|
-
const [lo, hi] = value;
|
|
1915
|
-
return fv >= lo && fv <= hi;
|
|
1916
|
-
}
|
|
1917
|
-
case "arrayContains":
|
|
1918
|
-
return Array.isArray(fv) && fv.includes(value);
|
|
1919
|
-
case "arrayOverlaps":
|
|
1920
|
-
return Array.isArray(fv) && Array.isArray(value) && value.some((v) => fv.includes(v));
|
|
1921
|
-
case "matches":
|
|
1922
|
-
return typeof fv === "string" && new RegExp(value).test(fv);
|
|
1923
|
-
case "custom":
|
|
1924
|
-
return predicate ? predicate(fv, entity) : true;
|
|
1925
|
-
default:
|
|
1926
|
-
return true;
|
|
1927
|
-
}
|
|
1928
|
-
}
|
|
1929
|
-
function matchesSearch(entity, query, fields) {
|
|
1930
|
-
if (!query.trim()) return true;
|
|
1931
|
-
const lq = query.toLowerCase();
|
|
1932
|
-
return fields.some((field) => {
|
|
1933
|
-
const v = getNestedValue(entity, field);
|
|
1934
|
-
return typeof v === "string" && v.toLowerCase().includes(lq);
|
|
1935
|
-
});
|
|
1936
|
-
}
|
|
1937
|
-
function compareEntities(a, b, sort) {
|
|
1938
|
-
for (const clause of sort) {
|
|
1939
|
-
const r = compareByClause(a, b, clause);
|
|
1940
|
-
if (r !== 0) return r;
|
|
1941
|
-
}
|
|
1942
|
-
return 0;
|
|
1943
|
-
}
|
|
1944
|
-
function compareByClause(a, b, clause) {
|
|
1945
|
-
const { field, direction, nulls = "last", comparator } = clause;
|
|
1946
|
-
const av = getNestedValue(a, field);
|
|
1947
|
-
const bv = getNestedValue(b, field);
|
|
1948
|
-
const aNull = av == null;
|
|
1949
|
-
const bNull = bv == null;
|
|
1950
|
-
if (aNull && bNull) return 0;
|
|
1951
|
-
if (aNull) return nulls === "first" ? -1 : 1;
|
|
1952
|
-
if (bNull) return nulls === "first" ? 1 : -1;
|
|
1953
|
-
let cmp;
|
|
1954
|
-
if (comparator) cmp = comparator(av, bv);
|
|
1955
|
-
else if (typeof av === "string" && typeof bv === "string") cmp = av.localeCompare(bv, void 0, { sensitivity: "base", numeric: true });
|
|
1956
|
-
else if (typeof av === "number" && typeof bv === "number") cmp = av - bv;
|
|
1957
|
-
else cmp = String(av).localeCompare(String(bv));
|
|
1958
|
-
return direction === "desc" ? -cmp : cmp;
|
|
1959
|
-
}
|
|
1960
|
-
function findInsertionIndex(entity, sortedIds, getEntity, sort) {
|
|
1961
|
-
let lo = 0;
|
|
1962
|
-
let hi = sortedIds.length;
|
|
1963
|
-
while (lo < hi) {
|
|
1964
|
-
const mid = lo + hi >>> 1;
|
|
1965
|
-
const me = getEntity(sortedIds[mid]);
|
|
1966
|
-
if (!me) {
|
|
1967
|
-
lo = mid + 1;
|
|
1968
|
-
continue;
|
|
1969
|
-
}
|
|
1970
|
-
if (compareEntities(entity, me, sort) <= 0) hi = mid;
|
|
1971
|
-
else lo = mid + 1;
|
|
1972
|
-
}
|
|
1973
|
-
return lo;
|
|
1974
|
-
}
|
|
1975
|
-
function applyView(ids, getEntity, filter, sort, search) {
|
|
1976
|
-
let entries = [];
|
|
1977
|
-
for (const id of ids) {
|
|
1978
|
-
const entity = getEntity(id);
|
|
1979
|
-
if (!entity) continue;
|
|
1980
|
-
entries.push({ id, entity });
|
|
1981
|
-
}
|
|
1982
|
-
if (filter && entries.length > 0) entries = entries.filter(({ entity }) => matchesFilter(entity, filter));
|
|
1983
|
-
if (search?.query) entries = entries.filter(({ entity }) => matchesSearch(entity, search.query, search.fields));
|
|
1984
|
-
if (sort && sort.length > 0) entries.sort((a, b) => compareEntities(a.entity, b.entity, sort));
|
|
1985
|
-
return entries.map((e) => e.id);
|
|
1986
|
-
}
|
|
1987
|
-
function checkCompleteness(loadedCount, total, hasNextPage) {
|
|
1988
|
-
if (!hasNextPage && total !== null && loadedCount >= total) return { isComplete: true, reason: "all-loaded" };
|
|
1989
|
-
if (hasNextPage) return { isComplete: false, reason: "has-more-pages" };
|
|
1990
|
-
return { isComplete: true, reason: "no-more-pages" };
|
|
1991
|
-
}
|
|
1992
|
-
function getNestedValue(obj, path) {
|
|
1993
|
-
const parts = path.replace(/\[(\d+)\]/g, ".$1").split(".");
|
|
1994
|
-
let current = obj;
|
|
1995
|
-
for (const part of parts) {
|
|
1996
|
-
if (current == null || typeof current !== "object") return void 0;
|
|
1997
|
-
current = current[part];
|
|
1998
|
-
}
|
|
1999
|
-
return current;
|
|
2000
|
-
}
|
|
2001
|
-
|
|
2002
2113
|
// src/view/incremental.ts
|
|
2003
2114
|
var IncrementalView = class {
|
|
2004
2115
|
opts;
|