uilint 0.2.32 → 0.2.34

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.
@@ -89,6 +89,10 @@ async function confirm2(options) {
89
89
  });
90
90
  return handleCancel(result);
91
91
  }
92
+ async function text2(options) {
93
+ const result = await p.text(options);
94
+ return handleCancel(result);
95
+ }
92
96
  async function multiselect2(options) {
93
97
  const result = await p.multiselect({
94
98
  message: options.message,
@@ -1209,6 +1213,7 @@ export {
1209
1213
  logError,
1210
1214
  select2 as select,
1211
1215
  confirm2 as confirm,
1216
+ text2 as text,
1212
1217
  multiselect2 as multiselect,
1213
1218
  detectNextAppRouter,
1214
1219
  findNextAppRouterProjects,
@@ -1225,4 +1230,4 @@ export {
1225
1230
  prepareCoverage,
1226
1231
  needsCoveragePreparation
1227
1232
  };
1228
- //# sourceMappingURL=chunk-W6X3RNOE.js.map
1233
+ //# sourceMappingURL=chunk-YS2QQOCB.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/prompts.ts","../src/utils/coverage-detect.ts","../src/utils/next-detect.ts","../src/utils/eslint-config-inject.ts","../src/utils/coverage-prepare.ts"],"sourcesContent":["/**\n * Shared clack/prompts utilities for UILint CLI\n * Provides branded intro/outro, spinners, and common UI patterns\n */\n\nimport * as p from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { readFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { fileURLToPath } from \"url\";\n\n/**\n * Get the CLI version from package.json\n */\nfunction getCLIVersion(): string {\n try {\n const __dirname = dirname(fileURLToPath(import.meta.url));\n const pkgPath = join(__dirname, \"..\", \"..\", \"package.json\");\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n version?: string;\n };\n return pkg.version || \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n\n/**\n * Branded UILint intro with logo and version\n */\nexport function intro(title?: string): void {\n const version = getCLIVersion();\n const header = pc.bold(pc.cyan(\"◆ UILint\")) + pc.dim(` v${version}`);\n \n console.log();\n p.intro(title ? `${header} ${pc.dim(\"·\")} ${title}` : header);\n}\n\n/**\n * Styled outro with next steps\n */\nexport function outro(message: string): void {\n p.outro(pc.green(message));\n}\n\n/**\n * Cancel message when user exits\n */\nexport function cancel(message = \"Operation cancelled.\"): void {\n p.cancel(pc.yellow(message));\n process.exit(0);\n}\n\n/**\n * Check if user cancelled a prompt\n */\nexport function isCancel(value: unknown): value is symbol {\n return p.isCancel(value);\n}\n\n/**\n * Handle cancel check - exits if cancelled\n */\nexport function handleCancel<T>(value: T | symbol): T {\n if (p.isCancel(value)) {\n cancel();\n process.exit(0);\n }\n return value as T;\n}\n\n/**\n * Spinner wrapper with automatic error handling\n */\nexport async function withSpinner<T>(\n message: string,\n fn: (() => Promise<T>) | ((spinner: ReturnType<typeof p.spinner>) => Promise<T>)\n): Promise<T> {\n const s = p.spinner();\n s.start(message);\n try {\n const result =\n fn.length >= 1\n ? await (fn as (spinner: ReturnType<typeof p.spinner>) => Promise<T>)(s)\n : await (fn as () => Promise<T>)();\n s.stop(pc.green(\"✓ \") + message);\n return result;\n } catch (error) {\n s.stop(pc.red(\"✗ \") + message);\n throw error;\n }\n}\n\n/**\n * Spinner that can be updated\n */\nexport function createSpinner() {\n return p.spinner();\n}\n\n/**\n * Display a note box\n */\nexport function note(message: string, title?: string): void {\n p.note(message, title);\n}\n\n/**\n * Display a log message\n */\nexport function log(message: string): void {\n p.log.message(message);\n}\n\n/**\n * Display an info message\n */\nexport function logInfo(message: string): void {\n p.log.info(message);\n}\n\n/**\n * Display a success message\n */\nexport function logSuccess(message: string): void {\n p.log.success(message);\n}\n\n/**\n * Display a warning message\n */\nexport function logWarning(message: string): void {\n p.log.warn(message);\n}\n\n/**\n * Display an error message\n */\nexport function logError(message: string): void {\n p.log.error(message);\n}\n\n/**\n * Display a step message\n */\nexport function logStep(message: string): void {\n p.log.step(message);\n}\n\n/**\n * Select prompt wrapper\n */\nexport async function select<T extends string>(options: {\n message: string;\n options: Array<{ value: T; label: string; hint?: string }>;\n initialValue?: T;\n}): Promise<T> {\n const result = await p.select({\n message: options.message,\n options: options.options as { value: T; label: string; hint?: string }[],\n initialValue: options.initialValue,\n } as Parameters<typeof p.select>[0]);\n return handleCancel(result) as T;\n}\n\n/**\n * Confirm prompt wrapper\n */\nexport async function confirm(options: {\n message: string;\n initialValue?: boolean;\n}): Promise<boolean> {\n const result = await p.confirm({\n message: options.message,\n initialValue: options.initialValue ?? true,\n });\n return handleCancel(result);\n}\n\n/**\n * Text input prompt wrapper\n */\nexport async function text(options: {\n message: string;\n placeholder?: string;\n defaultValue?: string;\n validate?: (value: string) => string | Error | undefined;\n}): Promise<string> {\n const result = await p.text(options);\n return handleCancel(result);\n}\n\n/**\n * Multiselect prompt wrapper\n */\nexport async function multiselect<T extends string>(options: {\n message: string;\n options: Array<{ value: T; label: string; hint?: string }>;\n required?: boolean;\n initialValues?: T[];\n}): Promise<T[]> {\n const result = await p.multiselect({\n message: options.message,\n options: options.options as { value: T; label: string; hint?: string }[],\n required: options.required,\n initialValues: options.initialValues,\n } as Parameters<typeof p.multiselect>[0]);\n return handleCancel(result) as T[];\n}\n\n/**\n * Group of tasks displayed together\n */\nexport async function group<T extends Record<string, unknown>>(\n prompts: p.PromptGroup<T>,\n options?: p.PromptGroupOptions<T>\n): Promise<T> {\n const result = await p.group(prompts, options);\n return result;\n}\n\n// Re-export picocolors for consistent styling\nexport { pc };\n","/**\n * Coverage detection utilities for vitest projects.\n *\n * Detects vitest installation, configuration, and coverage data.\n */\n\nimport { existsSync, readFileSync, statSync } from \"fs\";\nimport { join } from \"path\";\n\nexport interface CoverageSetupInfo {\n /** Whether vitest is in dependencies */\n hasVitest: boolean;\n /** Whether vitest config exists */\n hasVitestConfig: boolean;\n /** Path to vitest config if found */\n vitestConfigPath: string | null;\n /** Whether coverage is configured in vitest */\n hasCoverageConfig: boolean;\n /** Coverage provider (v8 or istanbul) */\n coverageProvider: \"v8\" | \"istanbul\" | null;\n /** Whether coverage data file exists */\n hasCoverageData: boolean;\n /** Path to coverage data */\n coverageDataPath: string | null;\n\n // Preparation flags\n /** Whether @vitest/coverage-v8 (or coverage-istanbul) package is missing */\n needsCoveragePackage: boolean;\n /** Whether vitest.config needs coverage block added */\n needsCoverageConfig: boolean;\n /** Age of coverage data in milliseconds (null if no data) */\n coverageDataAge: number | null;\n}\n\nconst VITEST_CONFIG_FILES = [\n \"vitest.config.ts\",\n \"vitest.config.js\",\n \"vitest.config.mts\",\n \"vitest.config.mjs\",\n];\n\ninterface PackageDepsInfo {\n hasVitest: boolean;\n hasCoveragePackage: boolean;\n}\n\n/**\n * Check if vitest and coverage packages are in package.json\n */\nfunction checkPackageDeps(projectPath: string): PackageDepsInfo {\n try {\n const pkgPath = join(projectPath, \"package.json\");\n if (!existsSync(pkgPath)) return { hasVitest: false, hasCoveragePackage: false };\n\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n\n const deps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };\n const hasVitest = \"vitest\" in deps;\n const hasCoveragePackage =\n \"@vitest/coverage-v8\" in deps || \"@vitest/coverage-istanbul\" in deps;\n\n return { hasVitest, hasCoveragePackage };\n } catch {\n return { hasVitest: false, hasCoveragePackage: false };\n }\n}\n\n/**\n * Find the vitest config file in the project\n */\nfunction findVitestConfig(projectPath: string): string | null {\n for (const configFile of VITEST_CONFIG_FILES) {\n const configPath = join(projectPath, configFile);\n if (existsSync(configPath)) {\n return configPath;\n }\n }\n return null;\n}\n\n/**\n * Parse vitest config to extract coverage settings\n */\nfunction parseCoverageConfig(configPath: string): {\n hasCoverageConfig: boolean;\n coverageProvider: \"v8\" | \"istanbul\" | null;\n} {\n try {\n const content = readFileSync(configPath, \"utf-8\");\n\n // Check if coverage block exists using regex\n const hasCoverageConfig = /coverage\\s*:\\s*\\{/.test(content);\n\n if (!hasCoverageConfig) {\n return { hasCoverageConfig: false, coverageProvider: null };\n }\n\n // Extract provider value using regex\n // Match patterns like: provider: \"v8\", provider: 'v8', provider: \"istanbul\", etc.\n const providerMatch = content.match(/provider\\s*:\\s*[\"']?(v8|istanbul)[\"']?/);\n const coverageProvider = providerMatch\n ? (providerMatch[1] as \"v8\" | \"istanbul\")\n : null;\n\n return { hasCoverageConfig, coverageProvider };\n } catch {\n return { hasCoverageConfig: false, coverageProvider: null };\n }\n}\n\n/**\n * Check if coverage data file exists and get its age\n */\nfunction findCoverageData(projectPath: string): {\n path: string | null;\n age: number | null;\n} {\n const coverageDataPath = join(projectPath, \"coverage\", \"coverage-final.json\");\n if (existsSync(coverageDataPath)) {\n try {\n const stats = statSync(coverageDataPath);\n const age = Date.now() - stats.mtimeMs;\n return { path: coverageDataPath, age };\n } catch {\n return { path: coverageDataPath, age: null };\n }\n }\n return { path: null, age: null };\n}\n\n/**\n * Detect coverage setup in a project\n */\nexport function detectCoverageSetup(projectPath: string): CoverageSetupInfo {\n const { hasVitest, hasCoveragePackage } = checkPackageDeps(projectPath);\n const vitestConfigPath = findVitestConfig(projectPath);\n const hasVitestConfig = vitestConfigPath !== null;\n\n let hasCoverageConfig = false;\n let coverageProvider: \"v8\" | \"istanbul\" | null = null;\n\n if (vitestConfigPath) {\n const coverageInfo = parseCoverageConfig(vitestConfigPath);\n hasCoverageConfig = coverageInfo.hasCoverageConfig;\n coverageProvider = coverageInfo.coverageProvider;\n }\n\n const coverageData = findCoverageData(projectPath);\n const hasCoverageData = coverageData.path !== null;\n\n // Compute preparation flags\n const needsCoveragePackage = hasVitest && !hasCoveragePackage;\n const needsCoverageConfig = hasVitest && hasVitestConfig && !hasCoverageConfig;\n\n return {\n hasVitest,\n hasVitestConfig,\n vitestConfigPath,\n hasCoverageConfig,\n coverageProvider,\n hasCoverageData,\n coverageDataPath: coverageData.path,\n needsCoveragePackage,\n needsCoverageConfig,\n coverageDataAge: coverageData.age,\n };\n}\n","import { existsSync, readdirSync } from \"fs\";\nimport { join } from \"path\";\n\nexport interface NextAppRouterDetection {\n /**\n * Relative path to the Next App Router root dir (either \"app\" or \"src/app\").\n */\n appRoot: string;\n /**\n * Absolute path to the App Router root dir.\n */\n appRootAbs: string;\n /**\n * Candidate entry files (relative paths) that are good injection targets.\n */\n candidates: string[];\n}\n\nfunction fileExists(projectPath: string, relPath: string): boolean {\n return existsSync(join(projectPath, relPath));\n}\n\nexport function detectNextAppRouter(\n projectPath: string\n): NextAppRouterDetection | null {\n const roots = [\"app\", join(\"src\", \"app\")];\n const candidates: string[] = [];\n\n let chosenRoot: string | null = null;\n for (const root of roots) {\n if (existsSync(join(projectPath, root))) {\n chosenRoot = root;\n break;\n }\n }\n\n if (!chosenRoot) return null;\n\n // Prioritize layout files (Next App Router canonical integration point).\n const entryCandidates = [\n join(chosenRoot, \"layout.tsx\"),\n join(chosenRoot, \"layout.jsx\"),\n join(chosenRoot, \"layout.ts\"),\n join(chosenRoot, \"layout.js\"),\n // Fallbacks (less ideal, but can work):\n join(chosenRoot, \"page.tsx\"),\n join(chosenRoot, \"page.jsx\"),\n ];\n\n for (const rel of entryCandidates) {\n if (fileExists(projectPath, rel)) candidates.push(rel);\n }\n\n // If nothing exists, still return detection so routes can be installed.\n return {\n appRoot: chosenRoot,\n appRootAbs: join(projectPath, chosenRoot),\n candidates,\n };\n}\n\nexport interface NextAppRouterProjectMatch {\n /**\n * Absolute path to the Next project root (dir containing app/ or src/app/).\n */\n projectPath: string;\n detection: NextAppRouterDetection;\n}\n\nconst DEFAULT_IGNORE_DIRS = new Set([\n \"node_modules\",\n \".git\",\n \".next\",\n \"dist\",\n \"build\",\n \"out\",\n \".turbo\",\n \".vercel\",\n \".cursor\",\n \"coverage\",\n \".uilint\",\n]);\n\n/**\n * Best-effort monorepo discovery for Next.js App Router apps.\n *\n * Walks down from `rootDir` looking for directories that contain `app/` or\n * `src/app/`. Skips common large/irrelevant dirs.\n */\nexport function findNextAppRouterProjects(\n rootDir: string,\n options?: { maxDepth?: number; ignoreDirs?: Set<string> }\n): NextAppRouterProjectMatch[] {\n const maxDepth = options?.maxDepth ?? 4;\n const ignoreDirs = options?.ignoreDirs ?? DEFAULT_IGNORE_DIRS;\n const results: NextAppRouterProjectMatch[] = [];\n const visited = new Set<string>();\n\n function walk(dir: string, depth: number) {\n if (depth > maxDepth) return;\n if (visited.has(dir)) return;\n visited.add(dir);\n\n const detection = detectNextAppRouter(dir);\n if (detection) {\n results.push({ projectPath: dir, detection });\n // Don't descend further once we found a project root (avoid nested hits).\n return;\n }\n\n let entries: Array<{ name: string; isDirectory: boolean }> = [];\n try {\n entries = readdirSync(dir, { withFileTypes: true }).map((d) => ({\n name: d.name,\n isDirectory: d.isDirectory(),\n }));\n } catch {\n return;\n }\n\n for (const ent of entries) {\n if (!ent.isDirectory) continue;\n if (ignoreDirs.has(ent.name)) continue;\n // Skip hidden dirs by default (except `src` which matters)\n if (ent.name.startsWith(\".\") && ent.name !== \".\") continue;\n walk(join(dir, ent.name), depth + 1);\n }\n }\n\n walk(rootDir, 0);\n return results;\n}\n","/**\n * Inject uilint-eslint rules into ESLint config\n *\n * Modifies eslint.config.{ts,mjs,js,cjs} to add uilint import and selected rules\n */\n\nimport { existsSync, readFileSync, writeFileSync } from \"fs\";\nimport { join, relative, dirname } from \"path\";\nimport type { RuleMetadata } from \"uilint-eslint\";\nimport { parseExpression, parseModule, generateCode } from \"magicast\";\nimport { findWorkspaceRoot } from \"uilint-core/node\";\n\nexport interface InstallEslintPluginOptions {\n projectPath: string;\n selectedRules: RuleMetadata[];\n force?: boolean;\n confirmAddMissingRules?: (\n relPath: string,\n missingRules: RuleMetadata[]\n ) => Promise<boolean>;\n}\n\nconst CONFIG_EXTENSIONS = [\".ts\", \".mjs\", \".js\", \".cjs\"];\n\n/**\n * Find the eslint.config file in a project\n */\nexport function findEslintConfigFile(projectPath: string): string | null {\n for (const ext of CONFIG_EXTENSIONS) {\n const configPath = join(projectPath, `eslint.config${ext}`);\n if (existsSync(configPath)) {\n return configPath;\n }\n }\n return null;\n}\n\n/**\n * Get the relative config filename for display\n */\nexport function getEslintConfigFilename(configPath: string): string {\n const parts = configPath.split(\"/\");\n return parts[parts.length - 1] || \"eslint.config.mjs\";\n}\n\n/**\n * Check if the source already has uilint rules configured\n */\nfunction hasUilintRules(source: string): boolean {\n return source.includes('\"uilint/') || source.includes(\"'uilint/\");\n}\n\n/**\n * Check if the source already has uilint imported\n */\nfunction hasUilintImport(source: string): boolean {\n return (\n source.includes('from \"uilint-eslint\"') ||\n source.includes(\"from 'uilint-eslint'\") ||\n source.includes('require(\"uilint-eslint\")') ||\n source.includes(\"require('uilint-eslint')\")\n );\n}\n\ntype UilintEslintConfigInfo = {\n /** Set of configured `uilint/*` rule IDs (without the `uilint/` prefix). */\n configuredRuleIds: Set<string>;\n /** Whether config appears to configure uilint rules. */\n configured: boolean;\n};\n\nfunction walkAst(node: any, visit: (n: any) => void): void {\n if (!node || typeof node !== \"object\") return;\n visit(node);\n for (const key of Object.keys(node)) {\n const v = (node as any)[key];\n if (!v) continue;\n if (Array.isArray(v)) {\n for (const item of v) walkAst(item, visit);\n } else if (typeof v === \"object\" && v.type) {\n walkAst(v, visit);\n }\n }\n}\n\nfunction isIdentifier(node: any, name?: string): boolean {\n return (\n !!node &&\n node.type === \"Identifier\" &&\n (name ? node.name === name : typeof node.name === \"string\")\n );\n}\n\nfunction isStringLiteral(node: any): node is { type: string; value: string } {\n return (\n !!node &&\n (node.type === \"StringLiteral\" || node.type === \"Literal\") &&\n typeof node.value === \"string\"\n );\n}\n\nfunction getObjectPropertyValue(obj: any, keyName: string): any | null {\n if (!obj || obj.type !== \"ObjectExpression\") return null;\n for (const prop of obj.properties ?? []) {\n if (!prop) continue;\n if (prop.type === \"ObjectProperty\" || prop.type === \"Property\") {\n const key = prop.key;\n const keyMatch =\n (key?.type === \"Identifier\" && key.name === keyName) ||\n (isStringLiteral(key) && key.value === keyName);\n if (keyMatch) return prop.value;\n }\n }\n return null;\n}\n\nfunction hasSpreadProperties(obj: any): boolean {\n if (!obj || obj.type !== \"ObjectExpression\") return false;\n return (obj.properties ?? []).some(\n (p: any) => p && (p.type === \"SpreadElement\" || p.type === \"SpreadProperty\")\n );\n}\n\nconst IGNORED_AST_KEYS = new Set([\n \"loc\",\n \"start\",\n \"end\",\n \"extra\",\n \"leadingComments\",\n \"trailingComments\",\n \"innerComments\",\n]);\n\nfunction normalizeAstForCompare(node: any): any {\n if (node === null) return null;\n if (node === undefined) return undefined;\n if (typeof node !== \"object\") return node;\n if (Array.isArray(node)) return node.map(normalizeAstForCompare);\n\n const out: Record<string, any> = {};\n const keys = Object.keys(node)\n .filter((k) => !IGNORED_AST_KEYS.has(k))\n .sort();\n for (const k of keys) {\n // Avoid proxy-ish or non-serializable fields if present.\n if (k.startsWith(\"$\")) continue;\n out[k] = normalizeAstForCompare(node[k]);\n }\n return out;\n}\n\nfunction astEquivalent(a: any, b: any): boolean {\n try {\n return (\n JSON.stringify(normalizeAstForCompare(a)) ===\n JSON.stringify(normalizeAstForCompare(b))\n );\n } catch {\n return false;\n }\n}\n\nfunction collectUilintRuleIdsFromRulesObject(rulesObj: any): Set<string> {\n const ids = new Set<string>();\n if (!rulesObj || rulesObj.type !== \"ObjectExpression\") return ids;\n for (const prop of rulesObj.properties ?? []) {\n if (!prop) continue;\n if (prop.type !== \"ObjectProperty\" && prop.type !== \"Property\") continue;\n const key = prop.key;\n if (!isStringLiteral(key)) continue;\n const val = key.value;\n if (typeof val !== \"string\") continue;\n if (val.startsWith(\"uilint/\")) {\n ids.add(val.slice(\"uilint/\".length));\n }\n }\n return ids;\n}\n\nfunction findExportedConfigArrayExpression(mod: any): {\n kind: \"esm\" | \"cjs\";\n arrayExpr: any;\n program: any;\n} | null {\n function unwrapExpression(expr: any): any {\n let e = expr;\n // Best-effort unwrap for TS/parenthesized wrappers. (These can appear if the\n // config is authored in TS/JS with type assertions or parentheses.)\n while (e) {\n if (e.type === \"TSAsExpression\" || e.type === \"TSNonNullExpression\") {\n e = e.expression;\n continue;\n }\n if (e.type === \"TSSatisfiesExpression\") {\n e = e.expression;\n continue;\n }\n if (e.type === \"ParenthesizedExpression\") {\n e = e.expression;\n continue;\n }\n break;\n }\n return e;\n }\n\n function resolveTopLevelIdentifierToArrayExpr(\n program: any,\n name: string\n ): any | null {\n if (!program || program.type !== \"Program\") return null;\n for (const stmt of program.body ?? []) {\n if (stmt?.type !== \"VariableDeclaration\") continue;\n for (const decl of stmt.declarations ?? []) {\n const id = decl?.id;\n if (!isIdentifier(id, name)) continue;\n const init = unwrapExpression(decl?.init);\n if (!init) return null;\n if (init.type === \"ArrayExpression\") return init;\n if (\n init.type === \"CallExpression\" &&\n isIdentifier(init.callee, \"defineConfig\") &&\n unwrapExpression(init.arguments?.[0])?.type === \"ArrayExpression\"\n ) {\n return unwrapExpression(init.arguments?.[0]);\n }\n return null;\n }\n }\n return null;\n }\n\n // Prefer reading directly from the program AST so we can handle:\n // - export default [ ... ]\n // - export default defineConfig([ ... ])\n // - export default eslintConfig; (where eslintConfig is a top-level array)\n const program = mod?.$ast;\n if (program && program.type === \"Program\") {\n for (const stmt of program.body ?? []) {\n if (!stmt || stmt.type !== \"ExportDefaultDeclaration\") continue;\n const decl = unwrapExpression(stmt.declaration);\n if (!decl) break;\n\n if (decl.type === \"ArrayExpression\") {\n return { kind: \"esm\", arrayExpr: decl, program };\n }\n if (\n decl.type === \"CallExpression\" &&\n isIdentifier(decl.callee, \"defineConfig\") &&\n unwrapExpression(decl.arguments?.[0])?.type === \"ArrayExpression\"\n ) {\n return {\n kind: \"esm\",\n arrayExpr: unwrapExpression(decl.arguments?.[0]),\n program,\n };\n }\n if (decl.type === \"Identifier\" && typeof decl.name === \"string\") {\n const resolved = resolveTopLevelIdentifierToArrayExpr(\n program,\n decl.name\n );\n if (resolved) return { kind: \"esm\", arrayExpr: resolved, program };\n }\n break;\n }\n }\n\n // CommonJS: module.exports = [ ... ] OR module.exports = defineConfig([ ... ])\n if (!program || program.type !== \"Program\") return null;\n\n for (const stmt of program.body ?? []) {\n if (!stmt || stmt.type !== \"ExpressionStatement\") continue;\n const expr = stmt.expression;\n if (!expr || expr.type !== \"AssignmentExpression\") continue;\n const left = expr.left;\n const right = expr.right;\n const isModuleExports =\n left?.type === \"MemberExpression\" &&\n isIdentifier(left.object, \"module\") &&\n isIdentifier(left.property, \"exports\");\n if (!isModuleExports) continue;\n\n if (right?.type === \"ArrayExpression\") {\n return { kind: \"cjs\", arrayExpr: right, program };\n }\n if (\n right?.type === \"CallExpression\" &&\n isIdentifier(right.callee, \"defineConfig\") &&\n right.arguments?.[0]?.type === \"ArrayExpression\"\n ) {\n return { kind: \"cjs\", arrayExpr: right.arguments[0], program };\n }\n if (right?.type === \"Identifier\" && typeof right.name === \"string\") {\n const resolved = resolveTopLevelIdentifierToArrayExpr(\n program,\n right.name\n );\n if (resolved) return { kind: \"cjs\", arrayExpr: resolved, program };\n }\n }\n\n return null;\n}\n\nfunction collectConfiguredUilintRuleIdsFromConfigArray(\n arrayExpr: any\n): Set<string> {\n const ids = new Set<string>();\n if (!arrayExpr || arrayExpr.type !== \"ArrayExpression\") return ids;\n for (const el of arrayExpr.elements ?? []) {\n if (!el || el.type !== \"ObjectExpression\") continue;\n const rules = getObjectPropertyValue(el, \"rules\");\n for (const id of collectUilintRuleIdsFromRulesObject(rules)) ids.add(id);\n }\n return ids;\n}\n\nfunction findExistingUilintRulesObject(arrayExpr: any): {\n configObj: any | null;\n rulesObj: any | null;\n safeToMutate: boolean;\n} {\n if (!arrayExpr || arrayExpr.type !== \"ArrayExpression\") {\n return { configObj: null, rulesObj: null, safeToMutate: false };\n }\n\n for (const el of arrayExpr.elements ?? []) {\n if (!el || el.type !== \"ObjectExpression\") continue;\n\n const plugins = getObjectPropertyValue(el, \"plugins\");\n const rules = getObjectPropertyValue(el, \"rules\");\n\n const hasUilintPlugin =\n plugins?.type === \"ObjectExpression\" &&\n getObjectPropertyValue(plugins, \"uilint\") !== null;\n\n const uilintIds = collectUilintRuleIdsFromRulesObject(rules);\n const hasUilintRules = uilintIds.size > 0;\n\n if (!hasUilintPlugin && !hasUilintRules) continue;\n\n const safe =\n rules?.type === \"ObjectExpression\" && !hasSpreadProperties(rules);\n return { configObj: el, rulesObj: rules, safeToMutate: safe };\n }\n\n return { configObj: null, rulesObj: null, safeToMutate: false };\n}\n\nfunction collectTopLevelBindings(program: any): Set<string> {\n const names = new Set<string>();\n if (!program || program.type !== \"Program\") return names;\n\n for (const stmt of program.body ?? []) {\n if (stmt?.type === \"ImportDeclaration\") {\n for (const spec of stmt.specifiers ?? []) {\n const local = spec?.local;\n if (local?.type === \"Identifier\" && typeof local.name === \"string\") {\n names.add(local.name);\n }\n }\n continue;\n }\n if (stmt?.type === \"VariableDeclaration\") {\n for (const decl of stmt.declarations ?? []) {\n const id = decl?.id;\n if (id?.type === \"Identifier\" && typeof id.name === \"string\") {\n names.add(id.name);\n }\n }\n } else if (stmt?.type === \"FunctionDeclaration\") {\n if (stmt.id?.type === \"Identifier\" && typeof stmt.id.name === \"string\") {\n names.add(stmt.id.name);\n }\n }\n }\n return names;\n}\n\nfunction chooseUniqueIdentifier(base: string, used: Set<string>): string {\n if (!used.has(base)) return base;\n let i = 2;\n while (used.has(`${base}${i}`)) i++;\n return `${base}${i}`;\n}\n\nfunction findExistingDefaultImportLocalName(\n program: any,\n from: string\n): string | null {\n if (!program || program.type !== \"Program\") return null;\n for (const stmt of program.body ?? []) {\n if (stmt?.type !== \"ImportDeclaration\") continue;\n const src = stmt.source?.value;\n if (typeof src !== \"string\" || src !== from) continue;\n for (const spec of stmt.specifiers ?? []) {\n if (spec?.type === \"ImportDefaultSpecifier\") {\n const local = spec.local;\n if (local?.type === \"Identifier\" && typeof local.name === \"string\") {\n return local.name;\n }\n }\n }\n }\n return null;\n}\n\n/**\n * Add imports for local rules from .uilint/rules/\n */\nfunction addLocalRuleImportsAst(\n mod: any,\n selectedRules: RuleMetadata[],\n configPath: string,\n rulesRoot: string,\n fileExtension: string = \".js\",\n isTypeScriptProject: boolean = false\n): { importNames: Map<string, string>; changed: boolean } {\n const importNames = new Map<string, string>();\n let changed = false;\n\n // Calculate relative path from config file to .uilint/rules/\n const configDir = dirname(configPath);\n const rulesDir = join(rulesRoot, \".uilint\", \"rules\");\n const relativeRulesPath = relative(configDir, rulesDir).replace(/\\\\/g, \"/\");\n\n // Ensure it starts with ./ or ../ (note: `.foo` is NOT a valid relative import)\n const normalizedRulesPath =\n relativeRulesPath.startsWith(\"./\") || relativeRulesPath.startsWith(\"../\")\n ? relativeRulesPath\n : `./${relativeRulesPath}`;\n\n const used = collectTopLevelBindings(mod.$ast);\n\n for (const rule of selectedRules) {\n // Directory-based rules use /index for TypeScript projects only\n // For JavaScript projects, all rules are bundled to single .js files\n const rulePath = (rule.isDirectoryBased && isTypeScriptProject)\n ? `${normalizedRulesPath}/${rule.id}/index${fileExtension}`\n : `${normalizedRulesPath}/${rule.id}${fileExtension}`;\n\n // If the import already exists (possibly with a different local name),\n // reuse it. Magicast can't always rename existing imports.\n const existingLocal = findExistingDefaultImportLocalName(mod.$ast, rulePath);\n if (existingLocal) {\n importNames.set(rule.id, existingLocal);\n used.add(existingLocal);\n continue;\n }\n\n // Generate a safe import name (e.g., noArbitraryTailwindRule)\n const importName = chooseUniqueIdentifier(\n `${rule.id\n .replace(/-([a-z])/g, (_: string, c: string) => c.toUpperCase())\n .replace(/^./, (c: string) => c.toUpperCase())}Rule`,\n used\n );\n importNames.set(rule.id, importName);\n used.add(importName);\n\n // Add import statement\n mod.imports.$add({\n imported: \"default\",\n local: importName,\n from: rulePath,\n });\n changed = true;\n }\n\n return { importNames, changed };\n}\n\n/**\n * Add require statements for local rules (CommonJS)\n */\nfunction addLocalRuleRequiresAst(\n program: any,\n selectedRules: RuleMetadata[],\n configPath: string,\n rulesRoot: string,\n fileExtension: string = \".js\",\n isTypeScriptProject: boolean = false\n): { importNames: Map<string, string>; changed: boolean } {\n const importNames = new Map<string, string>();\n let changed = false;\n\n if (!program || program.type !== \"Program\") {\n return { importNames, changed };\n }\n\n // Calculate relative path from config file to .uilint/rules/\n const configDir = dirname(configPath);\n const rulesDir = join(rulesRoot, \".uilint\", \"rules\");\n const relativeRulesPath = relative(configDir, rulesDir).replace(/\\\\/g, \"/\");\n\n // Ensure it starts with ./ or ../ (note: `.foo` is NOT a valid relative require)\n const normalizedRulesPath =\n relativeRulesPath.startsWith(\"./\") || relativeRulesPath.startsWith(\"../\")\n ? relativeRulesPath\n : `./${relativeRulesPath}`;\n\n const used = collectTopLevelBindings(program);\n\n for (const rule of selectedRules) {\n // Generate a safe import name\n const importName = chooseUniqueIdentifier(\n `${rule.id\n .replace(/-([a-z])/g, (_: string, c: string) => c.toUpperCase())\n .replace(/^./, (c: string) => c.toUpperCase())}Rule`,\n used\n );\n importNames.set(rule.id, importName);\n used.add(importName);\n\n // Add require statement\n // Directory-based rules use /index for TypeScript projects only\n // For JavaScript projects, all rules are bundled to single .js files\n const rulePath = (rule.isDirectoryBased && isTypeScriptProject)\n ? `${normalizedRulesPath}/${rule.id}/index${fileExtension}`\n : `${normalizedRulesPath}/${rule.id}${fileExtension}`;\n const stmtMod = parseModule(\n `const ${importName} = require(\"${rulePath}\");`\n );\n const stmt = (stmtMod.$ast as any).body?.[0];\n if (stmt) {\n // Place after a leading \"use strict\" if present.\n let insertAt = 0;\n const first = program.body?.[0];\n if (\n first?.type === \"ExpressionStatement\" &&\n first.expression?.type === \"StringLiteral\" &&\n first.expression.value === \"use strict\"\n ) {\n insertAt = 1;\n }\n program.body.splice(insertAt, 0, stmt);\n changed = true;\n }\n }\n\n return { importNames, changed };\n}\n\nfunction appendUilintConfigBlockToArray(\n arrayExpr: any,\n selectedRules: RuleMetadata[],\n ruleImportNames: Map<string, string>\n): void {\n // Build plugin object with local rule imports\n const pluginRulesCode = Array.from(ruleImportNames.entries())\n .map(([ruleId, importName]) => ` \"${ruleId}\": ${importName},`)\n .join(\"\\n\");\n\n const rulesPropsCode = selectedRules\n .map((r) => {\n const ruleKey = `uilint/${r.id}`;\n const valueCode =\n r.defaultOptions && r.defaultOptions.length > 0\n ? `[\"${r.defaultSeverity}\", ...${JSON.stringify(\n r.defaultOptions,\n null,\n 2\n )}]`\n : `\"${r.defaultSeverity}\"`;\n return ` \"${ruleKey}\": ${valueCode},`;\n })\n .join(\"\\n\");\n\n const blockCode = `{\n files: [\n \"src/**/*.{js,jsx,ts,tsx}\",\n \"app/**/*.{js,jsx,ts,tsx}\",\n \"pages/**/*.{js,jsx,ts,tsx}\",\n ],\n plugins: {\n uilint: {\n rules: {\n${pluginRulesCode}\n },\n },\n },\n rules: {\n${rulesPropsCode}\n },\n }`;\n\n const objExpr = (parseExpression(blockCode) as any).$ast;\n arrayExpr.elements.push(objExpr);\n}\n\nfunction getUilintEslintConfigInfoFromSourceAst(source: string):\n | {\n info: UilintEslintConfigInfo;\n mod: any;\n arrayExpr: any;\n kind: \"esm\" | \"cjs\";\n }\n | { error: string } {\n try {\n const mod = parseModule(source);\n const found = findExportedConfigArrayExpression(mod);\n if (!found) {\n return {\n error:\n \"Could not locate an exported ESLint flat config array (expected `export default [...]`, `export default defineConfig([...])`, `module.exports = [...]`, or `module.exports = defineConfig([...])`).\",\n };\n }\n\n const configuredRuleIds = collectConfiguredUilintRuleIdsFromConfigArray(\n found.arrayExpr\n );\n const existingUilint = findExistingUilintRulesObject(found.arrayExpr);\n const configured =\n configuredRuleIds.size > 0 || existingUilint.configObj !== null;\n\n return {\n info: { configuredRuleIds, configured },\n mod,\n arrayExpr: found.arrayExpr,\n kind: found.kind,\n };\n } catch {\n return {\n error:\n \"Unable to parse ESLint config as JavaScript. Please update it manually or simplify the config so it can be safely auto-modified.\",\n };\n }\n}\n\nexport function getUilintEslintConfigInfoFromSource(\n source: string\n): UilintEslintConfigInfo {\n const ast = getUilintEslintConfigInfoFromSourceAst(source);\n if (\"error\" in ast) {\n // Fallback (best-effort) to string heuristics for scan-only scenarios.\n const configuredRuleIds = extractConfiguredUilintRuleIds(source);\n return {\n configuredRuleIds,\n configured: configuredRuleIds.size > 0,\n };\n }\n return ast.info;\n}\n\nfunction findEsmExportedConfigArrayStartIndex(source: string): number | null {\n // Supported:\n // - export default [ ... ]\n // - export default defineConfig([ ... ])\n const patterns: RegExp[] = [\n /export\\s+default\\s+\\[/,\n /export\\s+default\\s+defineConfig\\s*\\(\\s*\\[/,\n ];\n\n for (const re of patterns) {\n const m = source.match(re);\n if (!m || m.index === undefined) continue;\n return m.index + m[0].length;\n }\n\n return null;\n}\n\nfunction findCommonJsExportedConfigArrayStartIndex(\n source: string\n): number | null {\n // Supported:\n // - module.exports = [ ... ]\n // - module.exports = defineConfig([ ... ]) (best-effort)\n const patterns: RegExp[] = [\n /module\\.exports\\s*=\\s*\\[/,\n /module\\.exports\\s*=\\s*defineConfig\\s*\\(\\s*\\[/,\n ];\n\n for (const re of patterns) {\n const m = source.match(re);\n if (!m || m.index === undefined) continue;\n return m.index + m[0].length;\n }\n\n return null;\n}\n\n/**\n * Extract configured uilint rule IDs from source.\n * Matches keys like: \"uilint/no-arbitrary-tailwind\": \"error\"\n */\nfunction extractConfiguredUilintRuleIds(source: string): Set<string> {\n const ids = new Set<string>();\n const re = /[\"']uilint\\/([^\"']+)[\"']\\s*:/g;\n for (const m of source.matchAll(re)) {\n if (m[1]) ids.add(m[1]);\n }\n return ids;\n}\n\nfunction getMissingSelectedRules(\n selectedRules: RuleMetadata[],\n configuredIds: Set<string>\n): RuleMetadata[] {\n return selectedRules.filter((r) => !configuredIds.has(r.id));\n}\n\n/**\n * Get rules that exist but need updating (different options or severity)\n */\nfunction buildDesiredRuleValueExpression(rule: RuleMetadata): string {\n if (rule.defaultOptions && rule.defaultOptions.length > 0) {\n // Match the shape we generate elsewhere: [\"severity\", ...[options...]]\n return `[\"${rule.defaultSeverity}\", ...${JSON.stringify(\n rule.defaultOptions,\n null,\n 2\n )}]`;\n }\n return `\"${rule.defaultSeverity}\"`;\n}\n\nfunction collectUilintRuleValueNodesFromConfigArray(\n arrayExpr: any\n): Map<string, any> {\n const out = new Map<string, any>();\n if (!arrayExpr || arrayExpr.type !== \"ArrayExpression\") return out;\n\n for (const el of arrayExpr.elements ?? []) {\n if (!el || el.type !== \"ObjectExpression\") continue;\n const rules = getObjectPropertyValue(el, \"rules\");\n if (!rules || rules.type !== \"ObjectExpression\") continue;\n\n for (const prop of rules.properties ?? []) {\n if (!prop) continue;\n if (prop.type !== \"ObjectProperty\" && prop.type !== \"Property\") continue;\n const key = prop.key;\n if (!isStringLiteral(key)) continue;\n const k = key.value;\n if (typeof k !== \"string\" || !k.startsWith(\"uilint/\")) continue;\n const id = k.slice(\"uilint/\".length);\n // First occurrence wins; that's enough for detecting up-to-date configs.\n if (!out.has(id)) out.set(id, prop.value);\n }\n }\n\n return out;\n}\n\nfunction getRulesNeedingUpdate(\n selectedRules: RuleMetadata[],\n configuredIds: Set<string>,\n arrayExpr: any\n): RuleMetadata[] {\n // Only consider rules that are already configured, and only update if the\n // existing severity/options differ from what we would generate.\n const existingVals = collectUilintRuleValueNodesFromConfigArray(arrayExpr);\n\n return selectedRules.filter((r) => {\n if (!configuredIds.has(r.id)) return false;\n const existing = existingVals.get(r.id);\n if (!existing) return true;\n\n const desiredExpr = buildDesiredRuleValueExpression(r);\n const desiredAst = (parseExpression(desiredExpr) as any).$ast;\n return !astEquivalent(existing, desiredAst);\n });\n}\n\n/**\n * Generate a single rule config string\n */\nfunction generateSingleRuleConfig(rule: RuleMetadata): string {\n const ruleKey = `\"uilint/${rule.id}\"`;\n\n if (rule.defaultOptions && rule.defaultOptions.length > 0) {\n // Rule with options\n const optionsStr = JSON.stringify(rule.defaultOptions, null, 6)\n .split(\"\\n\")\n .join(\"\\n \");\n return ` ${ruleKey}: [\"${rule.defaultSeverity}\", ...${optionsStr}],`;\n } else {\n // Simple rule\n return ` ${ruleKey}: \"${rule.defaultSeverity}\",`;\n }\n}\n\n/**\n * Add the uilint import to the source if not present\n */\nfunction ensureUilintImport(source: string, isCommonJS: boolean): string {\n if (hasUilintImport(source)) {\n return source;\n }\n\n const importLine = isCommonJS\n ? `const uilint = require(\"uilint-eslint\");\\n`\n : `import uilint from \"uilint-eslint\";\\n`;\n\n // Find the last import/require statement and insert after it\n const header = source.slice(0, Math.min(source.length, 5000));\n const importRegex = isCommonJS\n ? /^(?:const|var|let)\\s+.*?=\\s*require\\([^)]+\\);?\\s*$/gm\n : /^import[\\s\\S]*?;\\s*$/gm;\n\n let lastImportEnd = -1;\n for (const m of header.matchAll(importRegex)) {\n lastImportEnd = (m.index ?? 0) + m[0].length;\n }\n\n if (lastImportEnd !== -1) {\n return (\n source.slice(0, lastImportEnd) +\n \"\\n\" +\n importLine +\n source.slice(lastImportEnd)\n );\n }\n\n // No imports found, add at the beginning\n return importLine + source;\n}\n\n/**\n * Generate the rules config object from selected rules\n */\nfunction generateRulesConfig(selectedRules: RuleMetadata[]): string {\n const lines: string[] = [];\n\n for (const rule of selectedRules) {\n const ruleKey = `\"uilint/${rule.id}\"`;\n\n if (rule.defaultOptions && rule.defaultOptions.length > 0) {\n // Rule with options\n const optionsStr = JSON.stringify(rule.defaultOptions, null, 6)\n .split(\"\\n\")\n .join(\"\\n \");\n lines.push(\n ` ${ruleKey}: [\"${rule.defaultSeverity}\", ...${optionsStr}],`\n );\n } else {\n // Simple rule\n lines.push(` ${ruleKey}: \"${rule.defaultSeverity}\",`);\n }\n }\n\n return lines.join(\"\\n\");\n}\n\nfunction detectIndent(source: string, index: number): string {\n const lineStart = source.lastIndexOf(\"\\n\", index);\n const start = lineStart === -1 ? 0 : lineStart + 1;\n const line = source.slice(start, index);\n const m = line.match(/^\\s*/);\n return m?.[0] ?? \"\";\n}\n\n/**\n * Insert missing uilint rule keys into an existing `rules: { ... }` object\n * that already contains at least one \"uilint/\" key.\n *\n * This is intentionally a best-effort string transform (no JS AST dependency).\n */\nfunction insertMissingRulesIntoExistingRulesObject(\n source: string,\n missingRules: RuleMetadata[]\n): string {\n if (missingRules.length === 0) return source;\n\n // Anchor on an existing uilint rule key, then look backwards for the\n // nearest `rules:` preceding it.\n const uilintKeyMatch = source.match(/[\"']uilint\\/[^\"']+[\"']\\s*:/);\n if (!uilintKeyMatch || uilintKeyMatch.index === undefined) return source;\n\n const uilintKeyIndex = uilintKeyMatch.index;\n const searchStart = Math.max(0, uilintKeyIndex - 4000);\n const before = source.slice(searchStart, uilintKeyIndex);\n const rulesKwIndexRel = before.lastIndexOf(\"rules\");\n if (rulesKwIndexRel === -1) return source;\n\n const rulesKwIndex = searchStart + rulesKwIndexRel;\n const braceOpenIndex = source.indexOf(\"{\", rulesKwIndex);\n if (braceOpenIndex === -1 || braceOpenIndex > uilintKeyIndex) return source;\n\n // Find the matching closing brace for the rules object.\n let depth = 0;\n let braceCloseIndex = -1;\n for (let i = braceOpenIndex; i < source.length; i++) {\n const ch = source[i];\n if (ch === \"{\") depth++;\n else if (ch === \"}\") {\n depth--;\n if (depth === 0) {\n braceCloseIndex = i;\n break;\n }\n }\n }\n if (braceCloseIndex === -1) return source;\n\n const rulesIndent = detectIndent(source, braceOpenIndex);\n const entryIndent = rulesIndent + \" \";\n const entryTextRaw = generateRulesConfig(missingRules);\n const entryText = entryTextRaw\n .split(\"\\n\")\n .map((l) => (l.trim().length === 0 ? l : entryIndent + l.trimStart()))\n .join(\"\\n\");\n\n const insertion =\n (source.slice(braceOpenIndex + 1, braceCloseIndex).trim().length === 0\n ? \"\\n\"\n : \"\\n\") +\n entryText +\n \"\\n\" +\n rulesIndent;\n\n return (\n source.slice(0, braceCloseIndex) + insertion + source.slice(braceCloseIndex)\n );\n}\n\n/**\n * Find the end of a rule value in the source code\n * Handles: \"error\", [\"error\"], [\"error\", {...}], [\"error\", ...[{...}]]\n */\nfunction findRuleValueEnd(source: string, startIndex: number): number {\n let pos = startIndex;\n let depth = 0;\n let inString = false;\n let stringChar = \"\";\n let foundArray = false;\n\n while (pos < source.length) {\n const ch = source[pos];\n const prevCh = pos > 0 ? source[pos - 1] : \"\";\n\n // Handle string literals\n if (!inString && (ch === '\"' || ch === \"'\")) {\n inString = true;\n stringChar = ch;\n } else if (inString && ch === stringChar && prevCh !== \"\\\\\") {\n inString = false;\n } else if (!inString) {\n // Track brackets/braces\n if (ch === \"[\") {\n depth++;\n foundArray = true;\n } else if (ch === \"]\") {\n depth--;\n if (depth === 0 && foundArray) {\n // Found the end of the array\n pos++;\n // Skip whitespace and include trailing comma if present\n while (pos < source.length && /\\s/.test(source[pos])) {\n pos++;\n }\n if (pos < source.length && source[pos] === \",\") {\n pos++;\n }\n return pos;\n }\n } else if (ch === \"{\" || ch === \"(\") {\n depth++;\n } else if (ch === \"}\" || ch === \")\") {\n depth--;\n } else if (!foundArray && depth === 0) {\n // Simple string value - ends at comma or closing brace\n if (ch === \",\" || ch === \"}\") {\n return pos + (ch === \",\" ? 1 : 0);\n }\n }\n }\n\n pos++;\n }\n\n return pos;\n}\n\n/**\n * Update existing uilint rule configurations with new options/severity\n *\n * This finds existing rule entries and replaces them with updated configurations.\n * Uses a more robust approach to handle multi-line rules with spread syntax.\n */\nfunction updateExistingRulesWithNewOptions(\n source: string,\n rulesToUpdate: RuleMetadata[]\n): string {\n if (rulesToUpdate.length === 0) return source;\n\n let updated = source;\n\n // Process rules in reverse order to avoid index shifting issues\n for (let i = rulesToUpdate.length - 1; i >= 0; i--) {\n const rule = rulesToUpdate[i]!;\n const ruleKeyPattern = new RegExp(\n `[\"']uilint/${rule.id.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")}[\"']\\\\s*:`,\n \"g\"\n );\n\n // Find all occurrences (should only be one, but be safe)\n const matches: Array<{ index: number; length: number }> = [];\n let match;\n while ((match = ruleKeyPattern.exec(updated)) !== null) {\n if (match.index !== undefined) {\n matches.push({ index: match.index, length: match[0].length });\n }\n }\n\n // Process matches in reverse order\n for (let j = matches.length - 1; j >= 0; j--) {\n const keyMatch = matches[j]!;\n const keyStart = keyMatch.index;\n const keyEnd = keyStart + keyMatch.length;\n\n // Find the value start (after colon and whitespace)\n let valueStart = keyEnd;\n while (valueStart < updated.length && /\\s/.test(updated[valueStart])) {\n valueStart++;\n }\n\n // Find the value end\n const valueEnd = findRuleValueEnd(updated, valueStart);\n\n // Generate new rule config\n const newRuleConfig = generateSingleRuleConfig(rule);\n\n // Find the indentation of the rule key line\n const indent = detectIndent(updated, keyStart);\n\n // Replace the old rule with the new one\n const before = updated.slice(0, keyStart);\n const after = updated.slice(valueEnd);\n\n updated = before + newRuleConfig + \"\\n\" + indent + after;\n }\n }\n\n return updated;\n}\n\n/**\n * Inject uilint rules into the export default array\n */\nfunction injectUilintRules(\n source: string,\n selectedRules: RuleMetadata[]\n): { source: string; injected: boolean } {\n if (hasUilintRules(source)) {\n // Already has uilint rules - don't inject again\n return { source, injected: false };\n }\n\n const rulesConfig = generateRulesConfig(selectedRules);\n\n const configBlock = ` {\n files: [\n \"src/**/*.{js,jsx,ts,tsx}\",\n \"app/**/*.{js,jsx,ts,tsx}\",\n \"pages/**/*.{js,jsx,ts,tsx}\",\n ],\n plugins: { uilint: uilint },\n rules: {\n${rulesConfig}\n },\n },`;\n\n const arrayStart = findEsmExportedConfigArrayStartIndex(source);\n if (arrayStart === null) {\n return { source, injected: false };\n }\n\n const afterExport = source.slice(arrayStart);\n\n // Insert at the beginning of the array (after opening bracket)\n // Add a newline if the array doesn't start on a new line\n const needsNewline = !afterExport.trimStart().startsWith(\"\\n\");\n const insertion = needsNewline\n ? \"\\n\" + configBlock + \"\\n\"\n : configBlock + \"\\n\";\n\n return {\n source: source.slice(0, arrayStart) + insertion + source.slice(arrayStart),\n injected: true,\n };\n}\n\n/**\n * Inject uilint rules into the CommonJS export\n */\nfunction injectUilintRulesCommonJS(\n source: string,\n selectedRules: RuleMetadata[]\n): { source: string; injected: boolean } {\n if (hasUilintRules(source)) {\n return { source, injected: false };\n }\n\n const rulesConfig = generateRulesConfig(selectedRules);\n\n const configBlock = ` {\n files: [\n \"src/**/*.{js,jsx,ts,tsx}\",\n \"app/**/*.{js,jsx,ts,tsx}\",\n \"pages/**/*.{js,jsx,ts,tsx}\",\n ],\n plugins: { uilint: uilint },\n rules: {\n${rulesConfig}\n },\n },`;\n\n const arrayStart = findCommonJsExportedConfigArrayStartIndex(source);\n if (arrayStart === null) {\n return { source, injected: false };\n }\n\n const afterExport = source.slice(arrayStart);\n const needsNewline = !afterExport.trimStart().startsWith(\"\\n\");\n const insertion = needsNewline\n ? \"\\n\" + configBlock + \"\\n\"\n : configBlock + \"\\n\";\n\n return {\n source: source.slice(0, arrayStart) + insertion + source.slice(arrayStart),\n injected: true,\n };\n}\n\n/**\n * Install uilint-eslint into eslint config\n */\nexport async function installEslintPlugin(\n opts: InstallEslintPluginOptions\n): Promise<{\n configFile: string | null;\n modified: boolean;\n missingRuleIds: string[];\n configured: boolean;\n error?: string;\n}> {\n const configPath = findEslintConfigFile(opts.projectPath);\n\n if (!configPath) {\n return {\n configFile: null,\n modified: false,\n missingRuleIds: [],\n configured: false,\n };\n }\n\n const configFilename = getEslintConfigFilename(configPath);\n const original = readFileSync(configPath, \"utf-8\");\n const isCommonJS = configPath.endsWith(\".cjs\");\n\n const ast = getUilintEslintConfigInfoFromSourceAst(original);\n if (\"error\" in ast) {\n return {\n configFile: configFilename,\n modified: false,\n missingRuleIds: [],\n configured: false,\n error: ast.error,\n };\n }\n\n const { info, mod, arrayExpr, kind } = ast;\n const configuredIds = info.configuredRuleIds;\n\n const missingRules = getMissingSelectedRules(\n opts.selectedRules,\n configuredIds\n );\n const rulesToUpdate = getRulesNeedingUpdate(\n opts.selectedRules,\n configuredIds,\n arrayExpr\n );\n\n // Decide what rules to apply, respecting prompts.\n let rulesToApply: RuleMetadata[] = [];\n if (!info.configured) {\n rulesToApply = opts.selectedRules;\n } else {\n // When already configured, we only apply updates + missing rules.\n rulesToApply = [...missingRules, ...rulesToUpdate];\n if (missingRules.length > 0 && !opts.force) {\n const ok = await opts.confirmAddMissingRules?.(\n configFilename,\n missingRules\n );\n if (!ok) {\n return {\n configFile: configFilename,\n modified: false,\n missingRuleIds: missingRules.map((r) => r.id),\n configured: true,\n };\n }\n }\n }\n\n if (rulesToApply.length === 0) {\n return {\n configFile: configFilename,\n modified: false,\n missingRuleIds: missingRules.map((r) => r.id),\n configured: info.configured,\n };\n }\n\n let modifiedAst = false;\n\n // Check if .uilint/rules/ directory exists alongside this target package/app.\n // (Also allow a fallback to workspace root for backwards compatibility.)\n const localRulesDir = join(opts.projectPath, \".uilint\", \"rules\");\n const workspaceRoot = findWorkspaceRoot(opts.projectPath);\n const workspaceRulesDir = join(workspaceRoot, \".uilint\", \"rules\");\n\n const rulesRoot = existsSync(localRulesDir)\n ? opts.projectPath\n : workspaceRoot;\n\n // Always use local rules (they should have been copied by the plan phase)\n // For TypeScript configs, omit the extension (TypeScript will resolve .ts files)\n // For JavaScript configs, use .js extension\n // Note: We don't use .ts extension directly because it requires allowImportingTsExtensions\n const isTypeScriptConfig = configPath.endsWith(\".ts\");\n let fileExtension = isTypeScriptConfig ? \"\" : \".js\";\n\n let ruleImportNames: Map<string, string> | undefined;\n\n // Add imports for local rules\n if (kind === \"esm\") {\n const result = addLocalRuleImportsAst(\n mod,\n rulesToApply,\n configPath,\n rulesRoot,\n fileExtension,\n isTypeScriptConfig\n );\n ruleImportNames = result.importNames;\n if (result.changed) modifiedAst = true;\n } else {\n const result = addLocalRuleRequiresAst(\n mod.$ast,\n rulesToApply,\n configPath,\n rulesRoot,\n fileExtension,\n isTypeScriptConfig\n );\n ruleImportNames = result.importNames;\n if (result.changed) modifiedAst = true;\n }\n\n // Add config block with local rules\n if (ruleImportNames && ruleImportNames.size > 0) {\n appendUilintConfigBlockToArray(arrayExpr, rulesToApply, ruleImportNames);\n modifiedAst = true;\n }\n\n // Ensure uilint-eslint import for utilities (createRule, etc.)\n if (!info.configured) {\n if (kind === \"esm\") {\n // Import createRule utility from uilint-eslint\n mod.imports.$add({\n imported: \"createRule\",\n local: \"createRule\",\n from: \"uilint-eslint\",\n });\n modifiedAst = true;\n } else {\n // CommonJS: add require for createRule\n const stmtMod = parseModule(\n `const { createRule } = require(\"uilint-eslint\");`\n );\n const stmt = (stmtMod.$ast as any).body?.[0];\n if (stmt) {\n let insertAt = 0;\n const first = mod.$ast.body?.[0];\n if (\n first?.type === \"ExpressionStatement\" &&\n first.expression?.type === \"StringLiteral\" &&\n first.expression.value === \"use strict\"\n ) {\n insertAt = 1;\n }\n mod.$ast.body.splice(insertAt, 0, stmt);\n modifiedAst = true;\n }\n }\n }\n\n const updated = modifiedAst ? generateCode(mod).code : original;\n\n if (updated !== original) {\n writeFileSync(configPath, updated, \"utf-8\");\n return {\n configFile: configFilename,\n modified: true,\n missingRuleIds: missingRules.map((r) => r.id),\n configured: getUilintEslintConfigInfoFromSource(updated).configured,\n };\n }\n\n return {\n configFile: configFilename,\n modified: false,\n missingRuleIds: missingRules.map((r) => r.id),\n configured: getUilintEslintConfigInfoFromSource(updated).configured,\n };\n}\n\nexport interface UninstallEslintPluginOptions {\n projectPath: string;\n}\n\nexport interface UninstallEslintPluginResult {\n success: boolean;\n error?: string;\n modifiedFiles?: string[];\n}\n\n/**\n * Remove uilint-eslint rules from ESLint config\n *\n * This is a best-effort uninstall that:\n * 1. Removes uilint rule imports\n * 2. Removes uilint config blocks from the flat config array\n * 3. Removes uilint-eslint package import\n */\nexport async function uninstallEslintPlugin(\n options: UninstallEslintPluginOptions\n): Promise<UninstallEslintPluginResult> {\n const { projectPath } = options;\n\n const configPath = findEslintConfigFile(projectPath);\n if (!configPath) {\n return {\n success: true, // Nothing to uninstall\n modifiedFiles: [],\n };\n }\n\n try {\n const original = readFileSync(configPath, \"utf-8\");\n\n // Simple regex-based removal for now\n // Remove uilint rule imports (import { ... } from \"./uilint-rules/...\" or \"./.uilint/rules/...\")\n let updated = original.replace(\n /^import\\s+\\{[^}]*\\}\\s+from\\s+[\"'][^\"']*\\.uilint\\/rules[^\"']*[\"'];?\\s*$/gm,\n \"\"\n );\n\n // Remove default imports from .uilint/rules (e.g., import RuleName from \"./.uilint/rules/rule-name\")\n updated = updated.replace(\n /^import\\s+\\w+\\s+from\\s+[\"'][^\"']*\\.uilint\\/rules[^\"']*[\"'];?\\s*$/gm,\n \"\"\n );\n\n // Remove uilint-eslint import\n updated = updated.replace(\n /^import\\s+\\{[^}]*\\}\\s+from\\s+[\"']uilint-eslint[\"'];?\\s*$/gm,\n \"\"\n );\n\n // Remove createRule require\n updated = updated.replace(\n /^const\\s+\\{[^}]*createRule[^}]*\\}\\s*=\\s*require\\s*\\(\\s*[\"']uilint-eslint[\"']\\s*\\)\\s*;?\\s*$/gm,\n \"\"\n );\n\n // Remove uilint rules from rules objects (e.g., \"uilint/rule-name\": \"error\")\n updated = updated.replace(\n /[\"']uilint\\/[^\"']+[\"']\\s*:\\s*[\"'][^\"']+[\"']\\s*,?\\s*/g,\n \"\"\n );\n\n // Remove uilint rules array form (e.g., \"uilint/rule-name\": [\"error\", {}])\n updated = updated.replace(\n /[\"']uilint\\/[^\"']+[\"']\\s*:\\s*\\[[^\\]]*\\]\\s*,?\\s*/g,\n \"\"\n );\n\n // Remove entire uilint config block from flat config array\n // This matches: { plugins: { uilint: { rules: {...} } }, rules: {...} }\n updated = updated.replace(\n /\\{\\s*plugins:\\s*\\{\\s*uilint:\\s*\\{[^}]*\\}[^}]*\\}[^}]*rules:\\s*\\{[^}]*\\}[^}]*\\}\\s*,?\\s*/gs,\n \"\"\n );\n\n // Clean up empty lines\n updated = updated.replace(/\\n{3,}/g, \"\\n\\n\");\n\n if (updated !== original) {\n writeFileSync(configPath, updated, \"utf-8\");\n return {\n success: true,\n modifiedFiles: [configPath],\n };\n }\n\n return {\n success: true,\n modifiedFiles: [],\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\nexport interface UpdateRuleConfigResult {\n success: boolean;\n error?: string;\n}\n\nexport interface RuleConfigFromFile {\n severity: \"error\" | \"warn\" | \"off\";\n options?: Record<string, unknown>;\n}\n\n/**\n * Extract severity from an AST node representing a rule value.\n * Handles both formats:\n * - Simple string: \"error\"\n * - Array: [\"error\", { ...options }]\n */\nfunction extractSeverityFromValueNode(\n valueNode: any\n): \"error\" | \"warn\" | \"off\" | null {\n if (!valueNode) return null;\n\n // Simple string format: \"error\"\n if (isStringLiteral(valueNode)) {\n const val = valueNode.value;\n if (val === \"error\" || val === \"warn\" || val === \"off\") {\n return val;\n }\n return null;\n }\n\n // Array format: [\"error\", { ...options }]\n if (valueNode.type === \"ArrayExpression\") {\n const firstEl = valueNode.elements?.[0];\n if (firstEl && isStringLiteral(firstEl)) {\n const val = firstEl.value;\n if (val === \"error\" || val === \"warn\" || val === \"off\") {\n return val;\n }\n }\n }\n\n return null;\n}\n\n/**\n * Extract options object from an AST node representing a rule value in array format.\n * Returns undefined if not in array format or no options present.\n */\nfunction extractOptionsFromValueNode(\n valueNode: any\n): Record<string, unknown> | undefined {\n if (!valueNode || valueNode.type !== \"ArrayExpression\") return undefined;\n\n const elements = valueNode.elements ?? [];\n if (elements.length < 2) return undefined;\n\n const optionsNode = elements[1];\n if (!optionsNode || optionsNode.type !== \"ObjectExpression\") return undefined;\n\n // Convert AST object to plain JS object\n try {\n const obj: Record<string, unknown> = {};\n for (const prop of optionsNode.properties ?? []) {\n if (!prop || (prop.type !== \"ObjectProperty\" && prop.type !== \"Property\"))\n continue;\n\n const key = prop.key;\n let keyName: string | null = null;\n if (key?.type === \"Identifier\") {\n keyName = key.name;\n } else if (isStringLiteral(key)) {\n keyName = key.value;\n }\n if (!keyName) continue;\n\n const val = prop.value;\n if (isStringLiteral(val)) {\n obj[keyName] = val.value;\n } else if (\n val?.type === \"NumericLiteral\" ||\n (val?.type === \"Literal\" && typeof val.value === \"number\")\n ) {\n obj[keyName] = val.value;\n } else if (\n val?.type === \"BooleanLiteral\" ||\n (val?.type === \"Literal\" && typeof val.value === \"boolean\")\n ) {\n obj[keyName] = val.value;\n } else if (val?.type === \"ArrayExpression\") {\n // Simple array of literals\n const arr: unknown[] = [];\n for (const el of val.elements ?? []) {\n if (isStringLiteral(el)) arr.push(el.value);\n else if (\n el?.type === \"NumericLiteral\" ||\n (el?.type === \"Literal\" && typeof el.value === \"number\")\n )\n arr.push(el.value);\n else if (\n el?.type === \"BooleanLiteral\" ||\n (el?.type === \"Literal\" && typeof el.value === \"boolean\")\n )\n arr.push(el.value);\n }\n obj[keyName] = arr;\n }\n }\n return Object.keys(obj).length > 0 ? obj : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Read current rule configurations from an ESLint config file.\n * Uses magicast to parse the config and extract uilint rule severities and options.\n *\n * @param configPath Path to the ESLint config file\n * @returns Map of ruleId (without \"uilint/\" prefix) to { severity, options }\n */\nexport function readRuleConfigsFromConfig(\n configPath: string\n): Map<string, RuleConfigFromFile> {\n const configs = new Map<string, RuleConfigFromFile>();\n\n try {\n const source = readFileSync(configPath, \"utf-8\");\n const mod = parseModule(source);\n const found = findExportedConfigArrayExpression(mod);\n\n if (!found) {\n return configs;\n }\n\n const { arrayExpr } = found;\n const valueNodes = collectUilintRuleValueNodesFromConfigArray(arrayExpr);\n\n for (const [ruleId, valueNode] of valueNodes) {\n const severity = extractSeverityFromValueNode(valueNode);\n if (severity) {\n const options = extractOptionsFromValueNode(valueNode);\n configs.set(ruleId, { severity, options });\n }\n }\n } catch (error) {\n console.error(\"[eslint-config-inject] Failed to read rule configs:\", error);\n }\n\n return configs;\n}\n\n/**\n * Find a rule property node in the config array by rule ID.\n * Returns the property node and its parent rules object.\n */\nfunction findRulePropertyInConfigArray(\n arrayExpr: any,\n ruleId: string\n): { prop: any; rulesObj: any } | null {\n const fullRuleKey = `uilint/${ruleId}`;\n\n if (!arrayExpr || arrayExpr.type !== \"ArrayExpression\") return null;\n\n for (const el of arrayExpr.elements ?? []) {\n if (!el || el.type !== \"ObjectExpression\") continue;\n const rules = getObjectPropertyValue(el, \"rules\");\n if (!rules || rules.type !== \"ObjectExpression\") continue;\n\n for (const prop of rules.properties ?? []) {\n if (!prop) continue;\n if (prop.type !== \"ObjectProperty\" && prop.type !== \"Property\") continue;\n const key = prop.key;\n if (!isStringLiteral(key)) continue;\n if (key.value === fullRuleKey) {\n return { prop, rulesObj: rules };\n }\n }\n }\n\n return null;\n}\n\n/**\n * Update the severity of a single uilint rule in the ESLint config file.\n * Uses magicast for proper AST-based editing.\n *\n * Handles both formats:\n * - Simple: \"uilint/rule-name\": \"error\"\n * - With options: \"uilint/rule-name\": [\"error\", { ... }]\n *\n * Only updates existing rules - returns error if rule not found.\n */\nexport function updateRuleSeverityInConfig(\n configPath: string,\n ruleId: string,\n severity: \"error\" | \"warn\" | \"off\"\n): UpdateRuleConfigResult {\n try {\n const source = readFileSync(configPath, \"utf-8\");\n const mod = parseModule(source);\n const found = findExportedConfigArrayExpression(mod);\n\n if (!found) {\n return {\n success: false,\n error: \"Could not parse ESLint config array\",\n };\n }\n\n const { arrayExpr } = found;\n const ruleInfo = findRulePropertyInConfigArray(arrayExpr, ruleId);\n\n if (!ruleInfo) {\n return {\n success: false,\n error: `Rule \"uilint/${ruleId}\" not found in config. Use 'uilint install' to add new rules.`,\n };\n }\n\n const { prop } = ruleInfo;\n const valueNode = prop.value;\n\n // Update the severity based on the format\n if (isStringLiteral(valueNode)) {\n // Simple string format - replace the value\n valueNode.value = severity;\n } else if (valueNode?.type === \"ArrayExpression\") {\n // Array format - update the first element\n const firstEl = valueNode.elements?.[0];\n if (firstEl && isStringLiteral(firstEl)) {\n firstEl.value = severity;\n } else {\n // Create a new string literal for severity\n const severityNode = (parseExpression(`\"${severity}\"`) as any).$ast;\n if (valueNode.elements && valueNode.elements.length > 0) {\n valueNode.elements[0] = severityNode;\n } else {\n valueNode.elements = [severityNode];\n }\n }\n } else {\n return {\n success: false,\n error: `Rule \"uilint/${ruleId}\" has unexpected format`,\n };\n }\n\n const updated = generateCode(mod).code;\n writeFileSync(configPath, updated, \"utf-8\");\n return { success: true };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n/**\n * Update the severity AND options of a single uilint rule in the ESLint config file.\n * Uses magicast for proper AST-based editing.\n *\n * Converts the rule to array format: [\"severity\", { ...options }]\n *\n * Only updates existing rules - returns error if rule not found.\n */\nexport function updateRuleConfigInConfig(\n configPath: string,\n ruleId: string,\n severity: \"error\" | \"warn\" | \"off\",\n options: Record<string, unknown>\n): UpdateRuleConfigResult {\n try {\n const source = readFileSync(configPath, \"utf-8\");\n const mod = parseModule(source);\n const found = findExportedConfigArrayExpression(mod);\n\n if (!found) {\n return {\n success: false,\n error: \"Could not parse ESLint config array\",\n };\n }\n\n const { arrayExpr } = found;\n const ruleInfo = findRulePropertyInConfigArray(arrayExpr, ruleId);\n\n if (!ruleInfo) {\n return {\n success: false,\n error: `Rule \"uilint/${ruleId}\" not found in config. Use 'uilint install' to add new rules.`,\n };\n }\n\n const { prop } = ruleInfo;\n\n // Build the new value as array format: [\"severity\", { ...options }]\n const optionsJson = JSON.stringify(options);\n const newValueExpr = `[\"${severity}\", ${optionsJson}]`;\n const newValueNode = (parseExpression(newValueExpr) as any).$ast;\n\n // Replace the value\n prop.value = newValueNode;\n\n const updated = generateCode(mod).code;\n writeFileSync(configPath, updated, \"utf-8\");\n return { success: true };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n","/**\n * Coverage preparation utilities.\n *\n * Handles automatically setting up coverage for vitest projects:\n * - Installing @vitest/coverage-v8 package\n * - Adding coverage config to vitest.config.ts\n * - Running tests with coverage to generate data\n */\n\nimport { existsSync, readFileSync, writeFileSync } from \"fs\";\nimport { join } from \"path\";\nimport {\n detectPackageManager,\n installDependencies,\n runTestsWithCoverage,\n} from \"./package-manager.js\";\nimport { detectCoverageSetup, type CoverageSetupInfo } from \"./coverage-detect.js\";\n\nexport interface CoveragePreparationResult {\n /** Whether @vitest/coverage-v8 was added to package.json */\n packageAdded: boolean;\n /** Whether vitest.config.ts was modified to add coverage */\n configModified: boolean;\n /** Whether tests were run with coverage */\n testsRan: boolean;\n /** Whether coverage-final.json was generated */\n coverageGenerated: boolean;\n /** Total time taken in milliseconds */\n duration: number;\n /** Error message if something failed */\n error?: string;\n}\n\nexport interface PrepareCoverageOptions {\n /** Root directory of the app to prepare */\n appRoot: string;\n /** Progress callback for streaming updates */\n onProgress?: (message: string, phase: string) => void;\n /** Skip installing packages (useful in CI) */\n skipPackageInstall?: boolean;\n /** Skip running tests (useful when tests run separately) */\n skipTests?: boolean;\n}\n\n/**\n * Inject coverage configuration into vitest.config.ts\n * @returns true if config was modified, false if already configured or error\n */\nexport function injectCoverageConfig(vitestConfigPath: string): boolean {\n try {\n const content = readFileSync(vitestConfigPath, \"utf-8\");\n\n // Check if already has coverage config\n if (/coverage\\s*:\\s*\\{/.test(content)) {\n return false; // Already configured\n }\n\n // Find the `test: {` block and inject coverage after it\n // This handles patterns like:\n // - test: {\n // - test:{\n // - test : {\n const testBlockRegex = /(test\\s*:\\s*\\{)/;\n const match = content.match(testBlockRegex);\n\n if (!match) {\n // Can't find test block - might be a different config format\n return false;\n }\n\n const coverageConfig = `\n coverage: {\n provider: \"v8\",\n reporter: [\"text\", \"json\"],\n reportsDirectory: \"./coverage\",\n },`;\n\n // Insert coverage config right after `test: {`\n const newContent = content.replace(\n testBlockRegex,\n `$1${coverageConfig}`\n );\n\n writeFileSync(vitestConfigPath, newContent, \"utf-8\");\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Prepare a project for coverage generation.\n *\n * This function:\n * 1. Detects current coverage setup\n * 2. Installs @vitest/coverage-v8 if needed\n * 3. Adds coverage config to vitest.config.ts if needed\n * 4. Runs tests with coverage to generate data\n */\nexport async function prepareCoverage(\n options: PrepareCoverageOptions\n): Promise<CoveragePreparationResult> {\n const { appRoot, onProgress, skipPackageInstall, skipTests } = options;\n const start = Date.now();\n\n const result: CoveragePreparationResult = {\n packageAdded: false,\n configModified: false,\n testsRan: false,\n coverageGenerated: false,\n duration: 0,\n };\n\n try {\n // 1. Detect current setup\n onProgress?.(\"Detecting coverage setup...\", \"detect\");\n const setup = detectCoverageSetup(appRoot);\n\n // If no vitest, we can't set up coverage\n if (!setup.hasVitest) {\n result.error = \"Vitest not found in dependencies\";\n result.duration = Date.now() - start;\n return result;\n }\n\n // 2. Install coverage package if needed\n if (setup.needsCoveragePackage && !skipPackageInstall) {\n onProgress?.(\"Installing @vitest/coverage-v8...\", \"install\");\n const pm = detectPackageManager(appRoot);\n try {\n await installDependencies(pm, appRoot, [\"@vitest/coverage-v8\"]);\n result.packageAdded = true;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n result.error = `Failed to install coverage package: ${msg}`;\n result.duration = Date.now() - start;\n return result;\n }\n }\n\n // 3. Add coverage config if needed\n if (setup.needsCoverageConfig && setup.vitestConfigPath) {\n onProgress?.(\"Adding coverage configuration...\", \"config\");\n result.configModified = injectCoverageConfig(setup.vitestConfigPath);\n }\n\n // 4. Run tests with coverage\n if (!skipTests) {\n // Re-check if we need to run tests\n const updatedSetup = detectCoverageSetup(appRoot);\n\n // Only run if:\n // - No coverage data exists, OR\n // - Config was just modified (data is stale)\n if (!updatedSetup.hasCoverageData || result.configModified) {\n onProgress?.(\"Running tests with coverage...\", \"test\");\n const pm = detectPackageManager(appRoot);\n try {\n await runTestsWithCoverage(pm, appRoot);\n result.testsRan = true;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n // Tests might fail, but coverage might still be generated\n result.error = `Tests failed: ${msg}`;\n }\n\n // Check if coverage was generated\n const finalSetup = detectCoverageSetup(appRoot);\n result.coverageGenerated = finalSetup.hasCoverageData;\n }\n } else {\n onProgress?.(\"Skipping tests (skipTests=true)\", \"skip\");\n }\n\n result.duration = Date.now() - start;\n return result;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n result.error = `Coverage preparation failed: ${msg}`;\n result.duration = Date.now() - start;\n return result;\n }\n}\n\n/**\n * Check if coverage data needs to be regenerated.\n *\n * Returns true if:\n * - Coverage data doesn't exist\n * - Coverage package is missing\n * - Coverage config is missing\n */\nexport function needsCoveragePreparation(setup: CoverageSetupInfo): boolean {\n if (!setup.hasVitest) {\n return false; // Can't prepare without vitest\n }\n\n return (\n setup.needsCoveragePackage ||\n setup.needsCoverageConfig ||\n !setup.hasCoverageData\n );\n}\n"],"mappings":"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","names":["intro","outro","cancel","cancel","note","log","select","confirm","multiselect","readFileSync","join","existsSync","join","existsSync","readFileSync","join","dirname","p","program","dirname","join","readFileSync","join","existsSync","readFileSync","writeFileSync","readFileSync","writeFileSync"]}
1
+ {"version":3,"sources":["../src/utils/prompts.ts","../src/utils/coverage-detect.ts","../src/utils/next-detect.ts","../src/utils/eslint-config-inject.ts","../src/utils/coverage-prepare.ts"],"sourcesContent":["/**\n * Shared clack/prompts utilities for UILint CLI\n * Provides branded intro/outro, spinners, and common UI patterns\n */\n\nimport * as p from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { readFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { fileURLToPath } from \"url\";\n\n/**\n * Get the CLI version from package.json\n */\nfunction getCLIVersion(): string {\n try {\n const __dirname = dirname(fileURLToPath(import.meta.url));\n const pkgPath = join(__dirname, \"..\", \"..\", \"package.json\");\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n version?: string;\n };\n return pkg.version || \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n\n/**\n * Branded UILint intro with logo and version\n */\nexport function intro(title?: string): void {\n const version = getCLIVersion();\n const header = pc.bold(pc.cyan(\"◆ UILint\")) + pc.dim(` v${version}`);\n \n console.log();\n p.intro(title ? `${header} ${pc.dim(\"·\")} ${title}` : header);\n}\n\n/**\n * Styled outro with next steps\n */\nexport function outro(message: string): void {\n p.outro(pc.green(message));\n}\n\n/**\n * Cancel message when user exits\n */\nexport function cancel(message = \"Operation cancelled.\"): void {\n p.cancel(pc.yellow(message));\n process.exit(0);\n}\n\n/**\n * Check if user cancelled a prompt\n */\nexport function isCancel(value: unknown): value is symbol {\n return p.isCancel(value);\n}\n\n/**\n * Handle cancel check - exits if cancelled\n */\nexport function handleCancel<T>(value: T | symbol): T {\n if (p.isCancel(value)) {\n cancel();\n process.exit(0);\n }\n return value as T;\n}\n\n/**\n * Spinner wrapper with automatic error handling\n */\nexport async function withSpinner<T>(\n message: string,\n fn: (() => Promise<T>) | ((spinner: ReturnType<typeof p.spinner>) => Promise<T>)\n): Promise<T> {\n const s = p.spinner();\n s.start(message);\n try {\n const result =\n fn.length >= 1\n ? await (fn as (spinner: ReturnType<typeof p.spinner>) => Promise<T>)(s)\n : await (fn as () => Promise<T>)();\n s.stop(pc.green(\"✓ \") + message);\n return result;\n } catch (error) {\n s.stop(pc.red(\"✗ \") + message);\n throw error;\n }\n}\n\n/**\n * Spinner that can be updated\n */\nexport function createSpinner() {\n return p.spinner();\n}\n\n/**\n * Display a note box\n */\nexport function note(message: string, title?: string): void {\n p.note(message, title);\n}\n\n/**\n * Display a log message\n */\nexport function log(message: string): void {\n p.log.message(message);\n}\n\n/**\n * Display an info message\n */\nexport function logInfo(message: string): void {\n p.log.info(message);\n}\n\n/**\n * Display a success message\n */\nexport function logSuccess(message: string): void {\n p.log.success(message);\n}\n\n/**\n * Display a warning message\n */\nexport function logWarning(message: string): void {\n p.log.warn(message);\n}\n\n/**\n * Display an error message\n */\nexport function logError(message: string): void {\n p.log.error(message);\n}\n\n/**\n * Display a step message\n */\nexport function logStep(message: string): void {\n p.log.step(message);\n}\n\n/**\n * Select prompt wrapper\n */\nexport async function select<T extends string>(options: {\n message: string;\n options: Array<{ value: T; label: string; hint?: string }>;\n initialValue?: T;\n}): Promise<T> {\n const result = await p.select({\n message: options.message,\n options: options.options as { value: T; label: string; hint?: string }[],\n initialValue: options.initialValue,\n } as Parameters<typeof p.select>[0]);\n return handleCancel(result) as T;\n}\n\n/**\n * Confirm prompt wrapper\n */\nexport async function confirm(options: {\n message: string;\n initialValue?: boolean;\n}): Promise<boolean> {\n const result = await p.confirm({\n message: options.message,\n initialValue: options.initialValue ?? true,\n });\n return handleCancel(result);\n}\n\n/**\n * Text input prompt wrapper\n */\nexport async function text(options: {\n message: string;\n placeholder?: string;\n defaultValue?: string;\n validate?: (value: string) => string | Error | undefined;\n}): Promise<string> {\n const result = await p.text(options);\n return handleCancel(result);\n}\n\n/**\n * Multiselect prompt wrapper\n */\nexport async function multiselect<T extends string>(options: {\n message: string;\n options: Array<{ value: T; label: string; hint?: string }>;\n required?: boolean;\n initialValues?: T[];\n}): Promise<T[]> {\n const result = await p.multiselect({\n message: options.message,\n options: options.options as { value: T; label: string; hint?: string }[],\n required: options.required,\n initialValues: options.initialValues,\n } as Parameters<typeof p.multiselect>[0]);\n return handleCancel(result) as T[];\n}\n\n/**\n * Group of tasks displayed together\n */\nexport async function group<T extends Record<string, unknown>>(\n prompts: p.PromptGroup<T>,\n options?: p.PromptGroupOptions<T>\n): Promise<T> {\n const result = await p.group(prompts, options);\n return result;\n}\n\n// Re-export picocolors for consistent styling\nexport { pc };\n","/**\n * Coverage detection utilities for vitest projects.\n *\n * Detects vitest installation, configuration, and coverage data.\n */\n\nimport { existsSync, readFileSync, statSync } from \"fs\";\nimport { join } from \"path\";\n\nexport interface CoverageSetupInfo {\n /** Whether vitest is in dependencies */\n hasVitest: boolean;\n /** Whether vitest config exists */\n hasVitestConfig: boolean;\n /** Path to vitest config if found */\n vitestConfigPath: string | null;\n /** Whether coverage is configured in vitest */\n hasCoverageConfig: boolean;\n /** Coverage provider (v8 or istanbul) */\n coverageProvider: \"v8\" | \"istanbul\" | null;\n /** Whether coverage data file exists */\n hasCoverageData: boolean;\n /** Path to coverage data */\n coverageDataPath: string | null;\n\n // Preparation flags\n /** Whether @vitest/coverage-v8 (or coverage-istanbul) package is missing */\n needsCoveragePackage: boolean;\n /** Whether vitest.config needs coverage block added */\n needsCoverageConfig: boolean;\n /** Age of coverage data in milliseconds (null if no data) */\n coverageDataAge: number | null;\n}\n\nconst VITEST_CONFIG_FILES = [\n \"vitest.config.ts\",\n \"vitest.config.js\",\n \"vitest.config.mts\",\n \"vitest.config.mjs\",\n];\n\ninterface PackageDepsInfo {\n hasVitest: boolean;\n hasCoveragePackage: boolean;\n}\n\n/**\n * Check if vitest and coverage packages are in package.json\n */\nfunction checkPackageDeps(projectPath: string): PackageDepsInfo {\n try {\n const pkgPath = join(projectPath, \"package.json\");\n if (!existsSync(pkgPath)) return { hasVitest: false, hasCoveragePackage: false };\n\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n\n const deps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };\n const hasVitest = \"vitest\" in deps;\n const hasCoveragePackage =\n \"@vitest/coverage-v8\" in deps || \"@vitest/coverage-istanbul\" in deps;\n\n return { hasVitest, hasCoveragePackage };\n } catch {\n return { hasVitest: false, hasCoveragePackage: false };\n }\n}\n\n/**\n * Find the vitest config file in the project\n */\nfunction findVitestConfig(projectPath: string): string | null {\n for (const configFile of VITEST_CONFIG_FILES) {\n const configPath = join(projectPath, configFile);\n if (existsSync(configPath)) {\n return configPath;\n }\n }\n return null;\n}\n\n/**\n * Parse vitest config to extract coverage settings\n */\nfunction parseCoverageConfig(configPath: string): {\n hasCoverageConfig: boolean;\n coverageProvider: \"v8\" | \"istanbul\" | null;\n} {\n try {\n const content = readFileSync(configPath, \"utf-8\");\n\n // Check if coverage block exists using regex\n const hasCoverageConfig = /coverage\\s*:\\s*\\{/.test(content);\n\n if (!hasCoverageConfig) {\n return { hasCoverageConfig: false, coverageProvider: null };\n }\n\n // Extract provider value using regex\n // Match patterns like: provider: \"v8\", provider: 'v8', provider: \"istanbul\", etc.\n const providerMatch = content.match(/provider\\s*:\\s*[\"']?(v8|istanbul)[\"']?/);\n const coverageProvider = providerMatch\n ? (providerMatch[1] as \"v8\" | \"istanbul\")\n : null;\n\n return { hasCoverageConfig, coverageProvider };\n } catch {\n return { hasCoverageConfig: false, coverageProvider: null };\n }\n}\n\n/**\n * Check if coverage data file exists and get its age\n */\nfunction findCoverageData(projectPath: string): {\n path: string | null;\n age: number | null;\n} {\n const coverageDataPath = join(projectPath, \"coverage\", \"coverage-final.json\");\n if (existsSync(coverageDataPath)) {\n try {\n const stats = statSync(coverageDataPath);\n const age = Date.now() - stats.mtimeMs;\n return { path: coverageDataPath, age };\n } catch {\n return { path: coverageDataPath, age: null };\n }\n }\n return { path: null, age: null };\n}\n\n/**\n * Detect coverage setup in a project\n */\nexport function detectCoverageSetup(projectPath: string): CoverageSetupInfo {\n const { hasVitest, hasCoveragePackage } = checkPackageDeps(projectPath);\n const vitestConfigPath = findVitestConfig(projectPath);\n const hasVitestConfig = vitestConfigPath !== null;\n\n let hasCoverageConfig = false;\n let coverageProvider: \"v8\" | \"istanbul\" | null = null;\n\n if (vitestConfigPath) {\n const coverageInfo = parseCoverageConfig(vitestConfigPath);\n hasCoverageConfig = coverageInfo.hasCoverageConfig;\n coverageProvider = coverageInfo.coverageProvider;\n }\n\n const coverageData = findCoverageData(projectPath);\n const hasCoverageData = coverageData.path !== null;\n\n // Compute preparation flags\n const needsCoveragePackage = hasVitest && !hasCoveragePackage;\n const needsCoverageConfig = hasVitest && hasVitestConfig && !hasCoverageConfig;\n\n return {\n hasVitest,\n hasVitestConfig,\n vitestConfigPath,\n hasCoverageConfig,\n coverageProvider,\n hasCoverageData,\n coverageDataPath: coverageData.path,\n needsCoveragePackage,\n needsCoverageConfig,\n coverageDataAge: coverageData.age,\n };\n}\n","import { existsSync, readdirSync } from \"fs\";\nimport { join } from \"path\";\n\nexport interface NextAppRouterDetection {\n /**\n * Relative path to the Next App Router root dir (either \"app\" or \"src/app\").\n */\n appRoot: string;\n /**\n * Absolute path to the App Router root dir.\n */\n appRootAbs: string;\n /**\n * Candidate entry files (relative paths) that are good injection targets.\n */\n candidates: string[];\n}\n\nfunction fileExists(projectPath: string, relPath: string): boolean {\n return existsSync(join(projectPath, relPath));\n}\n\nexport function detectNextAppRouter(\n projectPath: string\n): NextAppRouterDetection | null {\n const roots = [\"app\", join(\"src\", \"app\")];\n const candidates: string[] = [];\n\n let chosenRoot: string | null = null;\n for (const root of roots) {\n if (existsSync(join(projectPath, root))) {\n chosenRoot = root;\n break;\n }\n }\n\n if (!chosenRoot) return null;\n\n // Prioritize layout files (Next App Router canonical integration point).\n const entryCandidates = [\n join(chosenRoot, \"layout.tsx\"),\n join(chosenRoot, \"layout.jsx\"),\n join(chosenRoot, \"layout.ts\"),\n join(chosenRoot, \"layout.js\"),\n // Fallbacks (less ideal, but can work):\n join(chosenRoot, \"page.tsx\"),\n join(chosenRoot, \"page.jsx\"),\n ];\n\n for (const rel of entryCandidates) {\n if (fileExists(projectPath, rel)) candidates.push(rel);\n }\n\n // If nothing exists, still return detection so routes can be installed.\n return {\n appRoot: chosenRoot,\n appRootAbs: join(projectPath, chosenRoot),\n candidates,\n };\n}\n\nexport interface NextAppRouterProjectMatch {\n /**\n * Absolute path to the Next project root (dir containing app/ or src/app/).\n */\n projectPath: string;\n detection: NextAppRouterDetection;\n}\n\nconst DEFAULT_IGNORE_DIRS = new Set([\n \"node_modules\",\n \".git\",\n \".next\",\n \"dist\",\n \"build\",\n \"out\",\n \".turbo\",\n \".vercel\",\n \".cursor\",\n \"coverage\",\n \".uilint\",\n]);\n\n/**\n * Best-effort monorepo discovery for Next.js App Router apps.\n *\n * Walks down from `rootDir` looking for directories that contain `app/` or\n * `src/app/`. Skips common large/irrelevant dirs.\n */\nexport function findNextAppRouterProjects(\n rootDir: string,\n options?: { maxDepth?: number; ignoreDirs?: Set<string> }\n): NextAppRouterProjectMatch[] {\n const maxDepth = options?.maxDepth ?? 4;\n const ignoreDirs = options?.ignoreDirs ?? DEFAULT_IGNORE_DIRS;\n const results: NextAppRouterProjectMatch[] = [];\n const visited = new Set<string>();\n\n function walk(dir: string, depth: number) {\n if (depth > maxDepth) return;\n if (visited.has(dir)) return;\n visited.add(dir);\n\n const detection = detectNextAppRouter(dir);\n if (detection) {\n results.push({ projectPath: dir, detection });\n // Don't descend further once we found a project root (avoid nested hits).\n return;\n }\n\n let entries: Array<{ name: string; isDirectory: boolean }> = [];\n try {\n entries = readdirSync(dir, { withFileTypes: true }).map((d) => ({\n name: d.name,\n isDirectory: d.isDirectory(),\n }));\n } catch {\n return;\n }\n\n for (const ent of entries) {\n if (!ent.isDirectory) continue;\n if (ignoreDirs.has(ent.name)) continue;\n // Skip hidden dirs by default (except `src` which matters)\n if (ent.name.startsWith(\".\") && ent.name !== \".\") continue;\n walk(join(dir, ent.name), depth + 1);\n }\n }\n\n walk(rootDir, 0);\n return results;\n}\n","/**\n * Inject uilint-eslint rules into ESLint config\n *\n * Modifies eslint.config.{ts,mjs,js,cjs} to add uilint import and selected rules\n */\n\nimport { existsSync, readFileSync, writeFileSync } from \"fs\";\nimport { join, relative, dirname } from \"path\";\nimport type { RuleMetadata } from \"uilint-eslint\";\nimport { parseExpression, parseModule, generateCode } from \"magicast\";\nimport { findWorkspaceRoot } from \"uilint-core/node\";\n\nexport interface InstallEslintPluginOptions {\n projectPath: string;\n selectedRules: RuleMetadata[];\n force?: boolean;\n confirmAddMissingRules?: (\n relPath: string,\n missingRules: RuleMetadata[]\n ) => Promise<boolean>;\n}\n\nconst CONFIG_EXTENSIONS = [\".ts\", \".mjs\", \".js\", \".cjs\"];\n\n/**\n * Find the eslint.config file in a project\n */\nexport function findEslintConfigFile(projectPath: string): string | null {\n for (const ext of CONFIG_EXTENSIONS) {\n const configPath = join(projectPath, `eslint.config${ext}`);\n if (existsSync(configPath)) {\n return configPath;\n }\n }\n return null;\n}\n\n/**\n * Get the relative config filename for display\n */\nexport function getEslintConfigFilename(configPath: string): string {\n const parts = configPath.split(\"/\");\n return parts[parts.length - 1] || \"eslint.config.mjs\";\n}\n\n/**\n * Check if the source already has uilint rules configured\n */\nfunction hasUilintRules(source: string): boolean {\n return source.includes('\"uilint/') || source.includes(\"'uilint/\");\n}\n\n/**\n * Check if the source already has uilint imported\n */\nfunction hasUilintImport(source: string): boolean {\n return (\n source.includes('from \"uilint-eslint\"') ||\n source.includes(\"from 'uilint-eslint'\") ||\n source.includes('require(\"uilint-eslint\")') ||\n source.includes(\"require('uilint-eslint')\")\n );\n}\n\ntype UilintEslintConfigInfo = {\n /** Set of configured `uilint/*` rule IDs (without the `uilint/` prefix). */\n configuredRuleIds: Set<string>;\n /** Whether config appears to configure uilint rules. */\n configured: boolean;\n};\n\nfunction walkAst(node: any, visit: (n: any) => void): void {\n if (!node || typeof node !== \"object\") return;\n visit(node);\n for (const key of Object.keys(node)) {\n const v = (node as any)[key];\n if (!v) continue;\n if (Array.isArray(v)) {\n for (const item of v) walkAst(item, visit);\n } else if (typeof v === \"object\" && v.type) {\n walkAst(v, visit);\n }\n }\n}\n\nfunction isIdentifier(node: any, name?: string): boolean {\n return (\n !!node &&\n node.type === \"Identifier\" &&\n (name ? node.name === name : typeof node.name === \"string\")\n );\n}\n\nfunction isStringLiteral(node: any): node is { type: string; value: string } {\n return (\n !!node &&\n (node.type === \"StringLiteral\" || node.type === \"Literal\") &&\n typeof node.value === \"string\"\n );\n}\n\nfunction getObjectPropertyValue(obj: any, keyName: string): any | null {\n if (!obj || obj.type !== \"ObjectExpression\") return null;\n for (const prop of obj.properties ?? []) {\n if (!prop) continue;\n if (prop.type === \"ObjectProperty\" || prop.type === \"Property\") {\n const key = prop.key;\n const keyMatch =\n (key?.type === \"Identifier\" && key.name === keyName) ||\n (isStringLiteral(key) && key.value === keyName);\n if (keyMatch) return prop.value;\n }\n }\n return null;\n}\n\nfunction hasSpreadProperties(obj: any): boolean {\n if (!obj || obj.type !== \"ObjectExpression\") return false;\n return (obj.properties ?? []).some(\n (p: any) => p && (p.type === \"SpreadElement\" || p.type === \"SpreadProperty\")\n );\n}\n\nconst IGNORED_AST_KEYS = new Set([\n \"loc\",\n \"start\",\n \"end\",\n \"extra\",\n \"leadingComments\",\n \"trailingComments\",\n \"innerComments\",\n]);\n\nfunction normalizeAstForCompare(node: any): any {\n if (node === null) return null;\n if (node === undefined) return undefined;\n if (typeof node !== \"object\") return node;\n if (Array.isArray(node)) return node.map(normalizeAstForCompare);\n\n const out: Record<string, any> = {};\n const keys = Object.keys(node)\n .filter((k) => !IGNORED_AST_KEYS.has(k))\n .sort();\n for (const k of keys) {\n // Avoid proxy-ish or non-serializable fields if present.\n if (k.startsWith(\"$\")) continue;\n out[k] = normalizeAstForCompare(node[k]);\n }\n return out;\n}\n\nfunction astEquivalent(a: any, b: any): boolean {\n try {\n return (\n JSON.stringify(normalizeAstForCompare(a)) ===\n JSON.stringify(normalizeAstForCompare(b))\n );\n } catch {\n return false;\n }\n}\n\nfunction collectUilintRuleIdsFromRulesObject(rulesObj: any): Set<string> {\n const ids = new Set<string>();\n if (!rulesObj || rulesObj.type !== \"ObjectExpression\") return ids;\n for (const prop of rulesObj.properties ?? []) {\n if (!prop) continue;\n if (prop.type !== \"ObjectProperty\" && prop.type !== \"Property\") continue;\n const key = prop.key;\n if (!isStringLiteral(key)) continue;\n const val = key.value;\n if (typeof val !== \"string\") continue;\n if (val.startsWith(\"uilint/\")) {\n ids.add(val.slice(\"uilint/\".length));\n }\n }\n return ids;\n}\n\nfunction findExportedConfigArrayExpression(mod: any): {\n kind: \"esm\" | \"cjs\";\n arrayExpr: any;\n program: any;\n} | null {\n function unwrapExpression(expr: any): any {\n let e = expr;\n // Best-effort unwrap for TS/parenthesized wrappers. (These can appear if the\n // config is authored in TS/JS with type assertions or parentheses.)\n while (e) {\n if (e.type === \"TSAsExpression\" || e.type === \"TSNonNullExpression\") {\n e = e.expression;\n continue;\n }\n if (e.type === \"TSSatisfiesExpression\") {\n e = e.expression;\n continue;\n }\n if (e.type === \"ParenthesizedExpression\") {\n e = e.expression;\n continue;\n }\n break;\n }\n return e;\n }\n\n function resolveTopLevelIdentifierToArrayExpr(\n program: any,\n name: string\n ): any | null {\n if (!program || program.type !== \"Program\") return null;\n for (const stmt of program.body ?? []) {\n if (stmt?.type !== \"VariableDeclaration\") continue;\n for (const decl of stmt.declarations ?? []) {\n const id = decl?.id;\n if (!isIdentifier(id, name)) continue;\n const init = unwrapExpression(decl?.init);\n if (!init) return null;\n if (init.type === \"ArrayExpression\") return init;\n if (\n init.type === \"CallExpression\" &&\n isIdentifier(init.callee, \"defineConfig\") &&\n unwrapExpression(init.arguments?.[0])?.type === \"ArrayExpression\"\n ) {\n return unwrapExpression(init.arguments?.[0]);\n }\n return null;\n }\n }\n return null;\n }\n\n // Prefer reading directly from the program AST so we can handle:\n // - export default [ ... ]\n // - export default defineConfig([ ... ])\n // - export default eslintConfig; (where eslintConfig is a top-level array)\n const program = mod?.$ast;\n if (program && program.type === \"Program\") {\n for (const stmt of program.body ?? []) {\n if (!stmt || stmt.type !== \"ExportDefaultDeclaration\") continue;\n const decl = unwrapExpression(stmt.declaration);\n if (!decl) break;\n\n if (decl.type === \"ArrayExpression\") {\n return { kind: \"esm\", arrayExpr: decl, program };\n }\n if (\n decl.type === \"CallExpression\" &&\n isIdentifier(decl.callee, \"defineConfig\") &&\n unwrapExpression(decl.arguments?.[0])?.type === \"ArrayExpression\"\n ) {\n return {\n kind: \"esm\",\n arrayExpr: unwrapExpression(decl.arguments?.[0]),\n program,\n };\n }\n if (decl.type === \"Identifier\" && typeof decl.name === \"string\") {\n const resolved = resolveTopLevelIdentifierToArrayExpr(\n program,\n decl.name\n );\n if (resolved) return { kind: \"esm\", arrayExpr: resolved, program };\n }\n break;\n }\n }\n\n // CommonJS: module.exports = [ ... ] OR module.exports = defineConfig([ ... ])\n if (!program || program.type !== \"Program\") return null;\n\n for (const stmt of program.body ?? []) {\n if (!stmt || stmt.type !== \"ExpressionStatement\") continue;\n const expr = stmt.expression;\n if (!expr || expr.type !== \"AssignmentExpression\") continue;\n const left = expr.left;\n const right = expr.right;\n const isModuleExports =\n left?.type === \"MemberExpression\" &&\n isIdentifier(left.object, \"module\") &&\n isIdentifier(left.property, \"exports\");\n if (!isModuleExports) continue;\n\n if (right?.type === \"ArrayExpression\") {\n return { kind: \"cjs\", arrayExpr: right, program };\n }\n if (\n right?.type === \"CallExpression\" &&\n isIdentifier(right.callee, \"defineConfig\") &&\n right.arguments?.[0]?.type === \"ArrayExpression\"\n ) {\n return { kind: \"cjs\", arrayExpr: right.arguments[0], program };\n }\n if (right?.type === \"Identifier\" && typeof right.name === \"string\") {\n const resolved = resolveTopLevelIdentifierToArrayExpr(\n program,\n right.name\n );\n if (resolved) return { kind: \"cjs\", arrayExpr: resolved, program };\n }\n }\n\n return null;\n}\n\nfunction collectConfiguredUilintRuleIdsFromConfigArray(\n arrayExpr: any\n): Set<string> {\n const ids = new Set<string>();\n if (!arrayExpr || arrayExpr.type !== \"ArrayExpression\") return ids;\n for (const el of arrayExpr.elements ?? []) {\n if (!el || el.type !== \"ObjectExpression\") continue;\n const rules = getObjectPropertyValue(el, \"rules\");\n for (const id of collectUilintRuleIdsFromRulesObject(rules)) ids.add(id);\n }\n return ids;\n}\n\nfunction findExistingUilintRulesObject(arrayExpr: any): {\n configObj: any | null;\n rulesObj: any | null;\n safeToMutate: boolean;\n} {\n if (!arrayExpr || arrayExpr.type !== \"ArrayExpression\") {\n return { configObj: null, rulesObj: null, safeToMutate: false };\n }\n\n for (const el of arrayExpr.elements ?? []) {\n if (!el || el.type !== \"ObjectExpression\") continue;\n\n const plugins = getObjectPropertyValue(el, \"plugins\");\n const rules = getObjectPropertyValue(el, \"rules\");\n\n const hasUilintPlugin =\n plugins?.type === \"ObjectExpression\" &&\n getObjectPropertyValue(plugins, \"uilint\") !== null;\n\n const uilintIds = collectUilintRuleIdsFromRulesObject(rules);\n const hasUilintRules = uilintIds.size > 0;\n\n if (!hasUilintPlugin && !hasUilintRules) continue;\n\n const safe =\n rules?.type === \"ObjectExpression\" && !hasSpreadProperties(rules);\n return { configObj: el, rulesObj: rules, safeToMutate: safe };\n }\n\n return { configObj: null, rulesObj: null, safeToMutate: false };\n}\n\nfunction collectTopLevelBindings(program: any): Set<string> {\n const names = new Set<string>();\n if (!program || program.type !== \"Program\") return names;\n\n for (const stmt of program.body ?? []) {\n if (stmt?.type === \"ImportDeclaration\") {\n for (const spec of stmt.specifiers ?? []) {\n const local = spec?.local;\n if (local?.type === \"Identifier\" && typeof local.name === \"string\") {\n names.add(local.name);\n }\n }\n continue;\n }\n if (stmt?.type === \"VariableDeclaration\") {\n for (const decl of stmt.declarations ?? []) {\n const id = decl?.id;\n if (id?.type === \"Identifier\" && typeof id.name === \"string\") {\n names.add(id.name);\n }\n }\n } else if (stmt?.type === \"FunctionDeclaration\") {\n if (stmt.id?.type === \"Identifier\" && typeof stmt.id.name === \"string\") {\n names.add(stmt.id.name);\n }\n }\n }\n return names;\n}\n\nfunction chooseUniqueIdentifier(base: string, used: Set<string>): string {\n if (!used.has(base)) return base;\n let i = 2;\n while (used.has(`${base}${i}`)) i++;\n return `${base}${i}`;\n}\n\nfunction findExistingDefaultImportLocalName(\n program: any,\n from: string\n): string | null {\n if (!program || program.type !== \"Program\") return null;\n for (const stmt of program.body ?? []) {\n if (stmt?.type !== \"ImportDeclaration\") continue;\n const src = stmt.source?.value;\n if (typeof src !== \"string\" || src !== from) continue;\n for (const spec of stmt.specifiers ?? []) {\n if (spec?.type === \"ImportDefaultSpecifier\") {\n const local = spec.local;\n if (local?.type === \"Identifier\" && typeof local.name === \"string\") {\n return local.name;\n }\n }\n }\n }\n return null;\n}\n\n/**\n * Add imports for local rules from .uilint/rules/\n */\nfunction addLocalRuleImportsAst(\n mod: any,\n selectedRules: RuleMetadata[],\n configPath: string,\n rulesRoot: string,\n fileExtension: string = \".js\",\n isTypeScriptProject: boolean = false\n): { importNames: Map<string, string>; changed: boolean } {\n const importNames = new Map<string, string>();\n let changed = false;\n\n // Calculate relative path from config file to .uilint/rules/\n const configDir = dirname(configPath);\n const rulesDir = join(rulesRoot, \".uilint\", \"rules\");\n const relativeRulesPath = relative(configDir, rulesDir).replace(/\\\\/g, \"/\");\n\n // Ensure it starts with ./ or ../ (note: `.foo` is NOT a valid relative import)\n const normalizedRulesPath =\n relativeRulesPath.startsWith(\"./\") || relativeRulesPath.startsWith(\"../\")\n ? relativeRulesPath\n : `./${relativeRulesPath}`;\n\n const used = collectTopLevelBindings(mod.$ast);\n\n for (const rule of selectedRules) {\n // Directory-based rules use /index for TypeScript projects only\n // For JavaScript projects, all rules are bundled to single .js files\n const rulePath = (rule.isDirectoryBased && isTypeScriptProject)\n ? `${normalizedRulesPath}/${rule.id}/index${fileExtension}`\n : `${normalizedRulesPath}/${rule.id}${fileExtension}`;\n\n // If the import already exists (possibly with a different local name),\n // reuse it. Magicast can't always rename existing imports.\n const existingLocal = findExistingDefaultImportLocalName(mod.$ast, rulePath);\n if (existingLocal) {\n importNames.set(rule.id, existingLocal);\n used.add(existingLocal);\n continue;\n }\n\n // Generate a safe import name (e.g., noArbitraryTailwindRule)\n const importName = chooseUniqueIdentifier(\n `${rule.id\n .replace(/-([a-z])/g, (_: string, c: string) => c.toUpperCase())\n .replace(/^./, (c: string) => c.toUpperCase())}Rule`,\n used\n );\n importNames.set(rule.id, importName);\n used.add(importName);\n\n // Add import statement\n mod.imports.$add({\n imported: \"default\",\n local: importName,\n from: rulePath,\n });\n changed = true;\n }\n\n return { importNames, changed };\n}\n\n/**\n * Add require statements for local rules (CommonJS)\n */\nfunction addLocalRuleRequiresAst(\n program: any,\n selectedRules: RuleMetadata[],\n configPath: string,\n rulesRoot: string,\n fileExtension: string = \".js\",\n isTypeScriptProject: boolean = false\n): { importNames: Map<string, string>; changed: boolean } {\n const importNames = new Map<string, string>();\n let changed = false;\n\n if (!program || program.type !== \"Program\") {\n return { importNames, changed };\n }\n\n // Calculate relative path from config file to .uilint/rules/\n const configDir = dirname(configPath);\n const rulesDir = join(rulesRoot, \".uilint\", \"rules\");\n const relativeRulesPath = relative(configDir, rulesDir).replace(/\\\\/g, \"/\");\n\n // Ensure it starts with ./ or ../ (note: `.foo` is NOT a valid relative require)\n const normalizedRulesPath =\n relativeRulesPath.startsWith(\"./\") || relativeRulesPath.startsWith(\"../\")\n ? relativeRulesPath\n : `./${relativeRulesPath}`;\n\n const used = collectTopLevelBindings(program);\n\n for (const rule of selectedRules) {\n // Generate a safe import name\n const importName = chooseUniqueIdentifier(\n `${rule.id\n .replace(/-([a-z])/g, (_: string, c: string) => c.toUpperCase())\n .replace(/^./, (c: string) => c.toUpperCase())}Rule`,\n used\n );\n importNames.set(rule.id, importName);\n used.add(importName);\n\n // Add require statement\n // Directory-based rules use /index for TypeScript projects only\n // For JavaScript projects, all rules are bundled to single .js files\n const rulePath = (rule.isDirectoryBased && isTypeScriptProject)\n ? `${normalizedRulesPath}/${rule.id}/index${fileExtension}`\n : `${normalizedRulesPath}/${rule.id}${fileExtension}`;\n const stmtMod = parseModule(\n `const ${importName} = require(\"${rulePath}\");`\n );\n const stmt = (stmtMod.$ast as any).body?.[0];\n if (stmt) {\n // Place after a leading \"use strict\" if present.\n let insertAt = 0;\n const first = program.body?.[0];\n if (\n first?.type === \"ExpressionStatement\" &&\n first.expression?.type === \"StringLiteral\" &&\n first.expression.value === \"use strict\"\n ) {\n insertAt = 1;\n }\n program.body.splice(insertAt, 0, stmt);\n changed = true;\n }\n }\n\n return { importNames, changed };\n}\n\nfunction appendUilintConfigBlockToArray(\n arrayExpr: any,\n selectedRules: RuleMetadata[],\n ruleImportNames: Map<string, string>\n): void {\n // Build plugin object with local rule imports\n const pluginRulesCode = Array.from(ruleImportNames.entries())\n .map(([ruleId, importName]) => ` \"${ruleId}\": ${importName},`)\n .join(\"\\n\");\n\n const rulesPropsCode = selectedRules\n .map((r) => {\n const ruleKey = `uilint/${r.id}`;\n const valueCode =\n r.defaultOptions && r.defaultOptions.length > 0\n ? `[\"${r.defaultSeverity}\", ...${JSON.stringify(\n r.defaultOptions,\n null,\n 2\n )}]`\n : `\"${r.defaultSeverity}\"`;\n return ` \"${ruleKey}\": ${valueCode},`;\n })\n .join(\"\\n\");\n\n const blockCode = `{\n files: [\n \"src/**/*.{js,jsx,ts,tsx}\",\n \"app/**/*.{js,jsx,ts,tsx}\",\n \"pages/**/*.{js,jsx,ts,tsx}\",\n ],\n plugins: {\n uilint: {\n rules: {\n${pluginRulesCode}\n },\n },\n },\n rules: {\n${rulesPropsCode}\n },\n }`;\n\n const objExpr = (parseExpression(blockCode) as any).$ast;\n arrayExpr.elements.push(objExpr);\n}\n\nfunction getUilintEslintConfigInfoFromSourceAst(source: string):\n | {\n info: UilintEslintConfigInfo;\n mod: any;\n arrayExpr: any;\n kind: \"esm\" | \"cjs\";\n }\n | { error: string } {\n try {\n const mod = parseModule(source);\n const found = findExportedConfigArrayExpression(mod);\n if (!found) {\n return {\n error:\n \"Could not locate an exported ESLint flat config array (expected `export default [...]`, `export default defineConfig([...])`, `module.exports = [...]`, or `module.exports = defineConfig([...])`).\",\n };\n }\n\n const configuredRuleIds = collectConfiguredUilintRuleIdsFromConfigArray(\n found.arrayExpr\n );\n const existingUilint = findExistingUilintRulesObject(found.arrayExpr);\n const configured =\n configuredRuleIds.size > 0 || existingUilint.configObj !== null;\n\n return {\n info: { configuredRuleIds, configured },\n mod,\n arrayExpr: found.arrayExpr,\n kind: found.kind,\n };\n } catch {\n return {\n error:\n \"Unable to parse ESLint config as JavaScript. Please update it manually or simplify the config so it can be safely auto-modified.\",\n };\n }\n}\n\nexport function getUilintEslintConfigInfoFromSource(\n source: string\n): UilintEslintConfigInfo {\n const ast = getUilintEslintConfigInfoFromSourceAst(source);\n if (\"error\" in ast) {\n // Fallback (best-effort) to string heuristics for scan-only scenarios.\n const configuredRuleIds = extractConfiguredUilintRuleIds(source);\n return {\n configuredRuleIds,\n configured: configuredRuleIds.size > 0,\n };\n }\n return ast.info;\n}\n\nfunction findEsmExportedConfigArrayStartIndex(source: string): number | null {\n // Supported:\n // - export default [ ... ]\n // - export default defineConfig([ ... ])\n const patterns: RegExp[] = [\n /export\\s+default\\s+\\[/,\n /export\\s+default\\s+defineConfig\\s*\\(\\s*\\[/,\n ];\n\n for (const re of patterns) {\n const m = source.match(re);\n if (!m || m.index === undefined) continue;\n return m.index + m[0].length;\n }\n\n return null;\n}\n\nfunction findCommonJsExportedConfigArrayStartIndex(\n source: string\n): number | null {\n // Supported:\n // - module.exports = [ ... ]\n // - module.exports = defineConfig([ ... ]) (best-effort)\n const patterns: RegExp[] = [\n /module\\.exports\\s*=\\s*\\[/,\n /module\\.exports\\s*=\\s*defineConfig\\s*\\(\\s*\\[/,\n ];\n\n for (const re of patterns) {\n const m = source.match(re);\n if (!m || m.index === undefined) continue;\n return m.index + m[0].length;\n }\n\n return null;\n}\n\n/**\n * Extract configured uilint rule IDs from source.\n * Matches keys like: \"uilint/no-arbitrary-tailwind\": \"error\"\n */\nfunction extractConfiguredUilintRuleIds(source: string): Set<string> {\n const ids = new Set<string>();\n const re = /[\"']uilint\\/([^\"']+)[\"']\\s*:/g;\n for (const m of source.matchAll(re)) {\n if (m[1]) ids.add(m[1]);\n }\n return ids;\n}\n\nfunction getMissingSelectedRules(\n selectedRules: RuleMetadata[],\n configuredIds: Set<string>\n): RuleMetadata[] {\n return selectedRules.filter((r) => !configuredIds.has(r.id));\n}\n\n/**\n * Get rules that exist but need updating (different options or severity)\n */\nfunction buildDesiredRuleValueExpression(rule: RuleMetadata): string {\n if (rule.defaultOptions && rule.defaultOptions.length > 0) {\n // Match the shape we generate elsewhere: [\"severity\", ...[options...]]\n return `[\"${rule.defaultSeverity}\", ...${JSON.stringify(\n rule.defaultOptions,\n null,\n 2\n )}]`;\n }\n return `\"${rule.defaultSeverity}\"`;\n}\n\nfunction collectUilintRuleValueNodesFromConfigArray(\n arrayExpr: any\n): Map<string, any> {\n const out = new Map<string, any>();\n if (!arrayExpr || arrayExpr.type !== \"ArrayExpression\") return out;\n\n for (const el of arrayExpr.elements ?? []) {\n if (!el || el.type !== \"ObjectExpression\") continue;\n const rules = getObjectPropertyValue(el, \"rules\");\n if (!rules || rules.type !== \"ObjectExpression\") continue;\n\n for (const prop of rules.properties ?? []) {\n if (!prop) continue;\n if (prop.type !== \"ObjectProperty\" && prop.type !== \"Property\") continue;\n const key = prop.key;\n if (!isStringLiteral(key)) continue;\n const k = key.value;\n if (typeof k !== \"string\" || !k.startsWith(\"uilint/\")) continue;\n const id = k.slice(\"uilint/\".length);\n // First occurrence wins; that's enough for detecting up-to-date configs.\n if (!out.has(id)) out.set(id, prop.value);\n }\n }\n\n return out;\n}\n\nfunction getRulesNeedingUpdate(\n selectedRules: RuleMetadata[],\n configuredIds: Set<string>,\n arrayExpr: any\n): RuleMetadata[] {\n // Only consider rules that are already configured, and only update if the\n // existing severity/options differ from what we would generate.\n const existingVals = collectUilintRuleValueNodesFromConfigArray(arrayExpr);\n\n return selectedRules.filter((r) => {\n if (!configuredIds.has(r.id)) return false;\n const existing = existingVals.get(r.id);\n if (!existing) return true;\n\n const desiredExpr = buildDesiredRuleValueExpression(r);\n const desiredAst = (parseExpression(desiredExpr) as any).$ast;\n return !astEquivalent(existing, desiredAst);\n });\n}\n\n/**\n * Generate a single rule config string\n */\nfunction generateSingleRuleConfig(rule: RuleMetadata): string {\n const ruleKey = `\"uilint/${rule.id}\"`;\n\n if (rule.defaultOptions && rule.defaultOptions.length > 0) {\n // Rule with options\n const optionsStr = JSON.stringify(rule.defaultOptions, null, 6)\n .split(\"\\n\")\n .join(\"\\n \");\n return ` ${ruleKey}: [\"${rule.defaultSeverity}\", ...${optionsStr}],`;\n } else {\n // Simple rule\n return ` ${ruleKey}: \"${rule.defaultSeverity}\",`;\n }\n}\n\n/**\n * Add the uilint import to the source if not present\n */\nfunction ensureUilintImport(source: string, isCommonJS: boolean): string {\n if (hasUilintImport(source)) {\n return source;\n }\n\n const importLine = isCommonJS\n ? `const uilint = require(\"uilint-eslint\");\\n`\n : `import uilint from \"uilint-eslint\";\\n`;\n\n // Find the last import/require statement and insert after it\n const header = source.slice(0, Math.min(source.length, 5000));\n const importRegex = isCommonJS\n ? /^(?:const|var|let)\\s+.*?=\\s*require\\([^)]+\\);?\\s*$/gm\n : /^import[\\s\\S]*?;\\s*$/gm;\n\n let lastImportEnd = -1;\n for (const m of header.matchAll(importRegex)) {\n lastImportEnd = (m.index ?? 0) + m[0].length;\n }\n\n if (lastImportEnd !== -1) {\n return (\n source.slice(0, lastImportEnd) +\n \"\\n\" +\n importLine +\n source.slice(lastImportEnd)\n );\n }\n\n // No imports found, add at the beginning\n return importLine + source;\n}\n\n/**\n * Generate the rules config object from selected rules\n */\nfunction generateRulesConfig(selectedRules: RuleMetadata[]): string {\n const lines: string[] = [];\n\n for (const rule of selectedRules) {\n const ruleKey = `\"uilint/${rule.id}\"`;\n\n if (rule.defaultOptions && rule.defaultOptions.length > 0) {\n // Rule with options\n const optionsStr = JSON.stringify(rule.defaultOptions, null, 6)\n .split(\"\\n\")\n .join(\"\\n \");\n lines.push(\n ` ${ruleKey}: [\"${rule.defaultSeverity}\", ...${optionsStr}],`\n );\n } else {\n // Simple rule\n lines.push(` ${ruleKey}: \"${rule.defaultSeverity}\",`);\n }\n }\n\n return lines.join(\"\\n\");\n}\n\nfunction detectIndent(source: string, index: number): string {\n const lineStart = source.lastIndexOf(\"\\n\", index);\n const start = lineStart === -1 ? 0 : lineStart + 1;\n const line = source.slice(start, index);\n const m = line.match(/^\\s*/);\n return m?.[0] ?? \"\";\n}\n\n/**\n * Insert missing uilint rule keys into an existing `rules: { ... }` object\n * that already contains at least one \"uilint/\" key.\n *\n * This is intentionally a best-effort string transform (no JS AST dependency).\n */\nfunction insertMissingRulesIntoExistingRulesObject(\n source: string,\n missingRules: RuleMetadata[]\n): string {\n if (missingRules.length === 0) return source;\n\n // Anchor on an existing uilint rule key, then look backwards for the\n // nearest `rules:` preceding it.\n const uilintKeyMatch = source.match(/[\"']uilint\\/[^\"']+[\"']\\s*:/);\n if (!uilintKeyMatch || uilintKeyMatch.index === undefined) return source;\n\n const uilintKeyIndex = uilintKeyMatch.index;\n const searchStart = Math.max(0, uilintKeyIndex - 4000);\n const before = source.slice(searchStart, uilintKeyIndex);\n const rulesKwIndexRel = before.lastIndexOf(\"rules\");\n if (rulesKwIndexRel === -1) return source;\n\n const rulesKwIndex = searchStart + rulesKwIndexRel;\n const braceOpenIndex = source.indexOf(\"{\", rulesKwIndex);\n if (braceOpenIndex === -1 || braceOpenIndex > uilintKeyIndex) return source;\n\n // Find the matching closing brace for the rules object.\n let depth = 0;\n let braceCloseIndex = -1;\n for (let i = braceOpenIndex; i < source.length; i++) {\n const ch = source[i];\n if (ch === \"{\") depth++;\n else if (ch === \"}\") {\n depth--;\n if (depth === 0) {\n braceCloseIndex = i;\n break;\n }\n }\n }\n if (braceCloseIndex === -1) return source;\n\n const rulesIndent = detectIndent(source, braceOpenIndex);\n const entryIndent = rulesIndent + \" \";\n const entryTextRaw = generateRulesConfig(missingRules);\n const entryText = entryTextRaw\n .split(\"\\n\")\n .map((l) => (l.trim().length === 0 ? l : entryIndent + l.trimStart()))\n .join(\"\\n\");\n\n const insertion =\n (source.slice(braceOpenIndex + 1, braceCloseIndex).trim().length === 0\n ? \"\\n\"\n : \"\\n\") +\n entryText +\n \"\\n\" +\n rulesIndent;\n\n return (\n source.slice(0, braceCloseIndex) + insertion + source.slice(braceCloseIndex)\n );\n}\n\n/**\n * Find the end of a rule value in the source code\n * Handles: \"error\", [\"error\"], [\"error\", {...}], [\"error\", ...[{...}]]\n */\nfunction findRuleValueEnd(source: string, startIndex: number): number {\n let pos = startIndex;\n let depth = 0;\n let inString = false;\n let stringChar = \"\";\n let foundArray = false;\n\n while (pos < source.length) {\n const ch = source[pos];\n const prevCh = pos > 0 ? source[pos - 1] : \"\";\n\n // Handle string literals\n if (!inString && (ch === '\"' || ch === \"'\")) {\n inString = true;\n stringChar = ch;\n } else if (inString && ch === stringChar && prevCh !== \"\\\\\") {\n inString = false;\n } else if (!inString) {\n // Track brackets/braces\n if (ch === \"[\") {\n depth++;\n foundArray = true;\n } else if (ch === \"]\") {\n depth--;\n if (depth === 0 && foundArray) {\n // Found the end of the array\n pos++;\n // Skip whitespace and include trailing comma if present\n while (pos < source.length && /\\s/.test(source[pos])) {\n pos++;\n }\n if (pos < source.length && source[pos] === \",\") {\n pos++;\n }\n return pos;\n }\n } else if (ch === \"{\" || ch === \"(\") {\n depth++;\n } else if (ch === \"}\" || ch === \")\") {\n depth--;\n } else if (!foundArray && depth === 0) {\n // Simple string value - ends at comma or closing brace\n if (ch === \",\" || ch === \"}\") {\n return pos + (ch === \",\" ? 1 : 0);\n }\n }\n }\n\n pos++;\n }\n\n return pos;\n}\n\n/**\n * Update existing uilint rule configurations with new options/severity\n *\n * This finds existing rule entries and replaces them with updated configurations.\n * Uses a more robust approach to handle multi-line rules with spread syntax.\n */\nfunction updateExistingRulesWithNewOptions(\n source: string,\n rulesToUpdate: RuleMetadata[]\n): string {\n if (rulesToUpdate.length === 0) return source;\n\n let updated = source;\n\n // Process rules in reverse order to avoid index shifting issues\n for (let i = rulesToUpdate.length - 1; i >= 0; i--) {\n const rule = rulesToUpdate[i]!;\n const ruleKeyPattern = new RegExp(\n `[\"']uilint/${rule.id.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")}[\"']\\\\s*:`,\n \"g\"\n );\n\n // Find all occurrences (should only be one, but be safe)\n const matches: Array<{ index: number; length: number }> = [];\n let match;\n while ((match = ruleKeyPattern.exec(updated)) !== null) {\n if (match.index !== undefined) {\n matches.push({ index: match.index, length: match[0].length });\n }\n }\n\n // Process matches in reverse order\n for (let j = matches.length - 1; j >= 0; j--) {\n const keyMatch = matches[j]!;\n const keyStart = keyMatch.index;\n const keyEnd = keyStart + keyMatch.length;\n\n // Find the value start (after colon and whitespace)\n let valueStart = keyEnd;\n while (valueStart < updated.length && /\\s/.test(updated[valueStart])) {\n valueStart++;\n }\n\n // Find the value end\n const valueEnd = findRuleValueEnd(updated, valueStart);\n\n // Generate new rule config\n const newRuleConfig = generateSingleRuleConfig(rule);\n\n // Find the indentation of the rule key line\n const indent = detectIndent(updated, keyStart);\n\n // Replace the old rule with the new one\n const before = updated.slice(0, keyStart);\n const after = updated.slice(valueEnd);\n\n updated = before + newRuleConfig + \"\\n\" + indent + after;\n }\n }\n\n return updated;\n}\n\n/**\n * Inject uilint rules into the export default array\n */\nfunction injectUilintRules(\n source: string,\n selectedRules: RuleMetadata[]\n): { source: string; injected: boolean } {\n if (hasUilintRules(source)) {\n // Already has uilint rules - don't inject again\n return { source, injected: false };\n }\n\n const rulesConfig = generateRulesConfig(selectedRules);\n\n const configBlock = ` {\n files: [\n \"src/**/*.{js,jsx,ts,tsx}\",\n \"app/**/*.{js,jsx,ts,tsx}\",\n \"pages/**/*.{js,jsx,ts,tsx}\",\n ],\n plugins: { uilint: uilint },\n rules: {\n${rulesConfig}\n },\n },`;\n\n const arrayStart = findEsmExportedConfigArrayStartIndex(source);\n if (arrayStart === null) {\n return { source, injected: false };\n }\n\n const afterExport = source.slice(arrayStart);\n\n // Insert at the beginning of the array (after opening bracket)\n // Add a newline if the array doesn't start on a new line\n const needsNewline = !afterExport.trimStart().startsWith(\"\\n\");\n const insertion = needsNewline\n ? \"\\n\" + configBlock + \"\\n\"\n : configBlock + \"\\n\";\n\n return {\n source: source.slice(0, arrayStart) + insertion + source.slice(arrayStart),\n injected: true,\n };\n}\n\n/**\n * Inject uilint rules into the CommonJS export\n */\nfunction injectUilintRulesCommonJS(\n source: string,\n selectedRules: RuleMetadata[]\n): { source: string; injected: boolean } {\n if (hasUilintRules(source)) {\n return { source, injected: false };\n }\n\n const rulesConfig = generateRulesConfig(selectedRules);\n\n const configBlock = ` {\n files: [\n \"src/**/*.{js,jsx,ts,tsx}\",\n \"app/**/*.{js,jsx,ts,tsx}\",\n \"pages/**/*.{js,jsx,ts,tsx}\",\n ],\n plugins: { uilint: uilint },\n rules: {\n${rulesConfig}\n },\n },`;\n\n const arrayStart = findCommonJsExportedConfigArrayStartIndex(source);\n if (arrayStart === null) {\n return { source, injected: false };\n }\n\n const afterExport = source.slice(arrayStart);\n const needsNewline = !afterExport.trimStart().startsWith(\"\\n\");\n const insertion = needsNewline\n ? \"\\n\" + configBlock + \"\\n\"\n : configBlock + \"\\n\";\n\n return {\n source: source.slice(0, arrayStart) + insertion + source.slice(arrayStart),\n injected: true,\n };\n}\n\n/**\n * Install uilint-eslint into eslint config\n */\nexport async function installEslintPlugin(\n opts: InstallEslintPluginOptions\n): Promise<{\n configFile: string | null;\n modified: boolean;\n missingRuleIds: string[];\n configured: boolean;\n error?: string;\n}> {\n const configPath = findEslintConfigFile(opts.projectPath);\n\n if (!configPath) {\n return {\n configFile: null,\n modified: false,\n missingRuleIds: [],\n configured: false,\n };\n }\n\n const configFilename = getEslintConfigFilename(configPath);\n const original = readFileSync(configPath, \"utf-8\");\n const isCommonJS = configPath.endsWith(\".cjs\");\n\n const ast = getUilintEslintConfigInfoFromSourceAst(original);\n if (\"error\" in ast) {\n return {\n configFile: configFilename,\n modified: false,\n missingRuleIds: [],\n configured: false,\n error: ast.error,\n };\n }\n\n const { info, mod, arrayExpr, kind } = ast;\n const configuredIds = info.configuredRuleIds;\n\n const missingRules = getMissingSelectedRules(\n opts.selectedRules,\n configuredIds\n );\n const rulesToUpdate = getRulesNeedingUpdate(\n opts.selectedRules,\n configuredIds,\n arrayExpr\n );\n\n // Decide what rules to apply, respecting prompts.\n let rulesToApply: RuleMetadata[] = [];\n if (!info.configured) {\n rulesToApply = opts.selectedRules;\n } else {\n // When already configured, we only apply updates + missing rules.\n rulesToApply = [...missingRules, ...rulesToUpdate];\n if (missingRules.length > 0 && !opts.force) {\n const ok = await opts.confirmAddMissingRules?.(\n configFilename,\n missingRules\n );\n if (!ok) {\n return {\n configFile: configFilename,\n modified: false,\n missingRuleIds: missingRules.map((r) => r.id),\n configured: true,\n };\n }\n }\n }\n\n if (rulesToApply.length === 0) {\n return {\n configFile: configFilename,\n modified: false,\n missingRuleIds: missingRules.map((r) => r.id),\n configured: info.configured,\n };\n }\n\n let modifiedAst = false;\n\n // Check if .uilint/rules/ directory exists alongside this target package/app.\n // (Also allow a fallback to workspace root for backwards compatibility.)\n const localRulesDir = join(opts.projectPath, \".uilint\", \"rules\");\n const workspaceRoot = findWorkspaceRoot(opts.projectPath);\n const workspaceRulesDir = join(workspaceRoot, \".uilint\", \"rules\");\n\n const rulesRoot = existsSync(localRulesDir)\n ? opts.projectPath\n : workspaceRoot;\n\n // Always use local rules (they should have been copied by the plan phase)\n // For TypeScript configs, omit the extension (TypeScript will resolve .ts files)\n // For JavaScript configs, use .js extension\n // Note: We don't use .ts extension directly because it requires allowImportingTsExtensions\n const isTypeScriptConfig = configPath.endsWith(\".ts\");\n let fileExtension = isTypeScriptConfig ? \"\" : \".js\";\n\n let ruleImportNames: Map<string, string> | undefined;\n\n // Add imports for local rules\n if (kind === \"esm\") {\n const result = addLocalRuleImportsAst(\n mod,\n rulesToApply,\n configPath,\n rulesRoot,\n fileExtension,\n isTypeScriptConfig\n );\n ruleImportNames = result.importNames;\n if (result.changed) modifiedAst = true;\n } else {\n const result = addLocalRuleRequiresAst(\n mod.$ast,\n rulesToApply,\n configPath,\n rulesRoot,\n fileExtension,\n isTypeScriptConfig\n );\n ruleImportNames = result.importNames;\n if (result.changed) modifiedAst = true;\n }\n\n // Add config block with local rules\n if (ruleImportNames && ruleImportNames.size > 0) {\n appendUilintConfigBlockToArray(arrayExpr, rulesToApply, ruleImportNames);\n modifiedAst = true;\n }\n\n // Ensure uilint-eslint import for utilities (createRule, etc.)\n if (!info.configured) {\n if (kind === \"esm\") {\n // Import createRule utility from uilint-eslint\n mod.imports.$add({\n imported: \"createRule\",\n local: \"createRule\",\n from: \"uilint-eslint\",\n });\n modifiedAst = true;\n } else {\n // CommonJS: add require for createRule\n const stmtMod = parseModule(\n `const { createRule } = require(\"uilint-eslint\");`\n );\n const stmt = (stmtMod.$ast as any).body?.[0];\n if (stmt) {\n let insertAt = 0;\n const first = mod.$ast.body?.[0];\n if (\n first?.type === \"ExpressionStatement\" &&\n first.expression?.type === \"StringLiteral\" &&\n first.expression.value === \"use strict\"\n ) {\n insertAt = 1;\n }\n mod.$ast.body.splice(insertAt, 0, stmt);\n modifiedAst = true;\n }\n }\n }\n\n const updated = modifiedAst ? generateCode(mod).code : original;\n\n if (updated !== original) {\n writeFileSync(configPath, updated, \"utf-8\");\n return {\n configFile: configFilename,\n modified: true,\n missingRuleIds: missingRules.map((r) => r.id),\n configured: getUilintEslintConfigInfoFromSource(updated).configured,\n };\n }\n\n return {\n configFile: configFilename,\n modified: false,\n missingRuleIds: missingRules.map((r) => r.id),\n configured: getUilintEslintConfigInfoFromSource(updated).configured,\n };\n}\n\nexport interface UninstallEslintPluginOptions {\n projectPath: string;\n}\n\nexport interface UninstallEslintPluginResult {\n success: boolean;\n error?: string;\n modifiedFiles?: string[];\n}\n\n/**\n * Remove uilint-eslint rules from ESLint config\n *\n * This is a best-effort uninstall that:\n * 1. Removes uilint rule imports\n * 2. Removes uilint config blocks from the flat config array\n * 3. Removes uilint-eslint package import\n */\nexport async function uninstallEslintPlugin(\n options: UninstallEslintPluginOptions\n): Promise<UninstallEslintPluginResult> {\n const { projectPath } = options;\n\n const configPath = findEslintConfigFile(projectPath);\n if (!configPath) {\n return {\n success: true, // Nothing to uninstall\n modifiedFiles: [],\n };\n }\n\n try {\n const original = readFileSync(configPath, \"utf-8\");\n\n // Simple regex-based removal for now\n // Remove uilint rule imports (import { ... } from \"./uilint-rules/...\" or \"./.uilint/rules/...\")\n let updated = original.replace(\n /^import\\s+\\{[^}]*\\}\\s+from\\s+[\"'][^\"']*\\.uilint\\/rules[^\"']*[\"'];?\\s*$/gm,\n \"\"\n );\n\n // Remove default imports from .uilint/rules (e.g., import RuleName from \"./.uilint/rules/rule-name\")\n updated = updated.replace(\n /^import\\s+\\w+\\s+from\\s+[\"'][^\"']*\\.uilint\\/rules[^\"']*[\"'];?\\s*$/gm,\n \"\"\n );\n\n // Remove uilint-eslint import\n updated = updated.replace(\n /^import\\s+\\{[^}]*\\}\\s+from\\s+[\"']uilint-eslint[\"'];?\\s*$/gm,\n \"\"\n );\n\n // Remove createRule require\n updated = updated.replace(\n /^const\\s+\\{[^}]*createRule[^}]*\\}\\s*=\\s*require\\s*\\(\\s*[\"']uilint-eslint[\"']\\s*\\)\\s*;?\\s*$/gm,\n \"\"\n );\n\n // Remove uilint rules from rules objects (e.g., \"uilint/rule-name\": \"error\")\n updated = updated.replace(\n /[\"']uilint\\/[^\"']+[\"']\\s*:\\s*[\"'][^\"']+[\"']\\s*,?\\s*/g,\n \"\"\n );\n\n // Remove uilint rules array form (e.g., \"uilint/rule-name\": [\"error\", {}])\n updated = updated.replace(\n /[\"']uilint\\/[^\"']+[\"']\\s*:\\s*\\[[^\\]]*\\]\\s*,?\\s*/g,\n \"\"\n );\n\n // Remove entire uilint config block from flat config array\n // This matches: { plugins: { uilint: { rules: {...} } }, rules: {...} }\n updated = updated.replace(\n /\\{\\s*plugins:\\s*\\{\\s*uilint:\\s*\\{[^}]*\\}[^}]*\\}[^}]*rules:\\s*\\{[^}]*\\}[^}]*\\}\\s*,?\\s*/gs,\n \"\"\n );\n\n // Clean up empty lines\n updated = updated.replace(/\\n{3,}/g, \"\\n\\n\");\n\n if (updated !== original) {\n writeFileSync(configPath, updated, \"utf-8\");\n return {\n success: true,\n modifiedFiles: [configPath],\n };\n }\n\n return {\n success: true,\n modifiedFiles: [],\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\nexport interface UpdateRuleConfigResult {\n success: boolean;\n error?: string;\n}\n\nexport interface RuleConfigFromFile {\n severity: \"error\" | \"warn\" | \"off\";\n options?: Record<string, unknown>;\n}\n\n/**\n * Extract severity from an AST node representing a rule value.\n * Handles both formats:\n * - Simple string: \"error\"\n * - Array: [\"error\", { ...options }]\n */\nfunction extractSeverityFromValueNode(\n valueNode: any\n): \"error\" | \"warn\" | \"off\" | null {\n if (!valueNode) return null;\n\n // Simple string format: \"error\"\n if (isStringLiteral(valueNode)) {\n const val = valueNode.value;\n if (val === \"error\" || val === \"warn\" || val === \"off\") {\n return val;\n }\n return null;\n }\n\n // Array format: [\"error\", { ...options }]\n if (valueNode.type === \"ArrayExpression\") {\n const firstEl = valueNode.elements?.[0];\n if (firstEl && isStringLiteral(firstEl)) {\n const val = firstEl.value;\n if (val === \"error\" || val === \"warn\" || val === \"off\") {\n return val;\n }\n }\n }\n\n return null;\n}\n\n/**\n * Extract options object from an AST node representing a rule value in array format.\n * Returns undefined if not in array format or no options present.\n */\nfunction extractOptionsFromValueNode(\n valueNode: any\n): Record<string, unknown> | undefined {\n if (!valueNode || valueNode.type !== \"ArrayExpression\") return undefined;\n\n const elements = valueNode.elements ?? [];\n if (elements.length < 2) return undefined;\n\n const optionsNode = elements[1];\n if (!optionsNode || optionsNode.type !== \"ObjectExpression\") return undefined;\n\n // Convert AST object to plain JS object\n try {\n const obj: Record<string, unknown> = {};\n for (const prop of optionsNode.properties ?? []) {\n if (!prop || (prop.type !== \"ObjectProperty\" && prop.type !== \"Property\"))\n continue;\n\n const key = prop.key;\n let keyName: string | null = null;\n if (key?.type === \"Identifier\") {\n keyName = key.name;\n } else if (isStringLiteral(key)) {\n keyName = key.value;\n }\n if (!keyName) continue;\n\n const val = prop.value;\n if (isStringLiteral(val)) {\n obj[keyName] = val.value;\n } else if (\n val?.type === \"NumericLiteral\" ||\n (val?.type === \"Literal\" && typeof val.value === \"number\")\n ) {\n obj[keyName] = val.value;\n } else if (\n val?.type === \"BooleanLiteral\" ||\n (val?.type === \"Literal\" && typeof val.value === \"boolean\")\n ) {\n obj[keyName] = val.value;\n } else if (val?.type === \"ArrayExpression\") {\n // Simple array of literals\n const arr: unknown[] = [];\n for (const el of val.elements ?? []) {\n if (isStringLiteral(el)) arr.push(el.value);\n else if (\n el?.type === \"NumericLiteral\" ||\n (el?.type === \"Literal\" && typeof el.value === \"number\")\n )\n arr.push(el.value);\n else if (\n el?.type === \"BooleanLiteral\" ||\n (el?.type === \"Literal\" && typeof el.value === \"boolean\")\n )\n arr.push(el.value);\n }\n obj[keyName] = arr;\n }\n }\n return Object.keys(obj).length > 0 ? obj : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Read current rule configurations from an ESLint config file.\n * Uses magicast to parse the config and extract uilint rule severities and options.\n *\n * @param configPath Path to the ESLint config file\n * @returns Map of ruleId (without \"uilint/\" prefix) to { severity, options }\n */\nexport function readRuleConfigsFromConfig(\n configPath: string\n): Map<string, RuleConfigFromFile> {\n const configs = new Map<string, RuleConfigFromFile>();\n\n try {\n const source = readFileSync(configPath, \"utf-8\");\n const mod = parseModule(source);\n const found = findExportedConfigArrayExpression(mod);\n\n if (!found) {\n return configs;\n }\n\n const { arrayExpr } = found;\n const valueNodes = collectUilintRuleValueNodesFromConfigArray(arrayExpr);\n\n for (const [ruleId, valueNode] of valueNodes) {\n const severity = extractSeverityFromValueNode(valueNode);\n if (severity) {\n const options = extractOptionsFromValueNode(valueNode);\n configs.set(ruleId, { severity, options });\n }\n }\n } catch (error) {\n console.error(\"[eslint-config-inject] Failed to read rule configs:\", error);\n }\n\n return configs;\n}\n\n/**\n * Find a rule property node in the config array by rule ID.\n * Returns the property node and its parent rules object.\n */\nfunction findRulePropertyInConfigArray(\n arrayExpr: any,\n ruleId: string\n): { prop: any; rulesObj: any } | null {\n const fullRuleKey = `uilint/${ruleId}`;\n\n if (!arrayExpr || arrayExpr.type !== \"ArrayExpression\") return null;\n\n for (const el of arrayExpr.elements ?? []) {\n if (!el || el.type !== \"ObjectExpression\") continue;\n const rules = getObjectPropertyValue(el, \"rules\");\n if (!rules || rules.type !== \"ObjectExpression\") continue;\n\n for (const prop of rules.properties ?? []) {\n if (!prop) continue;\n if (prop.type !== \"ObjectProperty\" && prop.type !== \"Property\") continue;\n const key = prop.key;\n if (!isStringLiteral(key)) continue;\n if (key.value === fullRuleKey) {\n return { prop, rulesObj: rules };\n }\n }\n }\n\n return null;\n}\n\n/**\n * Update the severity of a single uilint rule in the ESLint config file.\n * Uses magicast for proper AST-based editing.\n *\n * Handles both formats:\n * - Simple: \"uilint/rule-name\": \"error\"\n * - With options: \"uilint/rule-name\": [\"error\", { ... }]\n *\n * Only updates existing rules - returns error if rule not found.\n */\nexport function updateRuleSeverityInConfig(\n configPath: string,\n ruleId: string,\n severity: \"error\" | \"warn\" | \"off\"\n): UpdateRuleConfigResult {\n try {\n const source = readFileSync(configPath, \"utf-8\");\n const mod = parseModule(source);\n const found = findExportedConfigArrayExpression(mod);\n\n if (!found) {\n return {\n success: false,\n error: \"Could not parse ESLint config array\",\n };\n }\n\n const { arrayExpr } = found;\n const ruleInfo = findRulePropertyInConfigArray(arrayExpr, ruleId);\n\n if (!ruleInfo) {\n return {\n success: false,\n error: `Rule \"uilint/${ruleId}\" not found in config. Use 'uilint install' to add new rules.`,\n };\n }\n\n const { prop } = ruleInfo;\n const valueNode = prop.value;\n\n // Update the severity based on the format\n if (isStringLiteral(valueNode)) {\n // Simple string format - replace the value\n valueNode.value = severity;\n } else if (valueNode?.type === \"ArrayExpression\") {\n // Array format - update the first element\n const firstEl = valueNode.elements?.[0];\n if (firstEl && isStringLiteral(firstEl)) {\n firstEl.value = severity;\n } else {\n // Create a new string literal for severity\n const severityNode = (parseExpression(`\"${severity}\"`) as any).$ast;\n if (valueNode.elements && valueNode.elements.length > 0) {\n valueNode.elements[0] = severityNode;\n } else {\n valueNode.elements = [severityNode];\n }\n }\n } else {\n return {\n success: false,\n error: `Rule \"uilint/${ruleId}\" has unexpected format`,\n };\n }\n\n const updated = generateCode(mod).code;\n writeFileSync(configPath, updated, \"utf-8\");\n return { success: true };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n/**\n * Update the severity AND options of a single uilint rule in the ESLint config file.\n * Uses magicast for proper AST-based editing.\n *\n * Converts the rule to array format: [\"severity\", { ...options }]\n *\n * Only updates existing rules - returns error if rule not found.\n */\nexport function updateRuleConfigInConfig(\n configPath: string,\n ruleId: string,\n severity: \"error\" | \"warn\" | \"off\",\n options: Record<string, unknown>\n): UpdateRuleConfigResult {\n try {\n const source = readFileSync(configPath, \"utf-8\");\n const mod = parseModule(source);\n const found = findExportedConfigArrayExpression(mod);\n\n if (!found) {\n return {\n success: false,\n error: \"Could not parse ESLint config array\",\n };\n }\n\n const { arrayExpr } = found;\n const ruleInfo = findRulePropertyInConfigArray(arrayExpr, ruleId);\n\n if (!ruleInfo) {\n return {\n success: false,\n error: `Rule \"uilint/${ruleId}\" not found in config. Use 'uilint install' to add new rules.`,\n };\n }\n\n const { prop } = ruleInfo;\n\n // Build the new value as array format: [\"severity\", { ...options }]\n const optionsJson = JSON.stringify(options);\n const newValueExpr = `[\"${severity}\", ${optionsJson}]`;\n const newValueNode = (parseExpression(newValueExpr) as any).$ast;\n\n // Replace the value\n prop.value = newValueNode;\n\n const updated = generateCode(mod).code;\n writeFileSync(configPath, updated, \"utf-8\");\n return { success: true };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n","/**\n * Coverage preparation utilities.\n *\n * Handles automatically setting up coverage for vitest projects:\n * - Installing @vitest/coverage-v8 package\n * - Adding coverage config to vitest.config.ts\n * - Running tests with coverage to generate data\n */\n\nimport { existsSync, readFileSync, writeFileSync } from \"fs\";\nimport { join } from \"path\";\nimport {\n detectPackageManager,\n installDependencies,\n runTestsWithCoverage,\n} from \"./package-manager.js\";\nimport { detectCoverageSetup, type CoverageSetupInfo } from \"./coverage-detect.js\";\n\nexport interface CoveragePreparationResult {\n /** Whether @vitest/coverage-v8 was added to package.json */\n packageAdded: boolean;\n /** Whether vitest.config.ts was modified to add coverage */\n configModified: boolean;\n /** Whether tests were run with coverage */\n testsRan: boolean;\n /** Whether coverage-final.json was generated */\n coverageGenerated: boolean;\n /** Total time taken in milliseconds */\n duration: number;\n /** Error message if something failed */\n error?: string;\n}\n\nexport interface PrepareCoverageOptions {\n /** Root directory of the app to prepare */\n appRoot: string;\n /** Progress callback for streaming updates */\n onProgress?: (message: string, phase: string) => void;\n /** Skip installing packages (useful in CI) */\n skipPackageInstall?: boolean;\n /** Skip running tests (useful when tests run separately) */\n skipTests?: boolean;\n}\n\n/**\n * Inject coverage configuration into vitest.config.ts\n * @returns true if config was modified, false if already configured or error\n */\nexport function injectCoverageConfig(vitestConfigPath: string): boolean {\n try {\n const content = readFileSync(vitestConfigPath, \"utf-8\");\n\n // Check if already has coverage config\n if (/coverage\\s*:\\s*\\{/.test(content)) {\n return false; // Already configured\n }\n\n // Find the `test: {` block and inject coverage after it\n // This handles patterns like:\n // - test: {\n // - test:{\n // - test : {\n const testBlockRegex = /(test\\s*:\\s*\\{)/;\n const match = content.match(testBlockRegex);\n\n if (!match) {\n // Can't find test block - might be a different config format\n return false;\n }\n\n const coverageConfig = `\n coverage: {\n provider: \"v8\",\n reporter: [\"text\", \"json\"],\n reportsDirectory: \"./coverage\",\n },`;\n\n // Insert coverage config right after `test: {`\n const newContent = content.replace(\n testBlockRegex,\n `$1${coverageConfig}`\n );\n\n writeFileSync(vitestConfigPath, newContent, \"utf-8\");\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Prepare a project for coverage generation.\n *\n * This function:\n * 1. Detects current coverage setup\n * 2. Installs @vitest/coverage-v8 if needed\n * 3. Adds coverage config to vitest.config.ts if needed\n * 4. Runs tests with coverage to generate data\n */\nexport async function prepareCoverage(\n options: PrepareCoverageOptions\n): Promise<CoveragePreparationResult> {\n const { appRoot, onProgress, skipPackageInstall, skipTests } = options;\n const start = Date.now();\n\n const result: CoveragePreparationResult = {\n packageAdded: false,\n configModified: false,\n testsRan: false,\n coverageGenerated: false,\n duration: 0,\n };\n\n try {\n // 1. Detect current setup\n onProgress?.(\"Detecting coverage setup...\", \"detect\");\n const setup = detectCoverageSetup(appRoot);\n\n // If no vitest, we can't set up coverage\n if (!setup.hasVitest) {\n result.error = \"Vitest not found in dependencies\";\n result.duration = Date.now() - start;\n return result;\n }\n\n // 2. Install coverage package if needed\n if (setup.needsCoveragePackage && !skipPackageInstall) {\n onProgress?.(\"Installing @vitest/coverage-v8...\", \"install\");\n const pm = detectPackageManager(appRoot);\n try {\n await installDependencies(pm, appRoot, [\"@vitest/coverage-v8\"]);\n result.packageAdded = true;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n result.error = `Failed to install coverage package: ${msg}`;\n result.duration = Date.now() - start;\n return result;\n }\n }\n\n // 3. Add coverage config if needed\n if (setup.needsCoverageConfig && setup.vitestConfigPath) {\n onProgress?.(\"Adding coverage configuration...\", \"config\");\n result.configModified = injectCoverageConfig(setup.vitestConfigPath);\n }\n\n // 4. Run tests with coverage\n if (!skipTests) {\n // Re-check if we need to run tests\n const updatedSetup = detectCoverageSetup(appRoot);\n\n // Only run if:\n // - No coverage data exists, OR\n // - Config was just modified (data is stale)\n if (!updatedSetup.hasCoverageData || result.configModified) {\n onProgress?.(\"Running tests with coverage...\", \"test\");\n const pm = detectPackageManager(appRoot);\n try {\n await runTestsWithCoverage(pm, appRoot);\n result.testsRan = true;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n // Tests might fail, but coverage might still be generated\n result.error = `Tests failed: ${msg}`;\n }\n\n // Check if coverage was generated\n const finalSetup = detectCoverageSetup(appRoot);\n result.coverageGenerated = finalSetup.hasCoverageData;\n }\n } else {\n onProgress?.(\"Skipping tests (skipTests=true)\", \"skip\");\n }\n\n result.duration = Date.now() - start;\n return result;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n result.error = `Coverage preparation failed: ${msg}`;\n result.duration = Date.now() - start;\n return result;\n }\n}\n\n/**\n * Check if coverage data needs to be regenerated.\n *\n * Returns true if:\n * - Coverage data doesn't exist\n * - Coverage package is missing\n * - Coverage config is missing\n */\nexport function needsCoveragePreparation(setup: CoverageSetupInfo): boolean {\n if (!setup.hasVitest) {\n return false; // Can't prepare without vitest\n }\n\n return (\n setup.needsCoveragePackage ||\n setup.needsCoverageConfig ||\n !setup.hasCoverageData\n );\n}\n"],"mappings":"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","names":["intro","outro","cancel","cancel","note","log","select","confirm","text","multiselect","readFileSync","join","existsSync","join","existsSync","readFileSync","join","dirname","p","program","dirname","join","readFileSync","join","existsSync","readFileSync","writeFileSync","readFileSync","writeFileSync"]}
package/dist/index.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  updateRuleConfigInConfig,
20
20
  updateRuleSeverityInConfig,
21
21
  withSpinner
22
- } from "./chunk-W6X3RNOE.js";
22
+ } from "./chunk-YS2QQOCB.js";
23
23
  import "./chunk-OTU5FY6B.js";
24
24
 
25
25
  // src/index.ts
@@ -3643,7 +3643,7 @@ program.command("update").description("Update existing style guide with new styl
3643
3643
  });
3644
3644
  });
3645
3645
  program.command("install").description("Install UILint integration").option("--force", "Overwrite existing configuration files").action(async (options) => {
3646
- const { installUI } = await import("./install-ui-ZXMZNRU2.js");
3646
+ const { installUI } = await import("./install-ui-JV4G2CAC.js");
3647
3647
  await installUI({ force: options.force });
3648
3648
  });
3649
3649
  program.command("serve").description("Start WebSocket server for real-time UI linting").option("-p, --port <number>", "Port to listen on", "9234").action(async (options) => {