@taprootio/site-authoring 0.12.5 → 0.12.7

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.
@@ -15,6 +15,8 @@ import {
15
15
  } from "../fixture-contract.js";
16
16
  import { initializeFixture } from "../fixture-init.js";
17
17
  import { appearanceManifestEntry, FOOTER_SETTINGS_FILE, footerManifestEntry } from "../footer-workspace.js";
18
+ import { readWorkspaceForms } from "../forms-workspace.js";
19
+ import { FORMS_DIRECTORY } from "../forms-contract.js";
18
20
  import {
19
21
  isRedirectMapRevision,
20
22
  normalizeRedirectPath,
@@ -405,6 +407,57 @@ function headerWidthHints(headerWidth, rootBandPages) {
405
407
  }];
406
408
  }
407
409
 
410
+ /**
411
+ * The fixture's forms, when it carries any. The manifest binding and the files
412
+ * must name the same keys: a form file the manifest does not mention would be
413
+ * validated by no one, and a key with no file would be a baseline for nothing.
414
+ * Returns undefined for a fixture with no forms.
415
+ */
416
+ async function validateFixtureForms(fixtureRoot, bound, onProgress) {
417
+ const files = await readWorkspaceForms(fixtureRoot);
418
+ if (bound === undefined) {
419
+ if (files.length > 0) {
420
+ fail(
421
+ "fixture.forms_unbound",
422
+ "The fixture carries form files but its manifest does not bind them in 'forms'.",
423
+ "forms",
424
+ );
425
+ }
426
+ return undefined;
427
+ }
428
+ const items = isPlainObject(bound) && isPlainObject(bound.items) ? bound.items : undefined;
429
+ const keys = items === undefined ? [] : Object.keys(items).sort();
430
+ if (
431
+ items === undefined
432
+ || Object.keys(bound).length !== 1
433
+ || keys.length === 0
434
+ || keys.some((key) =>
435
+ !isPlainObject(items[key])
436
+ || Object.keys(items[key]).sort().join() !== "id,version"
437
+ || !isCanonicalUuid(items[key].id)
438
+ || !Number.isSafeInteger(items[key].version)
439
+ || items[key].version < 1
440
+ )
441
+ ) {
442
+ fail(
443
+ "fixture.forms_invalid",
444
+ "The fixture manifest's 'forms' must be { items: { <key>: { id, version } } } with at least one form, "
445
+ + "a canonical UUID id, and a positive version.",
446
+ "forms",
447
+ );
448
+ }
449
+ const fileKeys = files.map((form) => form.key);
450
+ if (fileKeys.join() !== keys.join()) {
451
+ fail(
452
+ "fixture.forms_mismatch",
453
+ `The fixture manifest binds forms [${keys.join(", ")}] but ${FORMS_DIRECTORY}/ holds [${fileKeys.join(", ")}].`,
454
+ "forms",
455
+ );
456
+ }
457
+ onProgress(`Validated ${files.length} form file${files.length === 1 ? "" : "s"} against the shared field schema.`);
458
+ return files;
459
+ }
460
+
408
461
  export async function validateFixture(invocation = {}) {
409
462
  if (invocation.init) return await initializeFixture(invocation, validateFixture);
410
463
  const onProgress = typeof invocation.onProgress === "function" ? invocation.onProgress : () => {};
@@ -597,6 +650,8 @@ export async function validateFixture(invocation = {}) {
597
650
  },
598
651
  );
599
652
 
653
+ const forms = await validateFixtureForms(fixtureRoot, manifest.forms, onProgress);
654
+
600
655
  const reportedPages = boundedList(validatedPages, MAXIMUM_REPORTED);
601
656
  onProgress(
602
657
  `Validated ${validatedPages.length} page(s), ${navigation.items} navigation item(s), two themes, appearance, and footer without credentials or mutation.`,
@@ -620,6 +675,7 @@ export async function validateFixture(invocation = {}) {
620
675
  entries: redirects.entries.length,
621
676
  gone: redirects.entries.filter((entry) => entry.kind === REDIRECT_KIND_GONE).length,
622
677
  },
678
+ ...(forms === undefined ? {} : { forms: { count: forms.length } }),
623
679
  themes: 2,
624
680
  appearanceSettings: presentation.scalarOperations.length,
625
681
  footer: true,
@@ -636,6 +692,7 @@ export async function validateFixture(invocation = {}) {
636
692
  "navigation shape and local page-resource references",
637
693
  "redirect-map shape, normalization, chains, loops, and fixture-local path occupancy",
638
694
  "complete theme, appearance, header, brand, and footer semantics",
695
+ "form files, when the manifest binds any, against the shared field schema",
639
696
  "fixture-local image identities and reserved delivery origins",
640
697
  ],
641
698
  doesNotProve: [