@safe-ugc-ui/validator 1.0.0 → 1.1.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/index.js CHANGED
@@ -648,8 +648,10 @@ var STRUCTURED_OBJECT_STYLE_PROPERTIES = /* @__PURE__ */ new Set([
648
648
  "borderLeft",
649
649
  // Shadow
650
650
  "boxShadow",
651
- "textShadow"
651
+ "textShadow",
652
+ "clipPath"
652
653
  ]);
654
+ var RESPONSIVE_OVERRIDE_KEYS = ["medium", "compact"];
653
655
  function validateNodeStyle(style, path, errors) {
654
656
  if (!style) {
655
657
  return;
@@ -690,13 +692,15 @@ function validateValueTypes(views, fragments) {
690
692
  validateNodeStyle(style, `${ctx.path}.style`, errors);
691
693
  const responsive = node.responsive;
692
694
  if (responsive != null && typeof responsive === "object" && !Array.isArray(responsive)) {
693
- const compact = responsive.compact;
694
- if (compact != null && typeof compact === "object" && !Array.isArray(compact)) {
695
- validateNodeStyle(
696
- compact,
697
- `${ctx.path}.responsive.compact`,
698
- errors
699
- );
695
+ for (const mode of RESPONSIVE_OVERRIDE_KEYS) {
696
+ const override = responsive[mode];
697
+ if (override != null && typeof override === "object" && !Array.isArray(override)) {
698
+ validateNodeStyle(
699
+ override,
700
+ `${ctx.path}.responsive.${mode}`,
701
+ errors
702
+ );
703
+ }
700
704
  }
701
705
  }
702
706
  });
@@ -726,6 +730,7 @@ import {
726
730
  LETTER_SPACING_MAX,
727
731
  OPACITY_MIN,
728
732
  OPACITY_MAX,
733
+ BACKDROP_BLUR_MAX,
729
734
  CSS_NAMED_COLORS,
730
735
  TRANSITION_DURATION_MAX,
731
736
  TRANSITION_DELAY_MAX,
@@ -771,6 +776,7 @@ var LENGTH_AUTO_ALLOWED = /* @__PURE__ */ new Set([
771
776
  "marginBottom",
772
777
  "marginLeft"
773
778
  ]);
779
+ var RESPONSIVE_OVERRIDE_KEYS2 = ["medium", "compact"];
774
780
  var RANGE_LENGTH_PROPERTIES = {
775
781
  fontSize: { min: FONT_SIZE_MIN, max: FONT_SIZE_MAX },
776
782
  letterSpacing: { min: LETTER_SPACING_MIN, max: LETTER_SPACING_MAX },
@@ -912,6 +918,44 @@ function validateTextShadowObject(shadow, path, errors) {
912
918
  );
913
919
  }
914
920
  }
921
+ function validateClipPathLength(value, path, errors) {
922
+ if (value == null || isDynamic(value)) {
923
+ return;
924
+ }
925
+ if (typeof value === "number") {
926
+ return;
927
+ }
928
+ if (typeof value === "string" && isValidLength(value)) {
929
+ return;
930
+ }
931
+ errors.push(
932
+ createError(
933
+ "INVALID_LENGTH",
934
+ `Invalid length "${String(value)}" at "${path}"`,
935
+ path
936
+ )
937
+ );
938
+ }
939
+ function validateClipPathObject(clipPath, path, errors) {
940
+ switch (clipPath.type) {
941
+ case "circle":
942
+ validateClipPathLength(clipPath.radius, `${path}.radius`, errors);
943
+ return;
944
+ case "ellipse":
945
+ validateClipPathLength(clipPath.rx, `${path}.rx`, errors);
946
+ validateClipPathLength(clipPath.ry, `${path}.ry`, errors);
947
+ return;
948
+ case "inset":
949
+ validateClipPathLength(clipPath.top, `${path}.top`, errors);
950
+ validateClipPathLength(clipPath.right, `${path}.right`, errors);
951
+ validateClipPathLength(clipPath.bottom, `${path}.bottom`, errors);
952
+ validateClipPathLength(clipPath.left, `${path}.left`, errors);
953
+ validateClipPathLength(clipPath.round, `${path}.round`, errors);
954
+ return;
955
+ default:
956
+ return;
957
+ }
958
+ }
915
959
  var STYLE_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*$/;
916
960
  function reportStyleRefError(rawRef, stylePath, cardStyles, errors) {
917
961
  const trimmedRef = rawRef.trim();
@@ -1046,6 +1090,18 @@ function validateSingleStyle(style, stylePath, errors, cardStyles, options = {})
1046
1090
  );
1047
1091
  }
1048
1092
  }
1093
+ if ("backdropBlur" in style && isLiteralNumber(style.backdropBlur)) {
1094
+ const v = style.backdropBlur;
1095
+ if (v < 0 || v > BACKDROP_BLUR_MAX) {
1096
+ errors.push(
1097
+ createError(
1098
+ "STYLE_VALUE_OUT_OF_RANGE",
1099
+ `backdropBlur (${v}) must be between 0 and ${BACKDROP_BLUR_MAX} at "${stylePath}.backdropBlur"`,
1100
+ `${stylePath}.backdropBlur`
1101
+ )
1102
+ );
1103
+ }
1104
+ }
1049
1105
  if ("letterSpacing" in style && isLiteralNumber(style.letterSpacing)) {
1050
1106
  const v = style.letterSpacing;
1051
1107
  if (v < LETTER_SPACING_MIN || v > LETTER_SPACING_MAX) {
@@ -1250,6 +1306,13 @@ function validateSingleStyle(style, stylePath, errors, cardStyles, options = {})
1250
1306
  );
1251
1307
  }
1252
1308
  }
