@petrarca/sonnet-core 0.5.0 → 0.6.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/dist/config/index.d.ts +24 -2
- package/dist/config/index.js +16 -1
- package/dist/config/index.js.map +1 -1
- package/dist/index.d.ts +184 -1
- package/dist/index.js +316 -0
- package/dist/index.js.map +1 -1
- package/dist/schema/index.d.ts +179 -17
- package/dist/schema/index.js +209 -39
- package/dist/schema/index.js.map +1 -1
- package/package.json +1 -1
package/dist/schema/index.js
CHANGED
|
@@ -96,6 +96,48 @@ function hasProperties(schema) {
|
|
|
96
96
|
return Object.keys(schema.properties || {}).length > 0;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
// src/schema/variant.ts
|
|
100
|
+
function isOneOf(property) {
|
|
101
|
+
return Array.isArray(property.oneOf) && property.oneOf.length > 0;
|
|
102
|
+
}
|
|
103
|
+
function getDiscriminator(property) {
|
|
104
|
+
const explicit = property.discriminator?.propertyName;
|
|
105
|
+
if (typeof explicit === "string" && explicit) return explicit;
|
|
106
|
+
const branches = property.oneOf;
|
|
107
|
+
if (!Array.isArray(branches) || branches.length === 0) return void 0;
|
|
108
|
+
const first = branches[0].properties ?? {};
|
|
109
|
+
const candidates = Object.keys(first).filter(
|
|
110
|
+
(k) => first[k]?.const !== void 0
|
|
111
|
+
);
|
|
112
|
+
return candidates.find(
|
|
113
|
+
(key) => branches.every((b) => b.properties?.[key]?.const !== void 0)
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
function getBranchValue(branch, discriminator) {
|
|
117
|
+
const c = branch.properties?.[discriminator]?.const;
|
|
118
|
+
if (typeof c === "string" || typeof c === "number" || typeof c === "boolean") {
|
|
119
|
+
return c;
|
|
120
|
+
}
|
|
121
|
+
return void 0;
|
|
122
|
+
}
|
|
123
|
+
function getBranchLabel(branch, discriminator, index) {
|
|
124
|
+
if (branch.title) return branch.title;
|
|
125
|
+
if (discriminator) {
|
|
126
|
+
const v = getBranchValue(branch, discriminator);
|
|
127
|
+
if (v !== void 0) return String(v);
|
|
128
|
+
}
|
|
129
|
+
return `Option ${index + 1}`;
|
|
130
|
+
}
|
|
131
|
+
function findActiveBranch(property, data, discriminator) {
|
|
132
|
+
const branches = property.oneOf;
|
|
133
|
+
if (!Array.isArray(branches) || !discriminator || !data) return -1;
|
|
134
|
+
const current = data[discriminator];
|
|
135
|
+
if (current === void 0) return -1;
|
|
136
|
+
return branches.findIndex(
|
|
137
|
+
(b) => getBranchValue(b, discriminator) === current
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
99
141
|
// src/schema/schemaResolver.ts
|
|
100
142
|
import Ajv from "ajv";
|
|
101
143
|
import addFormats from "ajv-formats";
|
|
@@ -112,9 +154,29 @@ function resolveSchema(schema, formData) {
|
|
|
112
154
|
return schema;
|
|
113
155
|
}
|
|
114
156
|
let resolvedSchema = resolveAllOf(schema, formData);
|
|
157
|
+
resolvedSchema = resolveAnyOfConditionals(resolvedSchema, formData);
|
|
115
158
|
resolvedSchema = resolveConditionals(resolvedSchema, formData);
|
|
116
159
|
return resolvedSchema;
|
|
117
160
|
}
|
|
161
|
+
function resolveAnyOfConditionals(schema, formData) {
|
|
162
|
+
if (!schema.anyOf || !Array.isArray(schema.anyOf)) return schema;
|
|
163
|
+
const conditionalMembers = schema.anyOf.filter(
|
|
164
|
+
(m) => typeof m === "object" && m !== null && "if" in m
|
|
165
|
+
);
|
|
166
|
+
if (conditionalMembers.length === 0) return schema;
|
|
167
|
+
const nonConditionalMembers = schema.anyOf.filter(
|
|
168
|
+
(m) => !(typeof m === "object" && m !== null && "if" in m)
|
|
169
|
+
);
|
|
170
|
+
const { anyOf: _anyOf, ...baseSchema } = schema;
|
|
171
|
+
let result = nonConditionalMembers.length > 0 ? { ...baseSchema, anyOf: nonConditionalMembers } : baseSchema;
|
|
172
|
+
for (const member of conditionalMembers) {
|
|
173
|
+
const resolved = resolveConditionals(member, formData);
|
|
174
|
+
if (resolved !== member && typeof resolved === "object") {
|
|
175
|
+
result = mergeSchemas(result, resolved);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return result;
|
|
179
|
+
}
|
|
118
180
|
function resolveConditionals(schema, formData) {
|
|
119
181
|
if (!schema.if) {
|
|
120
182
|
return schema;
|
|
@@ -212,6 +274,65 @@ function hasConditionals(schema) {
|
|
|
212
274
|
return !!(schema.if || schema.allOf || schema.anyOf || schema.oneOf);
|
|
213
275
|
}
|
|
214
276
|
|
|
277
|
+
// src/schema/uiRule.ts
|
|
278
|
+
var validatorCache = /* @__PURE__ */ new Map();
|
|
279
|
+
function getValidator(schema) {
|
|
280
|
+
const key = JSON.stringify(schema);
|
|
281
|
+
let validator = validatorCache.get(key);
|
|
282
|
+
if (!validator) {
|
|
283
|
+
validator = ajv.compile(schema);
|
|
284
|
+
validatorCache.set(key, validator);
|
|
285
|
+
}
|
|
286
|
+
return validator;
|
|
287
|
+
}
|
|
288
|
+
var VISIBLE_ENABLED = { visible: true, enabled: true };
|
|
289
|
+
function unescapeToken(token) {
|
|
290
|
+
return token.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
291
|
+
}
|
|
292
|
+
function getAtPointer(data, pointer) {
|
|
293
|
+
if (pointer === "") return data;
|
|
294
|
+
if (!pointer.startsWith("/")) return void 0;
|
|
295
|
+
const tokens = pointer.slice(1).split("/").map(unescapeToken);
|
|
296
|
+
let current = data;
|
|
297
|
+
for (const token of tokens) {
|
|
298
|
+
if (current == null || typeof current !== "object") return void 0;
|
|
299
|
+
if (Array.isArray(current)) {
|
|
300
|
+
const idx = Number(token);
|
|
301
|
+
if (!Number.isInteger(idx) || idx < 0 || idx >= current.length)
|
|
302
|
+
return void 0;
|
|
303
|
+
current = current[idx];
|
|
304
|
+
} else {
|
|
305
|
+
current = current[token];
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return current;
|
|
309
|
+
}
|
|
310
|
+
function conditionHolds(rule, formData) {
|
|
311
|
+
const { scope, schema } = rule.condition;
|
|
312
|
+
const value = getAtPointer(formData, scope);
|
|
313
|
+
try {
|
|
314
|
+
const validator = getValidator(schema);
|
|
315
|
+
return !!validator(value);
|
|
316
|
+
} catch (error) {
|
|
317
|
+
warnLog("Error evaluating x-ui-rule condition:", error);
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function evaluateUiRule(rule, formData) {
|
|
322
|
+
if (!rule) return VISIBLE_ENABLED;
|
|
323
|
+
const holds = conditionHolds(rule, formData);
|
|
324
|
+
switch (rule.effect) {
|
|
325
|
+
case "show":
|
|
326
|
+
return { visible: holds, enabled: true };
|
|
327
|
+
case "hide":
|
|
328
|
+
return { visible: !holds, enabled: true };
|
|
329
|
+
case "enable":
|
|
330
|
+
return { visible: true, enabled: holds };
|
|
331
|
+
case "disable":
|
|
332
|
+
return { visible: true, enabled: !holds };
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
215
336
|
// src/schema/schemaUtils.ts
|
|
216
337
|
function applySchemaDefaults(data, schema) {
|
|
217
338
|
const result = { ...data };
|
|
@@ -269,51 +390,56 @@ function extractDefName(ref) {
|
|
|
269
390
|
const match = ref.match(/^#\/(\$defs|definitions)\/(.+)$/);
|
|
270
391
|
return match ? match[2] : null;
|
|
271
392
|
}
|
|
272
|
-
function
|
|
393
|
+
function inDocumentResolver(defs) {
|
|
394
|
+
return (ref) => {
|
|
395
|
+
const name = extractDefName(ref);
|
|
396
|
+
return name ? defs[name] : void 0;
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
function resolveRef(node, resolve, seen) {
|
|
273
400
|
const ref = node.$ref;
|
|
274
|
-
const
|
|
275
|
-
if (!
|
|
401
|
+
const resolved = resolve(ref);
|
|
402
|
+
if (!resolved) return node;
|
|
276
403
|
if (seen.has(ref)) return node;
|
|
277
404
|
seen.add(ref);
|
|
278
|
-
const resolved = defs[name];
|
|
279
405
|
const overrides = Object.fromEntries(
|
|
280
406
|
Object.entries(node).filter(([k]) => k !== "$ref")
|
|
281
407
|
);
|
|
282
408
|
const merged = Object.keys(overrides).length > 0 ? { ...resolved, ...overrides } : resolved;
|
|
283
|
-
const result = resolveNode(merged,
|
|
409
|
+
const result = resolveNode(merged, resolve, seen);
|
|
284
410
|
seen.delete(ref);
|
|
285
411
|
return result;
|
|
286
412
|
}
|
|
287
|
-
function resolveList(list,
|
|
288
|
-
const resolved = list.map((s) => resolveNode(s,
|
|
413
|
+
function resolveList(list, resolve, seen) {
|
|
414
|
+
const resolved = list.map((s) => resolveNode(s, resolve, seen));
|
|
289
415
|
return resolved.some((s, i) => s !== list[i]) ? resolved : null;
|
|
290
416
|
}
|
|
291
|
-
function resolveProperties(props,
|
|
417
|
+
function resolveProperties(props, resolve, seen) {
|
|
292
418
|
const entries = Object.entries(props);
|
|
293
419
|
const resolved = entries.map(
|
|
294
|
-
([k, v]) => [k, resolveNode(v,
|
|
420
|
+
([k, v]) => [k, resolveNode(v, resolve, seen)]
|
|
295
421
|
);
|
|
296
422
|
return resolved.some(([, v], i) => v !== entries[i][1]) ? Object.fromEntries(resolved) : null;
|
|
297
423
|
}
|
|
298
|
-
function resolveItems(items,
|
|
299
|
-
const r = resolveNode(items,
|
|
424
|
+
function resolveItems(items, resolve, seen) {
|
|
425
|
+
const r = resolveNode(items, resolve, seen);
|
|
300
426
|
return r !== items ? r : null;
|
|
301
427
|
}
|
|
302
|
-
function resolveChildren(node,
|
|
428
|
+
function resolveChildren(node, resolve, seen) {
|
|
303
429
|
const overrides = {};
|
|
304
430
|
let changed = false;
|
|
305
|
-
const props = node.properties ? resolveProperties(node.properties,
|
|
431
|
+
const props = node.properties ? resolveProperties(node.properties, resolve, seen) : null;
|
|
306
432
|
if (props) {
|
|
307
433
|
overrides.properties = props;
|
|
308
434
|
changed = true;
|
|
309
435
|
}
|
|
310
|
-
const items = node.items ? resolveItems(node.items,
|
|
436
|
+
const items = node.items ? resolveItems(node.items, resolve, seen) : null;
|
|
311
437
|
if (items) {
|
|
312
438
|
overrides.items = items;
|
|
313
439
|
changed = true;
|
|
314
440
|
}
|
|
315
441
|
for (const key of ["allOf", "anyOf", "oneOf"]) {
|
|
316
|
-
const list = node[key] ? resolveList(node[key],
|
|
442
|
+
const list = node[key] ? resolveList(node[key], resolve, seen) : null;
|
|
317
443
|
if (list) {
|
|
318
444
|
overrides[key] = list;
|
|
319
445
|
changed = true;
|
|
@@ -321,39 +447,60 @@ function resolveChildren(node, defs, seen) {
|
|
|
321
447
|
}
|
|
322
448
|
return changed ? overrides : null;
|
|
323
449
|
}
|
|
324
|
-
function resolveNode(node,
|
|
325
|
-
if (node.$ref) return resolveRef(node,
|
|
326
|
-
const overrides = resolveChildren(node,
|
|
450
|
+
function resolveNode(node, resolve, seen) {
|
|
451
|
+
if (node.$ref) return resolveRef(node, resolve, seen);
|
|
452
|
+
const overrides = resolveChildren(node, resolve, seen);
|
|
327
453
|
return overrides ? { ...node, ...overrides } : node;
|
|
328
454
|
}
|
|
329
|
-
function resolveRefs(schema) {
|
|
455
|
+
function resolveRefs(schema, resolve) {
|
|
330
456
|
const defs = schema.$defs ?? schema.definitions ?? {};
|
|
331
|
-
if (Object.keys(defs).length === 0) return schema;
|
|
457
|
+
if (!resolve && Object.keys(defs).length === 0) return schema;
|
|
458
|
+
const fallback = inDocumentResolver(defs);
|
|
459
|
+
const resolver = resolve ? (ref) => resolve(ref) ?? fallback(ref) : fallback;
|
|
332
460
|
const seen = /* @__PURE__ */ new Set();
|
|
333
461
|
const resolved = resolveNode(
|
|
334
462
|
schema,
|
|
335
|
-
|
|
463
|
+
resolver,
|
|
336
464
|
seen
|
|
337
465
|
);
|
|
338
466
|
return resolved;
|
|
339
467
|
}
|
|
340
468
|
|
|
341
469
|
// src/schema/validateFormData.ts
|
|
470
|
+
function escapePointerToken(token) {
|
|
471
|
+
return token.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
472
|
+
}
|
|
342
473
|
function isEmpty(value) {
|
|
343
474
|
return value === void 0 || value === null || value === "";
|
|
344
475
|
}
|
|
345
|
-
function fieldLabel(path, fieldName, property) {
|
|
346
|
-
return path ? `${path} > ${getFieldTitle(fieldName, property)}` : getFieldTitle(fieldName, property);
|
|
347
|
-
}
|
|
348
476
|
function isPlainObject(value) {
|
|
349
477
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
350
478
|
}
|
|
351
|
-
function
|
|
479
|
+
function childContext(parent, fieldName, property) {
|
|
480
|
+
const title = getFieldTitle(fieldName, property);
|
|
481
|
+
return {
|
|
482
|
+
label: parent.label ? `${parent.label} > ${title}` : title,
|
|
483
|
+
pointer: `${parent.pointer}/${escapePointerToken(fieldName)}`
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
function itemContext(parent, index) {
|
|
487
|
+
return {
|
|
488
|
+
label: `${parent.label}[${index + 1}]`,
|
|
489
|
+
pointer: `${parent.pointer}/${index}`
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
function validateArray(property, value, ctx, out) {
|
|
352
493
|
if (property.minItems !== void 0 && value.length < property.minItems) {
|
|
353
|
-
|
|
494
|
+
out.push({
|
|
495
|
+
pointer: ctx.pointer,
|
|
496
|
+
message: `${ctx.label} requires at least ${property.minItems} item(s)`
|
|
497
|
+
});
|
|
354
498
|
}
|
|
355
499
|
if (property.maxItems !== void 0 && value.length > property.maxItems) {
|
|
356
|
-
|
|
500
|
+
out.push({
|
|
501
|
+
pointer: ctx.pointer,
|
|
502
|
+
message: `${ctx.label} allows at most ${property.maxItems} item(s)`
|
|
503
|
+
});
|
|
357
504
|
}
|
|
358
505
|
if (!property.items?.properties) return;
|
|
359
506
|
const itemProperties = property.items.properties;
|
|
@@ -364,8 +511,8 @@ function validateArray(property, value, label, errors) {
|
|
|
364
511
|
itemProperties,
|
|
365
512
|
itemSchema,
|
|
366
513
|
value[i],
|
|
367
|
-
|
|
368
|
-
|
|
514
|
+
itemContext(ctx, i),
|
|
515
|
+
out
|
|
369
516
|
);
|
|
370
517
|
}
|
|
371
518
|
}
|
|
@@ -373,32 +520,47 @@ function validateArray(property, value, label, errors) {
|
|
|
373
520
|
function isNestedObject(property, value) {
|
|
374
521
|
return property.type === "object" && !!property.properties && isPlainObject(value);
|
|
375
522
|
}
|
|
376
|
-
function validateField(property, value, required,
|
|
523
|
+
function validateField(property, value, required, ctx, out) {
|
|
377
524
|
if (required && isEmpty(value)) {
|
|
378
|
-
|
|
525
|
+
out.push({ pointer: ctx.pointer, message: `${ctx.label} is required` });
|
|
379
526
|
return;
|
|
380
527
|
}
|
|
381
528
|
if (isNestedObject(property, value)) {
|
|
382
|
-
validateObject(property.properties, property, value,
|
|
529
|
+
validateObject(property.properties, property, value, ctx, out);
|
|
383
530
|
return;
|
|
384
531
|
}
|
|
385
532
|
if (property.type === "array" && Array.isArray(value)) {
|
|
386
|
-
validateArray(property, value,
|
|
533
|
+
validateArray(property, value, ctx, out);
|
|
387
534
|
}
|
|
388
535
|
}
|
|
389
|
-
function validateObject(properties, schema, data,
|
|
536
|
+
function validateObject(properties, schema, data, ctx, out) {
|
|
390
537
|
for (const fieldName of Object.keys(properties)) {
|
|
391
538
|
const property = properties[fieldName];
|
|
392
539
|
const required = schema.required?.includes(fieldName) ?? false;
|
|
393
|
-
|
|
394
|
-
|
|
540
|
+
validateField(
|
|
541
|
+
property,
|
|
542
|
+
data[fieldName],
|
|
543
|
+
required,
|
|
544
|
+
childContext(ctx, fieldName, property),
|
|
545
|
+
out
|
|
546
|
+
);
|
|
395
547
|
}
|
|
396
548
|
}
|
|
397
549
|
function validateFormData(schema, data) {
|
|
398
|
-
const
|
|
550
|
+
const fieldErrors = [];
|
|
399
551
|
const properties = getSchemaProperties(schema);
|
|
400
|
-
validateObject(
|
|
401
|
-
|
|
552
|
+
validateObject(
|
|
553
|
+
properties,
|
|
554
|
+
schema,
|
|
555
|
+
data,
|
|
556
|
+
{ label: "", pointer: "" },
|
|
557
|
+
fieldErrors
|
|
558
|
+
);
|
|
559
|
+
return {
|
|
560
|
+
errors: fieldErrors.map((e) => e.message),
|
|
561
|
+
fieldErrors,
|
|
562
|
+
isValid: fieldErrors.length === 0
|
|
563
|
+
};
|
|
402
564
|
}
|
|
403
565
|
|
|
404
566
|
// src/schema/diffFormData.ts
|
|
@@ -545,11 +707,18 @@ function diffFormData(original, updated) {
|
|
|
545
707
|
}
|
|
546
708
|
export {
|
|
547
709
|
WIDTH_TOKEN_REMS,
|
|
710
|
+
ajv,
|
|
548
711
|
applySchemaDefaults,
|
|
549
712
|
diffFormData,
|
|
713
|
+
evaluateUiRule,
|
|
550
714
|
extractEnumValues,
|
|
551
715
|
extractSchemaDefaults,
|
|
716
|
+
findActiveBranch,
|
|
552
717
|
generateJsonSchemaFromVariables,
|
|
718
|
+
getAtPointer,
|
|
719
|
+
getBranchLabel,
|
|
720
|
+
getBranchValue,
|
|
721
|
+
getDiscriminator,
|
|
553
722
|
getFieldConstraints,
|
|
554
723
|
getFieldDefault,
|
|
555
724
|
getFieldHelpText,
|
|
@@ -565,6 +734,7 @@ export {
|
|
|
565
734
|
isFieldOptional,
|
|
566
735
|
isFieldRequired,
|
|
567
736
|
isNullableBoolean,
|
|
737
|
+
isOneOf,
|
|
568
738
|
matchesConst,
|
|
569
739
|
resolveRefs,
|
|
570
740
|
resolveSchema,
|