{"record":{"id":"7a2c2495ccb25eb7","repo":"CherryHQ/cherry-studio","slug":"theme-contract-renderer-typescript-source-file","errorCode":null,"errorMessage":"[theme-contract] renderer TypeScript source ${fileName} cannot use Tailwind adapter variable ${adapterVariable}; use runtime semantic variables or Tailwind utilities","messagePattern":"\\[theme-contract\\] renderer TypeScript source (.+?) cannot use Tailwind adapter variable (.+?); use runtime semantic variables or Tailwind utilities","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ui/scripts/validate-migration-contract.ts","lineNumber":204,"sourceCode":"  if (/@theme(?:\\s+inline)?\\s*\\{/.test(rendererTheme)) {\n    throw new Error('[theme-contract] renderer theme must use the shared generated Tailwind adapter')\n  }\n\n  for (const [fileName, source] of Object.entries(sources.rendererStyles)) {\n    const adapterVariable = stripComments(source).match(TAILWIND_ADAPTER_VARIABLE_PATTERN)?.[0]\n\n    if (adapterVariable) {\n      throw new Error(\n        `[theme-contract] renderer stylesheet ${fileName} cannot use Tailwind adapter variable ${adapterVariable}; use runtime semantic variables directly`\n      )\n    }\n  }\n\n  for (const [fileName, source] of Object.entries(sources.rendererTypeScriptSources)) {\n    const adapterVariable = source.includes('--color-') ? findTypeScriptAdapterVariable(source, fileName) : undefined\n\n    if (adapterVariable) {\n      throw new Error(\n        `[theme-contract] renderer TypeScript source ${fileName} cannot use Tailwind adapter variable ${adapterVariable}; use runtime semantic variables or Tailwind utilities`\n      )\n    }\n\n    const disallowedWrite = findTypeScriptDisallowedThemeWrite(source, fileName)\n    if (disallowedWrite) {\n      throw new Error(\n        `[theme-contract] renderer TypeScript source ${fileName} cannot write shared theme variable ${disallowedWrite}; use a registered --cs-theme-* input or an owner-local --app-* variable`\n      )\n    }\n  }\n}\n\nexport async function loadMigrationContractSources(\n  repositoryRoot = DEFAULT_REPOSITORY_ROOT\n): Promise<MigrationContractSources> {\n  const [migrationRegistry, legacyAliases, rendererTheme, rendererStyleEntries, rendererTypeScriptEntries] =\n    await Promise.all([","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/packages/ui/scripts/validate-migration-contract.ts#L186-L222","documentation":"Thrown by the theme migration contract validator when a renderer TypeScript source file (.ts/.tsx under src/renderer/) contains a string literal, template literal, or JSX text referencing a Tailwind adapter variable (--color-*). Unlike the CSS check (error 30), this scans TypeScript AST nodes (StringLiteral, NoSubstitutionTemplateLiteral, TemplateExpression spans, JsxText) for adapter variable patterns. The contract requires TS code to use runtime semantic variables or Tailwind utility classes.","triggerScenarios":"A .ts or .tsx file under src/renderer/ contains code like style={{ background: 'var(--color-primary-500)' }}, document.body.style.setProperty('--color-blue-500', value), or a template string referencing a --color-* token. The validator parses the TS AST and inspects all string-like nodes.","commonSituations":"An inline style in a React component referencing a raw --color-* token instead of a semantic variable. Dynamic style manipulation via setProperty or CSSStyleSheet API using adapter variables. String interpolation constructing a CSS value with --color-* tokens. Copy-pasting adapter variable names from generated CSS into component code.","solutions":["Replace the --color-* reference in the TS string with the semantic variable name (e.g., '--color-primary-500' → '--primary').","If applying the color via inline styles, use the semantic CSS variable: style={{ color: 'var(--primary)' }}.","If the value should be a Tailwind utility class, use the className instead (e.g., className=\"text-primary\").","Confirm the fix by running: npx tsx packages/ui/scripts/validate-migration-contract.ts."],"exampleFix":"// before — renderer .tsx file\n<div style={{ background: 'var(--color-blue-500)' }}>...</div>\n\n// after — use semantic variable or Tailwind class\n<div style={{ background: 'var(--primary)' }}>...</div>\n// or\n<div className=\"bg-primary\">...</div>","handlingStrategy":"validation","validationCode":"// Scan renderer .ts/.tsx files for --color-* adapter variable strings before committing\nimport { readFileSync } from 'node:fs'\n\nfunction checkNoAdapterVarsInTs(tsPath: string): void {\n  const source = readFileSync(tsPath, 'utf8')\n  if (source.includes('--color-')) {\n    const match = source.match(/--color-[a-z0-9-]*/)\n    if (match) {\n      throw new Error(`${tsPath} references adapter variable ${match[0]} in a string — use semantic variables or Tailwind classes`)\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use semantic CSS variables (var(--primary)) or Tailwind utility classes (text-primary) in TypeScript inline styles — never raw --color-* tokens.","When using setProperty or inline styles in components, reference the semantic variable names.","Run the migration contract validator in CI to catch adapter variable usage in TS files.","Keep a cheat-sheet of semantic variable names accessible during development."],"tags":["theme-contract","build-validation","tailwind","typescript","semantic-tokens"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}