effect-atom-svelte 0.4.0 → 0.4.1
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/Form.d.ts
CHANGED
|
@@ -92,7 +92,11 @@ export interface MakeOptions {
|
|
|
92
92
|
readonly revalidateOn?: Timing | undefined;
|
|
93
93
|
/** How long to wait after a change before validating. Defaults to none. */
|
|
94
94
|
readonly debounce?: Duration.Input | undefined;
|
|
95
|
-
/**
|
|
95
|
+
/**
|
|
96
|
+
* A message for an issue that has no `message` annotation, or `undefined` for Effect's own. A
|
|
97
|
+
* value outside a union, such as one that isn't in a `Schema.Literals`, comes as an
|
|
98
|
+
* `InvalidType` whose `ast` is the union.
|
|
99
|
+
*/
|
|
96
100
|
readonly leafHook?: ((issue: SchemaIssue.Leaf) => string | undefined) | undefined;
|
|
97
101
|
/** A message for a failed check that has no `message` annotation, or `undefined` for Effect's. */
|
|
98
102
|
readonly checkHook?: ((issue: SchemaIssue.Filter) => string | undefined) | undefined;
|
|
@@ -9,5 +9,8 @@ export interface Constraints {
|
|
|
9
9
|
readonly max?: number | undefined;
|
|
10
10
|
readonly pattern?: string | undefined;
|
|
11
11
|
}
|
|
12
|
-
/**
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* The HTML constraints for the field at `path` in `schema`'s AST. `lengthAt` gives the length of the
|
|
14
|
+
* array at a path, read only for a tuple with elements after its rest.
|
|
15
|
+
*/
|
|
16
|
+
export declare const constraintsAt: (root: SchemaAST.AST, path: IndexPath, lengthAt: (path: IndexPath) => number | undefined) => Constraints;
|
|
@@ -104,13 +104,31 @@ const unwrap = (ast) => {
|
|
|
104
104
|
}
|
|
105
105
|
return ast;
|
|
106
106
|
};
|
|
107
|
+
// The element at `index`, picked as Effect's parser picks it (`Arrays.getParser` in `SchemaAST.ts`):
|
|
108
|
+
// a fixed element, else the rest element, except that the elements after the rest are counted back
|
|
109
|
+
// from the array's end. Those need its length; without one, there is no element.
|
|
110
|
+
const elementAt = (node, index, length) => {
|
|
111
|
+
if (index < node.elements.length) {
|
|
112
|
+
return node.elements[index];
|
|
113
|
+
}
|
|
114
|
+
const [rest, ...tail] = node.rest;
|
|
115
|
+
if (tail.length === 0) {
|
|
116
|
+
return rest;
|
|
117
|
+
}
|
|
118
|
+
const len = length();
|
|
119
|
+
if (len === undefined) {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
const threshold = Math.max(node.elements.length, len - tail.length);
|
|
123
|
+
return index >= threshold ? tail[index - threshold] : rest;
|
|
124
|
+
};
|
|
107
125
|
// The field at one step below `ast`, with whether its key is optional. In a union, the first member
|
|
108
126
|
// that has the step.
|
|
109
|
-
const step = (ast, segment) => {
|
|
127
|
+
const step = (ast, segment, length) => {
|
|
110
128
|
const node = unwrap(ast);
|
|
111
129
|
if (SchemaAST.isUnion(node)) {
|
|
112
130
|
for (const member of node.types) {
|
|
113
|
-
const found = step(member, segment);
|
|
131
|
+
const found = step(member, segment, length);
|
|
114
132
|
if (found !== undefined) {
|
|
115
133
|
return found;
|
|
116
134
|
}
|
|
@@ -124,7 +142,7 @@ const step = (ast, segment) => {
|
|
|
124
142
|
: { ast: property.type, optional: SchemaAST.isOptional(property.type) };
|
|
125
143
|
}
|
|
126
144
|
if (SchemaAST.isArrays(node) && typeof segment === "number") {
|
|
127
|
-
const element = node
|
|
145
|
+
const element = elementAt(node, segment, length);
|
|
128
146
|
return element === undefined
|
|
129
147
|
? undefined
|
|
130
148
|
: { ast: element, optional: SchemaAST.isOptional(element) };
|
|
@@ -139,19 +157,13 @@ const withoutUndefined = (ast) => {
|
|
|
139
157
|
const types = ast.types.filter((member) => member._tag !== "Undefined");
|
|
140
158
|
return types.length === 1 && types[0] !== undefined ? types[0] : ast;
|
|
141
159
|
};
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
found &&= step(found.ast, segment);
|
|
150
|
-
}
|
|
151
|
-
if (found === undefined) {
|
|
152
|
-
return {};
|
|
153
|
-
}
|
|
154
|
-
const { ast, optional } = found;
|
|
160
|
+
// A field's constraints depend only on its node and whether its key is optional, so each is read once.
|
|
161
|
+
const cache = {
|
|
162
|
+
optional: new WeakMap(),
|
|
163
|
+
required: new WeakMap(),
|
|
164
|
+
};
|
|
165
|
+
const none = {};
|
|
166
|
+
const read = (ast, optional) => {
|
|
155
167
|
const into = {};
|
|
156
168
|
readNode(withoutUndefined(ast), into);
|
|
157
169
|
// `required` means "not empty" to a browser, so it is set only where the Schema rejects an empty
|
|
@@ -164,3 +176,27 @@ export const constraintsAt = (root, path) => {
|
|
|
164
176
|
merge(out, into);
|
|
165
177
|
return out;
|
|
166
178
|
};
|
|
179
|
+
/**
|
|
180
|
+
* The HTML constraints for the field at `path` in `schema`'s AST. `lengthAt` gives the length of the
|
|
181
|
+
* array at a path, read only for a tuple with elements after its rest.
|
|
182
|
+
*/
|
|
183
|
+
export const constraintsAt = (root, path, lengthAt) => {
|
|
184
|
+
let found = {
|
|
185
|
+
ast: root,
|
|
186
|
+
optional: false,
|
|
187
|
+
};
|
|
188
|
+
for (const [depth, segment] of path.entries()) {
|
|
189
|
+
found &&= step(found.ast, segment, () => lengthAt(path.slice(0, depth)));
|
|
190
|
+
}
|
|
191
|
+
if (found === undefined) {
|
|
192
|
+
return none;
|
|
193
|
+
}
|
|
194
|
+
const { ast, optional } = found;
|
|
195
|
+
const byNode = optional ? cache.optional : cache.required;
|
|
196
|
+
let constraints = byNode.get(ast);
|
|
197
|
+
if (constraints === undefined) {
|
|
198
|
+
constraints = read(ast, optional);
|
|
199
|
+
byNode.set(ast, constraints);
|
|
200
|
+
}
|
|
201
|
+
return constraints;
|
|
202
|
+
};
|
|
@@ -89,7 +89,6 @@ export class Engine {
|
|
|
89
89
|
#fields = new Map();
|
|
90
90
|
#groups = new Map();
|
|
91
91
|
#arrays = new Map();
|
|
92
|
-
#constraints = new Map();
|
|
93
92
|
constructor(definition, options) {
|
|
94
93
|
this.definition = definition;
|
|
95
94
|
this.options = options;
|
|
@@ -784,14 +783,11 @@ export class Engine {
|
|
|
784
783
|
: `${this.options.id}-${idSuffix(path)}`;
|
|
785
784
|
}
|
|
786
785
|
constraints(path) {
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
this.#constraints.set(id, found);
|
|
793
|
-
}
|
|
794
|
-
return found;
|
|
786
|
+
// Reads the values only for a tuple with elements after its rest, whose fields move as it grows.
|
|
787
|
+
return constraintsAt(this.definition.schema.ast, path, (arrayPath) => {
|
|
788
|
+
const array = getIn(this.values, arrayPath);
|
|
789
|
+
return Array.isArray(array) ? array.length : undefined;
|
|
790
|
+
});
|
|
795
791
|
}
|
|
796
792
|
field(path) {
|
|
797
793
|
const id = pathId(path);
|
|
@@ -66,6 +66,9 @@ const emitDefault = (issue, path, emit) => {
|
|
|
66
66
|
emit([...path, ...(formatted.path ?? [])], formatted.message);
|
|
67
67
|
}
|
|
68
68
|
};
|
|
69
|
+
const asInvalidType = (issue) => new SchemaIssue.InvalidType(issue.ast, issue.input, {
|
|
70
|
+
reportInput: SchemaIssue.hasInput(issue),
|
|
71
|
+
});
|
|
69
72
|
const walkFilter = (issue, path, hooks, emit, walk) => {
|
|
70
73
|
const pointed = pointedPaths(issue.issue, path);
|
|
71
74
|
const annotated = findMessage(issue.issue) ?? findMessage(issue);
|
|
@@ -119,8 +122,13 @@ export const toPathIssues = (issue, hooks) => {
|
|
|
119
122
|
}
|
|
120
123
|
case "Composite":
|
|
121
124
|
case "AnyOf": {
|
|
122
|
-
|
|
123
|
-
|
|
125
|
+
// A value no member of the union applies to (one outside a Literals, say) fails with no
|
|
126
|
+
// inner issues. Effect's formatter reports it without calling a hook. Walked here as the
|
|
127
|
+
// InvalidType a single Literal gives, so `leafHook` names it, and the fallback is
|
|
128
|
+
// Effect's same `Expected "a" | "b"`.
|
|
129
|
+
if (current._tag === "AnyOf" && current.issues.length === 0) {
|
|
130
|
+
walk(asInvalidType(current), path);
|
|
131
|
+
return;
|
|
124
132
|
}
|
|
125
133
|
for (const inner of current.issues) {
|
|
126
134
|
walk(inner, path);
|