uilint 0.2.22 → 0.2.23

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.
@@ -2,13 +2,18 @@
2
2
  import {
3
3
  confirm,
4
4
  detectNextAppRouter,
5
+ findEslintConfigFile,
5
6
  findNextAppRouterProjects,
7
+ getEslintConfigFilename,
8
+ getUilintEslintConfigInfoFromSource,
9
+ installEslintPlugin,
6
10
  log,
7
11
  multiselect,
8
12
  note,
9
13
  pc,
10
- select
11
- } from "./chunk-FRNXXIEM.js";
14
+ select,
15
+ uninstallEslintPlugin
16
+ } from "./chunk-PB5DLLVC.js";
12
17
  import {
13
18
  GENSTYLEGUIDE_COMMAND_MD,
14
19
  detectPackageManager,
@@ -841,7 +846,7 @@ var nextOverlayInstaller = {
841
846
  label: app.projectPath.split("/").pop() || app.projectPath,
842
847
  path: app.projectPath,
843
848
  hint: "App Router",
844
- isInstalled: false
849
+ isInstalled: app.hasUilintOverlay
845
850
  }));
846
851
  },
847
852
  plan(targets, config, project) {
@@ -1309,9 +1314,9 @@ function InstallApp({
1309
1314
  }
1310
1315
 
1311
1316
  // src/commands/install/analyze.ts
1312
- import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
1313
- import { join as join5 } from "path";
1314
- import { findWorkspaceRoot as findWorkspaceRoot2 } from "uilint-core/node";
1317
+ import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
1318
+ import { join as join4 } from "path";
1319
+ import { findWorkspaceRoot } from "uilint-core/node";
1315
1320
 
1316
1321
  // src/utils/vite-detect.ts
1317
1322
  import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2 } from "fs";
@@ -1554,644 +1559,63 @@ function findPackages(rootDir, options) {
1554
1559
  });
1555
1560
  }
1556
1561
 
