(projectRoot: string)
| 460 | * Returns a partial theme object with the scales we care about. |
| 461 | */ |
| 462 | export function resolveV3Config(projectRoot: string): typeof DEFAULT_V4_THEME | null { |
| 463 | try { |
| 464 | // Dynamic require for v3 (CJS) |
| 465 | const resolveConfigPath = path.join( |
| 466 | projectRoot, |
| 467 | "node_modules", |
| 468 | "tailwindcss", |
| 469 | "resolveConfig" |
| 470 | ); |
| 471 | // eslint-disable-next-line @typescript-eslint/no-var-requires |
| 472 | const resolveConfig = require(resolveConfigPath) as (config: unknown) => { |
| 473 | theme: Record<string, unknown>; |
| 474 | }; |
| 475 | |
| 476 | // Try to load the user's tailwind config |
| 477 | let userConfig: unknown = {}; |
| 478 | const configCandidates = [ |
| 479 | "tailwind.config.js", |
| 480 | "tailwind.config.ts", |
| 481 | "tailwind.config.cjs", |
| 482 | "tailwind.config.mjs", |
| 483 | ]; |
| 484 | for (const candidate of configCandidates) { |
| 485 | const configPath = path.join(projectRoot, candidate); |
| 486 | if (fs.existsSync(configPath)) { |
| 487 | try { |
| 488 | userConfig = require(configPath) as unknown; |
| 489 | } catch { |
| 490 | // ignore — use empty config |
| 491 | } |
| 492 | break; |
| 493 | } |
| 494 | } |
| 495 | |
| 496 | const resolved = resolveConfig(userConfig); |
| 497 | const theme = resolved.theme as Record<string, Record<string, unknown>>; |
| 498 | |
| 499 | const flattenScale = (scale: Record<string, unknown> | undefined): Record<string, string> => { |
| 500 | const result: Record<string, string> = {}; |
| 501 | if (!scale) return result; |
| 502 | for (const [key, value] of Object.entries(scale)) { |
| 503 | if (typeof value === "string") { |
| 504 | result[key] = value; |
| 505 | } |
| 506 | } |
| 507 | return result; |
| 508 | }; |
| 509 | |
| 510 | // Flatten colors (may be nested like { slate: { 500: "#..." } }) |
| 511 | const flattenColors = (colors: Record<string, unknown> | undefined): Record<string, string> => { |
| 512 | const result: Record<string, string> = {}; |
| 513 | if (!colors) return result; |
| 514 | for (const [colorName, colorValue] of Object.entries(colors)) { |
| 515 | if (typeof colorValue === "string") { |
| 516 | result[colorName] = colorValue; |
| 517 | } else if (colorValue && typeof colorValue === "object") { |
| 518 | for (const [shade, hex] of Object.entries(colorValue as Record<string, unknown>)) { |
| 519 | if (typeof hex === "string") { |
no test coverage detected