effect-atom-svelte 0.3.0 → 0.4.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/README.md +4 -1
- package/dist/Form.d.ts +605 -0
- package/dist/Form.js +67 -0
- package/dist/Hooks.svelte.d.ts +54 -0
- package/dist/Hooks.svelte.js +98 -64
- package/dist/HydrationBoundary.svelte +4 -5
- package/dist/Inspector.js +49 -32
- package/dist/RegistryContext.js +3 -1
- package/dist/ScopedAtom.js +15 -7
- package/dist/SvelteKit.d.ts +46 -12
- package/dist/SvelteKit.js +130 -18
- package/dist/index.d.ts +9 -0
- package/dist/index.js +9 -0
- package/dist/internal/awaitWrite.d.ts +11 -0
- package/dist/internal/awaitWrite.js +27 -0
- package/dist/internal/boundaries.js +3 -1
- package/dist/internal/form/array.d.ts +21 -0
- package/dist/internal/form/array.js +57 -0
- package/dist/internal/form/constraints.d.ts +13 -0
- package/dist/internal/form/constraints.js +166 -0
- package/dist/internal/form/engine.d.ts +56 -0
- package/dist/internal/form/engine.js +842 -0
- package/dist/internal/form/engineOf.d.ts +26 -0
- package/dist/internal/form/engineOf.js +43 -0
- package/dist/internal/form/field.d.ts +30 -0
- package/dist/internal/form/field.js +68 -0
- package/dist/internal/form/group.d.ts +13 -0
- package/dist/internal/form/group.js +20 -0
- package/dist/internal/form/instance.d.ts +41 -0
- package/dist/internal/form/instance.js +135 -0
- package/dist/internal/form/issues.d.ts +23 -0
- package/dist/internal/form/issues.js +144 -0
- package/dist/internal/form/paths.d.ts +47 -0
- package/dist/internal/form/paths.js +175 -0
- package/dist/internal/form/types.d.ts +80 -0
- package/dist/internal/form/types.js +1 -0
- package/dist/internal/form/validationError.d.ts +13 -0
- package/dist/internal/form/validationError.js +6 -0
- package/dist/internal/hydration.js +3 -1
- package/dist/internal/nodeInternals.js +44 -11
- package/package.json +12 -10
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// Paths into a form's values, and the item keys that let state follow an array item when it moves.
|
|
2
|
+
// Internal: not exported from the package.
|
|
3
|
+
//
|
|
4
|
+
// Two kinds of path: an index path (["items", 0, "qty"]) addresses the values as they are now, and
|
|
5
|
+
// a key path (["items", 7, "qty"]) names array items by their key instead of their index. Touched
|
|
6
|
+
// state and errors are stored by key path, so they move with their item. Both are arrays of
|
|
7
|
+
// strings (object keys) and numbers (an index, or an item key).
|
|
8
|
+
import { Array as Arr, Equal, Predicate } from "effect";
|
|
9
|
+
/** A string for a key path, to use as a map key. */
|
|
10
|
+
export const pathId = (path) => JSON.stringify(path);
|
|
11
|
+
/** Parses a `pathId` back into its path. */
|
|
12
|
+
export const fromPathId = (id) => {
|
|
13
|
+
const path = JSON.parse(id);
|
|
14
|
+
// SAFETY: every id comes from `pathId`, which stringifies a KeyPath.
|
|
15
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- JSON.parse can't say what it parsed, and the id is only ever pathId's
|
|
16
|
+
return path;
|
|
17
|
+
};
|
|
18
|
+
const isRecord = Predicate.isObject;
|
|
19
|
+
/** The value at `path`, or `undefined` when a step is missing. */
|
|
20
|
+
export const getIn = (root, path) => {
|
|
21
|
+
let current = root;
|
|
22
|
+
for (const segment of path) {
|
|
23
|
+
if (Array.isArray(current) && typeof segment === "number") {
|
|
24
|
+
current = current[segment];
|
|
25
|
+
}
|
|
26
|
+
else if (isRecord(current) && typeof segment === "string") {
|
|
27
|
+
current = current[segment];
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return current;
|
|
34
|
+
};
|
|
35
|
+
/** A copy of `root` with `value` at `path`, sharing everything off the path. */
|
|
36
|
+
export const setIn = (root, path, value) => {
|
|
37
|
+
if (path.length === 0) {
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
const [head, ...rest] = path;
|
|
41
|
+
if (typeof head === "number") {
|
|
42
|
+
const array = Arr.isArray(root) ? [...root] : [];
|
|
43
|
+
array[head] = setIn(array[head], rest, value);
|
|
44
|
+
return array;
|
|
45
|
+
}
|
|
46
|
+
if (head === undefined) {
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
const record = isRecord(root) ? root : {};
|
|
50
|
+
return {
|
|
51
|
+
...record,
|
|
52
|
+
[head]: setIn(record[head], rest, value),
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
/** Whether `path` starts with `prefix`. */
|
|
56
|
+
export const startsWith = (path, prefix) => prefix.length <= path.length &&
|
|
57
|
+
prefix.every((segment, index) => path[index] === segment);
|
|
58
|
+
/**
|
|
59
|
+
* The key path for an index path, or `undefined` when an index has no item. A number segment is an
|
|
60
|
+
* index only where the value so far is an array; a record's numeric-looking keys are strings.
|
|
61
|
+
*/
|
|
62
|
+
export const toKeyPath = (keys, path) => {
|
|
63
|
+
const out = [];
|
|
64
|
+
for (const segment of path) {
|
|
65
|
+
if (typeof segment === "number") {
|
|
66
|
+
const key = keys.get(pathId(out))?.[segment];
|
|
67
|
+
if (key === undefined) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
out.push(key);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
out.push(segment);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return out;
|
|
77
|
+
};
|
|
78
|
+
/** The index path for a key path, or `undefined` when one of its items is gone. */
|
|
79
|
+
export const toIndexPath = (keys, path) => {
|
|
80
|
+
const out = [];
|
|
81
|
+
for (const [position, segment] of path.entries()) {
|
|
82
|
+
if (typeof segment === "number") {
|
|
83
|
+
const arrayKeys = keys.get(pathId(path.slice(0, position)));
|
|
84
|
+
const index = arrayKeys?.indexOf(segment) ?? -1;
|
|
85
|
+
if (index < 0) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
out.push(index);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
out.push(segment);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return out;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Item keys for every array in `values`. Arrays that already have keys keep them, by position, and
|
|
98
|
+
* new positions take fresh keys from `next`; keys for arrays that are gone are dropped.
|
|
99
|
+
*/
|
|
100
|
+
export const reconcileKeys = (values, previous, next) => {
|
|
101
|
+
const out = new Map();
|
|
102
|
+
const walk = (value, path) => {
|
|
103
|
+
if (Array.isArray(value)) {
|
|
104
|
+
const id = pathId(path);
|
|
105
|
+
const old = previous.get(id) ?? [];
|
|
106
|
+
const keys = old.length === value.length
|
|
107
|
+
? old
|
|
108
|
+
: Array.from({ length: value.length }, (_, index) => old[index] ?? next());
|
|
109
|
+
out.set(id, keys);
|
|
110
|
+
for (const [index, item] of value.entries()) {
|
|
111
|
+
const key = keys[index];
|
|
112
|
+
if (key !== undefined) {
|
|
113
|
+
walk(item, [...path, key]);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else if (isRecord(value)) {
|
|
118
|
+
for (const [key, item] of Object.entries(value)) {
|
|
119
|
+
walk(item, [...path, key]);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
walk(values, []);
|
|
124
|
+
return out;
|
|
125
|
+
};
|
|
126
|
+
/** Whether every item key in `path` still belongs to its array. */
|
|
127
|
+
export const isLive = (keys, path) => toIndexPath(keys, path) !== undefined;
|
|
128
|
+
// An object literal, or one made with `Object.create(null)`: not a class instance.
|
|
129
|
+
const isPlain = (value) => {
|
|
130
|
+
const prototype = Object.getPrototypeOf(value);
|
|
131
|
+
return prototype === Object.prototype || prototype === null;
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Equality for form values. Arrays and plain objects compare by content, with a key set to
|
|
135
|
+
* `undefined` the same as a missing one; dates by time; values that implement Effect's `Equal`
|
|
136
|
+
* (`Option`, `HashMap`) by `Equal.equals`. Any other class instance compares by identity: a
|
|
137
|
+
* `File`, a `Map`, and also a `Data.Class` or `Schema.Class` value, which in Effect 4 doesn't
|
|
138
|
+
* implement `Equal`. So a fresh instance with the same content counts as a change.
|
|
139
|
+
*/
|
|
140
|
+
export const equals = (a, b) => {
|
|
141
|
+
if (Object.is(a, b)) {
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
if (a instanceof Date && b instanceof Date) {
|
|
145
|
+
return a.getTime() === b.getTime();
|
|
146
|
+
}
|
|
147
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
148
|
+
return (a.length === b.length && a.every((item, index) => equals(item, b[index])));
|
|
149
|
+
}
|
|
150
|
+
if (Equal.isEqual(a) && Equal.isEqual(b)) {
|
|
151
|
+
return Equal.equals(a, b);
|
|
152
|
+
}
|
|
153
|
+
if (isRecord(a) && isRecord(b) && isPlain(a) && isPlain(b)) {
|
|
154
|
+
const keysA = Object.keys(a).filter((key) => a[key] !== undefined);
|
|
155
|
+
const keysB = Object.keys(b).filter((key) => b[key] !== undefined);
|
|
156
|
+
return (keysA.length === keysB.length &&
|
|
157
|
+
keysA.every((key) => equals(a[key], b[key])));
|
|
158
|
+
}
|
|
159
|
+
return false;
|
|
160
|
+
};
|
|
161
|
+
// One character of a key that isn't a letter or a digit, as `_` and its code in hex: `-` is `_2d`.
|
|
162
|
+
const escapeChar = (char) => `_${(char.codePointAt(0) ?? 0).toString(16)}_`;
|
|
163
|
+
/**
|
|
164
|
+
* A string for a key path that is safe in an element id and different for every path:
|
|
165
|
+
* `items-_7-qty`. Segments are joined with `-`, an item key is `_` and the number, and any other
|
|
166
|
+
* character of a key than a letter or a digit is escaped (`a-b` is `a_2d_b`), so a key can't
|
|
167
|
+
* produce a `-` or an item key's form.
|
|
168
|
+
*/
|
|
169
|
+
export const idSuffix = (path) => path
|
|
170
|
+
.map((segment) => typeof segment === "number"
|
|
171
|
+
? `_${segment}`
|
|
172
|
+
: segment.replaceAll(/[^A-Za-z0-9]/gu, escapeChar))
|
|
173
|
+
.join("-");
|
|
174
|
+
/** The `name` attribute for an index path: `items.0.qty`. */
|
|
175
|
+
export const nameOf = (path) => path.join(".");
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { Cause, Option, Schema } from "effect";
|
|
2
|
+
import type { AsyncResult, Atom, AtomRegistry } from "effect/reactivity";
|
|
3
|
+
import type { CheckHook, LeafHook } from "./issues.ts";
|
|
4
|
+
import type { IndexPath, Keys } from "./paths.ts";
|
|
5
|
+
/**
|
|
6
|
+
* When a field's error shows: as the user types, when they leave it, or only on submit. The Schema
|
|
7
|
+
* checks every change whatever the timing.
|
|
8
|
+
*/
|
|
9
|
+
export type Timing = "submit" | "blur" | "input";
|
|
10
|
+
/** Where an error came from, which decides when it clears. */
|
|
11
|
+
export type ErrorSource = "schema" | "submit" | "manual";
|
|
12
|
+
/** Errors to put on a form: per top-level field, per path, and form-level. */
|
|
13
|
+
export interface ErrorsInput {
|
|
14
|
+
readonly fields?: Readonly<Record<string, string | undefined>> | undefined;
|
|
15
|
+
readonly paths?: readonly (readonly [IndexPath | string, string])[] | undefined;
|
|
16
|
+
readonly form?: string | undefined;
|
|
17
|
+
}
|
|
18
|
+
/** A definition's settings, shared by every instance. */
|
|
19
|
+
export interface Definition {
|
|
20
|
+
readonly schema: Schema.Top;
|
|
21
|
+
/**
|
|
22
|
+
* The form's name, for its atoms' labels (`SignUp.values`). Writable: the devtools' Vite plugin
|
|
23
|
+
* fills it in from the variable a definition is declared as, when `Form.make` was given none.
|
|
24
|
+
*/
|
|
25
|
+
name: string | undefined;
|
|
26
|
+
/** An `Atom.AtomRuntime`, kept untyped: only its `fn` is used. */
|
|
27
|
+
readonly runtime?: unknown;
|
|
28
|
+
readonly validateOn: Timing;
|
|
29
|
+
readonly revalidateOn: Timing;
|
|
30
|
+
readonly debounce: number;
|
|
31
|
+
readonly leafHook?: LeafHook | undefined;
|
|
32
|
+
readonly checkHook?: CheckHook | undefined;
|
|
33
|
+
}
|
|
34
|
+
/** One instance's settings. */
|
|
35
|
+
export interface EngineOptions {
|
|
36
|
+
readonly registry: AtomRegistry.AtomRegistry;
|
|
37
|
+
readonly id: string;
|
|
38
|
+
readonly initialValues: unknown;
|
|
39
|
+
readonly values?: Atom.Writable<unknown> | undefined;
|
|
40
|
+
readonly submit?: {
|
|
41
|
+
readonly atom: () => Atom.Writable<AsyncResult.AsyncResult<unknown, unknown>, unknown>;
|
|
42
|
+
readonly payload?: ((decoded: unknown, args: unknown) => unknown) | undefined;
|
|
43
|
+
} | undefined;
|
|
44
|
+
readonly mapError?: ((error: unknown) => ErrorsInput | undefined) | undefined;
|
|
45
|
+
readonly autoSubmit?: boolean | undefined;
|
|
46
|
+
readonly resetOnSuccess?: boolean | undefined;
|
|
47
|
+
/** Whether validation runs at all: not while rendering on the server. */
|
|
48
|
+
readonly validates: boolean;
|
|
49
|
+
}
|
|
50
|
+
export interface ExternalError {
|
|
51
|
+
readonly message: string;
|
|
52
|
+
readonly source: "submit" | "manual";
|
|
53
|
+
}
|
|
54
|
+
/** An instance's state, in one atom. Error maps are keyed by `pathId` of a key path. */
|
|
55
|
+
export interface State {
|
|
56
|
+
readonly initial: unknown;
|
|
57
|
+
readonly keys: Keys;
|
|
58
|
+
readonly touched: ReadonlySet<string>;
|
|
59
|
+
/** Schema errors on show, by path. A path drops out once its check passes. */
|
|
60
|
+
readonly revealed: ReadonlySet<string>;
|
|
61
|
+
/** Paths that have shown an error since the last reset: they follow `revalidateOn`. */
|
|
62
|
+
readonly shown: ReadonlySet<string>;
|
|
63
|
+
/** The latest validation run's messages, in the Schema's order. */
|
|
64
|
+
readonly issues: ReadonlyMap<string, string>;
|
|
65
|
+
/** The values that run decoded, to tell whether its result is current. */
|
|
66
|
+
readonly checked: unknown;
|
|
67
|
+
readonly decoded: Option.Option<unknown>;
|
|
68
|
+
/** Why the latest run couldn't decode at all (a defect, a runtime that failed), if it couldn't. */
|
|
69
|
+
readonly failure: Cause.Cause<unknown> | undefined;
|
|
70
|
+
readonly validating: boolean;
|
|
71
|
+
readonly external: ReadonlyMap<string, ExternalError>;
|
|
72
|
+
readonly submitCount: number;
|
|
73
|
+
readonly validationCount: number;
|
|
74
|
+
readonly submitting: boolean;
|
|
75
|
+
readonly submitResult: AsyncResult.AsyncResult<unknown, unknown>;
|
|
76
|
+
readonly lastSubmitted: Option.Option<{
|
|
77
|
+
readonly encoded: unknown;
|
|
78
|
+
readonly decoded: unknown;
|
|
79
|
+
}>;
|
|
80
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { IndexPath } from "./paths.ts";
|
|
2
|
+
declare const FormValidationError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
3
|
+
readonly _tag: "FormValidationError";
|
|
4
|
+
} & Readonly<A>;
|
|
5
|
+
/** A form's validation failure, as `submit` reports it. */
|
|
6
|
+
export declare class FormValidationError extends FormValidationError_base<{
|
|
7
|
+
readonly errors: readonly {
|
|
8
|
+
readonly path: IndexPath;
|
|
9
|
+
readonly message: string;
|
|
10
|
+
}[];
|
|
11
|
+
}> {
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// The failure a form's submit reports when its values don't decode. Internal: `Form.ts` exports it.
|
|
2
|
+
import { Data } from "effect";
|
|
3
|
+
/** A form's validation failure, as `submit` reports it. */
|
|
4
|
+
// oxlint-disable-next-line effecttsgo/prefer-schema-tagged-error -- a local error that never crosses the network; a Schema class would change Form.ValidationError's public type and check its fields on every construction
|
|
5
|
+
export class FormValidationError extends Data.TaggedError("FormValidationError") {
|
|
6
|
+
}
|
|
@@ -14,7 +14,9 @@ export const setRevalidateOnHydrate = (value) => {
|
|
|
14
14
|
* Whether a hook runs its atom again once the page has hydrated: its own option, else the nearest
|
|
15
15
|
* provider's, else no (JND-19). Call during component init.
|
|
16
16
|
*/
|
|
17
|
-
export const revalidatesOnHydrate = (
|
|
17
|
+
export const revalidatesOnHydrate = (
|
|
18
|
+
// oxlint-disable-next-line sonarjs/bool-param-default -- undefined is "the hook gave no option", which a default would erase
|
|
19
|
+
option) => option ?? (hasDefault() ? getDefault() : false);
|
|
18
20
|
/**
|
|
19
21
|
* What the server sends for a result it doesn't pass on, so the browser computes the atom itself.
|
|
20
22
|
* An encoded `AsyncResult` is an object, never `null`.
|
|
@@ -1,7 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
// The one place the inspector (../Inspector.ts) relies on how Effect implements AtomRegistry rather
|
|
2
|
+
// than on its public API. Written against effect 4.0.1 (effect/src/reactivity/AtomRegistry.ts); the
|
|
3
|
+
// peer range is ~4.0.0 because of code like this.
|
|
4
|
+
//
|
|
5
|
+
// The public `AtomRegistry` announces nodes added and removed (`onNodeAdded`, `onNodeRemoved`), and
|
|
6
|
+
// a `Node` shows its parents, children and listeners. It says nothing when a node's value changes,
|
|
7
|
+
// when it computes, when what a computation started is torn down or when its listeners change.
|
|
8
|
+
// Each of those goes through a member of the implementation's node (`NodeImpl`), which is replaced
|
|
9
|
+
// on that one node:
|
|
10
|
+
//
|
|
11
|
+
// - `build()`: computes the node's value, running the atom's `read`. Wrapped, for when a
|
|
12
|
+
// computation starts and ends.
|
|
13
|
+
// - `_value`: the node's value. Written by `setValue` (a computation's result, `setSelf`, a write)
|
|
14
|
+
// and `setInitialValue`, and only when the value is not equal to the last. Made an accessor.
|
|
15
|
+
// - `lifetime`: what the current computation holds. `disposeLifetime` clears it, then runs its
|
|
16
|
+
// `finalizers`, which interrupt the fiber of an effect atom that hasn't finished. That happens
|
|
17
|
+
// before every recomputation and when the node is removed. Made an accessor.
|
|
18
|
+
// - `listeners`: public, but only as a set to read. Everything that reads an atom reactively
|
|
19
|
+
// (`AtomRegistry.subscribe` and `mount`, an atom's `get.subscribe`, the hooks' `holdNode`) adds
|
|
20
|
+
// to it and deletes from it through the node's field, so a set put in its place hears each one,
|
|
21
|
+
// including the deletes of subscriptions made before.
|
|
22
|
+
//
|
|
23
|
+
// A node that lacks any of them is left alone (`instrumentNode` returns false), so a change in
|
|
24
|
+
// Effect stops the inspector from reporting rather than breaking the registry.
|
|
25
|
+
//
|
|
26
|
+
// docs/proposals/atom-registry-inspector.md proposes an API in Effect that would replace this file.
|
|
27
|
+
import { Predicate } from "effect";
|
|
28
|
+
const isNodeImpl = (node) => {
|
|
29
|
+
if (!(Object.hasOwn(node, "_value") && Object.hasOwn(node, "lifetime"))) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return ("build" in node &&
|
|
33
|
+
typeof node.build === "function" &&
|
|
34
|
+
node.listeners instanceof Set);
|
|
35
|
+
};
|
|
5
36
|
/** A node's listeners that report each one added or removed. */
|
|
6
37
|
class Listeners extends Set {
|
|
7
38
|
#changed;
|
|
@@ -92,16 +123,18 @@ export const instrumentNode = (node, hooks) => {
|
|
|
92
123
|
* which the implementation keeps but the interface doesn't show.
|
|
93
124
|
*/
|
|
94
125
|
export const defaultIdleTTL = (registry) => {
|
|
95
|
-
const ttl = registry
|
|
96
|
-
.defaultIdleTTL;
|
|
126
|
+
const ttl = "defaultIdleTTL" in registry ? registry.defaultIdleTTL : undefined;
|
|
97
127
|
return typeof ttl === "number" ? ttl : undefined;
|
|
98
128
|
};
|
|
99
129
|
/** Whether the node holds an initial value it hasn't computed (setInitialValue on a new node). */
|
|
100
|
-
export const holdsInitialValue = (node) => node
|
|
101
|
-
.preserveInitialValueOnBuild === true;
|
|
130
|
+
export const holdsInitialValue = (node) => "preserveInitialValueOnBuild" in node &&
|
|
131
|
+
node.preserveInitialValueOnBuild === true;
|
|
102
132
|
/** Whether the node is building and its running build has not read `parent` yet. */
|
|
103
133
|
export const buildWillRead = (node, parent) => {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
134
|
+
// The lifetime is the build's `get`, a function.
|
|
135
|
+
const lifetime = "lifetime" in node ? node.lifetime : undefined;
|
|
136
|
+
const reads = Predicate.hasProperty(lifetime, "reads")
|
|
137
|
+
? lifetime.reads
|
|
138
|
+
: undefined;
|
|
139
|
+
return reads instanceof Set && !reads.has(parent);
|
|
107
140
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "effect-atom-svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Community-built Svelte 5 bindings for Effect Atom (not affiliated with the Effect team)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"effect",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
"scripts": {
|
|
47
47
|
"build": "svelte-package -i src -o dist",
|
|
48
|
-
"check": "svelte-check --tsconfig ./tsconfig.json && bun scripts/check-docs.ts",
|
|
48
|
+
"check": "svelte-check --tsconfig ./tsconfig.json && tsc -p scripts && bun scripts/check-docs.ts",
|
|
49
49
|
"test": "vitest run"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
@@ -53,16 +53,18 @@
|
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@demo/domain": "workspace:*",
|
|
56
|
-
"@sveltejs/package": "^3.0.
|
|
57
|
-
"@sveltejs/vite-plugin-svelte": "^7.
|
|
58
|
-
"@
|
|
59
|
-
"@vitest/browser
|
|
60
|
-
"
|
|
56
|
+
"@sveltejs/package": "^3.0.1",
|
|
57
|
+
"@sveltejs/vite-plugin-svelte": "^7.3.1",
|
|
58
|
+
"@types/bun": "^1.4.2",
|
|
59
|
+
"@vitest/browser": "^5.0.5",
|
|
60
|
+
"@vitest/browser-playwright": "^5.0.5",
|
|
61
|
+
"effect": "4.0.5",
|
|
61
62
|
"playwright": "^1.57.0",
|
|
62
63
|
"svelte": "^5.57.2",
|
|
63
|
-
"svelte-check": "^4.6
|
|
64
|
-
"
|
|
65
|
-
"
|
|
64
|
+
"svelte-check": "^4.7.6",
|
|
65
|
+
"typescript": "^6.0.3",
|
|
66
|
+
"vite": "^8.3.4",
|
|
67
|
+
"vitest": "^5.0.5",
|
|
66
68
|
"vitest-browser-svelte": "^3.1.0"
|
|
67
69
|
},
|
|
68
70
|
"peerDependencies": {
|