@weasel-js/prefs 1.9.3 → 1.10.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/dist/index.js CHANGED
@@ -1,378 +1,323 @@
1
- import { openRecords, openRecordsSync } from '@weasel-js/storage';
2
- import { unitScale, formatUnit } from '@weasel-js/quantity';
1
+ import { prefLeafHoldingIn, prefLeafHolding, prefSchemaHolding, UNSEEN, prefConditionHolds, prefValueAtPath, isPrefSection, prefSectionLeaves, isPrefLeaf, prefLeafAt, prefAliasTarget, prefAliasedLeaf, pairRowsOf, prefConditionReadsItem, visiblePrefSubtree } from './chunk-5KB3WBJZ.js';
2
+ export { PREF_KINDS, VERSION_RECORD, checkPrefCondition, checkPrefConditions, filterPrefSubtree, flattenPrefValues, isBuiltinPref, isPrefCondition, isPrefLeaf, isPrefLinearUnit, isPrefSection, mapPrefConditionPaths, openPrefs, openPrefsSync, pairRowsOf, prefAliasName, prefAliasTarget, prefAliasedLeaf, prefConditionHolds, prefConditionPaths, prefConditionReadsItem, prefDisplayBounds, prefHoldsValue, prefIsEnabled, prefIsShown, prefLeafAt, prefLeaves, prefSchemaHolding, prefSectionLeaves, prefUnit, prefValueAtPath, prefVariantDefault, prefVariantOf, repairPrefValue, resolvePrefUnit, visiblePrefSubtree } from './chunk-5KB3WBJZ.js';
3
3
 
