@weasel-js/prefs 1.9.3 → 1.9.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.
- package/README.md +10 -0
- package/dist/index.d.ts +84 -12
- package/dist/index.js +321 -62
- package/dist/index.js.map +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js.map +1 -1
- package/dist/{store-BU2tRX5H.d.ts → store-CNFnA_3c.d.ts} +250 -31
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
import { openRecords, openRecordsSync } from '@weasel-js/storage';
|
|
2
|
+
import { isPlainObject } from '@weasel-js/registry';
|
|
2
3
|
import { unitScale, formatUnit } from '@weasel-js/quantity';
|
|
3
4
|
|
|
5
|
+
// src/alias.ts
|
|
6
|
+
function prefAliasTarget(alias, leafAt) {
|
|
7
|
+
const passed = /* @__PURE__ */ new Set();
|
|
8
|
+
let path = alias.of;
|
|
9
|
+
for (; ; ) {
|
|
10
|
+
if (passed.has(path)) return void 0;
|
|
11
|
+
passed.add(path);
|
|
12
|
+
const leaf = leafAt(path);
|
|
13
|
+
if (leaf === void 0) return void 0;
|
|
14
|
+
if (leaf.kind !== "alias") return { path, leaf };
|
|
15
|
+
path = leaf.of;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function prefAliasedLeaf(alias, target) {
|
|
19
|
+
return {
|
|
20
|
+
...target,
|
|
21
|
+
name: alias.name === "" ? target.name : alias.name,
|
|
22
|
+
description: alias.description === "" ? target.description : alias.description
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
4
26
|
// src/helpers.ts
|
|
5
27
|
function prefDisplayBounds(p) {
|
|
6
28
|
if (!p.unit) return { min: p.min, max: p.max, step: p.step ?? 1 };
|
|
@@ -14,23 +36,61 @@ function prefDisplayBounds(p) {
|
|
|
14
36
|
function isPrefLeaf(node) {
|
|
15
37
|
return "kind" in node;
|
|
16
38
|
}
|
|
39
|
+
var VALUELESS = /* @__PURE__ */ new Set(["action", "alias", "label", "separator"]);
|
|
40
|
+
function prefHoldsValue(leaf) {
|
|
41
|
+
return !VALUELESS.has(leaf.kind);
|
|
42
|
+
}
|
|
43
|
+
function isPrefSection(node) {
|
|
44
|
+
return !isPrefLeaf(node) && "members" in node;
|
|
45
|
+
}
|
|
46
|
+
function prefSectionLeaves(members) {
|
|
47
|
+
return Object.entries(members).flatMap(
|
|
48
|
+
([key, child]) => isPrefLeaf(child) ? [[key, child]] : prefSectionLeaves(child.members)
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
function prefLeafAt(schema, path) {
|
|
52
|
+
if (isPrefSection(schema)) return prefSectionLeaves(schema.members).find(([key]) => key === path)?.[1];
|
|
53
|
+
let node = schema;
|
|
54
|
+
for (const seg of path.split(".")) {
|
|
55
|
+
if (isPrefLeaf(node) || !Object.hasOwn(node.children, seg)) return void 0;
|
|
56
|
+
node = node.children[seg];
|
|
57
|
+
}
|
|
58
|
+
return isPrefLeaf(node) ? node : void 0;
|
|
59
|
+
}
|
|
17
60
|
function prefValueAtPath(values, path) {
|
|
18
61
|
let cur = values;
|
|
19
62
|
for (const seg of path.split(".")) {
|
|
20
|
-
if (cur == null || typeof cur !== "object") return void 0;
|
|
63
|
+
if (cur == null || typeof cur !== "object" || !Object.hasOwn(cur, seg)) return void 0;
|
|
21
64
|
cur = cur[seg];
|
|
22
65
|
}
|
|
23
66
|
return cur;
|
|
24
67
|
}
|
|
25
|
-
function
|
|
26
|
-
|
|
68
|
+
function visibleFields(fields, keepEmpty) {
|
|
69
|
+
const out = {};
|
|
70
|
+
for (const [key, child] of Object.entries(fields)) {
|
|
71
|
+
if (isPrefLeaf(child)) {
|
|
72
|
+
const kept = visiblePrefSubtree(child, false, keepEmpty);
|
|
73
|
+
if (kept) out[key] = kept;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const members = visibleFields(child.members, keepEmpty);
|
|
77
|
+
if (Object.keys(members).length > 0 || keepEmpty) out[key] = { ...child, members };
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
function visiblePrefSubtree(node, showHidden, keepEmpty = false) {
|
|
82
|
+
if (isPrefLeaf(node)) {
|
|
83
|
+
if (node.hidden && !showHidden) return null;
|
|
84
|
+
if (showHidden || node.kind !== "object") return node;
|
|
85
|
+
return { ...node, children: visibleFields(node.children, keepEmpty) };
|
|
86
|
+
}
|
|
27
87
|
const group = node;
|
|
28
88
|
const children = {};
|
|
29
89
|
for (const [key, child] of Object.entries(group.children)) {
|
|
30
|
-
const kept = visiblePrefSubtree(child, showHidden);
|
|
90
|
+
const kept = visiblePrefSubtree(child, showHidden, keepEmpty);
|
|
31
91
|
if (kept) children[key] = kept;
|
|
32
92
|
}
|
|
33
|
-
if (Object.keys(children).length === 0) return null;
|
|
93
|
+
if (Object.keys(children).length === 0 && !keepEmpty) return null;
|
|
34
94
|
return { ...node, children };
|
|
35
95
|
}
|
|
36
96
|
var VERSION_RECORD = "$version";
|
|
@@ -52,13 +112,17 @@ function prefLeaves(schema) {
|
|
|
52
112
|
walk(schema, "");
|
|
53
113
|
return out;
|
|
54
114
|
}
|
|
115
|
+
function setOwnPrefValue(tree, key, value) {
|
|
116
|
+
Object.defineProperty(tree, key, { value, writable: true, enumerable: true, configurable: true });
|
|
117
|
+
}
|
|
55
118
|
function assignPrefValueAtPath(root, path, value) {
|
|
56
119
|
const parts = path.split(".");
|
|
57
120
|
let cursor = root;
|
|
58
|
-
for (
|
|
59
|
-
cursor
|
|
121
|
+
for (const part of parts.slice(0, -1)) {
|
|
122
|
+
if (!Object.hasOwn(cursor, part) || cursor[part] == null) setOwnPrefValue(cursor, part, {});
|
|
123
|
+
cursor = cursor[part];
|
|
60
124
|
}
|
|
61
|
-
cursor
|
|
125
|
+
setOwnPrefValue(cursor, parts[parts.length - 1], value);
|
|
62
126
|
}
|
|
63
127
|
function flattenPrefValues(schema, tree) {
|
|
64
128
|
const out = [];
|
|
@@ -73,27 +137,85 @@ function prefLeafMatches(pref, path, query) {
|
|
|
73
137
|
if (pref.description?.toLowerCase().includes(query)) return true;
|
|
74
138
|
return path.toLowerCase().includes(query);
|
|
75
139
|
}
|
|
76
|
-
function filterPrefSubtree(node, query, path = "") {
|
|
140
|
+
function filterPrefSubtree(node, query, path = "", leafAt) {
|
|
77
141
|
const q = query.trim().toLowerCase();
|
|
78
142
|
if (q === "") return node;
|
|
79
|
-
|
|
143
|
+
const find = leafAt ?? ((p) => isPrefLeaf(node) ? void 0 : prefLeafAt(node, p));
|
|
144
|
+
if (isPrefLeaf(node)) {
|
|
145
|
+
const target = node.kind === "alias" ? prefAliasTarget(node, find) : void 0;
|
|
146
|
+
const drawn = target ? prefAliasedLeaf(node, target.leaf) : node;
|
|
147
|
+
return prefLeafMatches(drawn, path, q) ? node : null;
|
|
148
|
+
}
|
|
80
149
|
const group = node;
|
|
81
150
|
if (group.name.toLowerCase().includes(q)) return node;
|
|
82
151
|
const children = {};
|
|
83
152
|
for (const [key, child] of Object.entries(group.children)) {
|
|
84
|
-
const kept = filterPrefSubtree(child, q, path === "" ? key : `${path}.${key}
|
|
153
|
+
const kept = filterPrefSubtree(child, q, path === "" ? key : `${path}.${key}`, find);
|
|
85
154
|
if (kept) children[key] = kept;
|
|
86
155
|
}
|
|
87
156
|
if (Object.keys(children).length === 0) return null;
|
|
88
157
|
return { ...node, children };
|
|
89
158
|
}
|
|
90
159
|
|
|
91
|
-
// src/
|
|
160
|
+
// src/object.ts
|
|
161
|
+
var isObject = (v) => typeof v === "object" && v !== null;
|
|
162
|
+
function prefObjectBase(pref, held) {
|
|
163
|
+
if (isObject(held)) return held;
|
|
164
|
+
return pref.fromScalar?.(held) ?? (isObject(pref.default) ? pref.default : {});
|
|
165
|
+
}
|
|
166
|
+
function prefObjectWithField(pref, held, key, value) {
|
|
167
|
+
const base = prefObjectBase(pref, held);
|
|
168
|
+
if (value !== void 0) return { ...base, [key]: value };
|
|
169
|
+
const { [key]: _dropped, ...rest } = base;
|
|
170
|
+
return rest;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// src/union.ts
|
|
174
|
+
function prefVariantOf(leaf, value) {
|
|
175
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
176
|
+
const key = value[leaf.tag];
|
|
177
|
+
if (typeof key !== "string" || !Object.hasOwn(leaf.variants, key)) return void 0;
|
|
178
|
+
return [key, leaf.variants[key]];
|
|
179
|
+
}
|
|
180
|
+
function prefVariantDefault(leaf, key) {
|
|
181
|
+
const held = leaf.variants[key]?.default;
|
|
182
|
+
const fields = held !== null && typeof held === "object" ? held : {};
|
|
183
|
+
return { ...fields, [leaf.tag]: key };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// src/type.ts
|
|
187
|
+
function prefType(name, leaf) {
|
|
188
|
+
return { ...leaf, type: name };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// src/groups.ts
|
|
192
|
+
function prefGroupIsPage(group) {
|
|
193
|
+
return group.as === void 0 || group.as === "page";
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// src/stamp.ts
|
|
92
197
|
var isVersion = (v) => typeof v === "number" && Number.isInteger(v) && v >= 0;
|
|
93
|
-
function
|
|
198
|
+
function stampRecord(value, at) {
|
|
199
|
+
return { $at: at, value };
|
|
200
|
+
}
|
|
201
|
+
function isStampedRecord(record) {
|
|
202
|
+
if (record === null || typeof record !== "object") return false;
|
|
203
|
+
const keys = Object.keys(record);
|
|
204
|
+
return keys.length === 2 && Object.hasOwn(record, "value") && isVersion(record.$at);
|
|
205
|
+
}
|
|
206
|
+
function readRecord(record, unstamped) {
|
|
207
|
+
return isStampedRecord(record) ? { at: record.$at, value: record.value, stamped: true } : { at: unstamped, value: record, stamped: false };
|
|
208
|
+
}
|
|
209
|
+
function recordValue(record) {
|
|
210
|
+
return isStampedRecord(record) ? record.value : record;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// src/migrate.ts
|
|
214
|
+
var isVersion2 = (v) => typeof v === "number" && Number.isInteger(v) && v >= 0;
|
|
215
|
+
function runPrefsMigrations(cache, migrations, { stampAll = true } = {}) {
|
|
94
216
|
const target = migrations.length;
|
|
95
217
|
const raw = cache.get(VERSION_RECORD);
|
|
96
|
-
if (cache.has(VERSION_RECORD) && !
|
|
218
|
+
if (cache.has(VERSION_RECORD) && !isVersion2(raw)) {
|
|
97
219
|
console.warn(
|
|
98
220
|
`[prefs] "${cache.prefix}" has an unreadable ${VERSION_RECORD} (${JSON.stringify(raw)}); opening read-only`
|
|
99
221
|
);
|
|
@@ -101,19 +223,23 @@ function runPrefsMigrations(cache, migrations) {
|
|
|
101
223
|
return false;
|
|
102
224
|
}
|
|
103
225
|
const stored = cache.has(VERSION_RECORD) ? raw : 0;
|
|
104
|
-
|
|
226
|
+
const held = cache.entries().filter(([name]) => name !== VERSION_RECORD).map(([name, record]) => ({ name, ...readRecord(record, Math.min(stored, target)) }));
|
|
227
|
+
const newest = Math.max(stored, ...held.map((r) => r.at));
|
|
228
|
+
if (newest > target) {
|
|
105
229
|
console.warn(
|
|
106
|
-
`[prefs] "${cache.prefix}" was written at version ${
|
|
230
|
+
`[prefs] "${cache.prefix}" was written at version ${newest}, newer than this build's ${target}; opening read-only`
|
|
107
231
|
);
|
|
108
232
|
cache.stopWriting();
|
|
109
233
|
return false;
|
|
110
234
|
}
|
|
111
|
-
if (
|
|
112
|
-
const
|
|
113
|
-
const records = new Map(
|
|
114
|
-
for (let v =
|
|
235
|
+
if (!cache.writable) return false;
|
|
236
|
+
const at = new Map(held.filter((r) => r.at < target).map((r) => [r.name, r.at]));
|
|
237
|
+
const records = new Map(held.filter((r) => at.has(r.name)).map((r) => [r.name, structuredClone(r.value)]));
|
|
238
|
+
for (let v = Math.min(target, ...at.values()); v < target; v++) {
|
|
239
|
+
const due = new Map([...records].filter(([name]) => at.get(name) <= v));
|
|
240
|
+
const before = [...due.keys()];
|
|
115
241
|
try {
|
|
116
|
-
migrations[v](
|
|
242
|
+
migrations[v](due);
|
|
117
243
|
} catch (error) {
|
|
118
244
|
console.warn(
|
|
119
245
|
`[prefs] migration ${v} \u2192 ${v + 1} for "${cache.prefix}" threw; opening read-only on the unmigrated records`,
|
|
@@ -122,35 +248,76 @@ function runPrefsMigrations(cache, migrations) {
|
|
|
122
248
|
cache.stopWriting();
|
|
123
249
|
return false;
|
|
124
250
|
}
|
|
251
|
+
for (const name of before) if (!due.has(name)) records.delete(name);
|
|
252
|
+
for (const [name, value] of due) {
|
|
253
|
+
records.set(name, value);
|
|
254
|
+
at.set(name, v + 1);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
let wrote = false;
|
|
258
|
+
for (const r of held) {
|
|
259
|
+
if (at.has(r.name)) {
|
|
260
|
+
if (!records.has(r.name)) cache.delete(r.name);
|
|
261
|
+
wrote = true;
|
|
262
|
+
} else if (stampAll && !r.stamped) {
|
|
263
|
+
cache.set(r.name, stampRecord(r.value, target));
|
|
264
|
+
wrote = true;
|
|
265
|
+
}
|
|
125
266
|
}
|
|
126
|
-
for (const [name] of before) if (!records.has(name)) cache.delete(name);
|
|
127
267
|
for (const [name, value] of records) {
|
|
128
268
|
if (value === void 0) cache.delete(name);
|
|
129
|
-
else cache.set(name, value);
|
|
269
|
+
else cache.set(name, stampRecord(value, target));
|
|
130
270
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
return
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
271
|
+
if (stored !== target) {
|
|
272
|
+
cache.set(VERSION_RECORD, target);
|
|
273
|
+
wrote = true;
|
|
274
|
+
}
|
|
275
|
+
return wrote;
|
|
276
|
+
}
|
|
277
|
+
function watchPrefsVersion(cache, migrations) {
|
|
278
|
+
const target = migrations.length;
|
|
279
|
+
let versioned = cache.has(VERSION_RECORD);
|
|
280
|
+
let stopped = false;
|
|
281
|
+
const migrate = () => {
|
|
282
|
+
const cleared = versioned && !cache.has(VERSION_RECORD);
|
|
283
|
+
if (cleared) cache.set(VERSION_RECORD, target);
|
|
284
|
+
else if (!runPrefsMigrations(cache, migrations, { stampAll: false })) return;
|
|
285
|
+
versioned = true;
|
|
286
|
+
void cache.flush();
|
|
287
|
+
};
|
|
288
|
+
void cache.whenRead().then(() => {
|
|
289
|
+
if (!stopped && cache.writable) migrate();
|
|
290
|
+
});
|
|
291
|
+
const heard = (version) => {
|
|
292
|
+
if (!isVersion2(version)) {
|
|
293
|
+
console.warn(
|
|
294
|
+
`[prefs] "${cache.prefix}" has an unreadable ${VERSION_RECORD} (${JSON.stringify(version)}) from another writer; no longer persisting`
|
|
295
|
+
);
|
|
296
|
+
cache.stopWriting();
|
|
297
|
+
} else if (version > target) {
|
|
298
|
+
console.warn(
|
|
299
|
+
`[prefs] "${cache.prefix}" was migrated to version ${version} by another writer; this build knows ${target}; no longer persisting`
|
|
300
|
+
);
|
|
301
|
+
cache.stopWriting();
|
|
149
302
|
}
|
|
303
|
+
};
|
|
304
|
+
const stopOverruled = cache.onOverruled((changes) => {
|
|
305
|
+
for (const [name, value] of changes) if (name === VERSION_RECORD && value !== void 0) heard(value);
|
|
150
306
|
});
|
|
307
|
+
const stopChanges = cache.subscribe((changes) => {
|
|
308
|
+
const remote = changes.filter((change) => change.origin === "remote");
|
|
309
|
+
for (const change of remote) {
|
|
310
|
+
if (change.name === VERSION_RECORD && change.value !== void 0) heard(change.value);
|
|
311
|
+
}
|
|
312
|
+
if (remote.length > 0 && cache.writable) migrate();
|
|
313
|
+
versioned ||= cache.has(VERSION_RECORD);
|
|
314
|
+
});
|
|
315
|
+
return () => {
|
|
316
|
+
stopped = true;
|
|
317
|
+
stopOverruled();
|
|
318
|
+
stopChanges();
|
|
319
|
+
};
|
|
151
320
|
}
|
|
152
|
-
|
|
153
|
-
// src/repair.ts
|
|
154
321
|
function repairPrefValue(leaf, stored, validators) {
|
|
155
322
|
if (leaf.kind === "number") {
|
|
156
323
|
if (stored === "Infinity") stored = Infinity;
|
|
@@ -180,14 +347,45 @@ function repairPrefValue(leaf, stored, validators) {
|
|
|
180
347
|
return e.options.some((o) => o.value === stored) ? stored : leaf.default;
|
|
181
348
|
}
|
|
182
349
|
case "object":
|
|
183
|
-
if (
|
|
184
|
-
return leaf.default;
|
|
350
|
+
if (isPlainObject(stored)) return repairFields(leaf, stored, validators);
|
|
351
|
+
return leaf.fromScalar ? stored : leaf.default;
|
|
352
|
+
case "map":
|
|
353
|
+
return repairMap(leaf, stored, validators);
|
|
354
|
+
case "union": {
|
|
355
|
+
const variant = prefVariantOf(leaf, stored);
|
|
356
|
+
return variant ? repairFields(variant[1], stored, validators) : leaf.default;
|
|
357
|
+
}
|
|
358
|
+
case "list":
|
|
359
|
+
return repairList(leaf, stored, validators);
|
|
185
360
|
default:
|
|
186
361
|
return stored;
|
|
187
362
|
}
|
|
188
363
|
}
|
|
189
|
-
function
|
|
190
|
-
|
|
364
|
+
function repairFields(leaf, stored, validators) {
|
|
365
|
+
let out;
|
|
366
|
+
for (const [key, field] of prefSectionLeaves(leaf.children)) {
|
|
367
|
+
if (!Object.hasOwn(stored, key) || stored[key] === void 0) continue;
|
|
368
|
+
const read = repairPrefValue(field, stored[key], validators);
|
|
369
|
+
if (read !== stored[key]) (out ??= { ...stored })[key] = read;
|
|
370
|
+
}
|
|
371
|
+
return out ?? stored;
|
|
372
|
+
}
|
|
373
|
+
function repairMap(leaf, stored, validators) {
|
|
374
|
+
if (!isPlainObject(stored)) return leaf.default;
|
|
375
|
+
const held = stored;
|
|
376
|
+
let out;
|
|
377
|
+
for (const [key, value] of Object.entries(held)) {
|
|
378
|
+
const read = repairPrefValue(leaf.item, value, validators);
|
|
379
|
+
if (read !== value) (out ??= { ...held })[key] = read;
|
|
380
|
+
}
|
|
381
|
+
return out ?? stored;
|
|
382
|
+
}
|
|
383
|
+
function repairList(leaf, stored, validators) {
|
|
384
|
+
if (!Array.isArray(stored)) return leaf.default;
|
|
385
|
+
if (leaf.minItems !== void 0 && stored.length < leaf.minItems) return leaf.default;
|
|
386
|
+
const kept = leaf.maxItems !== void 0 && stored.length > leaf.maxItems ? stored.slice(0, leaf.maxItems) : stored;
|
|
387
|
+
const read = kept.map((entry) => repairPrefValue(leaf.item, entry, validators));
|
|
388
|
+
return kept === stored && read.every((entry, i) => entry === stored[i]) ? stored : read;
|
|
191
389
|
}
|
|
192
390
|
function repairNumber(leaf, stored) {
|
|
193
391
|
if (typeof stored !== "number" || Number.isNaN(stored)) return leaf.default;
|
|
@@ -201,9 +399,30 @@ function repairNumber(leaf, stored) {
|
|
|
201
399
|
}
|
|
202
400
|
|
|
203
401
|
// src/store.ts
|
|
204
|
-
var encodeInfinity = (leaf, value) =>
|
|
205
|
-
|
|
206
|
-
|
|
402
|
+
var encodeInfinity = (leaf, value) => {
|
|
403
|
+
if (leaf.kind === "number") return value === Infinity || value === -Infinity ? String(value) : value;
|
|
404
|
+
if (leaf.kind === "list" && Array.isArray(value)) {
|
|
405
|
+
const { item } = leaf;
|
|
406
|
+
return value.map((entry) => encodeInfinity(item, entry));
|
|
407
|
+
}
|
|
408
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return value;
|
|
409
|
+
const held = value;
|
|
410
|
+
if (leaf.kind === "map") {
|
|
411
|
+
const { item } = leaf;
|
|
412
|
+
return Object.fromEntries(Object.entries(held).map(([key, entry]) => [key, encodeInfinity(item, entry)]));
|
|
413
|
+
}
|
|
414
|
+
const fields = leaf.kind === "union" ? prefVariantOf(leaf, held)?.[1] : leaf;
|
|
415
|
+
if (fields?.kind !== "object") return value;
|
|
416
|
+
let out;
|
|
417
|
+
for (const [key, field] of prefSectionLeaves(fields.children)) {
|
|
418
|
+
if (!Object.hasOwn(held, key)) continue;
|
|
419
|
+
const encoded = encodeInfinity(field, held[key]);
|
|
420
|
+
if (encoded !== held[key]) (out ??= { ...held })[key] = encoded;
|
|
421
|
+
}
|
|
422
|
+
return out ?? value;
|
|
423
|
+
};
|
|
424
|
+
function createPrefsStore(schema, cache, validators, onClose, version = 0) {
|
|
425
|
+
const leaves = new Map([...prefLeaves(schema)].filter(([, leaf]) => prefHoldsValue(leaf)));
|
|
207
426
|
let snapshot = null;
|
|
208
427
|
let previous = null;
|
|
209
428
|
const build = () => {
|
|
@@ -218,9 +437,10 @@ function createPrefsStore(schema, cache, validators, onClose) {
|
|
|
218
437
|
value = leaf.default;
|
|
219
438
|
unset.add(path);
|
|
220
439
|
} else {
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
440
|
+
const record = cache.get(path);
|
|
441
|
+
const stored = recordValue(record);
|
|
442
|
+
raw.set(path, record);
|
|
443
|
+
value = previous?.raw.has(path) && previous.raw.get(path) === record ? previous.byPath.get(path) : repairPrefValue(leaf, stored, validators);
|
|
224
444
|
}
|
|
225
445
|
byPath.set(path, value);
|
|
226
446
|
assignPrefValueAtPath(tree, path, value);
|
|
@@ -233,8 +453,9 @@ function createPrefsStore(schema, cache, validators, onClose) {
|
|
|
233
453
|
const buildStored = () => {
|
|
234
454
|
const tree = {};
|
|
235
455
|
const branches = new WeakSet([tree]);
|
|
236
|
-
for (const [name,
|
|
456
|
+
for (const [name, record] of cache.entries()) {
|
|
237
457
|
if (name === VERSION_RECORD) continue;
|
|
458
|
+
const value = recordValue(record);
|
|
238
459
|
const parts = name.split(".");
|
|
239
460
|
let cursor = tree;
|
|
240
461
|
for (const part of parts.slice(0, -1)) {
|
|
@@ -244,12 +465,12 @@ function createPrefsStore(schema, cache, validators, onClose) {
|
|
|
244
465
|
} else {
|
|
245
466
|
const branch = {};
|
|
246
467
|
branches.add(branch);
|
|
247
|
-
cursor
|
|
468
|
+
setOwnPrefValue(cursor, part, branch);
|
|
248
469
|
cursor = branch;
|
|
249
470
|
}
|
|
250
471
|
}
|
|
251
472
|
const last = parts[parts.length - 1];
|
|
252
|
-
if (!branches.has(cursor[last])) cursor
|
|
473
|
+
if (!branches.has(cursor[last])) setOwnPrefValue(cursor, last, value);
|
|
253
474
|
}
|
|
254
475
|
return tree;
|
|
255
476
|
};
|
|
@@ -273,7 +494,8 @@ function createPrefsStore(schema, cache, validators, onClose) {
|
|
|
273
494
|
console.warn(`[prefs] no leaf at "${path}"; ignoring the write`);
|
|
274
495
|
return;
|
|
275
496
|
}
|
|
276
|
-
|
|
497
|
+
const stored = encodeInfinity(leaf, value);
|
|
498
|
+
cache.set(path, stored === void 0 ? void 0 : stampRecord(stored, version));
|
|
277
499
|
},
|
|
278
500
|
reset: (path) => {
|
|
279
501
|
for (const p of leaves.keys()) {
|
|
@@ -293,6 +515,8 @@ function createPrefsStore(schema, cache, validators, onClose) {
|
|
|
293
515
|
get writable() {
|
|
294
516
|
return cache.writable;
|
|
295
517
|
},
|
|
518
|
+
read: () => cache.read(),
|
|
519
|
+
whenRead: () => cache.whenRead(),
|
|
296
520
|
flush: () => cache.flush(),
|
|
297
521
|
close: async () => {
|
|
298
522
|
onClose?.();
|
|
@@ -308,15 +532,43 @@ async function openPrefs(schema, options) {
|
|
|
308
532
|
const cache = await openRecords({ storage: options.storage, prefix: options.prefix });
|
|
309
533
|
const stop = watch(cache, options);
|
|
310
534
|
if (runPrefsMigrations(cache, options.migrations ?? [])) await cache.flush();
|
|
311
|
-
return createPrefsStore(schema, cache, options.validators, stop);
|
|
535
|
+
return createPrefsStore(schema, cache, options.validators, stop, options.migrations?.length ?? 0);
|
|
312
536
|
}
|
|
313
537
|
function openPrefsSync(schema, options) {
|
|
314
538
|
const cache = openRecordsSync({ storage: options.storage, prefix: options.prefix });
|
|
315
539
|
const stop = watch(cache, options);
|
|
316
540
|
if (runPrefsMigrations(cache, options.migrations ?? [])) void cache.flush();
|
|
317
|
-
return createPrefsStore(schema, cache, options.validators, stop);
|
|
541
|
+
return createPrefsStore(schema, cache, options.validators, stop, options.migrations?.length ?? 0);
|
|
542
|
+
}
|
|
543
|
+
var watch = (cache, options) => watchPrefsVersion(cache, options.migrations ?? []);
|
|
544
|
+
|
|
545
|
+
// src/kinds.ts
|
|
546
|
+
var ONE = { compound: false, several: false };
|
|
547
|
+
var MANY = { compound: true, several: true };
|
|
548
|
+
var PREF_KIND_TRAITS = {
|
|
549
|
+
number: ONE,
|
|
550
|
+
boolean: ONE,
|
|
551
|
+
string: ONE,
|
|
552
|
+
enum: ONE,
|
|
553
|
+
color: ONE,
|
|
554
|
+
paint: ONE,
|
|
555
|
+
object: MANY,
|
|
556
|
+
list: MANY,
|
|
557
|
+
map: MANY,
|
|
558
|
+
union: MANY,
|
|
559
|
+
field: ONE,
|
|
560
|
+
action: { compound: false, several: true },
|
|
561
|
+
alias: ONE,
|
|
562
|
+
label: ONE,
|
|
563
|
+
separator: ONE
|
|
564
|
+
};
|
|
565
|
+
var traitsOf = (leaf) => Object.hasOwn(PREF_KIND_TRAITS, leaf.kind) ? PREF_KIND_TRAITS[leaf.kind] : ONE;
|
|
566
|
+
function prefIsCompound(leaf) {
|
|
567
|
+
return traitsOf(leaf).compound;
|
|
568
|
+
}
|
|
569
|
+
function prefDrawsSeveral(leaf) {
|
|
570
|
+
return traitsOf(leaf).several;
|
|
318
571
|
}
|
|
319
|
-
var watch = (cache, options) => cache.writable ? watchPrefsVersion(cache, (options.migrations ?? []).length) : void 0;
|
|
320
572
|
function prefUnit(system, display, opts) {
|
|
321
573
|
let self;
|
|
322
574
|
try {
|
|
@@ -356,7 +608,14 @@ var PREF_KINDS = {
|
|
|
356
608
|
color: true,
|
|
357
609
|
paint: true,
|
|
358
610
|
object: true,
|
|
359
|
-
|
|
611
|
+
list: true,
|
|
612
|
+
map: true,
|
|
613
|
+
union: true,
|
|
614
|
+
field: true,
|
|
615
|
+
action: true,
|
|
616
|
+
alias: true,
|
|
617
|
+
label: true,
|
|
618
|
+
separator: true
|
|
360
619
|
};
|
|
361
620
|
function pairRowsOf(leaves) {
|
|
362
621
|
const rows = /* @__PURE__ */ new Map();
|
|
@@ -373,6 +632,6 @@ function isBuiltinPref(leaf) {
|
|
|
373
632
|
return Object.hasOwn(PREF_KINDS, leaf.kind);
|
|
374
633
|
}
|
|
375
634
|
|
|
376
|
-
export { PREF_KINDS, VERSION_RECORD, filterPrefSubtree, flattenPrefValues, isBuiltinPref, isPrefLeaf, openPrefs, openPrefsSync, pairRowsOf, prefDisplayBounds, prefLeaves, prefUnit, prefValueAtPath, repairPrefValue, visiblePrefSubtree };
|
|
635
|
+
export { PREF_KINDS, PREF_KIND_TRAITS, VERSION_RECORD, filterPrefSubtree, flattenPrefValues, isBuiltinPref, isPrefLeaf, isPrefSection, openPrefs, openPrefsSync, pairRowsOf, prefAliasTarget, prefAliasedLeaf, prefDisplayBounds, prefDrawsSeveral, prefGroupIsPage, prefHoldsValue, prefIsCompound, prefLeafAt, prefLeaves, prefObjectBase, prefObjectWithField, prefSectionLeaves, prefType, prefUnit, prefValueAtPath, prefVariantDefault, prefVariantOf, repairPrefValue, visiblePrefSubtree };
|
|
377
636
|
//# sourceMappingURL=index.js.map
|
|
378
637
|
//# sourceMappingURL=index.js.map
|