1557
- // src/utils/eslint-config-inject.ts
1558
- import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync } from "fs";
1559
- import { join as join4, relative as relative3, dirname as dirname2 } from "path";
1560
- import { parseExpression, parseModule as parseModule2, generateCode } from "magicast";
1561
- import { findWorkspaceRoot } from "uilint-core/node";
1562
- var CONFIG_EXTENSIONS = [".ts", ".mjs", ".js", ".cjs"];
1563
- function findEslintConfigFile(projectPath) {
1564
- for (const ext of CONFIG_EXTENSIONS) {
1565
- const configPath = join4(projectPath, `eslint.config${ext}`);
1566
- if (existsSync4(configPath)) {
1567
- return configPath;
1568
- }
1569
- }
1570
- return null;
1571
- }
1572
- function getEslintConfigFilename(configPath) {
1573
- const parts = configPath.split("/");
1574
- return parts[parts.length - 1] || "eslint.config.mjs";
1575
- }
1576
- function isIdentifier(node, name) {
1577
- return !!node && node.type === "Identifier" && (name ? node.name === name : typeof node.name === "string");
1578
- }
1579
- function isStringLiteral(node) {
1580
- return !!node && (node.type === "StringLiteral" || node.type === "Literal") && typeof node.value === "string";
1581
- }
1582
- function getObjectPropertyValue(obj, keyName) {
1583
- if (!obj || obj.type !== "ObjectExpression") return null;
1584
- for (const prop of obj.properties ?? []) {
1585
- if (!prop) continue;
1586
- if (prop.type === "ObjectProperty" || prop.type === "Property") {
1587
- const key = prop.key;
1588
- const keyMatch = key?.type === "Identifier" && key.name === keyName || isStringLiteral(key) && key.value === keyName;
1589
- if (keyMatch) return prop.value;
1590
- }
1591
- }
1592
- return null;
1593
- }
1594
- function hasSpreadProperties(obj) {
1595
- if (!obj || obj.type !== "ObjectExpression") return false;
1596
- return (obj.properties ?? []).some(
1597
- (p) => p && (p.type === "SpreadElement" || p.type === "SpreadProperty")
1598
- );
1599
- }
1600
- var IGNORED_AST_KEYS = /* @__PURE__ */ new Set([
1601
- "loc",
1602
- "start",
1603
- "end",
1604
- "extra",
1605
- "leadingComments",
1606
- "trailingComments",
1607
- "innerComments"
1608
- ]);
1609
- function normalizeAstForCompare(node) {
1610
- if (node === null) return null;
1611
- if (node === void 0) return void 0;
1612
- if (typeof node !== "object") return node;
1613
- if (Array.isArray(node)) return node.map(normalizeAstForCompare);
1614
- const out = {};
1615
- const keys = Object.keys(node).filter((k) => !IGNORED_AST_KEYS.has(k)).sort();
1616
- for (const k of keys) {
1617
- if (k.startsWith("$")) continue;
1618
- out[k] = normalizeAstForCompare(node[k]);
1619
- }
1620
- return out;
1621
- }
1622
- function astEquivalent(a, b) {
1623
- try {
1624
- return JSON.stringify(normalizeAstForCompare(a)) === JSON.stringify(normalizeAstForCompare(b));
1625
- } catch {
1626
- return false;
1627
- }
1628
- }
1629
- function collectUilintRuleIdsFromRulesObject(rulesObj) {
1630
- const ids = /* @__PURE__ */ new Set();
1631
- if (!rulesObj || rulesObj.type !== "ObjectExpression") return ids;
1632
- for (const prop of rulesObj.properties ?? []) {
1633
- if (!prop) continue;
1634
- if (prop.type !== "ObjectProperty" && prop.type !== "Property") continue;
1635
- const key = prop.key;
1636
- if (!isStringLiteral(key)) continue;
1637
- const val = key.value;
1638
- if (typeof val !== "string") continue;
1639
- if (val.startsWith("uilint/")) {
1640
- ids.add(val.slice("uilint/".length));
1641
- }
1642
- }
1643
- return ids;
1644
- }
1645
- function findExportedConfigArrayExpression(mod) {
1646
- function unwrapExpression2(expr) {
1647
- let e = expr;
1648
- while (e) {
1649
- if (e.type === "TSAsExpression" || e.type === "TSNonNullExpression") {
1650
- e = e.expression;
1651
- continue;
1652
- }
1653
- if (e.type === "TSSatisfiesExpression") {
1654
- e = e.expression;
1655
- continue;
1656
- }
1657
- if (e.type === "ParenthesizedExpression") {
1658
- e = e.expression;
1659
- continue;
1660
- }
1661
- break;
1662
- }
1663
- return e;
1664
- }
1665
- function resolveTopLevelIdentifierToArrayExpr(program2, name) {
1666
- if (!program2 || program2.type !== "Program") return null;
1667
- for (const stmt of program2.body ?? []) {
1668
- if (stmt?.type !== "VariableDeclaration") continue;
1669
- for (const decl of stmt.declarations ?? []) {
1670
- const id = decl?.id;
1671
- if (!isIdentifier(id, name)) continue;
1672
- const init = unwrapExpression2(decl?.init);
1673
- if (!init) return null;
1674
- if (init.type === "ArrayExpression") return init;
1675
- if (init.type === "CallExpression" && isIdentifier(init.callee, "defineConfig") && unwrapExpression2(init.arguments?.[0])?.type === "ArrayExpression") {
1676
- return unwrapExpression2(init.arguments?.[0]);
1677
- }
1678
- return null;
1679
- }
1680
- }
1681
- return null;
1682
- }
1683
- const program = mod?.$ast;
1684
- if (program && program.type === "Program") {
1685
- for (const stmt of program.body ?? []) {
1686
- if (!stmt || stmt.type !== "ExportDefaultDeclaration") continue;
1687
- const decl = unwrapExpression2(stmt.declaration);
1688
- if (!decl) break;
1689
- if (decl.type === "ArrayExpression") {
1690
- return { kind: "esm", arrayExpr: decl, program };
1691
- }
1692
- if (decl.type === "CallExpression" && isIdentifier(decl.callee, "defineConfig") && unwrapExpression2(decl.arguments?.[0])?.type === "ArrayExpression") {
1693
- return {
1694
- kind: "esm",
1695
- arrayExpr: unwrapExpression2(decl.arguments?.[0]),
1696
- program
1697
- };
1698
- }
1699
- if (decl.type === "Identifier" && typeof decl.name === "string") {
1700
- const resolved = resolveTopLevelIdentifierToArrayExpr(
1701
- program,
1702
- decl.name
1703
- );
1704
- if (resolved) return { kind: "esm", arrayExpr: resolved, program };
1705
- }
1706
- break;
1707
- }
1708
- }
1709
- if (!program || program.type !== "Program") return null;
1710
- for (const stmt of program.body ?? []) {
1711
- if (!stmt || stmt.type !== "ExpressionStatement") continue;
1712
- const expr = stmt.expression;
1713
- if (!expr || expr.type !== "AssignmentExpression") continue;
1714
- const left = expr.left;
1715
- const right = expr.right;
1716
- const isModuleExports = left?.type === "MemberExpression" && isIdentifier(left.object, "module") && isIdentifier(left.property, "exports");
1717
- if (!isModuleExports) continue;
1718
- if (right?.type === "ArrayExpression") {
1719
- return { kind: "cjs", arrayExpr: right, program };
1720
- }
1721
- if (right?.type === "CallExpression" && isIdentifier(right.callee, "defineConfig") && right.arguments?.[0]?.type === "ArrayExpression") {
1722
- return { kind: "cjs", arrayExpr: right.arguments[0], program };
1723
- }
1724
- if (right?.type === "Identifier" && typeof right.name === "string") {
1725
- const resolved = resolveTopLevelIdentifierToArrayExpr(
1726
- program,
1727
- right.name
1728
- );
1729
- if (resolved) return { kind: "cjs", arrayExpr: resolved, program };
1730
- }
1731
- }
1732
- return null;
1733
- }
1734
- function collectConfiguredUilintRuleIdsFromConfigArray(arrayExpr) {
1735
- const ids = /* @__PURE__ */ new Set();
1736
- if (!arrayExpr || arrayExpr.type !== "ArrayExpression") return ids;
1737
- for (const el of arrayExpr.elements ?? []) {
1738
- if (!el || el.type !== "ObjectExpression") continue;
1739
- const rules = getObjectPropertyValue(el, "rules");
1740
- for (const id of collectUilintRuleIdsFromRulesObject(rules)) ids.add(id);
1741
- }
1742
- return ids;
1743
- }
1744
- function findExistingUilintRulesObject(arrayExpr) {
1745
- if (!arrayExpr || arrayExpr.type !== "ArrayExpression") {
1746
- return { configObj: null, rulesObj: null, safeToMutate: false };
1747
- }
1748
- for (const el of arrayExpr.elements ?? []) {
1749
- if (!el || el.type !== "ObjectExpression") continue;
1750
- const plugins = getObjectPropertyValue(el, "plugins");
1751
- const rules = getObjectPropertyValue(el, "rules");
1752
- const hasUilintPlugin = plugins?.type === "ObjectExpression" && getObjectPropertyValue(plugins, "uilint") !== null;
1753
- const uilintIds = collectUilintRuleIdsFromRulesObject(rules);
1754
- const hasUilintRules = uilintIds.size > 0;
1755
- if (!hasUilintPlugin && !hasUilintRules) continue;
1756
- const safe = rules?.type === "ObjectExpression" && !hasSpreadProperties(rules);
1757
- return { configObj: el, rulesObj: rules, safeToMutate: safe };
1758
- }
1759
- return { configObj: null, rulesObj: null, safeToMutate: false };
1760
- }
1761
- function collectTopLevelBindings(program) {
1762
- const names = /* @__PURE__ */ new Set();
1763
- if (!program || program.type !== "Program") return names;
1764
- for (const stmt of program.body ?? []) {
1765
- if (stmt?.type === "VariableDeclaration") {
1766
- for (const decl of stmt.declarations ?? []) {
1767
- const id = decl?.id;
1768
- if (id?.type === "Identifier" && typeof id.name === "string") {
1769
- names.add(id.name);
1770
- }
1771
- }
1772
- } else if (stmt?.type === "FunctionDeclaration") {
1773
- if (stmt.id?.type === "Identifier" && typeof stmt.id.name === "string") {
1774
- names.add(stmt.id.name);
1775
- }
1776
- }
1777
- }
1778
- return names;
1779
- }
1780
- function chooseUniqueIdentifier(base, used) {
1781
- if (!used.has(base)) return base;
1782
- let i = 2;
1783
- while (used.has(`${base}${i}`)) i++;
1784
- return `${base}${i}`;
1785
- }
1786
- function addLocalRuleImportsAst(mod, selectedRules, configPath, rulesRoot, fileExtension = ".js") {
1787
- const importNames = /* @__PURE__ */ new Map();
1788
- let changed = false;
1789
- const configDir = dirname2(configPath);
1790
- const rulesDir = join4(rulesRoot, ".uilint", "rules");
1791
- const relativeRulesPath = relative3(configDir, rulesDir).replace(/\\/g, "/");
1792
- const normalizedRulesPath = relativeRulesPath.startsWith("./") || relativeRulesPath.startsWith("../") ? relativeRulesPath : `./${relativeRulesPath}`;
1793
- const used = collectTopLevelBindings(mod.$ast);
1794
- for (const rule of selectedRules) {
1795
- const importName = chooseUniqueIdentifier(
1796
- `${rule.id.replace(/-([a-z])/g, (_, c) => c.toUpperCase()).replace(/^./, (c) => c.toUpperCase())}Rule`,
1797
- used
1798
- );
1799
- importNames.set(rule.id, importName);
1800
- used.add(importName);
1801
- const rulePath = `${normalizedRulesPath}/${rule.id}${fileExtension}`;
1802
- mod.imports.$add({
1803
- imported: "default",
1804
- local: importName,
1805
- from: rulePath
1806
- });
1807
- changed = true;
1808
- }
1809
- return { importNames, changed };
1810
- }
1811
- function addLocalRuleRequiresAst(program, selectedRules, configPath, rulesRoot, fileExtension = ".js") {
1812
- const importNames = /* @__PURE__ */ new Map();
1813
- let changed = false;
1814
- if (!program || program.type !== "Program") {
1815
- return { importNames, changed };
1816
- }
1817
- const configDir = dirname2(configPath);
1818
- const rulesDir = join4(rulesRoot, ".uilint", "rules");
1819
- const relativeRulesPath = relative3(configDir, rulesDir).replace(/\\/g, "/");
1820
- const normalizedRulesPath = relativeRulesPath.startsWith("./") || relativeRulesPath.startsWith("../") ? relativeRulesPath : `./${relativeRulesPath}`;
1821
- const used = collectTopLevelBindings(program);
1822
- for (const rule of selectedRules) {
1823
- const importName = chooseUniqueIdentifier(
1824
- `${rule.id.replace(/-([a-z])/g, (_, c) => c.toUpperCase()).replace(/^./, (c) => c.toUpperCase())}Rule`,
1825
- used
1826
- );
1827
- importNames.set(rule.id, importName);
1828
- used.add(importName);
1829
- const rulePath = `${normalizedRulesPath}/${rule.id}${fileExtension}`;
1830
- const stmtMod = parseModule2(
1831
- `const ${importName} = require("${rulePath}");`
1832
- );
1833
- const stmt = stmtMod.$ast.body?.[0];
1834
- if (stmt) {
1835
- let insertAt = 0;
1836
- const first = program.body?.[0];
1837
- if (first?.type === "ExpressionStatement" && first.expression?.type === "StringLiteral" && first.expression.value === "use strict") {
1838
- insertAt = 1;
1839
- }
1840
- program.body.splice(insertAt, 0, stmt);
1841
- changed = true;
1842
- }
1843
- }
1844
- return { importNames, changed };
1845
- }
1846
- function appendUilintConfigBlockToArray(arrayExpr, selectedRules, ruleImportNames) {
1847
- const pluginRulesCode = Array.from(ruleImportNames.entries()).map(([ruleId, importName]) => ` "${ruleId}": ${importName},`).join("\n");
1848
- const rulesPropsCode = selectedRules.map((r) => {
1849
- const ruleKey = `uilint/${r.id}`;
1850
- const valueCode = r.defaultOptions && r.defaultOptions.length > 0 ? `["${r.defaultSeverity}", ...${JSON.stringify(
1851
- r.defaultOptions,
1852
- null,
1853
- 2
1854
- )}]` : `"${r.defaultSeverity}"`;
1855
- return ` "${ruleKey}": ${valueCode},`;
1856
- }).join("\n");
1857
- const blockCode = `{
1858
- files: [
1859
- "src/**/*.{js,jsx,ts,tsx}",
1860
- "app/**/*.{js,jsx,ts,tsx}",
1861
- "pages/**/*.{js,jsx,ts,tsx}",
1862
- ],
1863
- plugins: {
1864
- uilint: {
1865
- rules: {
1866
- ${pluginRulesCode}
1867
- },
1868
- },
1869
- },
1870
- rules: {
1871
- ${rulesPropsCode}
1872
- },
1873
- }`;
1874
- const objExpr = parseExpression(blockCode).$ast;
1875
- arrayExpr.elements.push(objExpr);
1876
- }
1877
- function getUilintEslintConfigInfoFromSourceAst(source) {
1562
+ // src/commands/install/analyze.ts
1563
+ function safeParseJson(filePath) {
1878
1564
  try {
1879
- const mod = parseModule2(source);
1880
- const found = findExportedConfigArrayExpression(mod);
1881
- if (!found) {
1882
- return {
1883
- error: "Could not locate an exported ESLint flat config array (expected `export default [...]`, `export default defineConfig([...])`, `module.exports = [...]`, or `module.exports = defineConfig([...])`)."
1884
- };
1885
- }
1886
- const configuredRuleIds = collectConfiguredUilintRuleIdsFromConfigArray(
1887
- found.arrayExpr
1888
- );
1889
- const existingUilint = findExistingUilintRulesObject(found.arrayExpr);
1890
- const configured = configuredRuleIds.size > 0 || existingUilint.configObj !== null;
1891
- return {
1892
- info: { configuredRuleIds, configured },
1893
- mod,
1894
- arrayExpr: found.arrayExpr,
1895
- kind: found.kind
1896
- };
1565
+ const content = readFileSync4(filePath, "utf-8");
1566
+ return JSON.parse(content);
1897
1567
  } catch {
1898
- return {
1899
- error: "Unable to parse ESLint config as JavaScript. Please update it manually or simplify the config so it can be safely auto-modified."
1900
- };
1901
- }
1902
- }
1903
- function getUilintEslintConfigInfoFromSource(source) {
1904
- const ast = getUilintEslintConfigInfoFromSourceAst(source);
1905
- if ("error" in ast) {
1906
- const configuredRuleIds = extractConfiguredUilintRuleIds(source);
1907
- return {
1908
- configuredRuleIds,
1909
- configured: configuredRuleIds.size > 0
1910
- };
1911
- }
1912
- return ast.info;
1913
- }
1914
- function extractConfiguredUilintRuleIds(source) {
1915
- const ids = /* @__PURE__ */ new Set();
1916
- const re = /["']uilint\/([^"']+)["']\s*:/g;
1917
- for (const m of source.matchAll(re)) {
1918
- if (m[1]) ids.add(m[1]);
1919
- }
1920
- return ids;
1921
- }
1922
- function getMissingSelectedRules(selectedRules, configuredIds) {
1923
- return selectedRules.filter((r) => !configuredIds.has(r.id));
1924
- }
1925
- function buildDesiredRuleValueExpression(rule) {
1926
- if (rule.defaultOptions && rule.defaultOptions.length > 0) {
1927
- return `["${rule.defaultSeverity}", ...${JSON.stringify(
1928
- rule.defaultOptions,
1929
- null,
1930
- 2
1931
- )}]`;
1932
- }
1933
- return `"${rule.defaultSeverity}"`;
1934
- }
1935
- function collectUilintRuleValueNodesFromConfigArray(arrayExpr) {
1936
- const out = /* @__PURE__ */ new Map();
1937
- if (!arrayExpr || arrayExpr.type !== "ArrayExpression") return out;
1938
- for (const el of arrayExpr.elements ?? []) {
1939
- if (!el || el.type !== "ObjectExpression") continue;
1940
- const rules = getObjectPropertyValue(el, "rules");
1941
- if (!rules || rules.type !== "ObjectExpression") continue;
1942
- for (const prop of rules.properties ?? []) {
1943
- if (!prop) continue;
1944
- if (prop.type !== "ObjectProperty" && prop.type !== "Property") continue;
1945
- const key = prop.key;
1946
- if (!isStringLiteral(key)) continue;
1947
- const k = key.value;
1948
- if (typeof k !== "string" || !k.startsWith("uilint/")) continue;
1949
- const id = k.slice("uilint/".length);
1950
- if (!out.has(id)) out.set(id, prop.value);
1951
- }
1952
- }
1953
- return out;
1954
- }
1955
- function getRulesNeedingUpdate(selectedRules, configuredIds, arrayExpr) {
1956
- const existingVals = collectUilintRuleValueNodesFromConfigArray(arrayExpr);
1957
- return selectedRules.filter((r) => {
1958
- if (!configuredIds.has(r.id)) return false;
1959
- const existing = existingVals.get(r.id);
1960
- if (!existing) return true;
1961
- const desiredExpr = buildDesiredRuleValueExpression(r);
1962
- const desiredAst = parseExpression(desiredExpr).$ast;
1963
- return !astEquivalent(existing, desiredAst);
1964
- });
1965
- }
1966
- async function installEslintPlugin(opts) {
1967
- const configPath = findEslintConfigFile(opts.projectPath);
1968
- if (!configPath) {
1969
- return {
1970
- configFile: null,
1971
- modified: false,
1972
- missingRuleIds: [],
1973
- configured: false
1974
- };
1975
- }
1976
- const configFilename = getEslintConfigFilename(configPath);
1977
- const original = readFileSync4(configPath, "utf-8");
1978
- const isCommonJS = configPath.endsWith(".cjs");
1979
- const ast = getUilintEslintConfigInfoFromSourceAst(original);
1980
- if ("error" in ast) {
1981
- return {
1982
- configFile: configFilename,
1983
- modified: false,
1984
- missingRuleIds: [],
1985
- configured: false,
1986
- error: ast.error
1987
- };
1988
- }
1989
- const { info, mod, arrayExpr, kind } = ast;
1990
- const configuredIds = info.configuredRuleIds;
1991
- const missingRules = getMissingSelectedRules(
1992
- opts.selectedRules,
1993
- configuredIds
1994
- );
1995
- const rulesToUpdate = getRulesNeedingUpdate(
1996
- opts.selectedRules,
1997
- configuredIds,
1998
- arrayExpr
1999
- );
2000
- let rulesToApply = [];
2001
- if (!info.configured) {
2002
- rulesToApply = opts.selectedRules;
2003
- } else {
2004
- rulesToApply = [...missingRules, ...rulesToUpdate];
2005
- if (missingRules.length > 0 && !opts.force) {
2006
- const ok = await opts.confirmAddMissingRules?.(
2007
- configFilename,
2008
- missingRules
2009
- );
2010
- if (!ok) {
2011
- return {
2012
- configFile: configFilename,
2013
- modified: false,
2014
- missingRuleIds: missingRules.map((r) => r.id),
2015
- configured: true
2016
- };
2017
- }
2018
- }
2019
- }
2020
- if (rulesToApply.length === 0) {
2021
- return {
2022
- configFile: configFilename,
2023
- modified: false,
2024
- missingRuleIds: missingRules.map((r) => r.id),
2025
- configured: info.configured
2026
- };
2027
- }
2028
- let modifiedAst = false;
2029
- const localRulesDir = join4(opts.projectPath, ".uilint", "rules");
2030
- const workspaceRoot = findWorkspaceRoot(opts.projectPath);
2031
- const workspaceRulesDir = join4(workspaceRoot, ".uilint", "rules");
2032
- const rulesRoot = existsSync4(localRulesDir) ? opts.projectPath : workspaceRoot;
2033
- const isTypeScriptConfig = configPath.endsWith(".ts");
2034
- let fileExtension = isTypeScriptConfig ? "" : ".js";
2035
- let ruleImportNames;
2036
- if (kind === "esm") {
2037
- const result = addLocalRuleImportsAst(
2038
- mod,
2039
- rulesToApply,
2040
- configPath,
2041
- rulesRoot,
2042
- fileExtension
2043
- );
2044
- ruleImportNames = result.importNames;
2045
- if (result.changed) modifiedAst = true;
2046
- } else {
2047
- const result = addLocalRuleRequiresAst(
2048
- mod.$ast,
2049
- rulesToApply,
2050
- configPath,
2051
- rulesRoot,
2052
- fileExtension
2053
- );
2054
- ruleImportNames = result.importNames;
2055
- if (result.changed) modifiedAst = true;
2056
- }
2057
- if (ruleImportNames && ruleImportNames.size > 0) {
2058
- appendUilintConfigBlockToArray(arrayExpr, rulesToApply, ruleImportNames);
2059
- modifiedAst = true;
2060
- }
2061
- if (!info.configured) {
2062
- if (kind === "esm") {
2063
- mod.imports.$add({
2064
- imported: "createRule",
2065
- local: "createRule",
2066
- from: "uilint-eslint"
2067
- });
2068
- modifiedAst = true;
2069
- } else {
2070
- const stmtMod = parseModule2(
2071
- `const { createRule } = require("uilint-eslint");`
2072
- );
2073
- const stmt = stmtMod.$ast.body?.[0];
2074
- if (stmt) {
2075
- let insertAt = 0;
2076
- const first = mod.$ast.body?.[0];
2077
- if (first?.type === "ExpressionStatement" && first.expression?.type === "StringLiteral" && first.expression.value === "use strict") {
2078
- insertAt = 1;
2079
- }
2080
- mod.$ast.body.splice(insertAt, 0, stmt);
2081
- modifiedAst = true;
2082
- }
2083
- }
2084
- }
2085
- const updated = modifiedAst ? generateCode(mod).code : original;
2086
- if (updated !== original) {
2087
- writeFileSync(configPath, updated, "utf-8");
2088
- return {
2089
- configFile: configFilename,
2090
- modified: true,
2091
- missingRuleIds: missingRules.map((r) => r.id),
2092
- configured: getUilintEslintConfigInfoFromSource(updated).configured
2093
- };
1568
+ return void 0;
2094
1569
  }
2095
- return {
2096
- configFile: configFilename,
2097
- modified: false,
2098
- missingRuleIds: missingRules.map((r) => r.id),
2099
- configured: getUilintEslintConfigInfoFromSource(updated).configured
2100
- };
2101
1570
  }
2102
- async function uninstallEslintPlugin(options) {
2103
- const { projectPath } = options;
2104
- const configPath = findEslintConfigFile(projectPath);
2105
- if (!configPath) {
2106
- return {
2107
- success: true,
2108
- // Nothing to uninstall
2109
- modifiedFiles: []
2110
- };
2111
- }
2112
- try {
2113
- const original = readFileSync4(configPath, "utf-8");
2114
- let updated = original.replace(
2115
- /^import\s+\{[^}]*\}\s+from\s+["'][^"']*\.uilint\/rules[^"']*["'];?\s*$/gm,
2116
- ""
2117
- );
2118
- updated = updated.replace(
2119
- /^import\s+\w+\s+from\s+["'][^"']*\.uilint\/rules[^"']*["'];?\s*$/gm,
2120
- ""
2121
- );
2122
- updated = updated.replace(
2123
- /^import\s+\{[^}]*\}\s+from\s+["']uilint-eslint["'];?\s*$/gm,
2124
- ""
2125
- );
2126
- updated = updated.replace(
2127
- /^const\s+\{[^}]*createRule[^}]*\}\s*=\s*require\s*\(\s*["']uilint-eslint["']\s*\)\s*;?\s*$/gm,
2128
- ""
2129
- );
2130
- updated = updated.replace(
2131
- /["']uilint\/[^"']+["']\s*:\s*["'][^"']+["']\s*,?\s*/g,
2132
- ""
2133
- );
2134
- updated = updated.replace(
2135
- /["']uilint\/[^"']+["']\s*:\s*\[[^\]]*\]\s*,?\s*/g,
2136
- ""
2137
- );
2138
- updated = updated.replace(
2139
- /\{\s*plugins:\s*\{\s*uilint:\s*\{[^}]*\}[^}]*\}[^}]*rules:\s*\{[^}]*\}[^}]*\}\s*,?\s*/gs,
2140
- ""
2141
- );
2142
- updated = updated.replace(/\n{3,}/g, "\n\n");
2143
- if (updated !== original) {
2144
- writeFileSync(configPath, updated, "utf-8");
2145
- return {
2146
- success: true,
2147
- modifiedFiles: [configPath]
2148
- };
2149
- }
2150
- return {
2151
- success: true,
2152
- modifiedFiles: []
2153
- };
2154
- } catch (error) {
2155
- return {
2156
- success: false,
2157
- error: error instanceof Error ? error.message : String(error)
2158
- };
2159
- }
1571
+ function hasUilintOverlayInstalled(projectPath) {
1572
+ const pkgPath = join4(projectPath, "package.json");
1573
+ const pkg = safeParseJson(pkgPath);
1574
+ if (!pkg) return false;
1575
+ return !!(pkg.dependencies?.["uilint-react"] || pkg.devDependencies?.["uilint-react"]);
2160
1576
  }
