|
13 | 13 | * once instead, keyed by the map object itself: the draft hands out a fresh snapshot per update, so |
14 | 14 | * an index is built at most once per keystroke and shared by every field reading from it, then |
15 | 15 | * garbage-collected with the snapshot. |
| 16 | + * |
| 17 | + * An index is therefore only valid while the map it was built from is left alone. A caller reading |
| 18 | + * a map it also mutates — a draft’s live content rather than a snapshot of it — has to pass the |
| 19 | + * `live` option, or it would keep getting the key paths the map had the first time it was read. |
16 | 20 | */ |
17 | 21 |
|
18 | 22 | /** |
@@ -51,9 +55,16 @@ const getSortedKeys = (valueMap) => { |
51 | 55 | * the “first” field under a key path. |
52 | 56 | * @param {FlattenedEntryContent} valueMap Flattened entry content. |
53 | 57 | * @param {string} prefix Key path prefix, e.g. `authors.0.`. |
| 58 | + * @param {object} [options] Options. |
| 59 | + * @param {boolean} [options.live] Whether the value map may be mutated after this call, in which |
| 60 | + * case the key paths are scanned instead of being read from — and memoized in — the index. |
54 | 61 | * @returns {FieldKeyPath[]} Matching key paths. |
55 | 62 | */ |
56 | | -export const getKeysByPrefix = (valueMap, prefix) => { |
| 63 | +export const getKeysByPrefix = (valueMap, prefix, { live = false } = {}) => { |
| 64 | + if (live) { |
| 65 | + return Object.keys(valueMap).filter((key) => key.startsWith(prefix)); |
| 66 | + } |
| 67 | + |
57 | 68 | const sorted = getSortedKeys(valueMap); |
58 | 69 | let low = 0; |
59 | 70 | let high = sorted.length; |
@@ -98,9 +109,18 @@ const listItemKeyCacheMap = new WeakMap(); |
98 | 109 | * multiple Relation or Select field — so the same index serves all of them. |
99 | 110 | * @param {FlattenedEntryContent} valueMap Flattened entry content. |
100 | 111 | * @param {FieldKeyPath} keyPath Key path of the list field. |
| 112 | + * @param {object} [options] Options. |
| 113 | + * @param {boolean} [options.live] Whether the value map may be mutated after this call, in which |
| 114 | + * case the key paths are scanned instead of being read from — and memoized in — the index. |
101 | 115 | * @returns {FieldKeyPath[]} Item key paths, e.g. `['authors.0', 'authors.1']`. |
102 | 116 | */ |
103 | | -export const getListItemKeys = (valueMap, keyPath) => { |
| 117 | +export const getListItemKeys = (valueMap, keyPath, { live = false } = {}) => { |
| 118 | + if (live) { |
| 119 | + return Object.keys(valueMap).filter( |
| 120 | + (key) => key.match(LIST_ITEM_KEY_REGEX)?.groups?.parent === keyPath, |
| 121 | + ); |
| 122 | + } |
| 123 | + |
104 | 124 | let index = listItemKeyCacheMap.get(valueMap); |
105 | 125 |
|
106 | 126 | if (!index) { |
|
0 commit comments