@mmstack/primitives 21.8.2 → 21.8.4
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.
|
@@ -1985,6 +1985,29 @@ function indexArray(source, map, opt = {}) {
|
|
|
1985
1985
|
*/
|
|
1986
1986
|
const mapArray = indexArray;
|
|
1987
1987
|
|
|
1988
|
+
function effectiveKeys(arr, getKey, report) {
|
|
1989
|
+
const out = new Array(arr.length);
|
|
1990
|
+
const counts = new Map();
|
|
1991
|
+
const firstOrder = [];
|
|
1992
|
+
let duped = null;
|
|
1993
|
+
for (let i = 0; i < arr.length; i++) {
|
|
1994
|
+
const base = String(getKey(arr[i]));
|
|
1995
|
+
const seen = counts.get(base) ?? 0;
|
|
1996
|
+
if (seen === 0) {
|
|
1997
|
+
firstOrder.push(base);
|
|
1998
|
+
}
|
|
1999
|
+
else {
|
|
2000
|
+
(duped ??= new Set()).add(base);
|
|
2001
|
+
}
|
|
2002
|
+
out[i] = seen === 0 ? base : base + '#' + seen;
|
|
2003
|
+
counts.set(base, seen + 1);
|
|
2004
|
+
}
|
|
2005
|
+
if (report && duped) {
|
|
2006
|
+
const bases = firstOrder.filter((b) => duped.has(b));
|
|
2007
|
+
untracked(() => report(bases));
|
|
2008
|
+
}
|
|
2009
|
+
return out;
|
|
2010
|
+
}
|
|
1988
2011
|
/**
|
|
1989
2012
|
* Reactively maps items from a source array to a new array by value (identity).
|
|
1990
2013
|
*
|
|
@@ -1998,11 +2021,15 @@ const mapArray = indexArray;
|
|
|
1998
2021
|
* when the list is reordered.
|
|
1999
2022
|
*
|
|
2000
2023
|
* @param source A `Signal<T[]>` or a function returning `T[]`.
|
|
2001
|
-
* @param mapFn The mapping function. Receives the item
|
|
2024
|
+
* @param mapFn The mapping function. Receives the item, its index as a Signal, and the
|
|
2025
|
+
* entry's key (the effective ordinal key when `duplicateKeys` is enabled, otherwise
|
|
2026
|
+
* the raw key) — stable for the lifetime of the mapped entry.
|
|
2002
2027
|
* @param options Optional configuration:
|
|
2003
2028
|
* - `onDestroy`: A callback invoked when a mapped item is removed from the array.
|
|
2004
2029
|
* - `key`: A custom key extractor for identity matching (e.g. `(item) => item.id`)
|
|
2005
2030
|
* when item references change but conceptual identity is preserved.
|
|
2031
|
+
* - `duplicateKeys`: Opt-in policy for handling duplicate keys. When omitted,
|
|
2032
|
+
* behavior is unchanged (duplicates collapse). See {@link DuplicateKeyPolicy}.
|
|
2006
2033
|
* @returns A `Signal<U[]>` containing the mapped array.
|
|
2007
2034
|
*
|
|
2008
2035
|
* @example
|
|
@@ -2037,9 +2064,11 @@ function keyArray(source, mapFn, options = {}) {
|
|
|
2037
2064
|
const tempIndexes = [];
|
|
2038
2065
|
const newIndicesNext = [];
|
|
2039
2066
|
const newIndexesCache = new Array();
|
|
2067
|
+
const dup = options.duplicateKeys;
|
|
2040
2068
|
return computed(() => {
|
|
2041
2069
|
const newItems = sourceSignal() || [];
|
|
2042
2070
|
return untracked(() => {
|
|
2071
|
+
const newKeys = dup ? effectiveKeys(newItems, getKey, dup.report) : null;
|
|
2043
2072
|
let i;
|
|
2044
2073
|
let j;
|
|
2045
2074
|
const newLen = newItems.length;
|
|
@@ -2071,7 +2100,7 @@ function keyArray(source, mapFn, options = {}) {
|
|
|
2071
2100
|
items[j] = item;
|
|
2072
2101
|
const indexSignal = signal(j, ...(ngDevMode ? [{ debugName: "indexSignal" }] : /* istanbul ignore next */ []));
|
|
2073
2102
|
newIndexes[j] = indexSignal;
|
|
2074
|
-
newMapped[j] = mapFn(item, indexSignal);
|
|
2103
|
+
newMapped[j] = mapFn(item, indexSignal, newKeys ? newKeys[j] : getKey(item));
|
|
2075
2104
|
}
|
|
2076
2105
|
}
|
|
2077
2106
|
else {
|
|
@@ -2079,26 +2108,29 @@ function keyArray(source, mapFn, options = {}) {
|
|
|
2079
2108
|
temp.length = 0;
|
|
2080
2109
|
tempIndexes.length = 0;
|
|
2081
2110
|
newIndicesNext.length = 0;
|
|
2082
|
-
|
|
2111
|
+
const oldKeys = dup ? effectiveKeys(items, getKey) : null;
|
|
2112
|
+
const kNew = newKeys
|
|
2113
|
+
? (idx) => newKeys[idx]
|
|
2114
|
+
: (idx) => getKey(newItems[idx]);
|
|
2115
|
+
const kOld = oldKeys
|
|
2116
|
+
? (idx) => oldKeys[idx]
|
|
2117
|
+
: (idx) => getKey(items[idx]);
|
|
2118
|
+
for (start = 0, end = Math.min(len, newLen); start < end && kOld(start) === kNew(start); start++) {
|
|
2083
2119
|
newMapped[start] = mapped[start];
|
|
2084
2120
|
newIndexes[start] = indexes[start];
|
|
2085
2121
|
}
|
|
2086
|
-
for (end = len - 1, newEnd = newLen - 1; end >= start &&
|
|
2087
|
-
newEnd >= start &&
|
|
2088
|
-
getKey(items[end]) === getKey(newItems[newEnd]); end--, newEnd--) {
|
|
2122
|
+
for (end = len - 1, newEnd = newLen - 1; end >= start && newEnd >= start && kOld(end) === kNew(newEnd); end--, newEnd--) {
|
|
2089
2123
|
temp[newEnd] = mapped[end];
|
|
2090
2124
|
tempIndexes[newEnd] = indexes[end];
|
|
2091
2125
|
}
|
|
2092
2126
|
for (j = newEnd; j >= start; j--) {
|
|
2093
|
-
|
|
2094
|
-
key = getKey(item);
|
|
2127
|
+
key = kNew(j);
|
|
2095
2128
|
i = newIndices.get(key) ?? -1;
|
|
2096
2129
|
newIndicesNext[j] = i === undefined ? -1 : i;
|
|
2097
2130
|
newIndices.set(key, j);
|
|
2098
2131
|
}
|
|
2099
2132
|
for (i = start; i <= end; i++) {
|
|
2100
|
-
|
|
2101
|
-
key = getKey(item);
|
|
2133
|
+
key = kOld(i);
|
|
2102
2134
|
j = newIndices.get(key) ?? -1;
|
|
2103
2135
|
if (j !== undefined && j !== -1) {
|
|
2104
2136
|
temp[j] = mapped[i];
|
|
@@ -2121,7 +2153,7 @@ function keyArray(source, mapFn, options = {}) {
|
|
|
2121
2153
|
else {
|
|
2122
2154
|
const indexSignal = signal(j, ...(ngDevMode ? [{ debugName: "indexSignal" }] : /* istanbul ignore next */ []));
|
|
2123
2155
|
newIndexes[j] = indexSignal;
|
|
2124
|
-
newMapped[j] = mapFn(newItems[j], indexSignal);
|
|
2156
|
+
newMapped[j] = mapFn(newItems[j], indexSignal, kNew(j));
|
|
2125
2157
|
}
|
|
2126
2158
|
}
|
|
2127
2159
|
items.length = newLen;
|