@json-render/core 0.0.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/README.md +184 -0
- package/dist/index.d.mts +746 -0
- package/dist/index.d.ts +746 -0
- package/dist/index.js +727 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +673 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +58 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,727 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
ActionConfirmSchema: () => ActionConfirmSchema,
|
|
24
|
+
ActionOnErrorSchema: () => ActionOnErrorSchema,
|
|
25
|
+
ActionOnSuccessSchema: () => ActionOnSuccessSchema,
|
|
26
|
+
ActionSchema: () => ActionSchema,
|
|
27
|
+
DynamicBooleanSchema: () => DynamicBooleanSchema,
|
|
28
|
+
DynamicNumberSchema: () => DynamicNumberSchema,
|
|
29
|
+
DynamicStringSchema: () => DynamicStringSchema,
|
|
30
|
+
DynamicValueSchema: () => DynamicValueSchema,
|
|
31
|
+
LogicExpressionSchema: () => LogicExpressionSchema,
|
|
32
|
+
ValidationCheckSchema: () => ValidationCheckSchema,
|
|
33
|
+
ValidationConfigSchema: () => ValidationConfigSchema,
|
|
34
|
+
VisibilityConditionSchema: () => VisibilityConditionSchema,
|
|
35
|
+
action: () => action,
|
|
36
|
+
builtInValidationFunctions: () => builtInValidationFunctions,
|
|
37
|
+
check: () => check,
|
|
38
|
+
createCatalog: () => createCatalog,
|
|
39
|
+
evaluateLogicExpression: () => evaluateLogicExpression,
|
|
40
|
+
evaluateVisibility: () => evaluateVisibility,
|
|
41
|
+
executeAction: () => executeAction,
|
|
42
|
+
generateCatalogPrompt: () => generateCatalogPrompt,
|
|
43
|
+
getByPath: () => getByPath,
|
|
44
|
+
interpolateString: () => interpolateString,
|
|
45
|
+
resolveAction: () => resolveAction,
|
|
46
|
+
resolveDynamicValue: () => resolveDynamicValue,
|
|
47
|
+
runValidation: () => runValidation,
|
|
48
|
+
runValidationCheck: () => runValidationCheck,
|
|
49
|
+
setByPath: () => setByPath,
|
|
50
|
+
visibility: () => visibility
|
|
51
|
+
});
|
|
52
|
+
module.exports = __toCommonJS(index_exports);
|
|
53
|
+
|
|
54
|
+
// src/types.ts
|
|
55
|
+
var import_zod = require("zod");
|
|
56
|
+
var DynamicValueSchema = import_zod.z.union([
|
|
57
|
+
import_zod.z.string(),
|
|
58
|
+
import_zod.z.number(),
|
|
59
|
+
import_zod.z.boolean(),
|
|
60
|
+
import_zod.z.null(),
|
|
61
|
+
import_zod.z.object({ path: import_zod.z.string() })
|
|
62
|
+
]);
|
|
63
|
+
var DynamicStringSchema = import_zod.z.union([
|
|
64
|
+
import_zod.z.string(),
|
|
65
|
+
import_zod.z.object({ path: import_zod.z.string() })
|
|
66
|
+
]);
|
|
67
|
+
var DynamicNumberSchema = import_zod.z.union([
|
|
68
|
+
import_zod.z.number(),
|
|
69
|
+
import_zod.z.object({ path: import_zod.z.string() })
|
|
70
|
+
]);
|
|
71
|
+
var DynamicBooleanSchema = import_zod.z.union([
|
|
72
|
+
import_zod.z.boolean(),
|
|
73
|
+
import_zod.z.object({ path: import_zod.z.string() })
|
|
74
|
+
]);
|
|
75
|
+
function resolveDynamicValue(value, dataModel) {
|
|
76
|
+
if (value === null || value === void 0) {
|
|
77
|
+
return void 0;
|
|
78
|
+
}
|
|
79
|
+
if (typeof value === "object" && "path" in value) {
|
|
80
|
+
return getByPath(dataModel, value.path);
|
|
81
|
+
}
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
function getByPath(obj, path) {
|
|
85
|
+
if (!path || path === "/") {
|
|
86
|
+
return obj;
|
|
87
|
+
}
|
|
88
|
+
const segments = path.startsWith("/") ? path.slice(1).split("/") : path.split("/");
|
|
89
|
+
let current = obj;
|
|
90
|
+
for (const segment of segments) {
|
|
91
|
+
if (current === null || current === void 0) {
|
|
92
|
+
return void 0;
|
|
93
|
+
}
|
|
94
|
+
if (typeof current === "object") {
|
|
95
|
+
current = current[segment];
|
|
96
|
+
} else {
|
|
97
|
+
return void 0;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return current;
|
|
101
|
+
}
|
|
102
|
+
function setByPath(obj, path, value) {
|
|
103
|
+
const segments = path.startsWith("/") ? path.slice(1).split("/") : path.split("/");
|
|
104
|
+
if (segments.length === 0) return;
|
|
105
|
+
let current = obj;
|
|
106
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
107
|
+
const segment = segments[i];
|
|
108
|
+
if (!(segment in current) || typeof current[segment] !== "object") {
|
|
109
|
+
current[segment] = {};
|
|
110
|
+
}
|
|
111
|
+
current = current[segment];
|
|
112
|
+
}
|
|
113
|
+
const lastSegment = segments[segments.length - 1];
|
|
114
|
+
current[lastSegment] = value;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/visibility.ts
|
|
118
|
+
var import_zod2 = require("zod");
|
|
119
|
+
var DynamicNumberValueSchema = import_zod2.z.union([
|
|
120
|
+
import_zod2.z.number(),
|
|
121
|
+
import_zod2.z.object({ path: import_zod2.z.string() })
|
|
122
|
+
]);
|
|
123
|
+
var LogicExpressionSchema = import_zod2.z.lazy(
|
|
124
|
+
() => import_zod2.z.union([
|
|
125
|
+
import_zod2.z.object({ and: import_zod2.z.array(LogicExpressionSchema) }),
|
|
126
|
+
import_zod2.z.object({ or: import_zod2.z.array(LogicExpressionSchema) }),
|
|
127
|
+
import_zod2.z.object({ not: LogicExpressionSchema }),
|
|
128
|
+
import_zod2.z.object({ path: import_zod2.z.string() }),
|
|
129
|
+
import_zod2.z.object({ eq: import_zod2.z.tuple([DynamicValueSchema, DynamicValueSchema]) }),
|
|
130
|
+
import_zod2.z.object({ neq: import_zod2.z.tuple([DynamicValueSchema, DynamicValueSchema]) }),
|
|
131
|
+
import_zod2.z.object({ gt: import_zod2.z.tuple([DynamicNumberValueSchema, DynamicNumberValueSchema]) }),
|
|
132
|
+
import_zod2.z.object({ gte: import_zod2.z.tuple([DynamicNumberValueSchema, DynamicNumberValueSchema]) }),
|
|
133
|
+
import_zod2.z.object({ lt: import_zod2.z.tuple([DynamicNumberValueSchema, DynamicNumberValueSchema]) }),
|
|
134
|
+
import_zod2.z.object({ lte: import_zod2.z.tuple([DynamicNumberValueSchema, DynamicNumberValueSchema]) })
|
|
135
|
+
])
|
|
136
|
+
);
|
|
137
|
+
var VisibilityConditionSchema = import_zod2.z.union([
|
|
138
|
+
import_zod2.z.boolean(),
|
|
139
|
+
import_zod2.z.object({ path: import_zod2.z.string() }),
|
|
140
|
+
import_zod2.z.object({ auth: import_zod2.z.enum(["signedIn", "signedOut"]) }),
|
|
141
|
+
LogicExpressionSchema
|
|
142
|
+
]);
|
|
143
|
+
function evaluateLogicExpression(expr, ctx) {
|
|
144
|
+
const { dataModel } = ctx;
|
|
145
|
+
if ("and" in expr) {
|
|
146
|
+
return expr.and.every((subExpr) => evaluateLogicExpression(subExpr, ctx));
|
|
147
|
+
}
|
|
148
|
+
if ("or" in expr) {
|
|
149
|
+
return expr.or.some((subExpr) => evaluateLogicExpression(subExpr, ctx));
|
|
150
|
+
}
|
|
151
|
+
if ("not" in expr) {
|
|
152
|
+
return !evaluateLogicExpression(expr.not, ctx);
|
|
153
|
+
}
|
|
154
|
+
if ("path" in expr) {
|
|
155
|
+
const value = resolveDynamicValue({ path: expr.path }, dataModel);
|
|
156
|
+
return Boolean(value);
|
|
157
|
+
}
|
|
158
|
+
if ("eq" in expr) {
|
|
159
|
+
const [left, right] = expr.eq;
|
|
160
|
+
const leftValue = resolveDynamicValue(left, dataModel);
|
|
161
|
+
const rightValue = resolveDynamicValue(right, dataModel);
|
|
162
|
+
return leftValue === rightValue;
|
|
163
|
+
}
|
|
164
|
+
if ("neq" in expr) {
|
|
165
|
+
const [left, right] = expr.neq;
|
|
166
|
+
const leftValue = resolveDynamicValue(left, dataModel);
|
|
167
|
+
const rightValue = resolveDynamicValue(right, dataModel);
|
|
168
|
+
return leftValue !== rightValue;
|
|
169
|
+
}
|
|
170
|
+
if ("gt" in expr) {
|
|
171
|
+
const [left, right] = expr.gt;
|
|
172
|
+
const leftValue = resolveDynamicValue(left, dataModel);
|
|
173
|
+
const rightValue = resolveDynamicValue(right, dataModel);
|
|
174
|
+
if (typeof leftValue === "number" && typeof rightValue === "number") {
|
|
175
|
+
return leftValue > rightValue;
|
|
176
|
+
}
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
if ("gte" in expr) {
|
|
180
|
+
const [left, right] = expr.gte;
|
|
181
|
+
const leftValue = resolveDynamicValue(left, dataModel);
|
|
182
|
+
const rightValue = resolveDynamicValue(right, dataModel);
|
|
183
|
+
if (typeof leftValue === "number" && typeof rightValue === "number") {
|
|
184
|
+
return leftValue >= rightValue;
|
|
185
|
+
}
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
if ("lt" in expr) {
|
|
189
|
+
const [left, right] = expr.lt;
|
|
190
|
+
const leftValue = resolveDynamicValue(left, dataModel);
|
|
191
|
+
const rightValue = resolveDynamicValue(right, dataModel);
|
|
192
|
+
if (typeof leftValue === "number" && typeof rightValue === "number") {
|
|
193
|
+
return leftValue < rightValue;
|
|
194
|
+
}
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
if ("lte" in expr) {
|
|
198
|
+
const [left, right] = expr.lte;
|
|
199
|
+
const leftValue = resolveDynamicValue(left, dataModel);
|
|
200
|
+
const rightValue = resolveDynamicValue(right, dataModel);
|
|
201
|
+
if (typeof leftValue === "number" && typeof rightValue === "number") {
|
|
202
|
+
return leftValue <= rightValue;
|
|
203
|
+
}
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
function evaluateVisibility(condition, ctx) {
|
|
209
|
+
if (condition === void 0) {
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
if (typeof condition === "boolean") {
|
|
213
|
+
return condition;
|
|
214
|
+
}
|
|
215
|
+
if ("path" in condition && !("and" in condition) && !("or" in condition)) {
|
|
216
|
+
const value = resolveDynamicValue({ path: condition.path }, ctx.dataModel);
|
|
217
|
+
return Boolean(value);
|
|
218
|
+
}
|
|
219
|
+
if ("auth" in condition) {
|
|
220
|
+
const isSignedIn = ctx.authState?.isSignedIn ?? false;
|
|
221
|
+
if (condition.auth === "signedIn") {
|
|
222
|
+
return isSignedIn;
|
|
223
|
+
}
|
|
224
|
+
if (condition.auth === "signedOut") {
|
|
225
|
+
return !isSignedIn;
|
|
226
|
+
}
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
return evaluateLogicExpression(condition, ctx);
|
|
230
|
+
}
|
|
231
|
+
var visibility = {
|
|
232
|
+
/** Always visible */
|
|
233
|
+
always: true,
|
|
234
|
+
/** Never visible */
|
|
235
|
+
never: false,
|
|
236
|
+
/** Visible when path is truthy */
|
|
237
|
+
when: (path) => ({ path }),
|
|
238
|
+
/** Visible when signed in */
|
|
239
|
+
signedIn: { auth: "signedIn" },
|
|
240
|
+
/** Visible when signed out */
|
|
241
|
+
signedOut: { auth: "signedOut" },
|
|
242
|
+
/** AND multiple conditions */
|
|
243
|
+
and: (...conditions) => ({ and: conditions }),
|
|
244
|
+
/** OR multiple conditions */
|
|
245
|
+
or: (...conditions) => ({ or: conditions }),
|
|
246
|
+
/** NOT a condition */
|
|
247
|
+
not: (condition) => ({ not: condition }),
|
|
248
|
+
/** Equality check */
|
|
249
|
+
eq: (left, right) => ({ eq: [left, right] }),
|
|
250
|
+
/** Not equal check */
|
|
251
|
+
neq: (left, right) => ({ neq: [left, right] }),
|
|
252
|
+
/** Greater than */
|
|
253
|
+
gt: (left, right) => ({ gt: [left, right] }),
|
|
254
|
+
/** Greater than or equal */
|
|
255
|
+
gte: (left, right) => ({ gte: [left, right] }),
|
|
256
|
+
/** Less than */
|
|
257
|
+
lt: (left, right) => ({ lt: [left, right] }),
|
|
258
|
+
/** Less than or equal */
|
|
259
|
+
lte: (left, right) => ({ lte: [left, right] })
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
// src/actions.ts
|
|
263
|
+
var import_zod3 = require("zod");
|
|
264
|
+
var ActionConfirmSchema = import_zod3.z.object({
|
|
265
|
+
title: import_zod3.z.string(),
|
|
266
|
+
message: import_zod3.z.string(),
|
|
267
|
+
confirmLabel: import_zod3.z.string().optional(),
|
|
268
|
+
cancelLabel: import_zod3.z.string().optional(),
|
|
269
|
+
variant: import_zod3.z.enum(["default", "danger"]).optional()
|
|
270
|
+
});
|
|
271
|
+
var ActionOnSuccessSchema = import_zod3.z.union([
|
|
272
|
+
import_zod3.z.object({ navigate: import_zod3.z.string() }),
|
|
273
|
+
import_zod3.z.object({ set: import_zod3.z.record(import_zod3.z.unknown()) }),
|
|
274
|
+
import_zod3.z.object({ action: import_zod3.z.string() })
|
|
275
|
+
]);
|
|
276
|
+
var ActionOnErrorSchema = import_zod3.z.union([
|
|
277
|
+
import_zod3.z.object({ set: import_zod3.z.record(import_zod3.z.unknown()) }),
|
|
278
|
+
import_zod3.z.object({ action: import_zod3.z.string() })
|
|
279
|
+
]);
|
|
280
|
+
var ActionSchema = import_zod3.z.object({
|
|
281
|
+
name: import_zod3.z.string(),
|
|
282
|
+
params: import_zod3.z.record(DynamicValueSchema).optional(),
|
|
283
|
+
confirm: ActionConfirmSchema.optional(),
|
|
284
|
+
onSuccess: ActionOnSuccessSchema.optional(),
|
|
285
|
+
onError: ActionOnErrorSchema.optional()
|
|
286
|
+
});
|
|
287
|
+
function resolveAction(action2, dataModel) {
|
|
288
|
+
const resolvedParams = {};
|
|
289
|
+
if (action2.params) {
|
|
290
|
+
for (const [key, value] of Object.entries(action2.params)) {
|
|
291
|
+
resolvedParams[key] = resolveDynamicValue(value, dataModel);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
let confirm = action2.confirm;
|
|
295
|
+
if (confirm) {
|
|
296
|
+
confirm = {
|
|
297
|
+
...confirm,
|
|
298
|
+
message: interpolateString(confirm.message, dataModel),
|
|
299
|
+
title: interpolateString(confirm.title, dataModel)
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
return {
|
|
303
|
+
name: action2.name,
|
|
304
|
+
params: resolvedParams,
|
|
305
|
+
confirm,
|
|
306
|
+
onSuccess: action2.onSuccess,
|
|
307
|
+
onError: action2.onError
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
function interpolateString(template, dataModel) {
|
|
311
|
+
return template.replace(/\$\{([^}]+)\}/g, (_, path) => {
|
|
312
|
+
const value = resolveDynamicValue({ path }, dataModel);
|
|
313
|
+
return String(value ?? "");
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
async function executeAction(ctx) {
|
|
317
|
+
const { action: action2, handler, setData, navigate, executeAction: executeAction2 } = ctx;
|
|
318
|
+
try {
|
|
319
|
+
await handler(action2.params);
|
|
320
|
+
if (action2.onSuccess) {
|
|
321
|
+
if ("navigate" in action2.onSuccess && navigate) {
|
|
322
|
+
navigate(action2.onSuccess.navigate);
|
|
323
|
+
} else if ("set" in action2.onSuccess) {
|
|
324
|
+
for (const [path, value] of Object.entries(action2.onSuccess.set)) {
|
|
325
|
+
setData(path, value);
|
|
326
|
+
}
|
|
327
|
+
} else if ("action" in action2.onSuccess && executeAction2) {
|
|
328
|
+
await executeAction2(action2.onSuccess.action);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
} catch (error) {
|
|
332
|
+
if (action2.onError) {
|
|
333
|
+
if ("set" in action2.onError) {
|
|
334
|
+
for (const [path, value] of Object.entries(action2.onError.set)) {
|
|
335
|
+
const resolvedValue = typeof value === "string" && value === "$error.message" ? error.message : value;
|
|
336
|
+
setData(path, resolvedValue);
|
|
337
|
+
}
|
|
338
|
+
} else if ("action" in action2.onError && executeAction2) {
|
|
339
|
+
await executeAction2(action2.onError.action);
|
|
340
|
+
}
|
|
341
|
+
} else {
|
|
342
|
+
throw error;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
var action = {
|
|
347
|
+
/** Create a simple action */
|
|
348
|
+
simple: (name, params) => ({
|
|
349
|
+
name,
|
|
350
|
+
params
|
|
351
|
+
}),
|
|
352
|
+
/** Create an action with confirmation */
|
|
353
|
+
withConfirm: (name, confirm, params) => ({
|
|
354
|
+
name,
|
|
355
|
+
params,
|
|
356
|
+
confirm
|
|
357
|
+
}),
|
|
358
|
+
/** Create an action with success handler */
|
|
359
|
+
withSuccess: (name, onSuccess, params) => ({
|
|
360
|
+
name,
|
|
361
|
+
params,
|
|
362
|
+
onSuccess
|
|
363
|
+
})
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
// src/validation.ts
|
|
367
|
+
var import_zod4 = require("zod");
|
|
368
|
+
var ValidationCheckSchema = import_zod4.z.object({
|
|
369
|
+
fn: import_zod4.z.string(),
|
|
370
|
+
args: import_zod4.z.record(DynamicValueSchema).optional(),
|
|
371
|
+
message: import_zod4.z.string()
|
|
372
|
+
});
|
|
373
|
+
var ValidationConfigSchema = import_zod4.z.object({
|
|
374
|
+
checks: import_zod4.z.array(ValidationCheckSchema).optional(),
|
|
375
|
+
validateOn: import_zod4.z.enum(["change", "blur", "submit"]).optional(),
|
|
376
|
+
enabled: LogicExpressionSchema.optional()
|
|
377
|
+
});
|
|
378
|
+
var builtInValidationFunctions = {
|
|
379
|
+
/**
|
|
380
|
+
* Check if value is not null, undefined, or empty string
|
|
381
|
+
*/
|
|
382
|
+
required: (value) => {
|
|
383
|
+
if (value === null || value === void 0) return false;
|
|
384
|
+
if (typeof value === "string") return value.trim().length > 0;
|
|
385
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
386
|
+
return true;
|
|
387
|
+
},
|
|
388
|
+
/**
|
|
389
|
+
* Check if value is a valid email address
|
|
390
|
+
*/
|
|
391
|
+
email: (value) => {
|
|
392
|
+
if (typeof value !== "string") return false;
|
|
393
|
+
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
|
|
394
|
+
},
|
|
395
|
+
/**
|
|
396
|
+
* Check minimum string length
|
|
397
|
+
*/
|
|
398
|
+
minLength: (value, args) => {
|
|
399
|
+
if (typeof value !== "string") return false;
|
|
400
|
+
const min = args?.min;
|
|
401
|
+
if (typeof min !== "number") return false;
|
|
402
|
+
return value.length >= min;
|
|
403
|
+
},
|
|
404
|
+
/**
|
|
405
|
+
* Check maximum string length
|
|
406
|
+
*/
|
|
407
|
+
maxLength: (value, args) => {
|
|
408
|
+
if (typeof value !== "string") return false;
|
|
409
|
+
const max = args?.max;
|
|
410
|
+
if (typeof max !== "number") return false;
|
|
411
|
+
return value.length <= max;
|
|
412
|
+
},
|
|
413
|
+
/**
|
|
414
|
+
* Check if string matches a regex pattern
|
|
415
|
+
*/
|
|
416
|
+
pattern: (value, args) => {
|
|
417
|
+
if (typeof value !== "string") return false;
|
|
418
|
+
const pattern = args?.pattern;
|
|
419
|
+
if (typeof pattern !== "string") return false;
|
|
420
|
+
try {
|
|
421
|
+
return new RegExp(pattern).test(value);
|
|
422
|
+
} catch {
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
},
|
|
426
|
+
/**
|
|
427
|
+
* Check minimum numeric value
|
|
428
|
+
*/
|
|
429
|
+
min: (value, args) => {
|
|
430
|
+
if (typeof value !== "number") return false;
|
|
431
|
+
const min = args?.min;
|
|
432
|
+
if (typeof min !== "number") return false;
|
|
433
|
+
return value >= min;
|
|
434
|
+
},
|
|
435
|
+
/**
|
|
436
|
+
* Check maximum numeric value
|
|
437
|
+
*/
|
|
438
|
+
max: (value, args) => {
|
|
439
|
+
if (typeof value !== "number") return false;
|
|
440
|
+
const max = args?.max;
|
|
441
|
+
if (typeof max !== "number") return false;
|
|
442
|
+
return value <= max;
|
|
443
|
+
},
|
|
444
|
+
/**
|
|
445
|
+
* Check if value is a number
|
|
446
|
+
*/
|
|
447
|
+
numeric: (value) => {
|
|
448
|
+
if (typeof value === "number") return !isNaN(value);
|
|
449
|
+
if (typeof value === "string") return !isNaN(parseFloat(value));
|
|
450
|
+
return false;
|
|
451
|
+
},
|
|
452
|
+
/**
|
|
453
|
+
* Check if value is a valid URL
|
|
454
|
+
*/
|
|
455
|
+
url: (value) => {
|
|
456
|
+
if (typeof value !== "string") return false;
|
|
457
|
+
try {
|
|
458
|
+
new URL(value);
|
|
459
|
+
return true;
|
|
460
|
+
} catch {
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
},
|
|
464
|
+
/**
|
|
465
|
+
* Check if value matches another field
|
|
466
|
+
*/
|
|
467
|
+
matches: (value, args) => {
|
|
468
|
+
const other = args?.other;
|
|
469
|
+
return value === other;
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
function runValidationCheck(check2, ctx) {
|
|
473
|
+
const { value, dataModel, customFunctions } = ctx;
|
|
474
|
+
const resolvedArgs = {};
|
|
475
|
+
if (check2.args) {
|
|
476
|
+
for (const [key, argValue] of Object.entries(check2.args)) {
|
|
477
|
+
resolvedArgs[key] = resolveDynamicValue(argValue, dataModel);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
const fn = builtInValidationFunctions[check2.fn] ?? customFunctions?.[check2.fn];
|
|
481
|
+
if (!fn) {
|
|
482
|
+
console.warn(`Unknown validation function: ${check2.fn}`);
|
|
483
|
+
return {
|
|
484
|
+
fn: check2.fn,
|
|
485
|
+
valid: true,
|
|
486
|
+
// Don't fail on unknown functions
|
|
487
|
+
message: check2.message
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
const valid = fn(value, resolvedArgs);
|
|
491
|
+
return {
|
|
492
|
+
fn: check2.fn,
|
|
493
|
+
valid,
|
|
494
|
+
message: check2.message
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
function runValidation(config, ctx) {
|
|
498
|
+
const checks = [];
|
|
499
|
+
const errors = [];
|
|
500
|
+
if (config.enabled) {
|
|
501
|
+
const enabled = evaluateLogicExpression(config.enabled, {
|
|
502
|
+
dataModel: ctx.dataModel,
|
|
503
|
+
authState: ctx.authState
|
|
504
|
+
});
|
|
505
|
+
if (!enabled) {
|
|
506
|
+
return { valid: true, errors: [], checks: [] };
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
if (config.checks) {
|
|
510
|
+
for (const check2 of config.checks) {
|
|
511
|
+
const result = runValidationCheck(check2, ctx);
|
|
512
|
+
checks.push(result);
|
|
513
|
+
if (!result.valid) {
|
|
514
|
+
errors.push(result.message);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
return {
|
|
519
|
+
valid: errors.length === 0,
|
|
520
|
+
errors,
|
|
521
|
+
checks
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
var check = {
|
|
525
|
+
required: (message = "This field is required") => ({
|
|
526
|
+
fn: "required",
|
|
527
|
+
message
|
|
528
|
+
}),
|
|
529
|
+
email: (message = "Invalid email address") => ({
|
|
530
|
+
fn: "email",
|
|
531
|
+
message
|
|
532
|
+
}),
|
|
533
|
+
minLength: (min, message) => ({
|
|
534
|
+
fn: "minLength",
|
|
535
|
+
args: { min },
|
|
536
|
+
message: message ?? `Must be at least ${min} characters`
|
|
537
|
+
}),
|
|
538
|
+
maxLength: (max, message) => ({
|
|
539
|
+
fn: "maxLength",
|
|
540
|
+
args: { max },
|
|
541
|
+
message: message ?? `Must be at most ${max} characters`
|
|
542
|
+
}),
|
|
543
|
+
pattern: (pattern, message = "Invalid format") => ({
|
|
544
|
+
fn: "pattern",
|
|
545
|
+
args: { pattern },
|
|
546
|
+
message
|
|
547
|
+
}),
|
|
548
|
+
min: (min, message) => ({
|
|
549
|
+
fn: "min",
|
|
550
|
+
args: { min },
|
|
551
|
+
message: message ?? `Must be at least ${min}`
|
|
552
|
+
}),
|
|
553
|
+
max: (max, message) => ({
|
|
554
|
+
fn: "max",
|
|
555
|
+
args: { max },
|
|
556
|
+
message: message ?? `Must be at most ${max}`
|
|
557
|
+
}),
|
|
558
|
+
url: (message = "Invalid URL") => ({
|
|
559
|
+
fn: "url",
|
|
560
|
+
message
|
|
561
|
+
}),
|
|
562
|
+
matches: (otherPath, message = "Fields must match") => ({
|
|
563
|
+
fn: "matches",
|
|
564
|
+
args: { other: { path: otherPath } },
|
|
565
|
+
message
|
|
566
|
+
})
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
// src/catalog.ts
|
|
570
|
+
var import_zod5 = require("zod");
|
|
571
|
+
function createCatalog(config) {
|
|
572
|
+
const {
|
|
573
|
+
name = "unnamed",
|
|
574
|
+
components,
|
|
575
|
+
actions = {},
|
|
576
|
+
functions = {},
|
|
577
|
+
validation = "strict"
|
|
578
|
+
} = config;
|
|
579
|
+
const componentNames = Object.keys(components);
|
|
580
|
+
const actionNames = Object.keys(actions);
|
|
581
|
+
const functionNames = Object.keys(functions);
|
|
582
|
+
const componentSchemas = componentNames.map((componentName) => {
|
|
583
|
+
const def = components[componentName];
|
|
584
|
+
return import_zod5.z.object({
|
|
585
|
+
key: import_zod5.z.string(),
|
|
586
|
+
type: import_zod5.z.literal(componentName),
|
|
587
|
+
props: def.props,
|
|
588
|
+
children: import_zod5.z.array(import_zod5.z.string()).optional(),
|
|
589
|
+
parentKey: import_zod5.z.string().nullable().optional(),
|
|
590
|
+
visible: VisibilityConditionSchema.optional()
|
|
591
|
+
});
|
|
592
|
+
});
|
|
593
|
+
let elementSchema;
|
|
594
|
+
if (componentSchemas.length === 0) {
|
|
595
|
+
elementSchema = import_zod5.z.object({
|
|
596
|
+
key: import_zod5.z.string(),
|
|
597
|
+
type: import_zod5.z.string(),
|
|
598
|
+
props: import_zod5.z.record(import_zod5.z.unknown()),
|
|
599
|
+
children: import_zod5.z.array(import_zod5.z.string()).optional(),
|
|
600
|
+
parentKey: import_zod5.z.string().nullable().optional(),
|
|
601
|
+
visible: VisibilityConditionSchema.optional()
|
|
602
|
+
});
|
|
603
|
+
} else if (componentSchemas.length === 1) {
|
|
604
|
+
elementSchema = componentSchemas[0];
|
|
605
|
+
} else {
|
|
606
|
+
elementSchema = import_zod5.z.discriminatedUnion("type", [
|
|
607
|
+
componentSchemas[0],
|
|
608
|
+
componentSchemas[1],
|
|
609
|
+
...componentSchemas.slice(2)
|
|
610
|
+
]);
|
|
611
|
+
}
|
|
612
|
+
const treeSchema = import_zod5.z.object({
|
|
613
|
+
root: import_zod5.z.string(),
|
|
614
|
+
elements: import_zod5.z.record(elementSchema)
|
|
615
|
+
});
|
|
616
|
+
return {
|
|
617
|
+
name,
|
|
618
|
+
componentNames,
|
|
619
|
+
actionNames,
|
|
620
|
+
functionNames,
|
|
621
|
+
validation,
|
|
622
|
+
components,
|
|
623
|
+
actions,
|
|
624
|
+
functions,
|
|
625
|
+
elementSchema,
|
|
626
|
+
treeSchema,
|
|
627
|
+
hasComponent(type) {
|
|
628
|
+
return type in components;
|
|
629
|
+
},
|
|
630
|
+
hasAction(name2) {
|
|
631
|
+
return name2 in actions;
|
|
632
|
+
},
|
|
633
|
+
hasFunction(name2) {
|
|
634
|
+
return name2 in functions;
|
|
635
|
+
},
|
|
636
|
+
validateElement(element) {
|
|
637
|
+
const result = elementSchema.safeParse(element);
|
|
638
|
+
if (result.success) {
|
|
639
|
+
return { success: true, data: result.data };
|
|
640
|
+
}
|
|
641
|
+
return { success: false, error: result.error };
|
|
642
|
+
},
|
|
643
|
+
validateTree(tree) {
|
|
644
|
+
const result = treeSchema.safeParse(tree);
|
|
645
|
+
if (result.success) {
|
|
646
|
+
return { success: true, data: result.data };
|
|
647
|
+
}
|
|
648
|
+
return { success: false, error: result.error };
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
function generateCatalogPrompt(catalog) {
|
|
653
|
+
const lines = [
|
|
654
|
+
`# ${catalog.name} Component Catalog`,
|
|
655
|
+
"",
|
|
656
|
+
"## Available Components",
|
|
657
|
+
""
|
|
658
|
+
];
|
|
659
|
+
for (const name of catalog.componentNames) {
|
|
660
|
+
const def = catalog.components[name];
|
|
661
|
+
lines.push(`### ${String(name)}`);
|
|
662
|
+
if (def.description) {
|
|
663
|
+
lines.push(def.description);
|
|
664
|
+
}
|
|
665
|
+
lines.push("");
|
|
666
|
+
}
|
|
667
|
+
if (catalog.actionNames.length > 0) {
|
|
668
|
+
lines.push("## Available Actions");
|
|
669
|
+
lines.push("");
|
|
670
|
+
for (const name of catalog.actionNames) {
|
|
671
|
+
const def = catalog.actions[name];
|
|
672
|
+
lines.push(`- \`${String(name)}\`${def.description ? `: ${def.description}` : ""}`);
|
|
673
|
+
}
|
|
674
|
+
lines.push("");
|
|
675
|
+
}
|
|
676
|
+
lines.push("## Visibility Conditions");
|
|
677
|
+
lines.push("");
|
|
678
|
+
lines.push("Components can have a `visible` property:");
|
|
679
|
+
lines.push("- `true` / `false` - Always visible/hidden");
|
|
680
|
+
lines.push('- `{ "path": "/data/path" }` - Visible when path is truthy');
|
|
681
|
+
lines.push('- `{ "auth": "signedIn" }` - Visible when user is signed in');
|
|
682
|
+
lines.push('- `{ "and": [...] }` - All conditions must be true');
|
|
683
|
+
lines.push('- `{ "or": [...] }` - Any condition must be true');
|
|
684
|
+
lines.push('- `{ "not": {...} }` - Negates a condition');
|
|
685
|
+
lines.push('- `{ "eq": [a, b] }` - Equality check');
|
|
686
|
+
lines.push("");
|
|
687
|
+
lines.push("## Validation Functions");
|
|
688
|
+
lines.push("");
|
|
689
|
+
lines.push("Built-in: `required`, `email`, `minLength`, `maxLength`, `pattern`, `min`, `max`, `url`");
|
|
690
|
+
if (catalog.functionNames.length > 0) {
|
|
691
|
+
lines.push(`Custom: ${catalog.functionNames.map(String).join(", ")}`);
|
|
692
|
+
}
|
|
693
|
+
lines.push("");
|
|
694
|
+
return lines.join("\n");
|
|
695
|
+
}
|
|
696
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
697
|
+
0 && (module.exports = {
|
|
698
|
+
ActionConfirmSchema,
|
|
699
|
+
ActionOnErrorSchema,
|
|
700
|
+
ActionOnSuccessSchema,
|
|
701
|
+
ActionSchema,
|
|
702
|
+
DynamicBooleanSchema,
|
|
703
|
+
DynamicNumberSchema,
|
|
704
|
+
DynamicStringSchema,
|
|
705
|
+
DynamicValueSchema,
|
|
706
|
+
LogicExpressionSchema,
|
|
707
|
+
ValidationCheckSchema,
|
|
708
|
+
ValidationConfigSchema,
|
|
709
|
+
VisibilityConditionSchema,
|
|
710
|
+
action,
|
|
711
|
+
builtInValidationFunctions,
|
|
712
|
+
check,
|
|
713
|
+
createCatalog,
|
|
714
|
+
evaluateLogicExpression,
|
|
715
|
+
evaluateVisibility,
|
|
716
|
+
executeAction,
|
|
717
|
+
generateCatalogPrompt,
|
|
718
|
+
getByPath,
|
|
719
|
+
interpolateString,
|
|
720
|
+
resolveAction,
|
|
721
|
+
resolveDynamicValue,
|
|
722
|
+
runValidation,
|
|
723
|
+
runValidationCheck,
|
|
724
|
+
setByPath,
|
|
725
|
+
visibility
|
|
726
|
+
});
|
|
727
|
+
//# sourceMappingURL=index.js.map
|