uilint 0.2.140 → 0.2.141

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/{chunk-RYRHWTLC.js → chunk-7GQXW4CT.js} +14 -10
  2. package/dist/chunk-7GQXW4CT.js.map +1 -0
  3. package/dist/{chunk-VSBVUS56.js → chunk-JWSZKDZY.js} +77 -77
  4. package/dist/chunk-JWSZKDZY.js.map +1 -0
  5. package/dist/{chunk-JIFAHBJ2.js → chunk-OW7Y4RTR.js} +4 -4
  6. package/dist/chunk-OW7Y4RTR.js.map +1 -0
  7. package/dist/{chunk-TKJ27W62.js → chunk-VKI3SQMQ.js} +2 -2
  8. package/dist/{chunk-TKJ27W62.js.map → chunk-VKI3SQMQ.js.map} +1 -1
  9. package/dist/chunk-X4PN5A4G.js +56 -0
  10. package/dist/chunk-X4PN5A4G.js.map +1 -0
  11. package/dist/{chunk-BFHNMKBU.js → chunk-ZUOFUPGT.js} +27 -27
  12. package/dist/chunk-ZUOFUPGT.js.map +1 -0
  13. package/dist/index.js +163 -58
  14. package/dist/index.js.map +1 -1
  15. package/dist/{init-ui-YAXRGBIJ.js → init-ui-DQZARD3F.js} +42 -17
  16. package/dist/init-ui-DQZARD3F.js.map +1 -0
  17. package/dist/{plan-2ISQNZBR.js → plan-ZJSVJL5X.js} +4 -4
  18. package/dist/plugin-loader-M2W3SMJ5.js +11 -0
  19. package/dist/plugin-loader-M2W3SMJ5.js.map +1 -0
  20. package/dist/{remove-ui-RHRSEUWJ.js → remove-ui-ZHW4GUFL.js} +7 -7
  21. package/dist/remove-ui-ZHW4GUFL.js.map +1 -0
  22. package/dist/{render-3GGNWYTF.js → render-43OMCORR.js} +1 -1
  23. package/dist/render-43OMCORR.js.map +1 -0
  24. package/dist/{upgrade-2EVTOYTJ.js → upgrade-GR6OJBXD.js} +8 -6
  25. package/dist/upgrade-GR6OJBXD.js.map +1 -0
  26. package/package.json +8 -7
  27. package/dist/chunk-BFHNMKBU.js.map +0 -1
  28. package/dist/chunk-JIFAHBJ2.js.map +0 -1
  29. package/dist/chunk-RUMBVNPY.js +0 -29
  30. package/dist/chunk-RUMBVNPY.js.map +0 -1
  31. package/dist/chunk-RYRHWTLC.js.map +0 -1
  32. package/dist/chunk-VSBVUS56.js.map +0 -1
  33. package/dist/init-ui-YAXRGBIJ.js.map +0 -1
  34. package/dist/remove-ui-RHRSEUWJ.js.map +0 -1
  35. package/dist/render-3GGNWYTF.js.map +0 -1
  36. package/dist/upgrade-2EVTOYTJ.js.map +0 -1
  37. /package/dist/{plan-2ISQNZBR.js.map → plan-ZJSVJL5X.js.map} +0 -0
@@ -231,11 +231,12 @@ function normalizeAstForCompare(node) {
231
231
  if (node === void 0) return void 0;
232
232
  if (typeof node !== "object") return node;
233
233
  if (Array.isArray(node)) return node.map(normalizeAstForCompare);
234
+ const obj = node;
234
235
  const out = {};
235
- const keys = Object.keys(node).filter((k) => !IGNORED_AST_KEYS.has(k)).sort();
236
+ const keys = Object.keys(obj).filter((k) => !IGNORED_AST_KEYS.has(k)).sort();
236
237
  for (const k of keys) {
237
238
  if (k.startsWith("$")) continue;
238
- out[k] = normalizeAstForCompare(node[k]);
239
+ out[k] = normalizeAstForCompare(obj[k]);
239
240
  }
240
241
  return out;
241
242
  }
@@ -357,7 +358,9 @@ function collectConfiguredUilintRuleIdsFromConfigArray(arrayExpr) {
357
358
  for (const el of arrayExpr.elements ?? []) {
358
359
  if (!el || el.type !== "ObjectExpression") continue;
359
360
  const rules = getObjectPropertyValue(el, "rules");
360
- for (const id of collectUilintRuleIdsFromRulesObject(rules)) ids.add(id);
361
+ if (rules) {
362
+ for (const id of collectUilintRuleIdsFromRulesObject(rules)) ids.add(id);
363
+ }
361
364
  }
362
365
  return ids;
363
366
  }
