@whatsaaaa/form-builder-affects 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +186 -2
- package/definition.schema.json +8051 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.js +326 -0
- package/dist/index.js.map +1 -0
- package/package.json +62 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as v from "valibot";
|
|
2
|
+
import { SchemaExtension } from "@whatsaaaa/form-builder-schema";
|
|
3
|
+
/**
|
|
4
|
+
* What an affect does while its condition is met: `hide` hides the field and keeps its value,
|
|
5
|
+
* `hideAndClear` hides it and clears its value, and `show` shows it only then. Hide always wins.
|
|
6
|
+
*/
|
|
7
|
+
type Effect = 'show' | 'hide' | 'hideAndClear';
|
|
8
|
+
/** The value an operator compares with. */
|
|
9
|
+
type Scalar = string | number | boolean;
|
|
10
|
+
/**
|
|
11
|
+
* When an affect applies: a test of one field, by its dot path, with one operator, or every
|
|
12
|
+
* (`all`) or any (`any`) of a list of conditions.
|
|
13
|
+
*/
|
|
14
|
+
type Condition = {
|
|
15
|
+
field: string;
|
|
16
|
+
equals: Scalar;
|
|
17
|
+
} | {
|
|
18
|
+
field: string;
|
|
19
|
+
notEquals: Scalar;
|
|
20
|
+
} | {
|
|
21
|
+
field: string;
|
|
22
|
+
in: readonly Scalar[];
|
|
23
|
+
} | {
|
|
24
|
+
field: string;
|
|
25
|
+
includes: Scalar;
|
|
26
|
+
} | {
|
|
27
|
+
field: string;
|
|
28
|
+
empty: true;
|
|
29
|
+
} | {
|
|
30
|
+
field: string;
|
|
31
|
+
notEmpty: true;
|
|
32
|
+
} | {
|
|
33
|
+
all: readonly Condition[];
|
|
34
|
+
} | {
|
|
35
|
+
any: readonly Condition[];
|
|
36
|
+
};
|
|
37
|
+
/** One effect of a field, step or section, and when it applies. */
|
|
38
|
+
interface Affect {
|
|
39
|
+
effect: Effect;
|
|
40
|
+
when: Condition;
|
|
41
|
+
}
|
|
42
|
+
/** The key the package adds to fields, steps and sections. */
|
|
43
|
+
declare const affectsProps: v.ObjectSchema<{
|
|
44
|
+
readonly affects: v.OptionalSchema<v.ArraySchema<v.LazySchema<v.GenericSchema<Affect>>, undefined>, undefined>;
|
|
45
|
+
}, undefined>;
|
|
46
|
+
/** The extension `affects()` gives, with the type of the key it adds, for `defineForm()`. */
|
|
47
|
+
export interface AffectsExtension extends SchemaExtension {
|
|
48
|
+
readonly fieldProps: typeof affectsProps;
|
|
49
|
+
readonly layoutProps: typeof affectsProps;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Conditions on fields, steps and sections: `affects`, a list of effects (`show`, `hide`,
|
|
53
|
+
* `hideAndClear`), each with the condition that applies it. Pass it to the schema builder:
|
|
54
|
+
* `createSchemaBuilder({ extensions: [affects()] })`. The schema it builds skips the validation of
|
|
55
|
+
* hidden fields, and the builder's `getVisibility()` tells renderers what to hide and to clear.
|
|
56
|
+
*/
|
|
57
|
+
export declare function affects(): AffectsExtension;
|
|
58
|
+
export type { Affect, Condition, Effect, Scalar };
|
|
59
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import * as v from "valibot";
|
|
2
|
+
import { coerceInput } from "@whatsaaaa/form-builder-schema";
|
|
3
|
+
// src/definition/affect.ts
|
|
4
|
+
/** The operators of a test, each with the value it takes. */
|
|
5
|
+
const OPERATORS = [
|
|
6
|
+
"equals",
|
|
7
|
+
"notEquals",
|
|
8
|
+
"in",
|
|
9
|
+
"includes",
|
|
10
|
+
"empty",
|
|
11
|
+
"notEmpty"
|
|
12
|
+
];
|
|
13
|
+
const EFFECTS = [
|
|
14
|
+
"show",
|
|
15
|
+
"hide",
|
|
16
|
+
"hideAndClear"
|
|
17
|
+
];
|
|
18
|
+
const path = v.pipe(v.string(), v.minLength(1));
|
|
19
|
+
const scalar = v.union([
|
|
20
|
+
v.string(),
|
|
21
|
+
v.number(),
|
|
22
|
+
v.boolean()
|
|
23
|
+
]);
|
|
24
|
+
const conditions = v.pipe(v.array(v.lazy(() => condition)), v.minLength(1));
|
|
25
|
+
const condition = v.union([
|
|
26
|
+
v.strictObject({
|
|
27
|
+
field: path,
|
|
28
|
+
equals: scalar
|
|
29
|
+
}),
|
|
30
|
+
v.strictObject({
|
|
31
|
+
field: path,
|
|
32
|
+
notEquals: scalar
|
|
33
|
+
}),
|
|
34
|
+
v.strictObject({
|
|
35
|
+
field: path,
|
|
36
|
+
in: v.pipe(v.array(scalar), v.minLength(1))
|
|
37
|
+
}),
|
|
38
|
+
v.strictObject({
|
|
39
|
+
field: path,
|
|
40
|
+
includes: scalar
|
|
41
|
+
}),
|
|
42
|
+
v.strictObject({
|
|
43
|
+
field: path,
|
|
44
|
+
empty: v.literal(true)
|
|
45
|
+
}),
|
|
46
|
+
v.strictObject({
|
|
47
|
+
field: path,
|
|
48
|
+
notEmpty: v.literal(true)
|
|
49
|
+
}),
|
|
50
|
+
v.strictObject({ all: conditions }),
|
|
51
|
+
v.strictObject({ any: conditions })
|
|
52
|
+
]);
|
|
53
|
+
const affect = v.strictObject({
|
|
54
|
+
effect: v.picklist(EFFECTS),
|
|
55
|
+
when: v.lazy(() => condition)
|
|
56
|
+
});
|
|
57
|
+
/** The key the package adds to fields, steps and sections. */
|
|
58
|
+
const affectsProps = v.object({ affects: v.optional(v.array(v.lazy(() => affect))) });
|
|
59
|
+
// src/evaluate/evaluate.ts
|
|
60
|
+
/**
|
|
61
|
+
* Whether a condition is met. `read(i)` gives the input of the field of read `i`, or undefined
|
|
62
|
+
* while it is hidden: a hidden field is empty.
|
|
63
|
+
*
|
|
64
|
+
* An empty field never equals a value, and so is not equal to any: `notEquals` is true for it.
|
|
65
|
+
*/
|
|
66
|
+
function test(condition, read) {
|
|
67
|
+
if ("all" in condition) return condition.all.every((each) => test(each, read));
|
|
68
|
+
if ("any" in condition) return condition.any.some((each) => test(each, read));
|
|
69
|
+
const { operator, value, kind, itemKind, kindDef } = condition;
|
|
70
|
+
const input = coerceInput(read(condition.read), {
|
|
71
|
+
kind,
|
|
72
|
+
itemKind
|
|
73
|
+
});
|
|
74
|
+
const empty = input === void 0 || kindDef.isEmpty(input);
|
|
75
|
+
switch (operator) {
|
|
76
|
+
case "empty": return empty;
|
|
77
|
+
case "notEmpty": return !empty;
|
|
78
|
+
case "equals": return !empty && input === value;
|
|
79
|
+
case "notEquals": return empty || input !== value;
|
|
80
|
+
case "in": return !empty && value.includes(input);
|
|
81
|
+
case "includes": return !empty && Array.isArray(input) && input.includes(value);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Whether the affects of a target hide it, and clear it: an unmet `show`, a met `hide` or a met
|
|
86
|
+
* `hideAndClear` hides it, so hide always wins, and only a met `hideAndClear` clears it.
|
|
87
|
+
*/
|
|
88
|
+
function stateOf(effects, read) {
|
|
89
|
+
const shown = effects.show === void 0 || test(effects.show, read);
|
|
90
|
+
const hidden = effects.hide !== void 0 && test(effects.hide, read);
|
|
91
|
+
const clear = effects.hideAndClear !== void 0 && test(effects.hideAndClear, read);
|
|
92
|
+
return {
|
|
93
|
+
hidden: !shown || hidden || clear,
|
|
94
|
+
clear
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
// src/check/check-affects.ts
|
|
98
|
+
/** The kinds whose values a test can compare: a value is one string, number or boolean. */
|
|
99
|
+
const SCALAR_KINDS = [
|
|
100
|
+
"string",
|
|
101
|
+
"number",
|
|
102
|
+
"boolean",
|
|
103
|
+
"date"
|
|
104
|
+
];
|
|
105
|
+
/**
|
|
106
|
+
* Checks the `affects` of every field, step and section, and adds their issues. Returns the
|
|
107
|
+
* conditions of each one whose affects have no issues.
|
|
108
|
+
*/
|
|
109
|
+
function checkAffects(ctx) {
|
|
110
|
+
const found = /* @__PURE__ */ new Map();
|
|
111
|
+
for (const target of ctx.targets) {
|
|
112
|
+
if (!Object.hasOwn(target.json, "affects")) continue;
|
|
113
|
+
const conditions = checkTarget(target, ctx);
|
|
114
|
+
if (conditions) found.set(target, conditions);
|
|
115
|
+
}
|
|
116
|
+
return found;
|
|
117
|
+
}
|
|
118
|
+
/** The conditions of one target, or undefined when its affects have issues. */
|
|
119
|
+
function checkTarget(target, ctx) {
|
|
120
|
+
const issues = createIssues(ctx);
|
|
121
|
+
const path = [...target.definitionPath, "affects"];
|
|
122
|
+
const raw = target.json["affects"];
|
|
123
|
+
if (!Array.isArray(raw)) {
|
|
124
|
+
issues.add("invalid_shape", path, "\"affects\" is a list of { \"effect\", \"when\" }");
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (isItemField(target)) {
|
|
128
|
+
issues.add("invalid_shape", path, `The field of a list's items has no "affects" of its own. Put them on the list`);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const reads = [];
|
|
132
|
+
const effects = {};
|
|
133
|
+
raw.forEach((affect, j) => {
|
|
134
|
+
const at = [...path, j];
|
|
135
|
+
if (!isObject(affect)) {
|
|
136
|
+
issues.add("invalid_shape", at, "An affect is an object with \"effect\" and \"when\"");
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
issues.unknownKeys(affect, ["effect", "when"], at, "an affect");
|
|
140
|
+
const effect = affect["effect"];
|
|
141
|
+
if (!EFFECTS.includes(effect)) issues.add("invalid_shape", [...at, "effect"], "\"effect\" is \"show\", \"hide\" or \"hideAndClear\"");
|
|
142
|
+
else if (Object.hasOwn(effects, effect)) {
|
|
143
|
+
const message = `"${effect}" is in "affects" already. Join its conditions with "all" or "any"`;
|
|
144
|
+
issues.add("invalid_shape", at, message);
|
|
145
|
+
}
|
|
146
|
+
if (!Object.hasOwn(affect, "when")) {
|
|
147
|
+
issues.add("invalid_shape", at, "An affect needs \"when\", its condition");
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const compiled = checkCondition(affect["when"], [...at, "when"], target, ctx, issues, reads);
|
|
151
|
+
if (compiled && EFFECTS.includes(effect)) effects[effect] ??= compiled;
|
|
152
|
+
});
|
|
153
|
+
if (issues.count) return void 0;
|
|
154
|
+
return {
|
|
155
|
+
reads,
|
|
156
|
+
evaluate: (read) => stateOf(effects, read)
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Checks a condition, and compiles it, adding each field it reads to `reads`. Undefined when it
|
|
161
|
+
* has issues.
|
|
162
|
+
*/
|
|
163
|
+
function checkCondition(raw, at, target, ctx, issues, reads) {
|
|
164
|
+
if (!isObject(raw)) {
|
|
165
|
+
issues.add("invalid_shape", at, "A condition is an object: \"field\" with an operator, \"all\" or \"any\"");
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const groups = ["all", "any"].filter((key) => Object.hasOwn(raw, key));
|
|
169
|
+
const operators = OPERATORS.filter((key) => Object.hasOwn(raw, key));
|
|
170
|
+
const kinds = [...groups, ...Object.hasOwn(raw, "field") ? ["field"] : []];
|
|
171
|
+
if (kinds.length > 1) {
|
|
172
|
+
const keys = kinds.map((key) => `"${key}"`).join(" and ");
|
|
173
|
+
issues.add("invalid_shape", at, `A condition has one of "all", "any" and "field", not ${keys}`);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const [group] = groups;
|
|
177
|
+
if (group) {
|
|
178
|
+
issues.unknownKeys(raw, [group], at, "a condition");
|
|
179
|
+
const list = raw[group];
|
|
180
|
+
if (!Array.isArray(list) || !list.length) {
|
|
181
|
+
issues.add("invalid_shape", [...at, group], `"${group}" is a list of at least one condition`);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const compiled = list.map((each, k) => checkCondition(each, [
|
|
185
|
+
...at,
|
|
186
|
+
group,
|
|
187
|
+
k
|
|
188
|
+
], target, ctx, issues, reads));
|
|
189
|
+
if (!compiled.every((each) => each !== void 0)) return void 0;
|
|
190
|
+
return group === "all" ? { all: compiled } : { any: compiled };
|
|
191
|
+
}
|
|
192
|
+
const unknown = issues.unknownKeys(raw, ["field", ...OPERATORS], at, "a condition");
|
|
193
|
+
const field = raw["field"];
|
|
194
|
+
if (typeof field !== "string" || !field) issues.add("invalid_shape", [...at, "field"], "\"field\" is the dot path of a field, like \"address.city\"");
|
|
195
|
+
const [operator, other] = operators;
|
|
196
|
+
if (other) {
|
|
197
|
+
const keys = operators.map((key) => `"${key}"`).join(", ");
|
|
198
|
+
issues.add("invalid_shape", at, `A condition has one operator, not ${keys}`);
|
|
199
|
+
} else if (!operator && !unknown) {
|
|
200
|
+
const message = `A condition needs an operator: ${OPERATORS.map((key) => `"${key}"`).join(", ")}`;
|
|
201
|
+
issues.add("invalid_shape", at, message);
|
|
202
|
+
}
|
|
203
|
+
if (typeof field !== "string" || !field || !operator || other) return void 0;
|
|
204
|
+
const value = checkValueShape(operator, raw[operator], [...at, operator], issues);
|
|
205
|
+
if (value === void 0) return void 0;
|
|
206
|
+
const resolved = ctx.resolve(field, target);
|
|
207
|
+
if (typeof resolved === "string") issues.add("unknown_field", [...at, "field"], resolved);
|
|
208
|
+
if (typeof resolved === "string" || resolved === null) return void 0;
|
|
209
|
+
if (!checkKind(operator, resolved, field, [...at, operator], issues)) return void 0;
|
|
210
|
+
if (!checkValues(operator, value, resolved, field, [...at, operator], issues)) return void 0;
|
|
211
|
+
reads.push({
|
|
212
|
+
field: resolved,
|
|
213
|
+
at: [...at, "field"]
|
|
214
|
+
});
|
|
215
|
+
return {
|
|
216
|
+
read: reads.length - 1,
|
|
217
|
+
operator,
|
|
218
|
+
value,
|
|
219
|
+
kind: resolved.kind,
|
|
220
|
+
itemKind: resolved.item?.kind,
|
|
221
|
+
kindDef: resolved.kindDef
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
/** The operator's value when it has the right shape, or undefined with an issue. */
|
|
225
|
+
function checkValueShape(operator, value, at, issues) {
|
|
226
|
+
switch (operator) {
|
|
227
|
+
case "empty":
|
|
228
|
+
case "notEmpty":
|
|
229
|
+
if (value === true) return true;
|
|
230
|
+
issues.add("invalid_shape", at, `"${operator}" is true. For the opposite, use "${operator === "empty" ? "notEmpty" : "empty"}"`);
|
|
231
|
+
return;
|
|
232
|
+
case "in":
|
|
233
|
+
if (Array.isArray(value) && value.length && value.every(isScalar)) return value;
|
|
234
|
+
issues.add("invalid_shape", at, "\"in\" is a list of at least one string, number or boolean");
|
|
235
|
+
return;
|
|
236
|
+
default:
|
|
237
|
+
if (isScalar(value)) return value;
|
|
238
|
+
issues.add("invalid_shape", at, `"${operator}" is a string, a number or a boolean`);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/** True when the operator fits the field's kind. Adds a `kind_mismatch` issue when it doesn't. */
|
|
243
|
+
function checkKind(operator, field, dotPath, at, issues) {
|
|
244
|
+
const { kind, item } = field;
|
|
245
|
+
let fits;
|
|
246
|
+
let what = `${kind} fields`;
|
|
247
|
+
if (operator === "empty" || operator === "notEmpty") fits = kind !== "object";
|
|
248
|
+
else if (operator === "includes") {
|
|
249
|
+
fits = kind === "array" && !!item && SCALAR_KINDS.includes(item.kind);
|
|
250
|
+
what = kind !== "array" ? what : `lists of ${item ? `${item.kind} items` : "objects"}`;
|
|
251
|
+
} else fits = SCALAR_KINDS.includes(kind);
|
|
252
|
+
if (!fits) issues.add("kind_mismatch", at, `"${operator}" can't be used on ${what}, like "${dotPath}"`);
|
|
253
|
+
return fits;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* True when the field can hold each value the operator compares with: its schema, or that of its
|
|
257
|
+
* items for `includes`, takes it, and it isn't empty. Adds an `invalid_value` issue for each it
|
|
258
|
+
* can't.
|
|
259
|
+
*/
|
|
260
|
+
function checkValues(operator, value, field, dotPath, at, issues) {
|
|
261
|
+
if (operator === "empty" || operator === "notEmpty") return true;
|
|
262
|
+
const schema = operator === "includes" ? field.item.schema : field.schema;
|
|
263
|
+
const values = operator === "in" ? value : [value];
|
|
264
|
+
let valid = true;
|
|
265
|
+
values.forEach((each, k) => {
|
|
266
|
+
const where = operator === "in" ? [...at, k] : at;
|
|
267
|
+
if (operator !== "includes" && field.kindDef.isEmpty(each)) {
|
|
268
|
+
const message = `${JSON.stringify(each)} is no value, so it never matches. Use "empty" or "notEmpty"`;
|
|
269
|
+
issues.add("invalid_value", where, message);
|
|
270
|
+
valid = false;
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const result = v.safeParse(schema, each);
|
|
274
|
+
if (result.success) return;
|
|
275
|
+
const reason = result.issues[0].message;
|
|
276
|
+
issues.add("invalid_value", where, `"${dotPath}" can't hold ${JSON.stringify(each)}: ${reason}`);
|
|
277
|
+
valid = false;
|
|
278
|
+
});
|
|
279
|
+
return valid;
|
|
280
|
+
}
|
|
281
|
+
/** True for the field of a list's items, which has a value and no name: its value is the item. */
|
|
282
|
+
function isItemField(target) {
|
|
283
|
+
return target.kind === "field" && target.field.field.name === void 0 && target.field.kind !== "none" && target.field.dataPath.at(-1) === "*";
|
|
284
|
+
}
|
|
285
|
+
function createIssues(ctx) {
|
|
286
|
+
let count = 0;
|
|
287
|
+
const issues = {
|
|
288
|
+
get count() {
|
|
289
|
+
return count;
|
|
290
|
+
},
|
|
291
|
+
add(code, path, message) {
|
|
292
|
+
count++;
|
|
293
|
+
ctx.issue(code, path, message);
|
|
294
|
+
},
|
|
295
|
+
unknownKeys(raw, known, at, what) {
|
|
296
|
+
const unknown = Object.keys(raw).filter((key) => !known.includes(key));
|
|
297
|
+
for (const key of unknown) issues.add("unknown_key", [...at, key], `Unknown key "${key}" on ${what}`);
|
|
298
|
+
return unknown.length > 0;
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
return issues;
|
|
302
|
+
}
|
|
303
|
+
const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
304
|
+
const isScalar = (value) => typeof value === "string" || typeof value === "number" && Number.isFinite(value) || typeof value === "boolean";
|
|
305
|
+
// src/index.ts
|
|
306
|
+
/**
|
|
307
|
+
* Conditions on fields, steps and sections: `affects`, a list of effects (`show`, `hide`,
|
|
308
|
+
* `hideAndClear`), each with the condition that applies it. Pass it to the schema builder:
|
|
309
|
+
* `createSchemaBuilder({ extensions: [affects()] })`. The schema it builds skips the validation of
|
|
310
|
+
* hidden fields, and the builder's `getVisibility()` tells renderers what to hide and to clear.
|
|
311
|
+
*/
|
|
312
|
+
function affects() {
|
|
313
|
+
return {
|
|
314
|
+
name: "affects",
|
|
315
|
+
fieldProps: affectsProps,
|
|
316
|
+
layoutProps: affectsProps,
|
|
317
|
+
definitions: {
|
|
318
|
+
affect,
|
|
319
|
+
condition
|
|
320
|
+
},
|
|
321
|
+
check: checkAffects
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
export { affects };
|
|
325
|
+
|
|
326
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/definition/affect.ts","../src/evaluate/evaluate.ts","../src/check/check-affects.ts","../src/index.ts"],"sourcesContent":["import * as v from 'valibot'\n\n/**\n * What an affect does while its condition is met: `hide` hides the field and keeps its value,\n * `hideAndClear` hides it and clears its value, and `show` shows it only then. Hide always wins.\n */\nexport type Effect = 'show' | 'hide' | 'hideAndClear'\n\n/** The value an operator compares with. */\nexport type Scalar = string | number | boolean\n\n/**\n * When an affect applies: a test of one field, by its dot path, with one operator, or every\n * (`all`) or any (`any`) of a list of conditions.\n */\nexport type Condition =\n | { field: string; equals: Scalar }\n | { field: string; notEquals: Scalar }\n | { field: string; in: readonly Scalar[] }\n | { field: string; includes: Scalar }\n | { field: string; empty: true }\n | { field: string; notEmpty: true }\n | { all: readonly Condition[] }\n | { any: readonly Condition[] }\n\n/** One effect of a field, step or section, and when it applies. */\nexport interface Affect {\n effect: Effect\n when: Condition\n}\n\n/** The operators of a test, each with the value it takes. */\nexport const OPERATORS = ['equals', 'notEquals', 'in', 'includes', 'empty', 'notEmpty'] as const\n\nexport type Operator = (typeof OPERATORS)[number]\n\nexport const EFFECTS = ['show', 'hide', 'hideAndClear'] as const satisfies readonly Effect[]\n\n// These schemas type `affects` in `defineForm()`, and make its JSON Schema. `validate()` checks a\n// definition with the package's own checks, which give each issue its code and path.\n\nconst path = v.pipe(v.string(), v.minLength(1))\nconst scalar = v.union([v.string(), v.number(), v.boolean()])\nconst conditions = v.pipe(v.array(v.lazy(() => condition)), v.minLength(1))\n\nexport const condition: v.GenericSchema<Condition> = v.union([\n v.strictObject({ field: path, equals: scalar }),\n v.strictObject({ field: path, notEquals: scalar }),\n v.strictObject({ field: path, in: v.pipe(v.array(scalar), v.minLength(1)) }),\n v.strictObject({ field: path, includes: scalar }),\n v.strictObject({ field: path, empty: v.literal(true) }),\n v.strictObject({ field: path, notEmpty: v.literal(true) }),\n v.strictObject({ all: conditions }),\n v.strictObject({ any: conditions }),\n])\n\nexport const affect: v.GenericSchema<Affect> = v.strictObject({\n effect: v.picklist(EFFECTS),\n when: v.lazy(() => condition),\n})\n\n/** The key the package adds to fields, steps and sections. */\nexport const affectsProps = v.object({\n affects: v.optional(v.array(v.lazy(() => affect))),\n})\n","import { coerceInput, type KindDef, type ValueKind } from '@whatsaaaa/form-builder-schema'\nimport type { Effect, Operator, Scalar } from '../definition/affect'\n\n/** A condition, checked, with each test reading its field by the index of the read. */\nexport type Compiled =\n | { readonly all: readonly Compiled[] }\n | { readonly any: readonly Compiled[] }\n | CompiledTest\n\nexport interface CompiledTest {\n /** The index of the field it reads, in the reads of the target. */\n readonly read: number\n readonly operator: Operator\n /** The value `equals`, `notEquals` and `includes` compare with, or the values of `in`. */\n readonly value: Scalar | readonly Scalar[] | true\n /** The kinds of the field it reads, to turn its input into its value, e.g. `'5'` into `5`. */\n readonly kind: ValueKind\n readonly itemKind: ValueKind | undefined\n readonly kindDef: KindDef\n}\n\n/**\n * Whether a condition is met. `read(i)` gives the input of the field of read `i`, or undefined\n * while it is hidden: a hidden field is empty.\n *\n * An empty field never equals a value, and so is not equal to any: `notEquals` is true for it.\n */\nexport function test(condition: Compiled, read: (i: number) => unknown): boolean {\n if ('all' in condition) return condition.all.every((each) => test(each, read))\n if ('any' in condition) return condition.any.some((each) => test(each, read))\n\n const { operator, value, kind, itemKind, kindDef } = condition\n // What the form holds, the way a renderer sets it: '5' is 5 for a number.\n const input = coerceInput(read(condition.read), { kind, itemKind })\n const empty = input === undefined || kindDef.isEmpty(input)\n switch (operator) {\n case 'empty':\n return empty\n case 'notEmpty':\n return !empty\n case 'equals':\n return !empty && input === value\n case 'notEquals':\n return empty || input !== value\n case 'in':\n return !empty && (value as readonly Scalar[]).includes(input as Scalar)\n case 'includes':\n return !empty && Array.isArray(input) && input.includes(value)\n }\n}\n\n/**\n * Whether the affects of a target hide it, and clear it: an unmet `show`, a met `hide` or a met\n * `hideAndClear` hides it, so hide always wins, and only a met `hideAndClear` clears it.\n */\nexport function stateOf(\n effects: Readonly<Partial<Record<Effect, Compiled>>>,\n read: (i: number) => unknown,\n): { hidden: boolean; clear: boolean } {\n const shown = effects.show === undefined || test(effects.show, read)\n const hidden = effects.hide !== undefined && test(effects.hide, read)\n const clear = effects.hideAndClear !== undefined && test(effects.hideAndClear, read)\n return { hidden: !shown || hidden || clear, clear }\n}\n","import type {\n DefinitionPath,\n ExtensionContext,\n ExtensionTarget,\n ResolvedField,\n TargetConditions,\n} from '@whatsaaaa/form-builder-schema'\nimport * as v from 'valibot'\nimport { EFFECTS, type Effect, OPERATORS, type Operator, type Scalar } from '../definition/affect'\nimport { type Compiled, type CompiledTest, stateOf } from '../evaluate/evaluate'\n\n/** The kinds whose values a test can compare: a value is one string, number or boolean. */\nconst SCALAR_KINDS: readonly string[] = ['string', 'number', 'boolean', 'date']\n\n/**\n * Checks the `affects` of every field, step and section, and adds their issues. Returns the\n * conditions of each one whose affects have no issues.\n */\nexport function checkAffects(\n ctx: ExtensionContext,\n): ReadonlyMap<ExtensionTarget, TargetConditions> {\n const found = new Map<ExtensionTarget, TargetConditions>()\n for (const target of ctx.targets) {\n if (!Object.hasOwn(target.json, 'affects')) continue\n const conditions = checkTarget(target, ctx)\n if (conditions) found.set(target, conditions)\n }\n return found\n}\n\n/** The conditions of one target, or undefined when its affects have issues. */\nfunction checkTarget(target: ExtensionTarget, ctx: ExtensionContext): TargetConditions | undefined {\n const issues = createIssues(ctx)\n const path = [...target.definitionPath, 'affects']\n const raw = target.json['affects']\n if (!Array.isArray(raw)) {\n issues.add('invalid_shape', path, '\"affects\" is a list of { \"effect\", \"when\" }')\n return undefined\n }\n if (isItemField(target)) {\n const message = `The field of a list's items has no \"affects\" of its own. Put them on the list`\n issues.add('invalid_shape', path, message)\n return undefined\n }\n\n const reads: TargetConditions['reads'][number][] = []\n const effects: Partial<Record<Effect, Compiled>> = {}\n raw.forEach((affect: unknown, j) => {\n const at = [...path, j]\n if (!isObject(affect)) {\n issues.add('invalid_shape', at, 'An affect is an object with \"effect\" and \"when\"')\n return\n }\n issues.unknownKeys(affect, ['effect', 'when'], at, 'an affect')\n const effect = affect['effect']\n if (!EFFECTS.includes(effect as Effect)) {\n issues.add('invalid_shape', [...at, 'effect'], '\"effect\" is \"show\", \"hide\" or \"hideAndClear\"')\n } else if (Object.hasOwn(effects, effect as Effect)) {\n const message = `\"${effect as string}\" is in \"affects\" already. Join its conditions with \"all\" or \"any\"`\n issues.add('invalid_shape', at, message)\n }\n if (!Object.hasOwn(affect, 'when')) {\n issues.add('invalid_shape', at, 'An affect needs \"when\", its condition')\n return\n }\n const compiled = checkCondition(affect['when'], [...at, 'when'], target, ctx, issues, reads)\n if (compiled && EFFECTS.includes(effect as Effect)) effects[effect as Effect] ??= compiled\n })\n\n if (issues.count) return undefined\n return { reads, evaluate: (read) => stateOf(effects, read) }\n}\n\n/**\n * Checks a condition, and compiles it, adding each field it reads to `reads`. Undefined when it\n * has issues.\n */\nfunction checkCondition(\n raw: unknown,\n at: DefinitionPath,\n target: ExtensionTarget,\n ctx: ExtensionContext,\n issues: Issues,\n reads: TargetConditions['reads'][number][],\n): Compiled | undefined {\n if (!isObject(raw)) {\n const message = 'A condition is an object: \"field\" with an operator, \"all\" or \"any\"'\n issues.add('invalid_shape', at, message)\n return undefined\n }\n const groups = (['all', 'any'] as const).filter((key) => Object.hasOwn(raw, key))\n const operators = OPERATORS.filter((key) => Object.hasOwn(raw, key))\n const kinds = [...groups, ...(Object.hasOwn(raw, 'field') ? ['field'] : [])]\n if (kinds.length > 1) {\n const keys = kinds.map((key) => `\"${key}\"`).join(' and ')\n issues.add('invalid_shape', at, `A condition has one of \"all\", \"any\" and \"field\", not ${keys}`)\n return undefined\n }\n\n const [group] = groups\n if (group) {\n issues.unknownKeys(raw, [group], at, 'a condition')\n const list = raw[group]\n if (!Array.isArray(list) || !list.length) {\n issues.add('invalid_shape', [...at, group], `\"${group}\" is a list of at least one condition`)\n return undefined\n }\n const compiled = list.map((each: unknown, k) =>\n checkCondition(each, [...at, group, k], target, ctx, issues, reads),\n )\n if (!compiled.every((each) => each !== undefined)) return undefined\n return group === 'all' ? { all: compiled } : { any: compiled }\n }\n\n const unknown = issues.unknownKeys(raw, ['field', ...OPERATORS], at, 'a condition')\n const field = raw['field']\n if (typeof field !== 'string' || !field) {\n issues.add(\n 'invalid_shape',\n [...at, 'field'],\n '\"field\" is the dot path of a field, like \"address.city\"',\n )\n }\n const [operator, other] = operators\n if (other) {\n const keys = operators.map((key) => `\"${key}\"`).join(', ')\n issues.add('invalid_shape', at, `A condition has one operator, not ${keys}`)\n } else if (!operator && !unknown) {\n const message = `A condition needs an operator: ${OPERATORS.map((key) => `\"${key}\"`).join(', ')}`\n issues.add('invalid_shape', at, message)\n }\n if (typeof field !== 'string' || !field || !operator || other) return undefined\n const value = checkValueShape(operator, raw[operator], [...at, operator], issues)\n if (value === undefined) return undefined\n\n const resolved = ctx.resolve(field, target)\n if (typeof resolved === 'string') issues.add('unknown_field', [...at, 'field'], resolved)\n if (typeof resolved === 'string' || resolved === null) return undefined\n if (!checkKind(operator, resolved, field, [...at, operator], issues)) return undefined\n if (!checkValues(operator, value, resolved, field, [...at, operator], issues)) return undefined\n\n reads.push({ field: resolved, at: [...at, 'field'] })\n return {\n read: reads.length - 1,\n operator,\n value,\n kind: resolved.kind,\n itemKind: resolved.item?.kind,\n kindDef: resolved.kindDef,\n } satisfies CompiledTest\n}\n\n/** The operator's value when it has the right shape, or undefined with an issue. */\nfunction checkValueShape(\n operator: Operator,\n value: unknown,\n at: DefinitionPath,\n issues: Issues,\n): CompiledTest['value'] | undefined {\n switch (operator) {\n case 'empty':\n case 'notEmpty':\n if (value === true) return true\n issues.add(\n 'invalid_shape',\n at,\n `\"${operator}\" is true. For the opposite, use \"${operator === 'empty' ? 'notEmpty' : 'empty'}\"`,\n )\n return undefined\n case 'in':\n if (Array.isArray(value) && value.length && value.every(isScalar)) return value\n issues.add('invalid_shape', at, '\"in\" is a list of at least one string, number or boolean')\n return undefined\n default:\n if (isScalar(value)) return value\n issues.add('invalid_shape', at, `\"${operator}\" is a string, a number or a boolean`)\n return undefined\n }\n}\n\n/** True when the operator fits the field's kind. Adds a `kind_mismatch` issue when it doesn't. */\nfunction checkKind(\n operator: Operator,\n field: ResolvedField,\n dotPath: string,\n at: DefinitionPath,\n issues: Issues,\n): boolean {\n const { kind, item } = field\n let fits: boolean\n let what = `${kind} fields`\n if (operator === 'empty' || operator === 'notEmpty') {\n // A group is never empty: it always holds its fields.\n fits = kind !== 'object'\n } else if (operator === 'includes') {\n fits = kind === 'array' && !!item && SCALAR_KINDS.includes(item.kind)\n what = kind !== 'array' ? what : `lists of ${item ? `${item.kind} items` : 'objects'}`\n } else {\n fits = SCALAR_KINDS.includes(kind)\n }\n if (!fits)\n issues.add('kind_mismatch', at, `\"${operator}\" can't be used on ${what}, like \"${dotPath}\"`)\n return fits\n}\n\n/**\n * True when the field can hold each value the operator compares with: its schema, or that of its\n * items for `includes`, takes it, and it isn't empty. Adds an `invalid_value` issue for each it\n * can't.\n */\nfunction checkValues(\n operator: Operator,\n value: CompiledTest['value'],\n field: ResolvedField,\n dotPath: string,\n at: DefinitionPath,\n issues: Issues,\n): boolean {\n if (operator === 'empty' || operator === 'notEmpty') return true\n const schema =\n operator === 'includes'\n ? (field.item as NonNullable<ResolvedField['item']>).schema\n : field.schema\n const values = operator === 'in' ? (value as readonly Scalar[]) : [value as Scalar]\n let valid = true\n values.forEach((each, k) => {\n const where = operator === 'in' ? [...at, k] : at\n if (operator !== 'includes' && field.kindDef.isEmpty(each)) {\n const message = `${JSON.stringify(each)} is no value, so it never matches. Use \"empty\" or \"notEmpty\"`\n issues.add('invalid_value', where, message)\n valid = false\n return\n }\n const result = v.safeParse(schema, each)\n if (result.success) return\n const reason = result.issues[0].message\n issues.add('invalid_value', where, `\"${dotPath}\" can't hold ${JSON.stringify(each)}: ${reason}`)\n valid = false\n })\n return valid\n}\n\n/** True for the field of a list's items, which has a value and no name: its value is the item. */\nfunction isItemField(target: ExtensionTarget): boolean {\n return (\n target.kind === 'field' &&\n target.field.field.name === undefined &&\n target.field.kind !== 'none' &&\n target.field.dataPath.at(-1) === '*'\n )\n}\n\ninterface Issues {\n /** How many issues this target has. */\n readonly count: number\n add(code: Parameters<ExtensionContext['issue']>[0], path: DefinitionPath, message: string): void\n /** Adds an issue for each key of `raw` that isn't `known`. True when there are some. */\n unknownKeys(\n raw: Record<string, unknown>,\n known: readonly string[],\n at: DefinitionPath,\n what: string,\n ): boolean\n}\n\nfunction createIssues(ctx: ExtensionContext): Issues {\n let count = 0\n const issues: Issues = {\n get count() {\n return count\n },\n add(code, path, message) {\n count++\n ctx.issue(code, path, message)\n },\n unknownKeys(raw, known, at, what) {\n const unknown = Object.keys(raw).filter((key) => !known.includes(key))\n for (const key of unknown)\n issues.add('unknown_key', [...at, key], `Unknown key \"${key}\" on ${what}`)\n return unknown.length > 0\n },\n }\n return issues\n}\n\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst isScalar = (value: unknown): value is Scalar =>\n typeof value === 'string' ||\n (typeof value === 'number' && Number.isFinite(value)) ||\n typeof value === 'boolean'\n","// Public API. Everything a consumer can import is exported here and nowhere else.\nimport type { SchemaExtension } from '@whatsaaaa/form-builder-schema'\nimport { checkAffects } from './check/check-affects'\nimport { affect, affectsProps, condition } from './definition/affect'\n\nexport type { Affect, Condition, Effect, Scalar } from './definition/affect'\n\n/** The extension `affects()` gives, with the type of the key it adds, for `defineForm()`. */\nexport interface AffectsExtension extends SchemaExtension {\n readonly fieldProps: typeof affectsProps\n readonly layoutProps: typeof affectsProps\n}\n\n/**\n * Conditions on fields, steps and sections: `affects`, a list of effects (`show`, `hide`,\n * `hideAndClear`), each with the condition that applies it. Pass it to the schema builder:\n * `createSchemaBuilder({ extensions: [affects()] })`. The schema it builds skips the validation of\n * hidden fields, and the builder's `getVisibility()` tells renderers what to hide and to clear.\n */\nexport function affects(): AffectsExtension {\n return {\n name: 'affects',\n fieldProps: affectsProps,\n layoutProps: affectsProps,\n definitions: { affect, condition },\n check: checkAffects,\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,65 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@whatsaaaa/form-builder-affects",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Show, hide and clear the fields, sections and steps of JSON form definitions by conditions.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"conditional",
|
|
7
|
+
"form",
|
|
8
|
+
"formisch",
|
|
9
|
+
"json",
|
|
10
|
+
"schema"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://github.com/whatsaaaa/form-builder",
|
|
13
|
+
"bugs": "https://github.com/whatsaaaa/form-builder/issues",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": "Whatsaaaa",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/whatsaaaa/form-builder.git",
|
|
19
|
+
"directory": "packages/affects"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"definition.schema.json"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"default": "./dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./definition.schema.json": "./definition.schema.json"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@arethetypeswrong/cli": "^0.18.5",
|
|
39
|
+
"@size-limit/preset-small-lib": "^14.3.0",
|
|
40
|
+
"@valibot/to-json-schema": "^1.8.0",
|
|
41
|
+
"@vitest/coverage-v8": "^5.0.5",
|
|
42
|
+
"@whatsaaaa/form-builder-schema": "^0.15.0",
|
|
43
|
+
"ajv": "^8.18.0",
|
|
44
|
+
"jiti": "^2.7.0",
|
|
45
|
+
"publint": "^0.3.25",
|
|
46
|
+
"size-limit": "^14.3.0",
|
|
47
|
+
"tsdown": "^0.23.2",
|
|
48
|
+
"typescript": "~6.0.3",
|
|
49
|
+
"valibot": "^1.5.0",
|
|
50
|
+
"vitest": "^5.0.5"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@whatsaaaa/form-builder-schema": "^0.15.0",
|
|
54
|
+
"valibot": "^1.3.0"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsdown",
|
|
58
|
+
"test": "vitest run",
|
|
59
|
+
"test:coverage": "vitest run --coverage",
|
|
60
|
+
"type-check": "tsc --noEmit && tsc --noEmit -p scripts",
|
|
61
|
+
"docs:gen": "jiti scripts/generate.ts",
|
|
62
|
+
"lint:pkg": "publint && pnpm pack --pack-destination .attw && attw .attw/*.tgz --profile esm-only --exclude-entrypoints definition.schema.json",
|
|
63
|
+
"size": "size-limit"
|
|
64
|
+
}
|
|
6
65
|
}
|