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