@@ -370,7 +373,7 @@ function findExistingUilintRulesObject(arrayExpr) {
370
373
  const plugins = getObjectPropertyValue(el, "plugins");
371
374
  const rules = getObjectPropertyValue(el, "rules");
372
375
  const hasUilintPlugin = plugins?.type === "ObjectExpression" && getObjectPropertyValue(plugins, "uilint") !== null;
373
- const uilintIds = collectUilintRuleIdsFromRulesObject(rules);
376
+ const uilintIds = rules ? collectUilintRuleIdsFromRulesObject(rules) : /* @__PURE__ */ new Set();
374
377
  const hasUilintRules = uilintIds.size > 0;
375
378
  if (!hasUilintPlugin && !hasUilintRules) continue;
376
379
  const safe = rules?.type === "ObjectExpression" && !hasSpreadProperties(rules);
@@ -685,7 +688,7 @@ async function installEslintPlugin(opts) {
685
688
  }
686
689
  const configFilename = getEslintConfigFilename(configPath);
687
690
  const original = readFileSync2(configPath, "utf-8");
688
- const isCommonJS = configPath.endsWith(".cjs");
691
+ const _isCommonJS = configPath.endsWith(".cjs");
689
692
  const ast = getUilintEslintConfigInfoFromSourceAst(original);
690
693
  if ("error" in ast) {
691
694
  return {
@@ -738,10 +741,10 @@ async function installEslintPlugin(opts) {
738
741
  let modifiedAst = false;
739
742
  const localRulesDir = join3(opts.projectPath, ".uilint", "rules");
740
743
  const workspaceRoot = findWorkspaceRoot(opts.projectPath);
741
- const workspaceRulesDir = join3(workspaceRoot, ".uilint", "rules");
744
+ const _workspaceRulesDir = join3(workspaceRoot, ".uilint", "rules");
742
745
  const rulesRoot = existsSync3(localRulesDir) ? opts.projectPath : workspaceRoot;
743
746
  const isTypeScriptConfig = configPath.endsWith(".ts");
744
- let fileExtension = isTypeScriptConfig ? "" : ".js";
747
+ const fileExtension = isTypeScriptConfig ? "" : ".js";
745
748
  let ruleImportNames;
746
749
  const localRulesToApply = rulesToApply.filter((r) => !r.eslintImport);
747
750
  const externalRulesToApply = rulesToApply.filter((r) => r.eslintImport);
@@ -830,11 +833,12 @@ async function installEslintPlugin(opts) {
830
833
  const stmt = stmtMod.$ast.body?.[0];
831
834
  if (stmt) {
832
835
  let insertAt = 0;
833
- const first = mod.$ast.body?.[0];
836
+ const programBody = mod.$ast.body;
837
+ const first = programBody?.[0];
834
838
  if (first?.type === "ExpressionStatement" && first.expression?.type === "StringLiteral" && first.expression.value === "use strict") {
835
839
  insertAt = 1;
836
840
  }
837
- mod.$ast.body.splice(insertAt, 0, stmt);
841
+ programBody.splice(insertAt, 0, stmt);
838
842
  modifiedAst = true;
839
843
  }
840
844
  }
@@ -1220,4 +1224,4 @@ export {
1220
1224
  prepareCoverage,
1221
1225
  needsCoveragePreparation
1222
1226
  };
1223
- //# sourceMappingURL=chunk-RYRHWTLC.js.map
1227
+ //# sourceMappingURL=chunk-7GQXW4CT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/coverage-detect.ts","../src/utils/next-detect.ts","../src/utils/eslint-config-inject.ts","../src/utils/coverage-prepare.ts"],"sourcesContent":["/**\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\";\n\n/** Generic AST node type used throughout config manipulation. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AstNode = Record<string, any>;\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: AstNode, visit: (n: AstNode) => void): void {\n if (!node || typeof node !== \"object\") return;\n visit(node);\n for (const key of Object.keys(node)) {\n const v = node[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: AstNode, 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: AstNode): 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: AstNode, keyName: string): AstNode | 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: AstNode): boolean {\n if (!obj || obj.type !== \"ObjectExpression\") return false;\n return ((obj.properties as AstNode[] | undefined) ?? []).some(\n (p: AstNode) => 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: unknown): unknown {\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 obj = node as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n const keys = Object.keys(obj)\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(obj[k]);\n }\n return out;\n}\n\nfunction astEquivalent(a: unknown, b: unknown): 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: AstNode): 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: AstNode): {\n kind: \"esm\" | \"cjs\";\n arrayExpr: AstNode;\n program: AstNode;\n} | null {\n function unwrapExpression(expr: AstNode): AstNode {\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: AstNode,\n name: string\n ): AstNode | 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: AstNode\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 if (rules) {\n for (const id of collectUilintRuleIdsFromRulesObject(rules)) ids.add(id);\n }\n }\n return ids;\n}\n\nfunction findExistingUilintRulesObject(arrayExpr: AstNode): {\n configObj: AstNode | null;\n rulesObj: AstNode | 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 = rules ? collectUilintRuleIdsFromRulesObject(rules) : new Set<string>();\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: AstNode): 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: AstNode,\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: AstNode,\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., ConsistentDarkModeRule)\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: AstNode,\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 unknown as AstNode).body as AstNode[])?.[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: AstNode,\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 unknown as AstNode).$ast;\n arrayExpr.elements.push(objExpr);\n}\n\n/**\n * Update an existing uilint config block with new rules.\n * This modifies the existing config object instead of creating a new one.\n *\n * Handles both plugin formats:\n * - `plugins: { uilint: uilint }` (old format with identifier)\n * - `plugins: { uilint: { rules: {...} } }` (new format with rules object)\n */\nfunction updateExistingUilintConfigBlock(\n configObj: AstNode,\n selectedRules: RuleMetadata[],\n ruleImportNames: Map<string, string>\n): void {\n const pluginsObj = getObjectPropertyValue(configObj, \"plugins\");\n const rulesObj = getObjectPropertyValue(configObj, \"rules\");\n\n // Update the plugins.uilint object to include the new rule imports\n if (pluginsObj?.type === \"ObjectExpression\") {\n const uilintPluginProp = pluginsObj.properties?.find(\n (p: AstNode) =>\n (p.type === \"ObjectProperty\" || p.type === \"Property\") &&\n ((p.key?.type === \"Identifier\" && p.key.name === \"uilint\") ||\n (isStringLiteral(p.key) && p.key.value === \"uilint\"))\n );\n\n if (uilintPluginProp) {\n const uilintValue = uilintPluginProp.value;\n\n // Check if it's the old format (identifier like `uilint`) or new format (object with rules)\n if (uilintValue?.type === \"Identifier\") {\n // Old format: `plugins: { uilint: uilint }`\n // Replace with new format: `plugins: { uilint: { rules: {...} } }`\n const pluginRulesCode = Array.from(ruleImportNames.entries())\n .map(([ruleId, importName]) => `\"${ruleId}\": ${importName}`)\n .join(\", \");\n\n const newPluginObjCode = `{ rules: { ${pluginRulesCode} } }`;\n const newPluginObj = (parseExpression(newPluginObjCode) as unknown as AstNode).$ast;\n uilintPluginProp.value = newPluginObj;\n } else if (uilintValue?.type === \"ObjectExpression\") {\n // New format: `plugins: { uilint: { rules: {...} } }`\n // Find or create the rules object inside\n let pluginRulesObj = getObjectPropertyValue(uilintValue, \"rules\");\n\n if (!pluginRulesObj || pluginRulesObj.type !== \"ObjectExpression\") {\n // Create the rules property\n const rulesCode = `{ rules: {} }`;\n const tempObj = (parseExpression(rulesCode) as unknown as AstNode).$ast;\n pluginRulesObj = tempObj.properties[0].value;\n uilintValue.properties.push(tempObj.properties[0]);\n }\n\n // Add each rule import to the plugins.uilint.rules object\n for (const [ruleId, importName] of ruleImportNames.entries()) {\n // Check if already exists\n const exists = pluginRulesObj!.properties?.some(\n (p: AstNode) =>\n (p.type === \"ObjectProperty\" || p.type === \"Property\") &&\n isStringLiteral(p.key) &&\n p.key.value === ruleId\n );\n\n if (!exists) {\n const propCode = `{ \"${ruleId}\": ${importName} }`;\n const tempObj = (parseExpression(propCode) as unknown as AstNode).$ast;\n pluginRulesObj!.properties.push(tempObj.properties[0]);\n }\n }\n }\n }\n }\n\n // Add new rules or update existing ones in the rules object\n if (rulesObj?.type === \"ObjectExpression\") {\n for (const rule of selectedRules) {\n const ruleKey = `uilint/${rule.id}`;\n\n // Generate the new value for this rule\n const valueCode =\n rule.defaultOptions && rule.defaultOptions.length > 0\n ? `[\"${rule.defaultSeverity}\", ...${JSON.stringify(\n rule.defaultOptions,\n null,\n 2\n )}]`\n : `\"${rule.defaultSeverity}\"`;\n\n // Find existing rule property\n const existingPropIndex = rulesObj.properties?.findIndex(\n (p: AstNode) =>\n (p.type === \"ObjectProperty\" || p.type === \"Property\") &&\n isStringLiteral(p.key) &&\n p.key.value === ruleKey\n );\n\n const propCode = `{ \"${ruleKey}\": ${valueCode} }`;\n const tempObj = (parseExpression(propCode) as unknown as AstNode).$ast;\n const newProp = tempObj.properties[0];\n\n if (existingPropIndex !== undefined && existingPropIndex >= 0) {\n // Update existing rule with new value\n rulesObj.properties[existingPropIndex] = newProp;\n } else {\n // Add new rule\n rulesObj.properties.push(newProp);\n }\n }\n }\n}\n\nfunction getUilintEslintConfigInfoFromSourceAst(source: string):\n | {\n info: UilintEslintConfigInfo;\n mod: ReturnType<typeof parseModule>;\n arrayExpr: AstNode;\n kind: \"esm\" | \"cjs\";\n existingConfig: {\n configObj: AstNode | null;\n rulesObj: AstNode | null;\n safeToMutate: boolean;\n };\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 existingConfig: existingUilint,\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/consistent-dark-mode\": \"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: AstNode\n): Map<string, AstNode> {\n const out = new Map<string, AstNode>();\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: AstNode\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 unknown as AstNode).$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, existingConfig } = 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 const fileExtension = isTypeScriptConfig ? \"\" : \".js\";\n\n let ruleImportNames: Map<string, string> | undefined;\n\n // External plugin rules (e.g. vision, semantic) live in their own npm packages\n // and don't need local imports from .uilint/rules/. Only import local rules.\n const localRulesToApply = rulesToApply.filter((r) => !r.eslintImport);\n const externalRulesToApply = rulesToApply.filter((r) => r.eslintImport);\n\n // Add imports for local rules\n if (kind === \"esm\") {\n const result = addLocalRuleImportsAst(\n mod,\n localRulesToApply,\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 localRulesToApply,\n configPath,\n rulesRoot,\n fileExtension,\n isTypeScriptConfig\n );\n ruleImportNames = result.importNames;\n if (result.changed) modifiedAst = true;\n }\n\n // Add imports for external plugin rules (from their npm packages)\n if (externalRulesToApply.length > 0 && ruleImportNames) {\n const used = collectTopLevelBindings(mod.$ast);\n // Include already-added local rule import names\n for (const name of ruleImportNames.values()) used.add(name);\n\n for (const rule of externalRulesToApply) {\n const importSpecifier = rule.eslintImport!;\n\n // Check if already imported\n const existingLocal = findExistingDefaultImportLocalName(mod.$ast, importSpecifier);\n if (existingLocal) {\n ruleImportNames.set(rule.id, existingLocal);\n used.add(existingLocal);\n continue;\n }\n\n // Generate a safe import name (e.g., SemanticVisionRule)\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 ruleImportNames.set(rule.id, importName);\n used.add(importName);\n\n if (kind === \"esm\") {\n mod.imports.$add({\n imported: \"default\",\n local: importName,\n from: importSpecifier,\n });\n } else {\n // CommonJS require\n const requireStmt = parseModule(\n `const ${importName} = require(\"${importSpecifier}\");`\n );\n const stmt = ((requireStmt.$ast as unknown as AstNode).body as AstNode[])?.[0];\n if (stmt) {\n (mod.$ast as unknown as AstNode).body.splice(0, 0, stmt);\n }\n }\n modifiedAst = true;\n }\n }\n\n // Add config block with all rules (local + external)\n if (ruleImportNames && ruleImportNames.size > 0) {\n if (existingConfig.configObj !== null) {\n // Update the existing config block instead of creating a new one\n updateExistingUilintConfigBlock(\n existingConfig.configObj,\n rulesToApply,\n ruleImportNames\n );\n } else {\n // No existing config block, append a new one\n appendUilintConfigBlockToArray(arrayExpr, rulesToApply, ruleImportNames);\n }\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 unknown as AstNode).body as AstNode[])?.[0];\n if (stmt) {\n let insertAt = 0;\n const programBody = (mod.$ast as unknown as AstNode).body;\n const first = programBody?.[0];\n if (\n first?.type === \"ExpressionStatement\" &&\n first.expression?.type === \"StringLiteral\" &&\n first.expression.value === \"use strict\"\n ) {\n insertAt = 1;\n }\n programBody.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 RemoveEslintPluginOptions {\n projectPath: string;\n}\n\nexport interface RemoveEslintPluginResult {\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 removal 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 removeEslintPlugin(\n options: RemoveEslintPluginOptions\n): Promise<RemoveEslintPluginResult> {\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: AstNode\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: AstNode\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: AstNode,\n ruleId: string\n): { prop: AstNode; rulesObj: AstNode } | 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 init' 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 unknown as AstNode).$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 init' 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 unknown as AstNode).$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 { readFileSync, writeFileSync } from \"fs\";\nimport {\n detectPackageManager,\n installDependencies,\n runTestsWithCoverage,\n type SpawnOutputOptions,\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 extends SpawnOutputOptions {\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, silent, onOutput } = 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\"], { silent, onOutput });\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, { silent, onOutput });\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":";;;;;;;;AAMA,SAAS,YAAY,cAAc,gBAAgB;AACnD,SAAS,YAAY;AA2BrB,IAAM,sBAAsB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAUA,SAAS,iBAAiB,aAAsC;AAC9D,MAAI;AACF,UAAM,UAAU,KAAK,aAAa,cAAc;AAChD,QAAI,CAAC,WAAW,OAAO,EAAG,QAAO,EAAE,WAAW,OAAO,oBAAoB,MAAM;AAE/E,UAAM,MAAM,KAAK,MAAM,aAAa,SAAS,OAAO,CAAC;AAKrD,UAAM,OAAO,EAAE,GAAI,IAAI,gBAAgB,CAAC,GAAI,GAAI,IAAI,mBAAmB,CAAC,EAAG;AAC3E,UAAM,YAAY,YAAY;AAC9B,UAAM,qBACJ,yBAAyB,QAAQ,+BAA+B;AAElE,WAAO,EAAE,WAAW,mBAAmB;AAAA,EACzC,QAAQ;AACN,WAAO,EAAE,WAAW,OAAO,oBAAoB,MAAM;AAAA,EACvD;AACF;AAKA,SAAS,iBAAiB,aAAoC;AAC5D,aAAW,cAAc,qBAAqB;AAC5C,UAAM,aAAa,KAAK,aAAa,UAAU;AAC/C,QAAI,WAAW,UAAU,GAAG;AAC1B,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAKA,SAAS,oBAAoB,YAG3B;AACA,MAAI;AACF,UAAM,UAAU,aAAa,YAAY,OAAO;AAGhD,UAAM,oBAAoB,oBAAoB,KAAK,OAAO;AAE1D,QAAI,CAAC,mBAAmB;AACtB,aAAO,EAAE,mBAAmB,OAAO,kBAAkB,KAAK;AAAA,IAC5D;AAIA,UAAM,gBAAgB,QAAQ,MAAM,wCAAwC;AAC5E,UAAM,mBAAmB,gBACpB,cAAc,CAAC,IAChB;AAEJ,WAAO,EAAE,mBAAmB,iBAAiB;AAAA,EAC/C,QAAQ;AACN,WAAO,EAAE,mBAAmB,OAAO,kBAAkB,KAAK;AAAA,EAC5D;AACF;AAKA,SAAS,iBAAiB,aAGxB;AACA,QAAM,mBAAmB,KAAK,aAAa,YAAY,qBAAqB;AAC5E,MAAI,WAAW,gBAAgB,GAAG;AAChC,QAAI;AACF,YAAM,QAAQ,SAAS,gBAAgB;AACvC,YAAM,MAAM,KAAK,IAAI,IAAI,MAAM;AAC/B,aAAO,EAAE,MAAM,kBAAkB,IAAI;AAAA,IACvC,QAAQ;AACN,aAAO,EAAE,MAAM,kBAAkB,KAAK,KAAK;AAAA,IAC7C;AAAA,EACF;AACA,SAAO,EAAE,MAAM,MAAM,KAAK,KAAK;AACjC;AAKO,SAAS,oBAAoB,aAAwC;AAC1E,QAAM,EAAE,WAAW,mBAAmB,IAAI,iBAAiB,WAAW;AACtE,QAAM,mBAAmB,iBAAiB,WAAW;AACrD,QAAM,kBAAkB,qBAAqB;AAE7C,MAAI,oBAAoB;AACxB,MAAI,mBAA6C;AAEjD,MAAI,kBAAkB;AACpB,UAAM,eAAe,oBAAoB,gBAAgB;AACzD,wBAAoB,aAAa;AACjC,uBAAmB,aAAa;AAAA,EAClC;AAEA,QAAM,eAAe,iBAAiB,WAAW;AACjD,QAAM,kBAAkB,aAAa,SAAS;AAG9C,QAAM,uBAAuB,aAAa,CAAC;AAC3C,QAAM,sBAAsB,aAAa,mBAAmB,CAAC;AAE7D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,kBAAkB,aAAa;AAAA,IAC/B;AAAA,IACA;AAAA,IACA,iBAAiB,aAAa;AAAA,EAChC;AACF;;;ACzKA,SAAS,cAAAA,aAAY,mBAAmB;AACxC,SAAS,QAAAC,aAAY;AAiBrB,SAAS,WAAW,aAAqB,SAA0B;AACjE,SAAOD,YAAWC,MAAK,aAAa,OAAO,CAAC;AAC9C;AAEO,SAAS,oBACd,aAC+B;AAC/B,QAAM,QAAQ,CAAC,OAAOA,MAAK,OAAO,KAAK,CAAC;AACxC,QAAM,aAAuB,CAAC;AAE9B,MAAI,aAA4B;AAChC,aAAW,QAAQ,OAAO;AACxB,QAAID,YAAWC,MAAK,aAAa,IAAI,CAAC,GAAG;AACvC,mBAAa;AACb;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,WAAY,QAAO;AAGxB,QAAM,kBAAkB;AAAA,IACtBA,MAAK,YAAY,YAAY;AAAA,IAC7BA,MAAK,YAAY,YAAY;AAAA,IAC7BA,MAAK,YAAY,WAAW;AAAA,IAC5BA,MAAK,YAAY,WAAW;AAAA;AAAA,IAE5BA,MAAK,YAAY,UAAU;AAAA,IAC3BA,MAAK,YAAY,UAAU;AAAA,EAC7B;AAEA,aAAW,OAAO,iBAAiB;AACjC,QAAI,WAAW,aAAa,GAAG,EAAG,YAAW,KAAK,GAAG;AAAA,EACvD;AAGA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,YAAYA,MAAK,aAAa,UAAU;AAAA,IACxC;AAAA,EACF;AACF;AAUA,IAAM,sBAAsB,oBAAI,IAAI;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAQM,SAAS,0BACd,SACA,SAC6B;AAC7B,QAAM,WAAW,SAAS,YAAY;AACtC,QAAM,aAAa,SAAS,cAAc;AAC1C,QAAM,UAAuC,CAAC;AAC9C,QAAM,UAAU,oBAAI,IAAY;AAEhC,WAAS,KAAK,KAAa,OAAe;AACxC,QAAI,QAAQ,SAAU;AACtB,QAAI,QAAQ,IAAI,GAAG,EAAG;AACtB,YAAQ,IAAI,GAAG;AAEf,UAAM,YAAY,oBAAoB,GAAG;AACzC,QAAI,WAAW;AACb,cAAQ,KAAK,EAAE,aAAa,KAAK,UAAU,CAAC;AAE5C;AAAA,IACF;AAEA,QAAI,UAAyD,CAAC;AAC9D,QAAI;AACF,gBAAU,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC,EAAE,IAAI,CAAC,OAAO;AAAA,QAC9D,MAAM,EAAE;AAAA,QACR,aAAa,EAAE,YAAY;AAAA,MAC7B,EAAE;AAAA,IACJ,QAAQ;AACN;AAAA,IACF;AAEA,eAAW,OAAO,SAAS;AACzB,UAAI,CAAC,IAAI,YAAa;AACtB,UAAI,WAAW,IAAI,IAAI,IAAI,EAAG;AAE9B,UAAI,IAAI,KAAK,WAAW,GAAG,KAAK,IAAI,SAAS,IAAK;AAClD,WAAKA,MAAK,KAAK,IAAI,IAAI,GAAG,QAAQ,CAAC;AAAA,IACrC;AAAA,EACF;AAEA,OAAK,SAAS,CAAC;AACf,SAAO;AACT;;;AC7HA,SAAS,cAAAC,aAAY,gBAAAC,eAAc,qBAAqB;AACxD,SAAS,QAAAC,OAAM,UAAU,eAAe;AAExC,SAAS,iBAAiB,aAAa,oBAAoB;AAK3D,SAAS,yBAAyB;AAYlC,IAAM,oBAAoB,CAAC,OAAO,QAAQ,OAAO,MAAM;AAKhD,SAAS,qBAAqB,aAAoC;AACvE,aAAW,OAAO,mBAAmB;AACnC,UAAM,aAAaA,MAAK,aAAa,gBAAgB,GAAG,EAAE;AAC1D,QAAIF,YAAW,UAAU,GAAG;AAC1B,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAKO,SAAS,wBAAwB,YAA4B;AAClE,QAAM,QAAQ,WAAW,MAAM,GAAG;AAClC,SAAO,MAAM,MAAM,SAAS,CAAC,KAAK;AACpC;AA0CA,SAAS,aAAa,MAAe,MAAwB;AAC3D,SACE,CAAC,CAAC,QACF,KAAK,SAAS,iBACb,OAAO,KAAK,SAAS,OAAO,OAAO,KAAK,SAAS;AAEtD;AAEA,SAAS,gBAAgB,MAAwD;AAC/E,SACE,CAAC,CAAC,SACD,KAAK,SAAS,mBAAmB,KAAK,SAAS,cAChD,OAAO,KAAK,UAAU;AAE1B;AAEA,SAAS,uBAAuB,KAAc,SAAiC;AAC7E,MAAI,CAAC,OAAO,IAAI,SAAS,mBAAoB,QAAO;AACpD,aAAW,QAAQ,IAAI,cAAc,CAAC,GAAG;AACvC,QAAI,CAAC,KAAM;AACX,QAAI,KAAK,SAAS,oBAAoB,KAAK,SAAS,YAAY;AAC9D,YAAM,MAAM,KAAK;AACjB,YAAM,WACH,KAAK,SAAS,gBAAgB,IAAI,SAAS,WAC3C,gBAAgB,GAAG,KAAK,IAAI,UAAU;AACzC,UAAI,SAAU,QAAO,KAAK;AAAA,IAC5B;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,oBAAoB,KAAuB;AAClD,MAAI,CAAC,OAAO,IAAI,SAAS,mBAAoB,QAAO;AACpD,UAAS,IAAI,cAAwC,CAAC,GAAG;AAAA,IACvD,CAAC,MAAe,MAAM,EAAE,SAAS,mBAAmB,EAAE,SAAS;AAAA,EACjE;AACF;AAEA,IAAM,mBAAmB,oBAAI,IAAI;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,uBAAuB,MAAwB;AACtD,MAAI,SAAS,KAAM,QAAO;AAC1B,MAAI,SAAS,OAAW,QAAO;AAC/B,MAAI,OAAO,SAAS,SAAU,QAAO;AACrC,MAAI,MAAM,QAAQ,IAAI,EAAG,QAAO,KAAK,IAAI,sBAAsB;AAE/D,QAAM,MAAM;AACZ,QAAM,MAA+B,CAAC;AACtC,QAAM,OAAO,OAAO,KAAK,GAAG,EACzB,OAAO,CAAC,MAAM,CAAC,iBAAiB,IAAI,CAAC,CAAC,EACtC,KAAK;AACR,aAAW,KAAK,MAAM;AAEpB,QAAI,EAAE,WAAW,GAAG,EAAG;AACvB,QAAI,CAAC,IAAI,uBAAuB,IAAI,CAAC,CAAC;AAAA,EACxC;AACA,SAAO;AACT;AAEA,SAAS,cAAc,GAAY,GAAqB;AACtD,MAAI;AACF,WACE,KAAK,UAAU,uBAAuB,CAAC,CAAC,MACxC,KAAK,UAAU,uBAAuB,CAAC,CAAC;AAAA,EAE5C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,oCAAoC,UAAgC;AAC3E,QAAM,MAAM,oBAAI,IAAY;AAC5B,MAAI,CAAC,YAAY,SAAS,SAAS,mBAAoB,QAAO;AAC9D,aAAW,QAAQ,SAAS,cAAc,CAAC,GAAG;AAC5C,QAAI,CAAC,KAAM;AACX,QAAI,KAAK,SAAS,oBAAoB,KAAK,SAAS,WAAY;AAChE,UAAM,MAAM,KAAK;AACjB,QAAI,CAAC,gBAAgB,GAAG,EAAG;AAC3B,UAAM,MAAM,IAAI;AAChB,QAAI,OAAO,QAAQ,SAAU;AAC7B,QAAI,IAAI,WAAW,SAAS,GAAG;AAC7B,UAAI,IAAI,IAAI,MAAM,UAAU,MAAM,CAAC;AAAA,IACrC;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,kCAAkC,KAIlC;AACP,WAAS,iBAAiB,MAAwB;AAChD,QAAI,IAAI;AAGR,WAAO,GAAG;AACR,UAAI,EAAE,SAAS,oBAAoB,EAAE,SAAS,uBAAuB;AACnE,YAAI,EAAE;AACN;AAAA,MACF;AACA,UAAI,EAAE,SAAS,yBAAyB;AACtC,YAAI,EAAE;AACN;AAAA,MACF;AACA,UAAI,EAAE,SAAS,2BAA2B;AACxC,YAAI,EAAE;AACN;AAAA,MACF;AACA;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,WAAS,qCACPG,UACA,MACgB;AAChB,QAAI,CAACA,YAAWA,SAAQ,SAAS,UAAW,QAAO;AACnD,eAAW,QAAQA,SAAQ,QAAQ,CAAC,GAAG;AACrC,UAAI,MAAM,SAAS,sBAAuB;AAC1C,iBAAW,QAAQ,KAAK,gBAAgB,CAAC,GAAG;AAC1C,cAAM,KAAK,MAAM;AACjB,YAAI,CAAC,aAAa,IAAI,IAAI,EAAG;AAC7B,cAAM,OAAO,iBAAiB,MAAM,IAAI;AACxC,YAAI,CAAC,KAAM,QAAO;AAClB,YAAI,KAAK,SAAS,kBAAmB,QAAO;AAC5C,YACE,KAAK,SAAS,oBACd,aAAa,KAAK,QAAQ,cAAc,KACxC,iBAAiB,KAAK,YAAY,CAAC,CAAC,GAAG,SAAS,mBAChD;AACA,iBAAO,iBAAiB,KAAK,YAAY,CAAC,CAAC;AAAA,QAC7C;AACA,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAMA,QAAM,UAAU,KAAK;AACrB,MAAI,WAAW,QAAQ,SAAS,WAAW;AACzC,eAAW,QAAQ,QAAQ,QAAQ,CAAC,GAAG;AACrC,UAAI,CAAC,QAAQ,KAAK,SAAS,2BAA4B;AACvD,YAAM,OAAO,iBAAiB,KAAK,WAAW;AAC9C,UAAI,CAAC,KAAM;AAEX,UAAI,KAAK,SAAS,mBAAmB;AACnC,eAAO,EAAE,MAAM,OAAO,WAAW,MAAM,QAAQ;AAAA,MACjD;AACA,UACE,KAAK,SAAS,oBACd,aAAa,KAAK,QAAQ,cAAc,KACxC,iBAAiB,KAAK,YAAY,CAAC,CAAC,GAAG,SAAS,mBAChD;AACA,eAAO;AAAA,UACL,MAAM;AAAA,UACN,WAAW,iBAAiB,KAAK,YAAY,CAAC,CAAC;AAAA,UAC/C;AAAA,QACF;AAAA,MACF;AACA,UAAI,KAAK,SAAS,gBAAgB,OAAO,KAAK,SAAS,UAAU;AAC/D,cAAM,WAAW;AAAA,UACf;AAAA,UACA,KAAK;AAAA,QACP;AACA,YAAI,SAAU,QAAO,EAAE,MAAM,OAAO,WAAW,UAAU,QAAQ;AAAA,MACnE;AACA;AAAA,IACF;AAAA,EACF;AAGA,MAAI,CAAC,WAAW,QAAQ,SAAS,UAAW,QAAO;AAEnD,aAAW,QAAQ,QAAQ,QAAQ,CAAC,GAAG;AACrC,QAAI,CAAC,QAAQ,KAAK,SAAS,sBAAuB;AAClD,UAAM,OAAO,KAAK;AAClB,QAAI,CAAC,QAAQ,KAAK,SAAS,uBAAwB;AACnD,UAAM,OAAO,KAAK;AAClB,UAAM,QAAQ,KAAK;AACnB,UAAM,kBACJ,MAAM,SAAS,sBACf,aAAa,KAAK,QAAQ,QAAQ,KAClC,aAAa,KAAK,UAAU,SAAS;AACvC,QAAI,CAAC,gBAAiB;AAEtB,QAAI,OAAO,SAAS,mBAAmB;AACrC,aAAO,EAAE,MAAM,OAAO,WAAW,OAAO,QAAQ;AAAA,IAClD;AACA,QACE,OAAO,SAAS,oBAChB,aAAa,MAAM,QAAQ,cAAc,KACzC,MAAM,YAAY,CAAC,GAAG,SAAS,mBAC/B;AACA,aAAO,EAAE,MAAM,OAAO,WAAW,MAAM,UAAU,CAAC,GAAG,QAAQ;AAAA,IAC/D;AACA,QAAI,OAAO,SAAS,gBAAgB,OAAO,MAAM,SAAS,UAAU;AAClE,YAAM,WAAW;AAAA,QACf;AAAA,QACA,MAAM;AAAA,MACR;AACA,UAAI,SAAU,QAAO,EAAE,MAAM,OAAO,WAAW,UAAU,QAAQ;AAAA,IACnE;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,8CACP,WACa;AACb,QAAM,MAAM,oBAAI,IAAY;AAC5B,MAAI,CAAC,aAAa,UAAU,SAAS,kBAAmB,QAAO;AAC/D,aAAW,MAAM,UAAU,YAAY,CAAC,GAAG;AACzC,QAAI,CAAC,MAAM,GAAG,SAAS,mBAAoB;AAC3C,UAAM,QAAQ,uBAAuB,IAAI,OAAO;AAChD,QAAI,OAAO;AACT,iBAAW,MAAM,oCAAoC,KAAK,EAAG,KAAI,IAAI,EAAE;AAAA,IACzE;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,8BAA8B,WAIrC;AACA,MAAI,CAAC,aAAa,UAAU,SAAS,mBAAmB;AACtD,WAAO,EAAE,WAAW,MAAM,UAAU,MAAM,cAAc,MAAM;AAAA,EAChE;AAEA,aAAW,MAAM,UAAU,YAAY,CAAC,GAAG;AACzC,QAAI,CAAC,MAAM,GAAG,SAAS,mBAAoB;AAE3C,UAAM,UAAU,uBAAuB,IAAI,SAAS;AACpD,UAAM,QAAQ,uBAAuB,IAAI,OAAO;AAEhD,UAAM,kBACJ,SAAS,SAAS,sBAClB,uBAAuB,SAAS,QAAQ,MAAM;AAEhD,UAAM,YAAY,QAAQ,oCAAoC,KAAK,IAAI,oBAAI,IAAY;AACvF,UAAM,iBAAiB,UAAU,OAAO;AAExC,QAAI,CAAC,mBAAmB,CAAC,eAAgB;AAEzC,UAAM,OACJ,OAAO,SAAS,sBAAsB,CAAC,oBAAoB,KAAK;AAClE,WAAO,EAAE,WAAW,IAAI,UAAU,OAAO,cAAc,KAAK;AAAA,EAC9D;AAEA,SAAO,EAAE,WAAW,MAAM,UAAU,MAAM,cAAc,MAAM;AAChE;AAEA,SAAS,wBAAwB,SAA+B;AAC9D,QAAM,QAAQ,oBAAI,IAAY;AAC9B,MAAI,CAAC,WAAW,QAAQ,SAAS,UAAW,QAAO;AAEnD,aAAW,QAAQ,QAAQ,QAAQ,CAAC,GAAG;AACrC,QAAI,MAAM,SAAS,qBAAqB;AACtC,iBAAW,QAAQ,KAAK,cAAc,CAAC,GAAG;AACxC,cAAM,QAAQ,MAAM;AACpB,YAAI,OAAO,SAAS,gBAAgB,OAAO,MAAM,SAAS,UAAU;AAClE,gBAAM,IAAI,MAAM,IAAI;AAAA,QACtB;AAAA,MACF;AACA;AAAA,IACF;AACA,QAAI,MAAM,SAAS,uBAAuB;AACxC,iBAAW,QAAQ,KAAK,gBAAgB,CAAC,GAAG;AAC1C,cAAM,KAAK,MAAM;AACjB,YAAI,IAAI,SAAS,gBAAgB,OAAO,GAAG,SAAS,UAAU;AAC5D,gBAAM,IAAI,GAAG,IAAI;AAAA,QACnB;AAAA,MACF;AAAA,IACF,WAAW,MAAM,SAAS,uBAAuB;AAC/C,UAAI,KAAK,IAAI,SAAS,gBAAgB,OAAO,KAAK,GAAG,SAAS,UAAU;AACtE,cAAM,IAAI,KAAK,GAAG,IAAI;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,uBAAuB,MAAc,MAA2B;AACvE,MAAI,CAAC,KAAK,IAAI,IAAI,EAAG,QAAO;AAC5B,MAAI,IAAI;AACR,SAAO,KAAK,IAAI,GAAG,IAAI,GAAG,CAAC,EAAE,EAAG;AAChC,SAAO,GAAG,IAAI,GAAG,CAAC;AACpB;AAEA,SAAS,mCACP,SACA,MACe;AACf,MAAI,CAAC,WAAW,QAAQ,SAAS,UAAW,QAAO;AACnD,aAAW,QAAQ,QAAQ,QAAQ,CAAC,GAAG;AACrC,QAAI,MAAM,SAAS,oBAAqB;AACxC,UAAM,MAAM,KAAK,QAAQ;AACzB,QAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM;AAC7C,eAAW,QAAQ,KAAK,cAAc,CAAC,GAAG;AACxC,UAAI,MAAM,SAAS,0BAA0B;AAC3C,cAAM,QAAQ,KAAK;AACnB,YAAI,OAAO,SAAS,gBAAgB,OAAO,MAAM,SAAS,UAAU;AAClE,iBAAO,MAAM;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAKA,SAAS,uBACP,KACA,eACA,YACA,WACA,gBAAwB,OACxB,sBAA+B,OACyB;AACxD,QAAM,cAAc,oBAAI,IAAoB;AAC5C,MAAI,UAAU;AAGd,QAAM,YAAY,QAAQ,UAAU;AACpC,QAAM,WAAWC,MAAK,WAAW,WAAW,OAAO;AACnD,QAAM,oBAAoB,SAAS,WAAW,QAAQ,EAAE,QAAQ,OAAO,GAAG;AAG1E,QAAM,sBACJ,kBAAkB,WAAW,IAAI,KAAK,kBAAkB,WAAW,KAAK,IACpE,oBACA,KAAK,iBAAiB;AAE5B,QAAM,OAAO,wBAAwB,IAAI,IAAI;AAE7C,aAAW,QAAQ,eAAe;AAGhC,UAAM,WAAY,KAAK,oBAAoB,sBACvC,GAAG,mBAAmB,IAAI,KAAK,EAAE,SAAS,aAAa,KACvD,GAAG,mBAAmB,IAAI,KAAK,EAAE,GAAG,aAAa;AAIrD,UAAM,gBAAgB,mCAAmC,IAAI,MAAM,QAAQ;AAC3E,QAAI,eAAe;AACjB,kBAAY,IAAI,KAAK,IAAI,aAAa;AACtC,WAAK,IAAI,aAAa;AACtB;AAAA,IACF;AAGA,UAAM,aAAa;AAAA,MACjB,GAAG,KAAK,GACL,QAAQ,aAAa,CAAC,GAAW,MAAc,EAAE,YAAY,CAAC,EAC9D,QAAQ,MAAM,CAAC,MAAc,EAAE,YAAY,CAAC,CAAC;AAAA,MAChD;AAAA,IACF;AACA,gBAAY,IAAI,KAAK,IAAI,UAAU;AACnC,SAAK,IAAI,UAAU;AAGnB,QAAI,QAAQ,KAAK;AAAA,MACf,UAAU;AAAA,MACV,OAAO;AAAA,MACP,MAAM;AAAA,IACR,CAAC;AACD,cAAU;AAAA,EACZ;AAEA,SAAO,EAAE,aAAa,QAAQ;AAChC;AAKA,SAAS,wBACP,SACA,eACA,YACA,WACA,gBAAwB,OACxB,sBAA+B,OACyB;AACxD,QAAM,cAAc,oBAAI,IAAoB;AAC5C,MAAI,UAAU;AAEd,MAAI,CAAC,WAAW,QAAQ,SAAS,WAAW;AAC1C,WAAO,EAAE,aAAa,QAAQ;AAAA,EAChC;AAGA,QAAM,YAAY,QAAQ,UAAU;AACpC,QAAM,WAAWA,MAAK,WAAW,WAAW,OAAO;AACnD,QAAM,oBAAoB,SAAS,WAAW,QAAQ,EAAE,QAAQ,OAAO,GAAG;AAG1E,QAAM,sBACJ,kBAAkB,WAAW,IAAI,KAAK,kBAAkB,WAAW,KAAK,IACpE,oBACA,KAAK,iBAAiB;AAE5B,QAAM,OAAO,wBAAwB,OAAO;AAE5C,aAAW,QAAQ,eAAe;AAEhC,UAAM,aAAa;AAAA,MACjB,GAAG,KAAK,GACL,QAAQ,aAAa,CAAC,GAAW,MAAc,EAAE,YAAY,CAAC,EAC9D,QAAQ,MAAM,CAAC,MAAc,EAAE,YAAY,CAAC,CAAC;AAAA,MAChD;AAAA,IACF;AACA,gBAAY,IAAI,KAAK,IAAI,UAAU;AACnC,SAAK,IAAI,UAAU;AAKnB,UAAM,WAAY,KAAK,oBAAoB,sBACvC,GAAG,mBAAmB,IAAI,KAAK,EAAE,SAAS,aAAa,KACvD,GAAG,mBAAmB,IAAI,KAAK,EAAE,GAAG,aAAa;AACrD,UAAM,UAAU;AAAA,MACd,SAAS,UAAU,eAAe,QAAQ;AAAA,IAC5C;AACA,UAAM,OAAS,QAAQ,KAA4B,OAAqB,CAAC;AACzE,QAAI,MAAM;AAER,UAAI,WAAW;AACf,YAAM,QAAQ,QAAQ,OAAO,CAAC;AAC9B,UACE,OAAO,SAAS,yBAChB,MAAM,YAAY,SAAS,mBAC3B,MAAM,WAAW,UAAU,cAC3B;AACA,mBAAW;AAAA,MACb;AACA,cAAQ,KAAK,OAAO,UAAU,GAAG,IAAI;AACrC,gBAAU;AAAA,IACZ;AAAA,EACF;AAEA,SAAO,EAAE,aAAa,QAAQ;AAChC;AAEA,SAAS,+BACP,WACA,eACA,iBACM;AAEN,QAAM,kBAAkB,MAAM,KAAK,gBAAgB,QAAQ,CAAC,EACzD,IAAI,CAAC,CAAC,QAAQ,UAAU,MAAM,UAAU,MAAM,MAAM,UAAU,GAAG,EACjE,KAAK,IAAI;AAEZ,QAAM,iBAAiB,cACpB,IAAI,CAAC,MAAM;AACV,UAAM,UAAU,UAAU,EAAE,EAAE;AAC9B,UAAM,YACJ,EAAE,kBAAkB,EAAE,eAAe,SAAS,IAC1C,KAAK,EAAE,eAAe,SAAS,KAAK;AAAA,MAClC,EAAE;AAAA,MACF;AAAA,MACA;AAAA,IACF,CAAC,MACD,IAAI,EAAE,eAAe;AAC3B,WAAO,UAAU,OAAO,MAAM,SAAS;AAAA,EACzC,CAAC,EACA,KAAK,IAAI;AAEZ,QAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASlB,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA,EAKf,cAAc;AAAA;AAAA;AAId,QAAM,UAAW,gBAAgB,SAAS,EAAyB;AACnE,YAAU,SAAS,KAAK,OAAO;AACjC;AAUA,SAAS,gCACP,WACA,eACA,iBACM;AACN,QAAM,aAAa,uBAAuB,WAAW,SAAS;AAC9D,QAAM,WAAW,uBAAuB,WAAW,OAAO;AAG1D,MAAI,YAAY,SAAS,oBAAoB;AAC3C,UAAM,mBAAmB,WAAW,YAAY;AAAA,MAC9C,CAAC,OACE,EAAE,SAAS,oBAAoB,EAAE,SAAS,gBACzC,EAAE,KAAK,SAAS,gBAAgB,EAAE,IAAI,SAAS,YAC9C,gBAAgB,EAAE,GAAG,KAAK,EAAE,IAAI,UAAU;AAAA,IACjD;AAEA,QAAI,kBAAkB;AACpB,YAAM,cAAc,iBAAiB;AAGrC,UAAI,aAAa,SAAS,cAAc;AAGtC,cAAM,kBAAkB,MAAM,KAAK,gBAAgB,QAAQ,CAAC,EACzD,IAAI,CAAC,CAAC,QAAQ,UAAU,MAAM,IAAI,MAAM,MAAM,UAAU,EAAE,EAC1D,KAAK,IAAI;AAEZ,cAAM,mBAAmB,cAAc,eAAe;AACtD,cAAM,eAAgB,gBAAgB,gBAAgB,EAAyB;AAC/E,yBAAiB,QAAQ;AAAA,MAC3B,WAAW,aAAa,SAAS,oBAAoB;AAGnD,YAAI,iBAAiB,uBAAuB,aAAa,OAAO;AAEhE,YAAI,CAAC,kBAAkB,eAAe,SAAS,oBAAoB;AAEjE,gBAAM,YAAY;AAClB,gBAAM,UAAW,gBAAgB,SAAS,EAAyB;AACnE,2BAAiB,QAAQ,WAAW,CAAC,EAAE;AACvC,sBAAY,WAAW,KAAK,QAAQ,WAAW,CAAC,CAAC;AAAA,QACnD;AAGA,mBAAW,CAAC,QAAQ,UAAU,KAAK,gBAAgB,QAAQ,GAAG;AAE5D,gBAAM,SAAS,eAAgB,YAAY;AAAA,YACzC,CAAC,OACE,EAAE,SAAS,oBAAoB,EAAE,SAAS,eAC3C,gBAAgB,EAAE,GAAG,KACrB,EAAE,IAAI,UAAU;AAAA,UACpB;AAEA,cAAI,CAAC,QAAQ;AACX,kBAAM,WAAW,MAAM,MAAM,MAAM,UAAU;AAC7C,kBAAM,UAAW,gBAAgB,QAAQ,EAAyB;AAClE,2BAAgB,WAAW,KAAK,QAAQ,WAAW,CAAC,CAAC;AAAA,UACvD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,UAAU,SAAS,oBAAoB;AACzC,eAAW,QAAQ,eAAe;AAChC,YAAM,UAAU,UAAU,KAAK,EAAE;AAGjC,YAAM,YACJ,KAAK,kBAAkB,KAAK,eAAe,SAAS,IAChD,KAAK,KAAK,eAAe,SAAS,KAAK;AAAA,QACrC,KAAK;AAAA,QACL;AAAA,QACA;AAAA,MACF,CAAC,MACD,IAAI,KAAK,eAAe;AAG9B,YAAM,oBAAoB,SAAS,YAAY;AAAA,QAC7C,CAAC,OACE,EAAE,SAAS,oBAAoB,EAAE,SAAS,eAC3C,gBAAgB,EAAE,GAAG,KACrB,EAAE,IAAI,UAAU;AAAA,MACpB;AAEA,YAAM,WAAW,MAAM,OAAO,MAAM,SAAS;AAC7C,YAAM,UAAW,gBAAgB,QAAQ,EAAyB;AAClE,YAAM,UAAU,QAAQ,WAAW,CAAC;AAEpC,UAAI,sBAAsB,UAAa,qBAAqB,GAAG;AAE7D,iBAAS,WAAW,iBAAiB,IAAI;AAAA,MAC3C,OAAO;AAEL,iBAAS,WAAW,KAAK,OAAO;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,uCAAuC,QAY1B;AACpB,MAAI;AACF,UAAM,MAAM,YAAY,MAAM;AAC9B,UAAM,QAAQ,kCAAkC,GAAG;AACnD,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,QACL,OACE;AAAA,MACJ;AAAA,IACF;AAEA,UAAM,oBAAoB;AAAA,MACxB,MAAM;AAAA,IACR;AACA,UAAM,iBAAiB,8BAA8B,MAAM,SAAS;AACpE,UAAM,aACJ,kBAAkB,OAAO,KAAK,eAAe,cAAc;AAE7D,WAAO;AAAA,MACL,MAAM,EAAE,mBAAmB,WAAW;AAAA,MACtC;AAAA,MACA,WAAW,MAAM;AAAA,MACjB,MAAM,MAAM;AAAA,MACZ,gBAAgB;AAAA,IAClB;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,MACL,OACE;AAAA,IACJ;AAAA,EACF;AACF;AAEO,SAAS,oCACd,QACwB;AACxB,QAAM,MAAM,uCAAuC,MAAM;AACzD,MAAI,WAAW,KAAK;AAElB,UAAM,oBAAoB,+BAA+B,MAAM;AAC/D,WAAO;AAAA,MACL;AAAA,MACA,YAAY,kBAAkB,OAAO;AAAA,IACvC;AAAA,EACF;AACA,SAAO,IAAI;AACb;AA4CA,SAAS,+BAA+B,QAA6B;AACnE,QAAM,MAAM,oBAAI,IAAY;AAC5B,QAAM,KAAK;AACX,aAAW,KAAK,OAAO,SAAS,EAAE,GAAG;AACnC,QAAI,EAAE,CAAC,EAAG,KAAI,IAAI,EAAE,CAAC,CAAC;AAAA,EACxB;AACA,SAAO;AACT;AAEA,SAAS,wBACP,eACA,eACgB;AAChB,SAAO,cAAc,OAAO,CAAC,MAAM,CAAC,cAAc,IAAI,EAAE,EAAE,CAAC;AAC7D;AAKA,SAAS,gCAAgC,MAA4B;AACnE,MAAI,KAAK,kBAAkB,KAAK,eAAe,SAAS,GAAG;AAEzD,WAAO,KAAK,KAAK,eAAe,SAAS,KAAK;AAAA,MAC5C,KAAK;AAAA,MACL;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AACA,SAAO,IAAI,KAAK,eAAe;AACjC;AAEA,SAAS,2CACP,WACsB;AACtB,QAAM,MAAM,oBAAI,IAAqB;AACrC,MAAI,CAAC,aAAa,UAAU,SAAS,kBAAmB,QAAO;AAE/D,aAAW,MAAM,UAAU,YAAY,CAAC,GAAG;AACzC,QAAI,CAAC,MAAM,GAAG,SAAS,mBAAoB;AAC3C,UAAM,QAAQ,uBAAuB,IAAI,OAAO;AAChD,QAAI,CAAC,SAAS,MAAM,SAAS,mBAAoB;AAEjD,eAAW,QAAQ,MAAM,cAAc,CAAC,GAAG;AACzC,UAAI,CAAC,KAAM;AACX,UAAI,KAAK,SAAS,oBAAoB,KAAK,SAAS,WAAY;AAChE,YAAM,MAAM,KAAK;AACjB,UAAI,CAAC,gBAAgB,GAAG,EAAG;AAC3B,YAAM,IAAI,IAAI;AACd,UAAI,OAAO,MAAM,YAAY,CAAC,EAAE,WAAW,SAAS,EAAG;AACvD,YAAM,KAAK,EAAE,MAAM,UAAU,MAAM;AAEnC,UAAI,CAAC,IAAI,IAAI,EAAE,EAAG,KAAI,IAAI,IAAI,KAAK,KAAK;AAAA,IAC1C;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,sBACP,eACA,eACA,WACgB;AAGhB,QAAM,eAAe,2CAA2C,SAAS;AAEzE,SAAO,cAAc,OAAO,CAAC,MAAM;AACjC,QAAI,CAAC,cAAc,IAAI,EAAE,EAAE,EAAG,QAAO;AACrC,UAAM,WAAW,aAAa,IAAI,EAAE,EAAE;AACtC,QAAI,CAAC,SAAU,QAAO;AAEtB,UAAM,cAAc,gCAAgC,CAAC;AACrD,UAAM,aAAc,gBAAgB,WAAW,EAAyB;AACxE,WAAO,CAAC,cAAc,UAAU,UAAU;AAAA,EAC5C,CAAC;AACH;AA8WA,eAAsB,oBACpB,MAOC;AACD,QAAM,aAAa,qBAAqB,KAAK,WAAW;AAExD,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,MACL,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,gBAAgB,CAAC;AAAA,MACjB,YAAY;AAAA,IACd;AAAA,EACF;AAEA,QAAM,iBAAiB,wBAAwB,UAAU;AACzD,QAAM,WAAWC,cAAa,YAAY,OAAO;AACjD,QAAM,cAAc,WAAW,SAAS,MAAM;AAE9C,QAAM,MAAM,uCAAuC,QAAQ;AAC3D,MAAI,WAAW,KAAK;AAClB,WAAO;AAAA,MACL,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,gBAAgB,CAAC;AAAA,MACjB,YAAY;AAAA,MACZ,OAAO,IAAI;AAAA,IACb;AAAA,EACF;AAEA,QAAM,EAAE,MAAM,KAAK,WAAW,MAAM,eAAe,IAAI;AACvD,QAAM,gBAAgB,KAAK;AAE3B,QAAM,eAAe;AAAA,IACnB,KAAK;AAAA,IACL;AAAA,EACF;AACA,QAAM,gBAAgB;AAAA,IACpB,KAAK;AAAA,IACL;AAAA,IACA;AAAA,EACF;AAGA,MAAI,eAA+B,CAAC;AACpC,MAAI,CAAC,KAAK,YAAY;AACpB,mBAAe,KAAK;AAAA,EACtB,OAAO;AAEL,mBAAe,CAAC,GAAG,cAAc,GAAG,aAAa;AACjD,QAAI,aAAa,SAAS,KAAK,CAAC,KAAK,OAAO;AAC1C,YAAM,KAAK,MAAM,KAAK;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AACA,UAAI,CAAC,IAAI;AACP,eAAO;AAAA,UACL,YAAY;AAAA,UACZ,UAAU;AAAA,UACV,gBAAgB,aAAa,IAAI,CAAC,MAAM,EAAE,EAAE;AAAA,UAC5C,YAAY;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,aAAa,WAAW,GAAG;AAC7B,WAAO;AAAA,MACL,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,gBAAgB,aAAa,IAAI,CAAC,MAAM,EAAE,EAAE;AAAA,MAC5C,YAAY,KAAK;AAAA,IACnB;AAAA,EACF;AAEA,MAAI,cAAc;AAIlB,QAAM,gBAAgBC,MAAK,KAAK,aAAa,WAAW,OAAO;AAC/D,QAAM,gBAAgB,kBAAkB,KAAK,WAAW;AACxD,QAAM,qBAAqBA,MAAK,eAAe,WAAW,OAAO;AAEjE,QAAM,YAAYC,YAAW,aAAa,IACtC,KAAK,cACL;AAMJ,QAAM,qBAAqB,WAAW,SAAS,KAAK;AACpD,QAAM,gBAAgB,qBAAqB,KAAK;AAEhD,MAAI;AAIJ,QAAM,oBAAoB,aAAa,OAAO,CAAC,MAAM,CAAC,EAAE,YAAY;AACpE,QAAM,uBAAuB,aAAa,OAAO,CAAC,MAAM,EAAE,YAAY;AAGtE,MAAI,SAAS,OAAO;AAClB,UAAM,SAAS;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,sBAAkB,OAAO;AACzB,QAAI,OAAO,QAAS,eAAc;AAAA,EACpC,OAAO;AACL,UAAM,SAAS;AAAA,MACb,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,sBAAkB,OAAO;AACzB,QAAI,OAAO,QAAS,eAAc;AAAA,EACpC;AAGA,MAAI,qBAAqB,SAAS,KAAK,iBAAiB;AACtD,UAAM,OAAO,wBAAwB,IAAI,IAAI;AAE7C,eAAW,QAAQ,gBAAgB,OAAO,EAAG,MAAK,IAAI,IAAI;AAE1D,eAAW,QAAQ,sBAAsB;AACvC,YAAM,kBAAkB,KAAK;AAG7B,YAAM,gBAAgB,mCAAmC,IAAI,MAAM,eAAe;AAClF,UAAI,eAAe;AACjB,wBAAgB,IAAI,KAAK,IAAI,aAAa;AAC1C,aAAK,IAAI,aAAa;AACtB;AAAA,MACF;AAGA,YAAM,aAAa;AAAA,QACjB,GAAG,KAAK,GACL,QAAQ,aAAa,CAAC,GAAW,MAAc,EAAE,YAAY,CAAC,EAC9D,QAAQ,MAAM,CAAC,MAAc,EAAE,YAAY,CAAC,CAAC;AAAA,QAChD;AAAA,MACF;AACA,sBAAgB,IAAI,KAAK,IAAI,UAAU;AACvC,WAAK,IAAI,UAAU;AAEnB,UAAI,SAAS,OAAO;AAClB,YAAI,QAAQ,KAAK;AAAA,UACf,UAAU;AAAA,UACV,OAAO;AAAA,UACP,MAAM;AAAA,QACR,CAAC;AAAA,MACH,OAAO;AAEL,cAAM,cAAc;AAAA,UAClB,SAAS,UAAU,eAAe,eAAe;AAAA,QACnD;AACA,cAAM,OAAS,YAAY,KAA4B,OAAqB,CAAC;AAC7E,YAAI,MAAM;AACR,UAAC,IAAI,KAA4B,KAAK,OAAO,GAAG,GAAG,IAAI;AAAA,QACzD;AAAA,MACF;AACA,oBAAc;AAAA,IAChB;AAAA,EACF;AAGA,MAAI,mBAAmB,gBAAgB,OAAO,GAAG;AAC/C,QAAI,eAAe,cAAc,MAAM;AAErC;AAAA,QACE,eAAe;AAAA,QACf;AAAA,QACA;AAAA,MACF;AAAA,IACF,OAAO;AAEL,qCAA+B,WAAW,cAAc,eAAe;AAAA,IACzE;AACA,kBAAc;AAAA,EAChB;AAGA,MAAI,CAAC,KAAK,YAAY;AACpB,QAAI,SAAS,OAAO;AAElB,UAAI,QAAQ,KAAK;AAAA,QACf,UAAU;AAAA,QACV,OAAO;AAAA,QACP,MAAM;AAAA,MACR,CAAC;AACD,oBAAc;AAAA,IAChB,OAAO;AAEL,YAAM,UAAU;AAAA,QACd;AAAA,MACF;AACA,YAAM,OAAS,QAAQ,KAA4B,OAAqB,CAAC;AACzE,UAAI,MAAM;AACR,YAAI,WAAW;AACf,cAAM,cAAe,IAAI,KAA4B;AACrD,cAAM,QAAQ,cAAc,CAAC;AAC7B,YACE,OAAO,SAAS,yBAChB,MAAM,YAAY,SAAS,mBAC3B,MAAM,WAAW,UAAU,cAC3B;AACA,qBAAW;AAAA,QACb;AACA,oBAAY,OAAO,UAAU,GAAG,IAAI;AACpC,sBAAc;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,cAAc,aAAa,GAAG,EAAE,OAAO;AAEvD,MAAI,YAAY,UAAU;AACxB,kBAAc,YAAY,SAAS,OAAO;AAC1C,WAAO;AAAA,MACL,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,gBAAgB,aAAa,IAAI,CAAC,MAAM,EAAE,EAAE;AAAA,MAC5C,YAAY,oCAAoC,OAAO,EAAE;AAAA,IAC3D;AAAA,EACF;AAEA,SAAO;AAAA,IACL,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,gBAAgB,aAAa,IAAI,CAAC,MAAM,EAAE,EAAE;AAAA,IAC5C,YAAY,oCAAoC,OAAO,EAAE;AAAA,EAC3D;AACF;AAoBA,eAAsB,mBACpB,SACmC;AACnC,QAAM,EAAE,YAAY,IAAI;AAExB,QAAM,aAAa,qBAAqB,WAAW;AACnD,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,MACL,SAAS;AAAA;AAAA,MACT,eAAe,CAAC;AAAA,IAClB;AAAA,EACF;AAEA,MAAI;AACF,UAAM,WAAWF,cAAa,YAAY,OAAO;AAIjD,QAAI,UAAU,SAAS;AAAA,MACrB;AAAA,MACA;AAAA,IACF;AAGA,cAAU,QAAQ;AAAA,MAChB;AAAA,MACA;AAAA,IACF;AAGA,cAAU,QAAQ;AAAA,MAChB;AAAA,MACA;AAAA,IACF;AAGA,cAAU,QAAQ;AAAA,MAChB;AAAA,MACA;AAAA,IACF;AAGA,cAAU,QAAQ;AAAA,MAChB;AAAA,MACA;AAAA,IACF;AAGA,cAAU,QAAQ;AAAA,MAChB;AAAA,MACA;AAAA,IACF;AAIA,cAAU,QAAQ;AAAA,MAChB;AAAA,MACA;AAAA,IACF;AAGA,cAAU,QAAQ,QAAQ,WAAW,MAAM;AAE3C,QAAI,YAAY,UAAU;AACxB,oBAAc,YAAY,SAAS,OAAO;AAC1C,aAAO;AAAA,QACL,SAAS;AAAA,QACT,eAAe,CAAC,UAAU;AAAA,MAC5B;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,eAAe,CAAC;AAAA,IAClB;AAAA,EACF,SAAS,OAAO;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IAC9D;AAAA,EACF;AACF;AAkBA,SAAS,6BACP,WACiC;AACjC,MAAI,CAAC,UAAW,QAAO;AAGvB,MAAI,gBAAgB,SAAS,GAAG;AAC9B,UAAM,MAAM,UAAU;AACtB,QAAI,QAAQ,WAAW,QAAQ,UAAU,QAAQ,OAAO;AACtD,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAGA,MAAI,UAAU,SAAS,mBAAmB;AACxC,UAAM,UAAU,UAAU,WAAW,CAAC;AACtC,QAAI,WAAW,gBAAgB,OAAO,GAAG;AACvC,YAAM,MAAM,QAAQ;AACpB,UAAI,QAAQ,WAAW,QAAQ,UAAU,QAAQ,OAAO;AACtD,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAMA,SAAS,4BACP,WACqC;AACrC,MAAI,CAAC,aAAa,UAAU,SAAS,kBAAmB,QAAO;AAE/D,QAAM,WAAW,UAAU,YAAY,CAAC;AACxC,MAAI,SAAS,SAAS,EAAG,QAAO;AAEhC,QAAM,cAAc,SAAS,CAAC;AAC9B,MAAI,CAAC,eAAe,YAAY,SAAS,mBAAoB,QAAO;AAGpE,MAAI;AACF,UAAM,MAA+B,CAAC;AACtC,eAAW,QAAQ,YAAY,cAAc,CAAC,GAAG;AAC/C,UAAI,CAAC,QAAS,KAAK,SAAS,oBAAoB,KAAK,SAAS;AAC5D;AAEF,YAAM,MAAM,KAAK;AACjB,UAAI,UAAyB;AAC7B,UAAI,KAAK,SAAS,cAAc;AAC9B,kBAAU,IAAI;AAAA,MAChB,WAAW,gBAAgB,GAAG,GAAG;AAC/B,kBAAU,IAAI;AAAA,MAChB;AACA,UAAI,CAAC,QAAS;AAEd,YAAM,MAAM,KAAK;AACjB,UAAI,gBAAgB,GAAG,GAAG;AACxB,YAAI,OAAO,IAAI,IAAI;AAAA,MACrB,WACE,KAAK,SAAS,oBACb,KAAK,SAAS,aAAa,OAAO,IAAI,UAAU,UACjD;AACA,YAAI,OAAO,IAAI,IAAI;AAAA,MACrB,WACE,KAAK,SAAS,oBACb,KAAK,SAAS,aAAa,OAAO,IAAI,UAAU,WACjD;AACA,YAAI,OAAO,IAAI,IAAI;AAAA,MACrB,WAAW,KAAK,SAAS,mBAAmB;AAE1C,cAAM,MAAiB,CAAC;AACxB,mBAAW,MAAM,IAAI,YAAY,CAAC,GAAG;AACnC,cAAI,gBAAgB,EAAE,EAAG,KAAI,KAAK,GAAG,KAAK;AAAA,mBAExC,IAAI,SAAS,oBACZ,IAAI,SAAS,aAAa,OAAO,GAAG,UAAU;AAE/C,gBAAI,KAAK,GAAG,KAAK;AAAA,mBAEjB,IAAI,SAAS,oBACZ,IAAI,SAAS,aAAa,OAAO,GAAG,UAAU;AAE/C,gBAAI,KAAK,GAAG,KAAK;AAAA,QACrB;AACA,YAAI,OAAO,IAAI;AAAA,MACjB;AAAA,IACF;AACA,WAAO,OAAO,KAAK,GAAG,EAAE,SAAS,IAAI,MAAM;AAAA,EAC7C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AASO,SAAS,0BACd,YACiC;AACjC,QAAM,UAAU,oBAAI,IAAgC;AAEpD,MAAI;AACF,UAAM,SAASA,cAAa,YAAY,OAAO;AAC/C,UAAM,MAAM,YAAY,MAAM;AAC9B,UAAM,QAAQ,kCAAkC,GAAG;AAEnD,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,IACT;AAEA,UAAM,EAAE,UAAU,IAAI;AACtB,UAAM,aAAa,2CAA2C,SAAS;AAEvE,eAAW,CAAC,QAAQ,SAAS,KAAK,YAAY;AAC5C,YAAM,WAAW,6BAA6B,SAAS;AACvD,UAAI,UAAU;AACZ,cAAM,UAAU,4BAA4B,SAAS;AACrD,gBAAQ,IAAI,QAAQ,EAAE,UAAU,QAAQ,CAAC;AAAA,MAC3C;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,uDAAuD,KAAK;AAAA,EAC5E;AAEA,SAAO;AACT;AAMA,SAAS,8BACP,WACA,QAC6C;AAC7C,QAAM,cAAc,UAAU,MAAM;AAEpC,MAAI,CAAC,aAAa,UAAU,SAAS,kBAAmB,QAAO;AAE/D,aAAW,MAAM,UAAU,YAAY,CAAC,GAAG;AACzC,QAAI,CAAC,MAAM,GAAG,SAAS,mBAAoB;AAC3C,UAAM,QAAQ,uBAAuB,IAAI,OAAO;AAChD,QAAI,CAAC,SAAS,MAAM,SAAS,mBAAoB;AAEjD,eAAW,QAAQ,MAAM,cAAc,CAAC,GAAG;AACzC,UAAI,CAAC,KAAM;AACX,UAAI,KAAK,SAAS,oBAAoB,KAAK,SAAS,WAAY;AAChE,YAAM,MAAM,KAAK;AACjB,UAAI,CAAC,gBAAgB,GAAG,EAAG;AAC3B,UAAI,IAAI,UAAU,aAAa;AAC7B,eAAO,EAAE,MAAM,UAAU,MAAM;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAYO,SAAS,2BACd,YACA,QACA,UACwB;AACxB,MAAI;AACF,UAAM,SAASA,cAAa,YAAY,OAAO;AAC/C,UAAM,MAAM,YAAY,MAAM;AAC9B,UAAM,QAAQ,kCAAkC,GAAG;AAEnD,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,EAAE,UAAU,IAAI;AACtB,UAAM,WAAW,8BAA8B,WAAW,MAAM;AAEhE,QAAI,CAAC,UAAU;AACb,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,gBAAgB,MAAM;AAAA,MAC/B;AAAA,IACF;AAEA,UAAM,EAAE,KAAK,IAAI;AACjB,UAAM,YAAY,KAAK;AAGvB,QAAI,gBAAgB,SAAS,GAAG;AAE9B,gBAAU,QAAQ;AAAA,IACpB,WAAW,WAAW,SAAS,mBAAmB;AAEhD,YAAM,UAAU,UAAU,WAAW,CAAC;AACtC,UAAI,WAAW,gBAAgB,OAAO,GAAG;AACvC,gBAAQ,QAAQ;AAAA,MAClB,OAAO;AAEL,cAAM,eAAgB,gBAAgB,IAAI,QAAQ,GAAG,EAAyB;AAC9E,YAAI,UAAU,YAAY,UAAU,SAAS,SAAS,GAAG;AACvD,oBAAU,SAAS,CAAC,IAAI;AAAA,QAC1B,OAAO;AACL,oBAAU,WAAW,CAAC,YAAY;AAAA,QACpC;AAAA,MACF;AAAA,IACF,OAAO;AACL,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,gBAAgB,MAAM;AAAA,MAC/B;AAAA,IACF;AAEA,UAAM,UAAU,aAAa,GAAG,EAAE;AAClC,kBAAc,YAAY,SAAS,OAAO;AAC1C,WAAO,EAAE,SAAS,KAAK;AAAA,EACzB,SAAS,OAAO;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IAC9D;AAAA,EACF;AACF;AAUO,SAAS,yBACd,YACA,QACA,UACA,SACwB;AACxB,MAAI;AACF,UAAM,SAASA,cAAa,YAAY,OAAO;AAC/C,UAAM,MAAM,YAAY,MAAM;AAC9B,UAAM,QAAQ,kCAAkC,GAAG;AAEnD,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,EAAE,UAAU,IAAI;AACtB,UAAM,WAAW,8BAA8B,WAAW,MAAM;AAEhE,QAAI,CAAC,UAAU;AACb,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,gBAAgB,MAAM;AAAA,MAC/B;AAAA,IACF;AAEA,UAAM,EAAE,KAAK,IAAI;AAGjB,UAAM,cAAc,KAAK,UAAU,OAAO;AAC1C,UAAM,eAAe,KAAK,QAAQ,MAAM,WAAW;AACnD,UAAM,eAAgB,gBAAgB,YAAY,EAAyB;AAG3E,SAAK,QAAQ;AAEb,UAAM,UAAU,aAAa,GAAG,EAAE;AAClC,kBAAc,YAAY,SAAS,OAAO;AAC1C,WAAO,EAAE,SAAS,KAAK;AAAA,EACzB,SAAS,OAAO;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IAC9D;AAAA,EACF;AACF;;;ACh3DA,SAAS,gBAAAG,eAAc,iBAAAC,sBAAqB;AAuCrC,SAAS,qBAAqB,kBAAmC;AACtE,MAAI;AACF,UAAM,UAAUC,cAAa,kBAAkB,OAAO;AAGtD,QAAI,oBAAoB,KAAK,OAAO,GAAG;AACrC,aAAO;AAAA,IACT;AAOA,UAAM,iBAAiB;AACvB,UAAM,QAAQ,QAAQ,MAAM,cAAc;AAE1C,QAAI,CAAC,OAAO;AAEV,aAAO;AAAA,IACT;AAEA,UAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAQvB,UAAM,aAAa,QAAQ;AAAA,MACzB;AAAA,MACA,KAAK,cAAc;AAAA,IACrB;AAEA,IAAAC,eAAc,kBAAkB,YAAY,OAAO;AACnD,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAWA,eAAsB,gBACpB,SACoC;AACpC,QAAM,EAAE,SAAS,YAAY,oBAAoB,WAAW,QAAQ,SAAS,IAAI;AACjF,QAAM,QAAQ,KAAK,IAAI;AAEvB,QAAM,SAAoC;AAAA,IACxC,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,mBAAmB;AAAA,IACnB,UAAU;AAAA,EACZ;AAEA,MAAI;AAEF,iBAAa,+BAA+B,QAAQ;AACpD,UAAM,QAAQ,oBAAoB,OAAO;AAGzC,QAAI,CAAC,MAAM,WAAW;AACpB,aAAO,QAAQ;AACf,aAAO,WAAW,KAAK,IAAI,IAAI;AAC/B,aAAO;AAAA,IACT;AAGA,QAAI,MAAM,wBAAwB,CAAC,oBAAoB;AACrD,mBAAa,qCAAqC,SAAS;AAC3D,YAAM,KAAK,qBAAqB,OAAO;AACvC,UAAI;AACF,cAAM,oBAAoB,IAAI,SAAS,CAAC,qBAAqB,GAAG,EAAE,QAAQ,SAAS,CAAC;AACpF,eAAO,eAAe;AAAA,MACxB,SAAS,KAAK;AACZ,cAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,eAAO,QAAQ,uCAAuC,GAAG;AACzD,eAAO,WAAW,KAAK,IAAI,IAAI;AAC/B,eAAO;AAAA,MACT;AAAA,IACF;AAGA,QAAI,MAAM,uBAAuB,MAAM,kBAAkB;AACvD,mBAAa,oCAAoC,QAAQ;AACzD,aAAO,iBAAiB,qBAAqB,MAAM,gBAAgB;AAAA,IACrE;AAGA,QAAI,CAAC,WAAW;AAEd,YAAM,eAAe,oBAAoB,OAAO;AAKhD,UAAI,CAAC,aAAa,mBAAmB,OAAO,gBAAgB;AAC1D,qBAAa,kCAAkC,MAAM;AACrD,cAAM,KAAK,qBAAqB,OAAO;AACvC,YAAI;AACF,gBAAM,qBAAqB,IAAI,SAAS,EAAE,QAAQ,SAAS,CAAC;AAC5D,iBAAO,WAAW;AAAA,QACpB,SAAS,KAAK;AACZ,gBAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAE3D,iBAAO,QAAQ,iBAAiB,GAAG;AAAA,QACrC;AAGA,cAAM,aAAa,oBAAoB,OAAO;AAC9C,eAAO,oBAAoB,WAAW;AAAA,MACxC;AAAA,IACF,OAAO;AACL,mBAAa,mCAAmC,MAAM;AAAA,IACxD;AAEA,WAAO,WAAW,KAAK,IAAI,IAAI;AAC/B,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,UAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,WAAO,QAAQ,gCAAgC,GAAG;AAClD,WAAO,WAAW,KAAK,IAAI,IAAI;AAC/B,WAAO;AAAA,EACT;AACF;AAUO,SAAS,yBAAyB,OAAmC;AAC1E,MAAI,CAAC,MAAM,WAAW;AACpB,WAAO;AAAA,EACT;AAEA,SACE,MAAM,wBACN,MAAM,uBACN,CAAC,MAAM;AAEX;","names":["existsSync","join","existsSync","readFileSync","join","program","join","readFileSync","join","existsSync","readFileSync","writeFileSync","readFileSync","writeFileSync"]}
@@ -1,67 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // src/commands/init/versioning.ts
4
- import { createRequire } from "module";
5
- import { existsSync, readFileSync } from "fs";
6
- import { join } from "path";
7
- var require2 = createRequire(import.meta.url);
8
- function isWithinDir(childPath, parentPath) {
9
- const parent = parentPath.endsWith("/") ? parentPath : parentPath + "/";
10
- return childPath === parentPath || childPath.startsWith(parent);
11
- }
12
- function isPnpmWorkspaceRoot(dir) {
13
- if (!dir) return false;
14
- return existsSync(join(dir, "pnpm-workspace.yaml"));
15
- }
16
- function workspaceHasPackage(workspaceRoot, pkgName) {
17
- if (!workspaceRoot) return false;
18
- return existsSync(join(workspaceRoot, "packages", pkgName, "package.json"));
19
- }
20
- function tryReadInstalledVersion(pkgName) {
21
- try {
22
- const depPkg = require2(`${pkgName}/package.json`);
23
- const v = depPkg?.version;
24
- return typeof v === "string" ? v : null;
25
- } catch {
26
- try {
27
- const p = require2.resolve(`${pkgName}/package.json`);
28
- const raw = readFileSync(p, "utf-8");
29
- const parsed = JSON.parse(raw);
30
- return typeof parsed.version === "string" ? parsed.version : null;
31
- } catch {
32
- return null;
33
- }
34
- }
35
- }
36
- function getSelfDependencyVersionRange(pkgName) {
37
- try {
38
- const pkgJson = require2("uilint/package.json");
39
- const deps = pkgJson?.dependencies;
40
- const optDeps = pkgJson?.optionalDependencies;
41
- const peerDeps = pkgJson?.peerDependencies;
42
- const devDeps = pkgJson?.devDependencies;
43
- const v = deps?.[pkgName] ?? optDeps?.[pkgName] ?? peerDeps?.[pkgName] ?? devDeps?.[pkgName];
44
- return typeof v === "string" ? v : null;
45
- } catch {
46
- return null;
47
- }
48
- }
49
- function toInstallSpecifier(pkgName, options = {}) {
50
- const { preferWorkspaceProtocol, workspaceRoot, targetProjectPath } = options;
51
- if (preferWorkspaceProtocol && isPnpmWorkspaceRoot(workspaceRoot) && typeof targetProjectPath === "string" && isWithinDir(targetProjectPath, workspaceRoot || "") && workspaceHasPackage(workspaceRoot, pkgName)) {
52
- return `${pkgName}@workspace:*`;
53
- }
54
- const range = getSelfDependencyVersionRange(pkgName);
55
- if (!range) return pkgName;
56
- if (range.startsWith("workspace:")) {
57
- const installed = tryReadInstalledVersion(pkgName);
58
- return installed ? `${pkgName}@^${installed}` : pkgName;
59
- }
60
- if (range.startsWith("file:")) return pkgName;
61
- if (range.startsWith("link:")) return pkgName;
62
- return `${pkgName}@${range}`;
63
- }
64
-
65
3
  // src/commands/init/constants.ts
66
4
  var GENSTYLEGUIDE_COMMAND_MD = `# React Style Guide Generator
67
5
 
@@ -183,18 +121,18 @@ conventions:
183
121
  `;
184
122
 
185
123
  // src/utils/skill-loader.ts
186
- import { readFileSync as readFileSync2, readdirSync, statSync, existsSync as existsSync2 } from "fs";
187
- import { join as join2, dirname, relative } from "path";
124
+ import { readFileSync, readdirSync, statSync, existsSync } from "fs";
125
+ import { join, dirname, relative } from "path";
188
126
  import { fileURLToPath } from "url";
189
127
  var __filename = fileURLToPath(import.meta.url);
190
128
  var __dirname = dirname(__filename);
191
129
  function getSkillsDir() {
192
- const devPath = join2(__dirname, "..", "..", "skills");
193
- const prodPath = join2(__dirname, "..", "skills");
194
- if (existsSync2(devPath)) {
130
+ const devPath = join(__dirname, "..", "..", "skills");
131
+ const prodPath = join(__dirname, "..", "skills");
132
+ if (existsSync(devPath)) {
195
133
  return devPath;
196
134
  }
197
- if (existsSync2(prodPath)) {
135
+ if (existsSync(prodPath)) {
198
136
  return prodPath;
199
137
  }
200
138
  throw new Error(
@@ -205,13 +143,13 @@ function collectFiles(dir, baseDir) {
205
143
  const files = [];
206
144
  const entries = readdirSync(dir);
207
145
  for (const entry of entries) {
208
- const fullPath = join2(dir, entry);
146
+ const fullPath = join(dir, entry);
209
147
  const stat = statSync(fullPath);
210
148
  if (stat.isDirectory()) {
211
149
  files.push(...collectFiles(fullPath, baseDir));
212
150
  } else if (stat.isFile()) {
213
151
  const relativePath = relative(baseDir, fullPath);
214
- const content = readFileSync2(fullPath, "utf-8");
152
+ const content = readFileSync(fullPath, "utf-8");
215
153
  files.push({ relativePath, content });
216
154
  }
217
155
  }
@@ -219,21 +157,83 @@ function collectFiles(dir, baseDir) {
219
157
  }
220
158
  function loadSkill(name) {
221
159
  const skillsDir = getSkillsDir();
222
- const skillDir = join2(skillsDir, name);
223
- if (!existsSync2(skillDir)) {
160
+ const skillDir = join(skillsDir, name);
161
+ if (!existsSync(skillDir)) {
224
162
  throw new Error(`Skill "${name}" not found in ${skillsDir}`);
225
163
  }
226
- const skillMdPath = join2(skillDir, "SKILL.md");
227
- if (!existsSync2(skillMdPath)) {
164
+ const skillMdPath = join(skillDir, "SKILL.md");
165
+ if (!existsSync(skillMdPath)) {
228
166
  throw new Error(`Skill "${name}" is missing SKILL.md`);
229
167
  }
230
168
  const files = collectFiles(skillDir, skillDir);
231
169
  return { name, files };
232
170
  }
233
171
 
172
+ // src/commands/init/versioning.ts
173
+ import { createRequire } from "module";
174
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
175
+ import { join as join2 } from "path";
176
+ var require2 = createRequire(import.meta.url);
177
+ function isWithinDir(childPath, parentPath) {
178
+ const parent = parentPath.endsWith("/") ? parentPath : parentPath + "/";
179
+ return childPath === parentPath || childPath.startsWith(parent);
180
+ }
181
+ function isPnpmWorkspaceRoot(dir) {
182
+ if (!dir) return false;
183
+ return existsSync2(join2(dir, "pnpm-workspace.yaml"));
184
+ }
185
+ function workspaceHasPackage(workspaceRoot, pkgName) {
186
+ if (!workspaceRoot) return false;
187
+ return existsSync2(join2(workspaceRoot, "packages", pkgName, "package.json"));
188
+ }
189
+ function tryReadInstalledVersion(pkgName) {
190
+ try {
191
+ const depPkg = require2(`${pkgName}/package.json`);
192
+ const v = depPkg?.version;
193
+ return typeof v === "string" ? v : null;
194
+ } catch {
195
+ try {
196
+ const p = require2.resolve(`${pkgName}/package.json`);
197
+ const raw = readFileSync2(p, "utf-8");
198
+ const parsed = JSON.parse(raw);
199
+ return typeof parsed.version === "string" ? parsed.version : null;
200
+ } catch {
201
+ return null;
202
+ }
203
+ }
204
+ }
205
+ function getSelfDependencyVersionRange(pkgName) {
206
+ try {
207
+ const pkgJson = require2("uilint/package.json");
208
+ const deps = pkgJson?.dependencies;
209
+ const optDeps = pkgJson?.optionalDependencies;
210
+ const peerDeps = pkgJson?.peerDependencies;
211
+ const devDeps = pkgJson?.devDependencies;
212
+ const v = deps?.[pkgName] ?? optDeps?.[pkgName] ?? peerDeps?.[pkgName] ?? devDeps?.[pkgName];
213
+ return typeof v === "string" ? v : null;
214
+ } catch {
215
+ return null;
216
+ }
217
+ }
218
+ function toInstallSpecifier(pkgName, options = {}) {
219
+ const { preferWorkspaceProtocol, workspaceRoot, targetProjectPath } = options;
220
+ if (preferWorkspaceProtocol && isPnpmWorkspaceRoot(workspaceRoot) && typeof targetProjectPath === "string" && isWithinDir(targetProjectPath, workspaceRoot || "") && workspaceHasPackage(workspaceRoot, pkgName)) {
221
+ return `${pkgName}@workspace:*`;
222
+ }
223
+ const range = getSelfDependencyVersionRange(pkgName);
224
+ if (!range) return pkgName;
225
+ if (range.startsWith("workspace:")) {
226
+ const installed = tryReadInstalledVersion(pkgName);
227
+ return installed ? `${pkgName}@^${installed}` : pkgName;
228
+ }
229
+ if (range.startsWith("file:")) return pkgName;
230
+ if (range.startsWith("link:")) return pkgName;
231
+ return `${pkgName}@${range}`;
232
+ }
233
+
234
234
  export {
235
- toInstallSpecifier,
236
235
  GENSTYLEGUIDE_COMMAND_MD,
237
- loadSkill
236
+ loadSkill,
237
+ toInstallSpecifier
238
238
  };
239
- //# sourceMappingURL=chunk-VSBVUS56.js.map
239
+ //# sourceMappingURL=chunk-JWSZKDZY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/init/constants.ts","../src/utils/skill-loader.ts","../src/commands/init/versioning.ts"],"sourcesContent":["/**\n * Constants for the install command\n *\n * Contains file content templates for commands.\n */\n\n// ============================================================================\n// Cursor Commands\n// ============================================================================\n\nexport const GENSTYLEGUIDE_COMMAND_MD = `# React Style Guide Generator\n\nAnalyze the React UI codebase to produce a **prescriptive, semantic** style guide. Focus on consistency, intent, and relationships—not specific values.\n\n## Philosophy\n\n1. **Identify the intended architecture** from the best patterns in use\n2. **Prescribe semantic rules** — about consistency and relationships, not pixels\n3. **Stay general** — \"primary buttons should be visually consistent\" not \"buttons use px-4\"\n4. **Focus on intent** — what should FEEL the same, not what values to use\n\n## Analysis Steps\n\n### 1. Detect the Stack\n- Framework: Next.js (App Router? Pages?), Vite, CRA\n- Component system: shadcn, MUI, Chakra, Radix, custom\n- Styling: Tailwind, CSS Modules, styled-components\n- Forms: react-hook-form, Formik, native\n- State: React context, Zustand, Redux, Jotai\n\n### 2. Identify Best Patterns\nExamine the **best-written** components. Look at:\n- \\`components/ui/*\\` — the design system\n- Recently modified files — current standards\n- Shared layouts — structural patterns\n\n### 3. Infer Visual Hierarchy & Intent\nUnderstand the design language:\n- What distinguishes primary vs secondary actions?\n- How is visual hierarchy established?\n- What creates consistency across similar elements?\n\n## Output Format\n\nGenerate at \\`<nextjs app root>/.uilint/styleguide.md\\`:\n\\`\\`\\`yaml\n# Stack\nframework: \nstyling: \ncomponents: \ncomponent_path: \nforms: \n\n# Component Usage (MUST use these)\nuse:\n buttons: \n inputs: \n modals: \n cards: \n feedback: \n icons: \n links: \n\n# Semantic Rules (consistency & relationships)\nsemantics:\n hierarchy:\n - <e.g., \"primary actions must be visually distinct from secondary\">\n - <e.g., \"destructive actions should be visually cautionary\">\n - <e.g., \"page titles should be visually heavier than section titles\">\n consistency:\n - <e.g., \"all primary buttons should share the same visual weight\">\n - <e.g., \"form inputs should have uniform height and padding\">\n - <e.g., \"card padding should be consistent across the app\">\n - <e.g., \"interactive elements should have consistent hover/focus states\">\n spacing:\n - <e.g., \"use the spacing scale — no arbitrary values\">\n - <e.g., \"related elements should be closer than unrelated\">\n - <e.g., \"section spacing should be larger than element spacing\">\n layout:\n - <e.g., \"use gap for sibling spacing, not margin\">\n - <e.g., \"containers should have consistent max-width and padding\">\n\n# Patterns (structural, not values)\npatterns:\n forms: <e.g., \"FormField + Controller + zod schema\">\n conditionals: <e.g., \"cn() for class merging\">\n loading: <e.g., \"Skeleton for content, Spinner for actions\">\n errors: <e.g., \"ErrorBoundary at route, inline for forms\">\n responsive: <e.g., \"mobile-first, standard breakpoints only\">\n\n# Component Authoring\nauthoring:\n - <e.g., \"forwardRef for interactive components\">\n - <e.g., \"variants via CVA or component props, not className overrides\">\n - <e.g., \"extract when used 2+ times\">\n - <e.g., \"'use client' only when needed\">\n\n# Forbidden\nforbidden:\n - <e.g., \"inline style={{}}\">\n - <e.g., \"raw HTML elements when component exists\">\n - <e.g., \"arbitrary values — use scale\">\n - <e.g., \"className overrides that break visual consistency\">\n - <e.g., \"one-off spacing that doesn't match siblings\">\n\n# Legacy (if migration in progress)\nlegacy:\n - <e.g., \"old: CSS modules → new: Tailwind\">\n - <e.g., \"old: Formik → new: react-hook-form\">\n\n# Conventions\nconventions:\n - \n - \n - \n\\`\\`\\`\n\n## Rules\n\n- **Semantic over specific**: \"consistent padding\" not \"p-4\"\n- **Relationships over absolutes**: \"heavier than\" not \"font-bold\"\n- **Intent over implementation**: \"visually distinct\" not \"blue background\"\n- **Prescriptive**: Define target state, not current state\n- **Terse**: No prose. Fragments and short phrases only.\n- **Actionable**: Every rule should be human-verifiable\n- **Omit if N/A**: Skip sections that don't apply\n- **Max 5 items** per section — highest impact only\n`;\n\n","/**\n * Skill Loader Utility\n *\n * Loads Agent Skill files from the bundled skills directory for installation\n * into user projects. Skills follow the Agent Skills specification\n * (agentskills.io).\n */\n\nimport { readFileSync, readdirSync, statSync, existsSync } from \"fs\";\nimport { join, dirname, relative } from \"path\";\nimport { fileURLToPath } from \"url\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Represents a file in a skill directory\n */\nexport interface SkillFile {\n /** Relative path within the skill directory */\n relativePath: string;\n /** File content */\n content: string;\n}\n\n/**\n * Represents a complete skill ready for installation\n */\nexport interface Skill {\n /** Skill name (directory name) */\n name: string;\n /** All files in the skill */\n files: SkillFile[];\n}\n\n/**\n * Get the path to the bundled skills directory\n */\nfunction getSkillsDir(): string {\n // In development: packages/uilint/skills/\n // In production (installed): node_modules/uilint/dist/ -> ../skills/\n const devPath = join(__dirname, \"..\", \"..\", \"skills\");\n const prodPath = join(__dirname, \"..\", \"skills\");\n\n if (existsSync(devPath)) {\n return devPath;\n }\n if (existsSync(prodPath)) {\n return prodPath;\n }\n\n throw new Error(\n \"Could not find skills directory. This is a bug in uilint installation.\"\n );\n}\n\n/**\n * Recursively collect all files in a directory\n */\nfunction collectFiles(dir: string, baseDir: string): SkillFile[] {\n const files: SkillFile[] = [];\n const entries = readdirSync(dir);\n\n for (const entry of entries) {\n const fullPath = join(dir, entry);\n const stat = statSync(fullPath);\n\n if (stat.isDirectory()) {\n files.push(...collectFiles(fullPath, baseDir));\n } else if (stat.isFile()) {\n const relativePath = relative(baseDir, fullPath);\n const content = readFileSync(fullPath, \"utf-8\");\n files.push({ relativePath, content });\n }\n }\n\n return files;\n}\n\n/**\n * Load a specific skill by name\n */\nexport function loadSkill(name: string): Skill {\n const skillsDir = getSkillsDir();\n const skillDir = join(skillsDir, name);\n\n if (!existsSync(skillDir)) {\n throw new Error(`Skill \"${name}\" not found in ${skillsDir}`);\n }\n\n const skillMdPath = join(skillDir, \"SKILL.md\");\n if (!existsSync(skillMdPath)) {\n throw new Error(`Skill \"${name}\" is missing SKILL.md`);\n }\n\n const files = collectFiles(skillDir, skillDir);\n\n return { name, files };\n}\n\n/**\n * Load all available skills\n */\nexport function loadAllSkills(): Skill[] {\n const skillsDir = getSkillsDir();\n const entries = readdirSync(skillsDir);\n const skills: Skill[] = [];\n\n for (const entry of entries) {\n const skillDir = join(skillsDir, entry);\n const stat = statSync(skillDir);\n\n if (stat.isDirectory()) {\n const skillMdPath = join(skillDir, \"SKILL.md\");\n if (existsSync(skillMdPath)) {\n skills.push(loadSkill(entry));\n }\n }\n }\n\n return skills;\n}\n\n/**\n * Get the list of available skill names\n */\nexport function getAvailableSkillNames(): string[] {\n const skillsDir = getSkillsDir();\n const entries = readdirSync(skillsDir);\n const names: string[] = [];\n\n for (const entry of entries) {\n const skillDir = join(skillsDir, entry);\n const stat = statSync(skillDir);\n\n if (stat.isDirectory()) {\n const skillMdPath = join(skillDir, \"SKILL.md\");\n if (existsSync(skillMdPath)) {\n names.push(entry);\n }\n }\n }\n\n return names;\n}\n","import { createRequire } from \"module\";\nimport { existsSync, readFileSync } from \"fs\";\nimport { join } from \"path\";\n\nconst require = createRequire(import.meta.url);\n\nexport interface ToInstallSpecifierOptions {\n /**\n * When true, prefer pnpm workspace protocol for internal packages so local\n * monorepo installs always link the latest workspace version.\n */\n preferWorkspaceProtocol?: boolean;\n /** Workspace root (used for pnpm-workspace detection) */\n workspaceRoot?: string;\n /** Target project path (used to ensure target is within workspace) */\n targetProjectPath?: string;\n}\n\nfunction isWithinDir(childPath: string, parentPath: string): boolean {\n const parent = parentPath.endsWith(\"/\") ? parentPath : parentPath + \"/\";\n return childPath === parentPath || childPath.startsWith(parent);\n}\n\nfunction isPnpmWorkspaceRoot(dir: string | undefined): boolean {\n if (!dir) return false;\n return existsSync(join(dir, \"pnpm-workspace.yaml\"));\n}\n\nfunction workspaceHasPackage(\n workspaceRoot: string | undefined,\n pkgName: string\n): boolean {\n if (!workspaceRoot) return false;\n // In this repo, workspace packages live under /packages/<name>/package.json\n return existsSync(join(workspaceRoot, \"packages\", pkgName, \"package.json\"));\n}\n\nfunction tryReadInstalledVersion(pkgName: string): string | null {\n try {\n \n const depPkg = require(`${pkgName}/package.json`) as Record<\n string,\n unknown\n >;\n const v = depPkg?.version;\n return typeof v === \"string\" ? v : null;\n } catch {\n // Fallback: try filesystem relative to this package (best-effort)\n try {\n const p = require.resolve(`${pkgName}/package.json`);\n const raw = readFileSync(p, \"utf-8\");\n const parsed = JSON.parse(raw) as { version?: string };\n return typeof parsed.version === \"string\" ? parsed.version : null;\n } catch {\n return null;\n }\n }\n}\n\n/**\n * Get the version range for a dependency from uilint's package.json\n *\n * Note: We also check devDependencies so we can expose install-time version\n * ranges (e.g. for uilint-react) without forcing them to be runtime deps of the CLI.\n */\nexport function getSelfDependencyVersionRange(pkgName: string): string | null {\n try {\n \n const pkgJson = require(\"uilint/package.json\") as Record<string, unknown>;\n const deps = pkgJson?.dependencies as Record<string, string> | undefined;\n const optDeps = pkgJson?.optionalDependencies as\n | Record<string, string>\n | undefined;\n const peerDeps = pkgJson?.peerDependencies as\n | Record<string, string>\n | undefined;\n const devDeps = pkgJson?.devDependencies as\n | Record<string, string>\n | undefined;\n\n const v =\n deps?.[pkgName] ??\n optDeps?.[pkgName] ??\n peerDeps?.[pkgName] ??\n devDeps?.[pkgName];\n return typeof v === \"string\" ? v : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Convert package name to install specifier with version (when possible)\n */\nexport function toInstallSpecifier(\n pkgName: string,\n options: ToInstallSpecifierOptions = {}\n): string {\n const { preferWorkspaceProtocol, workspaceRoot, targetProjectPath } = options;\n\n // Local monorepo: force workspace protocol for internal packages.\n if (\n preferWorkspaceProtocol &&\n isPnpmWorkspaceRoot(workspaceRoot) &&\n typeof targetProjectPath === \"string\" &&\n isWithinDir(targetProjectPath, workspaceRoot || \"\") &&\n workspaceHasPackage(workspaceRoot, pkgName)\n ) {\n return `${pkgName}@workspace:*`;\n }\n\n const range = getSelfDependencyVersionRange(pkgName);\n if (!range) return pkgName;\n if (range.startsWith(\"workspace:\")) {\n // In published builds, pnpm usually rewrites workspace: to a semver range.\n // But if it doesn't, fall back to the actually installed dependency version.\n const installed = tryReadInstalledVersion(pkgName);\n return installed ? `${pkgName}@^${installed}` : pkgName;\n }\n if (range.startsWith(\"file:\")) return pkgName;\n if (range.startsWith(\"link:\")) return pkgName;\n return `${pkgName}@${range}`;\n}\n"],"mappings":"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","names":["existsSync","readFileSync","join","require"]}
@@ -3,10 +3,10 @@ import {
3
3
  GENSTYLEGUIDE_COMMAND_MD,
4
4
  loadSkill,
5
5
  toInstallSpecifier
6
- } from "./chunk-VSBVUS56.js";
6
+ } from "./chunk-JWSZKDZY.js";
7
7
  import {
8
8
  loadSelectedRules
9
- } from "./chunk-TKJ27W62.js";
9
+ } from "./chunk-VKI3SQMQ.js";
10
10
  import {
11
11
  detectPackageManager
12
12
  } from "./chunk-EKZZVYPF.js";
@@ -16,7 +16,7 @@ import { join } from "path";
16
16
  function createPlan(state, choices, options = {}) {
17
17
  const actions = [];
18
18
  const dependencies = [];
19
- const { force = false } = options;
19
+ const { force: _force = false } = options;
20
20
  const { items } = choices;
21
21
  const needsCursorDir = items.includes("genstyleguide") || items.includes("skill");
22
22
  if (needsCursorDir && !state.cursorDir.exists) {
@@ -294,4 +294,4 @@ export {
294
294
  createPlan,
295
295
  getMissingRules
296
296
  };
297
- //# sourceMappingURL=chunk-JIFAHBJ2.js.map
297
+ //# sourceMappingURL=chunk-OW7Y4RTR.js.map