1309
+ if ("clipPath" in style && style.clipPath != null && typeof style.clipPath === "object" && !Array.isArray(style.clipPath) && !isDynamic(style.clipPath)) {
1310
+ validateClipPathObject(
1311
+ style.clipPath,
1312
+ `${stylePath}.clipPath`,
1313
+ errors
1314
+ );
1315
+ }
1253
1316
  for (const [prop, range] of Object.entries(RANGE_LENGTH_PROPERTIES)) {
1254
1317
  if (prop in style && isLiteralString(style[prop]) && !isDynamic(style[prop])) {
1255
1318
  const numericValue = parseLengthValue(style[prop]);
@@ -1446,21 +1509,23 @@ function validateStyles(views, cardStyles, fragments) {
1446
1509
  }
1447
1510
  const responsive = node.responsive;
1448
1511
  if (responsive != null && typeof responsive === "object" && !Array.isArray(responsive)) {
1449
- const compact = responsive.compact;
1450
- if (compact != null && typeof compact === "object" && !Array.isArray(compact)) {
1451
- const compactPath = `${ctx.path}.responsive.compact`;
1452
- const mergedCompact = resolveStyleRef(
1453
- compact,
1454
- compactPath,
1455
- cardStyles,
1456
- errors
1457
- );
1458
- if (mergedCompact) {
1459
- validateSingleStyle(mergedCompact, compactPath, errors, cardStyles, {
1460
- allowHoverStyle: false,
1461
- allowTransition: false,
1462
- allowHoverStyleRefs: false
1463
- });
1512
+ for (const mode of RESPONSIVE_OVERRIDE_KEYS2) {
1513
+ const override = responsive[mode];
1514
+ if (override != null && typeof override === "object" && !Array.isArray(override)) {
1515
+ const overridePath = `${ctx.path}.responsive.${mode}`;
1516
+ const mergedOverride = resolveStyleRef(
1517
+ override,
1518
+ overridePath,
1519
+ cardStyles,
1520
+ errors
1521
+ );
1522
+ if (mergedOverride) {
1523
+ validateSingleStyle(mergedOverride, overridePath, errors, cardStyles, {
1524
+ allowHoverStyle: false,
1525
+ allowTransition: false,
1526
+ allowHoverStyleRefs: false
1527
+ });
1528
+ }
1464
1529
  }
1465
1530
  }
1466
1531
  }
@@ -1501,6 +1566,7 @@ import {
1501
1566
  // src/responsive-utils.ts
1502
1567
  var RESPONSIVE_MODES = [
1503
1568
  "default",
1569
+ "medium",
1504
1570
  "compact"
1505
1571
  ];
1506
1572
  function mergeNamedStyle(style, cardStyles) {
@@ -1522,16 +1588,16 @@ function mergeNamedStyle(style, cardStyles) {
1522
1588
  const { $style: _, ...inlineWithoutStyleRef } = style;
1523
1589
  return { ...baseStyle, ...inlineWithoutStyleRef };
1524
1590
  }
1525
- function getCompactResponsiveStyle(node) {
1591
+ function getResponsiveStyle(node, mode) {
1526
1592
  const responsive = node.responsive;
1527
1593
  if (responsive == null || typeof responsive !== "object" || Array.isArray(responsive)) {
1528
1594
  return void 0;
1529
1595
  }
1530
- const compact = responsive.compact;
1531
- if (compact == null || typeof compact !== "object" || Array.isArray(compact)) {
1596
+ const override = responsive[mode];
1597
+ if (override == null || typeof override !== "object" || Array.isArray(override)) {
1532
1598
  return void 0;
1533
1599
  }
1534
- return compact;
1600
+ return override;
1535
1601
  }
1536
1602
  function stripResponsiveOnlyUnsupportedFields(style) {
1537
1603
  if (!style) return void 0;
@@ -1547,22 +1613,36 @@ function getEffectiveStyleForMode(node, cardStyles, mode) {
1547
1613
  if (mode === "default") {
1548
1614
  return baseStyle;
1549
1615
  }
1616
+ const mediumStyle = stripResponsiveOnlyUnsupportedFields(
1617
+ mergeNamedStyle(getResponsiveStyle(node, "medium"), cardStyles)
1618
+ );
1619
+ if (mode === "medium") {
1620
+ if (!mediumStyle) {
1621
+ return baseStyle;
1622
+ }
1623
+ return {
1624
+ ...baseStyle ?? {},
1625
+ ...mediumStyle
1626
+ };
1627
+ }
1550
1628
  const compactStyle = stripResponsiveOnlyUnsupportedFields(
1551
- mergeNamedStyle(getCompactResponsiveStyle(node), cardStyles)
1629
+ mergeNamedStyle(getResponsiveStyle(node, "compact"), cardStyles)
1552
1630
  );
1553
- if (!compactStyle) {
1631
+ if (!mediumStyle && !compactStyle) {
1554
1632
  return baseStyle;
1555
1633
  }
1556
1634
  return {
1557
1635
  ...baseStyle ?? {},
1636
+ ...mediumStyle ?? {},
1558
1637
  ...compactStyle
1559
1638
  };
1560
1639
  }
1561
- function getMergedCompactResponsiveStyle(node, cardStyles) {
1562
- return mergeNamedStyle(getCompactResponsiveStyle(node), cardStyles);
1640
+ function getMergedResponsiveStyleOverride(node, cardStyles, mode) {
1641
+ return mergeNamedStyle(getResponsiveStyle(node, mode), cardStyles);
1563
1642
  }
1564
1643
 
1565
1644
  // src/security.ts
1645
+ var RESPONSIVE_OVERRIDE_KEYS3 = ["medium", "compact"];
1566
1646
  var FORBIDDEN_URL_PREFIXES = [
1567
1647
  "http://",
1568
1648
  "https://",
@@ -1825,13 +1905,15 @@ function validateSecurity(card) {
1825
1905
  scanStyleStringsForUrl(style, `${path}.style`, errors);
1826
1906
  const responsive = traversableNode.responsive;
1827
1907
  if (responsive != null && typeof responsive === "object" && !Array.isArray(responsive)) {
1828
- const compact = responsive.compact;
1829
- if (compact != null && typeof compact === "object" && !Array.isArray(compact)) {
1830
- scanStyleStringsForUrl(
1831
- compact,
1832
- `${path}.responsive.compact`,
1833
- errors
1834
- );
1908
+ for (const mode of RESPONSIVE_OVERRIDE_KEYS3) {
1909
+ const override = responsive[mode];
1910
+ if (override != null && typeof override === "object" && !Array.isArray(override)) {
1911
+ scanStyleStringsForUrl(
1912
+ override,
1913
+ `${path}.responsive.${mode}`,
1914
+ errors
1915
+ );
1916
+ }
1835
1917
  }
1836
1918
  }
1837
1919
  if (type === "Text" && Array.isArray(traversableNode.spans)) {
@@ -1982,6 +2064,7 @@ function countTemplateMetrics(template, cardStyles, fragments) {
1982
2064
  styleBytes: 0,
1983
2065
  overflowAutoCount: {
1984
2066
  default: 0,
2067
+ medium: 0,
1985
2068
  compact: 0
1986
2069
  }
1987
2070
  };
@@ -2001,12 +2084,15 @@ function countTemplateMetrics(template, cardStyles, fragments) {
2001
2084
  if (baseStyleForBytes) {
2002
2085
  result.styleBytes += utf8ByteLength(JSON.stringify(baseStyleForBytes));
2003
2086
  }
2004
- const compactStyleForBytes = getMergedCompactResponsiveStyle(
2005
- node,
2006
- cardStyles
2007
- );
2008
- if (compactStyleForBytes) {
2009
- result.styleBytes += utf8ByteLength(JSON.stringify(compactStyleForBytes));
2087
+ for (const mode of ["medium", "compact"]) {
2088
+ const responsiveStyleForBytes = getMergedResponsiveStyleOverride(
2089
+ node,
2090
+ cardStyles,
2091
+ mode
2092
+ );
2093
+ if (responsiveStyleForBytes) {
2094
+ result.styleBytes += utf8ByteLength(JSON.stringify(responsiveStyleForBytes));
2095
+ }
2010
2096
  }
2011
2097
  for (const mode of RESPONSIVE_MODES) {
2012
2098
  const effectiveStyle = getEffectiveStyleForMode(node, cardStyles, mode);
@@ -2027,6 +2113,7 @@ function validateLimits(card) {
2027
2113
  let styleObjectsBytes = 0;
2028
2114
  const overflowAutoCount = {
2029
2115
  default: 0,
2116
+ medium: 0,
2030
2117
  compact: 0
2031
2118
  };
2032
2119
  traverseCard(card.views, (node, context) => {
@@ -2044,12 +2131,15 @@ function validateLimits(card) {
2044
2131
  if (baseStyleForBytes) {
2045
2132
  styleObjectsBytes += utf8ByteLength(JSON.stringify(baseStyleForBytes));
2046
2133
  }
2047
- const compactStyleForBytes = getMergedCompactResponsiveStyle(
2048
- node,
2049
- card.cardStyles
2050
- );
2051
- if (compactStyleForBytes) {
2052
- styleObjectsBytes += utf8ByteLength(JSON.stringify(compactStyleForBytes));
2134
+ for (const mode of ["medium", "compact"]) {
2135
+ const responsiveStyleForBytes = getMergedResponsiveStyleOverride(
2136
+ node,
2137
+ card.cardStyles,
2138
+ mode
2139
+ );
2140
+ if (responsiveStyleForBytes) {
2141
+ styleObjectsBytes += utf8ByteLength(JSON.stringify(responsiveStyleForBytes));
2142
+ }
2053
2143
  }
2054
2144
  }
2055
2145
  const children = node.children;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/result.ts","../src/schema.ts","../src/traverse.ts","../src/renderable-walk.ts","../src/fragment-validator.ts","../src/node-validator.ts","../src/condition-validator.ts","../src/value-types.ts","../src/style-validator.ts","../src/security.ts","../src/responsive-utils.ts","../src/limits.ts"],"sourcesContent":["/**\n * @safe-ugc-ui/validator — Public API\n *\n * Provides two entry points for card validation:\n *\n * validateRaw(rawJson: string) — Recommended for raw JSON strings.\n * Checks UTF-8 byte size BEFORE parsing. If too large, rejects without\n * parsing (DoS prevention). Returns ValidationResult.\n *\n * validate(input: unknown) — For already-parsed objects.\n * Skips size check. Returns ValidationResult.\n *\n * Pipeline:\n * 1. (validateRaw only) UTF-8 byte size check (1MB limit)\n * 2. (validateRaw only) JSON.parse — parse error → ValidationResult\n * 3. Schema validation → fail → early return\n * 4. All remaining checks run, errors accumulated:\n * node → value-types → style → security → limits\n */\n\nimport { CARD_JSON_MAX_BYTES } from '@safe-ugc-ui/types';\n\nimport {\n type ValidationError,\n type ValidationResult,\n createError,\n toResult,\n} from './result.js';\nimport { validateSchema } from './schema.js';\nimport { validateFragments } from './fragment-validator.js';\nimport { validateNodes } from './node-validator.js';\nimport { validateConditions } from './condition-validator.js';\nimport { validateValueTypes } from './value-types.js';\nimport { validateStyles } from './style-validator.js';\nimport { validateSecurity } from './security.js';\nimport { validateLimits } from './limits.js';\n\n// ---------------------------------------------------------------------------\n// Re-exports\n// ---------------------------------------------------------------------------\n\nexport {\n type ValidationError,\n type ValidationErrorCode,\n type ValidationResult,\n createError,\n validResult,\n invalidResult,\n toResult,\n merge,\n} from './result.js';\n\nexport {\n type StyleResolver,\n type TraversalContext,\n type TraversableNode,\n type NodeVisitor,\n traverseNode,\n traverseCard,\n} from './traverse.js';\n\nexport { validateSchema, parseCard } from './schema.js';\nexport { validateFragments } from './fragment-validator.js';\nexport { validateNodes } from './node-validator.js';\nexport { validateConditions } from './condition-validator.js';\nexport { validateValueTypes } from './value-types.js';\nexport { validateStyles } from './style-validator.js';\nexport { validateSecurity } from './security.js';\nexport { validateLimits } from './limits.js';\n\n// ---------------------------------------------------------------------------\n// UTF-8 byte length (platform-agnostic)\n// ---------------------------------------------------------------------------\n\nfunction utf8ByteLength(str: string): number {\n let bytes = 0;\n for (let i = 0; i < str.length; i++) {\n const code = str.charCodeAt(i);\n if (code <= 0x7f) {\n bytes += 1;\n } else if (code <= 0x7ff) {\n bytes += 2;\n } else if (code >= 0xd800 && code <= 0xdbff) {\n bytes += 4;\n i++;\n } else {\n bytes += 3;\n }\n }\n return bytes;\n}\n\n// ---------------------------------------------------------------------------\n// runAllChecks — shared pipeline (post-schema)\n// ---------------------------------------------------------------------------\n\nfunction runAllChecks(input: unknown): ValidationError[] {\n const obj = input as {\n views: Record<string, unknown>;\n state?: Record<string, unknown>;\n assets?: Record<string, string>;\n styles?: Record<string, Record<string, unknown>>;\n fragments?: Record<string, unknown>;\n };\n const views = obj.views as Record<string, unknown>;\n const cardStyles = obj.styles as Record<string, Record<string, unknown>> | undefined;\n const fragments = obj.fragments as Record<string, unknown> | undefined;\n const errors: ValidationError[] = [];\n\n errors.push(...validateFragments(views, fragments));\n errors.push(...validateNodes(views, fragments));\n errors.push(...validateConditions(views, fragments));\n errors.push(...validateValueTypes(views, fragments));\n errors.push(...validateStyles(views, cardStyles, fragments));\n errors.push(...validateSecurity({\n views,\n state: obj.state as Record<string, unknown> | undefined,\n cardAssets: obj.assets as Record<string, string> | undefined,\n cardStyles,\n fragments,\n }));\n errors.push(...validateLimits({\n state: obj.state as Record<string, unknown> | undefined,\n views,\n cardStyles,\n fragments,\n }));\n\n return errors;\n}\n\n// ---------------------------------------------------------------------------\n// validate — object input (already parsed)\n// ---------------------------------------------------------------------------\n\n/**\n * Validate an already-parsed card object.\n *\n * Skips the JSON byte size check (use `validateRaw` for raw strings).\n *\n * Pipeline:\n * 1. Schema validation → fail → early return\n * 2. All remaining checks (node, value-types, style, security, limits)\n *\n * @param input - An unknown value (typically parsed JSON).\n * @returns A ValidationResult — safe to render only if `valid` is true.\n */\nexport function validate(input: unknown): ValidationResult {\n // 1. Schema validation (early return on failure)\n const schemaResult = validateSchema(input);\n if (!schemaResult.valid) {\n return schemaResult;\n }\n\n // 2. All remaining checks\n const errors = runAllChecks(input);\n return toResult(errors);\n}\n\n// ---------------------------------------------------------------------------\n// validateRaw — string input (pre-parse size check)\n// ---------------------------------------------------------------------------\n\n/**\n * Validate a raw JSON string. Recommended entry point.\n *\n * Checks the byte size of the raw string BEFORE parsing to prevent\n * JSON parsing DoS with oversized payloads.\n *\n * Pipeline:\n * 1. UTF-8 byte size check (1MB max) → reject without parsing\n * 2. JSON.parse → parse error → ValidationResult (no throw)\n * 3. Schema validation → fail → early return\n * 4. All remaining checks\n *\n * @param rawJson - A raw JSON string representing a UGC card.\n * @returns A ValidationResult — safe to render only if `valid` is true.\n */\nexport function validateRaw(rawJson: string): ValidationResult {\n // 1. Pre-parse size check\n const byteSize = utf8ByteLength(rawJson);\n if (byteSize > CARD_JSON_MAX_BYTES) {\n return toResult([\n createError(\n 'CARD_SIZE_EXCEEDED',\n `Card JSON is ${byteSize} bytes, maximum is ${CARD_JSON_MAX_BYTES} bytes.`,\n '',\n ),\n ]);\n }\n\n // 2. Parse JSON\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawJson);\n } catch (e) {\n const message = e instanceof Error ? e.message : 'Invalid JSON';\n return toResult([\n createError('INVALID_JSON', `Failed to parse JSON: ${message}`, ''),\n ]);\n }\n\n // 3-4. Delegate to validate()\n return validate(parsed);\n}\n","/**\n * @safe-ugc-ui/validator — Validation Result Types\n *\n * Provides the error and result types used throughout the validation pipeline.\n *\n * Design decisions:\n * - Errors include a `path` for precise location in the card tree.\n * - Errors include a `code` for programmatic handling.\n * - `merge()` combines multiple results, accumulating all errors.\n * - A valid result is simply `{ valid: true, errors: [] }`.\n */\n\n// ---------------------------------------------------------------------------\n// Error codes\n// ---------------------------------------------------------------------------\n\n/**\n * Machine-readable error codes for every validation failure type.\n */\nexport type ValidationErrorCode =\n // Schema / structural\n | 'INVALID_JSON'\n | 'MISSING_FIELD'\n | 'INVALID_TYPE'\n | 'INVALID_VALUE'\n | 'UNKNOWN_NODE_TYPE'\n | 'SCHEMA_ERROR'\n // Value-type restrictions\n | 'REF_NOT_ALLOWED'\n | 'DYNAMIC_NOT_ALLOWED'\n // Style\n | 'FORBIDDEN_STYLE_PROPERTY'\n | 'STYLE_VALUE_OUT_OF_RANGE'\n | 'FORBIDDEN_CSS_FUNCTION'\n | 'INVALID_COLOR'\n | 'INVALID_LENGTH'\n | 'FORBIDDEN_OVERFLOW_VALUE'\n | 'TRANSFORM_SKEW_FORBIDDEN'\n // Security\n | 'EXTERNAL_URL'\n | 'POSITION_FIXED_FORBIDDEN'\n | 'POSITION_STICKY_FORBIDDEN'\n | 'POSITION_ABSOLUTE_NOT_IN_STACK'\n | 'ASSET_PATH_TRAVERSAL'\n | 'INVALID_ASSET_PATH'\n | 'PROTOTYPE_POLLUTION'\n // Limits\n | 'CARD_SIZE_EXCEEDED'\n | 'TEXT_CONTENT_SIZE_EXCEEDED'\n | 'STYLE_SIZE_EXCEEDED'\n | 'NODE_COUNT_EXCEEDED'\n | 'LOOP_ITERATIONS_EXCEEDED'\n | 'NESTED_LOOPS_EXCEEDED'\n | 'OVERFLOW_AUTO_COUNT_EXCEEDED'\n | 'OVERFLOW_AUTO_NESTED'\n | 'STACK_NESTING_EXCEEDED'\n // ForLoop\n | 'LOOP_SOURCE_NOT_ARRAY'\n | 'LOOP_SOURCE_MISSING'\n // $style references\n | 'STYLE_CIRCULAR_REF'\n | 'STYLE_REF_NOT_FOUND'\n | 'INVALID_STYLE_REF'\n | 'INVALID_STYLE_NAME'\n // Fragments\n | 'FRAGMENT_REF_NOT_FOUND'\n | 'FRAGMENT_NESTED_USE'\n | 'INVALID_FRAGMENT_NAME'\n // Hover / Transition\n | 'INVALID_HOVER_STYLE'\n | 'HOVER_STYLE_NESTED'\n | 'TRANSITION_RAW_STRING'\n | 'TRANSITION_COUNT_EXCEEDED'\n | 'TRANSITION_PROPERTY_FORBIDDEN'\n // Conditions\n | 'CONDITION_DEPTH_EXCEEDED';\n\n// ---------------------------------------------------------------------------\n// ValidationError\n// ---------------------------------------------------------------------------\n\n/**\n * A single validation error with location and diagnostic info.\n */\nexport interface ValidationError {\n /** Machine-readable error code. */\n code: ValidationErrorCode;\n\n /** Human-readable error message. */\n message: string;\n\n /**\n * JSON-pointer-like path to the error location.\n * e.g. `\"views.StatusWindow.children[0].style.zIndex\"`\n */\n path: string;\n}\n\n// ---------------------------------------------------------------------------\n// ValidationResult\n// ---------------------------------------------------------------------------\n\n/**\n * The result of running the validation pipeline.\n *\n * - `valid: true` → the card is safe to render.\n * - `valid: false` → the card has errors; do NOT render.\n */\nexport interface ValidationResult {\n valid: boolean;\n errors: ValidationError[];\n}\n\n// ---------------------------------------------------------------------------\n// Factory helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Create a single validation error.\n */\nexport function createError(\n code: ValidationErrorCode,\n message: string,\n path: string,\n): ValidationError {\n return { code, message, path };\n}\n\n/**\n * Create a valid result (no errors).\n */\nexport function validResult(): ValidationResult {\n return { valid: true, errors: [] };\n}\n\n/**\n * Create an invalid result from a list of errors.\n */\nexport function invalidResult(errors: ValidationError[]): ValidationResult {\n return { valid: false, errors };\n}\n\n/**\n * Wrap errors into a ValidationResult (valid if no errors).\n */\nexport function toResult(errors: ValidationError[]): ValidationResult {\n return {\n valid: errors.length === 0,\n errors,\n };\n}\n\n/**\n * Merge multiple validation results into one.\n * The merged result is valid only if ALL inputs are valid.\n */\nexport function merge(...results: ValidationResult[]): ValidationResult {\n const errors: ValidationError[] = [];\n for (const r of results) {\n errors.push(...r.errors);\n }\n return {\n valid: errors.length === 0,\n errors,\n };\n}\n","/**\n * @safe-ugc-ui/validator — Schema (Structural) Validation\n *\n * Verifies the top-level structure of a UGC card:\n * - Required fields: meta (name, version), views (at least one)\n * - Zod schema parse for the full card structure\n * - Maps Zod parse errors to ValidationError format\n *\n * This is the first step in the validation pipeline (after size check).\n * If structural validation fails, no further checks are performed.\n */\n\nimport { ugcCardSchema, type UGCCard } from '@safe-ugc-ui/types';\n\nimport {\n type ValidationError,\n type ValidationResult,\n createError,\n toResult,\n} from './result.js';\n\n// ---------------------------------------------------------------------------\n// validateSchema\n// ---------------------------------------------------------------------------\n\n/**\n * Validate the structural shape of a card using the Zod schema.\n *\n * @param input - An unknown value (already parsed from JSON).\n * @returns A ValidationResult. If valid, the parsed UGCCard can be accessed\n * from the Zod result; callers should re-parse if they need the typed object.\n */\nexport function validateSchema(input: unknown): ValidationResult {\n const errors: ValidationError[] = [];\n\n // Quick structural pre-checks for better error messages\n if (typeof input !== 'object' || input === null || Array.isArray(input)) {\n errors.push(\n createError('SCHEMA_ERROR', 'Card must be a plain object.', ''),\n );\n return toResult(errors);\n }\n\n const obj = input as Record<string, unknown>;\n\n // Check required top-level fields before full Zod parse\n if (!obj.meta) {\n errors.push(\n createError('MISSING_FIELD', 'Card is missing required field \"meta\".', 'meta'),\n );\n }\n if (!obj.views) {\n errors.push(\n createError('MISSING_FIELD', 'Card is missing required field \"views\".', 'views'),\n );\n }\n\n // If critical fields are missing, return early\n if (errors.length > 0) {\n return toResult(errors);\n }\n\n // Check meta structure\n if (typeof obj.meta !== 'object' || obj.meta === null) {\n errors.push(\n createError('INVALID_TYPE', '\"meta\" must be an object.', 'meta'),\n );\n return toResult(errors);\n }\n\n const meta = obj.meta as Record<string, unknown>;\n if (typeof meta.name !== 'string') {\n errors.push(\n createError('MISSING_FIELD', '\"meta.name\" is required and must be a string.', 'meta.name'),\n );\n }\n if (typeof meta.version !== 'string') {\n errors.push(\n createError('MISSING_FIELD', '\"meta.version\" is required and must be a string.', 'meta.version'),\n );\n }\n\n // Check views structure\n if (typeof obj.views !== 'object' || obj.views === null || Array.isArray(obj.views)) {\n errors.push(\n createError('INVALID_TYPE', '\"views\" must be an object.', 'views'),\n );\n return toResult(errors);\n }\n\n const views = obj.views as Record<string, unknown>;\n if (Object.keys(views).length === 0) {\n errors.push(\n createError('MISSING_FIELD', '\"views\" must contain at least one view.', 'views'),\n );\n }\n\n // If pre-checks found issues, return them\n if (errors.length > 0) {\n return toResult(errors);\n }\n\n // Full Zod parse\n const result = ugcCardSchema.safeParse(input);\n\n if (!result.success) {\n for (const issue of result.error.issues) {\n const path = issue.path.join('.');\n errors.push(\n createError('SCHEMA_ERROR', issue.message, path),\n );\n }\n }\n\n return toResult(errors);\n}\n\n/**\n * Parse a card from an unknown input, returning either the typed UGCCard\n * or null if structural validation fails.\n *\n * Callers should first run `validateSchema()` to get user-facing errors.\n * This is a convenience for subsequent pipeline stages that need the typed card.\n */\nexport function parseCard(input: unknown): UGCCard | null {\n const result = ugcCardSchema.safeParse(input);\n return result.success ? result.data : null;\n}\n","/**\n * @safe-ugc-ui/validator — Tree Traversal\n *\n * Provides utilities for walking the UGC card tree, tracking:\n * - path: JSON-pointer-like location string\n * - depth: nesting level\n * - parentType: the type of the parent node (for position/overflow rules)\n * - loopDepth: nesting level of for-loops\n * - overflowAutoAncestor: whether an ancestor has overflow:auto\n * - stackDepth: nesting level of Stack components\n *\n * The traversal is generic: it calls a visitor function on each node,\n * allowing different validators to collect different data.\n */\n\n// ---------------------------------------------------------------------------\n// Context passed to visitor callbacks\n// ---------------------------------------------------------------------------\n\n/**\n * Contextual information available at each node during traversal.\n */\nexport interface TraversalContext {\n /** JSON-pointer-like path, e.g. \"views.Main.children[0].children[1]\" */\n path: string;\n\n /** Nesting depth (root node = 0). */\n depth: number;\n\n /** The `type` of the immediate parent node, or null for root-level nodes. */\n parentType: string | null;\n\n /** Current for-loop nesting depth (0 = no loop). */\n loopDepth: number;\n\n /** True if any ancestor has `overflow: auto` in its style. */\n overflowAutoAncestor: boolean;\n\n /** Current Stack nesting depth (0 = not inside a Stack). */\n stackDepth: number;\n}\n\n// ---------------------------------------------------------------------------\n// Node shape (loose — validated elsewhere)\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal shape expected for a node during traversal.\n * We use a loose type because traversal runs after schema validation,\n * but the node might have extra or unexpected fields.\n */\nexport interface TraversableNode {\n type: string;\n children?: TraversableRenderable[] | ForLoopLike;\n style?: Record<string, unknown>;\n responsive?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nexport interface FragmentUseLike {\n $use: string;\n $if?: unknown;\n [key: string]: unknown;\n}\n\nexport type TraversableRenderable = TraversableNode | FragmentUseLike;\n\nexport interface EmbeddedRenderableEntry {\n pathSuffix: string;\n renderable: TraversableRenderable;\n}\n\ninterface ForLoopLike {\n for: string;\n in: string;\n template: TraversableRenderable;\n}\n\n// ---------------------------------------------------------------------------\n// Visitor\n// ---------------------------------------------------------------------------\n\n/**\n * A visitor function called for every node in the tree.\n * Return `false` to skip traversing into this node's children.\n */\nexport type NodeVisitor = (\n node: TraversableNode,\n context: TraversalContext,\n) => void | false;\n\nexport type StyleResolver = (\n node: TraversableNode,\n) => Record<string, unknown> | undefined;\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction isForLoop(\n children: unknown,\n): children is ForLoopLike {\n return (\n typeof children === 'object' &&\n children !== null &&\n 'for' in children &&\n 'in' in children &&\n 'template' in children\n );\n}\n\nexport function isTraversableNode(value: unknown): value is TraversableNode {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n typeof (value as Record<string, unknown>).type === 'string'\n );\n}\n\nexport function isFragmentUseLike(value: unknown): value is FragmentUseLike {\n return (\n typeof value === 'object' &&\n value !== null &&\n '$use' in value &&\n typeof (value as Record<string, unknown>).$use === 'string'\n );\n}\n\nexport function getEmbeddedRenderables(\n node: TraversableNode,\n): EmbeddedRenderableEntry[] {\n const entries: EmbeddedRenderableEntry[] = [];\n\n const interactiveField =\n node.type === 'Accordion'\n ? 'items'\n : node.type === 'Tabs'\n ? 'tabs'\n : null;\n\n if (interactiveField) {\n const items = (node as Record<string, unknown>)[interactiveField];\n if (!Array.isArray(items)) {\n return entries;\n }\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n if (\n item == null ||\n typeof item !== 'object' ||\n Array.isArray(item)\n ) {\n continue;\n }\n\n const content = (item as Record<string, unknown>).content;\n if (isTraversableNode(content) || isFragmentUseLike(content)) {\n entries.push({\n pathSuffix: `${interactiveField}[${i}].content`,\n renderable: content,\n });\n }\n }\n }\n\n return entries;\n}\n\nfunction resolveRenderableNode(\n node: TraversableRenderable,\n fragments?: Record<string, unknown>,\n fragmentStack: string[] = [],\n): TraversableNode | null {\n if (isTraversableNode(node)) {\n return node;\n }\n\n if (!isFragmentUseLike(node) || !fragments) {\n return null;\n }\n\n // Fragment definitions are validated separately and may not nest `$use`.\n // Skip expansion here so invalid cards cannot recurse indefinitely.\n if (fragmentStack.length > 0 || fragmentStack.includes(node.$use)) {\n return null;\n }\n\n const target = fragments[node.$use];\n return isTraversableNode(target) ? target : null;\n}\n\nfunction hasOverflowAuto(style: Record<string, unknown> | undefined): boolean {\n return style?.overflow === 'auto';\n}\n\n// ---------------------------------------------------------------------------\n// traverseNode\n// ---------------------------------------------------------------------------\n\n/**\n * Recursively traverse a single node and its descendants.\n */\nexport function traverseNode(\n node: TraversableRenderable,\n context: TraversalContext,\n visitor: NodeVisitor,\n styleResolver?: StyleResolver,\n fragments?: Record<string, unknown>,\n fragmentStack: string[] = [],\n): void {\n const resolvedNode = resolveRenderableNode(node, fragments, fragmentStack);\n if (!resolvedNode) {\n return;\n }\n\n const nextFragmentStack =\n isFragmentUseLike(node) ? [...fragmentStack, node.$use] : fragmentStack;\n\n const result = visitor(resolvedNode, context);\n\n // If visitor returns false, skip children.\n if (result === false) {\n return;\n }\n\n const nextStackDepth =\n resolvedNode.type === 'Stack' ? context.stackDepth + 1 : context.stackDepth;\n const nextOverflowAuto =\n context.overflowAutoAncestor || hasOverflowAuto(styleResolver ? styleResolver(resolvedNode) : resolvedNode.style);\n\n const children = resolvedNode.children;\n if (children != null) {\n if (isForLoop(children)) {\n // ForLoop: traverse the template node\n const childCtx: TraversalContext = {\n path: `${context.path}.children.template`,\n depth: context.depth + 1,\n parentType: resolvedNode.type,\n loopDepth: context.loopDepth + 1,\n overflowAutoAncestor: nextOverflowAuto,\n stackDepth: nextStackDepth,\n };\n traverseNode(children.template, childCtx, visitor, styleResolver, fragments, nextFragmentStack);\n } else if (Array.isArray(children)) {\n // Array of child nodes\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (isTraversableNode(child) || isFragmentUseLike(child)) {\n const childCtx: TraversalContext = {\n path: `${context.path}.children[${i}]`,\n depth: context.depth + 1,\n parentType: resolvedNode.type,\n loopDepth: context.loopDepth,\n overflowAutoAncestor: nextOverflowAuto,\n stackDepth: nextStackDepth,\n };\n traverseNode(child, childCtx, visitor, styleResolver, fragments, nextFragmentStack);\n }\n }\n }\n }\n\n for (const entry of getEmbeddedRenderables(resolvedNode)) {\n const embeddedCtx: TraversalContext = {\n path: `${context.path}.${entry.pathSuffix}`,\n depth: context.depth + 1,\n parentType: resolvedNode.type,\n loopDepth: context.loopDepth,\n overflowAutoAncestor: nextOverflowAuto,\n stackDepth: nextStackDepth,\n };\n traverseNode(\n entry.renderable,\n embeddedCtx,\n visitor,\n styleResolver,\n fragments,\n nextFragmentStack,\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// traverseCard\n// ---------------------------------------------------------------------------\n\n/**\n * Traverse all nodes in every view of a card.\n *\n * @param views - The `views` object from a UGCCard (mapping view names to root nodes).\n * @param visitor - Called for every node in every view.\n */\nexport function traverseCard(\n views: Record<string, unknown>,\n visitor: NodeVisitor,\n styleResolver?: StyleResolver,\n fragments?: Record<string, unknown>,\n pathPrefix: string = 'views',\n): void {\n for (const [viewName, rootNode] of Object.entries(views)) {\n if (!isTraversableNode(rootNode) && !isFragmentUseLike(rootNode)) {\n continue;\n }\n\n const context: TraversalContext = {\n path: `${pathPrefix}.${viewName}`,\n depth: 0,\n parentType: null,\n loopDepth: 0,\n overflowAutoAncestor: false,\n stackDepth: 0,\n };\n\n traverseNode(rootNode, context, visitor, styleResolver, fragments);\n }\n}\n","/**\n * @safe-ugc-ui/validator — Raw Renderable Tree Walk\n *\n * Walks card trees before fragment expansion so validators can inspect\n * `$use` wrappers and fragment definitions directly.\n */\n\nimport {\n getEmbeddedRenderables,\n isFragmentUseLike,\n isTraversableNode,\n} from './traverse.js';\n\nexport interface RenderableWalkContext {\n path: string;\n inFragments: boolean;\n}\n\ntype RenderableWalker = (\n node: Record<string, unknown>,\n context: RenderableWalkContext,\n) => void;\n\nfunction isForLoopLike(value: unknown): value is { template: unknown } {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'for' in value &&\n 'in' in value &&\n 'template' in value\n );\n}\n\nfunction walkRenderableNode(\n node: Record<string, unknown>,\n path: string,\n inFragments: boolean,\n visitor: RenderableWalker,\n): void {\n visitor(node, { path, inFragments });\n\n if (!isTraversableNode(node)) {\n return;\n }\n\n const children = node.children;\n if (Array.isArray(children)) {\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!isTraversableNode(child) && !isFragmentUseLike(child)) {\n continue;\n }\n walkRenderableNode(\n child as Record<string, unknown>,\n `${path}.children[${i}]`,\n inFragments,\n visitor,\n );\n }\n }\n\n if (isForLoopLike(children)) {\n const template = children.template;\n if (isTraversableNode(template) || isFragmentUseLike(template)) {\n walkRenderableNode(\n template as Record<string, unknown>,\n `${path}.children.template`,\n inFragments,\n visitor,\n );\n }\n }\n\n for (const entry of getEmbeddedRenderables(node)) {\n walkRenderableNode(\n entry.renderable as Record<string, unknown>,\n `${path}.${entry.pathSuffix}`,\n inFragments,\n visitor,\n );\n }\n}\n\nexport function walkRenderableCard(\n views: Record<string, unknown>,\n fragments: Record<string, unknown> | undefined,\n visitor: RenderableWalker,\n): void {\n for (const [viewName, rootNode] of Object.entries(views)) {\n if (!isTraversableNode(rootNode) && !isFragmentUseLike(rootNode)) {\n continue;\n }\n\n walkRenderableNode(\n rootNode as Record<string, unknown>,\n `views.${viewName}`,\n false,\n visitor,\n );\n }\n\n if (!fragments) {\n return;\n }\n\n for (const [fragmentName, fragmentRoot] of Object.entries(fragments)) {\n if (!isTraversableNode(fragmentRoot) && !isFragmentUseLike(fragmentRoot)) {\n continue;\n }\n\n walkRenderableNode(\n fragmentRoot as Record<string, unknown>,\n `fragments.${fragmentName}`,\n true,\n visitor,\n );\n }\n}\n","/**\n * @safe-ugc-ui/validator — Fragment Validator\n *\n * Validates fragment references and the non-recursive fragment rules for v0.9.\n */\n\nimport { createError, type ValidationError } from './result.js';\nimport { walkRenderableCard } from './renderable-walk.js';\nimport { isFragmentUseLike } from './traverse.js';\n\nconst FRAGMENT_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*$/;\n\nexport function validateFragments(\n views: Record<string, unknown>,\n fragments?: Record<string, unknown>,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n if (fragments) {\n for (const fragmentName of Object.keys(fragments)) {\n if (!FRAGMENT_NAME_PATTERN.test(fragmentName)) {\n errors.push(\n createError(\n 'INVALID_FRAGMENT_NAME',\n `Fragment name \"${fragmentName}\" is invalid; must match /^[A-Za-z][A-Za-z0-9_-]*$/.`,\n `fragments.${fragmentName}`,\n ),\n );\n }\n }\n }\n\n walkRenderableCard(views, fragments, (node, context) => {\n if (!isFragmentUseLike(node)) {\n return;\n }\n\n if (context.inFragments) {\n errors.push(\n createError(\n 'FRAGMENT_NESTED_USE',\n `Fragments may not contain \"$use\" references. Found at \"${context.path}\".`,\n context.path,\n ),\n );\n return;\n }\n\n if (!fragments || !(node.$use in fragments)) {\n errors.push(\n createError(\n 'FRAGMENT_REF_NOT_FOUND',\n `Fragment \"${node.$use}\" was not found.`,\n context.path,\n ),\n );\n }\n });\n\n return errors;\n}\n","/**\n * @safe-ugc-ui/validator — Node Validator\n *\n * Validates component type-specific requirements for each node in the card tree.\n *\n * For every node encountered during traversal:\n * 1. Rejects unknown node types not in ALL_COMPONENT_TYPES.\n * 2. Checks that required fields exist for each component type.\n * 4. Validates ForLoop structure when children use `for`/`in`/`template`.\n */\n\nimport { ALL_COMPONENT_TYPES, MAX_INTERACTIVE_ITEMS } from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\nimport { walkRenderableCard } from './renderable-walk.js';\nimport { isFragmentUseLike, type TraversableNode, type TraversalContext } from './traverse.js';\n\n// ---------------------------------------------------------------------------\n// Required fields per component type\n// ---------------------------------------------------------------------------\n\n/**\n * Mapping from component type to the list of required field names.\n * Layout nodes (Box, Row, Column, Stack, Grid) and structural nodes\n * (Divider, Spacer) have no required fields.\n */\nconst REQUIRED_FIELDS: Record<string, string[]> = {\n Image: ['src'],\n ProgressBar: ['value', 'max'],\n Avatar: ['src'],\n Icon: ['name'],\n Badge: ['label'],\n Chip: ['label'],\n Button: ['label', 'action'],\n Toggle: ['value', 'onToggle'],\n Accordion: ['items'],\n Tabs: ['tabs'],\n};\n\n// ---------------------------------------------------------------------------\n// Set of known component types for fast lookup\n// ---------------------------------------------------------------------------\n\nconst KNOWN_TYPES: ReadonlySet<string> = new Set(ALL_COMPONENT_TYPES);\n\n// ---------------------------------------------------------------------------\n// ForLoop validation helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Returns true if the given value looks like a ForLoop structure\n * (has `for`, `in`, and `template` properties).\n */\nfunction looksLikeForLoop(value: unknown): boolean {\n return (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n 'for' in value &&\n 'in' in value &&\n 'template' in value\n );\n}\n\n/**\n * Validate the structural integrity of a ForLoop children object.\n */\nfunction validateForLoop(\n children: Record<string, unknown>,\n path: string,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n // `for` must be a string\n if (typeof children['for'] !== 'string') {\n errors.push(\n createError(\n 'INVALID_VALUE',\n 'ForLoop \"for\" must be a string.',\n `${path}.children.for`,\n ),\n );\n }\n\n // `in` must be a string starting with `$`\n const inValue = children['in'];\n if (typeof inValue !== 'string' || !inValue.startsWith('$')) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n 'ForLoop \"in\" must be a string starting with \"$\".',\n `${path}.children.in`,\n ),\n );\n }\n\n // `template` must be an object with a `type` property\n const template = children['template'];\n if (\n typeof template !== 'object' ||\n template === null ||\n (!('type' in template) && !isFragmentUseLike(template))\n ) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n 'ForLoop \"template\" must be an object with a \"type\" property or \"$use\" reference.',\n `${path}.children.template`,\n ),\n );\n }\n\n return errors;\n}\n\nfunction collectUniqueInteractiveItemIds(\n items: unknown[],\n nodeType: 'Accordion' | 'Tabs',\n path: string,\n errors: ValidationError[],\n): Set<string> {\n const itemIds = new Set<string>();\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n if (\n item == null ||\n typeof item !== 'object' ||\n Array.isArray(item)\n ) {\n continue;\n }\n\n const itemId = (item as Record<string, unknown>).id;\n if (typeof itemId !== 'string' || itemId.length === 0) {\n continue;\n }\n\n if (itemIds.has(itemId)) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n `\"${nodeType}\" item ids must be unique. Duplicate id \"${itemId}\".`,\n `${path}[${i}].id`,\n ),\n );\n continue;\n }\n\n itemIds.add(itemId);\n }\n\n return itemIds;\n}\n\n// ---------------------------------------------------------------------------\n// Per-node validation\n// ---------------------------------------------------------------------------\n\n/**\n * Validate a single node's type and required fields.\n */\nfunction validateNode(\n node: TraversableNode,\n context: TraversalContext,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n const { path } = context;\n\n // 1. Unknown node type\n if (!KNOWN_TYPES.has(node.type)) {\n errors.push(\n createError(\n 'UNKNOWN_NODE_TYPE',\n `Unknown node type \"${node.type}\".`,\n path,\n ),\n );\n // Cannot validate fields for an unknown type; return early.\n return errors;\n }\n\n // 2. Required field validation\n if (node.type === 'Text') {\n const hasContent = 'content' in node && (node as Record<string, unknown>).content !== undefined;\n const hasSpans = 'spans' in node && (node as Record<string, unknown>).spans !== undefined;\n\n if (!hasContent && !hasSpans) {\n errors.push(\n createError(\n 'MISSING_FIELD',\n '\"Text\" node must define either \"content\" or \"spans\".',\n `${path}.content`,\n ),\n );\n }\n\n if (hasContent && hasSpans) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n '\"Text\" node cannot define both \"content\" and \"spans\".',\n path,\n ),\n );\n }\n }\n\n const requiredFields = REQUIRED_FIELDS[node.type];\n if (requiredFields && requiredFields.length > 0) {\n // Check each required field on the node itself (v2 flattening).\n for (const field of requiredFields) {\n if (!(field in node) || (node as Record<string, unknown>)[field] === undefined) {\n errors.push(\n createError(\n 'MISSING_FIELD',\n `\"${node.type}\" node is missing required field \"${field}\".`,\n `${path}.${field}`,\n ),\n );\n }\n }\n }\n\n // 4. ForLoop structure validation\n if (node.children != null && looksLikeForLoop(node.children)) {\n errors.push(\n ...validateForLoop(\n node.children as unknown as Record<string, unknown>,\n path,\n ),\n );\n }\n\n if (node.type === 'Accordion') {\n const items = Array.isArray(node.items) ? node.items : undefined;\n if (items) {\n if (items.length > MAX_INTERACTIVE_ITEMS) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n `\"Accordion\" node may define at most ${MAX_INTERACTIVE_ITEMS} items.`,\n `${path}.items`,\n ),\n );\n }\n\n const itemIds = collectUniqueInteractiveItemIds(\n items,\n 'Accordion',\n `${path}.items`,\n errors,\n );\n\n if (Array.isArray(node.defaultExpanded)) {\n if (node.allowMultiple !== true && node.defaultExpanded.length > 1) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n '\"Accordion\" cannot define multiple defaultExpanded ids unless \"allowMultiple\" is true.',\n `${path}.defaultExpanded`,\n ),\n );\n }\n\n for (let i = 0; i < node.defaultExpanded.length; i++) {\n const itemId = node.defaultExpanded[i];\n if (typeof itemId !== 'string' || !itemIds.has(itemId)) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n `\"Accordion\" defaultExpanded id \"${String(itemId)}\" was not found in items.`,\n `${path}.defaultExpanded[${i}]`,\n ),\n );\n }\n }\n }\n }\n }\n\n if (node.type === 'Tabs') {\n const tabs = Array.isArray(node.tabs) ? node.tabs : undefined;\n if (tabs) {\n if (tabs.length > MAX_INTERACTIVE_ITEMS) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n `\"Tabs\" node may define at most ${MAX_INTERACTIVE_ITEMS} tabs.`,\n `${path}.tabs`,\n ),\n );\n }\n\n const tabIds = collectUniqueInteractiveItemIds(\n tabs,\n 'Tabs',\n `${path}.tabs`,\n errors,\n );\n\n if ('defaultTab' in node) {\n const defaultTab = (node as Record<string, unknown>).defaultTab;\n if (typeof defaultTab !== 'string' || !tabIds.has(defaultTab)) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n `\"Tabs\" defaultTab \"${String(defaultTab)}\" was not found in tabs.`,\n `${path}.defaultTab`,\n ),\n );\n }\n }\n }\n }\n\n return errors;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Validate all nodes in every view of a card.\n *\n * Uses `traverseCard()` to visit every node and checks:\n * - Node type is a known component type.\n * - Required fields are present for the given component type.\n * - ForLoop children have valid `for`, `in`, and `template` fields.\n *\n * @param views - The `views` object from a UGCCard.\n * @returns An array of validation errors (empty if all nodes are valid).\n */\nexport function validateNodes(\n views: Record<string, unknown>,\n fragments?: Record<string, unknown>,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n walkRenderableCard(views, fragments, (node, context) => {\n if (!('type' in node) || typeof node.type !== 'string') {\n return;\n }\n\n errors.push(\n ...validateNode(\n node as TraversableNode,\n {\n path: context.path,\n depth: 0,\n parentType: null,\n loopDepth: 0,\n overflowAutoAncestor: false,\n stackDepth: 0,\n } satisfies TraversalContext,\n ),\n );\n });\n\n return errors;\n}\n","/**\n * @safe-ugc-ui/validator — Condition Validator\n *\n * Validates node-level `$if` conditions that are structurally accepted by the\n * schema but still need semantic guardrails such as maximum nesting depth.\n */\n\nimport { MAX_CONDITION_DEPTH, isRef } from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\nimport { walkRenderableCard } from './renderable-walk.js';\n\nfunction validateConditionDepth(\n condition: unknown,\n path: string,\n errors: ValidationError[],\n depth: number = 1,\n): void {\n if (depth > MAX_CONDITION_DEPTH) {\n errors.push(\n createError(\n 'CONDITION_DEPTH_EXCEEDED',\n `$if condition exceeds maximum depth of ${MAX_CONDITION_DEPTH} at \"${path}\"`,\n path,\n ),\n );\n return;\n }\n\n if (typeof condition === 'boolean' || isRef(condition)) {\n return;\n }\n\n if (typeof condition !== 'object' || condition === null || Array.isArray(condition)) {\n return;\n }\n\n const conditionObj = condition as Record<string, unknown>;\n const op = conditionObj.op;\n if (op === 'not') {\n validateConditionDepth(conditionObj.value, `${path}.value`, errors, depth + 1);\n return;\n }\n\n if ((op === 'and' || op === 'or') && Array.isArray(conditionObj.values)) {\n for (let i = 0; i < conditionObj.values.length; i++) {\n validateConditionDepth(\n conditionObj.values[i],\n `${path}.values[${i}]`,\n errors,\n depth + 1,\n );\n }\n }\n}\n\nexport function validateConditions(\n views: Record<string, unknown>,\n fragments?: Record<string, unknown>,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n walkRenderableCard(views, fragments, (node, ctx) => {\n if ('$if' in node) {\n validateConditionDepth(node.$if, `${ctx.path}.$if`, errors);\n }\n });\n\n return errors;\n}\n","/**\n * @safe-ugc-ui/validator — Value Type Validation\n *\n * Validates per-property $ref permission rules based on spec\n * section 4.5 value type table.\n *\n * | Property Type | Literal | $ref |\n * |-------------------|---------|------|\n * | Image.src | yes | yes |\n * | Avatar.src | yes | yes |\n * | Icon.name | yes | yes |\n * | Text.content | yes | yes |\n * | Color properties | yes | yes |\n * | Size properties | yes | yes |\n * | position | yes | no |\n * | overflow | yes | no |\n * | zIndex | yes | no |\n * | structured style objects | object literal | top-level $ref no |\n *\n * Structured style objects such as border/transform/boxShadow/textShadow/backgroundGradient\n * must remain object literals, but selected leaf fields inside them may use $ref.\n */\n\nimport { type ValidationError, createError } from './result.js';\nimport { walkRenderableCard } from './renderable-walk.js';\n\n// ---------------------------------------------------------------------------\n// Style properties that must always be static (no $ref)\n// ---------------------------------------------------------------------------\n\n/**\n * Style properties where any dynamic binding ($ref) is forbidden.\n * These use the `DYNAMIC_NOT_ALLOWED` error code.\n */\nconst STATIC_ONLY_STYLE_PROPERTIES: ReadonlySet<string> = new Set([\n // Position / layout\n 'position',\n 'top',\n 'right',\n 'bottom',\n 'left',\n\n // Overflow\n 'overflow',\n\n // Stacking\n 'zIndex',\n]);\n\nconst STRUCTURED_OBJECT_STYLE_PROPERTIES: ReadonlySet<string> = new Set([\n // Transform\n 'transform',\n\n // Gradient\n 'backgroundGradient',\n\n // Borders\n 'border',\n 'borderTop',\n 'borderRight',\n 'borderBottom',\n 'borderLeft',\n\n // Shadow\n 'boxShadow',\n 'textShadow',\n]);\n\n/**\n * Validate the `style` of a node according to the value type table.\n */\nfunction validateNodeStyle(\n style: Record<string, unknown> | undefined,\n path: string,\n errors: ValidationError[],\n): void {\n if (!style) {\n return;\n }\n\n for (const [prop, value] of Object.entries(style)) {\n if (value === undefined) {\n continue;\n }\n\n if (\n typeof value === 'object' &&\n value !== null &&\n '$ref' in value &&\n typeof (value as Record<string, unknown>).$ref === 'string'\n ) {\n if (STATIC_ONLY_STYLE_PROPERTIES.has(prop)) {\n errors.push(\n createError(\n 'DYNAMIC_NOT_ALLOWED',\n `Style property \"${prop}\" must be a static literal; $ref is not allowed.`,\n `${path}.${prop}`,\n ),\n );\n }\n\n if (STRUCTURED_OBJECT_STYLE_PROPERTIES.has(prop)) {\n errors.push(\n createError(\n 'DYNAMIC_NOT_ALLOWED',\n `Style property \"${prop}\" must be an object literal; use $ref only inside its nested fields.`,\n `${path}.${prop}`,\n ),\n );\n }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Walk all nodes in the card and validate that each field's value\n * respects its allowed value types ($ref permissions).\n *\n * @param views - The `views` object from a UGCCard.\n * @returns An array of validation errors (empty if all values are valid).\n */\nexport function validateValueTypes(\n views: Record<string, unknown>,\n fragments?: Record<string, unknown>,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n walkRenderableCard(views, fragments, (node, ctx) => {\n if (!('type' in node) || typeof node.type !== 'string') {\n return;\n }\n\n const style =\n node.style != null &&\n typeof node.style === 'object' &&\n !Array.isArray(node.style)\n ? node.style as Record<string, unknown>\n : undefined;\n validateNodeStyle(style, `${ctx.path}.style`, errors);\n\n const responsive = node.responsive;\n if (\n responsive != null &&\n typeof responsive === 'object' &&\n !Array.isArray(responsive)\n ) {\n const compact = (responsive as Record<string, unknown>).compact;\n if (\n compact != null &&\n typeof compact === 'object' &&\n !Array.isArray(compact)\n ) {\n validateNodeStyle(\n compact as Record<string, unknown>,\n `${ctx.path}.responsive.compact`,\n errors,\n );\n }\n }\n });\n\n return errors;\n}\n","/**\n * @safe-ugc-ui/validator — Style Validator\n *\n * Validates style properties according to the spec's style restrictions:\n * - Forbidden CSS properties (spec 3.8)\n * - Numeric range limits (spec 6.4)\n * - Text-shadow count and value limits\n * - Box-shadow count and value limits\n * - Transform skew prohibition\n * - Dangerous CSS function injection detection\n * - Overflow: scroll prohibition (defense-in-depth)\n * - Color format validation\n * - Length format validation\n */\n\nimport {\n ASPECT_RATIO_PATTERN,\n FORBIDDEN_STYLE_PROPERTIES,\n DANGEROUS_CSS_FUNCTIONS,\n ZINDEX_MIN,\n ZINDEX_MAX,\n TRANSFORM_SCALE_MIN,\n TRANSFORM_SCALE_MAX,\n TRANSFORM_TRANSLATE_MIN,\n TRANSFORM_TRANSLATE_MAX,\n FONT_SIZE_MIN,\n FONT_SIZE_MAX,\n TEXT_SHADOW_MAX_COUNT,\n TEXT_SHADOW_BLUR_MAX,\n BOX_SHADOW_MAX_COUNT,\n BOX_SHADOW_BLUR_MAX,\n BOX_SHADOW_SPREAD_MAX,\n BORDER_RADIUS_MAX,\n LETTER_SPACING_MIN,\n LETTER_SPACING_MAX,\n OPACITY_MIN,\n OPACITY_MAX,\n CSS_NAMED_COLORS,\n TRANSITION_DURATION_MAX,\n TRANSITION_DELAY_MAX,\n TRANSITION_MAX_COUNT,\n ALLOWED_TRANSITION_PROPERTIES,\n isRef,\n} from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\nimport { walkRenderableCard } from './renderable-walk.js';\n\n// ---------------------------------------------------------------------------\n// Property sets\n// ---------------------------------------------------------------------------\n\nconst COLOR_PROPERTIES = new Set(['backgroundColor', 'color']);\n\nconst LENGTH_PROPERTIES = new Set([\n 'width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight',\n 'padding', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft',\n 'margin', 'marginTop', 'marginRight', 'marginBottom', 'marginLeft',\n 'top', 'right', 'bottom', 'left', 'gap', 'lineHeight',\n]);\n\nconst LENGTH_AUTO_ALLOWED = new Set([\n 'width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight',\n 'margin', 'marginTop', 'marginRight', 'marginBottom', 'marginLeft',\n]);\n\n// Properties that have range limits AND accept string lengths\nconst RANGE_LENGTH_PROPERTIES: Record<string, { min: number; max: number }> = {\n fontSize: { min: FONT_SIZE_MIN, max: FONT_SIZE_MAX },\n letterSpacing: { min: LETTER_SPACING_MIN, max: LETTER_SPACING_MAX },\n borderRadius: { min: 0, max: BORDER_RADIUS_MAX },\n borderRadiusTopLeft: { min: 0, max: BORDER_RADIUS_MAX },\n borderRadiusTopRight: { min: 0, max: BORDER_RADIUS_MAX },\n borderRadiusBottomLeft: { min: 0, max: BORDER_RADIUS_MAX },\n borderRadiusBottomRight: { min: 0, max: BORDER_RADIUS_MAX },\n};\n\ninterface StyleValidationOptions {\n allowHoverStyle?: boolean;\n allowTransition?: boolean;\n allowHoverStyleRefs?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Returns true only if the value is a literal number (not a $ref).\n */\nfunction isLiteralNumber(value: unknown): value is number {\n return typeof value === 'number';\n}\n\n/**\n * Returns true only if the value is a literal string (not a $ref).\n */\nfunction isLiteralString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\n/**\n * Returns true if the value is a dynamic binding ($ref) that should\n * be skipped for static range checks.\n */\nfunction isDynamic(value: unknown): boolean {\n return isRef(value);\n}\n\n/**\n * Returns true if the string is a valid CSS color value.\n *\n * Supported formats:\n * - Hex: #RGB, #RRGGBB, #RRGGBBAA\n * - Functional: rgb(...), rgba(...), hsl(...), hsla(...)\n * - Named CSS colors (148 standard keywords)\n * - Special keywords: transparent, currentcolor\n */\nfunction isValidColor(value: string): boolean {\n const lower = value.toLowerCase();\n\n // Hex colors\n if (/^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/.test(lower)) {\n return true;\n }\n\n // Functional color notations\n if (\n lower.startsWith('rgb(') ||\n lower.startsWith('rgba(') ||\n lower.startsWith('hsl(') ||\n lower.startsWith('hsla(')\n ) {\n return true;\n }\n\n // Named CSS colors\n if (CSS_NAMED_COLORS.has(lower)) {\n return true;\n }\n\n // Special keywords\n if (lower === 'transparent' || lower === 'currentcolor') {\n return true;\n }\n\n return false;\n}\n\n/**\n * Returns true if the string is a valid CSS length value.\n *\n * Allowed pattern: optional negative sign, digits (with optional decimal),\n * and optional unit (px, %, em, rem).\n *\n * NOTE: `auto` is NOT checked here — it's handled separately per property.\n */\nfunction isValidLength(value: string): boolean {\n return /^-?[0-9]+(\\.[0-9]+)?(px|%|em|rem)?$/.test(value);\n}\n\n/**\n * Extract the numeric part from a length string like \"42px\", \"50%\", \"16em\",\n * \"1.5rem\", or \"100\".\n *\n * Returns the number, or null if it can't be parsed.\n */\nfunction parseLengthValue(value: string): number | null {\n const match = value.match(/^(-?[0-9]+(\\.[0-9]+)?)(px|%|em|rem)?$/);\n if (!match) {\n return null;\n }\n return Number(match[1]);\n}\n\nfunction isValidAspectRatioLiteral(value: string | number): boolean {\n if (typeof value === 'number') {\n return Number.isFinite(value) && value > 0;\n }\n\n const match = value.match(ASPECT_RATIO_PATTERN);\n if (!match) {\n return false;\n }\n\n const parts = value.split('/');\n if (parts.length !== 2) {\n return false;\n }\n\n const width = Number(parts[0].trim());\n const height = Number(parts[1].trim());\n return Number.isFinite(width) && Number.isFinite(height) && width > 0 && height > 0;\n}\n\n/**\n * Recursively scan all string values in a value (which may be a string,\n * object, or array) for dangerous CSS function patterns.\n * Skips $ref objects entirely.\n */\nfunction collectDangerousCssErrors(\n value: unknown,\n path: string,\n errors: ValidationError[],\n): void {\n if (typeof value === 'string') {\n const lower = value.toLowerCase();\n for (const fn of DANGEROUS_CSS_FUNCTIONS) {\n if (lower.includes(fn)) {\n errors.push(\n createError(\n 'FORBIDDEN_CSS_FUNCTION',\n `Style value contains forbidden CSS function \"${fn.slice(0, -1)}\" at \"${path}\"`,\n path,\n ),\n );\n // Report only the first match per string to keep errors concise\n break;\n }\n }\n return;\n }\n\n // Skip $ref objects — they are not user-authored strings\n if (isRef(value)) {\n return;\n }\n\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n collectDangerousCssErrors(value[i], `${path}[${i}]`, errors);\n }\n return;\n }\n\n if (typeof value === 'object' && value !== null) {\n for (const [key, child] of Object.entries(value as Record<string, unknown>)) {\n collectDangerousCssErrors(child, `${path}.${key}`, errors);\n }\n }\n}\n\n/**\n * Validate a single shadow object's blur and spread values,\n * and its color if present.\n */\nfunction validateShadowObject(\n shadow: Record<string, unknown>,\n path: string,\n errors: ValidationError[],\n): void {\n if (\n isLiteralNumber(shadow.blur) &&\n shadow.blur > BOX_SHADOW_BLUR_MAX\n ) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `boxShadow blur (${shadow.blur}) exceeds maximum of ${BOX_SHADOW_BLUR_MAX} at \"${path}.blur\"`,\n `${path}.blur`,\n ),\n );\n }\n\n if (\n isLiteralNumber(shadow.spread) &&\n shadow.spread > BOX_SHADOW_SPREAD_MAX\n ) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `boxShadow spread (${shadow.spread}) exceeds maximum of ${BOX_SHADOW_SPREAD_MAX} at \"${path}.spread\"`,\n `${path}.spread`,\n ),\n );\n }\n\n // Validate shadow color\n if (isLiteralString(shadow.color) && !isValidColor(shadow.color)) {\n errors.push(\n createError(\n 'INVALID_COLOR',\n `Invalid color \"${shadow.color}\" at \"${path}.color\"`,\n `${path}.color`,\n ),\n );\n }\n}\n\n/**\n * Validate a single text-shadow object's blur value and color.\n */\nfunction validateTextShadowObject(\n shadow: Record<string, unknown>,\n path: string,\n errors: ValidationError[],\n): void {\n if (\n isLiteralNumber(shadow.blur) &&\n shadow.blur > TEXT_SHADOW_BLUR_MAX\n ) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `textShadow blur (${shadow.blur}) exceeds maximum of ${TEXT_SHADOW_BLUR_MAX} at \"${path}.blur\"`,\n `${path}.blur`,\n ),\n );\n }\n\n if (isLiteralString(shadow.color) && !isValidColor(shadow.color)) {\n errors.push(\n createError(\n 'INVALID_COLOR',\n `Invalid color \"${shadow.color}\" at \"${path}.color\"`,\n `${path}.color`,\n ),\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Regex for valid $style references and style names\n// ---------------------------------------------------------------------------\n\nconst STYLE_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*$/;\n\nfunction reportStyleRefError(\n rawRef: string,\n stylePath: string,\n cardStyles: Record<string, Record<string, unknown>> | undefined,\n errors: ValidationError[],\n): string | undefined {\n const trimmedRef = rawRef.trim();\n\n if (!STYLE_NAME_PATTERN.test(trimmedRef)) {\n errors.push(\n createError(\n 'INVALID_STYLE_REF',\n `$style value \"${rawRef}\" is invalid; must match /^[A-Za-z][A-Za-z0-9_-]*$/ at \"${stylePath}.$style\"`,\n `${stylePath}.$style`,\n ),\n );\n return undefined;\n }\n\n if (!cardStyles || !(trimmedRef in cardStyles)) {\n errors.push(\n createError(\n 'STYLE_REF_NOT_FOUND',\n `$style references \"${trimmedRef}\" which is not defined in card.styles at \"${stylePath}.$style\"`,\n `${stylePath}.$style`,\n ),\n );\n return undefined;\n }\n\n return trimmedRef;\n}\n\nfunction resolveStyleRef(\n style: Record<string, unknown>,\n stylePath: string,\n cardStyles: Record<string, Record<string, unknown>> | undefined,\n errors: ValidationError[],\n): Record<string, unknown> | undefined {\n if (typeof style.$style !== 'string') {\n return style;\n }\n\n const trimmedRef = reportStyleRefError(style.$style, stylePath, cardStyles, errors);\n if (!trimmedRef || !cardStyles) {\n return undefined;\n }\n\n return mergeStyleWithRef(cardStyles[trimmedRef], style);\n}\n\nfunction collectNestedStyleRefErrors(\n value: unknown,\n path: string,\n errors: ValidationError[],\n): void {\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n collectNestedStyleRefErrors(value[i], `${path}[${i}]`, errors);\n }\n return;\n }\n\n if (typeof value !== 'object' || value === null) {\n return;\n }\n\n for (const [key, child] of Object.entries(value as Record<string, unknown>)) {\n const childPath = `${path}.${key}`;\n if (key === '$style') {\n errors.push(\n createError(\n 'STYLE_CIRCULAR_REF',\n `$style cannot be used inside card.styles definitions at \"${childPath}\"`,\n childPath,\n ),\n );\n continue;\n }\n collectNestedStyleRefErrors(child, childPath, errors);\n }\n}\n\n// ---------------------------------------------------------------------------\n// validateSingleStyle — reusable per-style validation logic\n// ---------------------------------------------------------------------------\n\n/**\n * Validate a single style object's properties.\n *\n * Checks:\n * 1. Forbidden style properties (spec 3.8)\n * 2. Numeric range limits (spec 6.4)\n * 3. Box-shadow count and value limits\n * 4. Text-shadow count and value limits\n * 5. Transform skew prohibition\n * 6. CSS function injection in string values\n * 7. Overflow: scroll prohibition (defense-in-depth)\n * 8. Color format validation\n * 9. Length format validation\n * 10. Range checks on string length values\n * 11. Border color validation\n * 12. Background gradient stop color validation\n */\nfunction validateSingleStyle(\n style: Record<string, unknown>,\n stylePath: string,\n errors: ValidationError[],\n cardStyles?: Record<string, Record<string, unknown>>,\n options: StyleValidationOptions = {},\n): void {\n const {\n allowHoverStyle = true,\n allowTransition = true,\n allowHoverStyleRefs = true,\n } = options;\n\n // ------------------------------------------------------------------\n // 1. Forbidden properties (spec 3.8)\n // Note: 'transition' and 'hoverStyle' are handled as structured\n // fields (sections 12-13), not raw CSS properties.\n // ------------------------------------------------------------------\n const STRUCTURED_FIELDS = new Set<string>();\n if (allowTransition) STRUCTURED_FIELDS.add('transition');\n if (allowHoverStyle) STRUCTURED_FIELDS.add('hoverStyle');\n for (const key of Object.keys(style)) {\n if (\n !STRUCTURED_FIELDS.has(key) &&\n (FORBIDDEN_STYLE_PROPERTIES as readonly string[]).includes(key)\n ) {\n errors.push(\n createError(\n 'FORBIDDEN_STYLE_PROPERTY',\n `Style property \"${key}\" is forbidden at \"${stylePath}.${key}\"`,\n `${stylePath}.${key}`,\n ),\n );\n }\n }\n\n if (!allowHoverStyle && 'hoverStyle' in style) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n `hoverStyle is not allowed inside responsive overrides at \"${stylePath}.hoverStyle\"`,\n `${stylePath}.hoverStyle`,\n ),\n );\n }\n\n if (!allowTransition && 'transition' in style) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n `transition is not allowed inside responsive overrides at \"${stylePath}.transition\"`,\n `${stylePath}.transition`,\n ),\n );\n }\n\n // ------------------------------------------------------------------\n // 2. Numeric range checks (spec 6.4)\n // ------------------------------------------------------------------\n\n // zIndex: ZINDEX_MIN..ZINDEX_MAX\n if ('zIndex' in style && isLiteralNumber(style.zIndex)) {\n const v = style.zIndex;\n if (v < ZINDEX_MIN || v > ZINDEX_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `zIndex (${v}) must be between ${ZINDEX_MIN} and ${ZINDEX_MAX} at \"${stylePath}.zIndex\"`,\n `${stylePath}.zIndex`,\n ),\n );\n }\n }\n\n // fontSize: FONT_SIZE_MIN..FONT_SIZE_MAX\n if ('fontSize' in style && isLiteralNumber(style.fontSize)) {\n const v = style.fontSize;\n if (v < FONT_SIZE_MIN || v > FONT_SIZE_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `fontSize (${v}) must be between ${FONT_SIZE_MIN} and ${FONT_SIZE_MAX} at \"${stylePath}.fontSize\"`,\n `${stylePath}.fontSize`,\n ),\n );\n }\n }\n\n // opacity: OPACITY_MIN..OPACITY_MAX\n if ('opacity' in style && isLiteralNumber(style.opacity)) {\n const v = style.opacity;\n if (v < OPACITY_MIN || v > OPACITY_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `opacity (${v}) must be between ${OPACITY_MIN} and ${OPACITY_MAX} at \"${stylePath}.opacity\"`,\n `${stylePath}.opacity`,\n ),\n );\n }\n }\n\n // letterSpacing: LETTER_SPACING_MIN..LETTER_SPACING_MAX\n if ('letterSpacing' in style && isLiteralNumber(style.letterSpacing)) {\n const v = style.letterSpacing;\n if (v < LETTER_SPACING_MIN || v > LETTER_SPACING_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `letterSpacing (${v}) must be between ${LETTER_SPACING_MIN} and ${LETTER_SPACING_MAX} at \"${stylePath}.letterSpacing\"`,\n `${stylePath}.letterSpacing`,\n ),\n );\n }\n }\n\n // borderRadius + directional variants: 0..BORDER_RADIUS_MAX\n for (const prop of [\n 'borderRadius',\n 'borderRadiusTopLeft',\n 'borderRadiusTopRight',\n 'borderRadiusBottomLeft',\n 'borderRadiusBottomRight',\n ] as const) {\n if (prop in style && isLiteralNumber(style[prop])) {\n const v = style[prop] as number;\n if (v < 0 || v > BORDER_RADIUS_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `${prop} (${v}) must be between 0 and ${BORDER_RADIUS_MAX} at \"${stylePath}.${prop}\"`,\n `${stylePath}.${prop}`,\n ),\n );\n }\n }\n }\n\n // transform sub-properties\n if (\n 'transform' in style &&\n typeof style.transform === 'object' &&\n style.transform !== null &&\n !isDynamic(style.transform)\n ) {\n const transform = style.transform as Record<string, unknown>;\n const transformPath = `${stylePath}.transform`;\n\n // scale: TRANSFORM_SCALE_MIN..TRANSFORM_SCALE_MAX\n if ('scale' in transform && isLiteralNumber(transform.scale)) {\n const v = transform.scale;\n if (v < TRANSFORM_SCALE_MIN || v > TRANSFORM_SCALE_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `transform.scale (${v}) must be between ${TRANSFORM_SCALE_MIN} and ${TRANSFORM_SCALE_MAX} at \"${transformPath}.scale\"`,\n `${transformPath}.scale`,\n ),\n );\n }\n }\n\n // translateX: TRANSFORM_TRANSLATE_MIN..TRANSFORM_TRANSLATE_MAX\n if ('translateX' in transform && isLiteralNumber(transform.translateX)) {\n const v = transform.translateX;\n if (v < TRANSFORM_TRANSLATE_MIN || v > TRANSFORM_TRANSLATE_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `transform.translateX (${v}) must be between ${TRANSFORM_TRANSLATE_MIN} and ${TRANSFORM_TRANSLATE_MAX} at \"${transformPath}.translateX\"`,\n `${transformPath}.translateX`,\n ),\n );\n }\n }\n\n // translateY: TRANSFORM_TRANSLATE_MIN..TRANSFORM_TRANSLATE_MAX\n if ('translateY' in transform && isLiteralNumber(transform.translateY)) {\n const v = transform.translateY;\n if (v < TRANSFORM_TRANSLATE_MIN || v > TRANSFORM_TRANSLATE_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `transform.translateY (${v}) must be between ${TRANSFORM_TRANSLATE_MIN} and ${TRANSFORM_TRANSLATE_MAX} at \"${transformPath}.translateY\"`,\n `${transformPath}.translateY`,\n ),\n );\n }\n }\n\n // ------------------------------------------------------------------\n // 4. Transform skew forbidden\n // ------------------------------------------------------------------\n if ('skew' in transform) {\n errors.push(\n createError(\n 'TRANSFORM_SKEW_FORBIDDEN',\n `transform.skew is forbidden at \"${transformPath}.skew\"`,\n `${transformPath}.skew`,\n ),\n );\n }\n }\n\n // ------------------------------------------------------------------\n // 3. Box-shadow limits\n // ------------------------------------------------------------------\n if ('boxShadow' in style && style.boxShadow != null) {\n const boxShadow = style.boxShadow;\n const boxShadowPath = `${stylePath}.boxShadow`;\n\n if (Array.isArray(boxShadow)) {\n // Array of shadows — check count\n if (boxShadow.length > BOX_SHADOW_MAX_COUNT) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `boxShadow has ${boxShadow.length} entries, maximum is ${BOX_SHADOW_MAX_COUNT} at \"${boxShadowPath}\"`,\n boxShadowPath,\n ),\n );\n }\n\n // Check each shadow's blur/spread/color\n for (let i = 0; i < boxShadow.length; i++) {\n const shadow = boxShadow[i];\n if (typeof shadow === 'object' && shadow !== null) {\n validateShadowObject(\n shadow as Record<string, unknown>,\n `${boxShadowPath}[${i}]`,\n errors,\n );\n }\n }\n } else if (typeof boxShadow === 'object' && boxShadow !== null) {\n // Single shadow object\n validateShadowObject(\n boxShadow as Record<string, unknown>,\n boxShadowPath,\n errors,\n );\n }\n }\n\n // ------------------------------------------------------------------\n // 4. Text-shadow limits\n // ------------------------------------------------------------------\n if ('textShadow' in style && style.textShadow != null) {\n const textShadow = style.textShadow;\n const textShadowPath = `${stylePath}.textShadow`;\n\n if (Array.isArray(textShadow)) {\n if (textShadow.length > TEXT_SHADOW_MAX_COUNT) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `textShadow has ${textShadow.length} entries, maximum is ${TEXT_SHADOW_MAX_COUNT} at \"${textShadowPath}\"`,\n textShadowPath,\n ),\n );\n }\n\n for (let i = 0; i < textShadow.length; i++) {\n const shadow = textShadow[i];\n if (typeof shadow === 'object' && shadow !== null) {\n validateTextShadowObject(\n shadow as Record<string, unknown>,\n `${textShadowPath}[${i}]`,\n errors,\n );\n }\n }\n } else if (typeof textShadow === 'object' && textShadow !== null) {\n validateTextShadowObject(\n textShadow as Record<string, unknown>,\n textShadowPath,\n errors,\n );\n }\n }\n\n // ------------------------------------------------------------------\n // 6. CSS function injection — scan all string values\n // ------------------------------------------------------------------\n for (const [key, value] of Object.entries(style)) {\n collectDangerousCssErrors(value, `${stylePath}.${key}`, errors);\n }\n\n // ------------------------------------------------------------------\n // 7. Overflow: scroll forbidden (defense-in-depth)\n // ------------------------------------------------------------------\n if ('overflow' in style && style.overflow === 'scroll') {\n errors.push(\n createError(\n 'FORBIDDEN_OVERFLOW_VALUE',\n `overflow \"scroll\" is forbidden; use \"visible\", \"hidden\", or \"auto\" at \"${stylePath}.overflow\"`,\n `${stylePath}.overflow`,\n ),\n );\n }\n\n // ------------------------------------------------------------------\n // 8. Color format validation\n // ------------------------------------------------------------------\n for (const prop of COLOR_PROPERTIES) {\n if (\n prop in style &&\n isLiteralString(style[prop]) &&\n !isDynamic(style[prop])\n ) {\n if (!isValidColor(style[prop] as string)) {\n errors.push(\n createError(\n 'INVALID_COLOR',\n `Invalid color \"${style[prop]}\" at \"${stylePath}.${prop}\"`,\n `${stylePath}.${prop}`,\n ),\n );\n }\n }\n }\n\n // ------------------------------------------------------------------\n // 9. Length format validation\n // ------------------------------------------------------------------\n for (const prop of LENGTH_PROPERTIES) {\n if (\n prop in style &&\n isLiteralString(style[prop]) &&\n !isDynamic(style[prop])\n ) {\n const val = style[prop] as string;\n if (val === 'auto') {\n if (!LENGTH_AUTO_ALLOWED.has(prop)) {\n errors.push(\n createError(\n 'INVALID_LENGTH',\n `\"auto\" is not allowed for \"${prop}\" at \"${stylePath}.${prop}\"`,\n `${stylePath}.${prop}`,\n ),\n );\n }\n } else if (!isValidLength(val)) {\n errors.push(\n createError(\n 'INVALID_LENGTH',\n `Invalid length \"${val}\" at \"${stylePath}.${prop}\"`,\n `${stylePath}.${prop}`,\n ),\n );\n }\n }\n }\n\n if ('aspectRatio' in style && style.aspectRatio != null && !isDynamic(style.aspectRatio)) {\n const aspectRatio = style.aspectRatio;\n if (\n (typeof aspectRatio !== 'number' && typeof aspectRatio !== 'string') ||\n !isValidAspectRatioLiteral(aspectRatio)\n ) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n `Invalid aspectRatio \"${String(aspectRatio)}\" at \"${stylePath}.aspectRatio\"`,\n `${stylePath}.aspectRatio`,\n ),\n );\n }\n }\n\n // ------------------------------------------------------------------\n // 10. Range checks on string length values\n // ------------------------------------------------------------------\n for (const [prop, range] of Object.entries(RANGE_LENGTH_PROPERTIES)) {\n if (\n prop in style &&\n isLiteralString(style[prop]) &&\n !isDynamic(style[prop])\n ) {\n const numericValue = parseLengthValue(style[prop] as string);\n if (numericValue !== null) {\n if (numericValue < range.min || numericValue > range.max) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `${prop} (${style[prop]}) must be between ${range.min} and ${range.max} at \"${stylePath}.${prop}\"`,\n `${stylePath}.${prop}`,\n ),\n );\n }\n }\n }\n }\n\n // ------------------------------------------------------------------\n // 11. Border color validation (border + borderTop/Right/Bottom/Left)\n // ------------------------------------------------------------------\n const borderKeys = ['border', 'borderTop', 'borderRight', 'borderBottom', 'borderLeft'] as const;\n for (const borderKey of borderKeys) {\n if (\n borderKey in style &&\n typeof style[borderKey] === 'object' &&\n style[borderKey] !== null &&\n !isDynamic(style[borderKey])\n ) {\n const border = style[borderKey] as Record<string, unknown>;\n const borderPath = `${stylePath}.${borderKey}`;\n\n if (\n isLiteralString(border.color) &&\n !isDynamic(border.color) &&\n !isValidColor(border.color)\n ) {\n errors.push(\n createError(\n 'INVALID_COLOR',\n `Invalid color \"${border.color}\" at \"${borderPath}.color\"`,\n `${borderPath}.color`,\n ),\n );\n }\n }\n }\n\n // ------------------------------------------------------------------\n // 12. Background gradient stop color validation\n // ------------------------------------------------------------------\n if (\n 'backgroundGradient' in style &&\n typeof style.backgroundGradient === 'object' &&\n style.backgroundGradient !== null &&\n !isDynamic(style.backgroundGradient)\n ) {\n const gradient = style.backgroundGradient as Record<string, unknown>;\n const gradientPath = `${stylePath}.backgroundGradient`;\n\n if (Array.isArray(gradient.stops)) {\n for (let i = 0; i < gradient.stops.length; i++) {\n const stop = gradient.stops[i];\n if (\n typeof stop === 'object' &&\n stop !== null &&\n !isDynamic(stop)\n ) {\n const stopObj = stop as Record<string, unknown>;\n if (\n isLiteralString(stopObj.color) &&\n !isDynamic(stopObj.color) &&\n !isValidColor(stopObj.color)\n ) {\n errors.push(\n createError(\n 'INVALID_COLOR',\n `Invalid color \"${stopObj.color}\" at \"${gradientPath}.stops[${i}].color\"`,\n `${gradientPath}.stops[${i}].color`,\n ),\n );\n }\n }\n }\n }\n }\n\n // ------------------------------------------------------------------\n // 13. hoverStyle validation (spec 3.9)\n // ------------------------------------------------------------------\n if (allowHoverStyle && 'hoverStyle' in style && style.hoverStyle != null) {\n const hoverStyle = style.hoverStyle;\n const hoverPath = `${stylePath}.hoverStyle`;\n\n if (typeof hoverStyle !== 'object' || Array.isArray(hoverStyle)) {\n errors.push(\n createError(\n 'INVALID_HOVER_STYLE',\n `hoverStyle must be an object at \"${hoverPath}\"`,\n hoverPath,\n ),\n );\n } else {\n const hoverObj = hoverStyle as Record<string, unknown>;\n\n // Nested hoverStyle is forbidden\n if ('hoverStyle' in hoverObj) {\n errors.push(\n createError(\n 'HOVER_STYLE_NESTED',\n `Nested hoverStyle is forbidden at \"${hoverPath}.hoverStyle\"`,\n `${hoverPath}.hoverStyle`,\n ),\n );\n }\n\n const mergedHoverStyle = allowHoverStyleRefs\n ? resolveStyleRef(hoverObj, hoverPath, cardStyles, errors)\n : hoverObj;\n\n if (mergedHoverStyle) {\n // Validate hoverStyle with the same rules (recursive call)\n validateSingleStyle(\n mergedHoverStyle,\n hoverPath,\n errors,\n cardStyles,\n {\n allowHoverStyle,\n allowTransition,\n allowHoverStyleRefs,\n },\n );\n }\n }\n }\n\n // ------------------------------------------------------------------\n // 14. transition validation (spec 3.9)\n // ------------------------------------------------------------------\n if (allowTransition && 'transition' in style && style.transition != null) {\n const transition = style.transition;\n const transPath = `${stylePath}.transition`;\n\n // Defense-in-depth: reject raw string transitions\n if (typeof transition === 'string') {\n errors.push(\n createError(\n 'TRANSITION_RAW_STRING',\n `transition must be an object or array, not a string at \"${transPath}\"`,\n transPath,\n ),\n );\n } else {\n const transitions = Array.isArray(transition) ? transition : [transition];\n\n if (transitions.length > TRANSITION_MAX_COUNT) {\n errors.push(\n createError(\n 'TRANSITION_COUNT_EXCEEDED',\n `transition has ${transitions.length} entries, maximum is ${TRANSITION_MAX_COUNT} at \"${transPath}\"`,\n transPath,\n ),\n );\n }\n\n for (let i = 0; i < transitions.length; i++) {\n const t = transitions[i];\n const tPath = Array.isArray(transition) ? `${transPath}[${i}]` : transPath;\n\n if (typeof t !== 'object' || t === null) continue;\n const tObj = t as Record<string, unknown>;\n\n // Validate property is in whitelist\n if (\n isLiteralString(tObj.property) &&\n !(ALLOWED_TRANSITION_PROPERTIES as readonly string[]).includes(tObj.property)\n ) {\n errors.push(\n createError(\n 'TRANSITION_PROPERTY_FORBIDDEN',\n `transition property \"${tObj.property}\" is not in the allowed list at \"${tPath}.property\"`,\n `${tPath}.property`,\n ),\n );\n }\n\n // Validate duration range\n if (isLiteralNumber(tObj.duration)) {\n if (tObj.duration < 0 || tObj.duration > TRANSITION_DURATION_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `transition duration (${tObj.duration}) must be between 0 and ${TRANSITION_DURATION_MAX} at \"${tPath}.duration\"`,\n `${tPath}.duration`,\n ),\n );\n }\n }\n\n // Validate delay range\n if (isLiteralNumber(tObj.delay)) {\n if (tObj.delay < 0 || tObj.delay > TRANSITION_DELAY_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `transition delay (${tObj.delay}) must be between 0 and ${TRANSITION_DELAY_MAX} at \"${tPath}.delay\"`,\n `${tPath}.delay`,\n ),\n );\n }\n }\n }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helper: merge $style with inline style\n// ---------------------------------------------------------------------------\n\n/**\n * Build a merged style object from a card.styles entry and inline style\n * properties, excluding the `$style` key itself from the inline portion.\n */\nfunction mergeStyleWithRef(\n cardStyleEntry: Record<string, unknown>,\n inlineStyle: Record<string, unknown>,\n): Record<string, unknown> {\n const merged: Record<string, unknown> = { ...cardStyleEntry };\n for (const [key, value] of Object.entries(inlineStyle)) {\n if (key !== '$style') {\n merged[key] = value;\n }\n }\n return merged;\n}\n\n// ---------------------------------------------------------------------------\n// Main export\n// ---------------------------------------------------------------------------\n\n/**\n * Validate all style properties across every node in the card's view tree,\n * and validate card-level style definitions.\n *\n * Checks:\n * 1. Forbidden style properties (spec 3.8)\n * 2. Numeric range limits (spec 6.4)\n * 3. Box-shadow count and value limits\n * 4. Transform skew prohibition\n * 5. CSS function injection in string values\n * 6. Overflow: scroll prohibition (defense-in-depth)\n * 7. Color format validation\n * 8. Length format validation\n * 9. Range checks on string length values\n * 10. $style reference validation and merging\n */\nexport function validateStyles(\n views: Record<string, unknown>,\n cardStyles?: Record<string, Record<string, unknown>>,\n fragments?: Record<string, unknown>,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n // ------------------------------------------------------------------\n // Phase 0: Validate card.styles entries\n // ------------------------------------------------------------------\n if (cardStyles) {\n for (const [styleName, styleEntry] of Object.entries(cardStyles)) {\n const entryPath = `styles.${styleName}`;\n\n // Defense-in-depth: validate style name format\n // (Zod regex already checks this, but we add a redundant check)\n if (!STYLE_NAME_PATTERN.test(styleName)) {\n errors.push(\n createError(\n 'INVALID_STYLE_NAME',\n `Style name \"${styleName}\" is invalid; must match /^[A-Za-z][A-Za-z0-9_-]*$/ at \"${entryPath}\"`,\n entryPath,\n ),\n );\n }\n\n // $style cannot be used anywhere inside card.styles definitions\n collectNestedStyleRefErrors(styleEntry, entryPath, errors);\n\n // Run all per-style validations on this entry\n validateSingleStyle(styleEntry, entryPath, errors, undefined, {\n allowHoverStyleRefs: false,\n });\n }\n }\n\n // ------------------------------------------------------------------\n // Phase 1: Validate per-node styles (with $style merging)\n // ------------------------------------------------------------------\n walkRenderableCard(views, fragments, (node, ctx) => {\n if (!('type' in node) || typeof node.type !== 'string') {\n return;\n }\n\n const style =\n node.style != null &&\n typeof node.style === 'object' &&\n !Array.isArray(node.style)\n ? node.style as Record<string, unknown>\n : undefined;\n if (style != null && typeof style === 'object') {\n const stylePath = `${ctx.path}.style`;\n\n const mergedStyle = resolveStyleRef(style, stylePath, cardStyles, errors);\n if (mergedStyle) {\n // No $style or valid $style — validate the effective style\n validateSingleStyle(mergedStyle, stylePath, errors, cardStyles);\n }\n }\n\n const responsive = node.responsive;\n if (\n responsive != null &&\n typeof responsive === 'object' &&\n !Array.isArray(responsive)\n ) {\n const compact = (responsive as Record<string, unknown>).compact;\n if (\n compact != null &&\n typeof compact === 'object' &&\n !Array.isArray(compact)\n ) {\n const compactPath = `${ctx.path}.responsive.compact`;\n const mergedCompact = resolveStyleRef(\n compact as Record<string, unknown>,\n compactPath,\n cardStyles,\n errors,\n );\n\n if (mergedCompact) {\n validateSingleStyle(mergedCompact, compactPath, errors, cardStyles, {\n allowHoverStyle: false,\n allowTransition: false,\n allowHoverStyleRefs: false,\n });\n }\n }\n }\n\n const spans = Array.isArray(node.spans) ? node.spans : undefined;\n if (node.type === 'Text' && spans) {\n for (let i = 0; i < spans.length; i++) {\n const span = spans[i];\n if (\n span == null ||\n typeof span !== 'object' ||\n Array.isArray(span)\n ) {\n continue;\n }\n\n const spanStyle = (span as Record<string, unknown>).style;\n if (\n spanStyle == null ||\n typeof spanStyle !== 'object' ||\n Array.isArray(spanStyle)\n ) {\n continue;\n }\n\n validateSingleStyle(\n spanStyle as Record<string, unknown>,\n `${ctx.path}.spans[${i}].style`,\n errors,\n undefined,\n {\n allowHoverStyle: false,\n allowTransition: false,\n allowHoverStyleRefs: false,\n },\n );\n }\n }\n });\n\n return errors;\n}\n","/**\n * @safe-ugc-ui/validator — Security Validation\n *\n * Enforces security rules from spec sections 3 and 8:\n * - External URL blocking on Image/Avatar `src` fields (literal and $ref)\n * - Asset path validation (`@assets/` prefix, no traversal)\n * - cardAssets value validation\n * - Forbidden CSS `url()` function in style string values\n * - Position restrictions (fixed, sticky, absolute outside Stack)\n * - Nested overflow:auto detection\n * - Prototype pollution prevention in $ref paths\n */\n\nimport {\n PROTOTYPE_POLLUTION_SEGMENTS,\n isRef,\n} from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\n\nimport {\n type TraversableNode,\n type TraversalContext,\n traverseCard,\n} from './traverse.js';\nimport { walkRenderableCard } from './renderable-walk.js';\nimport {\n type ResponsiveMode,\n RESPONSIVE_MODES,\n getEffectiveStyleForMode,\n} from './responsive-utils.js';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/**\n * URL prefixes that are forbidden in Image/Avatar `src` values.\n * Checked case-insensitively to prevent bypass via mixed case.\n */\nconst FORBIDDEN_URL_PREFIXES = [\n 'http://',\n 'https://',\n '//',\n 'data:',\n 'javascript:',\n] as const;\n\n// ---------------------------------------------------------------------------\n// Helper: scanForRefs — recursively find $ref values for pollution check\n// ---------------------------------------------------------------------------\n\n/**\n * Recursively walk an unknown value looking for `{ $ref: string }` objects.\n * For each one found, verify the ref path segments do not contain\n * prototype pollution keys (`__proto__`, `constructor`, `prototype`).\n *\n * @param obj - The value to scan (may be primitive, array, or object).\n * @param path - The JSON-pointer-like location for error reporting.\n * @param errors - Accumulator for any validation errors found.\n */\nfunction scanForRefs(\n obj: unknown,\n path: string,\n errors: ValidationError[],\n): void {\n if (obj === null || obj === undefined || typeof obj !== 'object') {\n return;\n }\n\n // Check if this object is a $ref\n if (isRef(obj)) {\n const refStr = (obj as { $ref: string }).$ref;\n // Split by '.' and '[' to extract all path segments\n const segments = refStr.split(/[.\\[]/);\n for (const segment of segments) {\n // Remove trailing ']' from bracket access segments\n const clean = segment.replace(/]$/, '');\n if (\n (PROTOTYPE_POLLUTION_SEGMENTS as readonly string[]).includes(clean)\n ) {\n errors.push(\n createError(\n 'PROTOTYPE_POLLUTION',\n `$ref \"${refStr}\" contains forbidden prototype pollution segment \"${clean}\".`,\n path,\n ),\n );\n // One error per ref is sufficient\n return;\n }\n }\n return;\n }\n\n // Recurse into arrays\n if (Array.isArray(obj)) {\n for (let i = 0; i < obj.length; i++) {\n scanForRefs(obj[i], `${path}[${i}]`, errors);\n }\n return;\n }\n\n // Recurse into plain objects\n for (const [key, value] of Object.entries(obj)) {\n scanForRefs(value, `${path}.${key}`, errors);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helper: isForbiddenUrl\n// ---------------------------------------------------------------------------\n\n/**\n * Returns true if the string starts with any forbidden URL prefix\n * (case-insensitive comparison).\n */\nfunction isForbiddenUrl(value: string): boolean {\n const lower = value.trim().toLowerCase();\n return FORBIDDEN_URL_PREFIXES.some((prefix) => lower.startsWith(prefix));\n}\n\n// ---------------------------------------------------------------------------\n// Helper: validateAssetPath\n// ---------------------------------------------------------------------------\n\n/**\n * Validates an asset path string. Must start with `@assets/` and must not\n * contain path traversal sequences.\n *\n * @returns An error code if invalid, or null if the path is acceptable.\n */\nfunction validateAssetPath(\n value: string,\n): 'ASSET_PATH_TRAVERSAL' | 'INVALID_ASSET_PATH' | null {\n if (!value.startsWith('@assets/')) {\n return 'INVALID_ASSET_PATH';\n }\n if (value.includes('../')) {\n return 'ASSET_PATH_TRAVERSAL';\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Helper: resolveRefFromState\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a $ref path against a state object. Matches the algorithm in\n * `packages/react/src/state-resolver.ts`:\n * - Strip leading `$` from the ref path\n * - Split by `.`, then for each segment extract `[N]` bracket indices\n * - Traverse state, using numeric indices for arrays\n * - Block prototype pollution segments\n *\n * @returns The resolved value, or `undefined` if resolution fails.\n */\nfunction resolveRefFromState(\n refPath: string,\n state: Record<string, unknown>,\n): unknown {\n // Strip leading $\n const path = refPath.startsWith('$') ? refPath.slice(1) : refPath;\n const dotSegments = path.split('.');\n\n // Flatten dot-segments into individual traversal keys,\n // expanding bracket notation (e.g. \"items[0][1]\" → [\"items\", \"0\", \"1\"])\n const keys: string[] = [];\n for (const dotSeg of dotSegments) {\n // Match the base name (before any brackets) and any [N] patterns\n const bracketPattern = /\\[(\\d+)\\]/g;\n const firstBracket = dotSeg.indexOf('[');\n const baseName = firstBracket === -1 ? dotSeg : dotSeg.slice(0, firstBracket);\n if (baseName) {\n keys.push(baseName);\n }\n let match: RegExpExecArray | null;\n while ((match = bracketPattern.exec(dotSeg)) !== null) {\n keys.push(match[1]);\n }\n }\n\n // Block prototype pollution\n for (const key of keys) {\n if (\n (PROTOTYPE_POLLUTION_SEGMENTS as readonly string[]).includes(key)\n ) {\n return undefined;\n }\n }\n\n // Traverse state\n let current: unknown = state;\n for (const key of keys) {\n if (current == null || typeof current !== 'object') return undefined;\n\n if (Array.isArray(current)) {\n const index = Number(key);\n if (!Number.isInteger(index) || index < 0) return undefined;\n current = current[index];\n } else {\n current = (current as Record<string, unknown>)[key];\n }\n }\n return current;\n}\n\n// ---------------------------------------------------------------------------\n// Helper: checkSrcValue\n// ---------------------------------------------------------------------------\n\n/**\n * Check a resolved src string value and push appropriate errors.\n */\nfunction checkSrcValue(\n resolved: string,\n type: string,\n errorPath: string,\n errors: ValidationError[],\n): void {\n if (isForbiddenUrl(resolved)) {\n errors.push(\n createError(\n 'EXTERNAL_URL',\n `External URLs are not allowed in ${type}.src. Got \"${resolved}\".`,\n errorPath,\n ),\n );\n } else {\n const assetError = validateAssetPath(resolved);\n if (assetError === 'ASSET_PATH_TRAVERSAL') {\n errors.push(\n createError(\n 'ASSET_PATH_TRAVERSAL',\n `Asset path contains path traversal (\"../\"). Got \"${resolved}\".`,\n errorPath,\n ),\n );\n } else if (assetError === 'INVALID_ASSET_PATH') {\n errors.push(\n createError(\n 'INVALID_ASSET_PATH',\n `Asset path must start with \"@assets/\". Got \"${resolved}\".`,\n errorPath,\n ),\n );\n }\n }\n}\n\nfunction pushUniqueError(\n errors: ValidationError[],\n seen: Set<string>,\n error: ValidationError,\n): void {\n const key = `${error.code}|${error.path}|${error.message}`;\n if (seen.has(key)) {\n return;\n }\n seen.add(key);\n errors.push(error);\n}\n\nfunction getScannableNodeFields(\n node: TraversableNode,\n): Record<string, unknown> {\n const nodeFields = { ...node } as Record<string, unknown>;\n delete nodeFields.type;\n delete nodeFields.style;\n delete nodeFields.children;\n\n const interactiveField =\n node.type === 'Accordion'\n ? 'items'\n : node.type === 'Tabs'\n ? 'tabs'\n : null;\n\n if (interactiveField && Array.isArray(node[interactiveField])) {\n nodeFields[interactiveField] = node[interactiveField].map((item) => {\n if (\n item == null ||\n typeof item !== 'object' ||\n Array.isArray(item)\n ) {\n return item;\n }\n\n const { content: _content, ...rest } = item as Record<string, unknown>;\n return rest;\n });\n }\n\n return nodeFields;\n}\n\nfunction scanStyleStringsForUrl(\n style: Record<string, unknown> | undefined,\n path: string,\n errors: ValidationError[],\n): void {\n if (!style) {\n return;\n }\n\n for (const [prop, value] of Object.entries(style)) {\n if (typeof value === 'string' && value.toLowerCase().includes('url(')) {\n errors.push(\n createError(\n 'FORBIDDEN_CSS_FUNCTION',\n `CSS url() function is forbidden in style values. Found in \"${prop}\".`,\n `${path}.${prop}`,\n ),\n );\n }\n }\n}\n\nfunction validateEffectiveStylesForMode(\n mode: ResponsiveMode,\n views: Record<string, unknown>,\n cardStyles: Record<string, Record<string, unknown>> | undefined,\n fragments: Record<string, unknown> | undefined,\n errors: ValidationError[],\n seen: Set<string>,\n): void {\n const styleResolver = (node: TraversableNode) =>\n getEffectiveStyleForMode(node, cardStyles, mode);\n\n traverseCard(views, (node: TraversableNode, context: TraversalContext) => {\n const effectiveStyle = styleResolver(node);\n\n if (effectiveStyle && typeof effectiveStyle.position === 'string') {\n const position = effectiveStyle.position;\n\n if (position === 'fixed') {\n pushUniqueError(\n errors,\n seen,\n createError(\n 'POSITION_FIXED_FORBIDDEN',\n 'CSS position \"fixed\" is not allowed.',\n `${context.path}.style.position`,\n ),\n );\n } else if (position === 'sticky') {\n pushUniqueError(\n errors,\n seen,\n createError(\n 'POSITION_STICKY_FORBIDDEN',\n 'CSS position \"sticky\" is not allowed.',\n `${context.path}.style.position`,\n ),\n );\n } else if (position === 'absolute' && context.parentType !== 'Stack') {\n pushUniqueError(\n errors,\n seen,\n createError(\n 'POSITION_ABSOLUTE_NOT_IN_STACK',\n 'CSS position \"absolute\" is only allowed inside a Stack component.',\n `${context.path}.style.position`,\n ),\n );\n }\n }\n\n if (\n effectiveStyle &&\n effectiveStyle.overflow === 'auto' &&\n context.overflowAutoAncestor\n ) {\n pushUniqueError(\n errors,\n seen,\n createError(\n 'OVERFLOW_AUTO_NESTED',\n 'Nested overflow:auto is not allowed. An ancestor already has overflow:auto.',\n `${context.path}.style.overflow`,\n ),\n );\n }\n }, styleResolver, fragments);\n}\n\n// ---------------------------------------------------------------------------\n// validateSecurity\n// ---------------------------------------------------------------------------\n\n/**\n * Run all security validation rules against every node in every view.\n *\n * Rules checked (spec sections 3 and 8):\n * 1. External URL blocking on Image/Avatar `src` (literal and $ref)\n * 2. Asset path validation\n * 3. cardAssets value validation\n * 4. Forbidden CSS `url()` in style string values\n * 5. Position restrictions (fixed, sticky, absolute outside Stack)\n * 6. Nested overflow:auto\n * 7. Prototype pollution in $ref paths\n *\n * @param card - Object containing `views`, optional `state`, and optional `cardAssets`.\n * @returns An array of validation errors (empty if all rules pass).\n */\nexport function validateSecurity(card: {\n views: Record<string, unknown>;\n state?: Record<string, unknown>;\n cardAssets?: Record<string, string>;\n cardStyles?: Record<string, Record<string, unknown>>;\n fragments?: Record<string, unknown>;\n}): ValidationError[] {\n const errors: ValidationError[] = [];\n const seen = new Set<string>();\n const { views, state, cardAssets, cardStyles, fragments } = card;\n\n // -----------------------------------------------------------------\n // 0. Validate cardAssets values\n // -----------------------------------------------------------------\n if (cardAssets) {\n for (const [key, value] of Object.entries(cardAssets)) {\n const assetError = validateAssetPath(value);\n if (assetError === 'ASSET_PATH_TRAVERSAL') {\n errors.push(\n createError(\n 'ASSET_PATH_TRAVERSAL',\n `Asset path contains path traversal (\"../\"). Got \"${value}\".`,\n `assets.${key}`,\n ),\n );\n } else if (assetError === 'INVALID_ASSET_PATH') {\n errors.push(\n createError(\n 'INVALID_ASSET_PATH',\n `Asset path must start with \"@assets/\". Got \"${value}\".`,\n `assets.${key}`,\n ),\n );\n }\n }\n }\n\n walkRenderableCard(views, fragments, (node, context) => {\n if (!('type' in node) || typeof node.type !== 'string') {\n return;\n }\n\n const traversableNode = node as TraversableNode;\n const { path } = context;\n const style =\n traversableNode.style != null &&\n typeof traversableNode.style === 'object' &&\n !Array.isArray(traversableNode.style)\n ? traversableNode.style as Record<string, unknown>\n : undefined;\n const type = traversableNode.type;\n const nodeFields = getScannableNodeFields(traversableNode);\n\n // -----------------------------------------------------------------\n // 1. External URL blocking — Image and Avatar `src`\n // -----------------------------------------------------------------\n if (type === 'Image' || type === 'Avatar') {\n const src = (node as Record<string, unknown>).src;\n if (typeof src === 'string') {\n // Literal string src\n checkSrcValue(src, type, `${path}.src`, errors);\n } else if (isRef(src)) {\n // $ref src — resolve from state if available\n if (state) {\n const resolved = resolveRefFromState(\n (src as { $ref: string }).$ref,\n state,\n );\n if (typeof resolved === 'string') {\n checkSrcValue(resolved, type, `${path}.src`, errors);\n }\n // If resolution fails (undefined), skip — may be a loop-local variable\n }\n // If no state provided, skip $ref resolution\n }\n }\n\n // -----------------------------------------------------------------\n // 2. Scan all style string values for `url()` pattern\n // -----------------------------------------------------------------\n scanStyleStringsForUrl(style, `${path}.style`, errors);\n\n const responsive = traversableNode.responsive;\n if (\n responsive != null &&\n typeof responsive === 'object' &&\n !Array.isArray(responsive)\n ) {\n const compact = (responsive as Record<string, unknown>).compact;\n if (\n compact != null &&\n typeof compact === 'object' &&\n !Array.isArray(compact)\n ) {\n scanStyleStringsForUrl(\n compact as Record<string, unknown>,\n `${path}.responsive.compact`,\n errors,\n );\n }\n }\n\n if (type === 'Text' && Array.isArray((traversableNode as Record<string, unknown>).spans)) {\n const spans = (traversableNode as Record<string, unknown>).spans as unknown[];\n for (let i = 0; i < spans.length; i++) {\n const span = spans[i];\n if (\n span == null ||\n typeof span !== 'object' ||\n Array.isArray(span)\n ) {\n continue;\n }\n\n const spanStyle = (span as Record<string, unknown>).style;\n if (\n spanStyle != null &&\n typeof spanStyle === 'object' &&\n !Array.isArray(spanStyle)\n ) {\n scanStyleStringsForUrl(\n spanStyle as Record<string, unknown>,\n `${path}.spans[${i}].style`,\n errors,\n );\n }\n }\n }\n\n // -----------------------------------------------------------------\n // 3. Prototype pollution check on $ref values in node fields and style\n // -----------------------------------------------------------------\n scanForRefs(nodeFields, path, errors);\n if (style) {\n scanForRefs(style, `${path}.style`, errors);\n }\n if (\n responsive != null &&\n typeof responsive === 'object' &&\n !Array.isArray(responsive)\n ) {\n scanForRefs(responsive, `${path}.responsive`, errors);\n }\n });\n\n for (const mode of RESPONSIVE_MODES) {\n validateEffectiveStylesForMode(mode, views, cardStyles, fragments, errors, seen);\n }\n\n return errors;\n}\n","import type { TraversableNode } from './traverse.js';\n\nexport type ResponsiveMode = 'default' | 'compact';\n\nexport const RESPONSIVE_MODES: readonly ResponsiveMode[] = [\n 'default',\n 'compact',\n] as const;\n\nfunction mergeNamedStyle(\n style: Record<string, unknown> | undefined,\n cardStyles: Record<string, Record<string, unknown>> | undefined,\n): Record<string, unknown> | undefined {\n if (!style) return undefined;\n\n const rawStyleName = style.$style;\n const styleName = typeof rawStyleName === 'string' ? rawStyleName.trim() : rawStyleName;\n if (!styleName || typeof styleName !== 'string' || !cardStyles) {\n if (style.$style !== undefined) {\n const { $style: _, ...rest } = style;\n return rest;\n }\n return style;\n }\n\n const baseStyle = cardStyles[styleName];\n if (!baseStyle) {\n const { $style: _, ...rest } = style;\n return rest;\n }\n\n const { $style: _, ...inlineWithoutStyleRef } = style;\n return { ...baseStyle, ...inlineWithoutStyleRef };\n}\n\nfunction getCompactResponsiveStyle(\n node: TraversableNode,\n): Record<string, unknown> | undefined {\n const responsive = node.responsive;\n if (\n responsive == null ||\n typeof responsive !== 'object' ||\n Array.isArray(responsive)\n ) {\n return undefined;\n }\n\n const compact = (responsive as Record<string, unknown>).compact;\n if (\n compact == null ||\n typeof compact !== 'object' ||\n Array.isArray(compact)\n ) {\n return undefined;\n }\n\n return compact as Record<string, unknown>;\n}\n\nfunction stripResponsiveOnlyUnsupportedFields(\n style: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined {\n if (!style) return undefined;\n\n const {\n hoverStyle: _hoverStyle,\n transition: _transition,\n ...rest\n } = style;\n\n return rest;\n}\n\nexport function getEffectiveStyleForMode(\n node: TraversableNode,\n cardStyles: Record<string, Record<string, unknown>> | undefined,\n mode: ResponsiveMode,\n): Record<string, unknown> | undefined {\n const baseStyle = mergeNamedStyle(node.style, cardStyles);\n if (mode === 'default') {\n return baseStyle;\n }\n\n const compactStyle = stripResponsiveOnlyUnsupportedFields(\n mergeNamedStyle(getCompactResponsiveStyle(node), cardStyles),\n );\n\n if (!compactStyle) {\n return baseStyle;\n }\n\n return {\n ...(baseStyle ?? {}),\n ...compactStyle,\n };\n}\n\nexport function getMergedCompactResponsiveStyle(\n node: TraversableNode,\n cardStyles: Record<string, Record<string, unknown>> | undefined,\n): Record<string, unknown> | undefined {\n return mergeNamedStyle(getCompactResponsiveStyle(node), cardStyles);\n}\n","/**\n * @safe-ugc-ui/validator — Resource Limits Validation\n *\n * Validates resource limits per spec section 6.\n *\n * Uses a single traversal pass to collect all metrics (node count,\n * text content size, style object size, loop iterations, nested loops,\n * overflow:auto count, and stack nesting), then checks each against the\n * defined constants from @safe-ugc-ui/types.\n */\n\nimport {\n TEXT_CONTENT_TOTAL_MAX_BYTES,\n STYLE_OBJECTS_TOTAL_MAX_BYTES,\n MAX_NODE_COUNT,\n MAX_LOOP_ITERATIONS,\n MAX_NESTED_LOOPS,\n MAX_OVERFLOW_AUTO_COUNT,\n MAX_STACK_NESTING,\n PROTOTYPE_POLLUTION_SEGMENTS,\n} from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\nimport { type TraversableNode, type TraversalContext, traverseCard } from './traverse.js';\nimport {\n type ResponsiveMode,\n RESPONSIVE_MODES,\n getEffectiveStyleForMode,\n getMergedCompactResponsiveStyle,\n} from './responsive-utils.js';\n\n// ---------------------------------------------------------------------------\n// UTF-8 byte length — platform-agnostic (no DOM/Node dependency)\n// ---------------------------------------------------------------------------\n\n/**\n * Calculate UTF-8 byte length of a string without depending on\n * TextEncoder (DOM) or Buffer (Node).\n */\nfunction utf8ByteLength(str: string): number {\n let bytes = 0;\n for (let i = 0; i < str.length; i++) {\n const code = str.charCodeAt(i);\n if (code <= 0x7f) {\n bytes += 1;\n } else if (code <= 0x7ff) {\n bytes += 2;\n } else if (code >= 0xd800 && code <= 0xdbff) {\n // Surrogate pair → 4 UTF-8 bytes\n bytes += 4;\n i++; // skip low surrogate\n } else {\n bytes += 3;\n }\n }\n return bytes;\n}\n\nfunction isTemplateObject(\n value: unknown,\n): value is { $template: unknown[] } {\n return (\n typeof value === 'object' &&\n value !== null &&\n '$template' in value &&\n Array.isArray((value as Record<string, unknown>).$template)\n );\n}\n\nfunction countLiteralTemplatedStringBytes(value: unknown): number {\n if (typeof value === 'string') {\n return utf8ByteLength(value);\n }\n\n if (!isTemplateObject(value)) {\n return 0;\n }\n\n return value.$template.reduce((total: number, part): number => {\n if (typeof part === 'string') {\n return total + utf8ByteLength(part);\n }\n if (\n typeof part === 'number' ||\n typeof part === 'boolean' ||\n part === null\n ) {\n return total + utf8ByteLength(String(part));\n }\n return total;\n }, 0);\n}\n\nfunction countTextNodeLiteralBytes(node: Record<string, unknown>): number {\n if (Array.isArray(node.spans)) {\n return node.spans.reduce((total, span) => {\n if (\n span == null ||\n typeof span !== 'object' ||\n Array.isArray(span)\n ) {\n return total;\n }\n\n return total + countLiteralTemplatedStringBytes(\n (span as Record<string, unknown>).text,\n );\n }, 0);\n }\n\n return countLiteralTemplatedStringBytes(node.content);\n}\n\nfunction countTextSpanStyleBytes(node: Record<string, unknown>): number {\n if (!Array.isArray(node.spans)) {\n return 0;\n }\n\n return node.spans.reduce((total, span) => {\n if (\n span == null ||\n typeof span !== 'object' ||\n Array.isArray(span)\n ) {\n return total;\n }\n\n const style = (span as Record<string, unknown>).style;\n if (\n style == null ||\n typeof style !== 'object' ||\n Array.isArray(style)\n ) {\n return total;\n }\n\n return total + utf8ByteLength(JSON.stringify(style));\n }, 0);\n}\n\n// ---------------------------------------------------------------------------\n// Helper: resolveRefFromState — resolve dotted $ref paths against state\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a $ref path against a state object. Supports dotted paths and\n * bracket notation (e.g. \"$data.items[0].name\").\n *\n * @returns The resolved value, or `undefined` if resolution fails.\n */\nfunction resolveRefFromState(\n refPath: string,\n state: Record<string, unknown>,\n): unknown {\n // Strip leading $\n const path = refPath.startsWith('$') ? refPath.slice(1) : refPath;\n const dotSegments = path.split('.');\n\n // Flatten dot-segments into individual traversal keys,\n // expanding bracket notation (e.g. \"items[0][1]\" -> [\"items\", \"0\", \"1\"])\n const keys: string[] = [];\n for (const dotSeg of dotSegments) {\n const bracketPattern = /\\[(\\d+)\\]/g;\n const firstBracket = dotSeg.indexOf('[');\n const baseName = firstBracket === -1 ? dotSeg : dotSeg.slice(0, firstBracket);\n if (baseName) {\n keys.push(baseName);\n }\n let match: RegExpExecArray | null;\n while ((match = bracketPattern.exec(dotSeg)) !== null) {\n keys.push(match[1]);\n }\n }\n\n // Block prototype pollution\n for (const key of keys) {\n if (\n (PROTOTYPE_POLLUTION_SEGMENTS as readonly string[]).includes(key)\n ) {\n return undefined;\n }\n }\n\n // Traverse state\n let current: unknown = state;\n for (const key of keys) {\n if (current == null || typeof current !== 'object') return undefined;\n\n if (Array.isArray(current)) {\n const index = Number(key);\n if (!Number.isInteger(index) || index < 0) return undefined;\n current = current[index];\n } else {\n current = (current as Record<string, unknown>)[key];\n }\n }\n return current;\n}\n\n// ---------------------------------------------------------------------------\n// countTemplateMetrics — measure resource usage of a for-loop template\n// ---------------------------------------------------------------------------\n\ninterface TemplateMetrics {\n nodes: number;\n textBytes: number;\n styleBytes: number;\n overflowAutoCount: Record<ResponsiveMode, number>;\n}\n\n/**\n * Recursively count metrics for a for-loop template subtree.\n * Used to multiply metrics by (arrayLength - 1) since the traversal\n * already counts the template once.\n */\nfunction countTemplateMetrics(\n template: unknown,\n cardStyles?: Record<string, Record<string, unknown>>,\n fragments?: Record<string, unknown>,\n): TemplateMetrics {\n const result: TemplateMetrics = {\n nodes: 0,\n textBytes: 0,\n styleBytes: 0,\n overflowAutoCount: {\n default: 0,\n compact: 0,\n },\n };\n\n traverseCard(\n { __template: template },\n (node: TraversableNode) => {\n result.nodes += 1;\n\n if (node.type === 'Text') {\n result.textBytes += countTextNodeLiteralBytes(node as Record<string, unknown>);\n result.styleBytes += countTextSpanStyleBytes(node as Record<string, unknown>);\n }\n\n const baseStyleForBytes = getEffectiveStyleForMode(\n node,\n cardStyles,\n 'default',\n );\n if (baseStyleForBytes) {\n result.styleBytes += utf8ByteLength(JSON.stringify(baseStyleForBytes));\n }\n\n const compactStyleForBytes = getMergedCompactResponsiveStyle(\n node,\n cardStyles,\n );\n if (compactStyleForBytes) {\n result.styleBytes += utf8ByteLength(JSON.stringify(compactStyleForBytes));\n }\n\n for (const mode of RESPONSIVE_MODES) {\n const effectiveStyle = getEffectiveStyleForMode(node, cardStyles, mode);\n if (effectiveStyle?.overflow === 'auto') {\n result.overflowAutoCount[mode]++;\n }\n }\n },\n undefined,\n fragments,\n );\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// validateLimits\n// ---------------------------------------------------------------------------\n\n/**\n * Validate all resource limits defined in spec section 6.\n *\n * Performs a single traversal of the card tree, collecting metrics for:\n * - Total node count\n * - Total text content bytes (UTF-8)\n * - Total style object bytes (UTF-8, JSON-serialized)\n * - Loop iteration counts\n * - Nested loop depth\n * - overflow:auto element count\n * - Stack nesting depth\n *\n * @param card - A card object with optional `state` and required `views`.\n * @returns An array of validation errors (empty if all limits are satisfied).\n */\nexport function validateLimits(\n card: {\n state?: Record<string, unknown>;\n views: Record<string, unknown>;\n cardStyles?: Record<string, Record<string, unknown>>;\n fragments?: Record<string, unknown>;\n },\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n let nodeCount = 0;\n let textContentBytes = 0;\n let styleObjectsBytes = 0;\n const overflowAutoCount: Record<ResponsiveMode, number> = {\n default: 0,\n compact: 0,\n };\n\n traverseCard(card.views, (node: TraversableNode, context: TraversalContext) => {\n // -----------------------------------------------------------------------\n // 1. Node count\n // -----------------------------------------------------------------------\n nodeCount++;\n\n // -----------------------------------------------------------------------\n // 2. Text content total bytes\n // -----------------------------------------------------------------------\n if (node.type === 'Text') {\n textContentBytes += countTextNodeLiteralBytes(node as Record<string, unknown>);\n styleObjectsBytes += countTextSpanStyleBytes(node as Record<string, unknown>);\n }\n\n // -----------------------------------------------------------------------\n // 3. Style objects total bytes (use merged style if $style is present)\n // -----------------------------------------------------------------------\n {\n const baseStyleForBytes = getEffectiveStyleForMode(\n node,\n card.cardStyles,\n 'default',\n );\n if (baseStyleForBytes) {\n styleObjectsBytes += utf8ByteLength(JSON.stringify(baseStyleForBytes));\n }\n\n const compactStyleForBytes = getMergedCompactResponsiveStyle(\n node,\n card.cardStyles,\n );\n if (compactStyleForBytes) {\n styleObjectsBytes += utf8ByteLength(JSON.stringify(compactStyleForBytes));\n }\n }\n\n // -----------------------------------------------------------------------\n // 4. Loop iterations\n // -----------------------------------------------------------------------\n const children = node.children;\n if (\n children != null &&\n typeof children === 'object' &&\n !Array.isArray(children) &&\n 'for' in children &&\n 'in' in children &&\n 'template' in children\n ) {\n const forLoop = children as { for: string; in: string; template: unknown };\n const inValue = forLoop.in;\n\n if (typeof inValue === 'string' && inValue.startsWith('$')) {\n if (card.state == null) {\n // No state — loop source may be provided at runtime, skip validation\n } else {\n const source = resolveRefFromState(inValue, card.state);\n if (source === undefined) {\n // Single-segment path (e.g. \"$items\") at top-level (loopDepth 0)\n // must be a state key. If missing, likely a typo → report error.\n // Dotted paths or paths inside nested loops may reference\n // locals variables → skip.\n const pathAfterDollar = inValue.slice(1);\n if (!pathAfterDollar.includes('.') && context.loopDepth === 0) {\n errors.push(\n createError(\n 'LOOP_SOURCE_MISSING',\n `Loop source \"${inValue}\" not found in card state`,\n `${context.path}.children`,\n ),\n );\n }\n } else if (!Array.isArray(source)) {\n errors.push(\n createError(\n 'LOOP_SOURCE_NOT_ARRAY',\n `Loop source \"${inValue}\" is not an array`,\n `${context.path}.children`,\n ),\n );\n } else if (source.length > MAX_LOOP_ITERATIONS) {\n errors.push(\n createError(\n 'LOOP_ITERATIONS_EXCEEDED',\n `Loop source \"${inValue}\" has ${source.length} items, max is ${MAX_LOOP_ITERATIONS}`,\n `${context.path}.children`,\n ),\n );\n } else if (source.length > 1) {\n // Multiply template metrics by (N - 1) since traversal already\n // counts the template once\n const tplMetrics = countTemplateMetrics(forLoop.template, card.cardStyles, card.fragments);\n const multiplier = source.length - 1;\n nodeCount += tplMetrics.nodes * multiplier;\n textContentBytes += tplMetrics.textBytes * multiplier;\n styleObjectsBytes += tplMetrics.styleBytes * multiplier;\n for (const mode of RESPONSIVE_MODES) {\n overflowAutoCount[mode] += tplMetrics.overflowAutoCount[mode] * multiplier;\n }\n }\n }\n }\n\n // -------------------------------------------------------------------\n // 5. Nested loops\n // -------------------------------------------------------------------\n if (context.loopDepth >= MAX_NESTED_LOOPS) {\n errors.push(\n createError(\n 'NESTED_LOOPS_EXCEEDED',\n `Loop nesting depth ${context.loopDepth + 1} exceeds maximum of ${MAX_NESTED_LOOPS}`,\n `${context.path}.children`,\n ),\n );\n }\n }\n\n // -----------------------------------------------------------------------\n // 6. overflow: auto count (use merged style if $style is present)\n // -----------------------------------------------------------------------\n for (const mode of RESPONSIVE_MODES) {\n const effectiveStyle = getEffectiveStyleForMode(node, card.cardStyles, mode);\n if (effectiveStyle?.overflow === 'auto') {\n overflowAutoCount[mode]++;\n }\n }\n\n // -----------------------------------------------------------------------\n // 7. Stack nesting\n // -----------------------------------------------------------------------\n if (node.type === 'Stack' && context.stackDepth >= MAX_STACK_NESTING) {\n errors.push(\n createError(\n 'STACK_NESTING_EXCEEDED',\n `Stack nesting depth ${context.stackDepth + 1} exceeds maximum of ${MAX_STACK_NESTING}`,\n context.path,\n ),\n );\n }\n }, undefined, card.fragments);\n\n // -------------------------------------------------------------------------\n // Post-traversal aggregate checks\n // -------------------------------------------------------------------------\n\n if (nodeCount > MAX_NODE_COUNT) {\n errors.push(\n createError(\n 'NODE_COUNT_EXCEEDED',\n `Card has ${nodeCount} nodes, max is ${MAX_NODE_COUNT}`,\n 'views',\n ),\n );\n }\n\n if (textContentBytes > TEXT_CONTENT_TOTAL_MAX_BYTES) {\n errors.push(\n createError(\n 'TEXT_CONTENT_SIZE_EXCEEDED',\n `Total text content is ${textContentBytes} bytes, max is ${TEXT_CONTENT_TOTAL_MAX_BYTES}`,\n 'views',\n ),\n );\n }\n\n if (styleObjectsBytes > STYLE_OBJECTS_TOTAL_MAX_BYTES) {\n errors.push(\n createError(\n 'STYLE_SIZE_EXCEEDED',\n `Total style objects size is ${styleObjectsBytes} bytes, max is ${STYLE_OBJECTS_TOTAL_MAX_BYTES}`,\n 'views',\n ),\n );\n }\n\n const maxOverflowAutoCount = Math.max(\n overflowAutoCount.default,\n overflowAutoCount.compact,\n );\n\n if (maxOverflowAutoCount > MAX_OVERFLOW_AUTO_COUNT) {\n errors.push(\n createError(\n 'OVERFLOW_AUTO_COUNT_EXCEEDED',\n `Card has ${maxOverflowAutoCount} elements with overflow:auto in at least one responsive mode, max is ${MAX_OVERFLOW_AUTO_COUNT}`,\n 'views',\n ),\n );\n }\n\n return errors;\n}\n"],"mappings":"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","names":["isRef","isRef","isRef","_","isRef","PROTOTYPE_POLLUTION_SEGMENTS","resolveRefFromState","PROTOTYPE_POLLUTION_SEGMENTS","utf8ByteLength"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/result.ts","../src/schema.ts","../src/traverse.ts","../src/renderable-walk.ts","../src/fragment-validator.ts","../src/node-validator.ts","../src/condition-validator.ts","../src/value-types.ts","../src/style-validator.ts","../src/security.ts","../src/responsive-utils.ts","../src/limits.ts"],"sourcesContent":["/**\n * @safe-ugc-ui/validator — Public API\n *\n * Provides two entry points for card validation:\n *\n * validateRaw(rawJson: string) — Recommended for raw JSON strings.\n * Checks UTF-8 byte size BEFORE parsing. If too large, rejects without\n * parsing (DoS prevention). Returns ValidationResult.\n *\n * validate(input: unknown) — For already-parsed objects.\n * Skips size check. Returns ValidationResult.\n *\n * Pipeline:\n * 1. (validateRaw only) UTF-8 byte size check (1MB limit)\n * 2. (validateRaw only) JSON.parse — parse error → ValidationResult\n * 3. Schema validation → fail → early return\n * 4. All remaining checks run, errors accumulated:\n * node → value-types → style → security → limits\n */\n\nimport { CARD_JSON_MAX_BYTES } from '@safe-ugc-ui/types';\n\nimport {\n type ValidationError,\n type ValidationResult,\n createError,\n toResult,\n} from './result.js';\nimport { validateSchema } from './schema.js';\nimport { validateFragments } from './fragment-validator.js';\nimport { validateNodes } from './node-validator.js';\nimport { validateConditions } from './condition-validator.js';\nimport { validateValueTypes } from './value-types.js';\nimport { validateStyles } from './style-validator.js';\nimport { validateSecurity } from './security.js';\nimport { validateLimits } from './limits.js';\n\n// ---------------------------------------------------------------------------\n// Re-exports\n// ---------------------------------------------------------------------------\n\nexport {\n type ValidationError,\n type ValidationErrorCode,\n type ValidationResult,\n createError,\n validResult,\n invalidResult,\n toResult,\n merge,\n} from './result.js';\n\nexport {\n type StyleResolver,\n type TraversalContext,\n type TraversableNode,\n type NodeVisitor,\n traverseNode,\n traverseCard,\n} from './traverse.js';\n\nexport { validateSchema, parseCard } from './schema.js';\nexport { validateFragments } from './fragment-validator.js';\nexport { validateNodes } from './node-validator.js';\nexport { validateConditions } from './condition-validator.js';\nexport { validateValueTypes } from './value-types.js';\nexport { validateStyles } from './style-validator.js';\nexport { validateSecurity } from './security.js';\nexport { validateLimits } from './limits.js';\n\n// ---------------------------------------------------------------------------\n// UTF-8 byte length (platform-agnostic)\n// ---------------------------------------------------------------------------\n\nfunction utf8ByteLength(str: string): number {\n let bytes = 0;\n for (let i = 0; i < str.length; i++) {\n const code = str.charCodeAt(i);\n if (code <= 0x7f) {\n bytes += 1;\n } else if (code <= 0x7ff) {\n bytes += 2;\n } else if (code >= 0xd800 && code <= 0xdbff) {\n bytes += 4;\n i++;\n } else {\n bytes += 3;\n }\n }\n return bytes;\n}\n\n// ---------------------------------------------------------------------------\n// runAllChecks — shared pipeline (post-schema)\n// ---------------------------------------------------------------------------\n\nfunction runAllChecks(input: unknown): ValidationError[] {\n const obj = input as {\n views: Record<string, unknown>;\n state?: Record<string, unknown>;\n assets?: Record<string, string>;\n styles?: Record<string, Record<string, unknown>>;\n fragments?: Record<string, unknown>;\n };\n const views = obj.views as Record<string, unknown>;\n const cardStyles = obj.styles as Record<string, Record<string, unknown>> | undefined;\n const fragments = obj.fragments as Record<string, unknown> | undefined;\n const errors: ValidationError[] = [];\n\n errors.push(...validateFragments(views, fragments));\n errors.push(...validateNodes(views, fragments));\n errors.push(...validateConditions(views, fragments));\n errors.push(...validateValueTypes(views, fragments));\n errors.push(...validateStyles(views, cardStyles, fragments));\n errors.push(...validateSecurity({\n views,\n state: obj.state as Record<string, unknown> | undefined,\n cardAssets: obj.assets as Record<string, string> | undefined,\n cardStyles,\n fragments,\n }));\n errors.push(...validateLimits({\n state: obj.state as Record<string, unknown> | undefined,\n views,\n cardStyles,\n fragments,\n }));\n\n return errors;\n}\n\n// ---------------------------------------------------------------------------\n// validate — object input (already parsed)\n// ---------------------------------------------------------------------------\n\n/**\n * Validate an already-parsed card object.\n *\n * Skips the JSON byte size check (use `validateRaw` for raw strings).\n *\n * Pipeline:\n * 1. Schema validation → fail → early return\n * 2. All remaining checks (node, value-types, style, security, limits)\n *\n * @param input - An unknown value (typically parsed JSON).\n * @returns A ValidationResult — safe to render only if `valid` is true.\n */\nexport function validate(input: unknown): ValidationResult {\n // 1. Schema validation (early return on failure)\n const schemaResult = validateSchema(input);\n if (!schemaResult.valid) {\n return schemaResult;\n }\n\n // 2. All remaining checks\n const errors = runAllChecks(input);\n return toResult(errors);\n}\n\n// ---------------------------------------------------------------------------\n// validateRaw — string input (pre-parse size check)\n// ---------------------------------------------------------------------------\n\n/**\n * Validate a raw JSON string. Recommended entry point.\n *\n * Checks the byte size of the raw string BEFORE parsing to prevent\n * JSON parsing DoS with oversized payloads.\n *\n * Pipeline:\n * 1. UTF-8 byte size check (1MB max) → reject without parsing\n * 2. JSON.parse → parse error → ValidationResult (no throw)\n * 3. Schema validation → fail → early return\n * 4. All remaining checks\n *\n * @param rawJson - A raw JSON string representing a UGC card.\n * @returns A ValidationResult — safe to render only if `valid` is true.\n */\nexport function validateRaw(rawJson: string): ValidationResult {\n // 1. Pre-parse size check\n const byteSize = utf8ByteLength(rawJson);\n if (byteSize > CARD_JSON_MAX_BYTES) {\n return toResult([\n createError(\n 'CARD_SIZE_EXCEEDED',\n `Card JSON is ${byteSize} bytes, maximum is ${CARD_JSON_MAX_BYTES} bytes.`,\n '',\n ),\n ]);\n }\n\n // 2. Parse JSON\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawJson);\n } catch (e) {\n const message = e instanceof Error ? e.message : 'Invalid JSON';\n return toResult([\n createError('INVALID_JSON', `Failed to parse JSON: ${message}`, ''),\n ]);\n }\n\n // 3-4. Delegate to validate()\n return validate(parsed);\n}\n","/**\n * @safe-ugc-ui/validator — Validation Result Types\n *\n * Provides the error and result types used throughout the validation pipeline.\n *\n * Design decisions:\n * - Errors include a `path` for precise location in the card tree.\n * - Errors include a `code` for programmatic handling.\n * - `merge()` combines multiple results, accumulating all errors.\n * - A valid result is simply `{ valid: true, errors: [] }`.\n */\n\n// ---------------------------------------------------------------------------\n// Error codes\n// ---------------------------------------------------------------------------\n\n/**\n * Machine-readable error codes for every validation failure type.\n */\nexport type ValidationErrorCode =\n // Schema / structural\n | 'INVALID_JSON'\n | 'MISSING_FIELD'\n | 'INVALID_TYPE'\n | 'INVALID_VALUE'\n | 'UNKNOWN_NODE_TYPE'\n | 'SCHEMA_ERROR'\n // Value-type restrictions\n | 'REF_NOT_ALLOWED'\n | 'DYNAMIC_NOT_ALLOWED'\n // Style\n | 'FORBIDDEN_STYLE_PROPERTY'\n | 'STYLE_VALUE_OUT_OF_RANGE'\n | 'FORBIDDEN_CSS_FUNCTION'\n | 'INVALID_COLOR'\n | 'INVALID_LENGTH'\n | 'FORBIDDEN_OVERFLOW_VALUE'\n | 'TRANSFORM_SKEW_FORBIDDEN'\n // Security\n | 'EXTERNAL_URL'\n | 'POSITION_FIXED_FORBIDDEN'\n | 'POSITION_STICKY_FORBIDDEN'\n | 'POSITION_ABSOLUTE_NOT_IN_STACK'\n | 'ASSET_PATH_TRAVERSAL'\n | 'INVALID_ASSET_PATH'\n | 'PROTOTYPE_POLLUTION'\n // Limits\n | 'CARD_SIZE_EXCEEDED'\n | 'TEXT_CONTENT_SIZE_EXCEEDED'\n | 'STYLE_SIZE_EXCEEDED'\n | 'NODE_COUNT_EXCEEDED'\n | 'LOOP_ITERATIONS_EXCEEDED'\n | 'NESTED_LOOPS_EXCEEDED'\n | 'OVERFLOW_AUTO_COUNT_EXCEEDED'\n | 'OVERFLOW_AUTO_NESTED'\n | 'STACK_NESTING_EXCEEDED'\n // ForLoop\n | 'LOOP_SOURCE_NOT_ARRAY'\n | 'LOOP_SOURCE_MISSING'\n // $style references\n | 'STYLE_CIRCULAR_REF'\n | 'STYLE_REF_NOT_FOUND'\n | 'INVALID_STYLE_REF'\n | 'INVALID_STYLE_NAME'\n // Fragments\n | 'FRAGMENT_REF_NOT_FOUND'\n | 'FRAGMENT_NESTED_USE'\n | 'INVALID_FRAGMENT_NAME'\n // Hover / Transition\n | 'INVALID_HOVER_STYLE'\n | 'HOVER_STYLE_NESTED'\n | 'TRANSITION_RAW_STRING'\n | 'TRANSITION_COUNT_EXCEEDED'\n | 'TRANSITION_PROPERTY_FORBIDDEN'\n // Conditions\n | 'CONDITION_DEPTH_EXCEEDED';\n\n// ---------------------------------------------------------------------------\n// ValidationError\n// ---------------------------------------------------------------------------\n\n/**\n * A single validation error with location and diagnostic info.\n */\nexport interface ValidationError {\n /** Machine-readable error code. */\n code: ValidationErrorCode;\n\n /** Human-readable error message. */\n message: string;\n\n /**\n * JSON-pointer-like path to the error location.\n * e.g. `\"views.StatusWindow.children[0].style.zIndex\"`\n */\n path: string;\n}\n\n// ---------------------------------------------------------------------------\n// ValidationResult\n// ---------------------------------------------------------------------------\n\n/**\n * The result of running the validation pipeline.\n *\n * - `valid: true` → the card is safe to render.\n * - `valid: false` → the card has errors; do NOT render.\n */\nexport interface ValidationResult {\n valid: boolean;\n errors: ValidationError[];\n}\n\n// ---------------------------------------------------------------------------\n// Factory helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Create a single validation error.\n */\nexport function createError(\n code: ValidationErrorCode,\n message: string,\n path: string,\n): ValidationError {\n return { code, message, path };\n}\n\n/**\n * Create a valid result (no errors).\n */\nexport function validResult(): ValidationResult {\n return { valid: true, errors: [] };\n}\n\n/**\n * Create an invalid result from a list of errors.\n */\nexport function invalidResult(errors: ValidationError[]): ValidationResult {\n return { valid: false, errors };\n}\n\n/**\n * Wrap errors into a ValidationResult (valid if no errors).\n */\nexport function toResult(errors: ValidationError[]): ValidationResult {\n return {\n valid: errors.length === 0,\n errors,\n };\n}\n\n/**\n * Merge multiple validation results into one.\n * The merged result is valid only if ALL inputs are valid.\n */\nexport function merge(...results: ValidationResult[]): ValidationResult {\n const errors: ValidationError[] = [];\n for (const r of results) {\n errors.push(...r.errors);\n }\n return {\n valid: errors.length === 0,\n errors,\n };\n}\n","/**\n * @safe-ugc-ui/validator — Schema (Structural) Validation\n *\n * Verifies the top-level structure of a UGC card:\n * - Required fields: meta (name, version), views (at least one)\n * - Zod schema parse for the full card structure\n * - Maps Zod parse errors to ValidationError format\n *\n * This is the first step in the validation pipeline (after size check).\n * If structural validation fails, no further checks are performed.\n */\n\nimport { ugcCardSchema, type UGCCard } from '@safe-ugc-ui/types';\n\nimport {\n type ValidationError,\n type ValidationResult,\n createError,\n toResult,\n} from './result.js';\n\n// ---------------------------------------------------------------------------\n// validateSchema\n// ---------------------------------------------------------------------------\n\n/**\n * Validate the structural shape of a card using the Zod schema.\n *\n * @param input - An unknown value (already parsed from JSON).\n * @returns A ValidationResult. If valid, the parsed UGCCard can be accessed\n * from the Zod result; callers should re-parse if they need the typed object.\n */\nexport function validateSchema(input: unknown): ValidationResult {\n const errors: ValidationError[] = [];\n\n // Quick structural pre-checks for better error messages\n if (typeof input !== 'object' || input === null || Array.isArray(input)) {\n errors.push(\n createError('SCHEMA_ERROR', 'Card must be a plain object.', ''),\n );\n return toResult(errors);\n }\n\n const obj = input as Record<string, unknown>;\n\n // Check required top-level fields before full Zod parse\n if (!obj.meta) {\n errors.push(\n createError('MISSING_FIELD', 'Card is missing required field \"meta\".', 'meta'),\n );\n }\n if (!obj.views) {\n errors.push(\n createError('MISSING_FIELD', 'Card is missing required field \"views\".', 'views'),\n );\n }\n\n // If critical fields are missing, return early\n if (errors.length > 0) {\n return toResult(errors);\n }\n\n // Check meta structure\n if (typeof obj.meta !== 'object' || obj.meta === null) {\n errors.push(\n createError('INVALID_TYPE', '\"meta\" must be an object.', 'meta'),\n );\n return toResult(errors);\n }\n\n const meta = obj.meta as Record<string, unknown>;\n if (typeof meta.name !== 'string') {\n errors.push(\n createError('MISSING_FIELD', '\"meta.name\" is required and must be a string.', 'meta.name'),\n );\n }\n if (typeof meta.version !== 'string') {\n errors.push(\n createError('MISSING_FIELD', '\"meta.version\" is required and must be a string.', 'meta.version'),\n );\n }\n\n // Check views structure\n if (typeof obj.views !== 'object' || obj.views === null || Array.isArray(obj.views)) {\n errors.push(\n createError('INVALID_TYPE', '\"views\" must be an object.', 'views'),\n );\n return toResult(errors);\n }\n\n const views = obj.views as Record<string, unknown>;\n if (Object.keys(views).length === 0) {\n errors.push(\n createError('MISSING_FIELD', '\"views\" must contain at least one view.', 'views'),\n );\n }\n\n // If pre-checks found issues, return them\n if (errors.length > 0) {\n return toResult(errors);\n }\n\n // Full Zod parse\n const result = ugcCardSchema.safeParse(input);\n\n if (!result.success) {\n for (const issue of result.error.issues) {\n const path = issue.path.join('.');\n errors.push(\n createError('SCHEMA_ERROR', issue.message, path),\n );\n }\n }\n\n return toResult(errors);\n}\n\n/**\n * Parse a card from an unknown input, returning either the typed UGCCard\n * or null if structural validation fails.\n *\n * Callers should first run `validateSchema()` to get user-facing errors.\n * This is a convenience for subsequent pipeline stages that need the typed card.\n */\nexport function parseCard(input: unknown): UGCCard | null {\n const result = ugcCardSchema.safeParse(input);\n return result.success ? result.data : null;\n}\n","/**\n * @safe-ugc-ui/validator — Tree Traversal\n *\n * Provides utilities for walking the UGC card tree, tracking:\n * - path: JSON-pointer-like location string\n * - depth: nesting level\n * - parentType: the type of the parent node (for position/overflow rules)\n * - loopDepth: nesting level of for-loops\n * - overflowAutoAncestor: whether an ancestor has overflow:auto\n * - stackDepth: nesting level of Stack components\n *\n * The traversal is generic: it calls a visitor function on each node,\n * allowing different validators to collect different data.\n */\n\n// ---------------------------------------------------------------------------\n// Context passed to visitor callbacks\n// ---------------------------------------------------------------------------\n\n/**\n * Contextual information available at each node during traversal.\n */\nexport interface TraversalContext {\n /** JSON-pointer-like path, e.g. \"views.Main.children[0].children[1]\" */\n path: string;\n\n /** Nesting depth (root node = 0). */\n depth: number;\n\n /** The `type` of the immediate parent node, or null for root-level nodes. */\n parentType: string | null;\n\n /** Current for-loop nesting depth (0 = no loop). */\n loopDepth: number;\n\n /** True if any ancestor has `overflow: auto` in its style. */\n overflowAutoAncestor: boolean;\n\n /** Current Stack nesting depth (0 = not inside a Stack). */\n stackDepth: number;\n}\n\n// ---------------------------------------------------------------------------\n// Node shape (loose — validated elsewhere)\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal shape expected for a node during traversal.\n * We use a loose type because traversal runs after schema validation,\n * but the node might have extra or unexpected fields.\n */\nexport interface TraversableNode {\n type: string;\n children?: TraversableRenderable[] | ForLoopLike;\n style?: Record<string, unknown>;\n responsive?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nexport interface FragmentUseLike {\n $use: string;\n $if?: unknown;\n [key: string]: unknown;\n}\n\nexport type TraversableRenderable = TraversableNode | FragmentUseLike;\n\nexport interface EmbeddedRenderableEntry {\n pathSuffix: string;\n renderable: TraversableRenderable;\n}\n\ninterface ForLoopLike {\n for: string;\n in: string;\n template: TraversableRenderable;\n}\n\n// ---------------------------------------------------------------------------\n// Visitor\n// ---------------------------------------------------------------------------\n\n/**\n * A visitor function called for every node in the tree.\n * Return `false` to skip traversing into this node's children.\n */\nexport type NodeVisitor = (\n node: TraversableNode,\n context: TraversalContext,\n) => void | false;\n\nexport type StyleResolver = (\n node: TraversableNode,\n) => Record<string, unknown> | undefined;\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction isForLoop(\n children: unknown,\n): children is ForLoopLike {\n return (\n typeof children === 'object' &&\n children !== null &&\n 'for' in children &&\n 'in' in children &&\n 'template' in children\n );\n}\n\nexport function isTraversableNode(value: unknown): value is TraversableNode {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n typeof (value as Record<string, unknown>).type === 'string'\n );\n}\n\nexport function isFragmentUseLike(value: unknown): value is FragmentUseLike {\n return (\n typeof value === 'object' &&\n value !== null &&\n '$use' in value &&\n typeof (value as Record<string, unknown>).$use === 'string'\n );\n}\n\nexport function getEmbeddedRenderables(\n node: TraversableNode,\n): EmbeddedRenderableEntry[] {\n const entries: EmbeddedRenderableEntry[] = [];\n\n const interactiveField =\n node.type === 'Accordion'\n ? 'items'\n : node.type === 'Tabs'\n ? 'tabs'\n : null;\n\n if (interactiveField) {\n const items = (node as Record<string, unknown>)[interactiveField];\n if (!Array.isArray(items)) {\n return entries;\n }\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n if (\n item == null ||\n typeof item !== 'object' ||\n Array.isArray(item)\n ) {\n continue;\n }\n\n const content = (item as Record<string, unknown>).content;\n if (isTraversableNode(content) || isFragmentUseLike(content)) {\n entries.push({\n pathSuffix: `${interactiveField}[${i}].content`,\n renderable: content,\n });\n }\n }\n }\n\n return entries;\n}\n\nfunction resolveRenderableNode(\n node: TraversableRenderable,\n fragments?: Record<string, unknown>,\n fragmentStack: string[] = [],\n): TraversableNode | null {\n if (isTraversableNode(node)) {\n return node;\n }\n\n if (!isFragmentUseLike(node) || !fragments) {\n return null;\n }\n\n // Fragment definitions are validated separately and may not nest `$use`.\n // Skip expansion here so invalid cards cannot recurse indefinitely.\n if (fragmentStack.length > 0 || fragmentStack.includes(node.$use)) {\n return null;\n }\n\n const target = fragments[node.$use];\n return isTraversableNode(target) ? target : null;\n}\n\nfunction hasOverflowAuto(style: Record<string, unknown> | undefined): boolean {\n return style?.overflow === 'auto';\n}\n\n// ---------------------------------------------------------------------------\n// traverseNode\n// ---------------------------------------------------------------------------\n\n/**\n * Recursively traverse a single node and its descendants.\n */\nexport function traverseNode(\n node: TraversableRenderable,\n context: TraversalContext,\n visitor: NodeVisitor,\n styleResolver?: StyleResolver,\n fragments?: Record<string, unknown>,\n fragmentStack: string[] = [],\n): void {\n const resolvedNode = resolveRenderableNode(node, fragments, fragmentStack);\n if (!resolvedNode) {\n return;\n }\n\n const nextFragmentStack =\n isFragmentUseLike(node) ? [...fragmentStack, node.$use] : fragmentStack;\n\n const result = visitor(resolvedNode, context);\n\n // If visitor returns false, skip children.\n if (result === false) {\n return;\n }\n\n const nextStackDepth =\n resolvedNode.type === 'Stack' ? context.stackDepth + 1 : context.stackDepth;\n const nextOverflowAuto =\n context.overflowAutoAncestor || hasOverflowAuto(styleResolver ? styleResolver(resolvedNode) : resolvedNode.style);\n\n const children = resolvedNode.children;\n if (children != null) {\n if (isForLoop(children)) {\n // ForLoop: traverse the template node\n const childCtx: TraversalContext = {\n path: `${context.path}.children.template`,\n depth: context.depth + 1,\n parentType: resolvedNode.type,\n loopDepth: context.loopDepth + 1,\n overflowAutoAncestor: nextOverflowAuto,\n stackDepth: nextStackDepth,\n };\n traverseNode(children.template, childCtx, visitor, styleResolver, fragments, nextFragmentStack);\n } else if (Array.isArray(children)) {\n // Array of child nodes\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (isTraversableNode(child) || isFragmentUseLike(child)) {\n const childCtx: TraversalContext = {\n path: `${context.path}.children[${i}]`,\n depth: context.depth + 1,\n parentType: resolvedNode.type,\n loopDepth: context.loopDepth,\n overflowAutoAncestor: nextOverflowAuto,\n stackDepth: nextStackDepth,\n };\n traverseNode(child, childCtx, visitor, styleResolver, fragments, nextFragmentStack);\n }\n }\n }\n }\n\n for (const entry of getEmbeddedRenderables(resolvedNode)) {\n const embeddedCtx: TraversalContext = {\n path: `${context.path}.${entry.pathSuffix}`,\n depth: context.depth + 1,\n parentType: resolvedNode.type,\n loopDepth: context.loopDepth,\n overflowAutoAncestor: nextOverflowAuto,\n stackDepth: nextStackDepth,\n };\n traverseNode(\n entry.renderable,\n embeddedCtx,\n visitor,\n styleResolver,\n fragments,\n nextFragmentStack,\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// traverseCard\n// ---------------------------------------------------------------------------\n\n/**\n * Traverse all nodes in every view of a card.\n *\n * @param views - The `views` object from a UGCCard (mapping view names to root nodes).\n * @param visitor - Called for every node in every view.\n */\nexport function traverseCard(\n views: Record<string, unknown>,\n visitor: NodeVisitor,\n styleResolver?: StyleResolver,\n fragments?: Record<string, unknown>,\n pathPrefix: string = 'views',\n): void {\n for (const [viewName, rootNode] of Object.entries(views)) {\n if (!isTraversableNode(rootNode) && !isFragmentUseLike(rootNode)) {\n continue;\n }\n\n const context: TraversalContext = {\n path: `${pathPrefix}.${viewName}`,\n depth: 0,\n parentType: null,\n loopDepth: 0,\n overflowAutoAncestor: false,\n stackDepth: 0,\n };\n\n traverseNode(rootNode, context, visitor, styleResolver, fragments);\n }\n}\n","/**\n * @safe-ugc-ui/validator — Raw Renderable Tree Walk\n *\n * Walks card trees before fragment expansion so validators can inspect\n * `$use` wrappers and fragment definitions directly.\n */\n\nimport {\n getEmbeddedRenderables,\n isFragmentUseLike,\n isTraversableNode,\n} from './traverse.js';\n\nexport interface RenderableWalkContext {\n path: string;\n inFragments: boolean;\n}\n\ntype RenderableWalker = (\n node: Record<string, unknown>,\n context: RenderableWalkContext,\n) => void;\n\nfunction isForLoopLike(value: unknown): value is { template: unknown } {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'for' in value &&\n 'in' in value &&\n 'template' in value\n );\n}\n\nfunction walkRenderableNode(\n node: Record<string, unknown>,\n path: string,\n inFragments: boolean,\n visitor: RenderableWalker,\n): void {\n visitor(node, { path, inFragments });\n\n if (!isTraversableNode(node)) {\n return;\n }\n\n const children = node.children;\n if (Array.isArray(children)) {\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!isTraversableNode(child) && !isFragmentUseLike(child)) {\n continue;\n }\n walkRenderableNode(\n child as Record<string, unknown>,\n `${path}.children[${i}]`,\n inFragments,\n visitor,\n );\n }\n }\n\n if (isForLoopLike(children)) {\n const template = children.template;\n if (isTraversableNode(template) || isFragmentUseLike(template)) {\n walkRenderableNode(\n template as Record<string, unknown>,\n `${path}.children.template`,\n inFragments,\n visitor,\n );\n }\n }\n\n for (const entry of getEmbeddedRenderables(node)) {\n walkRenderableNode(\n entry.renderable as Record<string, unknown>,\n `${path}.${entry.pathSuffix}`,\n inFragments,\n visitor,\n );\n }\n}\n\nexport function walkRenderableCard(\n views: Record<string, unknown>,\n fragments: Record<string, unknown> | undefined,\n visitor: RenderableWalker,\n): void {\n for (const [viewName, rootNode] of Object.entries(views)) {\n if (!isTraversableNode(rootNode) && !isFragmentUseLike(rootNode)) {\n continue;\n }\n\n walkRenderableNode(\n rootNode as Record<string, unknown>,\n `views.${viewName}`,\n false,\n visitor,\n );\n }\n\n if (!fragments) {\n return;\n }\n\n for (const [fragmentName, fragmentRoot] of Object.entries(fragments)) {\n if (!isTraversableNode(fragmentRoot) && !isFragmentUseLike(fragmentRoot)) {\n continue;\n }\n\n walkRenderableNode(\n fragmentRoot as Record<string, unknown>,\n `fragments.${fragmentName}`,\n true,\n visitor,\n );\n }\n}\n","/**\n * @safe-ugc-ui/validator — Fragment Validator\n *\n * Validates fragment references and the non-recursive fragment rules for v0.9.\n */\n\nimport { createError, type ValidationError } from './result.js';\nimport { walkRenderableCard } from './renderable-walk.js';\nimport { isFragmentUseLike } from './traverse.js';\n\nconst FRAGMENT_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*$/;\n\nexport function validateFragments(\n views: Record<string, unknown>,\n fragments?: Record<string, unknown>,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n if (fragments) {\n for (const fragmentName of Object.keys(fragments)) {\n if (!FRAGMENT_NAME_PATTERN.test(fragmentName)) {\n errors.push(\n createError(\n 'INVALID_FRAGMENT_NAME',\n `Fragment name \"${fragmentName}\" is invalid; must match /^[A-Za-z][A-Za-z0-9_-]*$/.`,\n `fragments.${fragmentName}`,\n ),\n );\n }\n }\n }\n\n walkRenderableCard(views, fragments, (node, context) => {\n if (!isFragmentUseLike(node)) {\n return;\n }\n\n if (context.inFragments) {\n errors.push(\n createError(\n 'FRAGMENT_NESTED_USE',\n `Fragments may not contain \"$use\" references. Found at \"${context.path}\".`,\n context.path,\n ),\n );\n return;\n }\n\n if (!fragments || !(node.$use in fragments)) {\n errors.push(\n createError(\n 'FRAGMENT_REF_NOT_FOUND',\n `Fragment \"${node.$use}\" was not found.`,\n context.path,\n ),\n );\n }\n });\n\n return errors;\n}\n","/**\n * @safe-ugc-ui/validator — Node Validator\n *\n * Validates component type-specific requirements for each node in the card tree.\n *\n * For every node encountered during traversal:\n * 1. Rejects unknown node types not in ALL_COMPONENT_TYPES.\n * 2. Checks that required fields exist for each component type.\n * 4. Validates ForLoop structure when children use `for`/`in`/`template`.\n */\n\nimport { ALL_COMPONENT_TYPES, MAX_INTERACTIVE_ITEMS } from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\nimport { walkRenderableCard } from './renderable-walk.js';\nimport { isFragmentUseLike, type TraversableNode, type TraversalContext } from './traverse.js';\n\n// ---------------------------------------------------------------------------\n// Required fields per component type\n// ---------------------------------------------------------------------------\n\n/**\n * Mapping from component type to the list of required field names.\n * Layout nodes (Box, Row, Column, Stack, Grid) and structural nodes\n * (Divider, Spacer) have no required fields.\n */\nconst REQUIRED_FIELDS: Record<string, string[]> = {\n Image: ['src'],\n ProgressBar: ['value', 'max'],\n Avatar: ['src'],\n Icon: ['name'],\n Badge: ['label'],\n Chip: ['label'],\n Button: ['label', 'action'],\n Toggle: ['value', 'onToggle'],\n Accordion: ['items'],\n Tabs: ['tabs'],\n};\n\n// ---------------------------------------------------------------------------\n// Set of known component types for fast lookup\n// ---------------------------------------------------------------------------\n\nconst KNOWN_TYPES: ReadonlySet<string> = new Set(ALL_COMPONENT_TYPES);\n\n// ---------------------------------------------------------------------------\n// ForLoop validation helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Returns true if the given value looks like a ForLoop structure\n * (has `for`, `in`, and `template` properties).\n */\nfunction looksLikeForLoop(value: unknown): boolean {\n return (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n 'for' in value &&\n 'in' in value &&\n 'template' in value\n );\n}\n\n/**\n * Validate the structural integrity of a ForLoop children object.\n */\nfunction validateForLoop(\n children: Record<string, unknown>,\n path: string,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n // `for` must be a string\n if (typeof children['for'] !== 'string') {\n errors.push(\n createError(\n 'INVALID_VALUE',\n 'ForLoop \"for\" must be a string.',\n `${path}.children.for`,\n ),\n );\n }\n\n // `in` must be a string starting with `$`\n const inValue = children['in'];\n if (typeof inValue !== 'string' || !inValue.startsWith('$')) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n 'ForLoop \"in\" must be a string starting with \"$\".',\n `${path}.children.in`,\n ),\n );\n }\n\n // `template` must be an object with a `type` property\n const template = children['template'];\n if (\n typeof template !== 'object' ||\n template === null ||\n (!('type' in template) && !isFragmentUseLike(template))\n ) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n 'ForLoop \"template\" must be an object with a \"type\" property or \"$use\" reference.',\n `${path}.children.template`,\n ),\n );\n }\n\n return errors;\n}\n\nfunction collectUniqueInteractiveItemIds(\n items: unknown[],\n nodeType: 'Accordion' | 'Tabs',\n path: string,\n errors: ValidationError[],\n): Set<string> {\n const itemIds = new Set<string>();\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n if (\n item == null ||\n typeof item !== 'object' ||\n Array.isArray(item)\n ) {\n continue;\n }\n\n const itemId = (item as Record<string, unknown>).id;\n if (typeof itemId !== 'string' || itemId.length === 0) {\n continue;\n }\n\n if (itemIds.has(itemId)) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n `\"${nodeType}\" item ids must be unique. Duplicate id \"${itemId}\".`,\n `${path}[${i}].id`,\n ),\n );\n continue;\n }\n\n itemIds.add(itemId);\n }\n\n return itemIds;\n}\n\n// ---------------------------------------------------------------------------\n// Per-node validation\n// ---------------------------------------------------------------------------\n\n/**\n * Validate a single node's type and required fields.\n */\nfunction validateNode(\n node: TraversableNode,\n context: TraversalContext,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n const { path } = context;\n\n // 1. Unknown node type\n if (!KNOWN_TYPES.has(node.type)) {\n errors.push(\n createError(\n 'UNKNOWN_NODE_TYPE',\n `Unknown node type \"${node.type}\".`,\n path,\n ),\n );\n // Cannot validate fields for an unknown type; return early.\n return errors;\n }\n\n // 2. Required field validation\n if (node.type === 'Text') {\n const hasContent = 'content' in node && (node as Record<string, unknown>).content !== undefined;\n const hasSpans = 'spans' in node && (node as Record<string, unknown>).spans !== undefined;\n\n if (!hasContent && !hasSpans) {\n errors.push(\n createError(\n 'MISSING_FIELD',\n '\"Text\" node must define either \"content\" or \"spans\".',\n `${path}.content`,\n ),\n );\n }\n\n if (hasContent && hasSpans) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n '\"Text\" node cannot define both \"content\" and \"spans\".',\n path,\n ),\n );\n }\n }\n\n const requiredFields = REQUIRED_FIELDS[node.type];\n if (requiredFields && requiredFields.length > 0) {\n // Check each required field on the node itself (v2 flattening).\n for (const field of requiredFields) {\n if (!(field in node) || (node as Record<string, unknown>)[field] === undefined) {\n errors.push(\n createError(\n 'MISSING_FIELD',\n `\"${node.type}\" node is missing required field \"${field}\".`,\n `${path}.${field}`,\n ),\n );\n }\n }\n }\n\n // 4. ForLoop structure validation\n if (node.children != null && looksLikeForLoop(node.children)) {\n errors.push(\n ...validateForLoop(\n node.children as unknown as Record<string, unknown>,\n path,\n ),\n );\n }\n\n if (node.type === 'Accordion') {\n const items = Array.isArray(node.items) ? node.items : undefined;\n if (items) {\n if (items.length > MAX_INTERACTIVE_ITEMS) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n `\"Accordion\" node may define at most ${MAX_INTERACTIVE_ITEMS} items.`,\n `${path}.items`,\n ),\n );\n }\n\n const itemIds = collectUniqueInteractiveItemIds(\n items,\n 'Accordion',\n `${path}.items`,\n errors,\n );\n\n if (Array.isArray(node.defaultExpanded)) {\n if (node.allowMultiple !== true && node.defaultExpanded.length > 1) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n '\"Accordion\" cannot define multiple defaultExpanded ids unless \"allowMultiple\" is true.',\n `${path}.defaultExpanded`,\n ),\n );\n }\n\n for (let i = 0; i < node.defaultExpanded.length; i++) {\n const itemId = node.defaultExpanded[i];\n if (typeof itemId !== 'string' || !itemIds.has(itemId)) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n `\"Accordion\" defaultExpanded id \"${String(itemId)}\" was not found in items.`,\n `${path}.defaultExpanded[${i}]`,\n ),\n );\n }\n }\n }\n }\n }\n\n if (node.type === 'Tabs') {\n const tabs = Array.isArray(node.tabs) ? node.tabs : undefined;\n if (tabs) {\n if (tabs.length > MAX_INTERACTIVE_ITEMS) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n `\"Tabs\" node may define at most ${MAX_INTERACTIVE_ITEMS} tabs.`,\n `${path}.tabs`,\n ),\n );\n }\n\n const tabIds = collectUniqueInteractiveItemIds(\n tabs,\n 'Tabs',\n `${path}.tabs`,\n errors,\n );\n\n if ('defaultTab' in node) {\n const defaultTab = (node as Record<string, unknown>).defaultTab;\n if (typeof defaultTab !== 'string' || !tabIds.has(defaultTab)) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n `\"Tabs\" defaultTab \"${String(defaultTab)}\" was not found in tabs.`,\n `${path}.defaultTab`,\n ),\n );\n }\n }\n }\n }\n\n return errors;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Validate all nodes in every view of a card.\n *\n * Uses `traverseCard()` to visit every node and checks:\n * - Node type is a known component type.\n * - Required fields are present for the given component type.\n * - ForLoop children have valid `for`, `in`, and `template` fields.\n *\n * @param views - The `views` object from a UGCCard.\n * @returns An array of validation errors (empty if all nodes are valid).\n */\nexport function validateNodes(\n views: Record<string, unknown>,\n fragments?: Record<string, unknown>,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n walkRenderableCard(views, fragments, (node, context) => {\n if (!('type' in node) || typeof node.type !== 'string') {\n return;\n }\n\n errors.push(\n ...validateNode(\n node as TraversableNode,\n {\n path: context.path,\n depth: 0,\n parentType: null,\n loopDepth: 0,\n overflowAutoAncestor: false,\n stackDepth: 0,\n } satisfies TraversalContext,\n ),\n );\n });\n\n return errors;\n}\n","/**\n * @safe-ugc-ui/validator — Condition Validator\n *\n * Validates node-level `$if` conditions that are structurally accepted by the\n * schema but still need semantic guardrails such as maximum nesting depth.\n */\n\nimport { MAX_CONDITION_DEPTH, isRef } from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\nimport { walkRenderableCard } from './renderable-walk.js';\n\nfunction validateConditionDepth(\n condition: unknown,\n path: string,\n errors: ValidationError[],\n depth: number = 1,\n): void {\n if (depth > MAX_CONDITION_DEPTH) {\n errors.push(\n createError(\n 'CONDITION_DEPTH_EXCEEDED',\n `$if condition exceeds maximum depth of ${MAX_CONDITION_DEPTH} at \"${path}\"`,\n path,\n ),\n );\n return;\n }\n\n if (typeof condition === 'boolean' || isRef(condition)) {\n return;\n }\n\n if (typeof condition !== 'object' || condition === null || Array.isArray(condition)) {\n return;\n }\n\n const conditionObj = condition as Record<string, unknown>;\n const op = conditionObj.op;\n if (op === 'not') {\n validateConditionDepth(conditionObj.value, `${path}.value`, errors, depth + 1);\n return;\n }\n\n if ((op === 'and' || op === 'or') && Array.isArray(conditionObj.values)) {\n for (let i = 0; i < conditionObj.values.length; i++) {\n validateConditionDepth(\n conditionObj.values[i],\n `${path}.values[${i}]`,\n errors,\n depth + 1,\n );\n }\n }\n}\n\nexport function validateConditions(\n views: Record<string, unknown>,\n fragments?: Record<string, unknown>,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n walkRenderableCard(views, fragments, (node, ctx) => {\n if ('$if' in node) {\n validateConditionDepth(node.$if, `${ctx.path}.$if`, errors);\n }\n });\n\n return errors;\n}\n","/**\n * @safe-ugc-ui/validator — Value Type Validation\n *\n * Validates per-property $ref permission rules based on spec\n * section 4.5 value type table.\n *\n * | Property Type | Literal | $ref |\n * |-------------------|---------|------|\n * | Image.src | yes | yes |\n * | Avatar.src | yes | yes |\n * | Icon.name | yes | yes |\n * | Text.content | yes | yes |\n * | Color properties | yes | yes |\n * | Size properties | yes | yes |\n * | position | yes | no |\n * | overflow | yes | no |\n * | zIndex | yes | no |\n * | structured style objects | object literal | top-level $ref no |\n *\n * Structured style objects such as border/transform/boxShadow/textShadow/backgroundGradient\n * must remain object literals, but selected leaf fields inside them may use $ref.\n */\n\nimport { type ValidationError, createError } from './result.js';\nimport { walkRenderableCard } from './renderable-walk.js';\n\n// ---------------------------------------------------------------------------\n// Style properties that must always be static (no $ref)\n// ---------------------------------------------------------------------------\n\n/**\n * Style properties where any dynamic binding ($ref) is forbidden.\n * These use the `DYNAMIC_NOT_ALLOWED` error code.\n */\nconst STATIC_ONLY_STYLE_PROPERTIES: ReadonlySet<string> = new Set([\n // Position / layout\n 'position',\n 'top',\n 'right',\n 'bottom',\n 'left',\n\n // Overflow\n 'overflow',\n\n // Stacking\n 'zIndex',\n]);\n\nconst STRUCTURED_OBJECT_STYLE_PROPERTIES: ReadonlySet<string> = new Set([\n // Transform\n 'transform',\n\n // Gradient\n 'backgroundGradient',\n\n // Borders\n 'border',\n 'borderTop',\n 'borderRight',\n 'borderBottom',\n 'borderLeft',\n\n // Shadow\n 'boxShadow',\n 'textShadow',\n 'clipPath',\n]);\n\nconst RESPONSIVE_OVERRIDE_KEYS = ['medium', 'compact'] as const;\n\n/**\n * Validate the `style` of a node according to the value type table.\n */\nfunction validateNodeStyle(\n style: Record<string, unknown> | undefined,\n path: string,\n errors: ValidationError[],\n): void {\n if (!style) {\n return;\n }\n\n for (const [prop, value] of Object.entries(style)) {\n if (value === undefined) {\n continue;\n }\n\n if (\n typeof value === 'object' &&\n value !== null &&\n '$ref' in value &&\n typeof (value as Record<string, unknown>).$ref === 'string'\n ) {\n if (STATIC_ONLY_STYLE_PROPERTIES.has(prop)) {\n errors.push(\n createError(\n 'DYNAMIC_NOT_ALLOWED',\n `Style property \"${prop}\" must be a static literal; $ref is not allowed.`,\n `${path}.${prop}`,\n ),\n );\n }\n\n if (STRUCTURED_OBJECT_STYLE_PROPERTIES.has(prop)) {\n errors.push(\n createError(\n 'DYNAMIC_NOT_ALLOWED',\n `Style property \"${prop}\" must be an object literal; use $ref only inside its nested fields.`,\n `${path}.${prop}`,\n ),\n );\n }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Walk all nodes in the card and validate that each field's value\n * respects its allowed value types ($ref permissions).\n *\n * @param views - The `views` object from a UGCCard.\n * @returns An array of validation errors (empty if all values are valid).\n */\nexport function validateValueTypes(\n views: Record<string, unknown>,\n fragments?: Record<string, unknown>,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n walkRenderableCard(views, fragments, (node, ctx) => {\n if (!('type' in node) || typeof node.type !== 'string') {\n return;\n }\n\n const style =\n node.style != null &&\n typeof node.style === 'object' &&\n !Array.isArray(node.style)\n ? node.style as Record<string, unknown>\n : undefined;\n validateNodeStyle(style, `${ctx.path}.style`, errors);\n\n const responsive = node.responsive;\n if (\n responsive != null &&\n typeof responsive === 'object' &&\n !Array.isArray(responsive)\n ) {\n for (const mode of RESPONSIVE_OVERRIDE_KEYS) {\n const override = (responsive as Record<string, unknown>)[mode];\n if (\n override != null &&\n typeof override === 'object' &&\n !Array.isArray(override)\n ) {\n validateNodeStyle(\n override as Record<string, unknown>,\n `${ctx.path}.responsive.${mode}`,\n errors,\n );\n }\n }\n }\n });\n\n return errors;\n}\n","/**\n * @safe-ugc-ui/validator — Style Validator\n *\n * Validates style properties according to the spec's style restrictions:\n * - Forbidden CSS properties (spec 3.8)\n * - Numeric range limits (spec 6.4)\n * - Text-shadow count and value limits\n * - Box-shadow count and value limits\n * - Transform skew prohibition\n * - Dangerous CSS function injection detection\n * - Overflow: scroll prohibition (defense-in-depth)\n * - Color format validation\n * - Length format validation\n */\n\nimport {\n ASPECT_RATIO_PATTERN,\n FORBIDDEN_STYLE_PROPERTIES,\n DANGEROUS_CSS_FUNCTIONS,\n ZINDEX_MIN,\n ZINDEX_MAX,\n TRANSFORM_SCALE_MIN,\n TRANSFORM_SCALE_MAX,\n TRANSFORM_TRANSLATE_MIN,\n TRANSFORM_TRANSLATE_MAX,\n FONT_SIZE_MIN,\n FONT_SIZE_MAX,\n TEXT_SHADOW_MAX_COUNT,\n TEXT_SHADOW_BLUR_MAX,\n BOX_SHADOW_MAX_COUNT,\n BOX_SHADOW_BLUR_MAX,\n BOX_SHADOW_SPREAD_MAX,\n BORDER_RADIUS_MAX,\n LETTER_SPACING_MIN,\n LETTER_SPACING_MAX,\n OPACITY_MIN,\n OPACITY_MAX,\n BACKDROP_BLUR_MAX,\n CSS_NAMED_COLORS,\n TRANSITION_DURATION_MAX,\n TRANSITION_DELAY_MAX,\n TRANSITION_MAX_COUNT,\n ALLOWED_TRANSITION_PROPERTIES,\n isRef,\n} from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\nimport { walkRenderableCard } from './renderable-walk.js';\n\n// ---------------------------------------------------------------------------\n// Property sets\n// ---------------------------------------------------------------------------\n\nconst COLOR_PROPERTIES = new Set(['backgroundColor', 'color']);\n\nconst LENGTH_PROPERTIES = new Set([\n 'width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight',\n 'padding', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft',\n 'margin', 'marginTop', 'marginRight', 'marginBottom', 'marginLeft',\n 'top', 'right', 'bottom', 'left', 'gap', 'lineHeight',\n]);\n\nconst LENGTH_AUTO_ALLOWED = new Set([\n 'width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight',\n 'margin', 'marginTop', 'marginRight', 'marginBottom', 'marginLeft',\n]);\n\nconst RESPONSIVE_OVERRIDE_KEYS = ['medium', 'compact'] as const;\n\n// Properties that have range limits AND accept string lengths\nconst RANGE_LENGTH_PROPERTIES: Record<string, { min: number; max: number }> = {\n fontSize: { min: FONT_SIZE_MIN, max: FONT_SIZE_MAX },\n letterSpacing: { min: LETTER_SPACING_MIN, max: LETTER_SPACING_MAX },\n borderRadius: { min: 0, max: BORDER_RADIUS_MAX },\n borderRadiusTopLeft: { min: 0, max: BORDER_RADIUS_MAX },\n borderRadiusTopRight: { min: 0, max: BORDER_RADIUS_MAX },\n borderRadiusBottomLeft: { min: 0, max: BORDER_RADIUS_MAX },\n borderRadiusBottomRight: { min: 0, max: BORDER_RADIUS_MAX },\n};\n\ninterface StyleValidationOptions {\n allowHoverStyle?: boolean;\n allowTransition?: boolean;\n allowHoverStyleRefs?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Returns true only if the value is a literal number (not a $ref).\n */\nfunction isLiteralNumber(value: unknown): value is number {\n return typeof value === 'number';\n}\n\n/**\n * Returns true only if the value is a literal string (not a $ref).\n */\nfunction isLiteralString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\n/**\n * Returns true if the value is a dynamic binding ($ref) that should\n * be skipped for static range checks.\n */\nfunction isDynamic(value: unknown): boolean {\n return isRef(value);\n}\n\n/**\n * Returns true if the string is a valid CSS color value.\n *\n * Supported formats:\n * - Hex: #RGB, #RRGGBB, #RRGGBBAA\n * - Functional: rgb(...), rgba(...), hsl(...), hsla(...)\n * - Named CSS colors (148 standard keywords)\n * - Special keywords: transparent, currentcolor\n */\nfunction isValidColor(value: string): boolean {\n const lower = value.toLowerCase();\n\n // Hex colors\n if (/^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/.test(lower)) {\n return true;\n }\n\n // Functional color notations\n if (\n lower.startsWith('rgb(') ||\n lower.startsWith('rgba(') ||\n lower.startsWith('hsl(') ||\n lower.startsWith('hsla(')\n ) {\n return true;\n }\n\n // Named CSS colors\n if (CSS_NAMED_COLORS.has(lower)) {\n return true;\n }\n\n // Special keywords\n if (lower === 'transparent' || lower === 'currentcolor') {\n return true;\n }\n\n return false;\n}\n\n/**\n * Returns true if the string is a valid CSS length value.\n *\n * Allowed pattern: optional negative sign, digits (with optional decimal),\n * and optional unit (px, %, em, rem).\n *\n * NOTE: `auto` is NOT checked here — it's handled separately per property.\n */\nfunction isValidLength(value: string): boolean {\n return /^-?[0-9]+(\\.[0-9]+)?(px|%|em|rem)?$/.test(value);\n}\n\n/**\n * Extract the numeric part from a length string like \"42px\", \"50%\", \"16em\",\n * \"1.5rem\", or \"100\".\n *\n * Returns the number, or null if it can't be parsed.\n */\nfunction parseLengthValue(value: string): number | null {\n const match = value.match(/^(-?[0-9]+(\\.[0-9]+)?)(px|%|em|rem)?$/);\n if (!match) {\n return null;\n }\n return Number(match[1]);\n}\n\nfunction isLiteralLength(value: unknown): value is string | number {\n return typeof value === 'number' || typeof value === 'string';\n}\n\nfunction isValidAspectRatioLiteral(value: string | number): boolean {\n if (typeof value === 'number') {\n return Number.isFinite(value) && value > 0;\n }\n\n const match = value.match(ASPECT_RATIO_PATTERN);\n if (!match) {\n return false;\n }\n\n const parts = value.split('/');\n if (parts.length !== 2) {\n return false;\n }\n\n const width = Number(parts[0].trim());\n const height = Number(parts[1].trim());\n return Number.isFinite(width) && Number.isFinite(height) && width > 0 && height > 0;\n}\n\n/**\n * Recursively scan all string values in a value (which may be a string,\n * object, or array) for dangerous CSS function patterns.\n * Skips $ref objects entirely.\n */\nfunction collectDangerousCssErrors(\n value: unknown,\n path: string,\n errors: ValidationError[],\n): void {\n if (typeof value === 'string') {\n const lower = value.toLowerCase();\n for (const fn of DANGEROUS_CSS_FUNCTIONS) {\n if (lower.includes(fn)) {\n errors.push(\n createError(\n 'FORBIDDEN_CSS_FUNCTION',\n `Style value contains forbidden CSS function \"${fn.slice(0, -1)}\" at \"${path}\"`,\n path,\n ),\n );\n // Report only the first match per string to keep errors concise\n break;\n }\n }\n return;\n }\n\n // Skip $ref objects — they are not user-authored strings\n if (isRef(value)) {\n return;\n }\n\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n collectDangerousCssErrors(value[i], `${path}[${i}]`, errors);\n }\n return;\n }\n\n if (typeof value === 'object' && value !== null) {\n for (const [key, child] of Object.entries(value as Record<string, unknown>)) {\n collectDangerousCssErrors(child, `${path}.${key}`, errors);\n }\n }\n}\n\n/**\n * Validate a single shadow object's blur and spread values,\n * and its color if present.\n */\nfunction validateShadowObject(\n shadow: Record<string, unknown>,\n path: string,\n errors: ValidationError[],\n): void {\n if (\n isLiteralNumber(shadow.blur) &&\n shadow.blur > BOX_SHADOW_BLUR_MAX\n ) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `boxShadow blur (${shadow.blur}) exceeds maximum of ${BOX_SHADOW_BLUR_MAX} at \"${path}.blur\"`,\n `${path}.blur`,\n ),\n );\n }\n\n if (\n isLiteralNumber(shadow.spread) &&\n shadow.spread > BOX_SHADOW_SPREAD_MAX\n ) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `boxShadow spread (${shadow.spread}) exceeds maximum of ${BOX_SHADOW_SPREAD_MAX} at \"${path}.spread\"`,\n `${path}.spread`,\n ),\n );\n }\n\n // Validate shadow color\n if (isLiteralString(shadow.color) && !isValidColor(shadow.color)) {\n errors.push(\n createError(\n 'INVALID_COLOR',\n `Invalid color \"${shadow.color}\" at \"${path}.color\"`,\n `${path}.color`,\n ),\n );\n }\n}\n\n/**\n * Validate a single text-shadow object's blur value and color.\n */\nfunction validateTextShadowObject(\n shadow: Record<string, unknown>,\n path: string,\n errors: ValidationError[],\n): void {\n if (\n isLiteralNumber(shadow.blur) &&\n shadow.blur > TEXT_SHADOW_BLUR_MAX\n ) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `textShadow blur (${shadow.blur}) exceeds maximum of ${TEXT_SHADOW_BLUR_MAX} at \"${path}.blur\"`,\n `${path}.blur`,\n ),\n );\n }\n\n if (isLiteralString(shadow.color) && !isValidColor(shadow.color)) {\n errors.push(\n createError(\n 'INVALID_COLOR',\n `Invalid color \"${shadow.color}\" at \"${path}.color\"`,\n `${path}.color`,\n ),\n );\n }\n}\n\nfunction validateClipPathLength(\n value: unknown,\n path: string,\n errors: ValidationError[],\n): void {\n if (value == null || isDynamic(value)) {\n return;\n }\n\n if (typeof value === 'number') {\n return;\n }\n\n if (typeof value === 'string' && isValidLength(value)) {\n return;\n }\n\n errors.push(\n createError(\n 'INVALID_LENGTH',\n `Invalid length \"${String(value)}\" at \"${path}\"`,\n path,\n ),\n );\n}\n\nfunction validateClipPathObject(\n clipPath: Record<string, unknown>,\n path: string,\n errors: ValidationError[],\n): void {\n switch (clipPath.type) {\n case 'circle':\n validateClipPathLength(clipPath.radius, `${path}.radius`, errors);\n return;\n\n case 'ellipse':\n validateClipPathLength(clipPath.rx, `${path}.rx`, errors);\n validateClipPathLength(clipPath.ry, `${path}.ry`, errors);\n return;\n\n case 'inset':\n validateClipPathLength(clipPath.top, `${path}.top`, errors);\n validateClipPathLength(clipPath.right, `${path}.right`, errors);\n validateClipPathLength(clipPath.bottom, `${path}.bottom`, errors);\n validateClipPathLength(clipPath.left, `${path}.left`, errors);\n validateClipPathLength(clipPath.round, `${path}.round`, errors);\n return;\n\n default:\n return;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Regex for valid $style references and style names\n// ---------------------------------------------------------------------------\n\nconst STYLE_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*$/;\n\nfunction reportStyleRefError(\n rawRef: string,\n stylePath: string,\n cardStyles: Record<string, Record<string, unknown>> | undefined,\n errors: ValidationError[],\n): string | undefined {\n const trimmedRef = rawRef.trim();\n\n if (!STYLE_NAME_PATTERN.test(trimmedRef)) {\n errors.push(\n createError(\n 'INVALID_STYLE_REF',\n `$style value \"${rawRef}\" is invalid; must match /^[A-Za-z][A-Za-z0-9_-]*$/ at \"${stylePath}.$style\"`,\n `${stylePath}.$style`,\n ),\n );\n return undefined;\n }\n\n if (!cardStyles || !(trimmedRef in cardStyles)) {\n errors.push(\n createError(\n 'STYLE_REF_NOT_FOUND',\n `$style references \"${trimmedRef}\" which is not defined in card.styles at \"${stylePath}.$style\"`,\n `${stylePath}.$style`,\n ),\n );\n return undefined;\n }\n\n return trimmedRef;\n}\n\nfunction resolveStyleRef(\n style: Record<string, unknown>,\n stylePath: string,\n cardStyles: Record<string, Record<string, unknown>> | undefined,\n errors: ValidationError[],\n): Record<string, unknown> | undefined {\n if (typeof style.$style !== 'string') {\n return style;\n }\n\n const trimmedRef = reportStyleRefError(style.$style, stylePath, cardStyles, errors);\n if (!trimmedRef || !cardStyles) {\n return undefined;\n }\n\n return mergeStyleWithRef(cardStyles[trimmedRef], style);\n}\n\nfunction collectNestedStyleRefErrors(\n value: unknown,\n path: string,\n errors: ValidationError[],\n): void {\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n collectNestedStyleRefErrors(value[i], `${path}[${i}]`, errors);\n }\n return;\n }\n\n if (typeof value !== 'object' || value === null) {\n return;\n }\n\n for (const [key, child] of Object.entries(value as Record<string, unknown>)) {\n const childPath = `${path}.${key}`;\n if (key === '$style') {\n errors.push(\n createError(\n 'STYLE_CIRCULAR_REF',\n `$style cannot be used inside card.styles definitions at \"${childPath}\"`,\n childPath,\n ),\n );\n continue;\n }\n collectNestedStyleRefErrors(child, childPath, errors);\n }\n}\n\n// ---------------------------------------------------------------------------\n// validateSingleStyle — reusable per-style validation logic\n// ---------------------------------------------------------------------------\n\n/**\n * Validate a single style object's properties.\n *\n * Checks:\n * 1. Forbidden style properties (spec 3.8)\n * 2. Numeric range limits (spec 6.4)\n * 3. Box-shadow count and value limits\n * 4. Text-shadow count and value limits\n * 5. Transform skew prohibition\n * 6. CSS function injection in string values\n * 7. Overflow: scroll prohibition (defense-in-depth)\n * 8. Color format validation\n * 9. Length format validation\n * 10. Range checks on string length values\n * 11. Border color validation\n * 12. Background gradient stop color validation\n */\nfunction validateSingleStyle(\n style: Record<string, unknown>,\n stylePath: string,\n errors: ValidationError[],\n cardStyles?: Record<string, Record<string, unknown>>,\n options: StyleValidationOptions = {},\n): void {\n const {\n allowHoverStyle = true,\n allowTransition = true,\n allowHoverStyleRefs = true,\n } = options;\n\n // ------------------------------------------------------------------\n // 1. Forbidden properties (spec 3.8)\n // Note: 'transition' and 'hoverStyle' are handled as structured\n // fields (sections 12-13), not raw CSS properties.\n // ------------------------------------------------------------------\n const STRUCTURED_FIELDS = new Set<string>();\n if (allowTransition) STRUCTURED_FIELDS.add('transition');\n if (allowHoverStyle) STRUCTURED_FIELDS.add('hoverStyle');\n for (const key of Object.keys(style)) {\n if (\n !STRUCTURED_FIELDS.has(key) &&\n (FORBIDDEN_STYLE_PROPERTIES as readonly string[]).includes(key)\n ) {\n errors.push(\n createError(\n 'FORBIDDEN_STYLE_PROPERTY',\n `Style property \"${key}\" is forbidden at \"${stylePath}.${key}\"`,\n `${stylePath}.${key}`,\n ),\n );\n }\n }\n\n if (!allowHoverStyle && 'hoverStyle' in style) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n `hoverStyle is not allowed inside responsive overrides at \"${stylePath}.hoverStyle\"`,\n `${stylePath}.hoverStyle`,\n ),\n );\n }\n\n if (!allowTransition && 'transition' in style) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n `transition is not allowed inside responsive overrides at \"${stylePath}.transition\"`,\n `${stylePath}.transition`,\n ),\n );\n }\n\n // ------------------------------------------------------------------\n // 2. Numeric range checks (spec 6.4)\n // ------------------------------------------------------------------\n\n // zIndex: ZINDEX_MIN..ZINDEX_MAX\n if ('zIndex' in style && isLiteralNumber(style.zIndex)) {\n const v = style.zIndex;\n if (v < ZINDEX_MIN || v > ZINDEX_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `zIndex (${v}) must be between ${ZINDEX_MIN} and ${ZINDEX_MAX} at \"${stylePath}.zIndex\"`,\n `${stylePath}.zIndex`,\n ),\n );\n }\n }\n\n // fontSize: FONT_SIZE_MIN..FONT_SIZE_MAX\n if ('fontSize' in style && isLiteralNumber(style.fontSize)) {\n const v = style.fontSize;\n if (v < FONT_SIZE_MIN || v > FONT_SIZE_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `fontSize (${v}) must be between ${FONT_SIZE_MIN} and ${FONT_SIZE_MAX} at \"${stylePath}.fontSize\"`,\n `${stylePath}.fontSize`,\n ),\n );\n }\n }\n\n // opacity: OPACITY_MIN..OPACITY_MAX\n if ('opacity' in style && isLiteralNumber(style.opacity)) {\n const v = style.opacity;\n if (v < OPACITY_MIN || v > OPACITY_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `opacity (${v}) must be between ${OPACITY_MIN} and ${OPACITY_MAX} at \"${stylePath}.opacity\"`,\n `${stylePath}.opacity`,\n ),\n );\n }\n }\n\n if ('backdropBlur' in style && isLiteralNumber(style.backdropBlur)) {\n const v = style.backdropBlur;\n if (v < 0 || v > BACKDROP_BLUR_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `backdropBlur (${v}) must be between 0 and ${BACKDROP_BLUR_MAX} at \"${stylePath}.backdropBlur\"`,\n `${stylePath}.backdropBlur`,\n ),\n );\n }\n }\n\n // letterSpacing: LETTER_SPACING_MIN..LETTER_SPACING_MAX\n if ('letterSpacing' in style && isLiteralNumber(style.letterSpacing)) {\n const v = style.letterSpacing;\n if (v < LETTER_SPACING_MIN || v > LETTER_SPACING_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `letterSpacing (${v}) must be between ${LETTER_SPACING_MIN} and ${LETTER_SPACING_MAX} at \"${stylePath}.letterSpacing\"`,\n `${stylePath}.letterSpacing`,\n ),\n );\n }\n }\n\n // borderRadius + directional variants: 0..BORDER_RADIUS_MAX\n for (const prop of [\n 'borderRadius',\n 'borderRadiusTopLeft',\n 'borderRadiusTopRight',\n 'borderRadiusBottomLeft',\n 'borderRadiusBottomRight',\n ] as const) {\n if (prop in style && isLiteralNumber(style[prop])) {\n const v = style[prop] as number;\n if (v < 0 || v > BORDER_RADIUS_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `${prop} (${v}) must be between 0 and ${BORDER_RADIUS_MAX} at \"${stylePath}.${prop}\"`,\n `${stylePath}.${prop}`,\n ),\n );\n }\n }\n }\n\n // transform sub-properties\n if (\n 'transform' in style &&\n typeof style.transform === 'object' &&\n style.transform !== null &&\n !isDynamic(style.transform)\n ) {\n const transform = style.transform as Record<string, unknown>;\n const transformPath = `${stylePath}.transform`;\n\n // scale: TRANSFORM_SCALE_MIN..TRANSFORM_SCALE_MAX\n if ('scale' in transform && isLiteralNumber(transform.scale)) {\n const v = transform.scale;\n if (v < TRANSFORM_SCALE_MIN || v > TRANSFORM_SCALE_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `transform.scale (${v}) must be between ${TRANSFORM_SCALE_MIN} and ${TRANSFORM_SCALE_MAX} at \"${transformPath}.scale\"`,\n `${transformPath}.scale`,\n ),\n );\n }\n }\n\n // translateX: TRANSFORM_TRANSLATE_MIN..TRANSFORM_TRANSLATE_MAX\n if ('translateX' in transform && isLiteralNumber(transform.translateX)) {\n const v = transform.translateX;\n if (v < TRANSFORM_TRANSLATE_MIN || v > TRANSFORM_TRANSLATE_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `transform.translateX (${v}) must be between ${TRANSFORM_TRANSLATE_MIN} and ${TRANSFORM_TRANSLATE_MAX} at \"${transformPath}.translateX\"`,\n `${transformPath}.translateX`,\n ),\n );\n }\n }\n\n // translateY: TRANSFORM_TRANSLATE_MIN..TRANSFORM_TRANSLATE_MAX\n if ('translateY' in transform && isLiteralNumber(transform.translateY)) {\n const v = transform.translateY;\n if (v < TRANSFORM_TRANSLATE_MIN || v > TRANSFORM_TRANSLATE_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `transform.translateY (${v}) must be between ${TRANSFORM_TRANSLATE_MIN} and ${TRANSFORM_TRANSLATE_MAX} at \"${transformPath}.translateY\"`,\n `${transformPath}.translateY`,\n ),\n );\n }\n }\n\n // ------------------------------------------------------------------\n // 4. Transform skew forbidden\n // ------------------------------------------------------------------\n if ('skew' in transform) {\n errors.push(\n createError(\n 'TRANSFORM_SKEW_FORBIDDEN',\n `transform.skew is forbidden at \"${transformPath}.skew\"`,\n `${transformPath}.skew`,\n ),\n );\n }\n }\n\n // ------------------------------------------------------------------\n // 3. Box-shadow limits\n // ------------------------------------------------------------------\n if ('boxShadow' in style && style.boxShadow != null) {\n const boxShadow = style.boxShadow;\n const boxShadowPath = `${stylePath}.boxShadow`;\n\n if (Array.isArray(boxShadow)) {\n // Array of shadows — check count\n if (boxShadow.length > BOX_SHADOW_MAX_COUNT) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `boxShadow has ${boxShadow.length} entries, maximum is ${BOX_SHADOW_MAX_COUNT} at \"${boxShadowPath}\"`,\n boxShadowPath,\n ),\n );\n }\n\n // Check each shadow's blur/spread/color\n for (let i = 0; i < boxShadow.length; i++) {\n const shadow = boxShadow[i];\n if (typeof shadow === 'object' && shadow !== null) {\n validateShadowObject(\n shadow as Record<string, unknown>,\n `${boxShadowPath}[${i}]`,\n errors,\n );\n }\n }\n } else if (typeof boxShadow === 'object' && boxShadow !== null) {\n // Single shadow object\n validateShadowObject(\n boxShadow as Record<string, unknown>,\n boxShadowPath,\n errors,\n );\n }\n }\n\n // ------------------------------------------------------------------\n // 4. Text-shadow limits\n // ------------------------------------------------------------------\n if ('textShadow' in style && style.textShadow != null) {\n const textShadow = style.textShadow;\n const textShadowPath = `${stylePath}.textShadow`;\n\n if (Array.isArray(textShadow)) {\n if (textShadow.length > TEXT_SHADOW_MAX_COUNT) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `textShadow has ${textShadow.length} entries, maximum is ${TEXT_SHADOW_MAX_COUNT} at \"${textShadowPath}\"`,\n textShadowPath,\n ),\n );\n }\n\n for (let i = 0; i < textShadow.length; i++) {\n const shadow = textShadow[i];\n if (typeof shadow === 'object' && shadow !== null) {\n validateTextShadowObject(\n shadow as Record<string, unknown>,\n `${textShadowPath}[${i}]`,\n errors,\n );\n }\n }\n } else if (typeof textShadow === 'object' && textShadow !== null) {\n validateTextShadowObject(\n textShadow as Record<string, unknown>,\n textShadowPath,\n errors,\n );\n }\n }\n\n // ------------------------------------------------------------------\n // 6. CSS function injection — scan all string values\n // ------------------------------------------------------------------\n for (const [key, value] of Object.entries(style)) {\n collectDangerousCssErrors(value, `${stylePath}.${key}`, errors);\n }\n\n // ------------------------------------------------------------------\n // 7. Overflow: scroll forbidden (defense-in-depth)\n // ------------------------------------------------------------------\n if ('overflow' in style && style.overflow === 'scroll') {\n errors.push(\n createError(\n 'FORBIDDEN_OVERFLOW_VALUE',\n `overflow \"scroll\" is forbidden; use \"visible\", \"hidden\", or \"auto\" at \"${stylePath}.overflow\"`,\n `${stylePath}.overflow`,\n ),\n );\n }\n\n // ------------------------------------------------------------------\n // 8. Color format validation\n // ------------------------------------------------------------------\n for (const prop of COLOR_PROPERTIES) {\n if (\n prop in style &&\n isLiteralString(style[prop]) &&\n !isDynamic(style[prop])\n ) {\n if (!isValidColor(style[prop] as string)) {\n errors.push(\n createError(\n 'INVALID_COLOR',\n `Invalid color \"${style[prop]}\" at \"${stylePath}.${prop}\"`,\n `${stylePath}.${prop}`,\n ),\n );\n }\n }\n }\n\n // ------------------------------------------------------------------\n // 9. Length format validation\n // ------------------------------------------------------------------\n for (const prop of LENGTH_PROPERTIES) {\n if (\n prop in style &&\n isLiteralString(style[prop]) &&\n !isDynamic(style[prop])\n ) {\n const val = style[prop] as string;\n if (val === 'auto') {\n if (!LENGTH_AUTO_ALLOWED.has(prop)) {\n errors.push(\n createError(\n 'INVALID_LENGTH',\n `\"auto\" is not allowed for \"${prop}\" at \"${stylePath}.${prop}\"`,\n `${stylePath}.${prop}`,\n ),\n );\n }\n } else if (!isValidLength(val)) {\n errors.push(\n createError(\n 'INVALID_LENGTH',\n `Invalid length \"${val}\" at \"${stylePath}.${prop}\"`,\n `${stylePath}.${prop}`,\n ),\n );\n }\n }\n }\n\n if ('aspectRatio' in style && style.aspectRatio != null && !isDynamic(style.aspectRatio)) {\n const aspectRatio = style.aspectRatio;\n if (\n (typeof aspectRatio !== 'number' && typeof aspectRatio !== 'string') ||\n !isValidAspectRatioLiteral(aspectRatio)\n ) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n `Invalid aspectRatio \"${String(aspectRatio)}\" at \"${stylePath}.aspectRatio\"`,\n `${stylePath}.aspectRatio`,\n ),\n );\n }\n }\n\n if (\n 'clipPath' in style &&\n style.clipPath != null &&\n typeof style.clipPath === 'object' &&\n !Array.isArray(style.clipPath) &&\n !isDynamic(style.clipPath)\n ) {\n validateClipPathObject(\n style.clipPath as Record<string, unknown>,\n `${stylePath}.clipPath`,\n errors,\n );\n }\n\n // ------------------------------------------------------------------\n // 10. Range checks on string length values\n // ------------------------------------------------------------------\n for (const [prop, range] of Object.entries(RANGE_LENGTH_PROPERTIES)) {\n if (\n prop in style &&\n isLiteralString(style[prop]) &&\n !isDynamic(style[prop])\n ) {\n const numericValue = parseLengthValue(style[prop] as string);\n if (numericValue !== null) {\n if (numericValue < range.min || numericValue > range.max) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `${prop} (${style[prop]}) must be between ${range.min} and ${range.max} at \"${stylePath}.${prop}\"`,\n `${stylePath}.${prop}`,\n ),\n );\n }\n }\n }\n }\n\n // ------------------------------------------------------------------\n // 11. Border color validation (border + borderTop/Right/Bottom/Left)\n // ------------------------------------------------------------------\n const borderKeys = ['border', 'borderTop', 'borderRight', 'borderBottom', 'borderLeft'] as const;\n for (const borderKey of borderKeys) {\n if (\n borderKey in style &&\n typeof style[borderKey] === 'object' &&\n style[borderKey] !== null &&\n !isDynamic(style[borderKey])\n ) {\n const border = style[borderKey] as Record<string, unknown>;\n const borderPath = `${stylePath}.${borderKey}`;\n\n if (\n isLiteralString(border.color) &&\n !isDynamic(border.color) &&\n !isValidColor(border.color)\n ) {\n errors.push(\n createError(\n 'INVALID_COLOR',\n `Invalid color \"${border.color}\" at \"${borderPath}.color\"`,\n `${borderPath}.color`,\n ),\n );\n }\n }\n }\n\n // ------------------------------------------------------------------\n // 12. Background gradient stop color validation\n // ------------------------------------------------------------------\n if (\n 'backgroundGradient' in style &&\n typeof style.backgroundGradient === 'object' &&\n style.backgroundGradient !== null &&\n !isDynamic(style.backgroundGradient)\n ) {\n const gradient = style.backgroundGradient as Record<string, unknown>;\n const gradientPath = `${stylePath}.backgroundGradient`;\n\n if (Array.isArray(gradient.stops)) {\n for (let i = 0; i < gradient.stops.length; i++) {\n const stop = gradient.stops[i];\n if (\n typeof stop === 'object' &&\n stop !== null &&\n !isDynamic(stop)\n ) {\n const stopObj = stop as Record<string, unknown>;\n if (\n isLiteralString(stopObj.color) &&\n !isDynamic(stopObj.color) &&\n !isValidColor(stopObj.color)\n ) {\n errors.push(\n createError(\n 'INVALID_COLOR',\n `Invalid color \"${stopObj.color}\" at \"${gradientPath}.stops[${i}].color\"`,\n `${gradientPath}.stops[${i}].color`,\n ),\n );\n }\n }\n }\n }\n }\n\n // ------------------------------------------------------------------\n // 13. hoverStyle validation (spec 3.9)\n // ------------------------------------------------------------------\n if (allowHoverStyle && 'hoverStyle' in style && style.hoverStyle != null) {\n const hoverStyle = style.hoverStyle;\n const hoverPath = `${stylePath}.hoverStyle`;\n\n if (typeof hoverStyle !== 'object' || Array.isArray(hoverStyle)) {\n errors.push(\n createError(\n 'INVALID_HOVER_STYLE',\n `hoverStyle must be an object at \"${hoverPath}\"`,\n hoverPath,\n ),\n );\n } else {\n const hoverObj = hoverStyle as Record<string, unknown>;\n\n // Nested hoverStyle is forbidden\n if ('hoverStyle' in hoverObj) {\n errors.push(\n createError(\n 'HOVER_STYLE_NESTED',\n `Nested hoverStyle is forbidden at \"${hoverPath}.hoverStyle\"`,\n `${hoverPath}.hoverStyle`,\n ),\n );\n }\n\n const mergedHoverStyle = allowHoverStyleRefs\n ? resolveStyleRef(hoverObj, hoverPath, cardStyles, errors)\n : hoverObj;\n\n if (mergedHoverStyle) {\n // Validate hoverStyle with the same rules (recursive call)\n validateSingleStyle(\n mergedHoverStyle,\n hoverPath,\n errors,\n cardStyles,\n {\n allowHoverStyle,\n allowTransition,\n allowHoverStyleRefs,\n },\n );\n }\n }\n }\n\n // ------------------------------------------------------------------\n // 14. transition validation (spec 3.9)\n // ------------------------------------------------------------------\n if (allowTransition && 'transition' in style && style.transition != null) {\n const transition = style.transition;\n const transPath = `${stylePath}.transition`;\n\n // Defense-in-depth: reject raw string transitions\n if (typeof transition === 'string') {\n errors.push(\n createError(\n 'TRANSITION_RAW_STRING',\n `transition must be an object or array, not a string at \"${transPath}\"`,\n transPath,\n ),\n );\n } else {\n const transitions = Array.isArray(transition) ? transition : [transition];\n\n if (transitions.length > TRANSITION_MAX_COUNT) {\n errors.push(\n createError(\n 'TRANSITION_COUNT_EXCEEDED',\n `transition has ${transitions.length} entries, maximum is ${TRANSITION_MAX_COUNT} at \"${transPath}\"`,\n transPath,\n ),\n );\n }\n\n for (let i = 0; i < transitions.length; i++) {\n const t = transitions[i];\n const tPath = Array.isArray(transition) ? `${transPath}[${i}]` : transPath;\n\n if (typeof t !== 'object' || t === null) continue;\n const tObj = t as Record<string, unknown>;\n\n // Validate property is in whitelist\n if (\n isLiteralString(tObj.property) &&\n !(ALLOWED_TRANSITION_PROPERTIES as readonly string[]).includes(tObj.property)\n ) {\n errors.push(\n createError(\n 'TRANSITION_PROPERTY_FORBIDDEN',\n `transition property \"${tObj.property}\" is not in the allowed list at \"${tPath}.property\"`,\n `${tPath}.property`,\n ),\n );\n }\n\n // Validate duration range\n if (isLiteralNumber(tObj.duration)) {\n if (tObj.duration < 0 || tObj.duration > TRANSITION_DURATION_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `transition duration (${tObj.duration}) must be between 0 and ${TRANSITION_DURATION_MAX} at \"${tPath}.duration\"`,\n `${tPath}.duration`,\n ),\n );\n }\n }\n\n // Validate delay range\n if (isLiteralNumber(tObj.delay)) {\n if (tObj.delay < 0 || tObj.delay > TRANSITION_DELAY_MAX) {\n errors.push(\n createError(\n 'STYLE_VALUE_OUT_OF_RANGE',\n `transition delay (${tObj.delay}) must be between 0 and ${TRANSITION_DELAY_MAX} at \"${tPath}.delay\"`,\n `${tPath}.delay`,\n ),\n );\n }\n }\n }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helper: merge $style with inline style\n// ---------------------------------------------------------------------------\n\n/**\n * Build a merged style object from a card.styles entry and inline style\n * properties, excluding the `$style` key itself from the inline portion.\n */\nfunction mergeStyleWithRef(\n cardStyleEntry: Record<string, unknown>,\n inlineStyle: Record<string, unknown>,\n): Record<string, unknown> {\n const merged: Record<string, unknown> = { ...cardStyleEntry };\n for (const [key, value] of Object.entries(inlineStyle)) {\n if (key !== '$style') {\n merged[key] = value;\n }\n }\n return merged;\n}\n\n// ---------------------------------------------------------------------------\n// Main export\n// ---------------------------------------------------------------------------\n\n/**\n * Validate all style properties across every node in the card's view tree,\n * and validate card-level style definitions.\n *\n * Checks:\n * 1. Forbidden style properties (spec 3.8)\n * 2. Numeric range limits (spec 6.4)\n * 3. Box-shadow count and value limits\n * 4. Transform skew prohibition\n * 5. CSS function injection in string values\n * 6. Overflow: scroll prohibition (defense-in-depth)\n * 7. Color format validation\n * 8. Length format validation\n * 9. Range checks on string length values\n * 10. $style reference validation and merging\n */\nexport function validateStyles(\n views: Record<string, unknown>,\n cardStyles?: Record<string, Record<string, unknown>>,\n fragments?: Record<string, unknown>,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n // ------------------------------------------------------------------\n // Phase 0: Validate card.styles entries\n // ------------------------------------------------------------------\n if (cardStyles) {\n for (const [styleName, styleEntry] of Object.entries(cardStyles)) {\n const entryPath = `styles.${styleName}`;\n\n // Defense-in-depth: validate style name format\n // (Zod regex already checks this, but we add a redundant check)\n if (!STYLE_NAME_PATTERN.test(styleName)) {\n errors.push(\n createError(\n 'INVALID_STYLE_NAME',\n `Style name \"${styleName}\" is invalid; must match /^[A-Za-z][A-Za-z0-9_-]*$/ at \"${entryPath}\"`,\n entryPath,\n ),\n );\n }\n\n // $style cannot be used anywhere inside card.styles definitions\n collectNestedStyleRefErrors(styleEntry, entryPath, errors);\n\n // Run all per-style validations on this entry\n validateSingleStyle(styleEntry, entryPath, errors, undefined, {\n allowHoverStyleRefs: false,\n });\n }\n }\n\n // ------------------------------------------------------------------\n // Phase 1: Validate per-node styles (with $style merging)\n // ------------------------------------------------------------------\n walkRenderableCard(views, fragments, (node, ctx) => {\n if (!('type' in node) || typeof node.type !== 'string') {\n return;\n }\n\n const style =\n node.style != null &&\n typeof node.style === 'object' &&\n !Array.isArray(node.style)\n ? node.style as Record<string, unknown>\n : undefined;\n if (style != null && typeof style === 'object') {\n const stylePath = `${ctx.path}.style`;\n\n const mergedStyle = resolveStyleRef(style, stylePath, cardStyles, errors);\n if (mergedStyle) {\n // No $style or valid $style — validate the effective style\n validateSingleStyle(mergedStyle, stylePath, errors, cardStyles);\n }\n }\n\n const responsive = node.responsive;\n if (\n responsive != null &&\n typeof responsive === 'object' &&\n !Array.isArray(responsive)\n ) {\n for (const mode of RESPONSIVE_OVERRIDE_KEYS) {\n const override = (responsive as Record<string, unknown>)[mode];\n if (\n override != null &&\n typeof override === 'object' &&\n !Array.isArray(override)\n ) {\n const overridePath = `${ctx.path}.responsive.${mode}`;\n const mergedOverride = resolveStyleRef(\n override as Record<string, unknown>,\n overridePath,\n cardStyles,\n errors,\n );\n\n if (mergedOverride) {\n validateSingleStyle(mergedOverride, overridePath, errors, cardStyles, {\n allowHoverStyle: false,\n allowTransition: false,\n allowHoverStyleRefs: false,\n });\n }\n }\n }\n }\n\n const spans = Array.isArray(node.spans) ? node.spans : undefined;\n if (node.type === 'Text' && spans) {\n for (let i = 0; i < spans.length; i++) {\n const span = spans[i];\n if (\n span == null ||\n typeof span !== 'object' ||\n Array.isArray(span)\n ) {\n continue;\n }\n\n const spanStyle = (span as Record<string, unknown>).style;\n if (\n spanStyle == null ||\n typeof spanStyle !== 'object' ||\n Array.isArray(spanStyle)\n ) {\n continue;\n }\n\n validateSingleStyle(\n spanStyle as Record<string, unknown>,\n `${ctx.path}.spans[${i}].style`,\n errors,\n undefined,\n {\n allowHoverStyle: false,\n allowTransition: false,\n allowHoverStyleRefs: false,\n },\n );\n }\n }\n });\n\n return errors;\n}\n","/**\n * @safe-ugc-ui/validator — Security Validation\n *\n * Enforces security rules from spec sections 3 and 8:\n * - External URL blocking on Image/Avatar `src` fields (literal and $ref)\n * - Asset path validation (`@assets/` prefix, no traversal)\n * - cardAssets value validation\n * - Forbidden CSS `url()` function in style string values\n * - Position restrictions (fixed, sticky, absolute outside Stack)\n * - Nested overflow:auto detection\n * - Prototype pollution prevention in $ref paths\n */\n\nimport {\n PROTOTYPE_POLLUTION_SEGMENTS,\n isRef,\n} from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\n\nimport {\n type TraversableNode,\n type TraversalContext,\n traverseCard,\n} from './traverse.js';\nimport { walkRenderableCard } from './renderable-walk.js';\nimport {\n type ResponsiveMode,\n RESPONSIVE_MODES,\n getEffectiveStyleForMode,\n} from './responsive-utils.js';\n\nconst RESPONSIVE_OVERRIDE_KEYS = ['medium', 'compact'] as const;\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/**\n * URL prefixes that are forbidden in Image/Avatar `src` values.\n * Checked case-insensitively to prevent bypass via mixed case.\n */\nconst FORBIDDEN_URL_PREFIXES = [\n 'http://',\n 'https://',\n '//',\n 'data:',\n 'javascript:',\n] as const;\n\n// ---------------------------------------------------------------------------\n// Helper: scanForRefs — recursively find $ref values for pollution check\n// ---------------------------------------------------------------------------\n\n/**\n * Recursively walk an unknown value looking for `{ $ref: string }` objects.\n * For each one found, verify the ref path segments do not contain\n * prototype pollution keys (`__proto__`, `constructor`, `prototype`).\n *\n * @param obj - The value to scan (may be primitive, array, or object).\n * @param path - The JSON-pointer-like location for error reporting.\n * @param errors - Accumulator for any validation errors found.\n */\nfunction scanForRefs(\n obj: unknown,\n path: string,\n errors: ValidationError[],\n): void {\n if (obj === null || obj === undefined || typeof obj !== 'object') {\n return;\n }\n\n // Check if this object is a $ref\n if (isRef(obj)) {\n const refStr = (obj as { $ref: string }).$ref;\n // Split by '.' and '[' to extract all path segments\n const segments = refStr.split(/[.\\[]/);\n for (const segment of segments) {\n // Remove trailing ']' from bracket access segments\n const clean = segment.replace(/]$/, '');\n if (\n (PROTOTYPE_POLLUTION_SEGMENTS as readonly string[]).includes(clean)\n ) {\n errors.push(\n createError(\n 'PROTOTYPE_POLLUTION',\n `$ref \"${refStr}\" contains forbidden prototype pollution segment \"${clean}\".`,\n path,\n ),\n );\n // One error per ref is sufficient\n return;\n }\n }\n return;\n }\n\n // Recurse into arrays\n if (Array.isArray(obj)) {\n for (let i = 0; i < obj.length; i++) {\n scanForRefs(obj[i], `${path}[${i}]`, errors);\n }\n return;\n }\n\n // Recurse into plain objects\n for (const [key, value] of Object.entries(obj)) {\n scanForRefs(value, `${path}.${key}`, errors);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helper: isForbiddenUrl\n// ---------------------------------------------------------------------------\n\n/**\n * Returns true if the string starts with any forbidden URL prefix\n * (case-insensitive comparison).\n */\nfunction isForbiddenUrl(value: string): boolean {\n const lower = value.trim().toLowerCase();\n return FORBIDDEN_URL_PREFIXES.some((prefix) => lower.startsWith(prefix));\n}\n\n// ---------------------------------------------------------------------------\n// Helper: validateAssetPath\n// ---------------------------------------------------------------------------\n\n/**\n * Validates an asset path string. Must start with `@assets/` and must not\n * contain path traversal sequences.\n *\n * @returns An error code if invalid, or null if the path is acceptable.\n */\nfunction validateAssetPath(\n value: string,\n): 'ASSET_PATH_TRAVERSAL' | 'INVALID_ASSET_PATH' | null {\n if (!value.startsWith('@assets/')) {\n return 'INVALID_ASSET_PATH';\n }\n if (value.includes('../')) {\n return 'ASSET_PATH_TRAVERSAL';\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Helper: resolveRefFromState\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a $ref path against a state object. Matches the algorithm in\n * `packages/react/src/state-resolver.ts`:\n * - Strip leading `$` from the ref path\n * - Split by `.`, then for each segment extract `[N]` bracket indices\n * - Traverse state, using numeric indices for arrays\n * - Block prototype pollution segments\n *\n * @returns The resolved value, or `undefined` if resolution fails.\n */\nfunction resolveRefFromState(\n refPath: string,\n state: Record<string, unknown>,\n): unknown {\n // Strip leading $\n const path = refPath.startsWith('$') ? refPath.slice(1) : refPath;\n const dotSegments = path.split('.');\n\n // Flatten dot-segments into individual traversal keys,\n // expanding bracket notation (e.g. \"items[0][1]\" → [\"items\", \"0\", \"1\"])\n const keys: string[] = [];\n for (const dotSeg of dotSegments) {\n // Match the base name (before any brackets) and any [N] patterns\n const bracketPattern = /\\[(\\d+)\\]/g;\n const firstBracket = dotSeg.indexOf('[');\n const baseName = firstBracket === -1 ? dotSeg : dotSeg.slice(0, firstBracket);\n if (baseName) {\n keys.push(baseName);\n }\n let match: RegExpExecArray | null;\n while ((match = bracketPattern.exec(dotSeg)) !== null) {\n keys.push(match[1]);\n }\n }\n\n // Block prototype pollution\n for (const key of keys) {\n if (\n (PROTOTYPE_POLLUTION_SEGMENTS as readonly string[]).includes(key)\n ) {\n return undefined;\n }\n }\n\n // Traverse state\n let current: unknown = state;\n for (const key of keys) {\n if (current == null || typeof current !== 'object') return undefined;\n\n if (Array.isArray(current)) {\n const index = Number(key);\n if (!Number.isInteger(index) || index < 0) return undefined;\n current = current[index];\n } else {\n current = (current as Record<string, unknown>)[key];\n }\n }\n return current;\n}\n\n// ---------------------------------------------------------------------------\n// Helper: checkSrcValue\n// ---------------------------------------------------------------------------\n\n/**\n * Check a resolved src string value and push appropriate errors.\n */\nfunction checkSrcValue(\n resolved: string,\n type: string,\n errorPath: string,\n errors: ValidationError[],\n): void {\n if (isForbiddenUrl(resolved)) {\n errors.push(\n createError(\n 'EXTERNAL_URL',\n `External URLs are not allowed in ${type}.src. Got \"${resolved}\".`,\n errorPath,\n ),\n );\n } else {\n const assetError = validateAssetPath(resolved);\n if (assetError === 'ASSET_PATH_TRAVERSAL') {\n errors.push(\n createError(\n 'ASSET_PATH_TRAVERSAL',\n `Asset path contains path traversal (\"../\"). Got \"${resolved}\".`,\n errorPath,\n ),\n );\n } else if (assetError === 'INVALID_ASSET_PATH') {\n errors.push(\n createError(\n 'INVALID_ASSET_PATH',\n `Asset path must start with \"@assets/\". Got \"${resolved}\".`,\n errorPath,\n ),\n );\n }\n }\n}\n\nfunction pushUniqueError(\n errors: ValidationError[],\n seen: Set<string>,\n error: ValidationError,\n): void {\n const key = `${error.code}|${error.path}|${error.message}`;\n if (seen.has(key)) {\n return;\n }\n seen.add(key);\n errors.push(error);\n}\n\nfunction getScannableNodeFields(\n node: TraversableNode,\n): Record<string, unknown> {\n const nodeFields = { ...node } as Record<string, unknown>;\n delete nodeFields.type;\n delete nodeFields.style;\n delete nodeFields.children;\n\n const interactiveField =\n node.type === 'Accordion'\n ? 'items'\n : node.type === 'Tabs'\n ? 'tabs'\n : null;\n\n if (interactiveField && Array.isArray(node[interactiveField])) {\n nodeFields[interactiveField] = node[interactiveField].map((item) => {\n if (\n item == null ||\n typeof item !== 'object' ||\n Array.isArray(item)\n ) {\n return item;\n }\n\n const { content: _content, ...rest } = item as Record<string, unknown>;\n return rest;\n });\n }\n\n return nodeFields;\n}\n\nfunction scanStyleStringsForUrl(\n style: Record<string, unknown> | undefined,\n path: string,\n errors: ValidationError[],\n): void {\n if (!style) {\n return;\n }\n\n for (const [prop, value] of Object.entries(style)) {\n if (typeof value === 'string' && value.toLowerCase().includes('url(')) {\n errors.push(\n createError(\n 'FORBIDDEN_CSS_FUNCTION',\n `CSS url() function is forbidden in style values. Found in \"${prop}\".`,\n `${path}.${prop}`,\n ),\n );\n }\n }\n}\n\nfunction validateEffectiveStylesForMode(\n mode: ResponsiveMode,\n views: Record<string, unknown>,\n cardStyles: Record<string, Record<string, unknown>> | undefined,\n fragments: Record<string, unknown> | undefined,\n errors: ValidationError[],\n seen: Set<string>,\n): void {\n const styleResolver = (node: TraversableNode) =>\n getEffectiveStyleForMode(node, cardStyles, mode);\n\n traverseCard(views, (node: TraversableNode, context: TraversalContext) => {\n const effectiveStyle = styleResolver(node);\n\n if (effectiveStyle && typeof effectiveStyle.position === 'string') {\n const position = effectiveStyle.position;\n\n if (position === 'fixed') {\n pushUniqueError(\n errors,\n seen,\n createError(\n 'POSITION_FIXED_FORBIDDEN',\n 'CSS position \"fixed\" is not allowed.',\n `${context.path}.style.position`,\n ),\n );\n } else if (position === 'sticky') {\n pushUniqueError(\n errors,\n seen,\n createError(\n 'POSITION_STICKY_FORBIDDEN',\n 'CSS position \"sticky\" is not allowed.',\n `${context.path}.style.position`,\n ),\n );\n } else if (position === 'absolute' && context.parentType !== 'Stack') {\n pushUniqueError(\n errors,\n seen,\n createError(\n 'POSITION_ABSOLUTE_NOT_IN_STACK',\n 'CSS position \"absolute\" is only allowed inside a Stack component.',\n `${context.path}.style.position`,\n ),\n );\n }\n }\n\n if (\n effectiveStyle &&\n effectiveStyle.overflow === 'auto' &&\n context.overflowAutoAncestor\n ) {\n pushUniqueError(\n errors,\n seen,\n createError(\n 'OVERFLOW_AUTO_NESTED',\n 'Nested overflow:auto is not allowed. An ancestor already has overflow:auto.',\n `${context.path}.style.overflow`,\n ),\n );\n }\n }, styleResolver, fragments);\n}\n\n// ---------------------------------------------------------------------------\n// validateSecurity\n// ---------------------------------------------------------------------------\n\n/**\n * Run all security validation rules against every node in every view.\n *\n * Rules checked (spec sections 3 and 8):\n * 1. External URL blocking on Image/Avatar `src` (literal and $ref)\n * 2. Asset path validation\n * 3. cardAssets value validation\n * 4. Forbidden CSS `url()` in style string values\n * 5. Position restrictions (fixed, sticky, absolute outside Stack)\n * 6. Nested overflow:auto\n * 7. Prototype pollution in $ref paths\n *\n * @param card - Object containing `views`, optional `state`, and optional `cardAssets`.\n * @returns An array of validation errors (empty if all rules pass).\n */\nexport function validateSecurity(card: {\n views: Record<string, unknown>;\n state?: Record<string, unknown>;\n cardAssets?: Record<string, string>;\n cardStyles?: Record<string, Record<string, unknown>>;\n fragments?: Record<string, unknown>;\n}): ValidationError[] {\n const errors: ValidationError[] = [];\n const seen = new Set<string>();\n const { views, state, cardAssets, cardStyles, fragments } = card;\n\n // -----------------------------------------------------------------\n // 0. Validate cardAssets values\n // -----------------------------------------------------------------\n if (cardAssets) {\n for (const [key, value] of Object.entries(cardAssets)) {\n const assetError = validateAssetPath(value);\n if (assetError === 'ASSET_PATH_TRAVERSAL') {\n errors.push(\n createError(\n 'ASSET_PATH_TRAVERSAL',\n `Asset path contains path traversal (\"../\"). Got \"${value}\".`,\n `assets.${key}`,\n ),\n );\n } else if (assetError === 'INVALID_ASSET_PATH') {\n errors.push(\n createError(\n 'INVALID_ASSET_PATH',\n `Asset path must start with \"@assets/\". Got \"${value}\".`,\n `assets.${key}`,\n ),\n );\n }\n }\n }\n\n walkRenderableCard(views, fragments, (node, context) => {\n if (!('type' in node) || typeof node.type !== 'string') {\n return;\n }\n\n const traversableNode = node as TraversableNode;\n const { path } = context;\n const style =\n traversableNode.style != null &&\n typeof traversableNode.style === 'object' &&\n !Array.isArray(traversableNode.style)\n ? traversableNode.style as Record<string, unknown>\n : undefined;\n const type = traversableNode.type;\n const nodeFields = getScannableNodeFields(traversableNode);\n\n // -----------------------------------------------------------------\n // 1. External URL blocking — Image and Avatar `src`\n // -----------------------------------------------------------------\n if (type === 'Image' || type === 'Avatar') {\n const src = (node as Record<string, unknown>).src;\n if (typeof src === 'string') {\n // Literal string src\n checkSrcValue(src, type, `${path}.src`, errors);\n } else if (isRef(src)) {\n // $ref src — resolve from state if available\n if (state) {\n const resolved = resolveRefFromState(\n (src as { $ref: string }).$ref,\n state,\n );\n if (typeof resolved === 'string') {\n checkSrcValue(resolved, type, `${path}.src`, errors);\n }\n // If resolution fails (undefined), skip — may be a loop-local variable\n }\n // If no state provided, skip $ref resolution\n }\n }\n\n // -----------------------------------------------------------------\n // 2. Scan all style string values for `url()` pattern\n // -----------------------------------------------------------------\n scanStyleStringsForUrl(style, `${path}.style`, errors);\n\n const responsive = traversableNode.responsive;\n if (\n responsive != null &&\n typeof responsive === 'object' &&\n !Array.isArray(responsive)\n ) {\n for (const mode of RESPONSIVE_OVERRIDE_KEYS) {\n const override = (responsive as Record<string, unknown>)[mode];\n if (\n override != null &&\n typeof override === 'object' &&\n !Array.isArray(override)\n ) {\n scanStyleStringsForUrl(\n override as Record<string, unknown>,\n `${path}.responsive.${mode}`,\n errors,\n );\n }\n }\n }\n\n if (type === 'Text' && Array.isArray((traversableNode as Record<string, unknown>).spans)) {\n const spans = (traversableNode as Record<string, unknown>).spans as unknown[];\n for (let i = 0; i < spans.length; i++) {\n const span = spans[i];\n if (\n span == null ||\n typeof span !== 'object' ||\n Array.isArray(span)\n ) {\n continue;\n }\n\n const spanStyle = (span as Record<string, unknown>).style;\n if (\n spanStyle != null &&\n typeof spanStyle === 'object' &&\n !Array.isArray(spanStyle)\n ) {\n scanStyleStringsForUrl(\n spanStyle as Record<string, unknown>,\n `${path}.spans[${i}].style`,\n errors,\n );\n }\n }\n }\n\n // -----------------------------------------------------------------\n // 3. Prototype pollution check on $ref values in node fields and style\n // -----------------------------------------------------------------\n scanForRefs(nodeFields, path, errors);\n if (style) {\n scanForRefs(style, `${path}.style`, errors);\n }\n if (\n responsive != null &&\n typeof responsive === 'object' &&\n !Array.isArray(responsive)\n ) {\n scanForRefs(responsive, `${path}.responsive`, errors);\n }\n });\n\n for (const mode of RESPONSIVE_MODES) {\n validateEffectiveStylesForMode(mode, views, cardStyles, fragments, errors, seen);\n }\n\n return errors;\n}\n","import type { TraversableNode } from './traverse.js';\n\nexport type ResponsiveMode = 'default' | 'medium' | 'compact';\n\nexport const RESPONSIVE_MODES: readonly ResponsiveMode[] = [\n 'default',\n 'medium',\n 'compact',\n] as const;\n\nfunction mergeNamedStyle(\n style: Record<string, unknown> | undefined,\n cardStyles: Record<string, Record<string, unknown>> | undefined,\n): Record<string, unknown> | undefined {\n if (!style) return undefined;\n\n const rawStyleName = style.$style;\n const styleName = typeof rawStyleName === 'string' ? rawStyleName.trim() : rawStyleName;\n if (!styleName || typeof styleName !== 'string' || !cardStyles) {\n if (style.$style !== undefined) {\n const { $style: _, ...rest } = style;\n return rest;\n }\n return style;\n }\n\n const baseStyle = cardStyles[styleName];\n if (!baseStyle) {\n const { $style: _, ...rest } = style;\n return rest;\n }\n\n const { $style: _, ...inlineWithoutStyleRef } = style;\n return { ...baseStyle, ...inlineWithoutStyleRef };\n}\n\nfunction getResponsiveStyle(\n node: TraversableNode,\n mode: Exclude<ResponsiveMode, 'default'>,\n): Record<string, unknown> | undefined {\n const responsive = node.responsive;\n if (\n responsive == null ||\n typeof responsive !== 'object' ||\n Array.isArray(responsive)\n ) {\n return undefined;\n }\n\n const override = (responsive as Record<string, unknown>)[mode];\n if (\n override == null ||\n typeof override !== 'object' ||\n Array.isArray(override)\n ) {\n return undefined;\n }\n\n return override as Record<string, unknown>;\n}\n\nfunction stripResponsiveOnlyUnsupportedFields(\n style: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined {\n if (!style) return undefined;\n\n const {\n hoverStyle: _hoverStyle,\n transition: _transition,\n ...rest\n } = style;\n\n return rest;\n}\n\nexport function getEffectiveStyleForMode(\n node: TraversableNode,\n cardStyles: Record<string, Record<string, unknown>> | undefined,\n mode: ResponsiveMode,\n): Record<string, unknown> | undefined {\n const baseStyle = mergeNamedStyle(node.style, cardStyles);\n if (mode === 'default') {\n return baseStyle;\n }\n\n const mediumStyle = stripResponsiveOnlyUnsupportedFields(\n mergeNamedStyle(getResponsiveStyle(node, 'medium'), cardStyles),\n );\n\n if (mode === 'medium') {\n if (!mediumStyle) {\n return baseStyle;\n }\n\n return {\n ...(baseStyle ?? {}),\n ...mediumStyle,\n };\n }\n\n const compactStyle = stripResponsiveOnlyUnsupportedFields(\n mergeNamedStyle(getResponsiveStyle(node, 'compact'), cardStyles),\n );\n\n if (!mediumStyle && !compactStyle) {\n return baseStyle;\n }\n\n return {\n ...(baseStyle ?? {}),\n ...(mediumStyle ?? {}),\n ...compactStyle,\n };\n}\n\nexport function getMergedResponsiveStyleOverride(\n node: TraversableNode,\n cardStyles: Record<string, Record<string, unknown>> | undefined,\n mode: Exclude<ResponsiveMode, 'default'>,\n): Record<string, unknown> | undefined {\n return mergeNamedStyle(getResponsiveStyle(node, mode), cardStyles);\n}\n","/**\n * @safe-ugc-ui/validator — Resource Limits Validation\n *\n * Validates resource limits per spec section 6.\n *\n * Uses a single traversal pass to collect all metrics (node count,\n * text content size, style object size, loop iterations, nested loops,\n * overflow:auto count, and stack nesting), then checks each against the\n * defined constants from @safe-ugc-ui/types.\n */\n\nimport {\n TEXT_CONTENT_TOTAL_MAX_BYTES,\n STYLE_OBJECTS_TOTAL_MAX_BYTES,\n MAX_NODE_COUNT,\n MAX_LOOP_ITERATIONS,\n MAX_NESTED_LOOPS,\n MAX_OVERFLOW_AUTO_COUNT,\n MAX_STACK_NESTING,\n PROTOTYPE_POLLUTION_SEGMENTS,\n} from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\nimport { type TraversableNode, type TraversalContext, traverseCard } from './traverse.js';\nimport {\n type ResponsiveMode,\n RESPONSIVE_MODES,\n getEffectiveStyleForMode,\n getMergedResponsiveStyleOverride,\n} from './responsive-utils.js';\n\n// ---------------------------------------------------------------------------\n// UTF-8 byte length — platform-agnostic (no DOM/Node dependency)\n// ---------------------------------------------------------------------------\n\n/**\n * Calculate UTF-8 byte length of a string without depending on\n * TextEncoder (DOM) or Buffer (Node).\n */\nfunction utf8ByteLength(str: string): number {\n let bytes = 0;\n for (let i = 0; i < str.length; i++) {\n const code = str.charCodeAt(i);\n if (code <= 0x7f) {\n bytes += 1;\n } else if (code <= 0x7ff) {\n bytes += 2;\n } else if (code >= 0xd800 && code <= 0xdbff) {\n // Surrogate pair → 4 UTF-8 bytes\n bytes += 4;\n i++; // skip low surrogate\n } else {\n bytes += 3;\n }\n }\n return bytes;\n}\n\nfunction isTemplateObject(\n value: unknown,\n): value is { $template: unknown[] } {\n return (\n typeof value === 'object' &&\n value !== null &&\n '$template' in value &&\n Array.isArray((value as Record<string, unknown>).$template)\n );\n}\n\nfunction countLiteralTemplatedStringBytes(value: unknown): number {\n if (typeof value === 'string') {\n return utf8ByteLength(value);\n }\n\n if (!isTemplateObject(value)) {\n return 0;\n }\n\n return value.$template.reduce((total: number, part): number => {\n if (typeof part === 'string') {\n return total + utf8ByteLength(part);\n }\n if (\n typeof part === 'number' ||\n typeof part === 'boolean' ||\n part === null\n ) {\n return total + utf8ByteLength(String(part));\n }\n return total;\n }, 0);\n}\n\nfunction countTextNodeLiteralBytes(node: Record<string, unknown>): number {\n if (Array.isArray(node.spans)) {\n return node.spans.reduce((total, span) => {\n if (\n span == null ||\n typeof span !== 'object' ||\n Array.isArray(span)\n ) {\n return total;\n }\n\n return total + countLiteralTemplatedStringBytes(\n (span as Record<string, unknown>).text,\n );\n }, 0);\n }\n\n return countLiteralTemplatedStringBytes(node.content);\n}\n\nfunction countTextSpanStyleBytes(node: Record<string, unknown>): number {\n if (!Array.isArray(node.spans)) {\n return 0;\n }\n\n return node.spans.reduce((total, span) => {\n if (\n span == null ||\n typeof span !== 'object' ||\n Array.isArray(span)\n ) {\n return total;\n }\n\n const style = (span as Record<string, unknown>).style;\n if (\n style == null ||\n typeof style !== 'object' ||\n Array.isArray(style)\n ) {\n return total;\n }\n\n return total + utf8ByteLength(JSON.stringify(style));\n }, 0);\n}\n\n// ---------------------------------------------------------------------------\n// Helper: resolveRefFromState — resolve dotted $ref paths against state\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a $ref path against a state object. Supports dotted paths and\n * bracket notation (e.g. \"$data.items[0].name\").\n *\n * @returns The resolved value, or `undefined` if resolution fails.\n */\nfunction resolveRefFromState(\n refPath: string,\n state: Record<string, unknown>,\n): unknown {\n // Strip leading $\n const path = refPath.startsWith('$') ? refPath.slice(1) : refPath;\n const dotSegments = path.split('.');\n\n // Flatten dot-segments into individual traversal keys,\n // expanding bracket notation (e.g. \"items[0][1]\" -> [\"items\", \"0\", \"1\"])\n const keys: string[] = [];\n for (const dotSeg of dotSegments) {\n const bracketPattern = /\\[(\\d+)\\]/g;\n const firstBracket = dotSeg.indexOf('[');\n const baseName = firstBracket === -1 ? dotSeg : dotSeg.slice(0, firstBracket);\n if (baseName) {\n keys.push(baseName);\n }\n let match: RegExpExecArray | null;\n while ((match = bracketPattern.exec(dotSeg)) !== null) {\n keys.push(match[1]);\n }\n }\n\n // Block prototype pollution\n for (const key of keys) {\n if (\n (PROTOTYPE_POLLUTION_SEGMENTS as readonly string[]).includes(key)\n ) {\n return undefined;\n }\n }\n\n // Traverse state\n let current: unknown = state;\n for (const key of keys) {\n if (current == null || typeof current !== 'object') return undefined;\n\n if (Array.isArray(current)) {\n const index = Number(key);\n if (!Number.isInteger(index) || index < 0) return undefined;\n current = current[index];\n } else {\n current = (current as Record<string, unknown>)[key];\n }\n }\n return current;\n}\n\n// ---------------------------------------------------------------------------\n// countTemplateMetrics — measure resource usage of a for-loop template\n// ---------------------------------------------------------------------------\n\ninterface TemplateMetrics {\n nodes: number;\n textBytes: number;\n styleBytes: number;\n overflowAutoCount: Record<ResponsiveMode, number>;\n}\n\n/**\n * Recursively count metrics for a for-loop template subtree.\n * Used to multiply metrics by (arrayLength - 1) since the traversal\n * already counts the template once.\n */\nfunction countTemplateMetrics(\n template: unknown,\n cardStyles?: Record<string, Record<string, unknown>>,\n fragments?: Record<string, unknown>,\n): TemplateMetrics {\n const result: TemplateMetrics = {\n nodes: 0,\n textBytes: 0,\n styleBytes: 0,\n overflowAutoCount: {\n default: 0,\n medium: 0,\n compact: 0,\n },\n };\n\n traverseCard(\n { __template: template },\n (node: TraversableNode) => {\n result.nodes += 1;\n\n if (node.type === 'Text') {\n result.textBytes += countTextNodeLiteralBytes(node as Record<string, unknown>);\n result.styleBytes += countTextSpanStyleBytes(node as Record<string, unknown>);\n }\n\n const baseStyleForBytes = getEffectiveStyleForMode(\n node,\n cardStyles,\n 'default',\n );\n if (baseStyleForBytes) {\n result.styleBytes += utf8ByteLength(JSON.stringify(baseStyleForBytes));\n }\n\n for (const mode of ['medium', 'compact'] as const) {\n const responsiveStyleForBytes = getMergedResponsiveStyleOverride(\n node,\n cardStyles,\n mode,\n );\n if (responsiveStyleForBytes) {\n result.styleBytes += utf8ByteLength(JSON.stringify(responsiveStyleForBytes));\n }\n }\n\n for (const mode of RESPONSIVE_MODES) {\n const effectiveStyle = getEffectiveStyleForMode(node, cardStyles, mode);\n if (effectiveStyle?.overflow === 'auto') {\n result.overflowAutoCount[mode]++;\n }\n }\n },\n undefined,\n fragments,\n );\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// validateLimits\n// ---------------------------------------------------------------------------\n\n/**\n * Validate all resource limits defined in spec section 6.\n *\n * Performs a single traversal of the card tree, collecting metrics for:\n * - Total node count\n * - Total text content bytes (UTF-8)\n * - Total style object bytes (UTF-8, JSON-serialized)\n * - Loop iteration counts\n * - Nested loop depth\n * - overflow:auto element count\n * - Stack nesting depth\n *\n * @param card - A card object with optional `state` and required `views`.\n * @returns An array of validation errors (empty if all limits are satisfied).\n */\nexport function validateLimits(\n card: {\n state?: Record<string, unknown>;\n views: Record<string, unknown>;\n cardStyles?: Record<string, Record<string, unknown>>;\n fragments?: Record<string, unknown>;\n },\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n let nodeCount = 0;\n let textContentBytes = 0;\n let styleObjectsBytes = 0;\n const overflowAutoCount: Record<ResponsiveMode, number> = {\n default: 0,\n medium: 0,\n compact: 0,\n };\n\n traverseCard(card.views, (node: TraversableNode, context: TraversalContext) => {\n // -----------------------------------------------------------------------\n // 1. Node count\n // -----------------------------------------------------------------------\n nodeCount++;\n\n // -----------------------------------------------------------------------\n // 2. Text content total bytes\n // -----------------------------------------------------------------------\n if (node.type === 'Text') {\n textContentBytes += countTextNodeLiteralBytes(node as Record<string, unknown>);\n styleObjectsBytes += countTextSpanStyleBytes(node as Record<string, unknown>);\n }\n\n // -----------------------------------------------------------------------\n // 3. Style objects total bytes (use merged style if $style is present)\n // -----------------------------------------------------------------------\n {\n const baseStyleForBytes = getEffectiveStyleForMode(\n node,\n card.cardStyles,\n 'default',\n );\n if (baseStyleForBytes) {\n styleObjectsBytes += utf8ByteLength(JSON.stringify(baseStyleForBytes));\n }\n\n for (const mode of ['medium', 'compact'] as const) {\n const responsiveStyleForBytes = getMergedResponsiveStyleOverride(\n node,\n card.cardStyles,\n mode,\n );\n if (responsiveStyleForBytes) {\n styleObjectsBytes += utf8ByteLength(JSON.stringify(responsiveStyleForBytes));\n }\n }\n }\n\n // -----------------------------------------------------------------------\n // 4. Loop iterations\n // -----------------------------------------------------------------------\n const children = node.children;\n if (\n children != null &&\n typeof children === 'object' &&\n !Array.isArray(children) &&\n 'for' in children &&\n 'in' in children &&\n 'template' in children\n ) {\n const forLoop = children as { for: string; in: string; template: unknown };\n const inValue = forLoop.in;\n\n if (typeof inValue === 'string' && inValue.startsWith('$')) {\n if (card.state == null) {\n // No state — loop source may be provided at runtime, skip validation\n } else {\n const source = resolveRefFromState(inValue, card.state);\n if (source === undefined) {\n // Single-segment path (e.g. \"$items\") at top-level (loopDepth 0)\n // must be a state key. If missing, likely a typo → report error.\n // Dotted paths or paths inside nested loops may reference\n // locals variables → skip.\n const pathAfterDollar = inValue.slice(1);\n if (!pathAfterDollar.includes('.') && context.loopDepth === 0) {\n errors.push(\n createError(\n 'LOOP_SOURCE_MISSING',\n `Loop source \"${inValue}\" not found in card state`,\n `${context.path}.children`,\n ),\n );\n }\n } else if (!Array.isArray(source)) {\n errors.push(\n createError(\n 'LOOP_SOURCE_NOT_ARRAY',\n `Loop source \"${inValue}\" is not an array`,\n `${context.path}.children`,\n ),\n );\n } else if (source.length > MAX_LOOP_ITERATIONS) {\n errors.push(\n createError(\n 'LOOP_ITERATIONS_EXCEEDED',\n `Loop source \"${inValue}\" has ${source.length} items, max is ${MAX_LOOP_ITERATIONS}`,\n `${context.path}.children`,\n ),\n );\n } else if (source.length > 1) {\n // Multiply template metrics by (N - 1) since traversal already\n // counts the template once\n const tplMetrics = countTemplateMetrics(forLoop.template, card.cardStyles, card.fragments);\n const multiplier = source.length - 1;\n nodeCount += tplMetrics.nodes * multiplier;\n textContentBytes += tplMetrics.textBytes * multiplier;\n styleObjectsBytes += tplMetrics.styleBytes * multiplier;\n for (const mode of RESPONSIVE_MODES) {\n overflowAutoCount[mode] += tplMetrics.overflowAutoCount[mode] * multiplier;\n }\n }\n }\n }\n\n // -------------------------------------------------------------------\n // 5. Nested loops\n // -------------------------------------------------------------------\n if (context.loopDepth >= MAX_NESTED_LOOPS) {\n errors.push(\n createError(\n 'NESTED_LOOPS_EXCEEDED',\n `Loop nesting depth ${context.loopDepth + 1} exceeds maximum of ${MAX_NESTED_LOOPS}`,\n `${context.path}.children`,\n ),\n );\n }\n }\n\n // -----------------------------------------------------------------------\n // 6. overflow: auto count (use merged style if $style is present)\n // -----------------------------------------------------------------------\n for (const mode of RESPONSIVE_MODES) {\n const effectiveStyle = getEffectiveStyleForMode(node, card.cardStyles, mode);\n if (effectiveStyle?.overflow === 'auto') {\n overflowAutoCount[mode]++;\n }\n }\n\n // -----------------------------------------------------------------------\n // 7. Stack nesting\n // -----------------------------------------------------------------------\n if (node.type === 'Stack' && context.stackDepth >= MAX_STACK_NESTING) {\n errors.push(\n createError(\n 'STACK_NESTING_EXCEEDED',\n `Stack nesting depth ${context.stackDepth + 1} exceeds maximum of ${MAX_STACK_NESTING}`,\n context.path,\n ),\n );\n }\n }, undefined, card.fragments);\n\n // -------------------------------------------------------------------------\n // Post-traversal aggregate checks\n // -------------------------------------------------------------------------\n\n if (nodeCount > MAX_NODE_COUNT) {\n errors.push(\n createError(\n 'NODE_COUNT_EXCEEDED',\n `Card has ${nodeCount} nodes, max is ${MAX_NODE_COUNT}`,\n 'views',\n ),\n );\n }\n\n if (textContentBytes > TEXT_CONTENT_TOTAL_MAX_BYTES) {\n errors.push(\n createError(\n 'TEXT_CONTENT_SIZE_EXCEEDED',\n `Total text content is ${textContentBytes} bytes, max is ${TEXT_CONTENT_TOTAL_MAX_BYTES}`,\n 'views',\n ),\n );\n }\n\n if (styleObjectsBytes > STYLE_OBJECTS_TOTAL_MAX_BYTES) {\n errors.push(\n createError(\n 'STYLE_SIZE_EXCEEDED',\n `Total style objects size is ${styleObjectsBytes} bytes, max is ${STYLE_OBJECTS_TOTAL_MAX_BYTES}`,\n 'views',\n ),\n );\n }\n\n const maxOverflowAutoCount = Math.max(\n overflowAutoCount.default,\n overflowAutoCount.compact,\n );\n\n if (maxOverflowAutoCount > MAX_OVERFLOW_AUTO_COUNT) {\n errors.push(\n createError(\n 'OVERFLOW_AUTO_COUNT_EXCEEDED',\n `Card has ${maxOverflowAutoCount} elements with overflow:auto in at least one responsive mode, max is ${MAX_OVERFLOW_AUTO_COUNT}`,\n 'views',\n ),\n );\n }\n\n return errors;\n}\n"],"mappings":"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","names":["isRef","RESPONSIVE_OVERRIDE_KEYS","isRef","isRef","RESPONSIVE_OVERRIDE_KEYS","isRef","_","RESPONSIVE_OVERRIDE_KEYS","isRef","PROTOTYPE_POLLUTION_SEGMENTS","resolveRefFromState","PROTOTYPE_POLLUTION_SEGMENTS","utf8ByteLength"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@safe-ugc-ui/validator",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Security validator for Safe UGC UI card JSON",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -21,7 +21,7 @@
21
21
  "dist"
22
22
  ],
23
23
  "dependencies": {
24
- "@safe-ugc-ui/types": "1.0.0"
24
+ "@safe-ugc-ui/types": "1.1.0"
25
25
  },
26
26
  "devDependencies": {},
27
27
  "scripts": {