summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwen Jacobson <owen@grimoire.ca>2025-07-08 01:49:07 -0400
committerOwen Jacobson <owen@grimoire.ca>2025-07-08 01:55:36 -0400
commitaeb159c401ef446e6564e5a3643027560a3e22f4 (patch)
tree76d01d1804292906105c21372904d93362b3f61b
parent64d16441a390e889231f2f67333d5f305b7ab878 (diff)
Create "derivers," as an exception-free option for working with structured data in swatches.
This is meant to be used alongside `$derive`, for inputs with complex structure. For example: ```js let jsonInput = $state('{}'); let json = $derived(deriver.json(jsonInput)); // … <textarea bind:value={jsonInput}></textarea> ``` This allows textual editing of the data, while preventing exceptions due to syntax or logical errors in partially-edited data from breaking Svelte's derive process (see comments). Note that these exceptions are not considered [unexpected errors] by SvelteKit, because they do not arise "while handling a request;" they are considered errors by Svelte, but Svelte doesn't appear to provide any affordances for handling errors in this context, so we have to bring our own. [unexpected errors]: https://svelte.dev/docs/kit/errors#Unexpected-errors
-rw-r--r--ui/lib/swatch/derive.js20
1 files changed, 20 insertions, 0 deletions
diff --git a/ui/lib/swatch/derive.js b/ui/lib/swatch/derive.js
new file mode 100644
index 0000000..85547e8
--- /dev/null
+++ b/ui/lib/swatch/derive.js
@@ -0,0 +1,20 @@
+// A fun fact about $derive: if the deriving expression throws an error, then Svelte (at least as of
+// 5.20.2) _permanently_ stops evaluating it, even if the inputs change. To prevent this, you need
+// to ensure that derive expressions never raise an exception.
+function tryDerive(args, func, fallback) {
+ try {
+ return func(...args);
+ } catch (e) {
+ console.debug('deriver threw exception', e, func, args);
+ return fallback;
+ }
+}
+
+// A "deriver" is a function that never raises; if the underlying function would raise, the
+// corresponding deriver instead returns a fallback value (or `undefined`).
+export function makeDeriver(func, fallback) {
+ return (...args) => tryDerive(args, func, fallback);
+}
+
+// Some widely-used derivers, for convenience.
+export const json = makeDeriver(JSON.parse);