@motion-proto/live-tokens 0.74.0 → 0.76.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.
Files changed (171) hide show
  1. package/.claude/skills/live-tokens-check-compliance/SKILL.md +33 -38
  2. package/.claude/skills/live-tokens-create-component/SKILL copy.md +196 -0
  3. package/.claude/skills/live-tokens-create-component/SKILL.md +198 -146
  4. package/.claude/skills/live-tokens-create-component/references/contract-tests.md +95 -52
  5. package/.claude/skills/live-tokens-create-component/references/intrinsics.md +2 -2
  6. package/.claude/skills/live-tokens-create-component/references/linked-siblings.md +2 -2
  7. package/.claude/skills/live-tokens-create-component/references/sketch-mode.md +12 -12
  8. package/.claude/skills/live-tokens-create-component/references/token-naming.md +2 -1
  9. package/.claude/skills/live-tokens-create-page/SKILL.md +187 -0
  10. package/.claude/skills/live-tokens-create-page/references/interaction-sources.md +66 -0
  11. package/.claude/skills/live-tokens-create-page/references/layout-sources.md +87 -0
  12. package/.claude/skills/live-tokens-create-theme/SKILL.md +52 -48
  13. package/.claude/skills/live-tokens-create-theme/references/design-directions.md +1 -1
  14. package/.claude/skills/live-tokens-fix-findings/SKILL.md +69 -60
  15. package/.claude/skills/live-tokens-pick-component/SKILL.md +64 -79
  16. package/.claude/skills/live-tokens-set-colors/SKILL.md +47 -38
  17. package/.claude/skills/live-tokens-set-geometry/SKILL.md +58 -35
  18. package/.claude/skills/live-tokens-set-geometry/references/geometry-anchors.md +5 -3
  19. package/.claude/skills/live-tokens-set-type/SKILL.md +30 -30
  20. package/CHANGELOG.md +138 -0
  21. package/README.md +17 -7
  22. package/bin/check-component.mjs +91 -19
  23. package/bin/check-page.mjs +102 -21
  24. package/bin/cli.mjs +87 -113
  25. package/bin/contractRunner.mjs +945 -0
  26. package/bin/create.mjs +1 -1
  27. package/bin/lib/catalogue.mjs +37 -30
  28. package/bin/lib/findings.mjs +46 -15
  29. package/bin/lib/report.mjs +3 -3
  30. package/bin/lib/tokenVocabulary.mjs +4 -4
  31. package/bin/migrate-routes.mjs +5 -5
  32. package/bin/migrate.mjs +4 -4
  33. package/bin/save-theme.mjs +8 -9
  34. package/bin/set-colors.mjs +9 -11
  35. package/bin/set-geometry.mjs +7 -7
  36. package/bin/set-type.mjs +5 -7
  37. package/bin/setup-claude.mjs +110 -0
  38. package/dist-plugin/{chunk-W6Y4BWFB.js → chunk-6WGFOJXO.js} +22 -0
  39. package/dist-plugin/{chunk-7VRTBGJT.js → chunk-PDNL4NC5.js} +9 -2
  40. package/dist-plugin/{chunk-V3YF6CGT.js → chunk-SWXRVZKT.js} +43 -1
  41. package/dist-plugin/{dataPaths-BhWzd5cL.d.cts → dataPaths-BpIK_Obx.d.cts} +1 -0
  42. package/dist-plugin/{dataPaths-BhWzd5cL.d.ts → dataPaths-BpIK_Obx.d.ts} +1 -0
  43. package/dist-plugin/index.cjs +310 -147
  44. package/dist-plugin/index.d.cts +1 -1
  45. package/dist-plugin/index.d.ts +1 -1
  46. package/dist-plugin/index.js +218 -122
  47. package/dist-plugin/migrateData/index.cjs +66 -2
  48. package/dist-plugin/migrateData/index.d.cts +1 -1
  49. package/dist-plugin/migrateData/index.d.ts +1 -1
  50. package/dist-plugin/migrateData/index.js +3 -3
  51. package/dist-plugin/setColors/index.cjs +61 -4
  52. package/dist-plugin/setColors/index.d.cts +1 -1
  53. package/dist-plugin/setColors/index.d.ts +1 -1
  54. package/dist-plugin/setColors/index.js +5 -5
  55. package/dist-plugin/setGeometry/index.cjs +107 -44
  56. package/dist-plugin/setGeometry/index.d.cts +5 -5
  57. package/dist-plugin/setGeometry/index.d.ts +5 -5
  58. package/dist-plugin/setGeometry/index.js +51 -45
  59. package/dist-plugin/setType/index.cjs +15 -0
  60. package/dist-plugin/setType/index.d.cts +1 -1
  61. package/dist-plugin/setType/index.d.ts +1 -1
  62. package/dist-plugin/setType/index.js +1 -1
  63. package/dist-plugin/tokensCssMigrations/index.d.cts +1 -1
  64. package/dist-plugin/tokensCssMigrations/index.d.ts +1 -1
  65. package/dist-plugin/tokensCssMigrations/index.js +1 -1
  66. package/package.json +35 -8
  67. package/src/app/site.css +19 -9
  68. package/src/editor/bootstrap.ts +2 -0
  69. package/src/editor/component-editor/CollapsibleSectionEditor.svelte +4 -4
  70. package/src/editor/component-editor/DialogEditor.svelte +4 -4
  71. package/src/editor/component-editor/MenuSelectEditor.svelte +4 -1
  72. package/src/editor/component-editor/SegmentedControlEditor.svelte +6 -1
  73. package/src/editor/component-editor/TabBarEditor.svelte +1 -1
  74. package/src/editor/component-editor/TableEditor.svelte +2 -2
  75. package/src/editor/component-editor/scaffolding/TokenLayout.svelte +6 -3
  76. package/src/editor/component-editor/scaffolding/VariantGroup.svelte +41 -20
  77. package/src/editor/core/components/adjustAliases.ts +59 -45
  78. package/src/editor/core/components/aliasKinds.ts +9 -5
  79. package/src/editor/core/preview/themePreview.ts +9 -2
  80. package/src/editor/core/sketch/sketchLayer.ts +22 -0
  81. package/src/editor/core/store/editorStore.ts +10 -1
  82. package/src/editor/core/themes/buildColors.ts +3 -3
  83. package/src/editor/core/themes/liveStateStream.ts +26 -0
  84. package/src/editor/core/themes/migrations/2026-09-07-stroke-role-renames.ts +52 -0
  85. package/src/editor/core/themes/migrations/index.ts +2 -0
  86. package/src/editor/core/themes/themeDocumentSync.ts +22 -11
  87. package/src/editor/core/themes/themeService.ts +9 -2
  88. package/src/editor/pages/ComponentEditorPage.svelte +17 -1
  89. package/src/editor/pages/liveTokensEditorHandle.ts +23 -0
  90. package/src/editor/skill-atlas/SkillAtlas.svelte +75 -573
  91. package/src/editor/skill-atlas/TreeCanvas.svelte +263 -0
  92. package/src/editor/skill-atlas/TreeNodeCard.svelte +136 -53
  93. package/src/editor/skill-atlas/edges.ts +31 -0
  94. package/src/editor/skill-atlas/skillSources.generated.ts +20 -19
  95. package/src/editor/skill-atlas/skillTrees.ts +19 -3840
  96. package/src/editor/skill-atlas/trees/check-compliance.ts +183 -0
  97. package/src/editor/skill-atlas/trees/create-component.ts +275 -0
  98. package/src/editor/skill-atlas/trees/create-page.ts +320 -0
  99. package/src/editor/skill-atlas/trees/create-theme.ts +255 -0
  100. package/src/editor/skill-atlas/trees/fix-findings.ts +469 -0
  101. package/src/editor/skill-atlas/trees/pick-component.ts +300 -0
  102. package/src/editor/skill-atlas/trees/set-colors.ts +148 -0
  103. package/src/editor/skill-atlas/trees/set-geometry.ts +136 -0
  104. package/src/editor/skill-atlas/trees/set-type.ts +142 -0
  105. package/src/editor/skill-atlas/types.ts +3 -4
  106. package/src/editor/skill-atlas/wireLayout.ts +287 -0
  107. package/src/live-tokens/data/themes/autumn.json +15 -15
  108. package/src/live-tokens/data/themes/halloween.json +15 -15
  109. package/src/live-tokens/data/themes/midnight-study.json +15 -15
  110. package/src/live-tokens/data/themes/ocean.json +15 -15
  111. package/src/live-tokens/data/themes/royal-velvet.json +15 -15
  112. package/src/live-tokens/data/themes/sketchy.json +15 -15
  113. package/src/live-tokens/data/themes/spring-meadow.json +15 -15
  114. package/src/live-tokens/data/themes/sunset.json +15 -15
  115. package/src/system/components/Badge.svelte +7 -0
  116. package/src/system/components/Button.svelte +7 -0
  117. package/src/system/components/Callout.svelte +10 -6
  118. package/src/system/components/Card.svelte +23 -4
  119. package/src/system/components/CodeSnippet.svelte +4 -3
  120. package/src/system/components/CollapsibleSection.svelte +23 -8
  121. package/src/system/components/CornerBadge.svelte +6 -0
  122. package/src/system/components/Dialog.svelte +13 -6
  123. package/src/system/components/IconButton.svelte +9 -0
  124. package/src/system/components/Image.svelte +8 -0
  125. package/src/system/components/ImageLightbox.svelte +6 -0
  126. package/src/system/components/InlineEditActions.svelte +7 -0
  127. package/src/system/components/Input.svelte +7 -0
  128. package/src/system/components/MenuSelect.svelte +7 -0
  129. package/src/system/components/Notification.svelte +7 -0
  130. package/src/system/components/Panel.svelte +6 -0
  131. package/src/system/components/ProgressBar.svelte +5 -0
  132. package/src/system/components/RadioButton.svelte +11 -5
  133. package/src/system/components/SectionDivider.svelte +8 -0
  134. package/src/system/components/SegmentedControl.svelte +6 -0
  135. package/src/system/components/SideNavigation.svelte +6 -0
  136. package/src/system/components/Slider.svelte +7 -4
  137. package/src/system/components/TabBar.svelte +15 -9
  138. package/src/system/components/Table.svelte +8 -3
  139. package/src/system/components/Toggle.svelte +4 -4
  140. package/src/system/components/Tooltip.svelte +6 -0
  141. package/src/testing-js/chunk-AO7EZHYV.js +776 -0
  142. package/src/testing-js/chunk-AO7EZHYV.js.map +1 -0
  143. package/src/testing-js/chunk-FAFOAWYL.js +39 -0
  144. package/src/testing-js/chunk-FAFOAWYL.js.map +1 -0
  145. package/src/testing-js/chunk-L73N4NSO.js +23 -0
  146. package/src/testing-js/chunk-L73N4NSO.js.map +1 -0
  147. package/src/testing-js/chunk-LXR3MN6N.js +3063 -0
  148. package/src/testing-js/chunk-LXR3MN6N.js.map +1 -0
  149. package/src/testing-js/chunk-ZMSX6CXR.js +53 -0
  150. package/src/testing-js/chunk-ZMSX6CXR.js.map +1 -0
  151. package/src/testing-js/component-alias.contract.js +81 -0
  152. package/src/testing-js/component-alias.contract.js.map +1 -0
  153. package/src/testing-js/component-editor.contract.js +62 -0
  154. package/src/testing-js/component-editor.contract.js.map +1 -0
  155. package/src/testing-js/component-render.contract.js +568 -0
  156. package/src/testing-js/component-render.contract.js.map +1 -0
  157. package/src/testing-js/index.d.ts +293 -0
  158. package/src/testing-js/index.js +222 -0
  159. package/src/testing-js/index.js.map +1 -0
  160. package/src/testing-js/registry.contract.js +39 -0
  161. package/src/testing-js/registry.contract.js.map +1 -0
  162. package/src/testing-js/vitest-BE6uGF31.d.ts +73 -0
  163. package/src/testing-js/vitest.d.ts +3 -0
  164. package/src/testing-js/vitest.js +13 -0
  165. package/src/testing-js/vitest.js.map +1 -0
  166. package/template/README.md +13 -0
  167. package/template/_gitignore +6 -0
  168. package/template/package.json +3 -1
  169. package/template/src/pages/Home.svelte +4 -18
  170. package/.claude/skills/live-tokens-build-page/SKILL.md +0 -103
  171. package/.claude/skills/live-tokens-build-page/references/layout-sources.md +0 -48
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../testing/component-render.contract.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { expect, test, type Locator, type Page } from '@playwright/test';\nimport { openComponentsEditor } from './support/editor';\nimport { selectedContracts } from './contracts';\nimport { ContractHarness } from './support/contractHarness';\n\n// Each test boots its own editor and asserts only over its own component's\n// aliases, so the 25 component tests carry no shared state between them.\ntest.describe.configure({ mode: 'parallel' });\n\ninterface AliasCase {\n component: string;\n variable: string;\n}\n\nfunction discoverDefaultAliases(): AliasCase[] {\n const root = path.resolve(process.env.LIVE_TOKENS_DATA_DIR ?? 'src/live-tokens/data', 'component-configs');\n const cases: AliasCase[] = [];\n for (const directory of fs.readdirSync(root).sort()) {\n const file = path.join(root, directory, 'default.json');\n if (!fs.existsSync(file)) continue;\n const data = JSON.parse(fs.readFileSync(file, 'utf8')) as {\n component?: string;\n aliases?: Record<string, unknown>;\n };\n const component = data.component ?? directory;\n for (const variable of Object.keys(data.aliases ?? {}).sort()) {\n cases.push({ component, variable });\n }\n }\n return cases;\n}\n\nconst requestedComponent = process.env.LIVE_TOKENS_COMPONENT;\nconst aliasCases = discoverDefaultAliases()\n .filter(({ component }) => !requestedComponent || component === requestedComponent);\nconst aliasesByComponent = new Map<string, string[]>();\nfor (const { component, variable } of aliasCases) {\n const variables = aliasesByComponent.get(component) ?? [];\n variables.push(variable);\n aliasesByComponent.set(component, variables);\n}\n\ninterface ProbeResult {\n covered: string[];\n unchanged: string[];\n}\n\n/**\n * Exercise each standard token selector through the same click path a designer\n * uses. The rendered-property probe below deliberately writes root variables\n * directly so it can try arbitrary CSS values; this companion gate proves the\n * editor control itself reaches the store and the document root.\n */\nasync function exerciseVisibleTokenControls(\n page: Page,\n componentAliases: string[],\n exercised: Set<string>,\n): Promise<void> {\n const group = page.locator('.variant-group:visible');\n const settle = () => page.evaluate(() => new Promise<void>((resolve) =>\n requestAnimationFrame(() => requestAnimationFrame(() => resolve()))));\n await settle();\n // A disabled or locked selector (a hover surface stood down while the tint\n // is on) opens a dropdown with nothing to pick from.\n const variables = await group.locator('.ui-token-selector:visible[data-token-variable]:not(.disabled):not(.locked)')\n .evaluateAll((elements) => [...new Set(elements\n .map((element) => (element as HTMLElement).dataset.tokenVariable)\n .filter((value): value is string => !!value))]);\n\n for (const variable of variables) {\n if (!componentAliases.includes(variable) || exercised.has(variable)) continue;\n const selector = group.locator(`.ui-token-selector:visible[data-token-variable=\"${variable}\"]:not(.disabled):not(.locked)`).first();\n if (await selector.count() === 0) continue;\n const before = await page.evaluate((name) =>\n document.documentElement.style.getPropertyValue(name).trim(), variable);\n\n const optionSelector = [\n '.ui-ts-dropdown .static-chip:not(.active):not(:disabled)',\n '.ui-ts-dropdown .ui-option-item:not(.active):not(:disabled)',\n '.ui-ts-dropdown .font-size-row:not(.active):not(:disabled)',\n ].join(', ');\n let after = before;\n let foundOption = false;\n // Some semantic options can resolve to the same CSS as the current alias.\n // Try several distinct visible choices before treating the control as dead.\n for (let attempt = 0; attempt < 4 && after === before; attempt++) {\n await settle();\n await selector.locator('.ui-ts-trigger').click();\n const options = selector.locator(optionSelector);\n const count = await options.count();\n if (count === 0) {\n // Close an unsupported dropdown before the traversal moves on. The\n // final coverage assertion reports its precise variable.\n await selector.locator('.ui-ts-trigger').click();\n break;\n }\n foundOption = true;\n await options.nth(attempt % count).click();\n await settle();\n after = await page.evaluate((name) =>\n document.documentElement.style.getPropertyValue(name).trim(), variable);\n }\n if (!foundOption) continue;\n expect(after, `${variable} did not write through its editor control`).not.toBe(before);\n exercised.add(variable);\n }\n}\n\n/** Split padding exposes four side selectors and a merge action instead of a\n * selector for the fallback parent value. Merge each visible composite, then\n * exercise the newly rendered parent selector through the standard path. */\nasync function exerciseVisibleSplitPaddingControls(\n page: Page,\n componentAliases: string[],\n exercised: Set<string>,\n): Promise<void> {\n const group = page.locator('.variant-group:visible');\n const variables = await group.locator('.merge-btn:visible[data-padding-parent-variable]')\n .evaluateAll((elements) => [...new Set(elements\n .map((element) => (element as HTMLElement).dataset.paddingParentVariable)\n .filter((value): value is string => !!value))]);\n\n for (const variable of variables) {\n if (!componentAliases.includes(variable) || exercised.has(variable)) continue;\n const merge = group.locator(`.merge-btn:visible[data-padding-parent-variable=\"${variable}\"]`).first();\n if (await merge.count()) await merge.click();\n }\n if (variables.length > 0) {\n await page.evaluate(() => new Promise<void>((resolve) =>\n requestAnimationFrame(() => requestAnimationFrame(() => resolve()))));\n await exerciseVisibleTokenControls(page, componentAliases, exercised);\n }\n}\n\n/** A single semantic control may intentionally own several CSS variables.\n * Every listed variable must change before the component traversal can\n * advance. */\n/** Returns the gate inputs it toggled, so the caller can put each one back\n * after probing: a gate left on locks rows behind it (a hover surface stood\n * down behind a tint), and those rows still have to be exercised in the\n * views that follow. */\nasync function exerciseVisibleCompositeControls(\n page: Page,\n componentAliases: string[],\n exercised: Set<string>,\n): Promise<Locator[]> {\n const toggled: Locator[] = [];\n const group = page.locator('.variant-group:visible');\n const controls = group.locator('[data-token-variables]:visible');\n for (let index = 0; index < await controls.count(); index++) {\n const control = controls.nth(index);\n const variables = ((await control.getAttribute('data-token-variables')) ?? '')\n .split(/\\s+/)\n .filter((variable) => componentAliases.includes(variable) && !exercised.has(variable));\n if (variables.length === 0) continue;\n const before = await page.evaluate((names) => Object.fromEntries(names.map((name) => [name,\n document.documentElement.style.getPropertyValue(name).trim(),\n ])), variables);\n // A gate is a checkbox, a radio, or a Toggle, which is a `role=\"switch\"`.\n const input = control.locator('input[type=\"checkbox\"], input[type=\"radio\"], [role=\"switch\"]').first();\n if (await input.count() === 0) continue;\n await input.click();\n toggled.push(input);\n await page.evaluate(() => new Promise<void>((resolve) =>\n requestAnimationFrame(() => requestAnimationFrame(() => resolve()))));\n const after = await page.evaluate((names) => Object.fromEntries(names.map((name) => [name,\n document.documentElement.style.getPropertyValue(name).trim(),\n ])), variables);\n for (const variable of variables) {\n expect(after[variable], `${variable} did not write through its composite control`)\n .not.toBe(before[variable]);\n exercised.add(variable);\n }\n }\n return toggled;\n}\n\n/** Component-owned gradients use a composite editor instead of a token\n * selector. Pick a real stop colour through its nested palette control and\n * assert the owning component variable—not the scratch stop variable—writes. */\nasync function exerciseVisibleGradientControls(\n page: Page,\n componentAliases: string[],\n exercised: Set<string>,\n): Promise<void> {\n const group = page.locator('.variant-group:visible');\n const editors = group.locator('.gradient-editor:visible[data-token-variable]');\n for (let index = 0; index < await editors.count(); index++) {\n const editor = editors.nth(index);\n const variable = await editor.getAttribute('data-token-variable');\n if (!variable || !componentAliases.includes(variable) || exercised.has(variable)) continue;\n const before = await page.evaluate((name) =>\n document.documentElement.style.getPropertyValue(name).trim(), variable);\n\n // Promote an empty/flat background to Solid so its stop picker is present,\n // then select a non-active invariant colour through the real palette UI.\n const solid = editor.getByRole('radio', { name: 'Solid' });\n if (await solid.count() && !await solid.isChecked()) await solid.check({ force: true });\n const picker = editor.locator('.picker-slot .ui-token-selector').first();\n await picker.locator('.ui-ts-trigger').click({ force: true });\n const swatch = picker.locator('.static-chip:not(.active):not(:disabled)').first();\n if (await swatch.count() === 0) continue;\n await swatch.click({ force: true });\n\n await expect.poll(() => page.evaluate((name) =>\n document.documentElement.style.getPropertyValue(name).trim(), variable),\n { message: `${variable} did not write through its gradient editor` })\n .not.toMatch(new RegExp(`^${escapeRegExp(before)}$`));\n exercised.add(variable);\n }\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Exercise every property control visible for the current standardized\n * VariantGroup view. The preview and property panel are deliberately siblings:\n * only `.tabs-preview` is fingerprinted, so a selector repaint cannot satisfy\n * the runtime-component contract.\n */\nasync function probeCurrentView(\n page: Page,\n componentAliases: string[],\n forcedVariables: string[] = [],\n provenVariables: string[] = [],\n): Promise<ProbeResult> {\n return page.evaluate(async ({ allAliases, forced, proven }) => {\n const group = Array.from(document.querySelectorAll<HTMLElement>('.variant-group'))\n .find((element) => element.offsetParent !== null);\n const preview = group?.querySelector<HTMLElement>('.tabs-preview');\n if (!group || !preview) return { covered: [], unchanged: [] };\n\n const visibleVariables = new Set<string>();\n if (forced.length > 0) {\n for (const variable of forced) {\n if (allAliases.includes(variable)) visibleVariables.add(variable);\n }\n } else {\n for (const element of group.querySelectorAll<HTMLElement>('[data-token-variable]')) {\n const variable = element.dataset.tokenVariable;\n if (element.offsetParent !== null && variable && allAliases.includes(variable)) {\n visibleVariables.add(variable);\n }\n }\n for (const element of group.querySelectorAll<HTMLElement>('[data-token-variables]')) {\n if (element.offsetParent === null) continue;\n for (const variable of (element.dataset.tokenVariables ?? '').split(/\\s+/)) {\n if (allAliases.includes(variable)) visibleVariables.add(variable);\n }\n }\n }\n\n // Split padding's four override slots are intentionally hidden controls.\n // The standardized padding control owns them, so include their default-file\n // variables whenever their base padding row is visible.\n for (const variable of [...visibleVariables]) {\n if (!variable.endsWith('-padding')) continue;\n for (const side of ['top', 'right', 'bottom', 'left']) {\n const sideVariable = `${variable}-${side}`;\n if (allAliases.includes(sideVariable)) visibleVariables.add(sideVariable);\n }\n }\n\n // A property already observed repainting cannot become less reactive in a\n // later view, and it is already recorded as both seen and covered. Probing\n // it again in every remaining view is the traversal's dominant cost: a\n // component with 47 views pays for its whole alias set 47 times over.\n for (const variable of proven) visibleVariables.delete(variable);\n if (visibleVariables.size === 0) return { covered: [], unchanged: [] };\n const properties = [\n 'display', 'visibility', 'opacity', 'position', 'zIndex',\n 'color', 'background', 'backgroundColor', 'backgroundImage', 'backgroundSize', 'backgroundPosition',\n 'border', 'borderColor', 'borderWidth', 'borderStyle',\n 'borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor',\n 'borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth',\n 'borderRadius', 'borderTopLeftRadius', 'borderTopRightRadius',\n 'borderBottomRightRadius', 'borderBottomLeftRadius',\n 'outline', 'outlineColor', 'outlineWidth', 'boxShadow',\n 'filter', 'backdropFilter', 'mixBlendMode',\n 'fontFamily', 'fontSize', 'fontWeight', 'fontStyle', 'lineHeight', 'letterSpacing',\n 'textAlign', 'textDecoration', 'textTransform', 'textShadow', 'whiteSpace',\n 'padding', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft',\n 'margin', 'marginTop', 'marginRight', 'marginBottom', 'marginLeft',\n 'gap', 'rowGap', 'columnGap',\n 'width', 'minWidth', 'maxWidth', 'height', 'minHeight', 'maxHeight',\n 'top', 'right', 'bottom', 'left',\n 'transform', 'transformOrigin', 'translate', 'rotate', 'scale',\n 'justifyContent', 'justifyItems', 'justifySelf', 'alignContent', 'alignItems', 'alignSelf',\n 'gridTemplateColumns', 'gridTemplateRows', 'gridColumn', 'gridRow', 'flex', 'flexDirection',\n 'overflow', 'overflowX', 'overflowY', 'clipPath', 'objectFit', 'objectPosition',\n 'fill', 'stroke', 'strokeWidth', 'strokeDasharray', 'strokeDashoffset',\n 'cursor', 'pointerEvents', 'content',\n 'transitionProperty', 'transitionDuration', 'transitionTimingFunction', 'transitionDelay',\n 'scrollbarColor', 'scrollbarWidth',\n ] as const;\n\n const ignoredAttribute = /^(class|style|data-|aria-)/;\n const stableAttributes = (element: Element) => Array.from(element.attributes)\n .filter((attribute) => !ignoredAttribute.test(attribute.name))\n .map((attribute) => `${attribute.name}=${attribute.value}`)\n .sort()\n .join(';');\n\n const pseudoSelectorsFor = (variable: string) => {\n const pseudoSelectors = ['::before', '::after'];\n if (variable.includes('placeholder')) pseudoSelectors.push('::placeholder');\n if (variable.includes('scrollbar')) {\n pseudoSelectors.push(\n '::-webkit-scrollbar',\n '::-webkit-scrollbar-track',\n '::-webkit-scrollbar-thumb',\n );\n }\n return pseudoSelectors;\n };\n\n // Fixed overlays are portaled to body and are therefore outside the\n // preview subtree. Dialog roles let the harness include them without a\n // component-specific selector or fixture.\n const fingerprintNodes = () => {\n const roots = [preview, ...document.querySelectorAll<HTMLElement>('[role=\"dialog\"]')];\n return roots.flatMap((root) => [root, ...root.querySelectorAll<HTMLElement>('*')]);\n };\n\n const nodeFingerprint = (element: HTMLElement, index: number, pseudoSelectors: string[]) => {\n const style = getComputedStyle(element);\n const rect = element.getBoundingClientRect();\n const values = properties.map((property) => style[property]).join('|');\n const pseudoValues = pseudoSelectors.map((selector) => {\n const pseudo = getComputedStyle(element, selector);\n return properties.map((property) => pseudo[property]).join('|');\n }).join('~');\n return [\n index,\n element.tagName,\n values,\n pseudoValues,\n `${rect.x},${rect.y},${rect.width},${rect.height}`,\n `${element.scrollWidth},${element.scrollHeight}`,\n stableAttributes(element),\n ].join('~');\n };\n\n const fingerprint = (variable: string) => {\n const pseudoSelectors = pseudoSelectorsFor(variable);\n return fingerprintNodes().map((element, index) =>\n nodeFingerprint(element, index, pseudoSelectors));\n };\n\n /** Proving a repaint takes one difference, so stop at the node that moved\n * instead of reading every remaining node's computed style. Each node\n * costs 58 properties across the element and its pseudo-elements, and this\n * walk runs once per candidate value per alias, so it is the probe's\n * dominant cost. Only the negative case has to read everything. */\n const movedFrom = (variable: string, baseline: string[]) => {\n const pseudoSelectors = pseudoSelectorsFor(variable);\n const nodes = fingerprintNodes();\n if (nodes.length !== baseline.length) return true;\n for (let index = 0; index < nodes.length; index++) {\n if (nodeFingerprint(nodes[index], index, pseudoSelectors) !== baseline[index]) return true;\n }\n return false;\n };\n\n const alternateValues = (variable: string, current: string): string[] => {\n const values: string[] = [];\n const add = (...candidates: string[]) => {\n for (const candidate of candidates) {\n if (candidate !== current && !values.includes(candidate)) values.push(candidate);\n }\n };\n if (/(surface|color|text|border)(?!-width)|-icon$|outline-color/.test(variable)) {\n add('rgb(1, 2, 3)', 'rgb(253, 127, 3)');\n }\n if (variable.includes('font-family')) add('monospace', 'serif');\n if (variable.includes('font-weight')) add('900', '200');\n if (variable.includes('line-height')) add('2.75', '0.75');\n if (variable.includes('letter-spacing')) add('7px', '-2px');\n if (variable.includes('shadow')) add('rgb(1, 2, 3) 7px 9px 0 3px', 'none');\n if (variable.includes('blur')) add('blur(7px)', 'none');\n if (variable.includes('gradient') || variable.endsWith('-background')) {\n add('linear-gradient(90deg, rgb(1, 2, 3), rgb(253, 127, 3))', 'none');\n }\n if (variable.includes('duration') || variable.includes('transition')) add('9s', '0s');\n if (variable.includes('opacity')) add('0.17', '0.83');\n if (variable.includes('display')) add(current === 'none' ? 'block' : 'none', 'contents');\n if (variable.includes('align')) add('right', 'center', 'flex-end');\n if (variable.includes('position')) add('above-label', 'below-description', 'center');\n if (variable.includes('button-variant')) add('danger', 'outline');\n if (variable.includes('shimmer')) {\n add('linear-gradient(90deg, transparent, rgb(255 255 255 / 80%), transparent)', 'none');\n }\n if (/(padding|margin|radius|width|height|size|gap|offset|inset|thickness)/.test(variable)) {\n add('37px', '3px');\n }\n if (variable.includes('scale')) add('1.73', '0.53');\n add('__live_tokens_invalid_probe__', '37px', 'rgb(1, 2, 3)', 'none', '2');\n return values;\n };\n\n const root = document.documentElement;\n const covered: string[] = [];\n const unchanged: string[] = [];\n // Fast-forward in-flight transitions so the fingerprint samples end states.\n // Reading mid-interpolation makes consecutive samples differ on their own,\n // which reports a dead property as covered. Transition shorthands stay\n // untouched so the duration and easing aliases remain observable.\n const settle = async () => {\n await new Promise<void>((resolve) => requestAnimationFrame(() => resolve()));\n for (const animation of document.getAnimations()) animation.finish();\n };\n\n // Remove animation noise from the fingerprint. The contract concerns the\n // end-state projection, not interpolation frames.\n const freeze = document.createElement('style');\n freeze.dataset.reactivityProbe = 'true';\n freeze.textContent = '*,*::before,*::after{animation:none!important;caret-color:transparent!important}';\n document.head.appendChild(freeze);\n await document.fonts?.ready;\n await settle();\n\n for (const variable of visibleVariables) {\n // A split padding control edits its base plus all materialized sides as\n // one standardized transformation. Probe that same transformation so a\n // base fallback is not incorrectly reported dead merely because the\n // active theme already contains side overrides.\n const mutatedVariables = [variable];\n if (variable.endsWith('-padding')) {\n for (const side of ['top', 'right', 'bottom', 'left']) {\n const sideVariable = `${variable}-${side}`;\n if (allAliases.includes(sideVariable)) mutatedVariables.push(sideVariable);\n }\n }\n const previous = mutatedVariables.map((name) => ({\n name,\n value: root.style.getPropertyValue(name),\n priority: root.style.getPropertyPriority(name),\n }));\n const current = getComputedStyle(root).getPropertyValue(variable).trim();\n const baseline = fingerprint(variable);\n let changed = false;\n for (const candidate of alternateValues(variable, current)) {\n for (const name of mutatedVariables) root.style.setProperty(name, candidate, 'important');\n // CSS updates synchronously. One animation frame also gives the few\n // JavaScript-backed components (SVG/filter bridges) time to reconcile.\n await settle();\n if (movedFrom(variable, baseline)) {\n changed = true;\n break;\n }\n }\n for (const prior of previous) {\n if (prior.value) root.style.setProperty(prior.name, prior.value, prior.priority);\n else root.style.removeProperty(prior.name);\n }\n await settle();\n (changed ? covered : unchanged).push(variable);\n }\n\n freeze.remove();\n return { covered, unchanged };\n }, { allAliases: componentAliases, forced: forcedVariables, proven: provenVariables });\n}\n\nasync function selectComponent(page: Page, component: string): Promise<void> {\n await page.evaluate(async (id) => {\n const editor = window.__liveTokensEditor;\n if (!editor) throw new Error('window.__liveTokensEditor is not present on the components route');\n editor.selectComponent(id);\n await new Promise<void>((resolve) => requestAnimationFrame(() =>\n requestAnimationFrame(() => resolve())));\n }, component);\n await page.locator('.variant-group').filter({ visible: true }).waitFor();\n}\n\nfor (const [component, aliases] of aliasesByComponent) {\n test(`${component} repaints every property in its standardized runtime preview`, async ({ page }) => {\n test.setTimeout(600_000);\n await openComponentsEditor(page);\n const covered = new Set<string>();\n const seen = new Set<string>();\n const unchanged = new Set<string>();\n const controlExercised = new Set<string>();\n\n const probe = async (componentAliases: string[], forced: string[] = []) => {\n const remaining = forced.length > 0\n ? forced.filter((variable) => !covered.has(variable))\n : [];\n if (forced.length > 0 && remaining.length === 0) return;\n\n // Exercise standardized preview toggles (zoom, hover enablement, optional\n // content) when retrying a property that is dormant in the default mode.\n if (forced.length > 0) {\n const unchecked = page.locator(\n '.variant-group:visible .tabs-preview input[type=\"checkbox\"]:not(:checked):not(:disabled), '\n + '.variant-group:visible .properties-header input[type=\"checkbox\"]:not(:checked):not(:disabled)',\n );\n for (let index = 0; index < await unchecked.count(); index++) {\n await unchecked.nth(index).click({ force: true });\n }\n }\n\n // Portaled dialogs sit outside `.tabs-preview`; hover their first action\n // so hover-only chrome aliases are painted too. Role-based discovery keeps\n // this independent of any component name or DOM implementation class.\n const dialogAction = page.locator('[role=\"dialog\"] button:not(:disabled)').first();\n if (await dialogAction.count()) await dialogAction.hover({ force: true });\n\n await exerciseVisibleTokenControls(page, componentAliases, controlExercised);\n const gates = await exerciseVisibleCompositeControls(page, componentAliases, controlExercised);\n // A gate that just opened may have revealed a row (the tint colour).\n await exerciseVisibleTokenControls(page, componentAliases, controlExercised);\n await exerciseVisibleSplitPaddingControls(page, componentAliases, controlExercised);\n await exerciseVisibleGradientControls(page, componentAliases, controlExercised);\n const result = await probeCurrentView(page, componentAliases, remaining, [...covered]);\n for (const gate of gates) {\n if (await gate.count()) await gate.click();\n }\n result.covered.forEach((variable) => covered.add(variable));\n result.covered.forEach((variable) => seen.add(variable));\n result.unchanged.forEach((variable) => {\n seen.add(variable);\n if (!covered.has(variable)) unchanged.add(variable);\n });\n };\n\n const traverseComponent = async (\n componentId: string,\n componentAliases: string[],\n forced: string[] = [],\n ) => {\n await selectComponent(page, componentId);\n\n const visitViews = async () => {\n if (forced.length > 0 && forced.every((variable) => covered.has(variable))) return;\n const sizeSelect = page.locator('.variant-group:visible .preview-actions select').first();\n const sizeValues = await sizeSelect.count()\n ? await sizeSelect.locator('option').evaluateAll((options) =>\n options.map((option) => (option as HTMLOptionElement).value))\n : [''];\n\n for (const sizeValue of sizeValues) {\n const currentSizeSelect = page.locator('.variant-group:visible .preview-actions select').first();\n if (sizeValue && await currentSizeSelect.count()) await currentSizeSelect.selectOption(sizeValue);\n\n const variantTabs = page.locator('.variant-group:visible .variant-tabs .variant-tab-btn');\n const variantLabels = await variantTabs.count()\n ? await variantTabs.allTextContents()\n : [''];\n\n for (let variantIndex = 0; variantIndex < variantLabels.length; variantIndex++) {\n if (variantLabels[variantIndex]) {\n await page.locator('.variant-group:visible .variant-tabs .variant-tab-btn')\n .nth(variantIndex)\n .click({ force: true });\n }\n\n await probe(componentAliases, forced);\n const primaryTabs = page.locator(\n '.variant-group:visible .tabs-states-block > .tabs-selectors:first-of-type .state-tab-btn',\n );\n const primaryLabels = await primaryTabs.allTextContents();\n for (let primaryIndex = 0; primaryIndex < primaryLabels.length; primaryIndex++) {\n await page.locator(\n '.variant-group:visible .tabs-states-block > .tabs-selectors:first-of-type .state-tab-btn',\n ).nth(primaryIndex).click({ force: true });\n await probe(componentAliases, forced);\n\n const secondaryTabs = page.locator(\n '.variant-group:visible .tabs-states-block > .tabs-selectors.substrip .state-tab-btn',\n );\n const secondaryLabels = await secondaryTabs.allTextContents();\n for (let secondaryIndex = 0; secondaryIndex < secondaryLabels.length; secondaryIndex++) {\n await page.locator(\n '.variant-group:visible .tabs-states-block > .tabs-selectors.substrip .state-tab-btn',\n ).nth(secondaryIndex).click({ force: true });\n await probe(componentAliases, forced);\n }\n }\n }\n }\n };\n\n await visitViews();\n if (forced.length === 0 || forced.every((variable) => covered.has(variable))) return;\n\n // Open any dialog-capable preview and repeat the same registry traversal.\n const dialogTrigger = page.locator(\n '.variant-group:visible .tabs-preview [aria-haspopup=\"dialog\"][aria-expanded=\"false\"]',\n ).first();\n if (await dialogTrigger.count()) {\n await dialogTrigger.click({ force: true });\n await page.locator('[role=\"dialog\"]').waitFor();\n await visitViews();\n }\n\n // Exercise every option of standardized canvas selects. This covers modes\n // such as Input type and optional Notification actions without any\n // per-component fixture or test case.\n const canvasSelects = page.locator('.variant-group:visible .tabs-preview .canvas-toolbar select');\n for (let selectIndex = 0; selectIndex < await canvasSelects.count(); selectIndex++) {\n const values = await canvasSelects.nth(selectIndex).locator('option').evaluateAll((options) =>\n options.map((option) => (option as HTMLOptionElement).value));\n for (const value of values) {\n if (forced.every((variable) => covered.has(variable))) return;\n await canvasSelects.nth(selectIndex).selectOption(value);\n await visitViews();\n }\n }\n\n // Expanded/collapsed previews expose motion aliases whose computed style\n // is different in each direction.\n const expanders = page.locator(\n '.variant-group:visible .tabs-preview [aria-expanded]:not([aria-haspopup=\"dialog\"])',\n );\n for (let index = 0; index < await expanders.count(); index++) {\n if (forced.every((variable) => covered.has(variable))) return;\n await expanders.nth(index).click({ force: true });\n await visitViews();\n }\n\n // A default-off hover gate only paints while the runtime element itself\n // matches :hover. Forced preview classes intentionally bypass that gate,\n // so retry unresolved properties while hovering each visible preview node.\n // This stays component-agnostic and runs only for the small unresolved set.\n // The traversal above leaves a forced state selected, and its preview\n // class outranks the gated `:hover` rule, so return to the first state.\n const firstStateTab = page.locator(\n '.variant-group:visible .tabs-states-block > .tabs-selectors:first-of-type .state-tab-btn',\n ).first();\n if (await firstStateTab.count()) await firstStateTab.click({ force: true });\n const hoverTargets = page.locator('.variant-group:visible .tabs-preview *:visible');\n for (let index = 0; index < await hoverTargets.count(); index++) {\n if (forced.every((variable) => covered.has(variable))) return;\n // The node list was read once; a probe above may have re-rendered it.\n try {\n await hoverTargets.nth(index).hover({ force: true, timeout: 2_000 });\n } catch {\n continue;\n }\n await probe(componentAliases, forced);\n }\n };\n\n await traverseComponent(component, aliases);\n\n // Retry every property not yet observed repainting. Composite controls,\n // pseudo-elements, optional content, interaction modes and portaled dialogs\n // are all discovered from standard DOM semantics; there is no component\n // exception table.\n const unresolved = aliases.filter((variable) => !covered.has(variable));\n if (unresolved.length > 0) await traverseComponent(component, aliases, unresolved);\n\n const notExposed = aliases.filter((variable) => !seen.has(variable));\n const notReactive = aliases.filter((variable) => seen.has(variable) && !covered.has(variable));\n const notControlExercised = aliases.filter((variable) => !controlExercised.has(variable));\n\n expect(notExposed, `Properties not exposed by a standardized component view:\\n${notExposed.join('\\n')}`)\n .toEqual([]);\n expect(notReactive, `Properties whose rendered preview did not change:\\n${notReactive.join('\\n')}`)\n .toEqual([]);\n expect(notControlExercised, `Properties not exercised through a rendered editor control:\\n${notControlExercised.join('\\n')}`)\n .toEqual([]);\n expect(covered.size).toBe(aliases.length);\n });\n}\n\ntest('component discovery covers every alias exactly once', () => {\n const perComponent = [...aliasesByComponent.values()].reduce((sum, a) => sum + a.length, 0);\n expect(aliasCases.length).toBeGreaterThan(0);\n expect(perComponent).toBe(aliasCases.length);\n});\n\n// Obligation 6. The traversal above proves every property repaints something in\n// the preview; these pin the mapping, so a repaint elsewhere cannot stand in for\n// the part and CSS property the property is meant to drive.\nfor (const contract of await selectedContracts()) {\n test(`${contract.id} paints each declared property on its declared part`, async ({ page }) => {\n test.setTimeout(180_000);\n const harness = await ContractHarness.open(page, contract);\n expect(await harness.assertProperties()).toBeGreaterThan(0);\n });\n}\n"],"mappings":";;;;;;;;;;;;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,QAAQ,YAAqC;AAOtD,KAAK,SAAS,UAAU,EAAE,MAAM,WAAW,CAAC;AAO5C,SAAS,yBAAsC;AAC7C,QAAM,OAAO,KAAK,QAAQ,QAAQ,IAAI,wBAAwB,wBAAwB,mBAAmB;AACzG,QAAM,QAAqB,CAAC;AAC5B,aAAW,aAAa,GAAG,YAAY,IAAI,EAAE,KAAK,GAAG;AACnD,UAAM,OAAO,KAAK,KAAK,MAAM,WAAW,cAAc;AACtD,QAAI,CAAC,GAAG,WAAW,IAAI,EAAG;AAC1B,UAAM,OAAO,KAAK,MAAM,GAAG,aAAa,MAAM,MAAM,CAAC;AAIrD,UAAM,YAAY,KAAK,aAAa;AACpC,eAAW,YAAY,OAAO,KAAK,KAAK,WAAW,CAAC,CAAC,EAAE,KAAK,GAAG;AAC7D,YAAM,KAAK,EAAE,WAAW,SAAS,CAAC;AAAA,IACpC;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAM,qBAAqB,QAAQ,IAAI;AACvC,IAAM,aAAa,uBAAuB,EACvC,OAAO,CAAC,EAAE,UAAU,MAAM,CAAC,sBAAsB,cAAc,kBAAkB;AACpF,IAAM,qBAAqB,oBAAI,IAAsB;AACrD,WAAW,EAAE,WAAW,SAAS,KAAK,YAAY;AAChD,QAAM,YAAY,mBAAmB,IAAI,SAAS,KAAK,CAAC;AACxD,YAAU,KAAK,QAAQ;AACvB,qBAAmB,IAAI,WAAW,SAAS;AAC7C;AAaA,eAAe,6BACb,MACA,kBACA,WACe;AACf,QAAM,QAAQ,KAAK,QAAQ,wBAAwB;AACnD,QAAM,SAAS,MAAM,KAAK,SAAS,MAAM,IAAI,QAAc,CAAC,YAC1D,sBAAsB,MAAM,sBAAsB,MAAM,QAAQ,CAAC,CAAC,CAAC,CAAC;AACtE,QAAM,OAAO;AAGb,QAAM,YAAY,MAAM,MAAM,QAAQ,6EAA6E,EAChH,YAAY,CAAC,aAAa,CAAC,GAAG,IAAI,IAAI,SACpC,IAAI,CAAC,YAAa,QAAwB,QAAQ,aAAa,EAC/D,OAAO,CAAC,UAA2B,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAElD,aAAW,YAAY,WAAW;AAChC,QAAI,CAAC,iBAAiB,SAAS,QAAQ,KAAK,UAAU,IAAI,QAAQ,EAAG;AACrE,UAAM,WAAW,MAAM,QAAQ,mDAAmD,QAAQ,gCAAgC,EAAE,MAAM;AAClI,QAAI,MAAM,SAAS,MAAM,MAAM,EAAG;AAClC,UAAM,SAAS,MAAM,KAAK,SAAS,CAAC,SAClC,SAAS,gBAAgB,MAAM,iBAAiB,IAAI,EAAE,KAAK,GAAG,QAAQ;AAExE,UAAM,iBAAiB;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AACX,QAAI,QAAQ;AACZ,QAAI,cAAc;AAGlB,aAAS,UAAU,GAAG,UAAU,KAAK,UAAU,QAAQ,WAAW;AAChE,YAAM,OAAO;AACb,YAAM,SAAS,QAAQ,gBAAgB,EAAE,MAAM;AAC/C,YAAM,UAAU,SAAS,QAAQ,cAAc;AAC/C,YAAM,QAAQ,MAAM,QAAQ,MAAM;AAClC,UAAI,UAAU,GAAG;AAGf,cAAM,SAAS,QAAQ,gBAAgB,EAAE,MAAM;AAC/C;AAAA,MACF;AACA,oBAAc;AACd,YAAM,QAAQ,IAAI,UAAU,KAAK,EAAE,MAAM;AACzC,YAAM,OAAO;AACb,cAAQ,MAAM,KAAK,SAAS,CAAC,SAC3B,SAAS,gBAAgB,MAAM,iBAAiB,IAAI,EAAE,KAAK,GAAG,QAAQ;AAAA,IAC1E;AACA,QAAI,CAAC,YAAa;AAClB,WAAO,OAAO,GAAG,QAAQ,2CAA2C,EAAE,IAAI,KAAK,MAAM;AACrF,cAAU,IAAI,QAAQ;AAAA,EACxB;AACF;AAKA,eAAe,oCACb,MACA,kBACA,WACe;AACf,QAAM,QAAQ,KAAK,QAAQ,wBAAwB;AACnD,QAAM,YAAY,MAAM,MAAM,QAAQ,kDAAkD,EACrF,YAAY,CAAC,aAAa,CAAC,GAAG,IAAI,IAAI,SACpC,IAAI,CAAC,YAAa,QAAwB,QAAQ,qBAAqB,EACvE,OAAO,CAAC,UAA2B,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAElD,aAAW,YAAY,WAAW;AAChC,QAAI,CAAC,iBAAiB,SAAS,QAAQ,KAAK,UAAU,IAAI,QAAQ,EAAG;AACrE,UAAM,QAAQ,MAAM,QAAQ,oDAAoD,QAAQ,IAAI,EAAE,MAAM;AACpG,QAAI,MAAM,MAAM,MAAM,EAAG,OAAM,MAAM,MAAM;AAAA,EAC7C;AACA,MAAI,UAAU,SAAS,GAAG;AACxB,UAAM,KAAK,SAAS,MAAM,IAAI,QAAc,CAAC,YAC3C,sBAAsB,MAAM,sBAAsB,MAAM,QAAQ,CAAC,CAAC,CAAC,CAAC;AACtE,UAAM,6BAA6B,MAAM,kBAAkB,SAAS;AAAA,EACtE;AACF;AASA,eAAe,iCACb,MACA,kBACA,WACoB;AACpB,QAAM,UAAqB,CAAC;AAC5B,QAAM,QAAQ,KAAK,QAAQ,wBAAwB;AACnD,QAAM,WAAW,MAAM,QAAQ,gCAAgC;AAC/D,WAAS,QAAQ,GAAG,QAAQ,MAAM,SAAS,MAAM,GAAG,SAAS;AAC3D,UAAM,UAAU,SAAS,IAAI,KAAK;AAClC,UAAM,aAAc,MAAM,QAAQ,aAAa,sBAAsB,KAAM,IACxE,MAAM,KAAK,EACX,OAAO,CAAC,aAAa,iBAAiB,SAAS,QAAQ,KAAK,CAAC,UAAU,IAAI,QAAQ,CAAC;AACvF,QAAI,UAAU,WAAW,EAAG;AAC5B,UAAM,SAAS,MAAM,KAAK,SAAS,CAAC,UAAU,OAAO,YAAY,MAAM,IAAI,CAAC,SAAS;AAAA,MAAC;AAAA,MACpF,SAAS,gBAAgB,MAAM,iBAAiB,IAAI,EAAE,KAAK;AAAA,IAC7D,CAAC,CAAC,GAAG,SAAS;AAEd,UAAM,QAAQ,QAAQ,QAAQ,8DAA8D,EAAE,MAAM;AACpG,QAAI,MAAM,MAAM,MAAM,MAAM,EAAG;AAC/B,UAAM,MAAM,MAAM;AAClB,YAAQ,KAAK,KAAK;AAClB,UAAM,KAAK,SAAS,MAAM,IAAI,QAAc,CAAC,YAC3C,sBAAsB,MAAM,sBAAsB,MAAM,QAAQ,CAAC,CAAC,CAAC,CAAC;AACtE,UAAM,QAAQ,MAAM,KAAK,SAAS,CAAC,UAAU,OAAO,YAAY,MAAM,IAAI,CAAC,SAAS;AAAA,MAAC;AAAA,MACnF,SAAS,gBAAgB,MAAM,iBAAiB,IAAI,EAAE,KAAK;AAAA,IAC7D,CAAC,CAAC,GAAG,SAAS;AACd,eAAW,YAAY,WAAW;AAChC,aAAO,MAAM,QAAQ,GAAG,GAAG,QAAQ,8CAA8C,EAC9E,IAAI,KAAK,OAAO,QAAQ,CAAC;AAC5B,gBAAU,IAAI,QAAQ;AAAA,IACxB;AAAA,EACF;AACA,SAAO;AACT;AAKA,eAAe,gCACb,MACA,kBACA,WACe;AACf,QAAM,QAAQ,KAAK,QAAQ,wBAAwB;AACnD,QAAM,UAAU,MAAM,QAAQ,+CAA+C;AAC7E,WAAS,QAAQ,GAAG,QAAQ,MAAM,QAAQ,MAAM,GAAG,SAAS;AAC1D,UAAM,SAAS,QAAQ,IAAI,KAAK;AAChC,UAAM,WAAW,MAAM,OAAO,aAAa,qBAAqB;AAChE,QAAI,CAAC,YAAY,CAAC,iBAAiB,SAAS,QAAQ,KAAK,UAAU,IAAI,QAAQ,EAAG;AAClF,UAAM,SAAS,MAAM,KAAK,SAAS,CAAC,SAClC,SAAS,gBAAgB,MAAM,iBAAiB,IAAI,EAAE,KAAK,GAAG,QAAQ;AAIxE,UAAM,QAAQ,OAAO,UAAU,SAAS,EAAE,MAAM,QAAQ,CAAC;AACzD,QAAI,MAAM,MAAM,MAAM,KAAK,CAAC,MAAM,MAAM,UAAU,EAAG,OAAM,MAAM,MAAM,EAAE,OAAO,KAAK,CAAC;AACtF,UAAM,SAAS,OAAO,QAAQ,iCAAiC,EAAE,MAAM;AACvE,UAAM,OAAO,QAAQ,gBAAgB,EAAE,MAAM,EAAE,OAAO,KAAK,CAAC;AAC5D,UAAM,SAAS,OAAO,QAAQ,0CAA0C,EAAE,MAAM;AAChF,QAAI,MAAM,OAAO,MAAM,MAAM,EAAG;AAChC,UAAM,OAAO,MAAM,EAAE,OAAO,KAAK,CAAC;AAElC,UAAM,OAAO;AAAA,MAAK,MAAM,KAAK,SAAS,CAAC,SACrC,SAAS,gBAAgB,MAAM,iBAAiB,IAAI,EAAE,KAAK,GAAG,QAAQ;AAAA,MACtE,EAAE,SAAS,GAAG,QAAQ,6CAA6C;AAAA,IAAC,EACnE,IAAI,QAAQ,IAAI,OAAO,IAAI,aAAa,MAAM,CAAC,GAAG,CAAC;AACtD,cAAU,IAAI,QAAQ;AAAA,EACxB;AACF;AAEA,SAAS,aAAa,OAAuB;AAC3C,SAAO,MAAM,QAAQ,uBAAuB,MAAM;AACpD;AAQA,eAAe,iBACb,MACA,kBACA,kBAA4B,CAAC,GAC7B,kBAA4B,CAAC,GACP;AACtB,SAAO,KAAK,SAAS,OAAO,EAAE,YAAY,QAAQ,OAAO,MAAM;AAC7D,UAAM,QAAQ,MAAM,KAAK,SAAS,iBAA8B,gBAAgB,CAAC,EAC9E,KAAK,CAAC,YAAY,QAAQ,iBAAiB,IAAI;AAClD,UAAM,UAAU,OAAO,cAA2B,eAAe;AACjE,QAAI,CAAC,SAAS,CAAC,QAAS,QAAO,EAAE,SAAS,CAAC,GAAG,WAAW,CAAC,EAAE;AAE5D,UAAM,mBAAmB,oBAAI,IAAY;AACzC,QAAI,OAAO,SAAS,GAAG;AACrB,iBAAW,YAAY,QAAQ;AAC7B,YAAI,WAAW,SAAS,QAAQ,EAAG,kBAAiB,IAAI,QAAQ;AAAA,MAClE;AAAA,IACF,OAAO;AACL,iBAAW,WAAW,MAAM,iBAA8B,uBAAuB,GAAG;AAClF,cAAM,WAAW,QAAQ,QAAQ;AACjC,YAAI,QAAQ,iBAAiB,QAAQ,YAAY,WAAW,SAAS,QAAQ,GAAG;AAC9E,2BAAiB,IAAI,QAAQ;AAAA,QAC/B;AAAA,MACF;AACA,iBAAW,WAAW,MAAM,iBAA8B,wBAAwB,GAAG;AACnF,YAAI,QAAQ,iBAAiB,KAAM;AACnC,mBAAW,aAAa,QAAQ,QAAQ,kBAAkB,IAAI,MAAM,KAAK,GAAG;AAC1E,cAAI,WAAW,SAAS,QAAQ,EAAG,kBAAiB,IAAI,QAAQ;AAAA,QAClE;AAAA,MACF;AAAA,IACF;AAKA,eAAW,YAAY,CAAC,GAAG,gBAAgB,GAAG;AAC5C,UAAI,CAAC,SAAS,SAAS,UAAU,EAAG;AACpC,iBAAW,QAAQ,CAAC,OAAO,SAAS,UAAU,MAAM,GAAG;AACrD,cAAM,eAAe,GAAG,QAAQ,IAAI,IAAI;AACxC,YAAI,WAAW,SAAS,YAAY,EAAG,kBAAiB,IAAI,YAAY;AAAA,MAC1E;AAAA,IACF;AAMA,eAAW,YAAY,OAAQ,kBAAiB,OAAO,QAAQ;AAC/D,QAAI,iBAAiB,SAAS,EAAG,QAAO,EAAE,SAAS,CAAC,GAAG,WAAW,CAAC,EAAE;AACrE,UAAM,aAAa;AAAA,MACjB;AAAA,MAAW;AAAA,MAAc;AAAA,MAAW;AAAA,MAAY;AAAA,MAChD;AAAA,MAAS;AAAA,MAAc;AAAA,MAAmB;AAAA,MAAmB;AAAA,MAAkB;AAAA,MAC/E;AAAA,MAAU;AAAA,MAAe;AAAA,MAAe;AAAA,MACxC;AAAA,MAAkB;AAAA,MAAoB;AAAA,MAAqB;AAAA,MAC3D;AAAA,MAAkB;AAAA,MAAoB;AAAA,MAAqB;AAAA,MAC3D;AAAA,MAAgB;AAAA,MAAuB;AAAA,MACvC;AAAA,MAA2B;AAAA,MAC3B;AAAA,MAAW;AAAA,MAAgB;AAAA,MAAgB;AAAA,MAC3C;AAAA,MAAU;AAAA,MAAkB;AAAA,MAC5B;AAAA,MAAc;AAAA,MAAY;AAAA,MAAc;AAAA,MAAa;AAAA,MAAc;AAAA,MACnE;AAAA,MAAa;AAAA,MAAkB;AAAA,MAAiB;AAAA,MAAc;AAAA,MAC9D;AAAA,MAAW;AAAA,MAAc;AAAA,MAAgB;AAAA,MAAiB;AAAA,MAC1D;AAAA,MAAU;AAAA,MAAa;AAAA,MAAe;AAAA,MAAgB;AAAA,MACtD;AAAA,MAAO;AAAA,MAAU;AAAA,MACjB;AAAA,MAAS;AAAA,MAAY;AAAA,MAAY;AAAA,MAAU;AAAA,MAAa;AAAA,MACxD;AAAA,MAAO;AAAA,MAAS;AAAA,MAAU;AAAA,MAC1B;AAAA,MAAa;AAAA,MAAmB;AAAA,MAAa;AAAA,MAAU;AAAA,MACvD;AAAA,MAAkB;AAAA,MAAgB;AAAA,MAAe;AAAA,MAAgB;AAAA,MAAc;AAAA,MAC/E;AAAA,MAAuB;AAAA,MAAoB;AAAA,MAAc;AAAA,MAAW;AAAA,MAAQ;AAAA,MAC5E;AAAA,MAAY;AAAA,MAAa;AAAA,MAAa;AAAA,MAAY;AAAA,MAAa;AAAA,MAC/D;AAAA,MAAQ;AAAA,MAAU;AAAA,MAAe;AAAA,MAAmB;AAAA,MACpD;AAAA,MAAU;AAAA,MAAiB;AAAA,MAC3B;AAAA,MAAsB;AAAA,MAAsB;AAAA,MAA4B;AAAA,MACxE;AAAA,MAAkB;AAAA,IACpB;AAEA,UAAM,mBAAmB;AACzB,UAAM,mBAAmB,CAAC,YAAqB,MAAM,KAAK,QAAQ,UAAU,EACzE,OAAO,CAAC,cAAc,CAAC,iBAAiB,KAAK,UAAU,IAAI,CAAC,EAC5D,IAAI,CAAC,cAAc,GAAG,UAAU,IAAI,IAAI,UAAU,KAAK,EAAE,EACzD,KAAK,EACL,KAAK,GAAG;AAEX,UAAM,qBAAqB,CAAC,aAAqB;AAC/C,YAAM,kBAAkB,CAAC,YAAY,SAAS;AAC9C,UAAI,SAAS,SAAS,aAAa,EAAG,iBAAgB,KAAK,eAAe;AAC1E,UAAI,SAAS,SAAS,WAAW,GAAG;AAClC,wBAAgB;AAAA,UACd;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAKA,UAAM,mBAAmB,MAAM;AAC7B,YAAM,QAAQ,CAAC,SAAS,GAAG,SAAS,iBAA8B,iBAAiB,CAAC;AACpF,aAAO,MAAM,QAAQ,CAACA,UAAS,CAACA,OAAM,GAAGA,MAAK,iBAA8B,GAAG,CAAC,CAAC;AAAA,IACnF;AAEA,UAAM,kBAAkB,CAAC,SAAsB,OAAe,oBAA8B;AAC1F,YAAM,QAAQ,iBAAiB,OAAO;AACtC,YAAM,OAAO,QAAQ,sBAAsB;AAC3C,YAAM,SAAS,WAAW,IAAI,CAAC,aAAa,MAAM,QAAQ,CAAC,EAAE,KAAK,GAAG;AACrE,YAAM,eAAe,gBAAgB,IAAI,CAAC,aAAa;AACrD,cAAM,SAAS,iBAAiB,SAAS,QAAQ;AACjD,eAAO,WAAW,IAAI,CAAC,aAAa,OAAO,QAAQ,CAAC,EAAE,KAAK,GAAG;AAAA,MAChE,CAAC,EAAE,KAAK,GAAG;AACX,aAAO;AAAA,QACL;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACA,GAAG,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,IAAI,KAAK,MAAM;AAAA,QAChD,GAAG,QAAQ,WAAW,IAAI,QAAQ,YAAY;AAAA,QAC9C,iBAAiB,OAAO;AAAA,MAC1B,EAAE,KAAK,GAAG;AAAA,IACZ;AAEA,UAAM,cAAc,CAAC,aAAqB;AACxC,YAAM,kBAAkB,mBAAmB,QAAQ;AACnD,aAAO,iBAAiB,EAAE,IAAI,CAAC,SAAS,UACtC,gBAAgB,SAAS,OAAO,eAAe,CAAC;AAAA,IACpD;AAOA,UAAM,YAAY,CAAC,UAAkB,aAAuB;AAC1D,YAAM,kBAAkB,mBAAmB,QAAQ;AACnD,YAAM,QAAQ,iBAAiB;AAC/B,UAAI,MAAM,WAAW,SAAS,OAAQ,QAAO;AAC7C,eAAS,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS;AACjD,YAAI,gBAAgB,MAAM,KAAK,GAAG,OAAO,eAAe,MAAM,SAAS,KAAK,EAAG,QAAO;AAAA,MACxF;AACA,aAAO;AAAA,IACT;AAEA,UAAM,kBAAkB,CAAC,UAAkB,YAA8B;AACvE,YAAM,SAAmB,CAAC;AAC1B,YAAM,MAAM,IAAI,eAAyB;AACvC,mBAAW,aAAa,YAAY;AAClC,cAAI,cAAc,WAAW,CAAC,OAAO,SAAS,SAAS,EAAG,QAAO,KAAK,SAAS;AAAA,QACjF;AAAA,MACF;AACA,UAAI,6DAA6D,KAAK,QAAQ,GAAG;AAC/E,YAAI,gBAAgB,kBAAkB;AAAA,MACxC;AACA,UAAI,SAAS,SAAS,aAAa,EAAG,KAAI,aAAa,OAAO;AAC9D,UAAI,SAAS,SAAS,aAAa,EAAG,KAAI,OAAO,KAAK;AACtD,UAAI,SAAS,SAAS,aAAa,EAAG,KAAI,QAAQ,MAAM;AACxD,UAAI,SAAS,SAAS,gBAAgB,EAAG,KAAI,OAAO,MAAM;AAC1D,UAAI,SAAS,SAAS,QAAQ,EAAG,KAAI,8BAA8B,MAAM;AACzE,UAAI,SAAS,SAAS,MAAM,EAAG,KAAI,aAAa,MAAM;AACtD,UAAI,SAAS,SAAS,UAAU,KAAK,SAAS,SAAS,aAAa,GAAG;AACrE,YAAI,0DAA0D,MAAM;AAAA,MACtE;AACA,UAAI,SAAS,SAAS,UAAU,KAAK,SAAS,SAAS,YAAY,EAAG,KAAI,MAAM,IAAI;AACpF,UAAI,SAAS,SAAS,SAAS,EAAG,KAAI,QAAQ,MAAM;AACpD,UAAI,SAAS,SAAS,SAAS,EAAG,KAAI,YAAY,SAAS,UAAU,QAAQ,UAAU;AACvF,UAAI,SAAS,SAAS,OAAO,EAAG,KAAI,SAAS,UAAU,UAAU;AACjE,UAAI,SAAS,SAAS,UAAU,EAAG,KAAI,eAAe,qBAAqB,QAAQ;AACnF,UAAI,SAAS,SAAS,gBAAgB,EAAG,KAAI,UAAU,SAAS;AAChE,UAAI,SAAS,SAAS,SAAS,GAAG;AAChC,YAAI,4EAA4E,MAAM;AAAA,MACxF;AACA,UAAI,uEAAuE,KAAK,QAAQ,GAAG;AACzF,YAAI,QAAQ,KAAK;AAAA,MACnB;AACA,UAAI,SAAS,SAAS,OAAO,EAAG,KAAI,QAAQ,MAAM;AAClD,UAAI,iCAAiC,QAAQ,gBAAgB,QAAQ,GAAG;AACxE,aAAO;AAAA,IACT;AAEA,UAAM,OAAO,SAAS;AACtB,UAAM,UAAoB,CAAC;AAC3B,UAAM,YAAsB,CAAC;AAK7B,UAAM,SAAS,YAAY;AACzB,YAAM,IAAI,QAAc,CAAC,YAAY,sBAAsB,MAAM,QAAQ,CAAC,CAAC;AAC3E,iBAAW,aAAa,SAAS,cAAc,EAAG,WAAU,OAAO;AAAA,IACrE;AAIA,UAAM,SAAS,SAAS,cAAc,OAAO;AAC7C,WAAO,QAAQ,kBAAkB;AACjC,WAAO,cAAc;AACrB,aAAS,KAAK,YAAY,MAAM;AAChC,UAAM,SAAS,OAAO;AACtB,UAAM,OAAO;AAEb,eAAW,YAAY,kBAAkB;AAKvC,YAAM,mBAAmB,CAAC,QAAQ;AAClC,UAAI,SAAS,SAAS,UAAU,GAAG;AACjC,mBAAW,QAAQ,CAAC,OAAO,SAAS,UAAU,MAAM,GAAG;AACrD,gBAAM,eAAe,GAAG,QAAQ,IAAI,IAAI;AACxC,cAAI,WAAW,SAAS,YAAY,EAAG,kBAAiB,KAAK,YAAY;AAAA,QAC3E;AAAA,MACF;AACA,YAAM,WAAW,iBAAiB,IAAI,CAAC,UAAU;AAAA,QAC/C;AAAA,QACA,OAAO,KAAK,MAAM,iBAAiB,IAAI;AAAA,QACvC,UAAU,KAAK,MAAM,oBAAoB,IAAI;AAAA,MAC/C,EAAE;AACF,YAAM,UAAU,iBAAiB,IAAI,EAAE,iBAAiB,QAAQ,EAAE,KAAK;AACvE,YAAM,WAAW,YAAY,QAAQ;AACrC,UAAI,UAAU;AACd,iBAAW,aAAa,gBAAgB,UAAU,OAAO,GAAG;AAC1D,mBAAW,QAAQ,iBAAkB,MAAK,MAAM,YAAY,MAAM,WAAW,WAAW;AAGxF,cAAM,OAAO;AACb,YAAI,UAAU,UAAU,QAAQ,GAAG;AACjC,oBAAU;AACV;AAAA,QACF;AAAA,MACF;AACA,iBAAW,SAAS,UAAU;AAC5B,YAAI,MAAM,MAAO,MAAK,MAAM,YAAY,MAAM,MAAM,MAAM,OAAO,MAAM,QAAQ;AAAA,YAC1E,MAAK,MAAM,eAAe,MAAM,IAAI;AAAA,MAC3C;AACA,YAAM,OAAO;AACb,OAAC,UAAU,UAAU,WAAW,KAAK,QAAQ;AAAA,IAC/C;AAEA,WAAO,OAAO;AACd,WAAO,EAAE,SAAS,UAAU;AAAA,EAC9B,GAAG,EAAE,YAAY,kBAAkB,QAAQ,iBAAiB,QAAQ,gBAAgB,CAAC;AACvF;AAEA,eAAe,gBAAgB,MAAY,WAAkC;AAC3E,QAAM,KAAK,SAAS,OAAO,OAAO;AAChC,UAAM,SAAS,OAAO;AACtB,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,kEAAkE;AAC/F,WAAO,gBAAgB,EAAE;AACzB,UAAM,IAAI,QAAc,CAAC,YAAY,sBAAsB,MACzD,sBAAsB,MAAM,QAAQ,CAAC,CAAC,CAAC;AAAA,EAC3C,GAAG,SAAS;AACZ,QAAM,KAAK,QAAQ,gBAAgB,EAAE,OAAO,EAAE,SAAS,KAAK,CAAC,EAAE,QAAQ;AACzE;AAEA,WAAW,CAAC,WAAW,OAAO,KAAK,oBAAoB;AACrD,OAAK,GAAG,SAAS,gEAAgE,OAAO,EAAE,KAAK,MAAM;AACnG,SAAK,WAAW,GAAO;AACvB,UAAM,qBAAqB,IAAI;AAC/B,UAAM,UAAU,oBAAI,IAAY;AAChC,UAAM,OAAO,oBAAI,IAAY;AAC7B,UAAM,YAAY,oBAAI,IAAY;AAClC,UAAM,mBAAmB,oBAAI,IAAY;AAEzC,UAAM,QAAQ,OAAO,kBAA4B,SAAmB,CAAC,MAAM;AACzE,YAAM,YAAY,OAAO,SAAS,IAC9B,OAAO,OAAO,CAAC,aAAa,CAAC,QAAQ,IAAI,QAAQ,CAAC,IAClD,CAAC;AACL,UAAI,OAAO,SAAS,KAAK,UAAU,WAAW,EAAG;AAIjD,UAAI,OAAO,SAAS,GAAG;AACrB,cAAM,YAAY,KAAK;AAAA,UACrB;AAAA,QAEF;AACA,iBAAS,QAAQ,GAAG,QAAQ,MAAM,UAAU,MAAM,GAAG,SAAS;AAC5D,gBAAM,UAAU,IAAI,KAAK,EAAE,MAAM,EAAE,OAAO,KAAK,CAAC;AAAA,QAClD;AAAA,MACF;AAKA,YAAM,eAAe,KAAK,QAAQ,uCAAuC,EAAE,MAAM;AACjF,UAAI,MAAM,aAAa,MAAM,EAAG,OAAM,aAAa,MAAM,EAAE,OAAO,KAAK,CAAC;AAExE,YAAM,6BAA6B,MAAM,kBAAkB,gBAAgB;AAC3E,YAAM,QAAQ,MAAM,iCAAiC,MAAM,kBAAkB,gBAAgB;AAE7F,YAAM,6BAA6B,MAAM,kBAAkB,gBAAgB;AAC3E,YAAM,oCAAoC,MAAM,kBAAkB,gBAAgB;AAClF,YAAM,gCAAgC,MAAM,kBAAkB,gBAAgB;AAC9E,YAAM,SAAS,MAAM,iBAAiB,MAAM,kBAAkB,WAAW,CAAC,GAAG,OAAO,CAAC;AACrF,iBAAW,QAAQ,OAAO;AACxB,YAAI,MAAM,KAAK,MAAM,EAAG,OAAM,KAAK,MAAM;AAAA,MAC3C;AACA,aAAO,QAAQ,QAAQ,CAAC,aAAa,QAAQ,IAAI,QAAQ,CAAC;AAC1D,aAAO,QAAQ,QAAQ,CAAC,aAAa,KAAK,IAAI,QAAQ,CAAC;AACvD,aAAO,UAAU,QAAQ,CAAC,aAAa;AACrC,aAAK,IAAI,QAAQ;AACjB,YAAI,CAAC,QAAQ,IAAI,QAAQ,EAAG,WAAU,IAAI,QAAQ;AAAA,MACpD,CAAC;AAAA,IACH;AAEA,UAAM,oBAAoB,OACxB,aACA,kBACA,SAAmB,CAAC,MACjB;AACH,YAAM,gBAAgB,MAAM,WAAW;AAEvC,YAAM,aAAa,YAAY;AAC7B,YAAI,OAAO,SAAS,KAAK,OAAO,MAAM,CAAC,aAAa,QAAQ,IAAI,QAAQ,CAAC,EAAG;AAC5E,cAAM,aAAa,KAAK,QAAQ,gDAAgD,EAAE,MAAM;AACxF,cAAM,aAAa,MAAM,WAAW,MAAM,IACtC,MAAM,WAAW,QAAQ,QAAQ,EAAE,YAAY,CAAC,YAC9C,QAAQ,IAAI,CAAC,WAAY,OAA6B,KAAK,CAAC,IAC9D,CAAC,EAAE;AAEP,mBAAW,aAAa,YAAY;AAClC,gBAAM,oBAAoB,KAAK,QAAQ,gDAAgD,EAAE,MAAM;AAC/F,cAAI,aAAa,MAAM,kBAAkB,MAAM,EAAG,OAAM,kBAAkB,aAAa,SAAS;AAEhG,gBAAM,cAAc,KAAK,QAAQ,uDAAuD;AACxF,gBAAM,gBAAgB,MAAM,YAAY,MAAM,IAC1C,MAAM,YAAY,gBAAgB,IAClC,CAAC,EAAE;AAEP,mBAAS,eAAe,GAAG,eAAe,cAAc,QAAQ,gBAAgB;AAC9E,gBAAI,cAAc,YAAY,GAAG;AAC/B,oBAAM,KAAK,QAAQ,uDAAuD,EACvE,IAAI,YAAY,EAChB,MAAM,EAAE,OAAO,KAAK,CAAC;AAAA,YAC1B;AAEA,kBAAM,MAAM,kBAAkB,MAAM;AACpC,kBAAM,cAAc,KAAK;AAAA,cACvB;AAAA,YACF;AACA,kBAAM,gBAAgB,MAAM,YAAY,gBAAgB;AACxD,qBAAS,eAAe,GAAG,eAAe,cAAc,QAAQ,gBAAgB;AAC9E,oBAAM,KAAK;AAAA,gBACT;AAAA,cACF,EAAE,IAAI,YAAY,EAAE,MAAM,EAAE,OAAO,KAAK,CAAC;AACzC,oBAAM,MAAM,kBAAkB,MAAM;AAEpC,oBAAM,gBAAgB,KAAK;AAAA,gBACzB;AAAA,cACF;AACA,oBAAM,kBAAkB,MAAM,cAAc,gBAAgB;AAC5D,uBAAS,iBAAiB,GAAG,iBAAiB,gBAAgB,QAAQ,kBAAkB;AACtF,sBAAM,KAAK;AAAA,kBACT;AAAA,gBACF,EAAE,IAAI,cAAc,EAAE,MAAM,EAAE,OAAO,KAAK,CAAC;AAC3C,sBAAM,MAAM,kBAAkB,MAAM;AAAA,cACtC;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,YAAM,WAAW;AACjB,UAAI,OAAO,WAAW,KAAK,OAAO,MAAM,CAAC,aAAa,QAAQ,IAAI,QAAQ,CAAC,EAAG;AAG9E,YAAM,gBAAgB,KAAK;AAAA,QACzB;AAAA,MACF,EAAE,MAAM;AACR,UAAI,MAAM,cAAc,MAAM,GAAG;AAC/B,cAAM,cAAc,MAAM,EAAE,OAAO,KAAK,CAAC;AACzC,cAAM,KAAK,QAAQ,iBAAiB,EAAE,QAAQ;AAC9C,cAAM,WAAW;AAAA,MACnB;AAKA,YAAM,gBAAgB,KAAK,QAAQ,6DAA6D;AAChG,eAAS,cAAc,GAAG,cAAc,MAAM,cAAc,MAAM,GAAG,eAAe;AAClF,cAAM,SAAS,MAAM,cAAc,IAAI,WAAW,EAAE,QAAQ,QAAQ,EAAE,YAAY,CAAC,YACjF,QAAQ,IAAI,CAAC,WAAY,OAA6B,KAAK,CAAC;AAC9D,mBAAW,SAAS,QAAQ;AAC1B,cAAI,OAAO,MAAM,CAAC,aAAa,QAAQ,IAAI,QAAQ,CAAC,EAAG;AACvD,gBAAM,cAAc,IAAI,WAAW,EAAE,aAAa,KAAK;AACvD,gBAAM,WAAW;AAAA,QACnB;AAAA,MACF;AAIA,YAAM,YAAY,KAAK;AAAA,QACrB;AAAA,MACF;AACA,eAAS,QAAQ,GAAG,QAAQ,MAAM,UAAU,MAAM,GAAG,SAAS;AAC5D,YAAI,OAAO,MAAM,CAAC,aAAa,QAAQ,IAAI,QAAQ,CAAC,EAAG;AACvD,cAAM,UAAU,IAAI,KAAK,EAAE,MAAM,EAAE,OAAO,KAAK,CAAC;AAChD,cAAM,WAAW;AAAA,MACnB;AAQA,YAAM,gBAAgB,KAAK;AAAA,QACzB;AAAA,MACF,EAAE,MAAM;AACR,UAAI,MAAM,cAAc,MAAM,EAAG,OAAM,cAAc,MAAM,EAAE,OAAO,KAAK,CAAC;AAC1E,YAAM,eAAe,KAAK,QAAQ,gDAAgD;AAClF,eAAS,QAAQ,GAAG,QAAQ,MAAM,aAAa,MAAM,GAAG,SAAS;AAC/D,YAAI,OAAO,MAAM,CAAC,aAAa,QAAQ,IAAI,QAAQ,CAAC,EAAG;AAEvD,YAAI;AACF,gBAAM,aAAa,IAAI,KAAK,EAAE,MAAM,EAAE,OAAO,MAAM,SAAS,IAAM,CAAC;AAAA,QACrE,QAAQ;AACN;AAAA,QACF;AACA,cAAM,MAAM,kBAAkB,MAAM;AAAA,MACtC;AAAA,IACF;AAEA,UAAM,kBAAkB,WAAW,OAAO;AAM1C,UAAM,aAAa,QAAQ,OAAO,CAAC,aAAa,CAAC,QAAQ,IAAI,QAAQ,CAAC;AACtE,QAAI,WAAW,SAAS,EAAG,OAAM,kBAAkB,WAAW,SAAS,UAAU;AAEjF,UAAM,aAAa,QAAQ,OAAO,CAAC,aAAa,CAAC,KAAK,IAAI,QAAQ,CAAC;AACnE,UAAM,cAAc,QAAQ,OAAO,CAAC,aAAa,KAAK,IAAI,QAAQ,KAAK,CAAC,QAAQ,IAAI,QAAQ,CAAC;AAC7F,UAAM,sBAAsB,QAAQ,OAAO,CAAC,aAAa,CAAC,iBAAiB,IAAI,QAAQ,CAAC;AAExF,WAAO,YAAY;AAAA,EAA6D,WAAW,KAAK,IAAI,CAAC,EAAE,EACpG,QAAQ,CAAC,CAAC;AACb,WAAO,aAAa;AAAA,EAAsD,YAAY,KAAK,IAAI,CAAC,EAAE,EAC/F,QAAQ,CAAC,CAAC;AACb,WAAO,qBAAqB;AAAA,EAAgE,oBAAoB,KAAK,IAAI,CAAC,EAAE,EACzH,QAAQ,CAAC,CAAC;AACb,WAAO,QAAQ,IAAI,EAAE,KAAK,QAAQ,MAAM;AAAA,EAC1C,CAAC;AACH;AAEA,KAAK,uDAAuD,MAAM;AAChE,QAAM,eAAe,CAAC,GAAG,mBAAmB,OAAO,CAAC,EAAE,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,QAAQ,CAAC;AAC1F,SAAO,WAAW,MAAM,EAAE,gBAAgB,CAAC;AAC3C,SAAO,YAAY,EAAE,KAAK,WAAW,MAAM;AAC7C,CAAC;AAKD,WAAW,YAAY,MAAM,kBAAkB,GAAG;AAChD,OAAK,GAAG,SAAS,EAAE,uDAAuD,OAAO,EAAE,KAAK,MAAM;AAC5F,SAAK,WAAW,IAAO;AACvB,UAAM,UAAU,MAAM,gBAAgB,KAAK,MAAM,QAAQ;AACzD,WAAO,MAAM,QAAQ,iBAAiB,CAAC,EAAE,gBAAgB,CAAC;AAAA,EAC5D,CAAC;AACH;","names":["root"]}
@@ -0,0 +1,293 @@
1
+ import { PlaywrightTestProject, PlaywrightTestConfig } from '@playwright/test';
2
+ import { L as LiveTokensTestingConfig } from './vitest-BE6uGF31.js';
3
+ export { C as COMPONENTS_PATH_ENV, a as COMPONENT_ENV, R as ResolvedTestingConfig, T as TESTING_CONFIG_FILE, V as VitestConfigOptions, c as createVitestConfig, d as defineTestingConfig, b as devServerCommand, r as resolveTestingConfig } from './vitest-BE6uGF31.js';
4
+ import 'vite';
5
+ import 'vitest/config';
6
+
7
+ interface PlaywrightConfigOptions extends LiveTokensTestingConfig {
8
+ /** Project root the settings resolve against. Default `process.cwd()`. */
9
+ root?: string;
10
+ /** Projects that run beside the contract project. */
11
+ extraProjects?: PlaywrightTestProject[];
12
+ /** Where projects that declare no `testDir` of their own look. */
13
+ testDir?: string;
14
+ }
15
+ /**
16
+ * The contract project, its dev server, and the data isolation the two share.
17
+ *
18
+ * Isolation runs here rather than in a global setup because the config is the
19
+ * first thing every process in the run evaluates: the environment it leaves
20
+ * behind reaches the workers and the dev server, and nothing in the run can
21
+ * observe the state before it.
22
+ */
23
+ declare function createPlaywrightConfig(options?: PlaywrightConfigOptions): Promise<PlaywrightTestConfig>;
24
+
25
+ /**
26
+ * The plugin reads this name ahead of its own options and
27
+ * `live-tokens.config.json`, so setting it redirects every server-side write —
28
+ * the data tree, `tokens.generated.css`, and `fonts.css` — into the copy.
29
+ */
30
+ declare const TEST_DATA_DIR_ENV = "LIVE_TOKENS_TEST_DATA_DIR";
31
+ /** What the suites and the harness read component configs from in the runner's
32
+ * own process. It names the same directory and is a separate variable because
33
+ * it answers a different question: where a reader looks, not where the server
34
+ * is confined. */
35
+ declare const DATA_DIR_ENV = "LIVE_TOKENS_DATA_DIR";
36
+ interface IsolatedData {
37
+ dataDir: string;
38
+ /** True when this process made the copy and owns removing it. */
39
+ created: boolean;
40
+ }
41
+ /**
42
+ * Copy `sourceDataDir` into a unique temporary directory and point both the
43
+ * server and the runner at it. Idempotent across processes: Playwright loads
44
+ * the config again in every worker, and each inherits the parent's environment,
45
+ * so only the first call copies anything.
46
+ */
47
+ declare function isolateDataDir(sourceDataDir: string): IsolatedData;
48
+
49
+ declare const PORT_ENV = "LIVE_TOKENS_TEST_PORT";
50
+ /**
51
+ * The port the dev server and `baseURL` share. Cached in the environment so
52
+ * every Playwright worker, which loads the config again in its own process,
53
+ * reads the port the main process settled on.
54
+ */
55
+ declare function resolvePort(preferred?: number): number;
56
+
57
+ type ContractRule = 'contract-listed' | 'contract-render' | 'contract-alias' | 'contract-persist' | 'contract-theme' | 'contract-preview' | 'contract-sketch';
58
+ /**
59
+ * A failed obligation, carrying the rule id the CLI reports it under. A defect
60
+ * fixture names the rule it expects, and `check-component --tests` maps a
61
+ * reporter error onto a finding.
62
+ */
63
+ declare class ContractViolation extends Error {
64
+ readonly rule: ContractRule;
65
+ readonly component: string;
66
+ constructor(rule: ContractRule, component: string, message: string);
67
+ }
68
+ interface Inapplicable {
69
+ applicable: false;
70
+ reason: string;
71
+ }
72
+ declare function isInapplicable(value: unknown): value is Inapplicable;
73
+ interface PartLocator {
74
+ /** Resolved inside the preview stage unless `portal` is set. */
75
+ selector: string;
76
+ /** Read computed style from this pseudo-element of the part, e.g.
77
+ * `'::after'`. Chromium's `getComputedStyle` only tolerates the bare form
78
+ * (`'after'`) for `::before`/`::after`; use the full `::` syntax so a
79
+ * future pseudo-element (`::placeholder`, `::marker`, ...) works the same
80
+ * way without a silent fallback to the host element's own style. */
81
+ pseudo?: string;
82
+ /** Rendered outside the preview stage. Resolved against the document. */
83
+ portal?: boolean;
84
+ }
85
+ type PartDeclaration = string | PartLocator;
86
+ /**
87
+ * An editor control the preview is gated behind: a canvas-toolbar checkbox, an
88
+ * optional-content switch. `check` sets a checkbox to a state and is safe to
89
+ * repeat; `value` picks a select option; neither clicks once.
90
+ */
91
+ interface ControlStep {
92
+ kind: 'control';
93
+ /** Selector inside the visible variant group. */
94
+ selector: string;
95
+ check?: boolean;
96
+ value?: string;
97
+ }
98
+ type SetupStep = InteractionAction | ControlStep;
99
+ /** Which VariantGroup, which state tab, and what has to happen first. */
100
+ interface View {
101
+ /** Variant tab label. Omitted when the editor renders one variant. */
102
+ variant?: string;
103
+ /** State tab label. Omitted when the editor renders no state strip. */
104
+ state?: string;
105
+ /** Run after the tabs are selected. Portaled and toolbar-gated parts exist
106
+ * only once these have run. */
107
+ setup?: SetupStep[];
108
+ }
109
+ /** Part key -> CSS property -> the design token that must drive it. */
110
+ type PaintMap = Record<string, Record<string, string>>;
111
+ interface PropertyExpectation extends View {
112
+ paints: PaintMap;
113
+ }
114
+ interface StateExpectation extends View {
115
+ state: string;
116
+ /** Class the root part carries while the editor previews this state. */
117
+ forceClass?: string;
118
+ /** Part key -> attributes it must carry. A null value requires the absence. */
119
+ attributes?: Record<string, Record<string, string | null>>;
120
+ /** What the state repaints, as computed-value equality against its token. */
121
+ paints?: PaintMap;
122
+ }
123
+ /**
124
+ * `token` and `opacity` drive the token selector for `variable`. `gradient`
125
+ * drives the gradient editor for `variable`. `literal` drives `control` and
126
+ * reads `variable` back off the root, which is where an intrinsic lands: the
127
+ * editors write those into the alias bucket. `config` drives `control` and
128
+ * reads `configKey` out of the config bucket, which holds editor metadata that
129
+ * never reaches `:root`.
130
+ */
131
+ type PersistenceShape = 'token' | 'literal' | 'opacity' | 'gradient' | 'config';
132
+ interface PersistenceCase extends View {
133
+ shape: PersistenceShape;
134
+ /** The alias the value is read back from. Omitted for `config`. */
135
+ variable?: string;
136
+ /** Selector inside the visible variant group, for `literal` and `config`. */
137
+ control?: string;
138
+ /** The config-bucket key, for `config`. */
139
+ configKey?: string;
140
+ /** Where the persisted value must land once the page has reloaded. */
141
+ observe: {
142
+ part: string;
143
+ css: string;
144
+ };
145
+ }
146
+ interface PersistenceExpectation {
147
+ cases: PersistenceCase[];
148
+ /** The alias Reset must return to the value the server holds for it. It has
149
+ * to be one a case above moves, so the saved value and the value the
150
+ * component booted with are different and Reset can be seen to choose. */
151
+ resetVariable: string;
152
+ }
153
+ interface ThemeExpectation extends View {
154
+ /** Theme slug shown in the Theme Picker, e.g. `ocean`. */
155
+ theme: string;
156
+ /** Variables whose root value the theme must move. */
157
+ changed: string[];
158
+ /**
159
+ * Variables the theme must leave exactly as they were. Two theme JSON files
160
+ * can name the identical design token (e.g. both `--border-neutral`) and
161
+ * still resolve to different rendered colors, because many color primitives
162
+ * are computed per theme from a palette/seed even when the alias string is
163
+ * unchanged — comparing the two files' alias *names* does not establish
164
+ * invariance. Pick `unchanged` candidates from token families a theme never
165
+ * recolors: `--shadow-*`, `--icon-size-*`, `--font-size-*`,
166
+ * `--line-height-*`, `--font-family`/`--font-mono`, and the spacing/radius/
167
+ * border-width scale steps (`--space-*`, `--radius-*`, `--border-width-*`)
168
+ * are all fixed constants, not palette-derived — verify a candidate's
169
+ * *resolved* value is identical between the two theme files before trusting
170
+ * it, not just that the alias name matches.
171
+ */
172
+ unchanged: string[];
173
+ /** Variables the theme's own component config aliases, and the design token
174
+ * each must resolve to under it. */
175
+ aliasedTo: Record<string, string>;
176
+ /** Where the theme's value must land in the rendered preview. */
177
+ observe: {
178
+ part: string;
179
+ css: string;
180
+ variable: string;
181
+ };
182
+ }
183
+ type InteractionAction = {
184
+ kind: 'press';
185
+ part: string;
186
+ key: string;
187
+ } | {
188
+ kind: 'click';
189
+ part: string;
190
+ } | {
191
+ kind: 'type';
192
+ part: string;
193
+ text: string;
194
+ } | {
195
+ kind: 'dragTo';
196
+ part: string;
197
+ along: string;
198
+ fraction: number;
199
+ };
200
+ type InteractionOutcome = {
201
+ kind: 'attribute';
202
+ part: string;
203
+ name: string;
204
+ value: string;
205
+ } | {
206
+ kind: 'valueMoves';
207
+ part: string;
208
+ direction: 'up' | 'down';
209
+ } | {
210
+ kind: 'valueBecomes';
211
+ part: string;
212
+ value: string;
213
+ } | {
214
+ kind: 'valueChanges';
215
+ part: string;
216
+ } | {
217
+ kind: 'valueHolds';
218
+ part: string;
219
+ }
220
+ /** Whether the part takes focus. The only outcome a button with no state
221
+ * attribute has: a disabled one refuses it and an enabled one takes it. */
222
+ | {
223
+ kind: 'focused';
224
+ part: string;
225
+ value: boolean;
226
+ };
227
+ interface InteractionCase extends View {
228
+ name: string;
229
+ action: InteractionAction;
230
+ expect: InteractionOutcome;
231
+ }
232
+ interface InteractionExpectation {
233
+ /** The part carrying the interactive role. */
234
+ part: string;
235
+ role: string;
236
+ cases: InteractionCase[];
237
+ }
238
+ interface SketchPartExpectation {
239
+ part: string;
240
+ /** The design token `--sketch-fill` must resolve to on this part. */
241
+ fill?: string;
242
+ /** The design token `--sketch-stroke` must resolve to on this part. */
243
+ stroke?: string;
244
+ }
245
+ interface SketchExpectation extends View {
246
+ /** Sketchstyle id the paint is asserted under. */
247
+ style: string;
248
+ parts: SketchPartExpectation[];
249
+ }
250
+ interface ComponentContract {
251
+ id: string;
252
+ origin: 'system' | 'custom';
253
+ parts: Record<string, PartDeclaration>;
254
+ /** Part key of the component's own root element in the preview. */
255
+ root: string;
256
+ /** The view every obligation opens with. */
257
+ view?: View;
258
+ states: StateExpectation[] | Inapplicable;
259
+ properties: PropertyExpectation[];
260
+ /**
261
+ * Aliases no paint map can pin, each with the reason. A token consumed
262
+ * inside `calc()` or handed to a gradient function never appears verbatim in
263
+ * a computed style, so the probe cannot read it back — that is the only
264
+ * class this belongs to. A token a sibling alias merely happens to carry
265
+ * the same rendered value through (a base padding token behind four
266
+ * per-side overrides, say) is not in this class: the per-side entries pin
267
+ * their own aliases, not the base one, and a paint map that drives the base
268
+ * token directly and observes the per-side CSS property can pin it too. Put
269
+ * that here and Wave 4's coverage JSON records the base token as covered
270
+ * when nothing asserts the link between it and what actually painted.
271
+ */
272
+ uncovered?: Record<string, string>;
273
+ persistence: PersistenceExpectation;
274
+ theme: ThemeExpectation;
275
+ interaction: InteractionExpectation | Inapplicable;
276
+ sketch: SketchExpectation | Inapplicable;
277
+ }
278
+ declare function requiresInteraction(role: string | null): boolean;
279
+ declare function partLocator(contract: ComponentContract, key: string): PartLocator;
280
+
281
+ declare const shippedContracts: ComponentContract[];
282
+ /** Names the module `selectedContracts` loads a custom component's
283
+ * `ComponentContract[]` from. The suite files are static Playwright entry
284
+ * points with no argument to receive one through, so an env var plus a
285
+ * dynamic import is the only route in. */
286
+ declare const CONTRACTS_MODULE_ENV = "LIVE_TOKENS_CONTRACTS_MODULE";
287
+ /** The shipped list plus whatever `LIVE_TOKENS_CONTRACTS_MODULE` names,
288
+ * unfiltered — what a "no contract for this id" error lists as declared. */
289
+ declare function allContracts(contracts?: ComponentContract[]): Promise<ComponentContract[]>;
290
+ /** The contracts a run covers, narrowed by `LIVE_TOKENS_COMPONENT`. */
291
+ declare function selectedContracts(contracts?: ComponentContract[]): Promise<ComponentContract[]>;
292
+
293
+ export { CONTRACTS_MODULE_ENV, type ComponentContract, type ContractRule, ContractViolation, type ControlStep, DATA_DIR_ENV, type Inapplicable, type InteractionAction, type InteractionCase, type InteractionExpectation, type InteractionOutcome, type IsolatedData, LiveTokensTestingConfig, PORT_ENV, type PaintMap, type PartDeclaration, type PartLocator, type PersistenceCase, type PersistenceExpectation, type PersistenceShape, type PlaywrightConfigOptions, type PropertyExpectation, type SetupStep, type SketchExpectation, type SketchPartExpectation, type StateExpectation, TEST_DATA_DIR_ENV, type ThemeExpectation, type View, allContracts, createPlaywrightConfig, isInapplicable, isolateDataDir, partLocator, requiresInteraction, resolvePort, selectedContracts, shippedContracts };
@@ -0,0 +1,222 @@
1
+ import {
2
+ CONTRACTS_MODULE_ENV,
3
+ ContractViolation,
4
+ allContracts,
5
+ isInapplicable,
6
+ partLocator,
7
+ requiresInteraction,
8
+ selectedContracts,
9
+ shippedContracts
10
+ } from "./chunk-LXR3MN6N.js";
11
+ import {
12
+ createVitestConfig
13
+ } from "./chunk-FAFOAWYL.js";
14
+ import {
15
+ COMPONENTS_PATH_ENV,
16
+ COMPONENT_ENV,
17
+ TESTING_CONFIG_FILE,
18
+ defineTestingConfig,
19
+ devServerCommand,
20
+ resolveTestingConfig
21
+ } from "./chunk-ZMSX6CXR.js";
22
+
23
+ // src/testing/playwright.ts
24
+ import path2 from "path";
25
+ import { fileURLToPath } from "url";
26
+ import {
27
+ defineConfig,
28
+ devices
29
+ } from "@playwright/test";
30
+
31
+ // src/testing/isolation.ts
32
+ import fs from "fs";
33
+ import os from "os";
34
+ import path from "path";
35
+ var TEST_DATA_DIR_ENV = "LIVE_TOKENS_TEST_DATA_DIR";
36
+ var DATA_DIR_ENV = "LIVE_TOKENS_DATA_DIR";
37
+ var SESSION_FILES = /* @__PURE__ */ new Set(["_working.json", "_active.json", "_production.json"]);
38
+ var removed = false;
39
+ function registerCleanup(dataDir) {
40
+ const remove = () => {
41
+ if (removed) return;
42
+ removed = true;
43
+ fs.rmSync(dataDir, { recursive: true, force: true });
44
+ };
45
+ process.once("exit", remove);
46
+ process.once("SIGINT", remove);
47
+ process.once("SIGTERM", remove);
48
+ }
49
+ function isolateDataDir(sourceDataDir) {
50
+ const existing = process.env[TEST_DATA_DIR_ENV];
51
+ if (existing) {
52
+ const dataDir2 = path.resolve(existing);
53
+ if (!fs.existsSync(dataDir2)) {
54
+ throw new Error(`${TEST_DATA_DIR_ENV} names ${dataDir2}, which does not exist`);
55
+ }
56
+ process.env[DATA_DIR_ENV] = dataDir2;
57
+ return { dataDir: dataDir2, created: false };
58
+ }
59
+ const source = path.resolve(sourceDataDir);
60
+ if (!fs.existsSync(source)) {
61
+ throw new Error(
62
+ `No data directory at ${source}. Set \`dataDir\` in live-tokens.testing.ts when the project keeps its live-tokens data somewhere else.`
63
+ );
64
+ }
65
+ const dataDir = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), "live-tokens-contract-")));
66
+ fs.cpSync(source, dataDir, { recursive: true });
67
+ for (const entry of fs.readdirSync(dataDir, { recursive: true })) {
68
+ if (SESSION_FILES.has(path.basename(entry))) {
69
+ fs.rmSync(path.join(dataDir, entry), { force: true });
70
+ }
71
+ }
72
+ process.env[TEST_DATA_DIR_ENV] = dataDir;
73
+ process.env[DATA_DIR_ENV] = dataDir;
74
+ registerCleanup(dataDir);
75
+ return { dataDir, created: true };
76
+ }
77
+
78
+ // src/testing/port.ts
79
+ import { execFileSync } from "child_process";
80
+ var PORT_ENV = "LIVE_TOKENS_TEST_PORT";
81
+ var PREFERRED_PORT = 4173;
82
+ var PROBE = `
83
+ const net = require('net');
84
+ const listen = (port) => new Promise((resolve, reject) => {
85
+ const server = net.createServer();
86
+ server.once('error', reject);
87
+ server.listen(port, '127.0.0.1', () => {
88
+ const { port: bound } = server.address();
89
+ server.close(() => resolve(bound));
90
+ });
91
+ });
92
+ // process.stdout.write, not console.log: the parent's FORCE_COLOR makes
93
+ // console.log wrap a number in ANSI escapes.
94
+ listen(Number(process.argv[1])).catch(() => listen(0)).then((port) => process.stdout.write(String(port)));
95
+ `;
96
+ function resolvePort(preferred) {
97
+ const cached = process.env[PORT_ENV];
98
+ if (cached) return Number(cached);
99
+ const port = preferred ?? Number(execFileSync(process.execPath, ["-e", PROBE, String(PREFERRED_PORT)], {
100
+ encoding: "utf-8"
101
+ }).trim());
102
+ if (!Number.isInteger(port) || port <= 0) {
103
+ throw new Error(`Could not settle on a dev-server port (read ${port})`);
104
+ }
105
+ process.env[PORT_ENV] = String(port);
106
+ return port;
107
+ }
108
+
109
+ // src/testing/playwright.ts
110
+ var HOST = "127.0.0.1";
111
+ var CONTRACT_TEST_DIR = path2.dirname(fileURLToPath(import.meta.url));
112
+ async function createPlaywrightConfig(options = {}) {
113
+ const settings = resolveTestingConfig(options, options.root);
114
+ const { dataDir } = isolateDataDir(settings.dataDir);
115
+ const port = resolvePort(settings.port);
116
+ const baseURL = `http://${HOST}:${port}`;
117
+ process.env[COMPONENTS_PATH_ENV] = settings.componentsPath;
118
+ if (settings.contractsModule) process.env[CONTRACTS_MODULE_ENV] = settings.contractsModule;
119
+ const requested = process.env[COMPONENT_ENV];
120
+ if (requested) {
121
+ const matches = await selectedContracts();
122
+ if (matches.length === 0) {
123
+ const all = await allContracts();
124
+ throw new Error(
125
+ `${COMPONENT_ENV}=${requested} names a component with no contract. Declared: ${all.map((contract) => contract.id).sort().join(", ")}`
126
+ );
127
+ }
128
+ }
129
+ return defineConfig({
130
+ testDir: options.testDir ?? CONTRACT_TEST_DIR,
131
+ // The component suites carry their serial and parallel intent per file:
132
+ // `component-editor.contract.ts` runs each component's save and reset
133
+ // cycles in order against one data tree. Turning this on would interleave
134
+ // them.
135
+ fullyParallel: false,
136
+ // One worker is the safe default: the specs share a dev server and a data
137
+ // directory. A run that can afford more passes a worker count on the
138
+ // command line.
139
+ workers: 1,
140
+ timeout: 3e4,
141
+ expect: { timeout: 5e3 },
142
+ // A shared-server suite times out under CI load in ways it never does
143
+ // locally, and without a retry budget one wobble aborts a tagged release.
144
+ retries: process.env.CI ? 2 : 0,
145
+ // Absolute and rooted at the consumer project, not the config file's own
146
+ // directory: `check-component --tests`'s generated config lives in a
147
+ // temporary directory that gets removed on completion, and a relative
148
+ // `outputDir` would put every trace and screenshot in there too.
149
+ outputDir: path2.join(settings.root, "test-results/playwright"),
150
+ reporter: process.env.CI ? [["line"], ["html", { open: "never" }]] : "list",
151
+ use: {
152
+ baseURL,
153
+ // Unset, both of these are unbounded: a locator that never resolves waits
154
+ // out the whole test timeout and reports nothing about where it stopped.
155
+ actionTimeout: 1e4,
156
+ navigationTimeout: 3e4,
157
+ trace: "on-first-retry",
158
+ screenshot: "only-on-failure",
159
+ // `retain-on-failure` still records every passing test and throws the
160
+ // file away, which costs ~28% CPU. Match the trace policy instead.
161
+ video: "on-first-retry"
162
+ },
163
+ projects: [
164
+ ...options.extraProjects ?? [],
165
+ {
166
+ name: "contract",
167
+ testDir: CONTRACT_TEST_DIR,
168
+ // `.ts` in this repo, `.js` once tsup compiles the shipped build into
169
+ // `src/testing-js`; matching both here needs no build-time swap.
170
+ testMatch: "**/component-*.contract.{ts,js}",
171
+ // `.tabs-preview` now caps its sticky band at 50vh, which is enough for
172
+ // image, panel, card and sidenavigation to pass alone at 1280x720. A
173
+ // full parallel run still fails panel's gradient radio there, so the
174
+ // band can cover a control at some scroll positions. Until that is
175
+ // fixed the suite runs taller. See docs/contract-test-defects.md.
176
+ use: { ...devices["Desktop Chrome"], viewport: { width: 1280, height: 900 } }
177
+ }
178
+ ],
179
+ webServer: {
180
+ command: devServerCommand(settings.devCommand, HOST, port),
181
+ // Otherwise defaults to the config file's own directory. A generated
182
+ // config that lives outside the consumer root (`check-component
183
+ // --tests`'s temporary config) would run `npm run dev` from wherever
184
+ // that happens to be instead.
185
+ cwd: settings.root,
186
+ url: baseURL,
187
+ // A server this run did not start carries none of these variables, so it
188
+ // would write the project's own data tree.
189
+ reuseExistingServer: false,
190
+ timeout: 12e4,
191
+ env: {
192
+ ...process.env,
193
+ [TEST_DATA_DIR_ENV]: dataDir,
194
+ [DATA_DIR_ENV]: dataDir
195
+ }
196
+ }
197
+ });
198
+ }
199
+ export {
200
+ COMPONENTS_PATH_ENV,
201
+ COMPONENT_ENV,
202
+ CONTRACTS_MODULE_ENV,
203
+ ContractViolation,
204
+ DATA_DIR_ENV,
205
+ PORT_ENV,
206
+ TESTING_CONFIG_FILE,
207
+ TEST_DATA_DIR_ENV,
208
+ allContracts,
209
+ createPlaywrightConfig,
210
+ createVitestConfig,
211
+ defineTestingConfig,
212
+ devServerCommand,
213
+ isInapplicable,
214
+ isolateDataDir,
215
+ partLocator,
216
+ requiresInteraction,
217
+ resolvePort,
218
+ resolveTestingConfig,
219
+ selectedContracts,
220
+ shippedContracts
221
+ };
222
+ //# sourceMappingURL=index.js.map