@tokenoftrust/cli 2.0.22 → 2.0.23

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/validate.mjs +17 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokenoftrust/cli",
3
- "version": "2.0.22",
3
+ "version": "2.0.23",
4
4
  "description": "Token of Trust developer CLI — clone a tenant store, run it locally with save→reload, and submit it for preview. Installs the `tot` command.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Token of Trust",
package/src/validate.mjs CHANGED
@@ -321,7 +321,9 @@ export const BLOCK_PALETTE_SUPPORTED_CONTRACTS = Object.freeze([
321
321
  "block-palette@3",
322
322
  "block-palette@4",
323
323
  "block-palette@5",
324
+ "block-palette@6",
324
325
  ]);
326
+ export const FEATURED_PRODUCT_PRESENTATIONS = Object.freeze(["grid", "carousel"]);
325
327
  const SUPPORTED_BLOCK_CONTRACTS = new Set(BLOCK_PALETTE_SUPPORTED_CONTRACTS);
326
328
  const KNOWN_BLOCKS = new Set([
327
329
  "hero",
@@ -494,6 +496,19 @@ function validatePromoTiles(block, file, at, out, tenantId) {
494
496
  }
495
497
  }
496
498
 
499
+ function validateHeroSlides(slides, file, at, out, tenantId) {
500
+ if (!Array.isArray(slides) || slides.length === 0) { out.push(mk(ERROR, "block-prop", file, `${at}.slides must be a non-empty array`)); return; }
501
+ slides.forEach((slide, index) => {
502
+ const slideAt = `${at}.slides[${index}]`;
503
+ if (slide == null || typeof slide !== "object" || Array.isArray(slide)) { out.push(mk(ERROR, "block-prop", file, `${slideAt} must be an object`)); return; }
504
+ for (const prop of ["image", "imageAlt"]) if (typeof slide[prop] !== "string" || !slide[prop].trim()) out.push(mk(ERROR, "block-required", file, `${slideAt}.${prop} must be a non-empty string`));
505
+ validateVisualAsset(slide.image, file, `${slideAt}.image`, out, tenantId);
506
+ for (const prop of ["headline", "ctaLabel", "ctaHref"]) if (slide[prop] !== undefined && (typeof slide[prop] !== "string" || !slide[prop].trim())) out.push(mk(ERROR, "block-prop", file, `${slideAt}.${prop} must be a non-empty string`));
507
+ if ((slide.ctaLabel === undefined) !== (slide.ctaHref === undefined)) out.push(mk(ERROR, "block-required", file, `${slideAt}.ctaLabel and ${slideAt}.ctaHref must be supplied together`));
508
+ if (typeof slide.ctaHref === "string" && !isSafeStorefrontHref(slide.ctaHref)) out.push(mk(ERROR, "navigation-href", file, `${slideAt}.ctaHref must be a same-storefront root-relative path`));
509
+ });
510
+ }
511
+
497
512
  function validateTrustStrip(block, file, at, out, tenantId) {
498
513
  if (!Array.isArray(block.items)) {
499
514
  out.push(mk(ERROR, "block-prop", file, `${at}.items must be an array`));
@@ -582,10 +597,12 @@ function validateHomeDoc(doc, file, tenantId) {
582
597
  if (block.limit !== undefined && typeof block.limit !== "number") {
583
598
  out.push(mk(ERROR, "block-prop", file, `${at}.limit must be a number`));
584
599
  }
600
+ if (block.presentation !== undefined && !FEATURED_PRODUCT_PRESENTATIONS.includes(block.presentation)) out.push(mk(ERROR, "block-prop", file, `${at}.presentation must be grid or carousel`));
585
601
  }
586
602
  if (component === "hero" && block.image !== undefined) {
587
603
  validateVisualAsset(block.image, file, `${at}.image`, out, tenantId);
588
604
  }
605
+ if (component === "hero" && block.slides !== undefined) validateHeroSlides(block.slides, file, at, out, tenantId);
589
606
  if (component === "editorial" && block.image !== undefined) {
590
607
  validateVisualAsset(block.image, file, `${at}.image`, out, tenantId);
591
608
  if (typeof block.imageAlt !== "string") {