@petrarca/sonnet-core 0.4.2 → 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.
@@ -6,6 +6,15 @@ import {
6
6
  isEqual
7
7
  } from "../chunk-XCCOEUVC.js";
8
8
 
9
+ // src/schema/types.ts
10
+ var WIDTH_TOKEN_REMS = {
11
+ sm: "8rem",
12
+ md: "12rem",
13
+ lg: "16rem",
14
+ full: "1fr"
15
+ // grid track only; field slots use w-full instead
16
+ };
17
+
9
18
  // src/schema/schemaService.ts
10
19
  function getSchemaProperties(schema) {
11
20
  return schema.properties || {};
@@ -87,6 +96,48 @@ function hasProperties(schema) {
87
96
  return Object.keys(schema.properties || {}).length > 0;
88
97
  }
89
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
+
90
141
  // src/schema/schemaResolver.ts
91
142
  import Ajv from "ajv";
92
143
  import addFormats from "ajv-formats";
@@ -103,9 +154,29 @@ function resolveSchema(schema, formData) {
103
154
  return schema;
104
155
  }
105
156
  let resolvedSchema = resolveAllOf(schema, formData);
157
+ resolvedSchema = resolveAnyOfConditionals(resolvedSchema, formData);
106
158
  resolvedSchema = resolveConditionals(resolvedSchema, formData);
107
159
  return resolvedSchema;
108
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
+ }
109
180
  function resolveConditionals(schema, formData) {
110
181
  if (!schema.if) {
111
182
  return schema;
@@ -203,6 +274,65 @@ function hasConditionals(schema) {
203
274
  return !!(schema.if || schema.allOf || schema.anyOf || schema.oneOf);
204
275
  }
205
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
+
206
336
  // src/schema/schemaUtils.ts
207
337
  function applySchemaDefaults(data, schema) {
208
338
  const result = { ...data };
@@ -260,51 +390,56 @@ function extractDefName(ref) {
260
390
  const match = ref.match(/^#\/(\$defs|definitions)\/(.+)$/);
261
391
  return match ? match[2] : null;
262
392
  }
263
- function resolveRef(node, defs, seen) {
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) {
264
400
  const ref = node.$ref;
265
- const name = extractDefName(ref);
266
- if (!name || !defs[name]) return node;
401
+ const resolved = resolve(ref);
402
+ if (!resolved) return node;
267
403
  if (seen.has(ref)) return node;
268
404
  seen.add(ref);
269
- const resolved = defs[name];
270
405
  const overrides = Object.fromEntries(
271
406
  Object.entries(node).filter(([k]) => k !== "$ref")
272
407
  );
273
408
  const merged = Object.keys(overrides).length > 0 ? { ...resolved, ...overrides } : resolved;
274
- const result = resolveNode(merged, defs, seen);
409
+ const result = resolveNode(merged, resolve, seen);
275
410
  seen.delete(ref);
276
411
  return result;
277
412
  }
278
- function resolveList(list, defs, seen) {
279
- const resolved = list.map((s) => resolveNode(s, defs, seen));
413
+ function resolveList(list, resolve, seen) {
414
+ const resolved = list.map((s) => resolveNode(s, resolve, seen));
280
415
  return resolved.some((s, i) => s !== list[i]) ? resolved : null;
281
416
  }
282
- function resolveProperties(props, defs, seen) {
417
+ function resolveProperties(props, resolve, seen) {
283
418
  const entries = Object.entries(props);
284
419
  const resolved = entries.map(
285
- ([k, v]) => [k, resolveNode(v, defs, seen)]
420
+ ([k, v]) => [k, resolveNode(v, resolve, seen)]
286
421
  );
287
422
  return resolved.some(([, v], i) => v !== entries[i][1]) ? Object.fromEntries(resolved) : null;
288
423
  }
289
- function resolveItems(items, defs, seen) {
290
- const r = resolveNode(items, defs, seen);
424
+ function resolveItems(items, resolve, seen) {
425
+ const r = resolveNode(items, resolve, seen);
291
426
  return r !== items ? r : null;
292
427
  }
293
- function resolveChildren(node, defs, seen) {
428
+ function resolveChildren(node, resolve, seen) {
294
429
  const overrides = {};
295
430
  let changed = false;
296
- const props = node.properties ? resolveProperties(node.properties, defs, seen) : null;
431
+ const props = node.properties ? resolveProperties(node.properties, resolve, seen) : null;
297
432
  if (props) {
298
433
  overrides.properties = props;
299
434
  changed = true;
300
435
  }
301
- const items = node.items ? resolveItems(node.items, defs, seen) : null;
436
+ const items = node.items ? resolveItems(node.items, resolve, seen) : null;
302
437
  if (items) {
303
438
  overrides.items = items;
304
439
  changed = true;
305
440
  }
306
441
  for (const key of ["allOf", "anyOf", "oneOf"]) {
307
- const list = node[key] ? resolveList(node[key], defs, seen) : null;
442
+ const list = node[key] ? resolveList(node[key], resolve, seen) : null;
308
443
  if (list) {
309
444
  overrides[key] = list;
310
445
  changed = true;
@@ -312,39 +447,60 @@ function resolveChildren(node, defs, seen) {
312
447
  }
313
448
  return changed ? overrides : null;
314
449
  }
315
- function resolveNode(node, defs, seen) {
316
- if (node.$ref) return resolveRef(node, defs, seen);
317
- const overrides = resolveChildren(node, defs, seen);
450
+ function resolveNode(node, resolve, seen) {
451
+ if (node.$ref) return resolveRef(node, resolve, seen);
452
+ const overrides = resolveChildren(node, resolve, seen);
318
453
  return overrides ? { ...node, ...overrides } : node;
319
454
  }
320
- function resolveRefs(schema) {
455
+ function resolveRefs(schema, resolve) {
321
456
  const defs = schema.$defs ?? schema.definitions ?? {};
322
- 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;
323
460
  const seen = /* @__PURE__ */ new Set();
324
461
  const resolved = resolveNode(
325
462
  schema,
326
- defs,
463
+ resolver,
327
464
  seen
328
465
  );
329
466
  return resolved;
330
467
  }
331
468
 
332
469
  // src/schema/validateFormData.ts
470
+ function escapePointerToken(token) {
471
+ return token.replace(/~/g, "~0").replace(/\//g, "~1");
472
+ }
333
473
  function isEmpty(value) {
334
474
  return value === void 0 || value === null || value === "";
335
475
  }
336
- function fieldLabel(path, fieldName, property) {
337
- return path ? `${path} > ${getFieldTitle(fieldName, property)}` : getFieldTitle(fieldName, property);
338
- }
339
476
  function isPlainObject(value) {
340
477
  return value !== null && typeof value === "object" && !Array.isArray(value);
341
478
  }
342
- function validateArray(property, value, label, errors) {
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) {
343
493
  if (property.minItems !== void 0 && value.length < property.minItems) {
344
- errors.push(`${label} requires at least ${property.minItems} item(s)`);
494
+ out.push({
495
+ pointer: ctx.pointer,
496
+ message: `${ctx.label} requires at least ${property.minItems} item(s)`
497
+ });
345
498
  }
346
499
  if (property.maxItems !== void 0 && value.length > property.maxItems) {
347
- errors.push(`${label} allows at most ${property.maxItems} item(s)`);
500
+ out.push({
501
+ pointer: ctx.pointer,
502
+ message: `${ctx.label} allows at most ${property.maxItems} item(s)`
503
+ });
348
504
  }
349
505
  if (!property.items?.properties) return;
350
506
  const itemProperties = property.items.properties;
@@ -355,8 +511,8 @@ function validateArray(property, value, label, errors) {
355
511
  itemProperties,
356
512
  itemSchema,
357
513
  value[i],
358
- `${label}[${i + 1}]`,
359
- errors
514
+ itemContext(ctx, i),
515
+ out
360
516
  );
361
517
  }
362
518
  }
@@ -364,32 +520,47 @@ function validateArray(property, value, label, errors) {
364
520
  function isNestedObject(property, value) {
365
521
  return property.type === "object" && !!property.properties && isPlainObject(value);
366
522
  }
367
- function validateField(property, value, required, label, errors) {
523
+ function validateField(property, value, required, ctx, out) {
368
524
  if (required && isEmpty(value)) {
369
- errors.push(`${label} is required`);
525
+ out.push({ pointer: ctx.pointer, message: `${ctx.label} is required` });
370
526
  return;
371
527
  }
372
528
  if (isNestedObject(property, value)) {
373
- validateObject(property.properties, property, value, label, errors);
529
+ validateObject(property.properties, property, value, ctx, out);
374
530
  return;
375
531
  }
376
532
  if (property.type === "array" && Array.isArray(value)) {
377
- validateArray(property, value, label, errors);
533
+ validateArray(property, value, ctx, out);
378
534
  }
379
535
  }
380
- function validateObject(properties, schema, data, path, errors) {
536
+ function validateObject(properties, schema, data, ctx, out) {
381
537
  for (const fieldName of Object.keys(properties)) {
382
538
  const property = properties[fieldName];
383
539
  const required = schema.required?.includes(fieldName) ?? false;
384
- const label = fieldLabel(path, fieldName, property);
385
- validateField(property, data[fieldName], required, label, errors);
540
+ validateField(
541
+ property,
542
+ data[fieldName],
543
+ required,
544
+ childContext(ctx, fieldName, property),
545
+ out
546
+ );
386
547
  }
387
548
  }
388
549
  function validateFormData(schema, data) {
389
- const errors = [];
550
+ const fieldErrors = [];
390
551
  const properties = getSchemaProperties(schema);
391
- validateObject(properties, schema, data, "", errors);
392
- return { errors, isValid: errors.length === 0 };
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
+ };
393
564
  }
394
565
 
395
566
  // src/schema/diffFormData.ts
@@ -535,11 +706,19 @@ function diffFormData(original, updated) {
535
706
  return diff;
536
707
  }
537
708
  export {
709
+ WIDTH_TOKEN_REMS,
710
+ ajv,
538
711
  applySchemaDefaults,
539
712
  diffFormData,
713
+ evaluateUiRule,
540
714
  extractEnumValues,
541
715
  extractSchemaDefaults,
716
+ findActiveBranch,
542
717
  generateJsonSchemaFromVariables,
718
+ getAtPointer,
719
+ getBranchLabel,
720
+ getBranchValue,
721
+ getDiscriminator,
543
722
  getFieldConstraints,
544
723
  getFieldDefault,
545
724
  getFieldHelpText,
@@ -555,6 +734,7 @@ export {
555
734
  isFieldOptional,
556
735
  isFieldRequired,
557
736
  isNullableBoolean,
737
+ isOneOf,
558
738
  matchesConst,
559
739
  resolveRefs,
560
740
  resolveSchema,