4
- // src/helpers.ts
5
- function prefDisplayBounds(p) {
6
- if (!p.unit) return { min: p.min, max: p.max, step: p.step ?? 1 };
7
- const { toDisplay } = p.unit;
8
- const lo = p.min === void 0 ? void 0 : toDisplay(p.min);
9
- const hi = p.max === void 0 ? void 0 : toDisplay(p.max);
10
- const flipped = lo !== void 0 && hi !== void 0 && lo > hi;
11
- const step = p.step === void 0 ? 1 : Math.abs(toDisplay(p.step) - toDisplay(0)) || p.step;
12
- return { min: flipped ? hi : lo, max: flipped ? lo : hi, step };
13
- }
14
- function isPrefLeaf(node) {
15
- return "kind" in node;
16
- }
17
- function prefValueAtPath(values, path) {
18
- let cur = values;
19
- for (const seg of path.split(".")) {
20
- if (cur == null || typeof cur !== "object") return void 0;
21
- cur = cur[seg];
4
+ // src/tabRuns.ts
5
+ function prefTabRuns(items, isTab) {
6
+ const out = [];
7
+ let run;
8
+ for (const item of items) {
9
+ if (!isTab(item)) {
10
+ run = void 0;
11
+ out.push({ item });
12
+ } else if (run) {
13
+ run.push(item);
14
+ } else {
15
+ out.push({ tabs: run = [item] });
16
+ }
22
17
  }
23
- return cur;
18
+ return out;
24
19
  }
25
- function visiblePrefSubtree(node, showHidden) {
26
- if (isPrefLeaf(node)) return node.hidden && !showHidden ? null : node;
27
- const group = node;
28
- const children = {};
29
- for (const [key, child] of Object.entries(group.children)) {
30
- const kept = visiblePrefSubtree(child, showHidden);
31
- if (kept) children[key] = kept;
32
- }
33
- if (Object.keys(children).length === 0) return null;
34
- return { ...node, children };
20
+
21
+ // src/shown.ts
22
+ function prefShownValue(leaf, stored, siblings) {
23
+ if (leaf.kind !== "boolean" && leaf.kind !== "enum") return stored;
24
+ const { encoding } = leaf;
25
+ return encoding ? encoding.read(stored, siblings) : stored;
35
26
  }
36
- var VERSION_RECORD = "$version";
37
- function prefLeaves(schema) {
38
- const out = /* @__PURE__ */ new Map();
39
- const walk = (group, prefix) => {
40
- for (const [key, child] of Object.entries(group.children)) {
41
- if (key.includes(".")) {
42
- throw new Error(`[prefs] schema key "${key}" contains "."; group keys are path segments`);
43
- }
44
- if (prefix === "" && key === VERSION_RECORD) {
45
- throw new Error(`[prefs] schema key "${VERSION_RECORD}" is reserved`);
46
- }
47
- const path = prefix === "" ? key : `${prefix}.${key}`;
48
- if (isPrefLeaf(child)) out.set(path, child);
49
- else walk(child, path);
50
- }
27
+ function prefShownReader(schema, read, item, over) {
28
+ return (path, from) => {
29
+ const stored = read(path, from);
30
+ const held = from === "item" ? item && prefLeafHoldingIn(item, path) : prefLeafHolding(prefSchemaHolding(schema, path, over), path);
31
+ if (held === void 0 || held === UNSEEN) return stored;
32
+ const object = held.within === void 0 ? void 0 : read(held.within, from);
33
+ return prefShownValue(held.leaf, stored, typeof object === "object" && object !== null ? object : void 0);
51
34
  };
52
- walk(schema, "");
53
- return out;
54
35
  }
55
- function assignPrefValueAtPath(root, path, value) {
56
- const parts = path.split(".");
57
- let cursor = root;
58
- for (let i = 0; i < parts.length - 1; i++) {
59
- cursor = cursor[parts[i]] ??= {};
60
- }
61
- cursor[parts[parts.length - 1]] = value;
36
+
37
+ // src/judge.ts
38
+ function entryValue({ item, value }, path) {
39
+ if (path === "") return value !== void 0 ? value : item.default;
40
+ const held = prefValueAtPath(value, path);
41
+ return held !== void 0 ? held : prefValueAtPath(item.default, path);
62
42
  }
63
- function flattenPrefValues(schema, tree) {
64
- const out = [];
65
- for (const path of prefLeaves(schema).keys()) {
66
- const value = prefValueAtPath(tree, path);
67
- if (value !== void 0) out.push([path, value]);
68
- }
69
- return out;
43
+ function prefJudge(schema, read, entry, over) {
44
+ const stored = (path, from) => from === "item" ? entry && entryValue(entry, path) : read(path);
45
+ const shown = prefShownReader(schema, stored, entry?.item, over);
46
+ return (condition) => prefConditionHolds(condition, shown);
70
47
  }
71
- function prefLeafMatches(pref, path, query) {
72
- if (pref.name.toLowerCase().includes(query)) return true;
73
- if (pref.description?.toLowerCase().includes(query)) return true;
74
- return path.toLowerCase().includes(query);
48
+ function deferEntryConditions(holds) {
49
+ return (condition, field) => prefConditionReadsItem(condition) || holds(condition, field);
75
50
  }
76
- function filterPrefSubtree(node, query, path = "") {
77
- const q = query.trim().toLowerCase();
78
- if (q === "") return node;
79
- if (isPrefLeaf(node)) return prefLeafMatches(node, path, q) ? node : null;
80
- const group = node;
81
- if (group.name.toLowerCase().includes(q)) return node;
82
- const children = {};
83
- for (const [key, child] of Object.entries(group.children)) {
84
- const kept = filterPrefSubtree(child, q, path === "" ? key : `${path}.${key}`);
85
- if (kept) children[key] = kept;
86
- }
87
- if (Object.keys(children).length === 0) return null;
88
- return { ...node, children };
51
+ function prefReader(schema, values, over) {
52
+ const beyond = over && prefReader(over, values);
53
+ return (path) => {
54
+ const held = prefValueAtPath(values, path);
55
+ if (held !== void 0) return held;
56
+ if (beyond && prefSchemaHolding(schema, path, over) === over) return beyond(path);
57
+ if (isPrefSection(schema)) {
58
+ for (const [key, leaf] of prefSectionLeaves(schema.members)) {
59
+ if (path === key) return leaf.default;
60
+ if (path.startsWith(`${key}.`)) return prefValueAtPath(leaf.default, path.slice(key.length + 1));
61
+ }
62
+ return void 0;
63
+ }
64
+ const steps = path.split(".");
65
+ let node = schema;
66
+ for (let i = 0; i < steps.length; i++) {
67
+ if (!Object.hasOwn(node.children, steps[i])) return void 0;
68
+ const child = node.children[steps[i]];
69
+ if (!isPrefLeaf(child)) node = child;
70
+ else return i === steps.length - 1 ? child.default : prefValueAtPath(child.default, steps.slice(i + 1).join("."));
71
+ }
72
+ return void 0;
73
+ };
89
74
  }
90
75
 
91
- // src/migrate.ts
92
- var isVersion = (v) => typeof v === "number" && Number.isInteger(v) && v >= 0;
93
- function runPrefsMigrations(cache, migrations) {
94
- const target = migrations.length;
95
- const raw = cache.get(VERSION_RECORD);
96
- if (cache.has(VERSION_RECORD) && !isVersion(raw)) {
97
- console.warn(
98
- `[prefs] "${cache.prefix}" has an unreadable ${VERSION_RECORD} (${JSON.stringify(raw)}); opening read-only`
99
- );
100
- cache.stopWriting();
101
- return false;
76
+ // src/scopeAt.ts
77
+ var PREF_ENTRY = "*";
78
+ var PREF_SCOPE = Object.freeze({ shown: true, enabled: true });
79
+ function prefScopeUnder(above, node, holds) {
80
+ const shown = above.shown && (node.showIf === void 0 || holds(node.showIf, "showIf"));
81
+ const enabled = above.enabled && (node.enableIf === void 0 || holds(node.enableIf, "enableIf"));
82
+ return shown === above.shown && enabled === above.enabled ? above : { shown, enabled };
83
+ }
84
+ function scopeAmong(held, rest, above, holds) {
85
+ for (const [key, child] of Object.entries(held)) {
86
+ if (!isPrefLeaf(child)) {
87
+ const found = scopeAmong(child.members, rest, prefScopeUnder(above, child, holds), holds);
88
+ if (found) return found;
89
+ } else if (rest === key) return prefScopeUnder(above, child, holds);
90
+ else if (rest.startsWith(`${key}.`)) return scopeInside(child, rest.slice(key.length + 1), prefScopeUnder(above, child, holds), holds);
102
91
  }
103
- const stored = cache.has(VERSION_RECORD) ? raw : 0;
104
- if (stored > target) {
105
- console.warn(
106
- `[prefs] "${cache.prefix}" was written at version ${stored}, newer than this build's ${target}; opening read-only`
107
- );
108
- cache.stopWriting();
109
- return false;
92
+ return void 0;
93
+ }
94
+ function scopeInside(leaf, rest, scope, holds) {
95
+ if (leaf.kind === "object") return scopeAmong(leaf.children, rest, scope, holds) ?? scope;
96
+ if (leaf.kind === "list" || leaf.kind === "map") {
97
+ const { item } = leaf;
98
+ if (item === void 0) return scope;
99
+ const inItem = deferEntryConditions(holds);
100
+ const entry = prefScopeUnder(scope, { enableIf: item.enableIf }, inItem);
101
+ const dot = rest.indexOf(".");
102
+ return dot < 0 ? entry : scopeInside(item, rest.slice(dot + 1), entry, inItem);
110
103
  }
111
- if (stored === target || !cache.writable) return false;
112
- const before = cache.entries().filter(([name]) => name !== VERSION_RECORD);
113
- const records = new Map(before.map(([name, value]) => [name, structuredClone(value)]));
114
- for (let v = stored; v < target; v++) {
115
- try {
116
- migrations[v](records);
117
- } catch (error) {
118
- console.warn(
119
- `[prefs] migration ${v} \u2192 ${v + 1} for "${cache.prefix}" threw; opening read-only on the unmigrated records`,
120
- error
121
- );
122
- cache.stopWriting();
123
- return false;
124
- }
104
+ if (leaf.kind !== "union") return scope;
105
+ for (const variant of Object.values(leaf.variants)) {
106
+ const found = scopeAmong(variant.children, rest, scope, holds);
107
+ if (found) return found;
125
108
  }
126
- for (const [name] of before) if (!records.has(name)) cache.delete(name);
127
- for (const [name, value] of records) {
128
- if (value === void 0) cache.delete(name);
129
- else cache.set(name, value);
109
+ return scope;
110
+ }
111
+ function scopeAt(schema, path, holds) {
112
+ let scope = prefScopeUnder(PREF_SCOPE, schema, holds);
113
+ if (path === "") return scope;
114
+ if (isPrefSection(schema)) return scopeAmong(schema.members, path, scope, holds) ?? scope;
115
+ let node = schema;
116
+ const steps = path.split(".");
117
+ for (let i = 0; i < steps.length; i++) {
118
+ if (!Object.hasOwn(node.children, steps[i])) return scope;
119
+ const child = node.children[steps[i]];
120
+ scope = prefScopeUnder(scope, child, holds);
121
+ if (isPrefLeaf(child)) return i === steps.length - 1 ? scope : scopeInside(child, steps.slice(i + 1).join("."), scope, holds);
122
+ node = child;
130
123
  }
131
- cache.set(VERSION_RECORD, target);
132
- return true;
124
+ return scope;
133
125
  }
134
- function watchPrefsVersion(cache, target) {
135
- return cache.subscribe((changes) => {
136
- for (const change of changes) {
137
- if (change.origin !== "remote" || change.name !== VERSION_RECORD || change.value === void 0) continue;
138
- if (!isVersion(change.value)) {
139
- console.warn(
140
- `[prefs] "${cache.prefix}" has an unreadable ${VERSION_RECORD} (${JSON.stringify(change.value)}) from another writer; no longer persisting`
141
- );
142
- cache.stopWriting();
143
- } else if (change.value > target) {
144
- console.warn(
145
- `[prefs] "${cache.prefix}" was migrated to version ${change.value} by another writer; this build knows ${target}; no longer persisting`
146
- );
147
- cache.stopWriting();
148
- }
149
- }
150
- });
126
+ function prefAliasScope(own, alias, over, holds) {
127
+ const target = prefAliasTarget(alias, (path) => prefLeafAt(over, path));
128
+ if (target === void 0) return own;
129
+ const theirs = scopeAt(over, target.path, holds);
130
+ const shown = own.shown && theirs.shown;
131
+ const enabled = own.enabled && theirs.enabled;
132
+ return shown === own.shown && enabled === own.enabled ? own : { shown, enabled };
133
+ }
134
+ function prefScopeAt(schema, path, holds, { aliasOver, aliasHolds } = {}) {
135
+ const own = scopeAt(schema, path, holds);
136
+ const leaf = prefLeafAt(schema, path);
137
+ return leaf?.kind === "alias" ? prefAliasScope(own, leaf, aliasOver ?? schema, aliasHolds ?? holds) : own;
151
138
  }
152
139
 
153
- // src/repair.ts
154
- function repairPrefValue(leaf, stored, validators) {
155
- if (leaf.kind === "number") {
156
- if (stored === "Infinity") stored = Infinity;
157
- else if (stored === "-Infinity") stored = -Infinity;
158
- }
159
- const validate = validators?.[leaf.kind];
160
- if (validate) {
161
- try {
162
- const out = validate(stored, leaf);
163
- return out === void 0 ? leaf.default : out;
164
- } catch {
165
- return leaf.default;
140
+ // src/scope.ts
141
+ var under = (prefix, key) => prefix === "" ? key : `${prefix}.${key}`;
142
+ function leafWalk({ keepEmpty, keepHidden, inItem, aliasOver, aliasHolds }) {
143
+ const disabled = /* @__PURE__ */ new Set();
144
+ const hidden = /* @__PURE__ */ new Set();
145
+ const leaf = (node, path, above, holds) => {
146
+ const own = prefScopeUnder(above, node, holds);
147
+ const scope = node.kind === "alias" && aliasOver ? prefAliasScope(own, node, aliasOver, aliasHolds ?? holds) : own;
148
+ return scope.shown || keepHidden ? inside(node, path, scope, holds) : null;
149
+ };
150
+ const inside = (node, path, scope, holds) => {
151
+ if (!scope.shown) hidden.add(path);
152
+ if (!scope.enabled) disabled.add(path);
153
+ if (node.kind === "object") {
154
+ const children = members(node.children, path, scope, holds);
155
+ return children === node.children ? node : { ...node, children };
166
156
  }
167
- }
168
- switch (leaf.kind) {
169
- case "number":
170
- return repairNumber(leaf, stored);
171
- case "boolean":
172
- return leaf.encoding || typeof stored === "boolean" ? stored : leaf.default;
173
- case "string":
174
- case "color":
175
- case "field":
176
- return typeof stored === "string" ? stored : leaf.default;
177
- case "enum": {
178
- const e = leaf;
179
- if (e.encoding) return stored;
180
- return e.options.some((o) => o.value === stored) ? stored : leaf.default;
157
+ if (node.kind === "list" || node.kind === "map") {
158
+ const { item } = node;
159
+ if (item === void 0) return node;
160
+ const entry = inside(item, under(path, PREF_ENTRY), prefScopeUnder(scope, { enableIf: item.enableIf }, inItem), inItem);
161
+ return entry === item ? node : { ...node, item: entry };
181
162
  }
182
- case "object":
183
- if (leaf.fromScalar || isPlainObject(stored)) return stored;
184
- return leaf.default;
185
- default:
186
- return stored;
187
- }
163
+ if (node.kind !== "union") return node;
164
+ const { variants } = node;
165
+ let changed = false;
166
+ const next = {};
167
+ for (const [key, variant] of Object.entries(variants)) {
168
+ const children = members(variant.children, path, scope, holds);
169
+ changed ||= children !== variant.children;
170
+ next[key] = children === variant.children ? variant : { ...variant, children };
171
+ }
172
+ return changed ? { ...node, variants: next } : node;
173
+ };
174
+ const members = (held, prefix, above, holds) => {
175
+ let changed = false;
176
+ const out = {};
177
+ for (const [key, child] of Object.entries(held)) {
178
+ const kept = isPrefLeaf(child) ? leaf(child, under(prefix, key), above, holds) : section(child, prefix, above, holds);
179
+ changed ||= kept !== child;
180
+ if (kept !== null) out[key] = kept;
181
+ }
182
+ return changed ? out : held;
183
+ };
184
+ const section = (node, prefix, above, holds) => {
185
+ const scope = prefScopeUnder(above, node, holds);
186
+ if (!scope.shown && !keepHidden) return null;
187
+ const kept = members(node.members, prefix, scope, holds);
188
+ if (kept === node.members) return node;
189
+ return Object.keys(kept).length === 0 && !keepEmpty ? null : { ...node, members: kept };
190
+ };
191
+ return { disabled, hidden, leaf, inside, members };
188
192
  }
189
- function isPlainObject(v) {
190
- return v !== null && typeof v === "object" && !Array.isArray(v);
193
+ function applyPrefConditions(schema, holds, { keepEmpty = false, keepHidden = false, aliasOver, aliasHolds } = {}) {
194
+ const walk = leafWalk({ keepEmpty, keepHidden, inItem: deferEntryConditions(holds), aliasOver: aliasOver ?? schema, aliasHolds });
195
+ const { disabled, hidden } = walk;
196
+ const group = (node, path, above) => {
197
+ const scope2 = prefScopeUnder(above, node, holds);
198
+ if (!scope2.shown && !keepHidden) return null;
199
+ if (!scope2.shown && path !== "") hidden.add(path);
200
+ if (!scope2.enabled && path !== "") disabled.add(path);
201
+ let changed = false;
202
+ const children = {};
203
+ for (const [key, child] of Object.entries(node.children)) {
204
+ const at = under(path, key);
205
+ const kept2 = isPrefLeaf(child) ? walk.leaf(child, at, scope2, holds) : group(child, at, scope2);
206
+ changed ||= kept2 !== child;
207
+ if (kept2 !== null) children[key] = kept2;
208
+ }
209
+ if (!changed) return node;
210
+ return Object.keys(children).length === 0 && !keepEmpty && path !== "" ? null : { ...node, children };
211
+ };
212
+ if (!isPrefSection(schema)) return { shown: group(schema, "", PREF_SCOPE), disabled, hidden };
213
+ const scope = prefScopeUnder(PREF_SCOPE, schema, holds);
214
+ if (!scope.shown && !keepHidden) return { shown: null, disabled, hidden };
215
+ const kept = walk.members(schema.members, "", scope, holds);
216
+ return { shown: kept === schema.members ? schema : { ...schema, members: kept }, disabled, hidden };
191
217
  }
192
- function repairNumber(leaf, stored) {
193
- if (typeof stored !== "number" || Number.isNaN(stored)) return leaf.default;
194
- const { endless } = leaf;
195
- if (stored === Infinity && (endless === "max" || endless === "both")) return stored;
196
- if (stored === -Infinity && (endless === "min" || endless === "both")) return stored;
197
- let v = stored;
198
- if (leaf.min !== void 0 && v < leaf.min) v = leaf.min;
199
- if (leaf.max !== void 0 && v > leaf.max) v = leaf.max;
200
- return Number.isFinite(v) ? v : leaf.default;
218
+ var ALWAYS = () => true;
219
+ function applyPrefEntryConditions(item, path, holds, { keepEmpty = false, keepHidden = false } = {}) {
220
+ const asked = (condition, field) => !prefConditionReadsItem(condition) || holds(condition, field);
221
+ const walk = leafWalk({ keepEmpty, keepHidden, inItem: ALWAYS });
222
+ const scope = prefScopeUnder(PREF_SCOPE, { enableIf: item.enableIf }, asked);
223
+ return { item: walk.inside(item, path, scope, asked), disabled: walk.disabled, hidden: walk.hidden };
201
224
  }
202
225
 
203
- // src/store.ts
204
- var encodeInfinity = (leaf, value) => leaf.kind === "number" && (value === Infinity || value === -Infinity) ? String(value) : value;
205
- function createPrefsStore(schema, cache, validators, onClose) {
206
- const leaves = prefLeaves(schema);
207
- let snapshot = null;
208
- let previous = null;
209
- const build = () => {
210
- const byPath = /* @__PURE__ */ new Map();
211
- const raw = /* @__PURE__ */ new Map();
212
- const unset = /* @__PURE__ */ new Set();
213
- const tree = {};
214
- for (const [path, leaf] of leaves) {
215
- const has = cache.has(path);
216
- let value;
217
- if (!has) {
218
- value = leaf.default;
219
- unset.add(path);
220
- } else {
221
- const stored = cache.get(path);
222
- raw.set(path, stored);
223
- value = previous?.raw.has(path) && previous.raw.get(path) === stored ? previous.byPath.get(path) : repairPrefValue(leaf, stored, validators);
224
- }
225
- byPath.set(path, value);
226
- assignPrefValueAtPath(tree, path, value);
227
- }
228
- previous = { raw, byPath };
229
- return { byPath, tree, unset };
230
- };
231
- const current = () => snapshot ??= build();
232
- let storedTree = null;
233
- const buildStored = () => {
234
- const tree = {};
235
- const branches = new WeakSet([tree]);
236
- for (const [name, value] of cache.entries()) {
237
- if (name === VERSION_RECORD) continue;
238
- const parts = name.split(".");
239
- let cursor = tree;
240
- for (const part of parts.slice(0, -1)) {
241
- const next = cursor[part];
242
- if (typeof next === "object" && next !== null && branches.has(next)) {
243
- cursor = next;
244
- } else {
245
- const branch = {};
246
- branches.add(branch);
247
- cursor[part] = branch;
248
- cursor = branch;
249
- }
250
- }
251
- const last = parts[parts.length - 1];
252
- if (!branches.has(cursor[last])) cursor[last] = value;
253
- }
254
- return tree;
226
+ // src/aliasTargets.ts
227
+ function visibleFieldsOf(leaf) {
228
+ if (leaf.kind !== "object") return leaf;
229
+ const shown = visiblePrefSubtree({ ...leaf, hidden: false }, false, true);
230
+ return { ...leaf, children: shown.children };
231
+ }
232
+ function prefAliasTargets(over, judge, { showHidden = false, markHidden = false } = {}) {
233
+ const holds = judge();
234
+ let applied;
235
+ const get = () => applied ??= applyPrefConditions(over, holds, { keepEmpty: true, keepHidden: markHidden });
236
+ const leafAt = (path) => {
237
+ const { shown } = get();
238
+ const leaf = shown === null ? void 0 : prefLeafAt(shown, path);
239
+ return leaf === void 0 || showHidden ? leaf : visibleFieldsOf(leaf);
255
240
  };
256
- const listeners = /* @__PURE__ */ new Set();
257
- const stopCache = cache.subscribe((changes) => {
258
- const records = changes.filter((c) => c.name !== VERSION_RECORD);
259
- if (records.length === 0) return;
260
- storedTree = null;
261
- const mine = records.filter((c) => leaves.has(c.name));
262
- if (mine.length > 0) snapshot = null;
263
- const now = current();
264
- const out = mine.map((c) => ({ path: c.name, value: now.byPath.get(c.name), origin: c.origin }));
265
- for (const listener of [...listeners]) listener(out);
266
- });
267
241
  return {
268
- schema,
269
- get: (path) => current().byPath.get(path),
270
- set: (path, value) => {
271
- const leaf = leaves.get(path);
272
- if (!leaf) {
273
- console.warn(`[prefs] no leaf at "${path}"; ignoring the write`);
274
- return;
275
- }
276
- cache.set(path, encodeInfinity(leaf, value));
242
+ holds,
243
+ leafAt,
244
+ shown: (alias) => {
245
+ const target = prefAliasTarget(alias, leafAt);
246
+ return target && { path: target.path, leaf: prefAliasedLeaf(alias, target.leaf) };
277
247
  },
278
- reset: (path) => {
279
- for (const p of leaves.keys()) {
280
- if (path === void 0 || p === path || p.startsWith(`${path}.`)) cache.delete(p);
281
- }
282
- },
283
- isSet: (path) => cache.has(path),
284
- values: () => current().tree,
285
- unset: () => current().unset,
286
- stored: () => storedTree ??= buildStored(),
287
- subscribe: (listener) => {
288
- listeners.add(listener);
289
- return () => {
290
- listeners.delete(listener);
291
- };
292
- },
293
- get writable() {
294
- return cache.writable;
295
- },
296
- flush: () => cache.flush(),
297
- close: async () => {
298
- onClose?.();
299
- stopCache();
300
- listeners.clear();
301
- await cache.close();
302
- }
248
+ disabledAt: (path) => get().disabled.has(path),
249
+ ...markHidden ? { hiddenAt: (path) => get().hidden.has(path) } : {},
250
+ entryAt: (item, path, value) => applyPrefEntryConditions(item, path, judge({ item, value }), { keepHidden: markHidden })
303
251
  };
304
252
  }
305
253
 
306
- // src/open.ts
307
- async function openPrefs(schema, options) {
308
- const cache = await openRecords({ storage: options.storage, prefix: options.prefix });
309
- const stop = watch(cache, options);
310
- if (runPrefsMigrations(cache, options.migrations ?? [])) await cache.flush();
311
- return createPrefsStore(schema, cache, options.validators, stop);
254
+ // src/object.ts
255
+ var isObject = (v) => typeof v === "object" && v !== null;
256
+ function prefObjectBase(pref, held) {
257
+ if (isObject(held)) return held;
258
+ return pref.fromScalar?.(held) ?? (isObject(pref.default) ? pref.default : {});
312
259
  }
313
- function openPrefsSync(schema, options) {
314
- const cache = openRecordsSync({ storage: options.storage, prefix: options.prefix });
315
- const stop = watch(cache, options);
316
- if (runPrefsMigrations(cache, options.migrations ?? [])) void cache.flush();
317
- return createPrefsStore(schema, cache, options.validators, stop);
260
+ function prefObjectWithField(pref, held, key, value) {
261
+ const base = prefObjectBase(pref, held);
262
+ if (value !== void 0) return { ...base, [key]: value };
263
+ const { [key]: _dropped, ...rest } = base;
264
+ return rest;
318
265
  }
319
- var watch = (cache, options) => cache.writable ? watchPrefsVersion(cache, (options.migrations ?? []).length) : void 0;
320
- function prefUnit(system, display, opts) {
321
- let self;
322
- try {
323
- self = unitScale(system, display);
324
- } catch (e) {
325
- throw new Error(`prefUnit: ${e instanceof Error ? e.message : String(e)}`);
326
- }
327
- const scale = opts?.precision === void 0 ? void 0 : 10 ** opts.precision;
328
- const suffix = opts?.suffix ?? display;
329
- const accepts = { [suffix]: 1 };
330
- for (const name of Object.keys(system.units)) {
331
- const other = unitScale(system, name);
332
- const factor = other.factor / self.factor;
333
- const offset = (other.offset - self.offset) / self.factor;
334
- accepts[name] = offset === 0 ? factor : { factor, offset };
266
+
267
+ // src/type.ts
268
+ function prefType(name, leaf) {
269
+ return { ...leaf, type: name };
270
+ }
271
+
272
+ // src/groups.ts
273
+ function prefGroupIsPage(group) {
274
+ return group.as === void 0 || group.as === "page";
275
+ }
276
+
277
+ // src/pair.ts
278
+ function pairRuns(items, leafOf) {
279
+ const leaves = items.map(leafOf);
280
+ const pairs = pairRowsOf(leaves.filter((entry) => entry !== void 0));
281
+ const keys = leaves.map((entry) => entry === void 0 ? void 0 : pairs.get(entry[0]));
282
+ const runs = [];
283
+ for (let i = 0; i < items.length; ) {
284
+ const pair = keys[i];
285
+ let j = i + 1;
286
+ while (pair !== void 0 && keys[j]?.key === pair.key) j += 1;
287
+ runs.push(j - i > 1 ? { items: items.slice(i, j), pair } : { items: [items[i]] });
288
+ i = j;
335
289
  }
336
- const toDisplay = (stored) => {
337
- const shown = (stored - self.offset) / self.factor;
338
- return scale === void 0 ? shown : Math.round(shown * scale) / scale;
339
- };
340
- return {
341
- toDisplay,
342
- fromDisplay: (shown) => shown * self.factor + self.offset,
343
- suffix,
344
- accepts,
345
- format: (stored) => `${formatUnit(stored, display, system, {
346
- precision: opts?.precision ?? 2,
347
- suffix: false
348
- })}${suffix}`
349
- };
290
+ return runs;
350
291
  }
351
- var PREF_KINDS = {
352
- number: true,
353
- boolean: true,
354
- string: true,
355
- enum: true,
356
- color: true,
357
- paint: true,
358
- object: true,
359
- field: true
292
+
293
+ // src/kinds.ts
294
+ var ONE = { compound: false, several: false };
295
+ var MANY = { compound: true, several: true };
296
+ var PREF_KIND_TRAITS = {
297
+ number: ONE,
298
+ boolean: ONE,
299
+ string: ONE,
300
+ enum: ONE,
301
+ color: ONE,
302
+ paint: ONE,
303
+ object: MANY,
304
+ list: MANY,
305
+ map: MANY,
306
+ union: MANY,
307
+ field: ONE,
308
+ action: { compound: false, several: true },
309
+ alias: ONE,
310
+ label: ONE,
311
+ separator: ONE
360
312
  };
361
- function pairRowsOf(leaves) {
362
- const rows = /* @__PURE__ */ new Map();
363
- for (const [path, leaf] of leaves) {
364
- if (!leaf.pair || rows.has(path)) continue;
365
- const row = { key: path, label: leaf.pair.label ?? leaf.name };
366
- rows.set(path, row);
367
- const partners = typeof leaf.pair.with === "string" ? [leaf.pair.with] : leaf.pair.with;
368
- for (const partner of partners) if (!rows.has(partner)) rows.set(partner, row);
369
- }
370
- return rows;
313
+ var traitsOf = (leaf) => Object.hasOwn(PREF_KIND_TRAITS, leaf.kind) ? PREF_KIND_TRAITS[leaf.kind] : ONE;
314
+ function prefIsCompound(leaf) {
315
+ return traitsOf(leaf).compound;
371
316
  }
372
- function isBuiltinPref(leaf) {
373
- return Object.hasOwn(PREF_KINDS, leaf.kind);
317
+ function prefDrawsSeveral(leaf) {
318
+ return traitsOf(leaf).several;
374
319
  }
375
320
 
376
- export { PREF_KINDS, VERSION_RECORD, filterPrefSubtree, flattenPrefValues, isBuiltinPref, isPrefLeaf, openPrefs, openPrefsSync, pairRowsOf, prefDisplayBounds, prefLeaves, prefUnit, prefValueAtPath, repairPrefValue, visiblePrefSubtree };
321
+ export { PREF_ENTRY, PREF_KIND_TRAITS, PREF_SCOPE, applyPrefConditions, applyPrefEntryConditions, pairRuns, prefAliasTargets, prefDrawsSeveral, prefGroupIsPage, prefIsCompound, prefJudge, prefObjectBase, prefObjectWithField, prefReader, prefScopeAt, prefScopeUnder, prefShownReader, prefShownValue, prefTabRuns, prefType };
377
322
  //# sourceMappingURL=index.js.map
378
323
  //# sourceMappingURL=index.js.map