@safe-ugc-ui/validator 0.1.0 → 0.3.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.d.ts +1 -1
- package/dist/index.js +101 -1
- package/dist/index.js.map +1 -1
- package/package.json +8 -10
- package/LICENSE +0 -21
package/dist/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { UGCCard } from '@safe-ugc-ui/types';
|
|
|
14
14
|
/**
|
|
15
15
|
* Machine-readable error codes for every validation failure type.
|
|
16
16
|
*/
|
|
17
|
-
type ValidationErrorCode = 'INVALID_JSON' | 'MISSING_FIELD' | 'INVALID_TYPE' | 'INVALID_VALUE' | 'UNKNOWN_NODE_TYPE' | 'SCHEMA_ERROR' | 'EXPR_NOT_ALLOWED' | 'REF_NOT_ALLOWED' | 'DYNAMIC_NOT_ALLOWED' | 'FORBIDDEN_STYLE_PROPERTY' | 'STYLE_VALUE_OUT_OF_RANGE' | 'FORBIDDEN_CSS_FUNCTION' | 'INVALID_COLOR' | 'INVALID_LENGTH' | 'FORBIDDEN_OVERFLOW_VALUE' | 'TRANSFORM_SKEW_FORBIDDEN' | 'EXTERNAL_URL' | 'POSITION_FIXED_FORBIDDEN' | 'POSITION_STICKY_FORBIDDEN' | 'POSITION_ABSOLUTE_NOT_IN_STACK' | 'ASSET_PATH_TRAVERSAL' | 'INVALID_ASSET_PATH' | 'PROTOTYPE_POLLUTION' | 'CARD_SIZE_EXCEEDED' | 'TEXT_CONTENT_SIZE_EXCEEDED' | 'STYLE_SIZE_EXCEEDED' | 'NODE_COUNT_EXCEEDED' | 'LOOP_ITERATIONS_EXCEEDED' | 'NESTED_LOOPS_EXCEEDED' | 'OVERFLOW_AUTO_COUNT_EXCEEDED' | 'OVERFLOW_AUTO_NESTED' | 'STACK_NESTING_EXCEEDED' | 'EXPR_TOO_LONG' | 'REF_TOO_LONG' | 'EXPR_TOO_MANY_TOKENS' | 'EXPR_NESTING_TOO_DEEP' | 'EXPR_CONDITION_NESTING_TOO_DEEP' | 'EXPR_REF_DEPTH_EXCEEDED' | 'EXPR_ARRAY_INDEX_EXCEEDED' | 'EXPR_STRING_LITERAL_TOO_LONG' | 'EXPR_FORBIDDEN_TOKEN' | 'EXPR_FUNCTION_CALL' | 'EXPR_INVALID_TOKEN' | 'LOOP_SOURCE_NOT_ARRAY' | 'LOOP_SOURCE_MISSING' | 'STYLE_CIRCULAR_REF' | 'STYLE_REF_NOT_FOUND' | 'INVALID_STYLE_REF' | 'INVALID_STYLE_NAME';
|
|
17
|
+
type ValidationErrorCode = 'INVALID_JSON' | 'MISSING_FIELD' | 'INVALID_TYPE' | 'INVALID_VALUE' | 'UNKNOWN_NODE_TYPE' | 'SCHEMA_ERROR' | 'EXPR_NOT_ALLOWED' | 'REF_NOT_ALLOWED' | 'DYNAMIC_NOT_ALLOWED' | 'FORBIDDEN_STYLE_PROPERTY' | 'STYLE_VALUE_OUT_OF_RANGE' | 'FORBIDDEN_CSS_FUNCTION' | 'INVALID_COLOR' | 'INVALID_LENGTH' | 'FORBIDDEN_OVERFLOW_VALUE' | 'TRANSFORM_SKEW_FORBIDDEN' | 'EXTERNAL_URL' | 'POSITION_FIXED_FORBIDDEN' | 'POSITION_STICKY_FORBIDDEN' | 'POSITION_ABSOLUTE_NOT_IN_STACK' | 'ASSET_PATH_TRAVERSAL' | 'INVALID_ASSET_PATH' | 'PROTOTYPE_POLLUTION' | 'CARD_SIZE_EXCEEDED' | 'TEXT_CONTENT_SIZE_EXCEEDED' | 'STYLE_SIZE_EXCEEDED' | 'NODE_COUNT_EXCEEDED' | 'LOOP_ITERATIONS_EXCEEDED' | 'NESTED_LOOPS_EXCEEDED' | 'OVERFLOW_AUTO_COUNT_EXCEEDED' | 'OVERFLOW_AUTO_NESTED' | 'STACK_NESTING_EXCEEDED' | 'EXPR_TOO_LONG' | 'REF_TOO_LONG' | 'EXPR_TOO_MANY_TOKENS' | 'EXPR_NESTING_TOO_DEEP' | 'EXPR_CONDITION_NESTING_TOO_DEEP' | 'EXPR_REF_DEPTH_EXCEEDED' | 'EXPR_ARRAY_INDEX_EXCEEDED' | 'EXPR_STRING_LITERAL_TOO_LONG' | 'EXPR_FORBIDDEN_TOKEN' | 'EXPR_FUNCTION_CALL' | 'EXPR_INVALID_TOKEN' | 'LOOP_SOURCE_NOT_ARRAY' | 'LOOP_SOURCE_MISSING' | 'STYLE_CIRCULAR_REF' | 'STYLE_REF_NOT_FOUND' | 'INVALID_STYLE_REF' | 'INVALID_STYLE_NAME' | 'INVALID_HOVER_STYLE' | 'HOVER_STYLE_NESTED' | 'TRANSITION_RAW_STRING' | 'TRANSITION_COUNT_EXCEEDED' | 'TRANSITION_PROPERTY_FORBIDDEN';
|
|
18
18
|
/**
|
|
19
19
|
* A single validation error with location and diagnostic info.
|
|
20
20
|
*/
|
package/dist/index.js
CHANGED
|
@@ -373,6 +373,10 @@ import {
|
|
|
373
373
|
OPACITY_MIN,
|
|
374
374
|
OPACITY_MAX,
|
|
375
375
|
CSS_NAMED_COLORS,
|
|
376
|
+
TRANSITION_DURATION_MAX,
|
|
377
|
+
TRANSITION_DELAY_MAX,
|
|
378
|
+
TRANSITION_MAX_COUNT,
|
|
379
|
+
ALLOWED_TRANSITION_PROPERTIES,
|
|
376
380
|
isRef as isRef2,
|
|
377
381
|
isExpr as isExpr2
|
|
378
382
|
} from "@safe-ugc-ui/types";
|
|
@@ -521,8 +525,9 @@ function validateShadowObject(shadow, path, errors) {
|
|
|
521
525
|
}
|
|
522
526
|
var STYLE_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
523
527
|
function validateSingleStyle(style, stylePath, errors) {
|
|
528
|
+
const STRUCTURED_FIELDS = /* @__PURE__ */ new Set(["transition", "hoverStyle"]);
|
|
524
529
|
for (const key of Object.keys(style)) {
|
|
525
|
-
if (FORBIDDEN_STYLE_PROPERTIES.includes(key)) {
|
|
530
|
+
if (!STRUCTURED_FIELDS.has(key) && FORBIDDEN_STYLE_PROPERTIES.includes(key)) {
|
|
526
531
|
errors.push(
|
|
527
532
|
createError(
|
|
528
533
|
"FORBIDDEN_STYLE_PROPERTY",
|
|
@@ -782,6 +787,101 @@ function validateSingleStyle(style, stylePath, errors) {
|
|
|
782
787
|
}
|
|
783
788
|
}
|
|
784
789
|
}
|
|
790
|
+
if ("hoverStyle" in style && style.hoverStyle != null) {
|
|
791
|
+
const hoverStyle = style.hoverStyle;
|
|
792
|
+
const hoverPath = `${stylePath}.hoverStyle`;
|
|
793
|
+
if (typeof hoverStyle !== "object" || Array.isArray(hoverStyle)) {
|
|
794
|
+
errors.push(
|
|
795
|
+
createError(
|
|
796
|
+
"INVALID_HOVER_STYLE",
|
|
797
|
+
`hoverStyle must be an object at "${hoverPath}"`,
|
|
798
|
+
hoverPath
|
|
799
|
+
)
|
|
800
|
+
);
|
|
801
|
+
} else {
|
|
802
|
+
const hoverObj = hoverStyle;
|
|
803
|
+
if ("hoverStyle" in hoverObj) {
|
|
804
|
+
errors.push(
|
|
805
|
+
createError(
|
|
806
|
+
"HOVER_STYLE_NESTED",
|
|
807
|
+
`Nested hoverStyle is forbidden at "${hoverPath}.hoverStyle"`,
|
|
808
|
+
`${hoverPath}.hoverStyle`
|
|
809
|
+
)
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
if ("$style" in hoverObj) {
|
|
813
|
+
errors.push(
|
|
814
|
+
createError(
|
|
815
|
+
"INVALID_STYLE_REF",
|
|
816
|
+
`$style is not allowed inside hoverStyle at "${hoverPath}.$style"`,
|
|
817
|
+
`${hoverPath}.$style`
|
|
818
|
+
)
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
validateSingleStyle(hoverObj, hoverPath, errors);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
if ("transition" in style && style.transition != null) {
|
|
825
|
+
const transition = style.transition;
|
|
826
|
+
const transPath = `${stylePath}.transition`;
|
|
827
|
+
if (typeof transition === "string") {
|
|
828
|
+
errors.push(
|
|
829
|
+
createError(
|
|
830
|
+
"TRANSITION_RAW_STRING",
|
|
831
|
+
`transition must be an object or array, not a string at "${transPath}"`,
|
|
832
|
+
transPath
|
|
833
|
+
)
|
|
834
|
+
);
|
|
835
|
+
} else {
|
|
836
|
+
const transitions = Array.isArray(transition) ? transition : [transition];
|
|
837
|
+
if (transitions.length > TRANSITION_MAX_COUNT) {
|
|
838
|
+
errors.push(
|
|
839
|
+
createError(
|
|
840
|
+
"TRANSITION_COUNT_EXCEEDED",
|
|
841
|
+
`transition has ${transitions.length} entries, maximum is ${TRANSITION_MAX_COUNT} at "${transPath}"`,
|
|
842
|
+
transPath
|
|
843
|
+
)
|
|
844
|
+
);
|
|
845
|
+
}
|
|
846
|
+
for (let i = 0; i < transitions.length; i++) {
|
|
847
|
+
const t = transitions[i];
|
|
848
|
+
const tPath = Array.isArray(transition) ? `${transPath}[${i}]` : transPath;
|
|
849
|
+
if (typeof t !== "object" || t === null) continue;
|
|
850
|
+
const tObj = t;
|
|
851
|
+
if (isLiteralString(tObj.property) && !ALLOWED_TRANSITION_PROPERTIES.includes(tObj.property)) {
|
|
852
|
+
errors.push(
|
|
853
|
+
createError(
|
|
854
|
+
"TRANSITION_PROPERTY_FORBIDDEN",
|
|
855
|
+
`transition property "${tObj.property}" is not in the allowed list at "${tPath}.property"`,
|
|
856
|
+
`${tPath}.property`
|
|
857
|
+
)
|
|
858
|
+
);
|
|
859
|
+
}
|
|
860
|
+
if (isLiteralNumber(tObj.duration)) {
|
|
861
|
+
if (tObj.duration < 0 || tObj.duration > TRANSITION_DURATION_MAX) {
|
|
862
|
+
errors.push(
|
|
863
|
+
createError(
|
|
864
|
+
"STYLE_VALUE_OUT_OF_RANGE",
|
|
865
|
+
`transition duration (${tObj.duration}) must be between 0 and ${TRANSITION_DURATION_MAX} at "${tPath}.duration"`,
|
|
866
|
+
`${tPath}.duration`
|
|
867
|
+
)
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
if (isLiteralNumber(tObj.delay)) {
|
|
872
|
+
if (tObj.delay < 0 || tObj.delay > TRANSITION_DELAY_MAX) {
|
|
873
|
+
errors.push(
|
|
874
|
+
createError(
|
|
875
|
+
"STYLE_VALUE_OUT_OF_RANGE",
|
|
876
|
+
`transition delay (${tObj.delay}) must be between 0 and ${TRANSITION_DELAY_MAX} at "${tPath}.delay"`,
|
|
877
|
+
`${tPath}.delay`
|
|
878
|
+
)
|
|
879
|
+
);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
785
885
|
}
|
|
786
886
|
function mergeStyleWithRef(cardStyleEntry, inlineStyle) {
|
|
787
887
|
const merged = { ...cardStyleEntry };
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/result.ts","../src/schema.ts","../src/node-validator.ts","../src/traverse.ts","../src/value-types.ts","../src/style-validator.ts","../src/security.ts","../src/limits.ts","../src/expr-constraints.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 → expr-constraints\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 { validateNodes } from './node-validator.js';\nimport { validateValueTypes } from './value-types.js';\nimport { validateStyles } from './style-validator.js';\nimport { validateSecurity } from './security.js';\nimport { validateLimits } from './limits.js';\nimport { validateExprConstraints } from './expr-constraints.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 TraversalContext,\n type TraversableNode,\n type NodeVisitor,\n traverseNode,\n traverseCard,\n} from './traverse.js';\n\nexport { validateSchema, parseCard } from './schema.js';\nexport { validateNodes } from './node-validator.js';\nexport { validateValueTypes } from './value-types.js';\nexport { validateStyles } from './style-validator.js';\nexport { validateSecurity } from './security.js';\nexport { validateLimits } from './limits.js';\nexport { validateExprConstraints } from './expr-constraints.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 };\n const views = obj.views as Record<string, unknown>;\n const cardStyles = obj.styles as Record<string, Record<string, unknown>> | undefined;\n const errors: ValidationError[] = [];\n\n errors.push(...validateNodes(views));\n errors.push(...validateValueTypes(views));\n errors.push(...validateStyles(views, cardStyles));\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 }));\n errors.push(...validateLimits({ state: obj.state as Record<string, unknown> | undefined, views, cardStyles }));\n errors.push(...validateExprConstraints(views));\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, expr)\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 | 'EXPR_NOT_ALLOWED'\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 // Expression constraints\n | 'EXPR_TOO_LONG'\n | 'REF_TOO_LONG'\n | 'EXPR_TOO_MANY_TOKENS'\n | 'EXPR_NESTING_TOO_DEEP'\n | 'EXPR_CONDITION_NESTING_TOO_DEEP'\n | 'EXPR_REF_DEPTH_EXCEEDED'\n | 'EXPR_ARRAY_INDEX_EXCEEDED'\n | 'EXPR_STRING_LITERAL_TOO_LONG'\n | 'EXPR_FORBIDDEN_TOKEN'\n | 'EXPR_FUNCTION_CALL'\n | 'EXPR_INVALID_TOKEN'\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\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 — 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 } from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\nimport {\n type TraversableNode,\n type TraversalContext,\n traverseCard,\n} 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 Text: ['content'],\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};\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)\n ) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n 'ForLoop \"template\" must be an object with a \"type\" property.',\n `${path}.children.template`,\n ),\n );\n }\n\n return errors;\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 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 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): ValidationError[] {\n const errors: ValidationError[] = [];\n\n traverseCard(views, (node: TraversableNode, context: TraversalContext) => {\n errors.push(...validateNode(node, context));\n });\n\n return errors;\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?: TraversableNode[] | ForLoopLike;\n style?: Record<string, unknown>;\n condition?: unknown;\n [key: string]: unknown;\n}\n\ninterface ForLoopLike {\n for: string;\n in: string;\n template: TraversableNode;\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\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\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: TraversableNode,\n context: TraversalContext,\n visitor: NodeVisitor,\n): void {\n const result = visitor(node, context);\n\n // If visitor returns false, skip children.\n if (result === false) {\n return;\n }\n\n const children = node.children;\n if (children == null) {\n return;\n }\n\n const nextStackDepth =\n node.type === 'Stack' ? context.stackDepth + 1 : context.stackDepth;\n const nextOverflowAuto =\n context.overflowAutoAncestor || hasOverflowAuto(node.style);\n\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: node.type,\n loopDepth: context.loopDepth + 1,\n overflowAutoAncestor: nextOverflowAuto,\n stackDepth: nextStackDepth,\n };\n traverseNode(children.template, childCtx, visitor);\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 (child && typeof child === 'object' && 'type' in child) {\n const childCtx: TraversalContext = {\n path: `${context.path}.children[${i}]`,\n depth: context.depth + 1,\n parentType: node.type,\n loopDepth: context.loopDepth,\n overflowAutoAncestor: nextOverflowAuto,\n stackDepth: nextStackDepth,\n };\n traverseNode(child as TraversableNode, childCtx, visitor);\n }\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): void {\n for (const [viewName, rootNode] of Object.entries(views)) {\n if (\n rootNode == null ||\n typeof rootNode !== 'object' ||\n !('type' in rootNode)\n ) {\n continue;\n }\n\n const context: TraversalContext = {\n path: `views.${viewName}`,\n depth: 0,\n parentType: null,\n loopDepth: 0,\n overflowAutoAncestor: false,\n stackDepth: 0,\n };\n\n traverseNode(rootNode as TraversableNode, context, visitor);\n }\n}\n","/**\n * @safe-ugc-ui/validator — Value Type Validation\n *\n * Validates per-property $ref / $expr permission rules based on spec\n * section 4.5 value type table.\n *\n * | Property Type | Literal | $ref | $expr |\n * |-------------------|---------|------|-------|\n * | Image.src | yes | yes | no |\n * | Avatar.src | yes | yes | no |\n * | Icon.name | yes | no | no |\n * | Text.content | yes | yes | yes |\n * | Color properties | yes | yes | yes |\n * | Size properties | yes | yes | yes |\n * | position | yes | no | no |\n * | transform | yes | no | no |\n * | gradient | yes | no | no |\n *\n * Additionally, several style properties must always be static\n * (no $ref or $expr): overflow, border*, boxShadow, zIndex,\n * and position offset properties (top/right/bottom/left).\n */\n\nimport { isRef, isExpr } from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\nimport {\n type TraversableNode,\n type TraversalContext,\n traverseCard,\n} from './traverse.js';\n\n// ---------------------------------------------------------------------------\n// Style properties that must always be static (no $ref / $expr)\n// ---------------------------------------------------------------------------\n\n/**\n * Style properties where any dynamic binding ($ref or $expr) 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 // Transform\n 'transform',\n\n // Gradient\n 'backgroundGradient',\n\n // Overflow\n 'overflow',\n\n // Borders\n 'border',\n 'borderTop',\n 'borderRight',\n 'borderBottom',\n 'borderLeft',\n\n // Shadow\n 'boxShadow',\n\n // Stacking\n 'zIndex',\n]);\n\n// ---------------------------------------------------------------------------\n// Per-node field validation\n// ---------------------------------------------------------------------------\n\n/**\n * Validate component fields according to the value type table.\n */\nfunction validateNodeFields(\n node: TraversableNode,\n ctx: TraversalContext,\n errors: ValidationError[],\n): void {\n const nodeType = node.type;\n\n // Image.src / Avatar.src — $ref allowed, $expr forbidden\n if (nodeType === 'Image' || nodeType === 'Avatar') {\n const src = (node as Record<string, unknown>).src;\n if (src !== undefined && isExpr(src)) {\n errors.push(\n createError(\n 'EXPR_NOT_ALLOWED',\n `${nodeType}.src does not allow $expr bindings.`,\n `${ctx.path}.src`,\n ),\n );\n }\n }\n\n // Icon.name — neither $ref nor $expr allowed\n if (nodeType === 'Icon') {\n const name = (node as Record<string, unknown>).name;\n if (name !== undefined && isRef(name)) {\n errors.push(\n createError(\n 'REF_NOT_ALLOWED',\n 'Icon.name does not allow $ref bindings.',\n `${ctx.path}.name`,\n ),\n );\n }\n if (name !== undefined && isExpr(name)) {\n errors.push(\n createError(\n 'EXPR_NOT_ALLOWED',\n 'Icon.name does not allow $expr bindings.',\n `${ctx.path}.name`,\n ),\n );\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Per-node style validation\n// ---------------------------------------------------------------------------\n\n/**\n * Validate the `style` of a node according to the value type table.\n */\nfunction validateNodeStyle(\n node: TraversableNode,\n ctx: TraversalContext,\n errors: ValidationError[],\n): void {\n const style = node.style;\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 (STATIC_ONLY_STYLE_PROPERTIES.has(prop)) {\n if (isRef(value) || isExpr(value)) {\n errors.push(\n createError(\n 'DYNAMIC_NOT_ALLOWED',\n `Style property \"${prop}\" must be a static literal; $ref and $expr are not allowed.`,\n `${ctx.path}.style.${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 / $expr 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): ValidationError[] {\n const errors: ValidationError[] = [];\n\n traverseCard(views, (node: TraversableNode, ctx: TraversalContext) => {\n validateNodeFields(node, ctx, errors);\n validateNodeStyle(node, ctx, errors);\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 * - 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 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 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 isRef,\n isExpr,\n} from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\nimport { type TraversableNode, type TraversalContext, traverseCard } from './traverse.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\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Returns true only if the value is a literal number (not a $ref or $expr).\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 or $expr).\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 or $expr) that should\n * be skipped for static range checks.\n */\nfunction isDynamic(value: unknown): boolean {\n return isRef(value) || isExpr(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\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 and $expr 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 / $expr objects — they are not user-authored strings\n if (isRef(value) || isExpr(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// Regex for valid $style references and style names\n// ---------------------------------------------------------------------------\n\nconst STYLE_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*$/;\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. 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. Border color validation\n * 11. Background gradient stop color validation\n */\nfunction validateSingleStyle(\n style: Record<string, unknown>,\n stylePath: string,\n errors: ValidationError[],\n): void {\n // ------------------------------------------------------------------\n // 1. Forbidden properties (spec 3.8)\n // ------------------------------------------------------------------\n for (const key of Object.keys(style)) {\n if (\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 // ------------------------------------------------------------------\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 // 5. 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 // 6. 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 // 7. 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 // 8. 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 // ------------------------------------------------------------------\n // 9. 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 // 10. 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 // 11. 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// ---------------------------------------------------------------------------\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): 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 inside card.styles definitions (circular ref)\n if ('$style' in styleEntry) {\n errors.push(\n createError(\n 'STYLE_CIRCULAR_REF',\n `$style cannot be used inside card.styles definitions at \"${entryPath}.$style\"`,\n `${entryPath}.$style`,\n ),\n );\n }\n\n // Run all per-style validations on this entry\n validateSingleStyle(styleEntry, entryPath, errors);\n }\n }\n\n // ------------------------------------------------------------------\n // Phase 1: Validate per-node styles (with $style merging)\n // ------------------------------------------------------------------\n traverseCard(views, (node: TraversableNode, ctx: TraversalContext) => {\n const style = node.style;\n if (style == null || typeof style !== 'object') {\n return;\n }\n\n const stylePath = `${ctx.path}.style`;\n\n // Check for $style reference\n if ('$style' in style && typeof style.$style === 'string') {\n const rawRef = style.$style;\n const trimmedRef = rawRef.trim();\n\n // Validate $style value format\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;\n }\n\n // Check that the referenced style exists\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;\n }\n\n // Merge: card.styles[name] as base, inline styles (minus $style) as overrides\n const mergedStyle = mergeStyleWithRef(cardStyles[trimmedRef], style);\n\n // Validate the merged result\n validateSingleStyle(mergedStyle, stylePath, errors);\n } else {\n // No $style — validate the inline style directly\n validateSingleStyle(style, stylePath, errors);\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';\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\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}): ValidationError[] {\n const errors: ValidationError[] = [];\n const { views, state, cardAssets, cardStyles } = 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 traverseCard(views, (node: TraversableNode, context: TraversalContext) => {\n const { path } = context;\n const { style, type } = node;\n const nodeFields = { ...node } as Record<string, unknown>;\n delete nodeFields.type;\n delete nodeFields.style;\n delete nodeFields.children;\n delete nodeFields.condition;\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 if (style) {\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}.style.${prop}`,\n ),\n );\n }\n }\n }\n\n // -----------------------------------------------------------------\n // 3. Position rules (use merged style if $style is present)\n // -----------------------------------------------------------------\n // Build effective style by merging with card.styles if $style is present\n let effectiveStyle = style;\n if (\n style &&\n typeof style.$style === 'string' &&\n cardStyles &&\n style.$style.trim() in cardStyles\n ) {\n const refName = style.$style.trim();\n const merged: Record<string, unknown> = { ...cardStyles[refName] };\n for (const [key, value] of Object.entries(style)) {\n if (key !== '$style') {\n merged[key] = value;\n }\n }\n effectiveStyle = merged;\n }\n\n if (effectiveStyle && typeof effectiveStyle.position === 'string') {\n const position = effectiveStyle.position;\n\n if (position === 'fixed') {\n errors.push(\n createError(\n 'POSITION_FIXED_FORBIDDEN',\n 'CSS position \"fixed\" is not allowed.',\n `${path}.style.position`,\n ),\n );\n } else if (position === 'sticky') {\n errors.push(\n createError(\n 'POSITION_STICKY_FORBIDDEN',\n 'CSS position \"sticky\" is not allowed.',\n `${path}.style.position`,\n ),\n );\n } else if (position === 'absolute') {\n if (context.parentType !== 'Stack') {\n errors.push(\n createError(\n 'POSITION_ABSOLUTE_NOT_IN_STACK',\n 'CSS position \"absolute\" is only allowed inside a Stack component.',\n `${path}.style.position`,\n ),\n );\n }\n }\n }\n\n // -----------------------------------------------------------------\n // 4. Overflow auto nesting (use merged style)\n // -----------------------------------------------------------------\n if (\n effectiveStyle &&\n effectiveStyle.overflow === 'auto' &&\n context.overflowAutoAncestor\n ) {\n errors.push(\n createError(\n 'OVERFLOW_AUTO_NESTED',\n 'Nested overflow:auto is not allowed. An ancestor already has overflow:auto.',\n `${path}.style.overflow`,\n ),\n );\n }\n\n // -----------------------------------------------------------------\n // 5. 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 });\n\n return errors;\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 isRef,\n isExpr,\n} from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\nimport { type TraversableNode, type TraversalContext, traverseCard } from './traverse.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\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: 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): TemplateMetrics {\n const result: TemplateMetrics = { nodes: 0, textBytes: 0, styleBytes: 0, overflowAutoCount: 0 };\n if (template == null || typeof template !== 'object') return result;\n\n const node = template as Record<string, unknown>;\n if (!node.type) return result;\n\n result.nodes = 1;\n\n // Text bytes\n if (node.type === 'Text') {\n const content = (node as Record<string, unknown>).content;\n if (typeof content === 'string' && !isRef(content) && !isExpr(content)) {\n result.textBytes = utf8ByteLength(content);\n }\n }\n\n // Style bytes (merged with $style)\n if (node.style != null && typeof node.style === 'object') {\n const style = node.style as Record<string, unknown>;\n let styleForBytes = style;\n if (\n typeof style.$style === 'string' &&\n cardStyles &&\n style.$style.trim() in cardStyles\n ) {\n const refName = (style.$style as string).trim();\n const merged: Record<string, unknown> = { ...cardStyles[refName] };\n for (const [key, value] of Object.entries(style)) {\n if (key !== '$style') merged[key] = value;\n }\n styleForBytes = merged;\n }\n result.styleBytes = utf8ByteLength(JSON.stringify(styleForBytes));\n\n // Overflow auto\n let effectiveOverflow = style.overflow;\n if (\n typeof style.$style === 'string' &&\n cardStyles &&\n style.$style.trim() in cardStyles\n ) {\n const refName = (style.$style as string).trim();\n if (!('overflow' in style) || style.overflow === undefined) {\n effectiveOverflow = cardStyles[refName].overflow;\n }\n }\n if (effectiveOverflow === 'auto') {\n result.overflowAutoCount = 1;\n }\n }\n\n // Recurse into children\n const children = node.children;\n if (Array.isArray(children)) {\n for (const child of children) {\n const childMetrics = countTemplateMetrics(child, cardStyles);\n result.nodes += childMetrics.nodes;\n result.textBytes += childMetrics.textBytes;\n result.styleBytes += childMetrics.styleBytes;\n result.overflowAutoCount += childMetrics.overflowAutoCount;\n }\n } else if (\n children != null &&\n typeof children === 'object' &&\n !Array.isArray(children) &&\n 'template' in (children as Record<string, unknown>)\n ) {\n // Nested for-loop: count the template once (inner loop expansion\n // can't be calculated without knowing the inner array length)\n const innerTemplate = (children as Record<string, unknown>).template;\n const innerMetrics = countTemplateMetrics(innerTemplate, cardStyles);\n result.nodes += innerMetrics.nodes;\n result.textBytes += innerMetrics.textBytes;\n result.styleBytes += innerMetrics.styleBytes;\n result.overflowAutoCount += innerMetrics.overflowAutoCount;\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: { state?: Record<string, unknown>; views: Record<string, unknown>; cardStyles?: Record<string, Record<string, unknown>> },\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n let nodeCount = 0;\n let textContentBytes = 0;\n let styleObjectsBytes = 0;\n let overflowAutoCount = 0;\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 const content = (node as Record<string, unknown>).content;\n if (typeof content === 'string' && !isRef(content) && !isExpr(content)) {\n textContentBytes += utf8ByteLength(content);\n }\n }\n\n // -----------------------------------------------------------------------\n // 3. Style objects total bytes (use merged style if $style is present)\n // -----------------------------------------------------------------------\n if (node.style != null && typeof node.style === 'object') {\n let styleForBytes = node.style;\n if (\n typeof node.style.$style === 'string' &&\n card.cardStyles &&\n node.style.$style.trim() in card.cardStyles\n ) {\n const refName = node.style.$style.trim();\n const merged: Record<string, unknown> = { ...card.cardStyles[refName] };\n for (const [key, value] of Object.entries(node.style)) {\n if (key !== '$style') {\n merged[key] = value;\n }\n }\n styleForBytes = merged;\n }\n const serialized = JSON.stringify(styleForBytes);\n styleObjectsBytes += utf8ByteLength(serialized);\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);\n const multiplier = source.length - 1;\n nodeCount += tplMetrics.nodes * multiplier;\n textContentBytes += tplMetrics.textBytes * multiplier;\n styleObjectsBytes += tplMetrics.styleBytes * multiplier;\n overflowAutoCount += tplMetrics.overflowAutoCount * multiplier;\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 {\n let effectiveOverflow = node.style?.overflow;\n if (\n node.style &&\n typeof node.style.$style === 'string' &&\n card.cardStyles &&\n node.style.$style.trim() in card.cardStyles\n ) {\n const refName = node.style.$style.trim();\n // Inline overflow takes precedence; if not set, use card.styles value\n if (!('overflow' in node.style) || node.style.overflow === undefined) {\n effectiveOverflow = card.cardStyles[refName].overflow as string | undefined;\n }\n }\n if (effectiveOverflow === 'auto') {\n overflowAutoCount++;\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 });\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 if (overflowAutoCount > MAX_OVERFLOW_AUTO_COUNT) {\n errors.push(\n createError(\n 'OVERFLOW_AUTO_COUNT_EXCEEDED',\n `Card has ${overflowAutoCount} elements with overflow:auto, max is ${MAX_OVERFLOW_AUTO_COUNT}`,\n 'views',\n ),\n );\n }\n\n return errors;\n}\n","/**\n * @safe-ugc-ui/validator -- Expression & Reference Constraint Validation\n *\n * Validates $expr and $ref values found in the card tree against the\n * constraints defined in the spec's \"expression constraint\" section (6.3).\n *\n * A simple tokenizer splits expression strings into typed tokens so that\n * structural limits (nesting, token count, forbidden operators) can be\n * checked without executing the expression.\n */\n\nimport {\n EXPR_MAX_LENGTH,\n EXPR_MAX_TOKENS,\n EXPR_MAX_NESTING,\n EXPR_MAX_CONDITION_NESTING,\n EXPR_MAX_REF_DEPTH,\n EXPR_MAX_ARRAY_INDEX,\n EXPR_MAX_STRING_LITERAL,\n EXPR_MAX_FRACTIONAL_DIGITS,\n isRef,\n isExpr,\n} from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\nimport { type TraversableNode, type TraversalContext, traverseCard } from './traverse.js';\n\n// ---------------------------------------------------------------------------\n// Token types\n// ---------------------------------------------------------------------------\n\ntype TokenType =\n | 'identifier'\n | 'number'\n | 'string'\n | 'boolean'\n | 'arithmetic'\n | 'comparison'\n | 'logic_keyword'\n | 'condition_keyword'\n | 'separator';\n\ninterface Token {\n type: TokenType;\n value: string;\n position: number;\n}\n\n// ---------------------------------------------------------------------------\n// Forbidden tokens\n// ---------------------------------------------------------------------------\n\nconst FORBIDDEN_KEYWORDS = [\n 'typeof',\n 'instanceof',\n 'new',\n 'delete',\n 'function',\n 'return',\n 'var',\n 'let',\n 'const',\n] as const;\n\nconst FORBIDDEN_KEYWORD_SET = new Set<string>(FORBIDDEN_KEYWORDS);\n\n// ---------------------------------------------------------------------------\n// Prototype pollution segments\n// ---------------------------------------------------------------------------\n\nconst PROTOTYPE_POLLUTION_SEGMENTS = new Set([\n '__proto__',\n 'constructor',\n 'prototype',\n]);\n\n// ---------------------------------------------------------------------------\n// Tokenizer\n// ---------------------------------------------------------------------------\n\nfunction tokenize(\n expr: string,\n path: string,\n): { tokens: Token[]; errors: ValidationError[] } {\n const tokens: Token[] = [];\n const errors: ValidationError[] = [];\n let i = 0;\n\n while (i < expr.length) {\n // 1. Skip whitespace\n if (/\\s/.test(expr[i])) {\n i++;\n continue;\n }\n\n // 2. Three-char operators (must check before two-char)\n if (i + 2 < expr.length) {\n const three = expr.slice(i, i + 3);\n if (three === '===' || three === '!==') {\n tokens.push({ type: 'comparison', value: three, position: i });\n i += 3;\n continue;\n }\n }\n\n // 3. Two-char operators\n if (i + 1 < expr.length) {\n const two = expr.slice(i, i + 2);\n if (two === '==' || two === '!=' || two === '<=' || two === '>=') {\n tokens.push({ type: 'comparison', value: two, position: i });\n i += 2;\n continue;\n }\n if (two === '&&' || two === '||') {\n tokens.push({ type: 'logic_keyword', value: two, position: i });\n i += 2;\n continue;\n }\n }\n\n // 4. String literals\n if (expr[i] === \"'\" || expr[i] === '\"') {\n const quote = expr[i];\n let j = i + 1;\n while (j < expr.length && expr[j] !== quote) {\n // Allow escaped quotes\n if (expr[j] === '\\\\' && j + 1 < expr.length) {\n j += 2;\n } else {\n j++;\n }\n }\n // j now points to the closing quote (or end of string)\n const innerValue = expr.slice(i + 1, j);\n tokens.push({ type: 'string', value: innerValue, position: i });\n i = j + 1;\n continue;\n }\n\n // 5. Numbers: optional leading `-` for negative, digits, optional `.` + digits\n // Only treat `-` as part of a number if:\n // - it's at the start of the expression, OR\n // - the previous non-whitespace token is NOT a number, identifier, string,\n // boolean, or closing separator (i.e. it follows an operator or opening paren)\n if (/[0-9]/.test(expr[i]) || (expr[i] === '-' && i + 1 < expr.length && /[0-9]/.test(expr[i + 1]) && isNegativeSign(tokens))) {\n let j = i;\n if (expr[j] === '-') j++;\n while (j < expr.length && /[0-9]/.test(expr[j])) j++;\n if (j < expr.length && expr[j] === '.') {\n j++;\n while (j < expr.length && /[0-9]/.test(expr[j])) j++;\n }\n const numStr = expr.slice(i, j);\n // Check fractional digits\n const dotIdx = numStr.indexOf('.');\n if (dotIdx !== -1) {\n const fractionalPart = numStr.slice(dotIdx + 1);\n if (fractionalPart.length > EXPR_MAX_FRACTIONAL_DIGITS) {\n errors.push(\n createError(\n 'EXPR_INVALID_TOKEN',\n `Number literal \"${numStr}\" at position ${i} has ${fractionalPart.length} fractional digits, maximum is ${EXPR_MAX_FRACTIONAL_DIGITS}.`,\n path,\n ),\n );\n }\n }\n tokens.push({ type: 'number', value: numStr, position: i });\n i = j;\n continue;\n }\n\n // 6. Identifiers: `$` followed by word chars, or plain word chars\n if (expr[i] === '$' || /[a-zA-Z_]/.test(expr[i])) {\n let j = i;\n if (expr[j] === '$') j++;\n while (j < expr.length && /[\\w]/.test(expr[j])) j++;\n const word = expr.slice(i, j);\n\n if (word === 'true' || word === 'false') {\n tokens.push({ type: 'boolean', value: word, position: i });\n } else if (word === 'and' || word === 'or' || word === 'not') {\n tokens.push({ type: 'logic_keyword', value: word, position: i });\n } else if (word === 'if' || word === 'then' || word === 'else') {\n tokens.push({ type: 'condition_keyword', value: word, position: i });\n } else {\n tokens.push({ type: 'identifier', value: word, position: i });\n }\n i = j;\n continue;\n }\n\n // 7. Single-char operators and separators\n const ch = expr[i];\n if ('+-*/%'.includes(ch)) {\n tokens.push({ type: 'arithmetic', value: ch, position: i });\n i++;\n continue;\n }\n if (ch === '<' || ch === '>') {\n tokens.push({ type: 'comparison', value: ch, position: i });\n i++;\n continue;\n }\n if ('().[]'.includes(ch)) {\n tokens.push({ type: 'separator', value: ch, position: i });\n i++;\n continue;\n }\n if (ch === '!') {\n // Standalone `!` (not part of `!=` which was already handled)\n tokens.push({ type: 'comparison', value: ch, position: i });\n i++;\n continue;\n }\n\n // 8. Unrecognized character\n errors.push(\n createError(\n 'EXPR_INVALID_TOKEN',\n `Unrecognized character \"${ch}\" at position ${i} in expression.`,\n path,\n ),\n );\n i++;\n }\n\n // --- Post-tokenization: check for forbidden tokens ---\n\n for (let t = 0; t < tokens.length; t++) {\n const tok = tokens[t];\n\n // Forbidden JS operators: ===, !==, &&, ||\n if (\n (tok.value === '===' || tok.value === '!==') ||\n (tok.value === '&&' || tok.value === '||')\n ) {\n errors.push(\n createError(\n 'EXPR_FORBIDDEN_TOKEN',\n `Forbidden operator \"${tok.value}\" at position ${tok.position}. Use \"==\" / \"!=\" or \"and\" / \"or\" instead.`,\n path,\n ),\n );\n }\n\n // Standalone `!` (not part of `!=`)\n if (tok.value === '!') {\n errors.push(\n createError(\n 'EXPR_FORBIDDEN_TOKEN',\n `Forbidden operator \"!\" at position ${tok.position}. Use \"not\" instead.`,\n path,\n ),\n );\n }\n\n // Forbidden keywords\n if (tok.type === 'identifier' && FORBIDDEN_KEYWORD_SET.has(tok.value)) {\n errors.push(\n createError(\n 'EXPR_FORBIDDEN_TOKEN',\n `Forbidden keyword \"${tok.value}\" at position ${tok.position}.`,\n path,\n ),\n );\n }\n\n // Bare identifiers without $ prefix\n if (tok.type === 'identifier' && !tok.value.startsWith('$') && !FORBIDDEN_KEYWORD_SET.has(tok.value)) {\n errors.push(\n createError(\n 'EXPR_FORBIDDEN_TOKEN',\n `Identifier \"${tok.value}\" at position ${tok.position} must start with \"$\". Use \"$${tok.value}\" for variable references.`,\n path,\n ),\n );\n }\n\n // Function call pattern: identifier followed by `(`\n if (tok.type === 'identifier') {\n // Look ahead past any whitespace (already skipped during tokenization,\n // so the next token is the actual next non-whitespace token)\n const next = tokens[t + 1];\n if (next && next.type === 'separator' && next.value === '(') {\n errors.push(\n createError(\n 'EXPR_FUNCTION_CALL',\n `Function call pattern detected: \"${tok.value}(\" at position ${tok.position}. Function calls are not allowed.`,\n path,\n ),\n );\n }\n }\n }\n\n return { tokens, errors };\n}\n\n/**\n * Determines whether a `-` character should be interpreted as a negative sign\n * (unary minus for a negative number literal) rather than a subtraction operator.\n *\n * A `-` is a negative sign when there is no preceding token, or the preceding\n * token is an operator, opening paren, or opening bracket.\n */\nfunction isNegativeSign(tokens: Token[]): boolean {\n if (tokens.length === 0) return true;\n const prev = tokens[tokens.length - 1];\n if (\n prev.type === 'arithmetic' ||\n prev.type === 'comparison' ||\n prev.type === 'logic_keyword' ||\n prev.type === 'condition_keyword'\n ) {\n return true;\n }\n if (prev.type === 'separator' && (prev.value === '(' || prev.value === '[')) {\n return true;\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Deep scan helper\n// ---------------------------------------------------------------------------\n\n/**\n * Recursively walks an object/array structure to find all $ref and $expr\n * values, calling the callback for each one found.\n */\nfunction scanForDynamicValues(\n obj: unknown,\n basePath: string,\n callback: (value: unknown, path: string) => void,\n): void {\n if (obj === null || obj === undefined || typeof obj !== 'object') {\n return;\n }\n\n // Check if this object itself is a $ref or $expr\n if (isRef(obj) || isExpr(obj)) {\n callback(obj, basePath);\n return;\n }\n\n if (Array.isArray(obj)) {\n for (let i = 0; i < obj.length; i++) {\n scanForDynamicValues(obj[i], `${basePath}[${i}]`, callback);\n }\n } else {\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n scanForDynamicValues(value, `${basePath}.${key}`, callback);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// $ref validation\n// ---------------------------------------------------------------------------\n\nfunction validateRef(refValue: string, path: string): ValidationError[] {\n const errors: ValidationError[] = [];\n\n // 1. Length check\n if (refValue.length > 500) {\n errors.push(\n createError(\n 'REF_TOO_LONG',\n `$ref value exceeds maximum length of 500 characters (got ${refValue.length}).`,\n path,\n ),\n );\n }\n\n // 2. Ref depth: split by `.` segments\n const segments = refValue.split('.');\n if (segments.length > EXPR_MAX_REF_DEPTH) {\n errors.push(\n createError(\n 'EXPR_REF_DEPTH_EXCEEDED',\n `$ref path depth ${segments.length} exceeds maximum of ${EXPR_MAX_REF_DEPTH}.`,\n path,\n ),\n );\n }\n\n // 3. Array index check: find [N] patterns\n const arrayIndexPattern = /\\[(\\d+)\\]/g;\n let match: RegExpExecArray | null;\n while ((match = arrayIndexPattern.exec(refValue)) !== null) {\n const index = parseInt(match[1], 10);\n if (index > EXPR_MAX_ARRAY_INDEX) {\n errors.push(\n createError(\n 'EXPR_ARRAY_INDEX_EXCEEDED',\n `Array index ${index} in $ref exceeds maximum of ${EXPR_MAX_ARRAY_INDEX}.`,\n path,\n ),\n );\n }\n }\n\n // 4. Prototype pollution segments\n // Extract plain segment names (strip array index suffixes)\n for (const segment of segments) {\n const cleanSegment = segment.replace(/\\[\\d+\\]/g, '');\n if (PROTOTYPE_POLLUTION_SEGMENTS.has(cleanSegment)) {\n errors.push(\n createError(\n 'PROTOTYPE_POLLUTION',\n `$ref path contains forbidden segment \"${cleanSegment}\".`,\n path,\n ),\n );\n }\n }\n\n return errors;\n}\n\n// ---------------------------------------------------------------------------\n// $expr validation\n// ---------------------------------------------------------------------------\n\nfunction validateExpr(exprValue: string, path: string): ValidationError[] {\n const errors: ValidationError[] = [];\n\n // 1. Length check\n if (exprValue.length > EXPR_MAX_LENGTH) {\n errors.push(\n createError(\n 'EXPR_TOO_LONG',\n `Expression exceeds maximum length of ${EXPR_MAX_LENGTH} characters (got ${exprValue.length}).`,\n path,\n ),\n );\n }\n\n // 2. Tokenize\n const { tokens, errors: tokenErrors } = tokenize(exprValue, path);\n errors.push(...tokenErrors);\n\n // 3. Token count\n if (tokens.length > EXPR_MAX_TOKENS) {\n errors.push(\n createError(\n 'EXPR_TOO_MANY_TOKENS',\n `Expression has ${tokens.length} tokens, exceeding maximum of ${EXPR_MAX_TOKENS}.`,\n path,\n ),\n );\n }\n\n // 4. String literal lengths\n for (const tok of tokens) {\n if (tok.type === 'string' && tok.value.length > EXPR_MAX_STRING_LITERAL) {\n errors.push(\n createError(\n 'EXPR_STRING_LITERAL_TOO_LONG',\n `String literal at position ${tok.position} has ${tok.value.length} characters, exceeding maximum of ${EXPR_MAX_STRING_LITERAL}.`,\n path,\n ),\n );\n }\n }\n\n // 5. Nesting depth (parentheses) and condition nesting (if keywords)\n let parenDepth = 0;\n let maxParenDepth = 0;\n let ifCount = 0;\n\n for (const tok of tokens) {\n if (tok.type === 'separator' && tok.value === '(') {\n parenDepth++;\n if (parenDepth > maxParenDepth) {\n maxParenDepth = parenDepth;\n }\n } else if (tok.type === 'separator' && tok.value === ')') {\n parenDepth--;\n } else if (tok.type === 'condition_keyword' && tok.value === 'if') {\n ifCount++;\n }\n }\n\n if (maxParenDepth > EXPR_MAX_NESTING) {\n errors.push(\n createError(\n 'EXPR_NESTING_TOO_DEEP',\n `Expression parenthesis nesting depth ${maxParenDepth} exceeds maximum of ${EXPR_MAX_NESTING}.`,\n path,\n ),\n );\n }\n\n if (ifCount > EXPR_MAX_CONDITION_NESTING) {\n errors.push(\n createError(\n 'EXPR_CONDITION_NESTING_TOO_DEEP',\n `Expression has ${ifCount} nested if-conditions, exceeding maximum of ${EXPR_MAX_CONDITION_NESTING}.`,\n path,\n ),\n );\n }\n\n // 6. Variable reference depth inside expr: $identifier followed by `.` segments\n for (let t = 0; t < tokens.length; t++) {\n const tok = tokens[t];\n if (tok.type === 'identifier' && tok.value.startsWith('$')) {\n // Count consecutive `.identifier` sequences\n let depth = 1; // The $identifier itself counts as depth 1\n let j = t + 1;\n while (j + 1 < tokens.length) {\n if (\n tokens[j].type === 'separator' &&\n tokens[j].value === '.' &&\n tokens[j + 1].type === 'identifier'\n ) {\n depth++;\n j += 2;\n } else {\n break;\n }\n }\n if (depth > EXPR_MAX_REF_DEPTH) {\n errors.push(\n createError(\n 'EXPR_REF_DEPTH_EXCEEDED',\n `Variable reference \"${tok.value}\" has path depth ${depth}, exceeding maximum of ${EXPR_MAX_REF_DEPTH}.`,\n path,\n ),\n );\n }\n }\n }\n\n // 7. Array indices in tokens: `[` number `]` patterns\n for (let t = 0; t + 2 < tokens.length; t++) {\n if (\n tokens[t].type === 'separator' &&\n tokens[t].value === '[' &&\n tokens[t + 1].type === 'number' &&\n tokens[t + 2].type === 'separator' &&\n tokens[t + 2].value === ']'\n ) {\n const indexValue = parseFloat(tokens[t + 1].value);\n if (indexValue > EXPR_MAX_ARRAY_INDEX) {\n errors.push(\n createError(\n 'EXPR_ARRAY_INDEX_EXCEEDED',\n `Array index ${indexValue} in expression exceeds maximum of ${EXPR_MAX_ARRAY_INDEX}.`,\n path,\n ),\n );\n }\n }\n }\n\n return errors;\n}\n\n// ---------------------------------------------------------------------------\n// Main entry point\n// ---------------------------------------------------------------------------\n\n/**\n * Validates all $expr and $ref values found in the card's views.\n *\n * Uses tree traversal to visit every node, then deep-scans each node's\n * flattened node fields and `style` (and `condition`) for dynamic values.\n *\n * @param views - The `views` object from a UGCCard.\n * @returns An array of validation errors (empty if all constraints pass).\n */\nexport function validateExprConstraints(\n views: Record<string, unknown>,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n traverseCard(views, (node: TraversableNode, context: TraversalContext) => {\n // Scan node fields (excluding style/children/type/condition)\n const nodeFields = { ...node } as Record<string, unknown>;\n delete nodeFields.type;\n delete nodeFields.style;\n delete nodeFields.children;\n delete nodeFields.condition;\n scanForDynamicValues(nodeFields, context.path, (value, valuePath) => {\n if (isRef(value)) {\n errors.push(...validateRef(value.$ref, valuePath));\n } else if (isExpr(value)) {\n errors.push(...validateExpr(value.$expr, valuePath));\n }\n });\n\n // Scan style\n if (node.style) {\n scanForDynamicValues(node.style, `${context.path}.style`, (value, valuePath) => {\n if (isRef(value)) {\n errors.push(...validateRef(value.$ref, valuePath));\n } else if (isExpr(value)) {\n errors.push(...validateExpr(value.$expr, valuePath));\n }\n });\n }\n\n // Scan condition\n if (node.condition !== undefined) {\n scanForDynamicValues(node.condition, `${context.path}.condition`, (value, valuePath) => {\n if (isRef(value)) {\n errors.push(...validateRef(value.$ref, valuePath));\n } else if (isExpr(value)) {\n errors.push(...validateExpr(value.$expr, valuePath));\n }\n });\n }\n });\n\n return errors;\n}\n"],"mappings":"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","names":["isRef","isExpr","isRef","isExpr","isRef","isRef","PROTOTYPE_POLLUTION_SEGMENTS","isRef","isExpr","resolveRefFromState","PROTOTYPE_POLLUTION_SEGMENTS","isRef","isExpr","isRef","isExpr","PROTOTYPE_POLLUTION_SEGMENTS","isRef","isExpr","utf8ByteLength"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/result.ts","../src/schema.ts","../src/node-validator.ts","../src/traverse.ts","../src/value-types.ts","../src/style-validator.ts","../src/security.ts","../src/limits.ts","../src/expr-constraints.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 → expr-constraints\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 { validateNodes } from './node-validator.js';\nimport { validateValueTypes } from './value-types.js';\nimport { validateStyles } from './style-validator.js';\nimport { validateSecurity } from './security.js';\nimport { validateLimits } from './limits.js';\nimport { validateExprConstraints } from './expr-constraints.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 TraversalContext,\n type TraversableNode,\n type NodeVisitor,\n traverseNode,\n traverseCard,\n} from './traverse.js';\n\nexport { validateSchema, parseCard } from './schema.js';\nexport { validateNodes } from './node-validator.js';\nexport { validateValueTypes } from './value-types.js';\nexport { validateStyles } from './style-validator.js';\nexport { validateSecurity } from './security.js';\nexport { validateLimits } from './limits.js';\nexport { validateExprConstraints } from './expr-constraints.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 };\n const views = obj.views as Record<string, unknown>;\n const cardStyles = obj.styles as Record<string, Record<string, unknown>> | undefined;\n const errors: ValidationError[] = [];\n\n errors.push(...validateNodes(views));\n errors.push(...validateValueTypes(views));\n errors.push(...validateStyles(views, cardStyles));\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 }));\n errors.push(...validateLimits({ state: obj.state as Record<string, unknown> | undefined, views, cardStyles }));\n errors.push(...validateExprConstraints(views));\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, expr)\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 | 'EXPR_NOT_ALLOWED'\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 // Expression constraints\n | 'EXPR_TOO_LONG'\n | 'REF_TOO_LONG'\n | 'EXPR_TOO_MANY_TOKENS'\n | 'EXPR_NESTING_TOO_DEEP'\n | 'EXPR_CONDITION_NESTING_TOO_DEEP'\n | 'EXPR_REF_DEPTH_EXCEEDED'\n | 'EXPR_ARRAY_INDEX_EXCEEDED'\n | 'EXPR_STRING_LITERAL_TOO_LONG'\n | 'EXPR_FORBIDDEN_TOKEN'\n | 'EXPR_FUNCTION_CALL'\n | 'EXPR_INVALID_TOKEN'\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 // Hover / Transition\n | 'INVALID_HOVER_STYLE'\n | 'HOVER_STYLE_NESTED'\n | 'TRANSITION_RAW_STRING'\n | 'TRANSITION_COUNT_EXCEEDED'\n | 'TRANSITION_PROPERTY_FORBIDDEN';\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 — 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 } from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\nimport {\n type TraversableNode,\n type TraversalContext,\n traverseCard,\n} 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 Text: ['content'],\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};\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)\n ) {\n errors.push(\n createError(\n 'INVALID_VALUE',\n 'ForLoop \"template\" must be an object with a \"type\" property.',\n `${path}.children.template`,\n ),\n );\n }\n\n return errors;\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 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 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): ValidationError[] {\n const errors: ValidationError[] = [];\n\n traverseCard(views, (node: TraversableNode, context: TraversalContext) => {\n errors.push(...validateNode(node, context));\n });\n\n return errors;\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?: TraversableNode[] | ForLoopLike;\n style?: Record<string, unknown>;\n condition?: unknown;\n [key: string]: unknown;\n}\n\ninterface ForLoopLike {\n for: string;\n in: string;\n template: TraversableNode;\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\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\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: TraversableNode,\n context: TraversalContext,\n visitor: NodeVisitor,\n): void {\n const result = visitor(node, context);\n\n // If visitor returns false, skip children.\n if (result === false) {\n return;\n }\n\n const children = node.children;\n if (children == null) {\n return;\n }\n\n const nextStackDepth =\n node.type === 'Stack' ? context.stackDepth + 1 : context.stackDepth;\n const nextOverflowAuto =\n context.overflowAutoAncestor || hasOverflowAuto(node.style);\n\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: node.type,\n loopDepth: context.loopDepth + 1,\n overflowAutoAncestor: nextOverflowAuto,\n stackDepth: nextStackDepth,\n };\n traverseNode(children.template, childCtx, visitor);\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 (child && typeof child === 'object' && 'type' in child) {\n const childCtx: TraversalContext = {\n path: `${context.path}.children[${i}]`,\n depth: context.depth + 1,\n parentType: node.type,\n loopDepth: context.loopDepth,\n overflowAutoAncestor: nextOverflowAuto,\n stackDepth: nextStackDepth,\n };\n traverseNode(child as TraversableNode, childCtx, visitor);\n }\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): void {\n for (const [viewName, rootNode] of Object.entries(views)) {\n if (\n rootNode == null ||\n typeof rootNode !== 'object' ||\n !('type' in rootNode)\n ) {\n continue;\n }\n\n const context: TraversalContext = {\n path: `views.${viewName}`,\n depth: 0,\n parentType: null,\n loopDepth: 0,\n overflowAutoAncestor: false,\n stackDepth: 0,\n };\n\n traverseNode(rootNode as TraversableNode, context, visitor);\n }\n}\n","/**\n * @safe-ugc-ui/validator — Value Type Validation\n *\n * Validates per-property $ref / $expr permission rules based on spec\n * section 4.5 value type table.\n *\n * | Property Type | Literal | $ref | $expr |\n * |-------------------|---------|------|-------|\n * | Image.src | yes | yes | no |\n * | Avatar.src | yes | yes | no |\n * | Icon.name | yes | no | no |\n * | Text.content | yes | yes | yes |\n * | Color properties | yes | yes | yes |\n * | Size properties | yes | yes | yes |\n * | position | yes | no | no |\n * | transform | yes | no | no |\n * | gradient | yes | no | no |\n *\n * Additionally, several style properties must always be static\n * (no $ref or $expr): overflow, border*, boxShadow, zIndex,\n * and position offset properties (top/right/bottom/left).\n */\n\nimport { isRef, isExpr } from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\nimport {\n type TraversableNode,\n type TraversalContext,\n traverseCard,\n} from './traverse.js';\n\n// ---------------------------------------------------------------------------\n// Style properties that must always be static (no $ref / $expr)\n// ---------------------------------------------------------------------------\n\n/**\n * Style properties where any dynamic binding ($ref or $expr) 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 // Transform\n 'transform',\n\n // Gradient\n 'backgroundGradient',\n\n // Overflow\n 'overflow',\n\n // Borders\n 'border',\n 'borderTop',\n 'borderRight',\n 'borderBottom',\n 'borderLeft',\n\n // Shadow\n 'boxShadow',\n\n // Stacking\n 'zIndex',\n]);\n\n// ---------------------------------------------------------------------------\n// Per-node field validation\n// ---------------------------------------------------------------------------\n\n/**\n * Validate component fields according to the value type table.\n */\nfunction validateNodeFields(\n node: TraversableNode,\n ctx: TraversalContext,\n errors: ValidationError[],\n): void {\n const nodeType = node.type;\n\n // Image.src / Avatar.src — $ref allowed, $expr forbidden\n if (nodeType === 'Image' || nodeType === 'Avatar') {\n const src = (node as Record<string, unknown>).src;\n if (src !== undefined && isExpr(src)) {\n errors.push(\n createError(\n 'EXPR_NOT_ALLOWED',\n `${nodeType}.src does not allow $expr bindings.`,\n `${ctx.path}.src`,\n ),\n );\n }\n }\n\n // Icon.name — neither $ref nor $expr allowed\n if (nodeType === 'Icon') {\n const name = (node as Record<string, unknown>).name;\n if (name !== undefined && isRef(name)) {\n errors.push(\n createError(\n 'REF_NOT_ALLOWED',\n 'Icon.name does not allow $ref bindings.',\n `${ctx.path}.name`,\n ),\n );\n }\n if (name !== undefined && isExpr(name)) {\n errors.push(\n createError(\n 'EXPR_NOT_ALLOWED',\n 'Icon.name does not allow $expr bindings.',\n `${ctx.path}.name`,\n ),\n );\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Per-node style validation\n// ---------------------------------------------------------------------------\n\n/**\n * Validate the `style` of a node according to the value type table.\n */\nfunction validateNodeStyle(\n node: TraversableNode,\n ctx: TraversalContext,\n errors: ValidationError[],\n): void {\n const style = node.style;\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 (STATIC_ONLY_STYLE_PROPERTIES.has(prop)) {\n if (isRef(value) || isExpr(value)) {\n errors.push(\n createError(\n 'DYNAMIC_NOT_ALLOWED',\n `Style property \"${prop}\" must be a static literal; $ref and $expr are not allowed.`,\n `${ctx.path}.style.${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 / $expr 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): ValidationError[] {\n const errors: ValidationError[] = [];\n\n traverseCard(views, (node: TraversableNode, ctx: TraversalContext) => {\n validateNodeFields(node, ctx, errors);\n validateNodeStyle(node, ctx, errors);\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 * - 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 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 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 isExpr,\n} from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\nimport { type TraversableNode, type TraversalContext, traverseCard } from './traverse.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\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Returns true only if the value is a literal number (not a $ref or $expr).\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 or $expr).\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 or $expr) that should\n * be skipped for static range checks.\n */\nfunction isDynamic(value: unknown): boolean {\n return isRef(value) || isExpr(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\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 and $expr 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 / $expr objects — they are not user-authored strings\n if (isRef(value) || isExpr(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// Regex for valid $style references and style names\n// ---------------------------------------------------------------------------\n\nconst STYLE_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*$/;\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. 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. Border color validation\n * 11. Background gradient stop color validation\n */\nfunction validateSingleStyle(\n style: Record<string, unknown>,\n stylePath: string,\n errors: ValidationError[],\n): void {\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(['transition', '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 // ------------------------------------------------------------------\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 // 5. 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 // 6. 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 // 7. 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 // 8. 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 // ------------------------------------------------------------------\n // 9. 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 // 10. 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 // 11. 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 // 12. hoverStyle validation (spec 3.9)\n // ------------------------------------------------------------------\n if ('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 // $style is not allowed inside hoverStyle (no resolution path)\n if ('$style' in hoverObj) {\n errors.push(\n createError(\n 'INVALID_STYLE_REF',\n `$style is not allowed inside hoverStyle at \"${hoverPath}.$style\"`,\n `${hoverPath}.$style`,\n ),\n );\n }\n\n // Validate hoverStyle with the same rules (recursive call)\n validateSingleStyle(hoverObj, hoverPath, errors);\n }\n }\n\n // ------------------------------------------------------------------\n // 13. transition validation (spec 3.9)\n // ------------------------------------------------------------------\n if ('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): 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 inside card.styles definitions (circular ref)\n if ('$style' in styleEntry) {\n errors.push(\n createError(\n 'STYLE_CIRCULAR_REF',\n `$style cannot be used inside card.styles definitions at \"${entryPath}.$style\"`,\n `${entryPath}.$style`,\n ),\n );\n }\n\n // Run all per-style validations on this entry\n validateSingleStyle(styleEntry, entryPath, errors);\n }\n }\n\n // ------------------------------------------------------------------\n // Phase 1: Validate per-node styles (with $style merging)\n // ------------------------------------------------------------------\n traverseCard(views, (node: TraversableNode, ctx: TraversalContext) => {\n const style = node.style;\n if (style == null || typeof style !== 'object') {\n return;\n }\n\n const stylePath = `${ctx.path}.style`;\n\n // Check for $style reference\n if ('$style' in style && typeof style.$style === 'string') {\n const rawRef = style.$style;\n const trimmedRef = rawRef.trim();\n\n // Validate $style value format\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;\n }\n\n // Check that the referenced style exists\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;\n }\n\n // Merge: card.styles[name] as base, inline styles (minus $style) as overrides\n const mergedStyle = mergeStyleWithRef(cardStyles[trimmedRef], style);\n\n // Validate the merged result\n validateSingleStyle(mergedStyle, stylePath, errors);\n } else {\n // No $style — validate the inline style directly\n validateSingleStyle(style, stylePath, errors);\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';\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\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}): ValidationError[] {\n const errors: ValidationError[] = [];\n const { views, state, cardAssets, cardStyles } = 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 traverseCard(views, (node: TraversableNode, context: TraversalContext) => {\n const { path } = context;\n const { style, type } = node;\n const nodeFields = { ...node } as Record<string, unknown>;\n delete nodeFields.type;\n delete nodeFields.style;\n delete nodeFields.children;\n delete nodeFields.condition;\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 if (style) {\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}.style.${prop}`,\n ),\n );\n }\n }\n }\n\n // -----------------------------------------------------------------\n // 3. Position rules (use merged style if $style is present)\n // -----------------------------------------------------------------\n // Build effective style by merging with card.styles if $style is present\n let effectiveStyle = style;\n if (\n style &&\n typeof style.$style === 'string' &&\n cardStyles &&\n style.$style.trim() in cardStyles\n ) {\n const refName = style.$style.trim();\n const merged: Record<string, unknown> = { ...cardStyles[refName] };\n for (const [key, value] of Object.entries(style)) {\n if (key !== '$style') {\n merged[key] = value;\n }\n }\n effectiveStyle = merged;\n }\n\n if (effectiveStyle && typeof effectiveStyle.position === 'string') {\n const position = effectiveStyle.position;\n\n if (position === 'fixed') {\n errors.push(\n createError(\n 'POSITION_FIXED_FORBIDDEN',\n 'CSS position \"fixed\" is not allowed.',\n `${path}.style.position`,\n ),\n );\n } else if (position === 'sticky') {\n errors.push(\n createError(\n 'POSITION_STICKY_FORBIDDEN',\n 'CSS position \"sticky\" is not allowed.',\n `${path}.style.position`,\n ),\n );\n } else if (position === 'absolute') {\n if (context.parentType !== 'Stack') {\n errors.push(\n createError(\n 'POSITION_ABSOLUTE_NOT_IN_STACK',\n 'CSS position \"absolute\" is only allowed inside a Stack component.',\n `${path}.style.position`,\n ),\n );\n }\n }\n }\n\n // -----------------------------------------------------------------\n // 4. Overflow auto nesting (use merged style)\n // -----------------------------------------------------------------\n if (\n effectiveStyle &&\n effectiveStyle.overflow === 'auto' &&\n context.overflowAutoAncestor\n ) {\n errors.push(\n createError(\n 'OVERFLOW_AUTO_NESTED',\n 'Nested overflow:auto is not allowed. An ancestor already has overflow:auto.',\n `${path}.style.overflow`,\n ),\n );\n }\n\n // -----------------------------------------------------------------\n // 5. 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 });\n\n return errors;\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 isRef,\n isExpr,\n} from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\nimport { type TraversableNode, type TraversalContext, traverseCard } from './traverse.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\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: 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): TemplateMetrics {\n const result: TemplateMetrics = { nodes: 0, textBytes: 0, styleBytes: 0, overflowAutoCount: 0 };\n if (template == null || typeof template !== 'object') return result;\n\n const node = template as Record<string, unknown>;\n if (!node.type) return result;\n\n result.nodes = 1;\n\n // Text bytes\n if (node.type === 'Text') {\n const content = (node as Record<string, unknown>).content;\n if (typeof content === 'string' && !isRef(content) && !isExpr(content)) {\n result.textBytes = utf8ByteLength(content);\n }\n }\n\n // Style bytes (merged with $style)\n if (node.style != null && typeof node.style === 'object') {\n const style = node.style as Record<string, unknown>;\n let styleForBytes = style;\n if (\n typeof style.$style === 'string' &&\n cardStyles &&\n style.$style.trim() in cardStyles\n ) {\n const refName = (style.$style as string).trim();\n const merged: Record<string, unknown> = { ...cardStyles[refName] };\n for (const [key, value] of Object.entries(style)) {\n if (key !== '$style') merged[key] = value;\n }\n styleForBytes = merged;\n }\n result.styleBytes = utf8ByteLength(JSON.stringify(styleForBytes));\n\n // Overflow auto\n let effectiveOverflow = style.overflow;\n if (\n typeof style.$style === 'string' &&\n cardStyles &&\n style.$style.trim() in cardStyles\n ) {\n const refName = (style.$style as string).trim();\n if (!('overflow' in style) || style.overflow === undefined) {\n effectiveOverflow = cardStyles[refName].overflow;\n }\n }\n if (effectiveOverflow === 'auto') {\n result.overflowAutoCount = 1;\n }\n }\n\n // Recurse into children\n const children = node.children;\n if (Array.isArray(children)) {\n for (const child of children) {\n const childMetrics = countTemplateMetrics(child, cardStyles);\n result.nodes += childMetrics.nodes;\n result.textBytes += childMetrics.textBytes;\n result.styleBytes += childMetrics.styleBytes;\n result.overflowAutoCount += childMetrics.overflowAutoCount;\n }\n } else if (\n children != null &&\n typeof children === 'object' &&\n !Array.isArray(children) &&\n 'template' in (children as Record<string, unknown>)\n ) {\n // Nested for-loop: count the template once (inner loop expansion\n // can't be calculated without knowing the inner array length)\n const innerTemplate = (children as Record<string, unknown>).template;\n const innerMetrics = countTemplateMetrics(innerTemplate, cardStyles);\n result.nodes += innerMetrics.nodes;\n result.textBytes += innerMetrics.textBytes;\n result.styleBytes += innerMetrics.styleBytes;\n result.overflowAutoCount += innerMetrics.overflowAutoCount;\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: { state?: Record<string, unknown>; views: Record<string, unknown>; cardStyles?: Record<string, Record<string, unknown>> },\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n let nodeCount = 0;\n let textContentBytes = 0;\n let styleObjectsBytes = 0;\n let overflowAutoCount = 0;\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 const content = (node as Record<string, unknown>).content;\n if (typeof content === 'string' && !isRef(content) && !isExpr(content)) {\n textContentBytes += utf8ByteLength(content);\n }\n }\n\n // -----------------------------------------------------------------------\n // 3. Style objects total bytes (use merged style if $style is present)\n // -----------------------------------------------------------------------\n if (node.style != null && typeof node.style === 'object') {\n let styleForBytes = node.style;\n if (\n typeof node.style.$style === 'string' &&\n card.cardStyles &&\n node.style.$style.trim() in card.cardStyles\n ) {\n const refName = node.style.$style.trim();\n const merged: Record<string, unknown> = { ...card.cardStyles[refName] };\n for (const [key, value] of Object.entries(node.style)) {\n if (key !== '$style') {\n merged[key] = value;\n }\n }\n styleForBytes = merged;\n }\n const serialized = JSON.stringify(styleForBytes);\n styleObjectsBytes += utf8ByteLength(serialized);\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);\n const multiplier = source.length - 1;\n nodeCount += tplMetrics.nodes * multiplier;\n textContentBytes += tplMetrics.textBytes * multiplier;\n styleObjectsBytes += tplMetrics.styleBytes * multiplier;\n overflowAutoCount += tplMetrics.overflowAutoCount * multiplier;\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 {\n let effectiveOverflow = node.style?.overflow;\n if (\n node.style &&\n typeof node.style.$style === 'string' &&\n card.cardStyles &&\n node.style.$style.trim() in card.cardStyles\n ) {\n const refName = node.style.$style.trim();\n // Inline overflow takes precedence; if not set, use card.styles value\n if (!('overflow' in node.style) || node.style.overflow === undefined) {\n effectiveOverflow = card.cardStyles[refName].overflow as string | undefined;\n }\n }\n if (effectiveOverflow === 'auto') {\n overflowAutoCount++;\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 });\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 if (overflowAutoCount > MAX_OVERFLOW_AUTO_COUNT) {\n errors.push(\n createError(\n 'OVERFLOW_AUTO_COUNT_EXCEEDED',\n `Card has ${overflowAutoCount} elements with overflow:auto, max is ${MAX_OVERFLOW_AUTO_COUNT}`,\n 'views',\n ),\n );\n }\n\n return errors;\n}\n","/**\n * @safe-ugc-ui/validator -- Expression & Reference Constraint Validation\n *\n * Validates $expr and $ref values found in the card tree against the\n * constraints defined in the spec's \"expression constraint\" section (6.3).\n *\n * A simple tokenizer splits expression strings into typed tokens so that\n * structural limits (nesting, token count, forbidden operators) can be\n * checked without executing the expression.\n */\n\nimport {\n EXPR_MAX_LENGTH,\n EXPR_MAX_TOKENS,\n EXPR_MAX_NESTING,\n EXPR_MAX_CONDITION_NESTING,\n EXPR_MAX_REF_DEPTH,\n EXPR_MAX_ARRAY_INDEX,\n EXPR_MAX_STRING_LITERAL,\n EXPR_MAX_FRACTIONAL_DIGITS,\n isRef,\n isExpr,\n} from '@safe-ugc-ui/types';\n\nimport { type ValidationError, createError } from './result.js';\nimport { type TraversableNode, type TraversalContext, traverseCard } from './traverse.js';\n\n// ---------------------------------------------------------------------------\n// Token types\n// ---------------------------------------------------------------------------\n\ntype TokenType =\n | 'identifier'\n | 'number'\n | 'string'\n | 'boolean'\n | 'arithmetic'\n | 'comparison'\n | 'logic_keyword'\n | 'condition_keyword'\n | 'separator';\n\ninterface Token {\n type: TokenType;\n value: string;\n position: number;\n}\n\n// ---------------------------------------------------------------------------\n// Forbidden tokens\n// ---------------------------------------------------------------------------\n\nconst FORBIDDEN_KEYWORDS = [\n 'typeof',\n 'instanceof',\n 'new',\n 'delete',\n 'function',\n 'return',\n 'var',\n 'let',\n 'const',\n] as const;\n\nconst FORBIDDEN_KEYWORD_SET = new Set<string>(FORBIDDEN_KEYWORDS);\n\n// ---------------------------------------------------------------------------\n// Prototype pollution segments\n// ---------------------------------------------------------------------------\n\nconst PROTOTYPE_POLLUTION_SEGMENTS = new Set([\n '__proto__',\n 'constructor',\n 'prototype',\n]);\n\n// ---------------------------------------------------------------------------\n// Tokenizer\n// ---------------------------------------------------------------------------\n\nfunction tokenize(\n expr: string,\n path: string,\n): { tokens: Token[]; errors: ValidationError[] } {\n const tokens: Token[] = [];\n const errors: ValidationError[] = [];\n let i = 0;\n\n while (i < expr.length) {\n // 1. Skip whitespace\n if (/\\s/.test(expr[i])) {\n i++;\n continue;\n }\n\n // 2. Three-char operators (must check before two-char)\n if (i + 2 < expr.length) {\n const three = expr.slice(i, i + 3);\n if (three === '===' || three === '!==') {\n tokens.push({ type: 'comparison', value: three, position: i });\n i += 3;\n continue;\n }\n }\n\n // 3. Two-char operators\n if (i + 1 < expr.length) {\n const two = expr.slice(i, i + 2);\n if (two === '==' || two === '!=' || two === '<=' || two === '>=') {\n tokens.push({ type: 'comparison', value: two, position: i });\n i += 2;\n continue;\n }\n if (two === '&&' || two === '||') {\n tokens.push({ type: 'logic_keyword', value: two, position: i });\n i += 2;\n continue;\n }\n }\n\n // 4. String literals\n if (expr[i] === \"'\" || expr[i] === '\"') {\n const quote = expr[i];\n let j = i + 1;\n while (j < expr.length && expr[j] !== quote) {\n // Allow escaped quotes\n if (expr[j] === '\\\\' && j + 1 < expr.length) {\n j += 2;\n } else {\n j++;\n }\n }\n // j now points to the closing quote (or end of string)\n const innerValue = expr.slice(i + 1, j);\n tokens.push({ type: 'string', value: innerValue, position: i });\n i = j + 1;\n continue;\n }\n\n // 5. Numbers: optional leading `-` for negative, digits, optional `.` + digits\n // Only treat `-` as part of a number if:\n // - it's at the start of the expression, OR\n // - the previous non-whitespace token is NOT a number, identifier, string,\n // boolean, or closing separator (i.e. it follows an operator or opening paren)\n if (/[0-9]/.test(expr[i]) || (expr[i] === '-' && i + 1 < expr.length && /[0-9]/.test(expr[i + 1]) && isNegativeSign(tokens))) {\n let j = i;\n if (expr[j] === '-') j++;\n while (j < expr.length && /[0-9]/.test(expr[j])) j++;\n if (j < expr.length && expr[j] === '.') {\n j++;\n while (j < expr.length && /[0-9]/.test(expr[j])) j++;\n }\n const numStr = expr.slice(i, j);\n // Check fractional digits\n const dotIdx = numStr.indexOf('.');\n if (dotIdx !== -1) {\n const fractionalPart = numStr.slice(dotIdx + 1);\n if (fractionalPart.length > EXPR_MAX_FRACTIONAL_DIGITS) {\n errors.push(\n createError(\n 'EXPR_INVALID_TOKEN',\n `Number literal \"${numStr}\" at position ${i} has ${fractionalPart.length} fractional digits, maximum is ${EXPR_MAX_FRACTIONAL_DIGITS}.`,\n path,\n ),\n );\n }\n }\n tokens.push({ type: 'number', value: numStr, position: i });\n i = j;\n continue;\n }\n\n // 6. Identifiers: `$` followed by word chars, or plain word chars\n if (expr[i] === '$' || /[a-zA-Z_]/.test(expr[i])) {\n let j = i;\n if (expr[j] === '$') j++;\n while (j < expr.length && /[\\w]/.test(expr[j])) j++;\n const word = expr.slice(i, j);\n\n if (word === 'true' || word === 'false') {\n tokens.push({ type: 'boolean', value: word, position: i });\n } else if (word === 'and' || word === 'or' || word === 'not') {\n tokens.push({ type: 'logic_keyword', value: word, position: i });\n } else if (word === 'if' || word === 'then' || word === 'else') {\n tokens.push({ type: 'condition_keyword', value: word, position: i });\n } else {\n tokens.push({ type: 'identifier', value: word, position: i });\n }\n i = j;\n continue;\n }\n\n // 7. Single-char operators and separators\n const ch = expr[i];\n if ('+-*/%'.includes(ch)) {\n tokens.push({ type: 'arithmetic', value: ch, position: i });\n i++;\n continue;\n }\n if (ch === '<' || ch === '>') {\n tokens.push({ type: 'comparison', value: ch, position: i });\n i++;\n continue;\n }\n if ('().[]'.includes(ch)) {\n tokens.push({ type: 'separator', value: ch, position: i });\n i++;\n continue;\n }\n if (ch === '!') {\n // Standalone `!` (not part of `!=` which was already handled)\n tokens.push({ type: 'comparison', value: ch, position: i });\n i++;\n continue;\n }\n\n // 8. Unrecognized character\n errors.push(\n createError(\n 'EXPR_INVALID_TOKEN',\n `Unrecognized character \"${ch}\" at position ${i} in expression.`,\n path,\n ),\n );\n i++;\n }\n\n // --- Post-tokenization: check for forbidden tokens ---\n\n for (let t = 0; t < tokens.length; t++) {\n const tok = tokens[t];\n\n // Forbidden JS operators: ===, !==, &&, ||\n if (\n (tok.value === '===' || tok.value === '!==') ||\n (tok.value === '&&' || tok.value === '||')\n ) {\n errors.push(\n createError(\n 'EXPR_FORBIDDEN_TOKEN',\n `Forbidden operator \"${tok.value}\" at position ${tok.position}. Use \"==\" / \"!=\" or \"and\" / \"or\" instead.`,\n path,\n ),\n );\n }\n\n // Standalone `!` (not part of `!=`)\n if (tok.value === '!') {\n errors.push(\n createError(\n 'EXPR_FORBIDDEN_TOKEN',\n `Forbidden operator \"!\" at position ${tok.position}. Use \"not\" instead.`,\n path,\n ),\n );\n }\n\n // Forbidden keywords\n if (tok.type === 'identifier' && FORBIDDEN_KEYWORD_SET.has(tok.value)) {\n errors.push(\n createError(\n 'EXPR_FORBIDDEN_TOKEN',\n `Forbidden keyword \"${tok.value}\" at position ${tok.position}.`,\n path,\n ),\n );\n }\n\n // Bare identifiers without $ prefix\n if (tok.type === 'identifier' && !tok.value.startsWith('$') && !FORBIDDEN_KEYWORD_SET.has(tok.value)) {\n errors.push(\n createError(\n 'EXPR_FORBIDDEN_TOKEN',\n `Identifier \"${tok.value}\" at position ${tok.position} must start with \"$\". Use \"$${tok.value}\" for variable references.`,\n path,\n ),\n );\n }\n\n // Function call pattern: identifier followed by `(`\n if (tok.type === 'identifier') {\n // Look ahead past any whitespace (already skipped during tokenization,\n // so the next token is the actual next non-whitespace token)\n const next = tokens[t + 1];\n if (next && next.type === 'separator' && next.value === '(') {\n errors.push(\n createError(\n 'EXPR_FUNCTION_CALL',\n `Function call pattern detected: \"${tok.value}(\" at position ${tok.position}. Function calls are not allowed.`,\n path,\n ),\n );\n }\n }\n }\n\n return { tokens, errors };\n}\n\n/**\n * Determines whether a `-` character should be interpreted as a negative sign\n * (unary minus for a negative number literal) rather than a subtraction operator.\n *\n * A `-` is a negative sign when there is no preceding token, or the preceding\n * token is an operator, opening paren, or opening bracket.\n */\nfunction isNegativeSign(tokens: Token[]): boolean {\n if (tokens.length === 0) return true;\n const prev = tokens[tokens.length - 1];\n if (\n prev.type === 'arithmetic' ||\n prev.type === 'comparison' ||\n prev.type === 'logic_keyword' ||\n prev.type === 'condition_keyword'\n ) {\n return true;\n }\n if (prev.type === 'separator' && (prev.value === '(' || prev.value === '[')) {\n return true;\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Deep scan helper\n// ---------------------------------------------------------------------------\n\n/**\n * Recursively walks an object/array structure to find all $ref and $expr\n * values, calling the callback for each one found.\n */\nfunction scanForDynamicValues(\n obj: unknown,\n basePath: string,\n callback: (value: unknown, path: string) => void,\n): void {\n if (obj === null || obj === undefined || typeof obj !== 'object') {\n return;\n }\n\n // Check if this object itself is a $ref or $expr\n if (isRef(obj) || isExpr(obj)) {\n callback(obj, basePath);\n return;\n }\n\n if (Array.isArray(obj)) {\n for (let i = 0; i < obj.length; i++) {\n scanForDynamicValues(obj[i], `${basePath}[${i}]`, callback);\n }\n } else {\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n scanForDynamicValues(value, `${basePath}.${key}`, callback);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// $ref validation\n// ---------------------------------------------------------------------------\n\nfunction validateRef(refValue: string, path: string): ValidationError[] {\n const errors: ValidationError[] = [];\n\n // 1. Length check\n if (refValue.length > 500) {\n errors.push(\n createError(\n 'REF_TOO_LONG',\n `$ref value exceeds maximum length of 500 characters (got ${refValue.length}).`,\n path,\n ),\n );\n }\n\n // 2. Ref depth: split by `.` segments\n const segments = refValue.split('.');\n if (segments.length > EXPR_MAX_REF_DEPTH) {\n errors.push(\n createError(\n 'EXPR_REF_DEPTH_EXCEEDED',\n `$ref path depth ${segments.length} exceeds maximum of ${EXPR_MAX_REF_DEPTH}.`,\n path,\n ),\n );\n }\n\n // 3. Array index check: find [N] patterns\n const arrayIndexPattern = /\\[(\\d+)\\]/g;\n let match: RegExpExecArray | null;\n while ((match = arrayIndexPattern.exec(refValue)) !== null) {\n const index = parseInt(match[1], 10);\n if (index > EXPR_MAX_ARRAY_INDEX) {\n errors.push(\n createError(\n 'EXPR_ARRAY_INDEX_EXCEEDED',\n `Array index ${index} in $ref exceeds maximum of ${EXPR_MAX_ARRAY_INDEX}.`,\n path,\n ),\n );\n }\n }\n\n // 4. Prototype pollution segments\n // Extract plain segment names (strip array index suffixes)\n for (const segment of segments) {\n const cleanSegment = segment.replace(/\\[\\d+\\]/g, '');\n if (PROTOTYPE_POLLUTION_SEGMENTS.has(cleanSegment)) {\n errors.push(\n createError(\n 'PROTOTYPE_POLLUTION',\n `$ref path contains forbidden segment \"${cleanSegment}\".`,\n path,\n ),\n );\n }\n }\n\n return errors;\n}\n\n// ---------------------------------------------------------------------------\n// $expr validation\n// ---------------------------------------------------------------------------\n\nfunction validateExpr(exprValue: string, path: string): ValidationError[] {\n const errors: ValidationError[] = [];\n\n // 1. Length check\n if (exprValue.length > EXPR_MAX_LENGTH) {\n errors.push(\n createError(\n 'EXPR_TOO_LONG',\n `Expression exceeds maximum length of ${EXPR_MAX_LENGTH} characters (got ${exprValue.length}).`,\n path,\n ),\n );\n }\n\n // 2. Tokenize\n const { tokens, errors: tokenErrors } = tokenize(exprValue, path);\n errors.push(...tokenErrors);\n\n // 3. Token count\n if (tokens.length > EXPR_MAX_TOKENS) {\n errors.push(\n createError(\n 'EXPR_TOO_MANY_TOKENS',\n `Expression has ${tokens.length} tokens, exceeding maximum of ${EXPR_MAX_TOKENS}.`,\n path,\n ),\n );\n }\n\n // 4. String literal lengths\n for (const tok of tokens) {\n if (tok.type === 'string' && tok.value.length > EXPR_MAX_STRING_LITERAL) {\n errors.push(\n createError(\n 'EXPR_STRING_LITERAL_TOO_LONG',\n `String literal at position ${tok.position} has ${tok.value.length} characters, exceeding maximum of ${EXPR_MAX_STRING_LITERAL}.`,\n path,\n ),\n );\n }\n }\n\n // 5. Nesting depth (parentheses) and condition nesting (if keywords)\n let parenDepth = 0;\n let maxParenDepth = 0;\n let ifCount = 0;\n\n for (const tok of tokens) {\n if (tok.type === 'separator' && tok.value === '(') {\n parenDepth++;\n if (parenDepth > maxParenDepth) {\n maxParenDepth = parenDepth;\n }\n } else if (tok.type === 'separator' && tok.value === ')') {\n parenDepth--;\n } else if (tok.type === 'condition_keyword' && tok.value === 'if') {\n ifCount++;\n }\n }\n\n if (maxParenDepth > EXPR_MAX_NESTING) {\n errors.push(\n createError(\n 'EXPR_NESTING_TOO_DEEP',\n `Expression parenthesis nesting depth ${maxParenDepth} exceeds maximum of ${EXPR_MAX_NESTING}.`,\n path,\n ),\n );\n }\n\n if (ifCount > EXPR_MAX_CONDITION_NESTING) {\n errors.push(\n createError(\n 'EXPR_CONDITION_NESTING_TOO_DEEP',\n `Expression has ${ifCount} nested if-conditions, exceeding maximum of ${EXPR_MAX_CONDITION_NESTING}.`,\n path,\n ),\n );\n }\n\n // 6. Variable reference depth inside expr: $identifier followed by `.` segments\n for (let t = 0; t < tokens.length; t++) {\n const tok = tokens[t];\n if (tok.type === 'identifier' && tok.value.startsWith('$')) {\n // Count consecutive `.identifier` sequences\n let depth = 1; // The $identifier itself counts as depth 1\n let j = t + 1;\n while (j + 1 < tokens.length) {\n if (\n tokens[j].type === 'separator' &&\n tokens[j].value === '.' &&\n tokens[j + 1].type === 'identifier'\n ) {\n depth++;\n j += 2;\n } else {\n break;\n }\n }\n if (depth > EXPR_MAX_REF_DEPTH) {\n errors.push(\n createError(\n 'EXPR_REF_DEPTH_EXCEEDED',\n `Variable reference \"${tok.value}\" has path depth ${depth}, exceeding maximum of ${EXPR_MAX_REF_DEPTH}.`,\n path,\n ),\n );\n }\n }\n }\n\n // 7. Array indices in tokens: `[` number `]` patterns\n for (let t = 0; t + 2 < tokens.length; t++) {\n if (\n tokens[t].type === 'separator' &&\n tokens[t].value === '[' &&\n tokens[t + 1].type === 'number' &&\n tokens[t + 2].type === 'separator' &&\n tokens[t + 2].value === ']'\n ) {\n const indexValue = parseFloat(tokens[t + 1].value);\n if (indexValue > EXPR_MAX_ARRAY_INDEX) {\n errors.push(\n createError(\n 'EXPR_ARRAY_INDEX_EXCEEDED',\n `Array index ${indexValue} in expression exceeds maximum of ${EXPR_MAX_ARRAY_INDEX}.`,\n path,\n ),\n );\n }\n }\n }\n\n return errors;\n}\n\n// ---------------------------------------------------------------------------\n// Main entry point\n// ---------------------------------------------------------------------------\n\n/**\n * Validates all $expr and $ref values found in the card's views.\n *\n * Uses tree traversal to visit every node, then deep-scans each node's\n * flattened node fields and `style` (and `condition`) for dynamic values.\n *\n * @param views - The `views` object from a UGCCard.\n * @returns An array of validation errors (empty if all constraints pass).\n */\nexport function validateExprConstraints(\n views: Record<string, unknown>,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n traverseCard(views, (node: TraversableNode, context: TraversalContext) => {\n // Scan node fields (excluding style/children/type/condition)\n const nodeFields = { ...node } as Record<string, unknown>;\n delete nodeFields.type;\n delete nodeFields.style;\n delete nodeFields.children;\n delete nodeFields.condition;\n scanForDynamicValues(nodeFields, context.path, (value, valuePath) => {\n if (isRef(value)) {\n errors.push(...validateRef(value.$ref, valuePath));\n } else if (isExpr(value)) {\n errors.push(...validateExpr(value.$expr, valuePath));\n }\n });\n\n // Scan style\n if (node.style) {\n scanForDynamicValues(node.style, `${context.path}.style`, (value, valuePath) => {\n if (isRef(value)) {\n errors.push(...validateRef(value.$ref, valuePath));\n } else if (isExpr(value)) {\n errors.push(...validateExpr(value.$expr, valuePath));\n }\n });\n }\n\n // Scan condition\n if (node.condition !== undefined) {\n scanForDynamicValues(node.condition, `${context.path}.condition`, (value, valuePath) => {\n if (isRef(value)) {\n errors.push(...validateRef(value.$ref, valuePath));\n } else if (isExpr(value)) {\n errors.push(...validateExpr(value.$expr, valuePath));\n }\n });\n }\n });\n\n return errors;\n}\n"],"mappings":";AAoBA,SAAS,2BAA2B;;;AC2G7B,SAAS,YACd,MACA,SACA,MACiB;AACjB,SAAO,EAAE,MAAM,SAAS,KAAK;AAC/B;AAKO,SAAS,cAAgC;AAC9C,SAAO,EAAE,OAAO,MAAM,QAAQ,CAAC,EAAE;AACnC;AAKO,SAAS,cAAc,QAA6C;AACzE,SAAO,EAAE,OAAO,OAAO,OAAO;AAChC;AAKO,SAAS,SAAS,QAA6C;AACpE,SAAO;AAAA,IACL,OAAO,OAAO,WAAW;AAAA,IACzB;AAAA,EACF;AACF;AAMO,SAAS,SAAS,SAA+C;AACtE,QAAM,SAA4B,CAAC;AACnC,aAAW,KAAK,SAAS;AACvB,WAAO,KAAK,GAAG,EAAE,MAAM;AAAA,EACzB;AACA,SAAO;AAAA,IACL,OAAO,OAAO,WAAW;AAAA,IACzB;AAAA,EACF;AACF;;;AChKA,SAAS,qBAAmC;AAoBrC,SAAS,eAAe,OAAkC;AAC/D,QAAM,SAA4B,CAAC;AAGnC,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GAAG;AACvE,WAAO;AAAA,MACL,YAAY,gBAAgB,gCAAgC,EAAE;AAAA,IAChE;AACA,WAAO,SAAS,MAAM;AAAA,EACxB;AAEA,QAAM,MAAM;AAGZ,MAAI,CAAC,IAAI,MAAM;AACb,WAAO;AAAA,MACL,YAAY,iBAAiB,0CAA0C,MAAM;AAAA,IAC/E;AAAA,EACF;AACA,MAAI,CAAC,IAAI,OAAO;AACd,WAAO;AAAA,MACL,YAAY,iBAAiB,2CAA2C,OAAO;AAAA,IACjF;AAAA,EACF;AAGA,MAAI,OAAO,SAAS,GAAG;AACrB,WAAO,SAAS,MAAM;AAAA,EACxB;AAGA,MAAI,OAAO,IAAI,SAAS,YAAY,IAAI,SAAS,MAAM;AACrD,WAAO;AAAA,MACL,YAAY,gBAAgB,6BAA6B,MAAM;AAAA,IACjE;AACA,WAAO,SAAS,MAAM;AAAA,EACxB;AAEA,QAAM,OAAO,IAAI;AACjB,MAAI,OAAO,KAAK,SAAS,UAAU;AACjC,WAAO;AAAA,MACL,YAAY,iBAAiB,iDAAiD,WAAW;AAAA,IAC3F;AAAA,EACF;AACA,MAAI,OAAO,KAAK,YAAY,UAAU;AACpC,WAAO;AAAA,MACL,YAAY,iBAAiB,oDAAoD,cAAc;AAAA,IACjG;AAAA,EACF;AAGA,MAAI,OAAO,IAAI,UAAU,YAAY,IAAI,UAAU,QAAQ,MAAM,QAAQ,IAAI,KAAK,GAAG;AACnF,WAAO;AAAA,MACL,YAAY,gBAAgB,8BAA8B,OAAO;AAAA,IACnE;AACA,WAAO,SAAS,MAAM;AAAA,EACxB;AAEA,QAAM,QAAQ,IAAI;AAClB,MAAI,OAAO,KAAK,KAAK,EAAE,WAAW,GAAG;AACnC,WAAO;AAAA,MACL,YAAY,iBAAiB,2CAA2C,OAAO;AAAA,IACjF;AAAA,EACF;AAGA,MAAI,OAAO,SAAS,GAAG;AACrB,WAAO,SAAS,MAAM;AAAA,EACxB;AAGA,QAAM,SAAS,cAAc,UAAU,KAAK;AAE5C,MAAI,CAAC,OAAO,SAAS;AACnB,eAAW,SAAS,OAAO,MAAM,QAAQ;AACvC,YAAM,OAAO,MAAM,KAAK,KAAK,GAAG;AAChC,aAAO;AAAA,QACL,YAAY,gBAAgB,MAAM,SAAS,IAAI;AAAA,MACjD;AAAA,IACF;AAAA,EACF;AAEA,SAAO,SAAS,MAAM;AACxB;AASO,SAAS,UAAU,OAAgC;AACxD,QAAM,SAAS,cAAc,UAAU,KAAK;AAC5C,SAAO,OAAO,UAAU,OAAO,OAAO;AACxC;;;ACpHA,SAAS,2BAA2B;;;ACuEpC,SAAS,UACP,UACyB;AACzB,SACE,OAAO,aAAa,YACpB,aAAa,QACb,SAAS,YACT,QAAQ,YACR,cAAc;AAElB;AAEA,SAAS,gBAAgB,OAAqD;AAC5E,SAAO,OAAO,aAAa;AAC7B;AASO,SAAS,aACd,MACA,SACA,SACM;AACN,QAAM,SAAS,QAAQ,MAAM,OAAO;AAGpC,MAAI,WAAW,OAAO;AACpB;AAAA,EACF;AAEA,QAAM,WAAW,KAAK;AACtB,MAAI,YAAY,MAAM;AACpB;AAAA,EACF;AAEA,QAAM,iBACJ,KAAK,SAAS,UAAU,QAAQ,aAAa,IAAI,QAAQ;AAC3D,QAAM,mBACJ,QAAQ,wBAAwB,gBAAgB,KAAK,KAAK;AAE5D,MAAI,UAAU,QAAQ,GAAG;AAEvB,UAAM,WAA6B;AAAA,MACjC,MAAM,GAAG,QAAQ,IAAI;AAAA,MACrB,OAAO,QAAQ,QAAQ;AAAA,MACvB,YAAY,KAAK;AAAA,MACjB,WAAW,QAAQ,YAAY;AAAA,MAC/B,sBAAsB;AAAA,MACtB,YAAY;AAAA,IACd;AACA,iBAAa,SAAS,UAAU,UAAU,OAAO;AAAA,EACnD,WAAW,MAAM,QAAQ,QAAQ,GAAG;AAElC,aAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,YAAM,QAAQ,SAAS,CAAC;AACxB,UAAI,SAAS,OAAO,UAAU,YAAY,UAAU,OAAO;AACzD,cAAM,WAA6B;AAAA,UACjC,MAAM,GAAG,QAAQ,IAAI,aAAa,CAAC;AAAA,UACnC,OAAO,QAAQ,QAAQ;AAAA,UACvB,YAAY,KAAK;AAAA,UACjB,WAAW,QAAQ;AAAA,UACnB,sBAAsB;AAAA,UACtB,YAAY;AAAA,QACd;AACA,qBAAa,OAA0B,UAAU,OAAO;AAAA,MAC1D;AAAA,IACF;AAAA,EACF;AACF;AAYO,SAAS,aACd,OACA,SACM;AACN,aAAW,CAAC,UAAU,QAAQ,KAAK,OAAO,QAAQ,KAAK,GAAG;AACxD,QACE,YAAY,QACZ,OAAO,aAAa,YACpB,EAAE,UAAU,WACZ;AACA;AAAA,IACF;AAEA,UAAM,UAA4B;AAAA,MAChC,MAAM,SAAS,QAAQ;AAAA,MACvB,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,sBAAsB;AAAA,MACtB,YAAY;AAAA,IACd;AAEA,iBAAa,UAA6B,SAAS,OAAO;AAAA,EAC5D;AACF;;;ADlKA,IAAM,kBAA4C;AAAA,EAChD,MAAM,CAAC,SAAS;AAAA,EAChB,OAAO,CAAC,KAAK;AAAA,EACb,aAAa,CAAC,SAAS,KAAK;AAAA,EAC5B,QAAQ,CAAC,KAAK;AAAA,EACd,MAAM,CAAC,MAAM;AAAA,EACb,OAAO,CAAC,OAAO;AAAA,EACf,MAAM,CAAC,OAAO;AAAA,EACd,QAAQ,CAAC,SAAS,QAAQ;AAAA,EAC1B,QAAQ,CAAC,SAAS,UAAU;AAC9B;AAMA,IAAM,cAAmC,IAAI,IAAI,mBAAmB;AAUpE,SAAS,iBAAiB,OAAyB;AACjD,SACE,OAAO,UAAU,YACjB,UAAU,QACV,CAAC,MAAM,QAAQ,KAAK,KACpB,SAAS,SACT,QAAQ,SACR,cAAc;AAElB;AAKA,SAAS,gBACP,UACA,MACmB;AACnB,QAAM,SAA4B,CAAC;AAGnC,MAAI,OAAO,SAAS,KAAK,MAAM,UAAU;AACvC,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA;AAAA,QACA,GAAG,IAAI;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAGA,QAAM,UAAU,SAAS,IAAI;AAC7B,MAAI,OAAO,YAAY,YAAY,CAAC,QAAQ,WAAW,GAAG,GAAG;AAC3D,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA;AAAA,QACA,GAAG,IAAI;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAW,SAAS,UAAU;AACpC,MACE,OAAO,aAAa,YACpB,aAAa,QACb,EAAE,UAAU,WACZ;AACA,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA;AAAA,QACA,GAAG,IAAI;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AASA,SAAS,aACP,MACA,SACmB;AACnB,QAAM,SAA4B,CAAC;AACnC,QAAM,EAAE,KAAK,IAAI;AAGjB,MAAI,CAAC,YAAY,IAAI,KAAK,IAAI,GAAG;AAC/B,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,sBAAsB,KAAK,IAAI;AAAA,QAC/B;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAGA,QAAM,iBAAiB,gBAAgB,KAAK,IAAI;AAChD,MAAI,kBAAkB,eAAe,SAAS,GAAG;AAE/C,eAAW,SAAS,gBAAgB;AAClC,UAAI,EAAE,SAAS,SAAU,KAAiC,KAAK,MAAM,QAAW;AAC9E,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,IAAI,KAAK,IAAI,qCAAqC,KAAK;AAAA,YACvD,GAAG,IAAI,IAAI,KAAK;AAAA,UAClB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,KAAK,YAAY,QAAQ,iBAAiB,KAAK,QAAQ,GAAG;AAC5D,WAAO;AAAA,MACL,GAAG;AAAA,QACD,KAAK;AAAA,QACL;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAiBO,SAAS,cACd,OACmB;AACnB,QAAM,SAA4B,CAAC;AAEnC,eAAa,OAAO,CAAC,MAAuB,YAA8B;AACxE,WAAO,KAAK,GAAG,aAAa,MAAM,OAAO,CAAC;AAAA,EAC5C,CAAC;AAED,SAAO;AACT;;;AEhLA,SAAS,OAAO,cAAc;AAiB9B,IAAM,+BAAoD,oBAAI,IAAI;AAAA;AAAA,EAEhE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AACF,CAAC;AASD,SAAS,mBACP,MACA,KACA,QACM;AACN,QAAM,WAAW,KAAK;AAGtB,MAAI,aAAa,WAAW,aAAa,UAAU;AACjD,UAAM,MAAO,KAAiC;AAC9C,QAAI,QAAQ,UAAa,OAAO,GAAG,GAAG;AACpC,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,GAAG,QAAQ;AAAA,UACX,GAAG,IAAI,IAAI;AAAA,QACb;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,aAAa,QAAQ;AACvB,UAAM,OAAQ,KAAiC;AAC/C,QAAI,SAAS,UAAa,MAAM,IAAI,GAAG;AACrC,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA;AAAA,UACA,GAAG,IAAI,IAAI;AAAA,QACb;AAAA,MACF;AAAA,IACF;AACA,QAAI,SAAS,UAAa,OAAO,IAAI,GAAG;AACtC,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA;AAAA,UACA,GAAG,IAAI,IAAI;AAAA,QACb;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AASA,SAAS,kBACP,MACA,KACA,QACM;AACN,QAAM,QAAQ,KAAK;AACnB,MAAI,CAAC,OAAO;AACV;AAAA,EACF;AAEA,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AACjD,QAAI,UAAU,QAAW;AACvB;AAAA,IACF;AAEA,QAAI,6BAA6B,IAAI,IAAI,GAAG;AAC1C,UAAI,MAAM,KAAK,KAAK,OAAO,KAAK,GAAG;AACjC,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,mBAAmB,IAAI;AAAA,YACvB,GAAG,IAAI,IAAI,UAAU,IAAI;AAAA,UAC3B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAaO,SAAS,mBACd,OACmB;AACnB,QAAM,SAA4B,CAAC;AAEnC,eAAa,OAAO,CAAC,MAAuB,QAA0B;AACpE,uBAAmB,MAAM,KAAK,MAAM;AACpC,sBAAkB,MAAM,KAAK,MAAM;AAAA,EACrC,CAAC;AAED,SAAO;AACT;;;ACvKA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAAA;AAAA,EACA,UAAAC;AAAA,OACK;AASP,IAAM,mBAAmB,oBAAI,IAAI,CAAC,mBAAmB,OAAO,CAAC;AAE7D,IAAM,oBAAoB,oBAAI,IAAI;AAAA,EAChC;AAAA,EAAS;AAAA,EAAU;AAAA,EAAY;AAAA,EAAY;AAAA,EAAa;AAAA,EACxD;AAAA,EAAW;AAAA,EAAc;AAAA,EAAgB;AAAA,EAAiB;AAAA,EAC1D;AAAA,EAAU;AAAA,EAAa;AAAA,EAAe;AAAA,EAAgB;AAAA,EACtD;AAAA,EAAO;AAAA,EAAS;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAO;AAC3C,CAAC;AAED,IAAM,sBAAsB,oBAAI,IAAI;AAAA,EAClC;AAAA,EAAS;AAAA,EAAU;AAAA,EAAY;AAAA,EAAY;AAAA,EAAa;AAAA,EACxD;AAAA,EAAU;AAAA,EAAa;AAAA,EAAe;AAAA,EAAgB;AACxD,CAAC;AAGD,IAAM,0BAAwE;AAAA,EAC5E,UAAU,EAAE,KAAK,eAAe,KAAK,cAAc;AAAA,EACnD,eAAe,EAAE,KAAK,oBAAoB,KAAK,mBAAmB;AAAA,EAClE,cAAc,EAAE,KAAK,GAAG,KAAK,kBAAkB;AAAA,EAC/C,qBAAqB,EAAE,KAAK,GAAG,KAAK,kBAAkB;AAAA,EACtD,sBAAsB,EAAE,KAAK,GAAG,KAAK,kBAAkB;AAAA,EACvD,wBAAwB,EAAE,KAAK,GAAG,KAAK,kBAAkB;AAAA,EACzD,yBAAyB,EAAE,KAAK,GAAG,KAAK,kBAAkB;AAC5D;AASA,SAAS,gBAAgB,OAAiC;AACxD,SAAO,OAAO,UAAU;AAC1B;AAKA,SAAS,gBAAgB,OAAiC;AACxD,SAAO,OAAO,UAAU;AAC1B;AAMA,SAAS,UAAU,OAAyB;AAC1C,SAAOC,OAAM,KAAK,KAAKC,QAAO,KAAK;AACrC;AAWA,SAAS,aAAa,OAAwB;AAC5C,QAAM,QAAQ,MAAM,YAAY;AAGhC,MAAI,2CAA2C,KAAK,KAAK,GAAG;AAC1D,WAAO;AAAA,EACT;AAGA,MACE,MAAM,WAAW,MAAM,KACvB,MAAM,WAAW,OAAO,KACxB,MAAM,WAAW,MAAM,KACvB,MAAM,WAAW,OAAO,GACxB;AACA,WAAO;AAAA,EACT;AAGA,MAAI,iBAAiB,IAAI,KAAK,GAAG;AAC/B,WAAO;AAAA,EACT;AAGA,MAAI,UAAU,iBAAiB,UAAU,gBAAgB;AACvD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAUA,SAAS,cAAc,OAAwB;AAC7C,SAAO,sCAAsC,KAAK,KAAK;AACzD;AAQA,SAAS,iBAAiB,OAA8B;AACtD,QAAM,QAAQ,MAAM,MAAM,uCAAuC;AACjE,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,SAAO,OAAO,MAAM,CAAC,CAAC;AACxB;AAOA,SAAS,0BACP,OACA,MACA,QACM;AACN,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,QAAQ,MAAM,YAAY;AAChC,eAAW,MAAM,yBAAyB;AACxC,UAAI,MAAM,SAAS,EAAE,GAAG;AACtB,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,gDAAgD,GAAG,MAAM,GAAG,EAAE,CAAC,SAAS,IAAI;AAAA,YAC5E;AAAA,UACF;AAAA,QACF;AAEA;AAAA,MACF;AAAA,IACF;AACA;AAAA,EACF;AAGA,MAAID,OAAM,KAAK,KAAKC,QAAO,KAAK,GAAG;AACjC;AAAA,EACF;AAEA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,gCAA0B,MAAM,CAAC,GAAG,GAAG,IAAI,IAAI,CAAC,KAAK,MAAM;AAAA,IAC7D;AACA;AAAA,EACF;AAEA,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAgC,GAAG;AAC3E,gCAA0B,OAAO,GAAG,IAAI,IAAI,GAAG,IAAI,MAAM;AAAA,IAC3D;AAAA,EACF;AACF;AAMA,SAAS,qBACP,QACA,MACA,QACM;AACN,MACE,gBAAgB,OAAO,IAAI,KAC3B,OAAO,OAAO,qBACd;AACA,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,mBAAmB,OAAO,IAAI,wBAAwB,mBAAmB,QAAQ,IAAI;AAAA,QACrF,GAAG,IAAI;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,MACE,gBAAgB,OAAO,MAAM,KAC7B,OAAO,SAAS,uBAChB;AACA,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,qBAAqB,OAAO,MAAM,wBAAwB,qBAAqB,QAAQ,IAAI;AAAA,QAC3F,GAAG,IAAI;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAGA,MAAI,gBAAgB,OAAO,KAAK,KAAK,CAAC,aAAa,OAAO,KAAK,GAAG;AAChE,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,kBAAkB,OAAO,KAAK,SAAS,IAAI;AAAA,QAC3C,GAAG,IAAI;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACF;AAMA,IAAM,qBAAqB;AAsB3B,SAAS,oBACP,OACA,WACA,QACM;AAMN,QAAM,oBAAoB,oBAAI,IAAI,CAAC,cAAc,YAAY,CAAC;AAC9D,aAAW,OAAO,OAAO,KAAK,KAAK,GAAG;AACpC,QACE,CAAC,kBAAkB,IAAI,GAAG,KACzB,2BAAiD,SAAS,GAAG,GAC9D;AACA,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,mBAAmB,GAAG,sBAAsB,SAAS,IAAI,GAAG;AAAA,UAC5D,GAAG,SAAS,IAAI,GAAG;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAOA,MAAI,YAAY,SAAS,gBAAgB,MAAM,MAAM,GAAG;AACtD,UAAM,IAAI,MAAM;AAChB,QAAI,IAAI,cAAc,IAAI,YAAY;AACpC,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,WAAW,CAAC,qBAAqB,UAAU,QAAQ,UAAU,QAAQ,SAAS;AAAA,UAC9E,GAAG,SAAS;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,cAAc,SAAS,gBAAgB,MAAM,QAAQ,GAAG;AAC1D,UAAM,IAAI,MAAM;AAChB,QAAI,IAAI,iBAAiB,IAAI,eAAe;AAC1C,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,aAAa,CAAC,qBAAqB,aAAa,QAAQ,aAAa,QAAQ,SAAS;AAAA,UACtF,GAAG,SAAS;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,aAAa,SAAS,gBAAgB,MAAM,OAAO,GAAG;AACxD,UAAM,IAAI,MAAM;AAChB,QAAI,IAAI,eAAe,IAAI,aAAa;AACtC,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,YAAY,CAAC,qBAAqB,WAAW,QAAQ,WAAW,QAAQ,SAAS;AAAA,UACjF,GAAG,SAAS;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,mBAAmB,SAAS,gBAAgB,MAAM,aAAa,GAAG;AACpE,UAAM,IAAI,MAAM;AAChB,QAAI,IAAI,sBAAsB,IAAI,oBAAoB;AACpD,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,kBAAkB,CAAC,qBAAqB,kBAAkB,QAAQ,kBAAkB,QAAQ,SAAS;AAAA,UACrG,GAAG,SAAS;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,aAAW,QAAQ;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAAY;AACV,QAAI,QAAQ,SAAS,gBAAgB,MAAM,IAAI,CAAC,GAAG;AACjD,YAAM,IAAI,MAAM,IAAI;AACpB,UAAI,IAAI,KAAK,IAAI,mBAAmB;AAClC,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,GAAG,IAAI,KAAK,CAAC,2BAA2B,iBAAiB,QAAQ,SAAS,IAAI,IAAI;AAAA,YAClF,GAAG,SAAS,IAAI,IAAI;AAAA,UACtB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MACE,eAAe,SACf,OAAO,MAAM,cAAc,YAC3B,MAAM,cAAc,QACpB,CAAC,UAAU,MAAM,SAAS,GAC1B;AACA,UAAM,YAAY,MAAM;AACxB,UAAM,gBAAgB,GAAG,SAAS;AAGlC,QAAI,WAAW,aAAa,gBAAgB,UAAU,KAAK,GAAG;AAC5D,YAAM,IAAI,UAAU;AACpB,UAAI,IAAI,uBAAuB,IAAI,qBAAqB;AACtD,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,oBAAoB,CAAC,qBAAqB,mBAAmB,QAAQ,mBAAmB,QAAQ,aAAa;AAAA,YAC7G,GAAG,aAAa;AAAA,UAClB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,QAAI,gBAAgB,aAAa,gBAAgB,UAAU,UAAU,GAAG;AACtE,YAAM,IAAI,UAAU;AACpB,UAAI,IAAI,2BAA2B,IAAI,yBAAyB;AAC9D,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,yBAAyB,CAAC,qBAAqB,uBAAuB,QAAQ,uBAAuB,QAAQ,aAAa;AAAA,YAC1H,GAAG,aAAa;AAAA,UAClB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,QAAI,gBAAgB,aAAa,gBAAgB,UAAU,UAAU,GAAG;AACtE,YAAM,IAAI,UAAU;AACpB,UAAI,IAAI,2BAA2B,IAAI,yBAAyB;AAC9D,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,yBAAyB,CAAC,qBAAqB,uBAAuB,QAAQ,uBAAuB,QAAQ,aAAa;AAAA,YAC1H,GAAG,aAAa;AAAA,UAClB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAKA,QAAI,UAAU,WAAW;AACvB,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,mCAAmC,aAAa;AAAA,UAChD,GAAG,aAAa;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAKA,MAAI,eAAe,SAAS,MAAM,aAAa,MAAM;AACnD,UAAM,YAAY,MAAM;AACxB,UAAM,gBAAgB,GAAG,SAAS;AAElC,QAAI,MAAM,QAAQ,SAAS,GAAG;AAE5B,UAAI,UAAU,SAAS,sBAAsB;AAC3C,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,iBAAiB,UAAU,MAAM,wBAAwB,oBAAoB,QAAQ,aAAa;AAAA,YAClG;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,eAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,cAAM,SAAS,UAAU,CAAC;AAC1B,YAAI,OAAO,WAAW,YAAY,WAAW,MAAM;AACjD;AAAA,YACE;AAAA,YACA,GAAG,aAAa,IAAI,CAAC;AAAA,YACrB;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,WAAW,OAAO,cAAc,YAAY,cAAc,MAAM;AAE9D;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAKA,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,8BAA0B,OAAO,GAAG,SAAS,IAAI,GAAG,IAAI,MAAM;AAAA,EAChE;AAKA,MAAI,cAAc,SAAS,MAAM,aAAa,UAAU;AACtD,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,0EAA0E,SAAS;AAAA,QACnF,GAAG,SAAS;AAAA,MACd;AAAA,IACF;AAAA,EACF;AAKA,aAAW,QAAQ,kBAAkB;AACnC,QACE,QAAQ,SACR,gBAAgB,MAAM,IAAI,CAAC,KAC3B,CAAC,UAAU,MAAM,IAAI,CAAC,GACtB;AACA,UAAI,CAAC,aAAa,MAAM,IAAI,CAAW,GAAG;AACxC,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,kBAAkB,MAAM,IAAI,CAAC,SAAS,SAAS,IAAI,IAAI;AAAA,YACvD,GAAG,SAAS,IAAI,IAAI;AAAA,UACtB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAKA,aAAW,QAAQ,mBAAmB;AACpC,QACE,QAAQ,SACR,gBAAgB,MAAM,IAAI,CAAC,KAC3B,CAAC,UAAU,MAAM,IAAI,CAAC,GACtB;AACA,YAAM,MAAM,MAAM,IAAI;AACtB,UAAI,QAAQ,QAAQ;AAClB,YAAI,CAAC,oBAAoB,IAAI,IAAI,GAAG;AAClC,iBAAO;AAAA,YACL;AAAA,cACE;AAAA,cACA,8BAA8B,IAAI,SAAS,SAAS,IAAI,IAAI;AAAA,cAC5D,GAAG,SAAS,IAAI,IAAI;AAAA,YACtB;AAAA,UACF;AAAA,QACF;AAAA,MACF,WAAW,CAAC,cAAc,GAAG,GAAG;AAC9B,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,mBAAmB,GAAG,SAAS,SAAS,IAAI,IAAI;AAAA,YAChD,GAAG,SAAS,IAAI,IAAI;AAAA,UACtB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAKA,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,uBAAuB,GAAG;AACnE,QACE,QAAQ,SACR,gBAAgB,MAAM,IAAI,CAAC,KAC3B,CAAC,UAAU,MAAM,IAAI,CAAC,GACtB;AACA,YAAM,eAAe,iBAAiB,MAAM,IAAI,CAAW;AAC3D,UAAI,iBAAiB,MAAM;AACzB,YAAI,eAAe,MAAM,OAAO,eAAe,MAAM,KAAK;AACxD,iBAAO;AAAA,YACL;AAAA,cACE;AAAA,cACA,GAAG,IAAI,KAAK,MAAM,IAAI,CAAC,qBAAqB,MAAM,GAAG,QAAQ,MAAM,GAAG,QAAQ,SAAS,IAAI,IAAI;AAAA,cAC/F,GAAG,SAAS,IAAI,IAAI;AAAA,YACtB;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAKA,QAAM,aAAa,CAAC,UAAU,aAAa,eAAe,gBAAgB,YAAY;AACtF,aAAW,aAAa,YAAY;AAClC,QACE,aAAa,SACb,OAAO,MAAM,SAAS,MAAM,YAC5B,MAAM,SAAS,MAAM,QACrB,CAAC,UAAU,MAAM,SAAS,CAAC,GAC3B;AACA,YAAM,SAAS,MAAM,SAAS;AAC9B,YAAM,aAAa,GAAG,SAAS,IAAI,SAAS;AAE5C,UACE,gBAAgB,OAAO,KAAK,KAC5B,CAAC,UAAU,OAAO,KAAK,KACvB,CAAC,aAAa,OAAO,KAAK,GAC1B;AACA,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,kBAAkB,OAAO,KAAK,SAAS,UAAU;AAAA,YACjD,GAAG,UAAU;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAKA,MACE,wBAAwB,SACxB,OAAO,MAAM,uBAAuB,YACpC,MAAM,uBAAuB,QAC7B,CAAC,UAAU,MAAM,kBAAkB,GACnC;AACA,UAAM,WAAW,MAAM;AACvB,UAAM,eAAe,GAAG,SAAS;AAEjC,QAAI,MAAM,QAAQ,SAAS,KAAK,GAAG;AACjC,eAAS,IAAI,GAAG,IAAI,SAAS,MAAM,QAAQ,KAAK;AAC9C,cAAM,OAAO,SAAS,MAAM,CAAC;AAC7B,YACE,OAAO,SAAS,YAChB,SAAS,QACT,CAAC,UAAU,IAAI,GACf;AACA,gBAAM,UAAU;AAChB,cACE,gBAAgB,QAAQ,KAAK,KAC7B,CAAC,UAAU,QAAQ,KAAK,KACxB,CAAC,aAAa,QAAQ,KAAK,GAC3B;AACA,mBAAO;AAAA,cACL;AAAA,gBACE;AAAA,gBACA,kBAAkB,QAAQ,KAAK,SAAS,YAAY,UAAU,CAAC;AAAA,gBAC/D,GAAG,YAAY,UAAU,CAAC;AAAA,cAC5B;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAKA,MAAI,gBAAgB,SAAS,MAAM,cAAc,MAAM;AACrD,UAAM,aAAa,MAAM;AACzB,UAAM,YAAY,GAAG,SAAS;AAE9B,QAAI,OAAO,eAAe,YAAY,MAAM,QAAQ,UAAU,GAAG;AAC/D,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,oCAAoC,SAAS;AAAA,UAC7C;AAAA,QACF;AAAA,MACF;AAAA,IACF,OAAO;AACL,YAAM,WAAW;AAGjB,UAAI,gBAAgB,UAAU;AAC5B,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,sCAAsC,SAAS;AAAA,YAC/C,GAAG,SAAS;AAAA,UACd;AAAA,QACF;AAAA,MACF;AAGA,UAAI,YAAY,UAAU;AACxB,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,+CAA+C,SAAS;AAAA,YACxD,GAAG,SAAS;AAAA,UACd;AAAA,QACF;AAAA,MACF;AAGA,0BAAoB,UAAU,WAAW,MAAM;AAAA,IACjD;AAAA,EACF;AAKA,MAAI,gBAAgB,SAAS,MAAM,cAAc,MAAM;AACrD,UAAM,aAAa,MAAM;AACzB,UAAM,YAAY,GAAG,SAAS;AAG9B,QAAI,OAAO,eAAe,UAAU;AAClC,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,2DAA2D,SAAS;AAAA,UACpE;AAAA,QACF;AAAA,MACF;AAAA,IACF,OAAO;AACL,YAAM,cAAc,MAAM,QAAQ,UAAU,IAAI,aAAa,CAAC,UAAU;AAExE,UAAI,YAAY,SAAS,sBAAsB;AAC7C,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,kBAAkB,YAAY,MAAM,wBAAwB,oBAAoB,QAAQ,SAAS;AAAA,YACjG;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,eAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC3C,cAAM,IAAI,YAAY,CAAC;AACvB,cAAM,QAAQ,MAAM,QAAQ,UAAU,IAAI,GAAG,SAAS,IAAI,CAAC,MAAM;AAEjE,YAAI,OAAO,MAAM,YAAY,MAAM,KAAM;AACzC,cAAM,OAAO;AAGb,YACE,gBAAgB,KAAK,QAAQ,KAC7B,CAAE,8BAAoD,SAAS,KAAK,QAAQ,GAC5E;AACA,iBAAO;AAAA,YACL;AAAA,cACE;AAAA,cACA,wBAAwB,KAAK,QAAQ,oCAAoC,KAAK;AAAA,cAC9E,GAAG,KAAK;AAAA,YACV;AAAA,UACF;AAAA,QACF;AAGA,YAAI,gBAAgB,KAAK,QAAQ,GAAG;AAClC,cAAI,KAAK,WAAW,KAAK,KAAK,WAAW,yBAAyB;AAChE,mBAAO;AAAA,cACL;AAAA,gBACE;AAAA,gBACA,wBAAwB,KAAK,QAAQ,2BAA2B,uBAAuB,QAAQ,KAAK;AAAA,gBACpG,GAAG,KAAK;AAAA,cACV;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAGA,YAAI,gBAAgB,KAAK,KAAK,GAAG;AAC/B,cAAI,KAAK,QAAQ,KAAK,KAAK,QAAQ,sBAAsB;AACvD,mBAAO;AAAA,cACL;AAAA,gBACE;AAAA,gBACA,qBAAqB,KAAK,KAAK,2BAA2B,oBAAoB,QAAQ,KAAK;AAAA,gBAC3F,GAAG,KAAK;AAAA,cACV;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAUA,SAAS,kBACP,gBACA,aACyB;AACzB,QAAM,SAAkC,EAAE,GAAG,eAAe;AAC5D,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,WAAW,GAAG;AACtD,QAAI,QAAQ,UAAU;AACpB,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AACA,SAAO;AACT;AAsBO,SAAS,eACd,OACA,YACmB;AACnB,QAAM,SAA4B,CAAC;AAKnC,MAAI,YAAY;AACd,eAAW,CAAC,WAAW,UAAU,KAAK,OAAO,QAAQ,UAAU,GAAG;AAChE,YAAM,YAAY,UAAU,SAAS;AAIrC,UAAI,CAAC,mBAAmB,KAAK,SAAS,GAAG;AACvC,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,eAAe,SAAS,2DAA2D,SAAS;AAAA,YAC5F;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,UAAI,YAAY,YAAY;AAC1B,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,4DAA4D,SAAS;AAAA,YACrE,GAAG,SAAS;AAAA,UACd;AAAA,QACF;AAAA,MACF;AAGA,0BAAoB,YAAY,WAAW,MAAM;AAAA,IACnD;AAAA,EACF;AAKA,eAAa,OAAO,CAAC,MAAuB,QAA0B;AACpE,UAAM,QAAQ,KAAK;AACnB,QAAI,SAAS,QAAQ,OAAO,UAAU,UAAU;AAC9C;AAAA,IACF;AAEA,UAAM,YAAY,GAAG,IAAI,IAAI;AAG7B,QAAI,YAAY,SAAS,OAAO,MAAM,WAAW,UAAU;AACzD,YAAM,SAAS,MAAM;AACrB,YAAM,aAAa,OAAO,KAAK;AAG/B,UAAI,CAAC,mBAAmB,KAAK,UAAU,GAAG;AACxC,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,iBAAiB,MAAM,2DAA2D,SAAS;AAAA,YAC3F,GAAG,SAAS;AAAA,UACd;AAAA,QACF;AACA;AAAA,MACF;AAGA,UAAI,CAAC,cAAc,EAAE,cAAc,aAAa;AAC9C,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,sBAAsB,UAAU,6CAA6C,SAAS;AAAA,YACtF,GAAG,SAAS;AAAA,UACd;AAAA,QACF;AACA;AAAA,MACF;AAGA,YAAM,cAAc,kBAAkB,WAAW,UAAU,GAAG,KAAK;AAGnE,0BAAoB,aAAa,WAAW,MAAM;AAAA,IACpD,OAAO;AAEL,0BAAoB,OAAO,WAAW,MAAM;AAAA,IAC9C;AAAA,EACF,CAAC;AAED,SAAO;AACT;;;ACh5BA;AAAA,EACE;AAAA,EACA,SAAAC;AAAA,OACK;AAkBP,IAAM,yBAAyB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAeA,SAAS,YACP,KACA,MACA,QACM;AACN,MAAI,QAAQ,QAAQ,QAAQ,UAAa,OAAO,QAAQ,UAAU;AAChE;AAAA,EACF;AAGA,MAAIC,OAAM,GAAG,GAAG;AACd,UAAM,SAAU,IAAyB;AAEzC,UAAM,WAAW,OAAO,MAAM,OAAO;AACrC,eAAW,WAAW,UAAU;AAE9B,YAAM,QAAQ,QAAQ,QAAQ,MAAM,EAAE;AACtC,UACG,6BAAmD,SAAS,KAAK,GAClE;AACA,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,SAAS,MAAM,qDAAqD,KAAK;AAAA,YACzE;AAAA,UACF;AAAA,QACF;AAEA;AAAA,MACF;AAAA,IACF;AACA;AAAA,EACF;AAGA,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,kBAAY,IAAI,CAAC,GAAG,GAAG,IAAI,IAAI,CAAC,KAAK,MAAM;AAAA,IAC7C;AACA;AAAA,EACF;AAGA,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC9C,gBAAY,OAAO,GAAG,IAAI,IAAI,GAAG,IAAI,MAAM;AAAA,EAC7C;AACF;AAUA,SAAS,eAAe,OAAwB;AAC9C,QAAM,QAAQ,MAAM,KAAK,EAAE,YAAY;AACvC,SAAO,uBAAuB,KAAK,CAAC,WAAW,MAAM,WAAW,MAAM,CAAC;AACzE;AAYA,SAAS,kBACP,OACsD;AACtD,MAAI,CAAC,MAAM,WAAW,UAAU,GAAG;AACjC,WAAO;AAAA,EACT;AACA,MAAI,MAAM,SAAS,KAAK,GAAG;AACzB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAgBA,SAAS,oBACP,SACA,OACS;AAET,QAAM,OAAO,QAAQ,WAAW,GAAG,IAAI,QAAQ,MAAM,CAAC,IAAI;AAC1D,QAAM,cAAc,KAAK,MAAM,GAAG;AAIlC,QAAM,OAAiB,CAAC;AACxB,aAAW,UAAU,aAAa;AAEhC,UAAM,iBAAiB;AACvB,UAAM,eAAe,OAAO,QAAQ,GAAG;AACvC,UAAM,WAAW,iBAAiB,KAAK,SAAS,OAAO,MAAM,GAAG,YAAY;AAC5E,QAAI,UAAU;AACZ,WAAK,KAAK,QAAQ;AAAA,IACpB;AACA,QAAI;AACJ,YAAQ,QAAQ,eAAe,KAAK,MAAM,OAAO,MAAM;AACrD,WAAK,KAAK,MAAM,CAAC,CAAC;AAAA,IACpB;AAAA,EACF;AAGA,aAAW,OAAO,MAAM;AACtB,QACG,6BAAmD,SAAS,GAAG,GAChE;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAGA,MAAI,UAAmB;AACvB,aAAW,OAAO,MAAM;AACtB,QAAI,WAAW,QAAQ,OAAO,YAAY,SAAU,QAAO;AAE3D,QAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,YAAM,QAAQ,OAAO,GAAG;AACxB,UAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,EAAG,QAAO;AAClD,gBAAU,QAAQ,KAAK;AAAA,IACzB,OAAO;AACL,gBAAW,QAAoC,GAAG;AAAA,IACpD;AAAA,EACF;AACA,SAAO;AACT;AASA,SAAS,cACP,UACA,MACA,WACA,QACM;AACN,MAAI,eAAe,QAAQ,GAAG;AAC5B,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,oCAAoC,IAAI,cAAc,QAAQ;AAAA,QAC9D;AAAA,MACF;AAAA,IACF;AAAA,EACF,OAAO;AACL,UAAM,aAAa,kBAAkB,QAAQ;AAC7C,QAAI,eAAe,wBAAwB;AACzC,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,oDAAoD,QAAQ;AAAA,UAC5D;AAAA,QACF;AAAA,MACF;AAAA,IACF,WAAW,eAAe,sBAAsB;AAC9C,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,+CAA+C,QAAQ;AAAA,UACvD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAqBO,SAAS,iBAAiB,MAKX;AACpB,QAAM,SAA4B,CAAC;AACnC,QAAM,EAAE,OAAO,OAAO,YAAY,WAAW,IAAI;AAKjD,MAAI,YAAY;AACd,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,YAAM,aAAa,kBAAkB,KAAK;AAC1C,UAAI,eAAe,wBAAwB;AACzC,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,oDAAoD,KAAK;AAAA,YACzD,UAAU,GAAG;AAAA,UACf;AAAA,QACF;AAAA,MACF,WAAW,eAAe,sBAAsB;AAC9C,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,+CAA+C,KAAK;AAAA,YACpD,UAAU,GAAG;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,eAAa,OAAO,CAAC,MAAuB,YAA8B;AACxE,UAAM,EAAE,KAAK,IAAI;AACjB,UAAM,EAAE,OAAO,KAAK,IAAI;AACxB,UAAM,aAAa,EAAE,GAAG,KAAK;AAC7B,WAAO,WAAW;AAClB,WAAO,WAAW;AAClB,WAAO,WAAW;AAClB,WAAO,WAAW;AAKlB,QAAI,SAAS,WAAW,SAAS,UAAU;AACzC,YAAM,MAAO,KAAiC;AAC9C,UAAI,OAAO,QAAQ,UAAU;AAE3B,sBAAc,KAAK,MAAM,GAAG,IAAI,QAAQ,MAAM;AAAA,MAChD,WAAWA,OAAM,GAAG,GAAG;AAErB,YAAI,OAAO;AACT,gBAAM,WAAW;AAAA,YACd,IAAyB;AAAA,YAC1B;AAAA,UACF;AACA,cAAI,OAAO,aAAa,UAAU;AAChC,0BAAc,UAAU,MAAM,GAAG,IAAI,QAAQ,MAAM;AAAA,UACrD;AAAA,QAEF;AAAA,MAEF;AAAA,IACF;AAKA,QAAI,OAAO;AACT,iBAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AACjD,YAAI,OAAO,UAAU,YAAY,MAAM,YAAY,EAAE,SAAS,MAAM,GAAG;AACrE,iBAAO;AAAA,YACL;AAAA,cACE;AAAA,cACA,8DAA8D,IAAI;AAAA,cAClE,GAAG,IAAI,UAAU,IAAI;AAAA,YACvB;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAMA,QAAI,iBAAiB;AACrB,QACE,SACA,OAAO,MAAM,WAAW,YACxB,cACA,MAAM,OAAO,KAAK,KAAK,YACvB;AACA,YAAM,UAAU,MAAM,OAAO,KAAK;AAClC,YAAM,SAAkC,EAAE,GAAG,WAAW,OAAO,EAAE;AACjE,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,YAAI,QAAQ,UAAU;AACpB,iBAAO,GAAG,IAAI;AAAA,QAChB;AAAA,MACF;AACA,uBAAiB;AAAA,IACnB;AAEA,QAAI,kBAAkB,OAAO,eAAe,aAAa,UAAU;AACjE,YAAM,WAAW,eAAe;AAEhC,UAAI,aAAa,SAAS;AACxB,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA;AAAA,YACA,GAAG,IAAI;AAAA,UACT;AAAA,QACF;AAAA,MACF,WAAW,aAAa,UAAU;AAChC,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA;AAAA,YACA,GAAG,IAAI;AAAA,UACT;AAAA,QACF;AAAA,MACF,WAAW,aAAa,YAAY;AAClC,YAAI,QAAQ,eAAe,SAAS;AAClC,iBAAO;AAAA,YACL;AAAA,cACE;AAAA,cACA;AAAA,cACA,GAAG,IAAI;AAAA,YACT;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAKA,QACE,kBACA,eAAe,aAAa,UAC5B,QAAQ,sBACR;AACA,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA;AAAA,UACA,GAAG,IAAI;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAKA,gBAAY,YAAY,MAAM,MAAM;AACpC,QAAI,OAAO;AACT,kBAAY,OAAO,GAAG,IAAI,UAAU,MAAM;AAAA,IAC5C;AAAA,EACF,CAAC;AAED,SAAO;AACT;;;AClaA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,gCAAAC;AAAA,EACA,SAAAC;AAAA,EACA,UAAAC;AAAA,OACK;AAaP,SAAS,eAAe,KAAqB;AAC3C,MAAI,QAAQ;AACZ,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAM,OAAO,IAAI,WAAW,CAAC;AAC7B,QAAI,QAAQ,KAAM;AAChB,eAAS;AAAA,IACX,WAAW,QAAQ,MAAO;AACxB,eAAS;AAAA,IACX,WAAW,QAAQ,SAAU,QAAQ,OAAQ;AAE3C,eAAS;AACT;AAAA,IACF,OAAO;AACL,eAAS;AAAA,IACX;AAAA,EACF;AACA,SAAO;AACT;AAYA,SAASC,qBACP,SACA,OACS;AAET,QAAM,OAAO,QAAQ,WAAW,GAAG,IAAI,QAAQ,MAAM,CAAC,IAAI;AAC1D,QAAM,cAAc,KAAK,MAAM,GAAG;AAIlC,QAAM,OAAiB,CAAC;AACxB,aAAW,UAAU,aAAa;AAChC,UAAM,iBAAiB;AACvB,UAAM,eAAe,OAAO,QAAQ,GAAG;AACvC,UAAM,WAAW,iBAAiB,KAAK,SAAS,OAAO,MAAM,GAAG,YAAY;AAC5E,QAAI,UAAU;AACZ,WAAK,KAAK,QAAQ;AAAA,IACpB;AACA,QAAI;AACJ,YAAQ,QAAQ,eAAe,KAAK,MAAM,OAAO,MAAM;AACrD,WAAK,KAAK,MAAM,CAAC,CAAC;AAAA,IACpB;AAAA,EACF;AAGA,aAAW,OAAO,MAAM;AACtB,QACGC,8BAAmD,SAAS,GAAG,GAChE;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAGA,MAAI,UAAmB;AACvB,aAAW,OAAO,MAAM;AACtB,QAAI,WAAW,QAAQ,OAAO,YAAY,SAAU,QAAO;AAE3D,QAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,YAAM,QAAQ,OAAO,GAAG;AACxB,UAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,EAAG,QAAO;AAClD,gBAAU,QAAQ,KAAK;AAAA,IACzB,OAAO;AACL,gBAAW,QAAoC,GAAG;AAAA,IACpD;AAAA,EACF;AACA,SAAO;AACT;AAkBA,SAAS,qBACP,UACA,YACiB;AACjB,QAAM,SAA0B,EAAE,OAAO,GAAG,WAAW,GAAG,YAAY,GAAG,mBAAmB,EAAE;AAC9F,MAAI,YAAY,QAAQ,OAAO,aAAa,SAAU,QAAO;AAE7D,QAAM,OAAO;AACb,MAAI,CAAC,KAAK,KAAM,QAAO;AAEvB,SAAO,QAAQ;AAGf,MAAI,KAAK,SAAS,QAAQ;AACxB,UAAM,UAAW,KAAiC;AAClD,QAAI,OAAO,YAAY,YAAY,CAACC,OAAM,OAAO,KAAK,CAACC,QAAO,OAAO,GAAG;AACtE,aAAO,YAAY,eAAe,OAAO;AAAA,IAC3C;AAAA,EACF;AAGA,MAAI,KAAK,SAAS,QAAQ,OAAO,KAAK,UAAU,UAAU;AACxD,UAAM,QAAQ,KAAK;AACnB,QAAI,gBAAgB;AACpB,QACE,OAAO,MAAM,WAAW,YACxB,cACA,MAAM,OAAO,KAAK,KAAK,YACvB;AACA,YAAM,UAAW,MAAM,OAAkB,KAAK;AAC9C,YAAM,SAAkC,EAAE,GAAG,WAAW,OAAO,EAAE;AACjE,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,YAAI,QAAQ,SAAU,QAAO,GAAG,IAAI;AAAA,MACtC;AACA,sBAAgB;AAAA,IAClB;AACA,WAAO,aAAa,eAAe,KAAK,UAAU,aAAa,CAAC;AAGhE,QAAI,oBAAoB,MAAM;AAC9B,QACE,OAAO,MAAM,WAAW,YACxB,cACA,MAAM,OAAO,KAAK,KAAK,YACvB;AACA,YAAM,UAAW,MAAM,OAAkB,KAAK;AAC9C,UAAI,EAAE,cAAc,UAAU,MAAM,aAAa,QAAW;AAC1D,4BAAoB,WAAW,OAAO,EAAE;AAAA,MAC1C;AAAA,IACF;AACA,QAAI,sBAAsB,QAAQ;AAChC,aAAO,oBAAoB;AAAA,IAC7B;AAAA,EACF;AAGA,QAAM,WAAW,KAAK;AACtB,MAAI,MAAM,QAAQ,QAAQ,GAAG;AAC3B,eAAW,SAAS,UAAU;AAC5B,YAAM,eAAe,qBAAqB,OAAO,UAAU;AAC3D,aAAO,SAAS,aAAa;AAC7B,aAAO,aAAa,aAAa;AACjC,aAAO,cAAc,aAAa;AAClC,aAAO,qBAAqB,aAAa;AAAA,IAC3C;AAAA,EACF,WACE,YAAY,QACZ,OAAO,aAAa,YACpB,CAAC,MAAM,QAAQ,QAAQ,KACvB,cAAe,UACf;AAGA,UAAM,gBAAiB,SAAqC;AAC5D,UAAM,eAAe,qBAAqB,eAAe,UAAU;AACnE,WAAO,SAAS,aAAa;AAC7B,WAAO,aAAa,aAAa;AACjC,WAAO,cAAc,aAAa;AAClC,WAAO,qBAAqB,aAAa;AAAA,EAC3C;AAEA,SAAO;AACT;AAqBO,SAAS,eACd,MACmB;AACnB,QAAM,SAA4B,CAAC;AAEnC,MAAI,YAAY;AAChB,MAAI,mBAAmB;AACvB,MAAI,oBAAoB;AACxB,MAAI,oBAAoB;AAExB,eAAa,KAAK,OAAO,CAAC,MAAuB,YAA8B;AAI7E;AAKA,QAAI,KAAK,SAAS,QAAQ;AACxB,YAAM,UAAW,KAAiC;AAClD,UAAI,OAAO,YAAY,YAAY,CAACD,OAAM,OAAO,KAAK,CAACC,QAAO,OAAO,GAAG;AACtE,4BAAoB,eAAe,OAAO;AAAA,MAC5C;AAAA,IACF;AAKA,QAAI,KAAK,SAAS,QAAQ,OAAO,KAAK,UAAU,UAAU;AACxD,UAAI,gBAAgB,KAAK;AACzB,UACE,OAAO,KAAK,MAAM,WAAW,YAC7B,KAAK,cACL,KAAK,MAAM,OAAO,KAAK,KAAK,KAAK,YACjC;AACA,cAAM,UAAU,KAAK,MAAM,OAAO,KAAK;AACvC,cAAM,SAAkC,EAAE,GAAG,KAAK,WAAW,OAAO,EAAE;AACtE,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,KAAK,GAAG;AACrD,cAAI,QAAQ,UAAU;AACpB,mBAAO,GAAG,IAAI;AAAA,UAChB;AAAA,QACF;AACA,wBAAgB;AAAA,MAClB;AACA,YAAM,aAAa,KAAK,UAAU,aAAa;AAC/C,2BAAqB,eAAe,UAAU;AAAA,IAChD;AAKA,UAAM,WAAW,KAAK;AACtB,QACE,YAAY,QACZ,OAAO,aAAa,YACpB,CAAC,MAAM,QAAQ,QAAQ,KACvB,SAAS,YACT,QAAQ,YACR,cAAc,UACd;AACA,YAAM,UAAU;AAChB,YAAM,UAAU,QAAQ;AAExB,UAAI,OAAO,YAAY,YAAY,QAAQ,WAAW,GAAG,GAAG;AAC1D,YAAI,KAAK,SAAS,MAAM;AAAA,QAExB,OAAO;AACL,gBAAM,SAASH,qBAAoB,SAAS,KAAK,KAAK;AACtD,cAAI,WAAW,QAAW;AAKxB,kBAAM,kBAAkB,QAAQ,MAAM,CAAC;AACvC,gBAAI,CAAC,gBAAgB,SAAS,GAAG,KAAK,QAAQ,cAAc,GAAG;AAC7D,qBAAO;AAAA,gBACL;AAAA,kBACE;AAAA,kBACA,gBAAgB,OAAO;AAAA,kBACvB,GAAG,QAAQ,IAAI;AAAA,gBACjB;AAAA,cACF;AAAA,YACF;AAAA,UACF,WAAW,CAAC,MAAM,QAAQ,MAAM,GAAG;AACjC,mBAAO;AAAA,cACL;AAAA,gBACE;AAAA,gBACA,gBAAgB,OAAO;AAAA,gBACvB,GAAG,QAAQ,IAAI;AAAA,cACjB;AAAA,YACF;AAAA,UACF,WAAW,OAAO,SAAS,qBAAqB;AAC9C,mBAAO;AAAA,cACL;AAAA,gBACE;AAAA,gBACA,gBAAgB,OAAO,SAAS,OAAO,MAAM,kBAAkB,mBAAmB;AAAA,gBAClF,GAAG,QAAQ,IAAI;AAAA,cACjB;AAAA,YACF;AAAA,UACF,WAAW,OAAO,SAAS,GAAG;AAG5B,kBAAM,aAAa,qBAAqB,QAAQ,UAAU,KAAK,UAAU;AACzE,kBAAM,aAAa,OAAO,SAAS;AACnC,yBAAa,WAAW,QAAQ;AAChC,gCAAoB,WAAW,YAAY;AAC3C,iCAAqB,WAAW,aAAa;AAC7C,iCAAqB,WAAW,oBAAoB;AAAA,UACtD;AAAA,QACF;AAAA,MACF;AAKA,UAAI,QAAQ,aAAa,kBAAkB;AACzC,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,sBAAsB,QAAQ,YAAY,CAAC,uBAAuB,gBAAgB;AAAA,YAClF,GAAG,QAAQ,IAAI;AAAA,UACjB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAKA;AACE,UAAI,oBAAoB,KAAK,OAAO;AACpC,UACE,KAAK,SACL,OAAO,KAAK,MAAM,WAAW,YAC7B,KAAK,cACL,KAAK,MAAM,OAAO,KAAK,KAAK,KAAK,YACjC;AACA,cAAM,UAAU,KAAK,MAAM,OAAO,KAAK;AAEvC,YAAI,EAAE,cAAc,KAAK,UAAU,KAAK,MAAM,aAAa,QAAW;AACpE,8BAAoB,KAAK,WAAW,OAAO,EAAE;AAAA,QAC/C;AAAA,MACF;AACA,UAAI,sBAAsB,QAAQ;AAChC;AAAA,MACF;AAAA,IACF;AAKA,QAAI,KAAK,SAAS,WAAW,QAAQ,cAAc,mBAAmB;AACpE,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,uBAAuB,QAAQ,aAAa,CAAC,uBAAuB,iBAAiB;AAAA,UACrF,QAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AAMD,MAAI,YAAY,gBAAgB;AAC9B,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,YAAY,SAAS,kBAAkB,cAAc;AAAA,QACrD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,mBAAmB,8BAA8B;AACnD,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,yBAAyB,gBAAgB,kBAAkB,4BAA4B;AAAA,QACvF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,oBAAoB,+BAA+B;AACrD,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,+BAA+B,iBAAiB,kBAAkB,6BAA6B;AAAA,QAC/F;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,oBAAoB,yBAAyB;AAC/C,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,YAAY,iBAAiB,wCAAwC,uBAAuB;AAAA,QAC5F;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AC7aA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAAI;AAAA,EACA,UAAAC;AAAA,OACK;AA8BP,IAAM,qBAAqB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,wBAAwB,IAAI,IAAY,kBAAkB;AAMhE,IAAMC,gCAA+B,oBAAI,IAAI;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAMD,SAAS,SACP,MACA,MACgD;AAChD,QAAM,SAAkB,CAAC;AACzB,QAAM,SAA4B,CAAC;AACnC,MAAI,IAAI;AAER,SAAO,IAAI,KAAK,QAAQ;AAEtB,QAAI,KAAK,KAAK,KAAK,CAAC,CAAC,GAAG;AACtB;AACA;AAAA,IACF;AAGA,QAAI,IAAI,IAAI,KAAK,QAAQ;AACvB,YAAM,QAAQ,KAAK,MAAM,GAAG,IAAI,CAAC;AACjC,UAAI,UAAU,SAAS,UAAU,OAAO;AACtC,eAAO,KAAK,EAAE,MAAM,cAAc,OAAO,OAAO,UAAU,EAAE,CAAC;AAC7D,aAAK;AACL;AAAA,MACF;AAAA,IACF;AAGA,QAAI,IAAI,IAAI,KAAK,QAAQ;AACvB,YAAM,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;AAC/B,UAAI,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,MAAM;AAChE,eAAO,KAAK,EAAE,MAAM,cAAc,OAAO,KAAK,UAAU,EAAE,CAAC;AAC3D,aAAK;AACL;AAAA,MACF;AACA,UAAI,QAAQ,QAAQ,QAAQ,MAAM;AAChC,eAAO,KAAK,EAAE,MAAM,iBAAiB,OAAO,KAAK,UAAU,EAAE,CAAC;AAC9D,aAAK;AACL;AAAA,MACF;AAAA,IACF;AAGA,QAAI,KAAK,CAAC,MAAM,OAAO,KAAK,CAAC,MAAM,KAAK;AACtC,YAAM,QAAQ,KAAK,CAAC;AACpB,UAAI,IAAI,IAAI;AACZ,aAAO,IAAI,KAAK,UAAU,KAAK,CAAC,MAAM,OAAO;AAE3C,YAAI,KAAK,CAAC,MAAM,QAAQ,IAAI,IAAI,KAAK,QAAQ;AAC3C,eAAK;AAAA,QACP,OAAO;AACL;AAAA,QACF;AAAA,MACF;AAEA,YAAM,aAAa,KAAK,MAAM,IAAI,GAAG,CAAC;AACtC,aAAO,KAAK,EAAE,MAAM,UAAU,OAAO,YAAY,UAAU,EAAE,CAAC;AAC9D,UAAI,IAAI;AACR;AAAA,IACF;AAOA,QAAI,QAAQ,KAAK,KAAK,CAAC,CAAC,KAAM,KAAK,CAAC,MAAM,OAAO,IAAI,IAAI,KAAK,UAAU,QAAQ,KAAK,KAAK,IAAI,CAAC,CAAC,KAAK,eAAe,MAAM,GAAI;AAC5H,UAAI,IAAI;AACR,UAAI,KAAK,CAAC,MAAM,IAAK;AACrB,aAAO,IAAI,KAAK,UAAU,QAAQ,KAAK,KAAK,CAAC,CAAC,EAAG;AACjD,UAAI,IAAI,KAAK,UAAU,KAAK,CAAC,MAAM,KAAK;AACtC;AACA,eAAO,IAAI,KAAK,UAAU,QAAQ,KAAK,KAAK,CAAC,CAAC,EAAG;AAAA,MACnD;AACA,YAAM,SAAS,KAAK,MAAM,GAAG,CAAC;AAE9B,YAAM,SAAS,OAAO,QAAQ,GAAG;AACjC,UAAI,WAAW,IAAI;AACjB,cAAM,iBAAiB,OAAO,MAAM,SAAS,CAAC;AAC9C,YAAI,eAAe,SAAS,4BAA4B;AACtD,iBAAO;AAAA,YACL;AAAA,cACE;AAAA,cACA,mBAAmB,MAAM,iBAAiB,CAAC,QAAQ,eAAe,MAAM,kCAAkC,0BAA0B;AAAA,cACpI;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,aAAO,KAAK,EAAE,MAAM,UAAU,OAAO,QAAQ,UAAU,EAAE,CAAC;AAC1D,UAAI;AACJ;AAAA,IACF;AAGA,QAAI,KAAK,CAAC,MAAM,OAAO,YAAY,KAAK,KAAK,CAAC,CAAC,GAAG;AAChD,UAAI,IAAI;AACR,UAAI,KAAK,CAAC,MAAM,IAAK;AACrB,aAAO,IAAI,KAAK,UAAU,OAAO,KAAK,KAAK,CAAC,CAAC,EAAG;AAChD,YAAM,OAAO,KAAK,MAAM,GAAG,CAAC;AAE5B,UAAI,SAAS,UAAU,SAAS,SAAS;AACvC,eAAO,KAAK,EAAE,MAAM,WAAW,OAAO,MAAM,UAAU,EAAE,CAAC;AAAA,MAC3D,WAAW,SAAS,SAAS,SAAS,QAAQ,SAAS,OAAO;AAC5D,eAAO,KAAK,EAAE,MAAM,iBAAiB,OAAO,MAAM,UAAU,EAAE,CAAC;AAAA,MACjE,WAAW,SAAS,QAAQ,SAAS,UAAU,SAAS,QAAQ;AAC9D,eAAO,KAAK,EAAE,MAAM,qBAAqB,OAAO,MAAM,UAAU,EAAE,CAAC;AAAA,MACrE,OAAO;AACL,eAAO,KAAK,EAAE,MAAM,cAAc,OAAO,MAAM,UAAU,EAAE,CAAC;AAAA,MAC9D;AACA,UAAI;AACJ;AAAA,IACF;AAGA,UAAM,KAAK,KAAK,CAAC;AACjB,QAAI,QAAQ,SAAS,EAAE,GAAG;AACxB,aAAO,KAAK,EAAE,MAAM,cAAc,OAAO,IAAI,UAAU,EAAE,CAAC;AAC1D;AACA;AAAA,IACF;AACA,QAAI,OAAO,OAAO,OAAO,KAAK;AAC5B,aAAO,KAAK,EAAE,MAAM,cAAc,OAAO,IAAI,UAAU,EAAE,CAAC;AAC1D;AACA;AAAA,IACF;AACA,QAAI,QAAQ,SAAS,EAAE,GAAG;AACxB,aAAO,KAAK,EAAE,MAAM,aAAa,OAAO,IAAI,UAAU,EAAE,CAAC;AACzD;AACA;AAAA,IACF;AACA,QAAI,OAAO,KAAK;AAEd,aAAO,KAAK,EAAE,MAAM,cAAc,OAAO,IAAI,UAAU,EAAE,CAAC;AAC1D;AACA;AAAA,IACF;AAGA,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,2BAA2B,EAAE,iBAAiB,CAAC;AAAA,QAC/C;AAAA,MACF;AAAA,IACF;AACA;AAAA,EACF;AAIA,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAM,MAAM,OAAO,CAAC;AAGpB,QACG,IAAI,UAAU,SAAS,IAAI,UAAU,UACrC,IAAI,UAAU,QAAQ,IAAI,UAAU,OACrC;AACA,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,uBAAuB,IAAI,KAAK,iBAAiB,IAAI,QAAQ;AAAA,UAC7D;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,QAAI,IAAI,UAAU,KAAK;AACrB,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,sCAAsC,IAAI,QAAQ;AAAA,UAClD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,QAAI,IAAI,SAAS,gBAAgB,sBAAsB,IAAI,IAAI,KAAK,GAAG;AACrE,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,sBAAsB,IAAI,KAAK,iBAAiB,IAAI,QAAQ;AAAA,UAC5D;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,QAAI,IAAI,SAAS,gBAAgB,CAAC,IAAI,MAAM,WAAW,GAAG,KAAK,CAAC,sBAAsB,IAAI,IAAI,KAAK,GAAG;AACpG,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,eAAe,IAAI,KAAK,iBAAiB,IAAI,QAAQ,+BAA+B,IAAI,KAAK;AAAA,UAC7F;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,QAAI,IAAI,SAAS,cAAc;AAG7B,YAAM,OAAO,OAAO,IAAI,CAAC;AACzB,UAAI,QAAQ,KAAK,SAAS,eAAe,KAAK,UAAU,KAAK;AAC3D,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,oCAAoC,IAAI,KAAK,kBAAkB,IAAI,QAAQ;AAAA,YAC3E;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,QAAQ,OAAO;AAC1B;AASA,SAAS,eAAe,QAA0B;AAChD,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAM,OAAO,OAAO,OAAO,SAAS,CAAC;AACrC,MACE,KAAK,SAAS,gBACd,KAAK,SAAS,gBACd,KAAK,SAAS,mBACd,KAAK,SAAS,qBACd;AACA,WAAO;AAAA,EACT;AACA,MAAI,KAAK,SAAS,gBAAgB,KAAK,UAAU,OAAO,KAAK,UAAU,MAAM;AAC3E,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAUA,SAAS,qBACP,KACA,UACA,UACM;AACN,MAAI,QAAQ,QAAQ,QAAQ,UAAa,OAAO,QAAQ,UAAU;AAChE;AAAA,EACF;AAGA,MAAIC,OAAM,GAAG,KAAKC,QAAO,GAAG,GAAG;AAC7B,aAAS,KAAK,QAAQ;AACtB;AAAA,EACF;AAEA,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,2BAAqB,IAAI,CAAC,GAAG,GAAG,QAAQ,IAAI,CAAC,KAAK,QAAQ;AAAA,IAC5D;AAAA,EACF,OAAO;AACL,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAA8B,GAAG;AACzE,2BAAqB,OAAO,GAAG,QAAQ,IAAI,GAAG,IAAI,QAAQ;AAAA,IAC5D;AAAA,EACF;AACF;AAMA,SAAS,YAAY,UAAkB,MAAiC;AACtE,QAAM,SAA4B,CAAC;AAGnC,MAAI,SAAS,SAAS,KAAK;AACzB,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,4DAA4D,SAAS,MAAM;AAAA,QAC3E;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAW,SAAS,MAAM,GAAG;AACnC,MAAI,SAAS,SAAS,oBAAoB;AACxC,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,mBAAmB,SAAS,MAAM,uBAAuB,kBAAkB;AAAA,QAC3E;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,oBAAoB;AAC1B,MAAI;AACJ,UAAQ,QAAQ,kBAAkB,KAAK,QAAQ,OAAO,MAAM;AAC1D,UAAM,QAAQ,SAAS,MAAM,CAAC,GAAG,EAAE;AACnC,QAAI,QAAQ,sBAAsB;AAChC,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,eAAe,KAAK,+BAA+B,oBAAoB;AAAA,UACvE;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAIA,aAAW,WAAW,UAAU;AAC9B,UAAM,eAAe,QAAQ,QAAQ,YAAY,EAAE;AACnD,QAAIF,8BAA6B,IAAI,YAAY,GAAG;AAClD,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,yCAAyC,YAAY;AAAA,UACrD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAMA,SAAS,aAAa,WAAmB,MAAiC;AACxE,QAAM,SAA4B,CAAC;AAGnC,MAAI,UAAU,SAAS,iBAAiB;AACtC,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,wCAAwC,eAAe,oBAAoB,UAAU,MAAM;AAAA,QAC3F;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,EAAE,QAAQ,QAAQ,YAAY,IAAI,SAAS,WAAW,IAAI;AAChE,SAAO,KAAK,GAAG,WAAW;AAG1B,MAAI,OAAO,SAAS,iBAAiB;AACnC,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,kBAAkB,OAAO,MAAM,iCAAiC,eAAe;AAAA,QAC/E;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,aAAW,OAAO,QAAQ;AACxB,QAAI,IAAI,SAAS,YAAY,IAAI,MAAM,SAAS,yBAAyB;AACvE,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,8BAA8B,IAAI,QAAQ,QAAQ,IAAI,MAAM,MAAM,qCAAqC,uBAAuB;AAAA,UAC9H;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,aAAa;AACjB,MAAI,gBAAgB;AACpB,MAAI,UAAU;AAEd,aAAW,OAAO,QAAQ;AACxB,QAAI,IAAI,SAAS,eAAe,IAAI,UAAU,KAAK;AACjD;AACA,UAAI,aAAa,eAAe;AAC9B,wBAAgB;AAAA,MAClB;AAAA,IACF,WAAW,IAAI,SAAS,eAAe,IAAI,UAAU,KAAK;AACxD;AAAA,IACF,WAAW,IAAI,SAAS,uBAAuB,IAAI,UAAU,MAAM;AACjE;AAAA,IACF;AAAA,EACF;AAEA,MAAI,gBAAgB,kBAAkB;AACpC,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,wCAAwC,aAAa,uBAAuB,gBAAgB;AAAA,QAC5F;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,UAAU,4BAA4B;AACxC,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,kBAAkB,OAAO,+CAA+C,0BAA0B;AAAA,QAClG;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAM,MAAM,OAAO,CAAC;AACpB,QAAI,IAAI,SAAS,gBAAgB,IAAI,MAAM,WAAW,GAAG,GAAG;AAE1D,UAAI,QAAQ;AACZ,UAAI,IAAI,IAAI;AACZ,aAAO,IAAI,IAAI,OAAO,QAAQ;AAC5B,YACE,OAAO,CAAC,EAAE,SAAS,eACnB,OAAO,CAAC,EAAE,UAAU,OACpB,OAAO,IAAI,CAAC,EAAE,SAAS,cACvB;AACA;AACA,eAAK;AAAA,QACP,OAAO;AACL;AAAA,QACF;AAAA,MACF;AACA,UAAI,QAAQ,oBAAoB;AAC9B,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,uBAAuB,IAAI,KAAK,oBAAoB,KAAK,0BAA0B,kBAAkB;AAAA,YACrG;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,WAAS,IAAI,GAAG,IAAI,IAAI,OAAO,QAAQ,KAAK;AAC1C,QACE,OAAO,CAAC,EAAE,SAAS,eACnB,OAAO,CAAC,EAAE,UAAU,OACpB,OAAO,IAAI,CAAC,EAAE,SAAS,YACvB,OAAO,IAAI,CAAC,EAAE,SAAS,eACvB,OAAO,IAAI,CAAC,EAAE,UAAU,KACxB;AACA,YAAM,aAAa,WAAW,OAAO,IAAI,CAAC,EAAE,KAAK;AACjD,UAAI,aAAa,sBAAsB;AACrC,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,eAAe,UAAU,qCAAqC,oBAAoB;AAAA,YAClF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAeO,SAAS,wBACd,OACmB;AACnB,QAAM,SAA4B,CAAC;AAEnC,eAAa,OAAO,CAAC,MAAuB,YAA8B;AAExE,UAAM,aAAa,EAAE,GAAG,KAAK;AAC7B,WAAO,WAAW;AAClB,WAAO,WAAW;AAClB,WAAO,WAAW;AAClB,WAAO,WAAW;AAClB,yBAAqB,YAAY,QAAQ,MAAM,CAAC,OAAO,cAAc;AACnE,UAAIC,OAAM,KAAK,GAAG;AAChB,eAAO,KAAK,GAAG,YAAY,MAAM,MAAM,SAAS,CAAC;AAAA,MACnD,WAAWC,QAAO,KAAK,GAAG;AACxB,eAAO,KAAK,GAAG,aAAa,MAAM,OAAO,SAAS,CAAC;AAAA,MACrD;AAAA,IACF,CAAC;AAGD,QAAI,KAAK,OAAO;AACd,2BAAqB,KAAK,OAAO,GAAG,QAAQ,IAAI,UAAU,CAAC,OAAO,cAAc;AAC9E,YAAID,OAAM,KAAK,GAAG;AAChB,iBAAO,KAAK,GAAG,YAAY,MAAM,MAAM,SAAS,CAAC;AAAA,QACnD,WAAWC,QAAO,KAAK,GAAG;AACxB,iBAAO,KAAK,GAAG,aAAa,MAAM,OAAO,SAAS,CAAC;AAAA,QACrD;AAAA,MACF,CAAC;AAAA,IACH;AAGA,QAAI,KAAK,cAAc,QAAW;AAChC,2BAAqB,KAAK,WAAW,GAAG,QAAQ,IAAI,cAAc,CAAC,OAAO,cAAc;AACtF,YAAID,OAAM,KAAK,GAAG;AAChB,iBAAO,KAAK,GAAG,YAAY,MAAM,MAAM,SAAS,CAAC;AAAA,QACnD,WAAWC,QAAO,KAAK,GAAG;AACxB,iBAAO,KAAK,GAAG,aAAa,MAAM,OAAO,SAAS,CAAC;AAAA,QACrD;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAED,SAAO;AACT;;;ATniBA,SAASC,gBAAe,KAAqB;AAC3C,MAAI,QAAQ;AACZ,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAM,OAAO,IAAI,WAAW,CAAC;AAC7B,QAAI,QAAQ,KAAM;AAChB,eAAS;AAAA,IACX,WAAW,QAAQ,MAAO;AACxB,eAAS;AAAA,IACX,WAAW,QAAQ,SAAU,QAAQ,OAAQ;AAC3C,eAAS;AACT;AAAA,IACF,OAAO;AACL,eAAS;AAAA,IACX;AAAA,EACF;AACA,SAAO;AACT;AAMA,SAAS,aAAa,OAAmC;AACvD,QAAM,MAAM;AAMZ,QAAM,QAAQ,IAAI;AAClB,QAAM,aAAa,IAAI;AACvB,QAAM,SAA4B,CAAC;AAEnC,SAAO,KAAK,GAAG,cAAc,KAAK,CAAC;AACnC,SAAO,KAAK,GAAG,mBAAmB,KAAK,CAAC;AACxC,SAAO,KAAK,GAAG,eAAe,OAAO,UAAU,CAAC;AAChD,SAAO,KAAK,GAAG,iBAAiB;AAAA,IAC9B;AAAA,IACA,OAAO,IAAI;AAAA,IACX,YAAY,IAAI;AAAA,IAChB;AAAA,EACF,CAAC,CAAC;AACF,SAAO,KAAK,GAAG,eAAe,EAAE,OAAO,IAAI,OAA8C,OAAO,WAAW,CAAC,CAAC;AAC7G,SAAO,KAAK,GAAG,wBAAwB,KAAK,CAAC;AAE7C,SAAO;AACT;AAkBO,SAAS,SAAS,OAAkC;AAEzD,QAAM,eAAe,eAAe,KAAK;AACzC,MAAI,CAAC,aAAa,OAAO;AACvB,WAAO;AAAA,EACT;AAGA,QAAM,SAAS,aAAa,KAAK;AACjC,SAAO,SAAS,MAAM;AACxB;AAqBO,SAAS,YAAY,SAAmC;AAE7D,QAAM,WAAWA,gBAAe,OAAO;AACvC,MAAI,WAAW,qBAAqB;AAClC,WAAO,SAAS;AAAA,MACd;AAAA,QACE;AAAA,QACA,gBAAgB,QAAQ,sBAAsB,mBAAmB;AAAA,QACjE;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAGA,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,OAAO;AAAA,EAC7B,SAAS,GAAG;AACV,UAAM,UAAU,aAAa,QAAQ,EAAE,UAAU;AACjD,WAAO,SAAS;AAAA,MACd,YAAY,gBAAgB,yBAAyB,OAAO,IAAI,EAAE;AAAA,IACpE,CAAC;AAAA,EACH;AAGA,SAAO,SAAS,MAAM;AACxB;","names":["isRef","isExpr","isRef","isExpr","isRef","isRef","PROTOTYPE_POLLUTION_SEGMENTS","isRef","isExpr","resolveRefFromState","PROTOTYPE_POLLUTION_SEGMENTS","isRef","isExpr","isRef","isExpr","PROTOTYPE_POLLUTION_SEGMENTS","isRef","isExpr","utf8ByteLength"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@safe-ugc-ui/validator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Security validator for Safe UGC UI card JSON",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -17,15 +17,13 @@
|
|
|
17
17
|
"import": "./dist/index.js"
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
|
-
"files": [
|
|
21
|
-
"dist"
|
|
22
|
-
],
|
|
23
|
-
"dependencies": {
|
|
24
|
-
"@safe-ugc-ui/types": "0.1.0"
|
|
25
|
-
},
|
|
26
|
-
"devDependencies": {},
|
|
20
|
+
"files": ["dist"],
|
|
27
21
|
"scripts": {
|
|
28
22
|
"build": "tsup",
|
|
29
23
|
"test": "vitest run"
|
|
30
|
-
}
|
|
31
|
-
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@safe-ugc-ui/types": "workspace:*"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {}
|
|
29
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Safe UGC UI Contributors
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|