2161
-
2162
- // src/commands/install/analyze.ts
2163
1577
  async function analyze(projectPath = process.cwd()) {
2164
- const workspaceRoot = findWorkspaceRoot2(projectPath);
1578
+ const workspaceRoot = findWorkspaceRoot(projectPath);
2165
1579
  const packageManager = detectPackageManager(projectPath);
2166
- const cursorDir = join5(projectPath, ".cursor");
2167
- const cursorDirExists = existsSync5(cursorDir);
2168
- const styleguidePath = join5(projectPath, ".uilint", "styleguide.md");
2169
- const styleguideExists = existsSync5(styleguidePath);
2170
- const commandsDir = join5(cursorDir, "commands");
2171
- const genstyleguideExists = existsSync5(join5(commandsDir, "genstyleguide.md"));
1580
+ const cursorDir = join4(projectPath, ".cursor");
1581
+ const cursorDirExists = existsSync4(cursorDir);
1582
+ const styleguidePath = join4(projectPath, ".uilint", "styleguide.md");
1583
+ const styleguideExists = existsSync4(styleguidePath);
1584
+ const commandsDir = join4(cursorDir, "commands");
1585
+ const genstyleguideExists = existsSync4(join4(commandsDir, "genstyleguide.md"));
2172
1586
  const nextApps = [];
2173
1587
  const directDetection = detectNextAppRouter(projectPath);
2174
1588
  if (directDetection) {
2175
- nextApps.push({ projectPath, detection: directDetection });
1589
+ nextApps.push({
1590
+ projectPath,
1591
+ detection: directDetection,
1592
+ hasUilintOverlay: hasUilintOverlayInstalled(projectPath)
1593
+ });
2176
1594
  } else {
2177
1595
  const matches = findNextAppRouterProjects(workspaceRoot, { maxDepth: 5 });
2178
1596
  for (const match of matches) {
2179
1597
  nextApps.push({
2180
1598
  projectPath: match.projectPath,
2181
- detection: match.detection
1599
+ detection: match.detection,
1600
+ hasUilintOverlay: hasUilintOverlayInstalled(match.projectPath)
2182
1601
  });
2183
1602
  }
2184
1603
  }
2185
1604
  const viteApps = [];
2186
1605
  const directVite = detectViteReact(projectPath);
2187
1606
  if (directVite) {
2188
- viteApps.push({ projectPath, detection: directVite });
1607
+ viteApps.push({
1608
+ projectPath,
1609
+ detection: directVite,
1610
+ hasUilintOverlay: hasUilintOverlayInstalled(projectPath)
1611
+ });
2189
1612
  } else {
2190
1613
  const matches = findViteReactProjects(workspaceRoot, { maxDepth: 5 });
2191
1614
  for (const match of matches) {
2192
1615
  viteApps.push({
2193
1616
  projectPath: match.projectPath,
2194
- detection: match.detection
1617
+ detection: match.detection,
1618
+ hasUilintOverlay: hasUilintOverlayInstalled(match.projectPath)
2195
1619
  });
2196
1620
  }
2197
1621
  }
@@ -2204,7 +1628,7 @@ async function analyze(projectPath = process.cwd()) {
2204
1628
  if (eslintConfigPath) {
2205
1629
  eslintConfigFilename = getEslintConfigFilename(eslintConfigPath);
2206
1630
  try {
2207
- const source = readFileSync5(eslintConfigPath, "utf-8");
1631
+ const source = readFileSync4(eslintConfigPath, "utf-8");
2208
1632
  const info = getUilintEslintConfigInfoFromSource(source);
2209
1633
  hasRules = info.configuredRuleIds.size > 0;
2210
1634
  configuredRuleIds = Array.from(info.configuredRuleIds);
@@ -2242,50 +1666,50 @@ async function analyze(projectPath = process.cwd()) {
2242
1666
 
2243
1667
  // src/commands/install/execute.ts
2244
1668
  import {
2245
- existsSync as existsSync11,
1669
+ existsSync as existsSync10,
2246
1670
  mkdirSync,
2247
- writeFileSync as writeFileSync5,
2248
- readFileSync as readFileSync9,
1671
+ writeFileSync as writeFileSync4,
1672
+ readFileSync as readFileSync8,
2249
1673
  unlinkSync,
2250
1674
  chmodSync,
2251
1675
  rmSync
2252
1676
  } from "fs";
2253
- import { dirname as dirname5 } from "path";
1677
+ import { dirname as dirname4 } from "path";
2254
1678
 
2255
1679
  // src/utils/react-inject.ts
2256
- import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "fs";
2257
- import { join as join6, relative as relative4 } from "path";
2258
- import { parseModule as parseModule3, generateCode as generateCode2 } from "magicast";
1680
+ import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync } from "fs";
1681
+ import { join as join5, relative as relative3 } from "path";
1682
+ import { parseModule as parseModule2, generateCode } from "magicast";
2259
1683
  function getDefaultCandidates(projectPath, appRoot) {
2260
1684
  const viteMainCandidates = [
2261
- join6(appRoot, "main.tsx"),
2262
- join6(appRoot, "main.jsx"),
2263
- join6(appRoot, "main.ts"),
2264
- join6(appRoot, "main.js")
1685
+ join5(appRoot, "main.tsx"),
1686
+ join5(appRoot, "main.jsx"),
1687
+ join5(appRoot, "main.ts"),
1688
+ join5(appRoot, "main.js")
2265
1689
  ];
2266
1690
  const existingViteMain = viteMainCandidates.filter(
2267
- (rel) => existsSync6(join6(projectPath, rel))
1691
+ (rel) => existsSync5(join5(projectPath, rel))
2268
1692
  );
2269
1693
  if (existingViteMain.length > 0) return existingViteMain;
2270
- const viteAppCandidates = [join6(appRoot, "App.tsx"), join6(appRoot, "App.jsx")];
1694
+ const viteAppCandidates = [join5(appRoot, "App.tsx"), join5(appRoot, "App.jsx")];
2271
1695
  const existingViteApp = viteAppCandidates.filter(
2272
- (rel) => existsSync6(join6(projectPath, rel))
1696
+ (rel) => existsSync5(join5(projectPath, rel))
2273
1697
  );
2274
1698
  if (existingViteApp.length > 0) return existingViteApp;
2275
1699
  const layoutCandidates = [
2276
- join6(appRoot, "layout.tsx"),
2277
- join6(appRoot, "layout.jsx"),
2278
- join6(appRoot, "layout.ts"),
2279
- join6(appRoot, "layout.js")
1700
+ join5(appRoot, "layout.tsx"),
1701
+ join5(appRoot, "layout.jsx"),
1702
+ join5(appRoot, "layout.ts"),
1703
+ join5(appRoot, "layout.js")
2280
1704
  ];
2281
1705
  const existingLayouts = layoutCandidates.filter(
2282
- (rel) => existsSync6(join6(projectPath, rel))
1706
+ (rel) => existsSync5(join5(projectPath, rel))
2283
1707
  );
2284
1708
  if (existingLayouts.length > 0) {
2285
1709
  return existingLayouts;
2286
1710
  }
2287
- const pageCandidates = [join6(appRoot, "page.tsx"), join6(appRoot, "page.jsx")];
2288
- return pageCandidates.filter((rel) => existsSync6(join6(projectPath, rel)));
1711
+ const pageCandidates = [join5(appRoot, "page.tsx"), join5(appRoot, "page.jsx")];
1712
+ return pageCandidates.filter((rel) => existsSync5(join5(projectPath, rel)));
2289
1713
  }
2290
1714
  function isUseClientDirective(stmt) {
2291
1715
  return stmt?.type === "ExpressionStatement" && stmt.expression?.type === "StringLiteral" && stmt.expression.value === "use client";
@@ -2319,12 +1743,12 @@ function ensureNamedImport(program, from, name) {
2319
1743
  (s) => s?.type === "ImportSpecifier" && (s.imported?.name === name || s.imported?.value === name)
2320
1744
  );
2321
1745
  if (has) return { changed: false };
2322
- const spec = parseModule3(`import { ${name} } from "${from}";`).$ast.body?.[0]?.specifiers?.[0];
1746
+ const spec = parseModule2(`import { ${name} } from "${from}";`).$ast.body?.[0]?.specifiers?.[0];
2323
1747
  if (!spec) return { changed: false };
2324
1748
  existing.specifiers = [...existing.specifiers ?? [], spec];
2325
1749
  return { changed: true };
2326
1750
  }
2327
- const importDecl = parseModule3(`import { ${name} } from "${from}";`).$ast.body?.[0];
1751
+ const importDecl = parseModule2(`import { ${name} } from "${from}";`).$ast.body?.[0];
2328
1752
  if (!importDecl) return { changed: false };
2329
1753
  const body = program.body ?? [];
2330
1754
  let insertAt = 0;
@@ -2354,7 +1778,7 @@ function hasUILintDevtoolsJsx(program) {
2354
1778
  function addDevtoolsElementNextJs(program) {
2355
1779
  if (!program || program.type !== "Program") return { changed: false };
2356
1780
  if (hasUILintDevtoolsJsx(program)) return { changed: false };
2357
- const devtoolsMod = parseModule3(
1781
+ const devtoolsMod = parseModule2(
2358
1782
  "const __uilint_devtools = <uilint-devtools />;"
2359
1783
  );
2360
1784
  const devtoolsJsx = devtoolsMod.$ast.body?.[0]?.declarations?.[0]?.init ?? null;
@@ -2392,12 +1816,12 @@ function addDevtoolsElementVite(program) {
2392
1816
  const arg0 = node.arguments?.[0];
2393
1817
  if (!arg0) return;
2394
1818
  if (arg0.type !== "JSXElement" && arg0.type !== "JSXFragment") return;
2395
- const devtoolsMod = parseModule3(
1819
+ const devtoolsMod = parseModule2(
2396
1820
  "const __uilint_devtools = <uilint-devtools />;"
2397
1821
  );
2398
1822
  const devtoolsJsx = devtoolsMod.$ast.body?.[0]?.declarations?.[0]?.init ?? null;
2399
1823
  if (!devtoolsJsx) return;
2400
- const fragmentMod = parseModule3(
1824
+ const fragmentMod = parseModule2(
2401
1825
  "const __fragment = <></>;"
2402
1826
  );
2403
1827
  const fragmentJsx = fragmentMod.$ast.body?.[0]?.declarations?.[0]?.init ?? null;
@@ -2417,7 +1841,7 @@ function ensureSideEffectImport(program, from) {
2417
1841
  if (!program || program.type !== "Program") return { changed: false };
2418
1842
  const existing = findImportDeclaration(program, from);
2419
1843
  if (existing) return { changed: false };
2420
- const importDecl = parseModule3(`import "${from}";`).$ast.body?.[0];
1844
+ const importDecl = parseModule2(`import "${from}";`).$ast.body?.[0];
2421
1845
  if (!importDecl) return { changed: false };
2422
1846
  const body = program.body ?? [];
2423
1847
  let insertAt = 0;
@@ -2433,7 +1857,7 @@ function ensureSideEffectImport(program, from) {
2433
1857
  function addDevtoolsToClientComponent(program) {
2434
1858
  if (!program || program.type !== "Program") return { changed: false };
2435
1859
  if (hasUILintDevtoolsJsx(program)) return { changed: false };
2436
- const devtoolsMod = parseModule3(
1860
+ const devtoolsMod = parseModule2(
2437
1861
  "const __uilint_devtools = <uilint-devtools />;"
2438
1862
  );
2439
1863
  const devtoolsJsx = devtoolsMod.$ast.body?.[0]?.declarations?.[0]?.init ?? null;
@@ -2459,7 +1883,7 @@ function addDevtoolsToClientComponent(program) {
2459
1883
  const arg = node.argument;
2460
1884
  if (!arg) return;
2461
1885
  if (arg.type !== "JSXElement" && arg.type !== "JSXFragment") return;
2462
- const fragmentMod = parseModule3("const __fragment = <></>;");
1886
+ const fragmentMod = parseModule2("const __fragment = <></>;");
2463
1887
  const fragmentJsx = fragmentMod.$ast.body?.[0]?.declarations?.[0]?.init ?? null;
2464
1888
  if (!fragmentJsx) return;
2465
1889
  fragmentJsx.children = [arg, devtoolsJsx];
@@ -2514,7 +1938,7 @@ function wrapChildrenWithProviders(program, providersImportPath) {
2514
1938
  (child) => child?.type === "JSXExpressionContainer" && child.expression?.type === "Identifier" && child.expression.name === "children"
2515
1939
  );
2516
1940
  if (childrenIndex === -1) return;
2517
- const providersMod = parseModule3(
1941
+ const providersMod = parseModule2(
2518
1942
  "const __providers = <Providers>{children}</Providers>;"
2519
1943
  );
2520
1944
  const providersJsx = providersMod.$ast.body?.[0]?.declarations?.[0]?.init ?? null;
@@ -2532,8 +1956,8 @@ function wrapChildrenWithProviders(program, providersImportPath) {
2532
1956
  function findLayoutFile2(projectPath, appRoot) {
2533
1957
  const extensions = [".tsx", ".jsx", ".ts", ".js"];
2534
1958
  for (const ext of extensions) {
2535
- const layoutPath = join6(projectPath, appRoot, `layout${ext}`);
2536
- if (existsSync6(layoutPath)) return layoutPath;
1959
+ const layoutPath = join5(projectPath, appRoot, `layout${ext}`);
1960
+ if (existsSync5(layoutPath)) return layoutPath;
2537
1961
  }
2538
1962
  return null;
2539
1963
  }
@@ -2544,32 +1968,32 @@ async function createProvidersAndModifyLayout(projectPath, appRoot) {
2544
1968
  }
2545
1969
  const isTypeScript = layoutPath.endsWith(".tsx") || layoutPath.endsWith(".ts");
2546
1970
  const providersExt = isTypeScript ? ".tsx" : ".jsx";
2547
- const providersPath = join6(projectPath, appRoot, `providers${providersExt}`);
2548
- if (existsSync6(providersPath)) {
1971
+ const providersPath = join5(projectPath, appRoot, `providers${providersExt}`);
1972
+ if (existsSync5(providersPath)) {
2549
1973
  throw new Error(
2550
1974
  `providers${providersExt} already exists. Please select it from the list instead.`
2551
1975
  );
2552
1976
  }
2553
1977
  const providersContent = generateProvidersContent(isTypeScript);
2554
- writeFileSync2(providersPath, providersContent, "utf-8");
2555
- const layoutContent = readFileSync6(layoutPath, "utf-8");
1978
+ writeFileSync(providersPath, providersContent, "utf-8");
1979
+ const layoutContent = readFileSync5(layoutPath, "utf-8");
2556
1980
  let layoutMod;
2557
1981
  try {
2558
- layoutMod = parseModule3(layoutContent);
1982
+ layoutMod = parseModule2(layoutContent);
2559
1983
  } catch {
2560
1984
  throw new Error(
2561
- `Unable to parse ${relative4(projectPath, layoutPath)} as JavaScript/TypeScript.`
1985
+ `Unable to parse ${relative3(projectPath, layoutPath)} as JavaScript/TypeScript.`
2562
1986
  );
2563
1987
  }
2564
1988
  const layoutProgram = layoutMod.$ast;
2565
1989
  const wrapRes = wrapChildrenWithProviders(layoutProgram, "./providers");
2566
1990
  if (wrapRes.changed) {
2567
- const updatedLayout = generateCode2(layoutMod).code;
2568
- writeFileSync2(layoutPath, updatedLayout, "utf-8");
1991
+ const updatedLayout = generateCode(layoutMod).code;
1992
+ writeFileSync(layoutPath, updatedLayout, "utf-8");
2569
1993
  }
2570
1994
  return {
2571
- providersFile: relative4(projectPath, providersPath),
2572
- layoutFile: relative4(projectPath, layoutPath),
1995
+ providersFile: relative3(projectPath, providersPath),
1996
+ layoutFile: relative3(projectPath, layoutPath),
2573
1997
  modified: true
2574
1998
  };
2575
1999
  }
@@ -2581,8 +2005,8 @@ async function installReactUILintOverlay(opts) {
2581
2005
  );
2582
2006
  const modifiedFiles = [];
2583
2007
  if (result.modified) {
2584
- modifiedFiles.push(join6(opts.projectPath, result.providersFile));
2585
- modifiedFiles.push(join6(opts.projectPath, result.layoutFile));
2008
+ modifiedFiles.push(join5(opts.projectPath, result.providersFile));
2009
+ modifiedFiles.push(join5(opts.projectPath, result.layoutFile));
2586
2010
  }
2587
2011
  return {
2588
2012
  targetFile: result.providersFile,
@@ -2594,14 +2018,14 @@ async function installReactUILintOverlay(opts) {
2594
2018
  }
2595
2019
  if (opts.targetFile) {
2596
2020
  const absTarget2 = opts.targetFile;
2597
- const relTarget = relative4(opts.projectPath, absTarget2);
2598
- if (!existsSync6(absTarget2)) {
2021
+ const relTarget = relative3(opts.projectPath, absTarget2);
2022
+ if (!existsSync5(absTarget2)) {
2599
2023
  throw new Error(`Target file not found: ${relTarget}`);
2600
2024
  }
2601
- const original2 = readFileSync6(absTarget2, "utf-8");
2025
+ const original2 = readFileSync5(absTarget2, "utf-8");
2602
2026
  let mod2;
2603
2027
  try {
2604
- mod2 = parseModule3(original2);
2028
+ mod2 = parseModule2(original2);
2605
2029
  } catch {
2606
2030
  throw new Error(
2607
2031
  `Unable to parse ${relTarget} as JavaScript/TypeScript. Please update it manually.`
@@ -2624,10 +2048,10 @@ async function installReactUILintOverlay(opts) {
2624
2048
  if (importRes2.changed) changed2 = true;
2625
2049
  const addRes2 = addDevtoolsToClientComponent(program2);
2626
2050
  if (addRes2.changed) changed2 = true;
2627
- const updated2 = changed2 ? generateCode2(mod2).code : original2;
2051
+ const updated2 = changed2 ? generateCode(mod2).code : original2;
2628
2052
  const modified2 = updated2 !== original2;
2629
2053
  if (modified2) {
2630
- writeFileSync2(absTarget2, updated2, "utf-8");
2054
+ writeFileSync(absTarget2, updated2, "utf-8");
2631
2055
  }
2632
2056
  return {
2633
2057
  targetFile: relTarget,
@@ -2648,11 +2072,11 @@ async function installReactUILintOverlay(opts) {
2648
2072
  } else {
2649
2073
  chosen = candidates[0];
2650
2074
  }
2651
- const absTarget = join6(opts.projectPath, chosen);
2652
- const original = readFileSync6(absTarget, "utf-8");
2075
+ const absTarget = join5(opts.projectPath, chosen);
2076
+ const original = readFileSync5(absTarget, "utf-8");
2653
2077
  let mod;
2654
2078
  try {
2655
- mod = parseModule3(original);
2079
+ mod = parseModule2(original);
2656
2080
  } catch {
2657
2081
  throw new Error(
2658
2082
  `Unable to parse ${chosen} as JavaScript/TypeScript. Please update it manually.`
@@ -2668,10 +2092,10 @@ async function installReactUILintOverlay(opts) {
2668
2092
  const mode = opts.mode ?? "next";
2669
2093
  const addRes = mode === "vite" ? addDevtoolsElementVite(program) : addDevtoolsElementNextJs(program);
2670
2094
  if (addRes.changed) changed = true;
2671
- const updated = changed ? generateCode2(mod).code : original;
2095
+ const updated = changed ? generateCode(mod).code : original;
2672
2096
  const modified = updated !== original;
2673
2097
  if (modified) {
2674
- writeFileSync2(absTarget, updated, "utf-8");
2098
+ writeFileSync(absTarget, updated, "utf-8");
2675
2099
  }
2676
2100
  return {
2677
2101
  targetFile: chosen,
@@ -2685,10 +2109,10 @@ async function uninstallReactUILintOverlay(options) {
2685
2109
  const candidates = getDefaultCandidates(projectPath, appRoot);
2686
2110
  const modifiedFiles = [];
2687
2111
  for (const candidate of candidates) {
2688
- const absPath = join6(projectPath, candidate);
2689
- if (!existsSync6(absPath)) continue;
2112
+ const absPath = join5(projectPath, candidate);
2113
+ if (!existsSync5(absPath)) continue;
2690
2114
  try {
2691
- const original = readFileSync6(absPath, "utf-8");
2115
+ const original = readFileSync5(absPath, "utf-8");
2692
2116
  let updated = original.replace(
2693
2117
  /^import\s+["']uilint-react\/devtools["'];?\s*$/gm,
2694
2118
  ""
@@ -2706,7 +2130,7 @@ async function uninstallReactUILintOverlay(options) {
2706
2130
  );
2707
2131
  updated = updated.replace(/\n{3,}/g, "\n\n");
2708
2132
  if (updated !== original) {
2709
- writeFileSync2(absPath, updated, "utf-8");
2133
+ writeFileSync(absPath, updated, "utf-8");
2710
2134
  modifiedFiles.push(absPath);
2711
2135
  }
2712
2136
  } catch {
@@ -2719,14 +2143,14 @@ async function uninstallReactUILintOverlay(options) {
2719
2143
  }
2720
2144
 
2721
2145
  // src/utils/next-config-inject.ts
2722
- import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
2723
- import { join as join7 } from "path";
2724
- import { parseModule as parseModule4, generateCode as generateCode3 } from "magicast";
2725
- var CONFIG_EXTENSIONS2 = [".ts", ".mjs", ".js", ".cjs"];
2146
+ import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "fs";
2147
+ import { join as join6 } from "path";
2148
+ import { parseModule as parseModule3, generateCode as generateCode2 } from "magicast";
2149
+ var CONFIG_EXTENSIONS = [".ts", ".mjs", ".js", ".cjs"];
2726
2150
  function findNextConfigFile(projectPath) {
2727
- for (const ext of CONFIG_EXTENSIONS2) {
2728
- const configPath = join7(projectPath, `next.config${ext}`);
2729
- if (existsSync7(configPath)) {
2151
+ for (const ext of CONFIG_EXTENSIONS) {
2152
+ const configPath = join6(projectPath, `next.config${ext}`);
2153
+ if (existsSync6(configPath)) {
2730
2154
  return configPath;
2731
2155
  }
2732
2156
  }
@@ -2736,10 +2160,10 @@ function getNextConfigFilename(configPath) {
2736
2160
  const parts = configPath.split("/");
2737
2161
  return parts[parts.length - 1] || "next.config.ts";
2738
2162
  }
2739
- function isIdentifier2(node, name) {
2163
+ function isIdentifier(node, name) {
2740
2164
  return !!node && node.type === "Identifier" && (name ? node.name === name : typeof node.name === "string");
2741
2165
  }
2742
- function isStringLiteral2(node) {
2166
+ function isStringLiteral(node) {
2743
2167
  return !!node && (node.type === "StringLiteral" || node.type === "Literal") && typeof node.value === "string";
2744
2168
  }
2745
2169
  function ensureEsmWithJsxLocImport(program) {
@@ -2752,12 +2176,12 @@ function ensureEsmWithJsxLocImport(program) {
2752
2176
  (sp) => sp?.type === "ImportSpecifier" && (sp.imported?.name === "withJsxLoc" || sp.imported?.value === "withJsxLoc")
2753
2177
  );
2754
2178
  if (has) return { changed: false };
2755
- const spec = parseModule4('import { withJsxLoc } from "jsx-loc-plugin";').$ast.body?.[0]?.specifiers?.[0];
2179
+ const spec = parseModule3('import { withJsxLoc } from "jsx-loc-plugin";').$ast.body?.[0]?.specifiers?.[0];
2756
2180
  if (!spec) return { changed: false };
2757
2181
  existing.specifiers = [...existing.specifiers ?? [], spec];
2758
2182
  return { changed: true };
2759
2183
  }
2760
- const importDecl = parseModule4('import { withJsxLoc } from "jsx-loc-plugin";').$ast.body?.[0];
2184
+ const importDecl = parseModule3('import { withJsxLoc } from "jsx-loc-plugin";').$ast.body?.[0];
2761
2185
  if (!importDecl) return { changed: false };
2762
2186
  const body = program.body ?? [];
2763
2187
  let insertAt = 0;
@@ -2773,14 +2197,14 @@ function ensureCjsWithJsxLocRequire(program) {
2773
2197
  if (stmt?.type !== "VariableDeclaration") continue;
2774
2198
  for (const decl of stmt.declarations ?? []) {
2775
2199
  const init = decl?.init;
2776
- if (init?.type === "CallExpression" && isIdentifier2(init.callee, "require") && isStringLiteral2(init.arguments?.[0]) && init.arguments[0].value === "jsx-loc-plugin") {
2200
+ if (init?.type === "CallExpression" && isIdentifier(init.callee, "require") && isStringLiteral(init.arguments?.[0]) && init.arguments[0].value === "jsx-loc-plugin") {
2777
2201
  if (decl.id?.type === "ObjectPattern") {
2778
2202
  const has = (decl.id.properties ?? []).some((p) => {
2779
2203
  if (p?.type !== "ObjectProperty" && p?.type !== "Property") return false;
2780
- return isIdentifier2(p.key, "withJsxLoc");
2204
+ return isIdentifier(p.key, "withJsxLoc");
2781
2205
  });
2782
2206
  if (has) return { changed: false };
2783
- const prop = parseModule4('const { withJsxLoc } = require("jsx-loc-plugin");').$ast.body?.[0]?.declarations?.[0]?.id?.properties?.[0];
2207
+ const prop = parseModule3('const { withJsxLoc } = require("jsx-loc-plugin");').$ast.body?.[0]?.declarations?.[0]?.id?.properties?.[0];
2784
2208
  if (!prop) return { changed: false };
2785
2209
  decl.id.properties = [...decl.id.properties ?? [], prop];
2786
2210
  return { changed: true };
@@ -2789,7 +2213,7 @@ function ensureCjsWithJsxLocRequire(program) {
2789
2213
  }
2790
2214
  }
2791
2215
  }
2792
- const reqDecl = parseModule4('const { withJsxLoc } = require("jsx-loc-plugin");').$ast.body?.[0];
2216
+ const reqDecl = parseModule3('const { withJsxLoc } = require("jsx-loc-plugin");').$ast.body?.[0];
2793
2217
  if (!reqDecl) return { changed: false };
2794
2218
  program.body.unshift(reqDecl);
2795
2219
  return { changed: true };
@@ -2801,7 +2225,7 @@ function wrapEsmExportDefault(program) {
2801
2225
  );
2802
2226
  if (!exportDecl) return { changed: false };
2803
2227
  const decl = exportDecl.declaration;
2804
- if (decl?.type === "CallExpression" && isIdentifier2(decl.callee, "withJsxLoc")) {
2228
+ if (decl?.type === "CallExpression" && isIdentifier(decl.callee, "withJsxLoc")) {
2805
2229
  return { changed: false };
2806
2230
  }
2807
2231
  exportDecl.declaration = {
@@ -2819,9 +2243,9 @@ function wrapCjsModuleExports(program) {
2819
2243
  if (!expr || expr.type !== "AssignmentExpression") continue;
2820
2244
  const left = expr.left;
2821
2245
  const right = expr.right;
2822
- const isModuleExports = left?.type === "MemberExpression" && isIdentifier2(left.object, "module") && isIdentifier2(left.property, "exports");
2246
+ const isModuleExports = left?.type === "MemberExpression" && isIdentifier(left.object, "module") && isIdentifier(left.property, "exports");
2823
2247
  if (!isModuleExports) continue;
2824
- if (right?.type === "CallExpression" && isIdentifier2(right.callee, "withJsxLoc")) {
2248
+ if (right?.type === "CallExpression" && isIdentifier(right.callee, "withJsxLoc")) {
2825
2249
  return { changed: false };
2826
2250
  }
2827
2251
  expr.right = {
@@ -2839,10 +2263,10 @@ async function installJsxLocPlugin(opts) {
2839
2263
  return { configFile: null, modified: false, modifiedFiles: [] };
2840
2264
  }
2841
2265
  const configFilename = getNextConfigFilename(configPath);
2842
- const original = readFileSync7(configPath, "utf-8");
2266
+ const original = readFileSync6(configPath, "utf-8");
2843
2267
  let mod;
2844
2268
  try {
2845
- mod = parseModule4(original);
2269
+ mod = parseModule3(original);
2846
2270
  } catch {
2847
2271
  return { configFile: configFilename, modified: false, modifiedFiles: [] };
2848
2272
  }
@@ -2860,9 +2284,9 @@ async function installJsxLocPlugin(opts) {
2860
2284
  const wrapRes = wrapEsmExportDefault(program);
2861
2285
  if (wrapRes.changed) changed = true;
2862
2286
  }
2863
- const updated = changed ? generateCode3(mod).code : original;
2287
+ const updated = changed ? generateCode2(mod).code : original;
2864
2288
  if (updated !== original) {
2865
- writeFileSync3(configPath, updated, "utf-8");
2289
+ writeFileSync2(configPath, updated, "utf-8");
2866
2290
  return { configFile: configFilename, modified: true, modifiedFiles: [configPath] };
2867
2291
  }
2868
2292
  return { configFile: configFilename, modified: false, modifiedFiles: [] };
@@ -2877,7 +2301,7 @@ async function uninstallJsxLocPlugin(options) {
2877
2301
  };
2878
2302
  }
2879
2303
  try {
2880
- const original = readFileSync7(configPath, "utf-8");
2304
+ const original = readFileSync6(configPath, "utf-8");
2881
2305
  let updated = original.replace(
2882
2306
  /^import\s+\{[^}]*withJsxLoc[^}]*\}\s+from\s+["']jsx-loc-plugin\/next["'];?\s*$/gm,
2883
2307
  ""
@@ -2896,7 +2320,7 @@ async function uninstallJsxLocPlugin(options) {
2896
2320
  );
2897
2321
  updated = updated.replace(/\n{3,}/g, "\n\n");
2898
2322
  if (updated !== original) {
2899
- writeFileSync3(configPath, updated, "utf-8");
2323
+ writeFileSync2(configPath, updated, "utf-8");
2900
2324
  return {
2901
2325
  success: true,
2902
2326
  modifiedFiles: [configPath]
@@ -2915,14 +2339,14 @@ async function uninstallJsxLocPlugin(options) {
2915
2339
  }
2916
2340
 
2917
2341
  // src/utils/vite-config-inject.ts
2918
- import { existsSync as existsSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "fs";
2919
- import { join as join8 } from "path";
2920
- import { parseModule as parseModule5, generateCode as generateCode4 } from "magicast";
2921
- var CONFIG_EXTENSIONS3 = [".ts", ".mjs", ".js", ".cjs"];
2342
+ import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
2343
+ import { join as join7 } from "path";
2344
+ import { parseModule as parseModule4, generateCode as generateCode3 } from "magicast";
2345
+ var CONFIG_EXTENSIONS2 = [".ts", ".mjs", ".js", ".cjs"];
2922
2346
  function findViteConfigFile2(projectPath) {
2923
- for (const ext of CONFIG_EXTENSIONS3) {
2924
- const configPath = join8(projectPath, `vite.config${ext}`);
2925
- if (existsSync8(configPath)) return configPath;
2347
+ for (const ext of CONFIG_EXTENSIONS2) {
2348
+ const configPath = join7(projectPath, `vite.config${ext}`);
2349
+ if (existsSync7(configPath)) return configPath;
2926
2350
  }
2927
2351
  return null;
2928
2352
  }
@@ -2930,10 +2354,10 @@ function getViteConfigFilename(configPath) {
2930
2354
  const parts = configPath.split("/");
2931
2355
  return parts[parts.length - 1] || "vite.config.ts";
2932
2356
  }
2933
- function isIdentifier3(node, name) {
2357
+ function isIdentifier2(node, name) {
2934
2358
  return !!node && node.type === "Identifier" && (name ? node.name === name : typeof node.name === "string");
2935
2359
  }
2936
- function isStringLiteral3(node) {
2360
+ function isStringLiteral2(node) {
2937
2361
  return !!node && (node.type === "StringLiteral" || node.type === "Literal") && typeof node.value === "string";
2938
2362
  }
2939
2363
  function unwrapExpression(expr) {
@@ -2965,7 +2389,7 @@ function findExportedConfigObjectExpression(mod) {
2965
2389
  if (decl.type === "ObjectExpression") {
2966
2390
  return { kind: "esm", objExpr: decl, program };
2967
2391
  }
2968
- if (decl.type === "CallExpression" && isIdentifier3(decl.callee, "defineConfig") && unwrapExpression(decl.arguments?.[0])?.type === "ObjectExpression") {
2392
+ if (decl.type === "CallExpression" && isIdentifier2(decl.callee, "defineConfig") && unwrapExpression(decl.arguments?.[0])?.type === "ObjectExpression") {
2969
2393
  return {
2970
2394
  kind: "esm",
2971
2395
  objExpr: unwrapExpression(decl.arguments?.[0]),
@@ -2980,12 +2404,12 @@ function findExportedConfigObjectExpression(mod) {
2980
2404
  if (!expr || expr.type !== "AssignmentExpression") continue;
2981
2405
  const left = expr.left;
2982
2406
  const right = unwrapExpression(expr.right);
2983
- const isModuleExports = left?.type === "MemberExpression" && isIdentifier3(left.object, "module") && isIdentifier3(left.property, "exports");
2407
+ const isModuleExports = left?.type === "MemberExpression" && isIdentifier2(left.object, "module") && isIdentifier2(left.property, "exports");
2984
2408
  if (!isModuleExports) continue;
2985
2409
  if (right?.type === "ObjectExpression") {
2986
2410
  return { kind: "cjs", objExpr: right, program };
2987
2411
  }
2988
- if (right?.type === "CallExpression" && isIdentifier3(right.callee, "defineConfig") && unwrapExpression(right.arguments?.[0])?.type === "ObjectExpression") {
2412
+ if (right?.type === "CallExpression" && isIdentifier2(right.callee, "defineConfig") && unwrapExpression(right.arguments?.[0])?.type === "ObjectExpression") {
2989
2413
  return {
2990
2414
  kind: "cjs",
2991
2415
  objExpr: unwrapExpression(right.arguments?.[0]),
@@ -3001,7 +2425,7 @@ function getObjectProperty(obj, keyName) {
3001
2425
  if (!prop) continue;
3002
2426
  if (prop.type !== "ObjectProperty" && prop.type !== "Property") continue;
3003
2427
  const key = prop.key;
3004
- const keyMatch = key?.type === "Identifier" && key.name === keyName || isStringLiteral3(key) && key.value === keyName;
2428
+ const keyMatch = key?.type === "Identifier" && key.name === keyName || isStringLiteral2(key) && key.value === keyName;
3005
2429
  if (keyMatch) return prop;
3006
2430
  }
3007
2431
  return null;
@@ -3016,12 +2440,12 @@ function ensureEsmJsxLocImport(program) {
3016
2440
  (sp) => sp?.type === "ImportSpecifier" && (sp.imported?.name === "jsxLoc" || sp.imported?.value === "jsxLoc")
3017
2441
  );
3018
2442
  if (has) return { changed: false };
3019
- const spec = parseModule5('import { jsxLoc } from "jsx-loc-plugin/vite";').$ast.body?.[0]?.specifiers?.[0];
2443
+ const spec = parseModule4('import { jsxLoc } from "jsx-loc-plugin/vite";').$ast.body?.[0]?.specifiers?.[0];
3020
2444
  if (!spec) return { changed: false };
3021
2445
  existing.specifiers = [...existing.specifiers ?? [], spec];
3022
2446
  return { changed: true };
3023
2447
  }
3024
- const importDecl = parseModule5('import { jsxLoc } from "jsx-loc-plugin/vite";').$ast.body?.[0];
2448
+ const importDecl = parseModule4('import { jsxLoc } from "jsx-loc-plugin/vite";').$ast.body?.[0];
3025
2449
  if (!importDecl) return { changed: false };
3026
2450
  const body = program.body ?? [];
3027
2451
  let insertAt = 0;
@@ -3037,14 +2461,14 @@ function ensureCjsJsxLocRequire(program) {
3037
2461
  if (stmt?.type !== "VariableDeclaration") continue;
3038
2462
  for (const decl of stmt.declarations ?? []) {
3039
2463
  const init = decl?.init;
3040
- if (init?.type === "CallExpression" && isIdentifier3(init.callee, "require") && isStringLiteral3(init.arguments?.[0]) && init.arguments[0].value === "jsx-loc-plugin/vite") {
2464
+ if (init?.type === "CallExpression" && isIdentifier2(init.callee, "require") && isStringLiteral2(init.arguments?.[0]) && init.arguments[0].value === "jsx-loc-plugin/vite") {
3041
2465
  if (decl.id?.type === "ObjectPattern") {
3042
2466
  const has = (decl.id.properties ?? []).some((p) => {
3043
2467
  if (p?.type !== "ObjectProperty" && p?.type !== "Property") return false;
3044
- return isIdentifier3(p.key, "jsxLoc");
2468
+ return isIdentifier2(p.key, "jsxLoc");
3045
2469
  });
3046
2470
  if (has) return { changed: false };
3047
- const prop = parseModule5('const { jsxLoc } = require("jsx-loc-plugin/vite");').$ast.body?.[0]?.declarations?.[0]?.id?.properties?.[0];
2471
+ const prop = parseModule4('const { jsxLoc } = require("jsx-loc-plugin/vite");').$ast.body?.[0]?.declarations?.[0]?.id?.properties?.[0];
3048
2472
  if (!prop) return { changed: false };
3049
2473
  decl.id.properties = [...decl.id.properties ?? [], prop];
3050
2474
  return { changed: true };
@@ -3053,7 +2477,7 @@ function ensureCjsJsxLocRequire(program) {
3053
2477
  }
3054
2478
  }
3055
2479
  }
3056
- const reqDecl = parseModule5('const { jsxLoc } = require("jsx-loc-plugin/vite");').$ast.body?.[0];
2480
+ const reqDecl = parseModule4('const { jsxLoc } = require("jsx-loc-plugin/vite");').$ast.body?.[0];
3057
2481
  if (!reqDecl) return { changed: false };
3058
2482
  program.body.unshift(reqDecl);
3059
2483
  return { changed: true };
@@ -3063,16 +2487,16 @@ function pluginsHasJsxLoc(arr) {
3063
2487
  for (const el of arr.elements ?? []) {
3064
2488
  const e = unwrapExpression(el);
3065
2489
  if (!e) continue;
3066
- if (e.type === "CallExpression" && isIdentifier3(e.callee, "jsxLoc")) return true;
2490
+ if (e.type === "CallExpression" && isIdentifier2(e.callee, "jsxLoc")) return true;
3067
2491
  }
3068
2492
  return false;
3069
2493
  }
3070
2494
  function ensurePluginsContainsJsxLoc(configObj) {
3071
2495
  const pluginsProp = getObjectProperty(configObj, "plugins");
3072
2496
  if (!pluginsProp) {
3073
- const prop = parseModule5("export default { plugins: [jsxLoc()] };").$ast.body?.find((s) => s.type === "ExportDefaultDeclaration")?.declaration?.properties?.find((p) => {
2497
+ const prop = parseModule4("export default { plugins: [jsxLoc()] };").$ast.body?.find((s) => s.type === "ExportDefaultDeclaration")?.declaration?.properties?.find((p) => {
3074
2498
  const k = p?.key;
3075
- return k?.type === "Identifier" && k.name === "plugins" || isStringLiteral3(k) && k.value === "plugins";
2499
+ return k?.type === "Identifier" && k.name === "plugins" || isStringLiteral2(k) && k.value === "plugins";
3076
2500
  });
3077
2501
  if (!prop) return { changed: false };
3078
2502
  configObj.properties = [...configObj.properties ?? [], prop];
@@ -3082,12 +2506,12 @@ function ensurePluginsContainsJsxLoc(configObj) {
3082
2506
  if (!value) return { changed: false };
3083
2507
  if (value.type === "ArrayExpression") {
3084
2508
  if (pluginsHasJsxLoc(value)) return { changed: false };
3085
- const jsxLocCall2 = parseModule5("const __x = jsxLoc();").$ast.body?.[0]?.declarations?.[0]?.init;
2509
+ const jsxLocCall2 = parseModule4("const __x = jsxLoc();").$ast.body?.[0]?.declarations?.[0]?.init;
3086
2510
  if (!jsxLocCall2) return { changed: false };
3087
2511
  value.elements.push(jsxLocCall2);
3088
2512
  return { changed: true };
3089
2513
  }
3090
- const jsxLocCall = parseModule5("const __x = jsxLoc();").$ast.body?.[0]?.declarations?.[0]?.init;
2514
+ const jsxLocCall = parseModule4("const __x = jsxLoc();").$ast.body?.[0]?.declarations?.[0]?.init;
3091
2515
  if (!jsxLocCall) return { changed: false };
3092
2516
  const spread = { type: "SpreadElement", argument: value };
3093
2517
  pluginsProp.value = { type: "ArrayExpression", elements: [spread, jsxLocCall] };
@@ -3097,11 +2521,11 @@ async function installViteJsxLocPlugin(opts) {
3097
2521
  const configPath = findViteConfigFile2(opts.projectPath);
3098
2522
  if (!configPath) return { configFile: null, modified: false, modifiedFiles: [] };
3099
2523
  const configFilename = getViteConfigFilename(configPath);
3100
- const original = readFileSync8(configPath, "utf-8");
2524
+ const original = readFileSync7(configPath, "utf-8");
3101
2525
  const isCjs = configPath.endsWith(".cjs");
3102
2526
  let mod;
3103
2527
  try {
3104
- mod = parseModule5(original);
2528
+ mod = parseModule4(original);
3105
2529
  } catch {
3106
2530
  return { configFile: configFilename, modified: false, modifiedFiles: [] };
3107
2531
  }
@@ -3117,9 +2541,9 @@ async function installViteJsxLocPlugin(opts) {
3117
2541
  }
3118
2542
  const pluginsRes = ensurePluginsContainsJsxLoc(found.objExpr);
3119
2543
  if (pluginsRes.changed) changed = true;
3120
- const updated = changed ? generateCode4(mod).code : original;
2544
+ const updated = changed ? generateCode3(mod).code : original;
3121
2545
  if (updated !== original) {
3122
- writeFileSync4(configPath, updated, "utf-8");
2546
+ writeFileSync3(configPath, updated, "utf-8");
3123
2547
  return { configFile: configFilename, modified: true, modifiedFiles: [configPath] };
3124
2548
  }
3125
2549
  return { configFile: configFilename, modified: false, modifiedFiles: [] };
@@ -3134,7 +2558,7 @@ async function uninstallViteJsxLocPlugin(options) {
3134
2558
  };
3135
2559
  }
3136
2560
  try {
3137
- const original = readFileSync8(configPath, "utf-8");
2561
+ const original = readFileSync7(configPath, "utf-8");
3138
2562
  let updated = original.replace(
3139
2563
  /^import\s+\{[^}]*jsxLoc[^}]*\}\s+from\s+["']jsx-loc-plugin\/vite["'];?\s*$/gm,
3140
2564
  ""
@@ -3150,7 +2574,7 @@ async function uninstallViteJsxLocPlugin(options) {
3150
2574
  updated = updated.replace(/jsxLoc\s*\(\s*\)\s*,?\s*/g, "");
3151
2575
  updated = updated.replace(/\n{3,}/g, "\n\n");
3152
2576
  if (updated !== original) {
3153
- writeFileSync4(configPath, updated, "utf-8");
2577
+ writeFileSync3(configPath, updated, "utf-8");
3154
2578
  return {
3155
2579
  success: true,
3156
2580
  modifiedFiles: [configPath]
@@ -3169,9 +2593,9 @@ async function uninstallViteJsxLocPlugin(options) {
3169
2593
  }
3170
2594
 
3171
2595
  // src/utils/next-routes.ts
3172
- import { existsSync as existsSync9 } from "fs";
2596
+ import { existsSync as existsSync8 } from "fs";
3173
2597
  import { mkdir, writeFile } from "fs/promises";
3174
- import { join as join9 } from "path";
2598
+ import { join as join8 } from "path";
3175
2599
  var DEV_SOURCE_ROUTE_TS = `/**
3176
2600
  * Dev-only API route for fetching source files
3177
2601
  *
@@ -3627,23 +3051,23 @@ export async function GET(request: NextRequest) {
3627
3051
  }
3628
3052
  `;
3629
3053
  async function writeRouteFile(absPath, relPath, content, opts) {
3630
- if (existsSync9(absPath) && !opts.force) return;
3054
+ if (existsSync8(absPath) && !opts.force) return;
3631
3055
  await writeFile(absPath, content, "utf-8");
3632
3056
  }
3633
3057
  async function installNextUILintRoutes(opts) {
3634
- const baseRel = join9(opts.appRoot, "api", ".uilint");
3635
- const baseAbs = join9(opts.projectPath, baseRel);
3636
- await mkdir(join9(baseAbs, "source"), { recursive: true });
3058
+ const baseRel = join8(opts.appRoot, "api", ".uilint");
3059
+ const baseAbs = join8(opts.projectPath, baseRel);
3060
+ await mkdir(join8(baseAbs, "source"), { recursive: true });
3637
3061
  await writeRouteFile(
3638
- join9(baseAbs, "source", "route.ts"),
3639
- join9(baseRel, "source", "route.ts"),
3062
+ join8(baseAbs, "source", "route.ts"),
3063
+ join8(baseRel, "source", "route.ts"),
3640
3064
  DEV_SOURCE_ROUTE_TS,
3641
3065
  opts
3642
3066
  );
3643
- await mkdir(join9(baseAbs, "screenshots"), { recursive: true });
3067
+ await mkdir(join8(baseAbs, "screenshots"), { recursive: true });
3644
3068
  await writeRouteFile(
3645
- join9(baseAbs, "screenshots", "route.ts"),
3646
- join9(baseRel, "screenshots", "route.ts"),
3069
+ join8(baseAbs, "screenshots", "route.ts"),
3070
+ join8(baseRel, "screenshots", "route.ts"),
3647
3071
  SCREENSHOT_ROUTE_TS,
3648
3072
  opts
3649
3073
  );
@@ -3651,9 +3075,9 @@ async function installNextUILintRoutes(opts) {
3651
3075
  async function uninstallNextUILintRoutes(options) {
3652
3076
  const { projectPath, appRoot } = options;
3653
3077
  const { rm } = await import("fs/promises");
3654
- const baseAbs = join9(projectPath, appRoot, "api", ".uilint");
3078
+ const baseAbs = join8(projectPath, appRoot, "api", ".uilint");
3655
3079
  try {
3656
- if (existsSync9(baseAbs)) {
3080
+ if (existsSync8(baseAbs)) {
3657
3081
  await rm(baseAbs, { recursive: true, force: true });
3658
3082
  }
3659
3083
  return { success: true };
@@ -3666,17 +3090,17 @@ async function uninstallNextUILintRoutes(options) {
3666
3090
  }
3667
3091
 
3668
3092
  // src/utils/prettier.ts
3669
- import { existsSync as existsSync10, utimesSync } from "fs";
3093
+ import { existsSync as existsSync9, utimesSync } from "fs";
3670
3094
  import { spawn } from "child_process";
3671
- import { join as join10, dirname as dirname4 } from "path";
3095
+ import { join as join9, dirname as dirname3 } from "path";
3672
3096
  function getPrettierPath(projectPath) {
3673
- const localPath = join10(projectPath, "node_modules", ".bin", "prettier");
3674
- if (existsSync10(localPath)) return localPath;
3097
+ const localPath = join9(projectPath, "node_modules", ".bin", "prettier");
3098
+ if (existsSync9(localPath)) return localPath;
3675
3099
  let dir = projectPath;
3676
3100
  for (let i = 0; i < 10; i++) {
3677
- const binPath = join10(dir, "node_modules", ".bin", "prettier");
3678
- if (existsSync10(binPath)) return binPath;
3679
- const parent = dirname4(dir);
3101
+ const binPath = join9(dir, "node_modules", ".bin", "prettier");
3102
+ if (existsSync9(binPath)) return binPath;
3103
+ const parent = dirname3(dir);
3680
3104
  if (parent === dir) break;
3681
3105
  dir = parent;
3682
3106
  }
@@ -3807,7 +3231,7 @@ function touchFiles(filePaths) {
3807
3231
  const now = /* @__PURE__ */ new Date();
3808
3232
  for (const filePath of filePaths) {
3809
3233
  try {
3810
- if (existsSync10(filePath)) {
3234
+ if (existsSync9(filePath)) {
3811
3235
  utimesSync(filePath, now, now);
3812
3236
  }
3813
3237
  } catch {
@@ -3828,7 +3252,7 @@ async function executeAction(action, options) {
3828
3252
  wouldDo: `Create directory: ${action.path}`
3829
3253
  };
3830
3254
  }
3831
- if (!existsSync11(action.path)) {
3255
+ if (!existsSync10(action.path)) {
3832
3256
  mkdirSync(action.path, { recursive: true });
3833
3257
  }
3834
3258
  return { action, success: true };
@@ -3841,11 +3265,11 @@ async function executeAction(action, options) {
3841
3265
  wouldDo: `Create file: ${action.path}${action.permissions ? ` (mode: ${action.permissions.toString(8)})` : ""}`
3842
3266
  };
3843
3267
  }
3844
- const dir = dirname5(action.path);
3845
- if (!existsSync11(dir)) {
3268
+ const dir = dirname4(action.path);
3269
+ if (!existsSync10(dir)) {
3846
3270
  mkdirSync(dir, { recursive: true });
3847
3271
  }
3848
- writeFileSync5(action.path, action.content, "utf-8");
3272
+ writeFileSync4(action.path, action.content, "utf-8");
3849
3273
  if (action.permissions) {
3850
3274
  chmodSync(action.path, action.permissions);
3851
3275
  }
@@ -3860,18 +3284,18 @@ async function executeAction(action, options) {
3860
3284
  };
3861
3285
  }
3862
3286
  let existing = {};
3863
- if (existsSync11(action.path)) {
3287
+ if (existsSync10(action.path)) {
3864
3288
  try {
3865
- existing = JSON.parse(readFileSync9(action.path, "utf-8"));
3289
+ existing = JSON.parse(readFileSync8(action.path, "utf-8"));
3866
3290
  } catch {
3867
3291
  }
3868
3292
  }
3869
3293
  const merged = deepMerge(existing, action.merge);
3870
- const dir = dirname5(action.path);
3871
- if (!existsSync11(dir)) {
3294
+ const dir = dirname4(action.path);
3295
+ if (!existsSync10(dir)) {
3872
3296
  mkdirSync(dir, { recursive: true });
3873
3297
  }
3874
- writeFileSync5(action.path, JSON.stringify(merged, null, 2), "utf-8");
3298
+ writeFileSync4(action.path, JSON.stringify(merged, null, 2), "utf-8");
3875
3299
  return { action, success: true };
3876
3300
  }
3877
3301
  case "delete_file": {
@@ -3882,7 +3306,7 @@ async function executeAction(action, options) {
3882
3306
  wouldDo: `Delete file: ${action.path}`
3883
3307
  };
3884
3308
  }
3885
- if (existsSync11(action.path)) {
3309
+ if (existsSync10(action.path)) {
3886
3310
  unlinkSync(action.path);
3887
3311
  }
3888
3312
  return { action, success: true };
@@ -3895,12 +3319,12 @@ async function executeAction(action, options) {
3895
3319
  wouldDo: `Append to file: ${action.path}`
3896
3320
  };
3897
3321
  }
3898
- if (existsSync11(action.path)) {
3899
- const content = readFileSync9(action.path, "utf-8");
3322
+ if (existsSync10(action.path)) {
3323
+ const content = readFileSync8(action.path, "utf-8");
3900
3324
  if (action.ifNotContains && content.includes(action.ifNotContains)) {
3901
3325
  return { action, success: true };
3902
3326
  }
3903
- writeFileSync5(action.path, content + action.content, "utf-8");
3327
+ writeFileSync4(action.path, content + action.content, "utf-8");
3904
3328
  }
3905
3329
  return { action, success: true };
3906
3330
  }
@@ -4169,7 +3593,7 @@ async function executeRemoveDirectory(action, options) {
4169
3593
  wouldDo: `Remove directory: ${action.path}`
4170
3594
  };
4171
3595
  }
4172
- if (existsSync11(action.path)) {
3596
+ if (existsSync10(action.path)) {
4173
3597
  rmSync(action.path, { recursive: true, force: true });
4174
3598
  }
4175
3599
  return { action, success: true };
@@ -4406,7 +3830,7 @@ async function execute(plan, options = {}) {
4406
3830
  import { ruleRegistry as ruleRegistry3 } from "uilint-eslint";
4407
3831
 
4408
3832
  // src/commands/install/installers/genstyleguide.ts
4409
- import { join as join11 } from "path";
3833
+ import { join as join10 } from "path";
4410
3834
  var genstyleguideInstaller = {
4411
3835
  id: "genstyleguide",
4412
3836
  name: "/genstyleguide command",
@@ -4416,7 +3840,7 @@ var genstyleguideInstaller = {
4416
3840
  return true;
4417
3841
  },
4418
3842
  getTargets(project) {
4419
- const commandPath = join11(project.cursorDir.path, "commands", "genstyleguide.md");
3843
+ const commandPath = join10(project.cursorDir.path, "commands", "genstyleguide.md");
4420
3844
  const isInstalled = project.commands.genstyleguide;
4421
3845
  return [
4422
3846
  {
@@ -4429,7 +3853,7 @@ var genstyleguideInstaller = {
4429
3853
  },
4430
3854
  plan(targets, config, project) {
4431
3855
  const actions = [];
4432
- const commandsDir = join11(project.cursorDir.path, "commands");
3856
+ const commandsDir = join10(project.cursorDir.path, "commands");
4433
3857
  if (!project.cursorDir.exists) {
4434
3858
  actions.push({
4435
3859
  type: "create_directory",
@@ -4442,7 +3866,7 @@ var genstyleguideInstaller = {
4442
3866
  });
4443
3867
  actions.push({
4444
3868
  type: "create_file",
4445
- path: join11(commandsDir, "genstyleguide.md"),
3869
+ path: join10(commandsDir, "genstyleguide.md"),
4446
3870
  content: GENSTYLEGUIDE_COMMAND_MD
4447
3871
  });
4448
3872
  return {
@@ -4471,7 +3895,7 @@ var genstyleguideInstaller = {
4471
3895
  },
4472
3896
  planUninstall(targets, project) {
4473
3897
  const actions = [];
4474
- const commandPath = join11(project.cursorDir.path, "commands", "genstyleguide.md");
3898
+ const commandPath = join10(project.cursorDir.path, "commands", "genstyleguide.md");
4475
3899
  actions.push({
4476
3900
  type: "delete_file",
4477
3901
  path: commandPath
@@ -4481,8 +3905,8 @@ var genstyleguideInstaller = {
4481
3905
  };
4482
3906
 
4483
3907
  // src/commands/install/installers/skill.ts
4484
- import { existsSync as existsSync12 } from "fs";
4485
- import { join as join12 } from "path";
3908
+ import { existsSync as existsSync11 } from "fs";
3909
+ import { join as join11 } from "path";
4486
3910
  var skillInstaller = {
4487
3911
  id: "skill",
4488
3912
  name: "UI Consistency Agent skill",
@@ -4492,9 +3916,9 @@ var skillInstaller = {
4492
3916
  return true;
4493
3917
  },
4494
3918
  getTargets(project) {
4495
- const skillsDir = join12(project.cursorDir.path, "skills", "ui-consistency-enforcer");
4496
- const skillMdPath = join12(skillsDir, "SKILL.md");
4497
- const isInstalled = existsSync12(skillMdPath);
3919
+ const skillsDir = join11(project.cursorDir.path, "skills", "ui-consistency-enforcer");
3920
+ const skillMdPath = join11(skillsDir, "SKILL.md");
3921
+ const isInstalled = existsSync11(skillMdPath);
4498
3922
  return [
4499
3923
  {
4500
3924
  id: "ui-consistency-skill",
@@ -4513,21 +3937,21 @@ var skillInstaller = {
4513
3937
  path: project.cursorDir.path
4514
3938
  });
4515
3939
  }
4516
- const skillsDir = join12(project.cursorDir.path, "skills");
3940
+ const skillsDir = join11(project.cursorDir.path, "skills");
4517
3941
  actions.push({
4518
3942
  type: "create_directory",
4519
3943
  path: skillsDir
4520
3944
  });
4521
3945
  try {
4522
3946
  const skill = loadSkill("ui-consistency-enforcer");
4523
- const skillDir = join12(skillsDir, skill.name);
3947
+ const skillDir = join11(skillsDir, skill.name);
4524
3948
  actions.push({
4525
3949
  type: "create_directory",
4526
3950
  path: skillDir
4527
3951
  });
4528
3952
  for (const file of skill.files) {
4529
- const filePath = join12(skillDir, file.relativePath);
4530
- const fileDir = join12(
3953
+ const filePath = join11(skillDir, file.relativePath);
3954
+ const fileDir = join11(
4531
3955
  skillDir,
4532
3956
  file.relativePath.split("/").slice(0, -1).join("/")
4533
3957
  );
@@ -4583,7 +4007,7 @@ var skillInstaller = {
4583
4007
  },
4584
4008
  planUninstall(targets, project) {
4585
4009
  const actions = [];
4586
- const skillDir = join12(project.cursorDir.path, "skills", "ui-consistency-enforcer");
4010
+ const skillDir = join11(project.cursorDir.path, "skills", "ui-consistency-enforcer");
4587
4011
  actions.push({
4588
4012
  type: "remove_directory",
4589
4013
  path: skillDir
@@ -4593,7 +4017,7 @@ var skillInstaller = {
4593
4017
  };
4594
4018
 
4595
4019
  // src/commands/install/installers/eslint.ts
4596
- import { join as join13 } from "path";
4020
+ import { join as join12 } from "path";
4597
4021
  import { ruleRegistry as ruleRegistry2, getRulesByCategory as getRulesByCategory2 } from "uilint-eslint";
4598
4022
  function getUpgradeInfo(configuredRuleIds) {
4599
4023
  const configuredSet = new Set(configuredRuleIds);
@@ -4769,7 +4193,7 @@ var eslintInstaller = {
4769
4193
  for (const target of targets) {
4770
4194
  const pkgInfo = project.packages.find((p) => p.path === target.path);
4771
4195
  if (!pkgInfo || !pkgInfo.eslintConfigPath) continue;
4772
- const rulesDir = join13(target.path, ".uilint", "rules");
4196
+ const rulesDir = join12(target.path, ".uilint", "rules");
4773
4197
  actions.push({
4774
4198
  type: "create_directory",
4775
4199
  path: rulesDir
@@ -4787,7 +4211,7 @@ var eslintInstaller = {
4787
4211
  hasExistingRules: pkgInfo.hasUilintRules
4788
4212
  });
4789
4213
  }
4790
- const gitignorePath = join13(project.workspaceRoot, ".gitignore");
4214
+ const gitignorePath = join12(project.workspaceRoot, ".gitignore");
4791
4215
  actions.push({
4792
4216
  type: "append_to_file",
4793
4217
  path: gitignorePath,
@@ -4829,7 +4253,7 @@ var eslintInstaller = {
4829
4253
  packagePath: target.path,
4830
4254
  configPath: pkgInfo.eslintConfigPath
4831
4255
  });
4832
- const rulesDir = join13(target.path, ".uilint", "rules");
4256
+ const rulesDir = join12(target.path, ".uilint", "rules");
4833
4257
  actions.push({
4834
4258
  type: "remove_directory",
4835
4259
  path: rulesDir
@@ -4854,8 +4278,7 @@ var viteOverlayInstaller = {
4854
4278
  label: app.projectPath.split("/").pop() || app.projectPath,
4855
4279
  path: app.projectPath,
4856
4280
  hint: "React + Vite",
4857
- isInstalled: false
4858
- // TODO: Detect if already installed
4281
+ isInstalled: app.hasUilintOverlay
4859
4282
  }));
4860
4283
  },
4861
4284
  plan(targets, config, project) {
@@ -5066,4 +4489,4 @@ async function installUI(options = {}, executeOptions = {}) {
5066
4489
  export {
5067
4490
  installUI
5068
4491
  };
5069
- //# sourceMappingURL=install-ui-HTVB5HDB.js.map
4492
+ //# sourceMappingURL=install-ui-TXV7A34M.js.map