uilint 0.2.42 → 0.2.43
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.
- package/dist/chunk-CZNPG4UI.js +118 -0
- package/dist/chunk-CZNPG4UI.js.map +1 -0
- package/dist/{chunk-OTU5FY6B.js → chunk-JPE27ROY.js} +68 -2
- package/dist/chunk-JPE27ROY.js.map +1 -0
- package/dist/{chunk-PVUDWWTL.js → chunk-KNZVCCXM.js} +41 -154
- package/dist/chunk-KNZVCCXM.js.map +1 -0
- package/dist/{plan-QVR3RBLG.js → chunk-Y7ZNZFVZ.js} +2 -245
- package/dist/chunk-Y7ZNZFVZ.js.map +1 -0
- package/dist/chunk-ZDSDZNIB.js +93 -0
- package/dist/chunk-ZDSDZNIB.js.map +1 -0
- package/dist/index.js +20 -9
- package/dist/index.js.map +1 -1
- package/dist/{install-ui-HG73W6P7.js → install-ui-COFD7H2I.js} +54 -11
- package/dist/install-ui-COFD7H2I.js.map +1 -0
- package/dist/plan-N453UW4O.js +259 -0
- package/dist/plan-N453UW4O.js.map +1 -0
- package/dist/upgrade-TGYLZ4QX.js +587 -0
- package/dist/upgrade-TGYLZ4QX.js.map +1 -0
- package/package.json +5 -5
- package/dist/chunk-OTU5FY6B.js.map +0 -1
- package/dist/chunk-PVUDWWTL.js.map +0 -1
- package/dist/install-ui-HG73W6P7.js.map +0 -1
- package/dist/plan-QVR3RBLG.js.map +0 -1
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/utils/prompts.ts
|
|
4
|
+
import * as p from "@clack/prompts";
|
|
5
|
+
import pc from "picocolors";
|
|
6
|
+
import { readFileSync } from "fs";
|
|
7
|
+
import { dirname, join } from "path";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
9
|
+
function getCLIVersion() {
|
|
10
|
+
try {
|
|
11
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const pkgPath = join(__dirname, "..", "..", "package.json");
|
|
13
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
14
|
+
return pkg.version || "0.0.0";
|
|
15
|
+
} catch {
|
|
16
|
+
return "0.0.0";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function intro2(title) {
|
|
20
|
+
const version = getCLIVersion();
|
|
21
|
+
const header = pc.bold(pc.cyan("\u25C6 UILint")) + pc.dim(` v${version}`);
|
|
22
|
+
console.log();
|
|
23
|
+
p.intro(title ? `${header} ${pc.dim("\xB7")} ${title}` : header);
|
|
24
|
+
}
|
|
25
|
+
function outro2(message) {
|
|
26
|
+
p.outro(pc.green(message));
|
|
27
|
+
}
|
|
28
|
+
function cancel2(message = "Operation cancelled.") {
|
|
29
|
+
p.cancel(pc.yellow(message));
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
function handleCancel(value) {
|
|
33
|
+
if (p.isCancel(value)) {
|
|
34
|
+
cancel2();
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
async function withSpinner(message, fn) {
|
|
40
|
+
const s = p.spinner();
|
|
41
|
+
s.start(message);
|
|
42
|
+
try {
|
|
43
|
+
const result = fn.length >= 1 ? await fn(s) : await fn();
|
|
44
|
+
s.stop(pc.green("\u2713 ") + message);
|
|
45
|
+
return result;
|
|
46
|
+
} catch (error) {
|
|
47
|
+
s.stop(pc.red("\u2717 ") + message);
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function createSpinner() {
|
|
52
|
+
return p.spinner();
|
|
53
|
+
}
|
|
54
|
+
function note2(message, title) {
|
|
55
|
+
p.note(message, title);
|
|
56
|
+
}
|
|
57
|
+
function log2(message) {
|
|
58
|
+
p.log.message(message);
|
|
59
|
+
}
|
|
60
|
+
function logInfo(message) {
|
|
61
|
+
p.log.info(message);
|
|
62
|
+
}
|
|
63
|
+
function logSuccess(message) {
|
|
64
|
+
p.log.success(message);
|
|
65
|
+
}
|
|
66
|
+
function logWarning(message) {
|
|
67
|
+
p.log.warn(message);
|
|
68
|
+
}
|
|
69
|
+
function logError(message) {
|
|
70
|
+
p.log.error(message);
|
|
71
|
+
}
|
|
72
|
+
async function select2(options) {
|
|
73
|
+
const result = await p.select({
|
|
74
|
+
message: options.message,
|
|
75
|
+
options: options.options,
|
|
76
|
+
initialValue: options.initialValue
|
|
77
|
+
});
|
|
78
|
+
return handleCancel(result);
|
|
79
|
+
}
|
|
80
|
+
async function confirm2(options) {
|
|
81
|
+
const result = await p.confirm({
|
|
82
|
+
message: options.message,
|
|
83
|
+
initialValue: options.initialValue ?? true
|
|
84
|
+
});
|
|
85
|
+
return handleCancel(result);
|
|
86
|
+
}
|
|
87
|
+
async function text2(options) {
|
|
88
|
+
const result = await p.text(options);
|
|
89
|
+
return handleCancel(result);
|
|
90
|
+
}
|
|
91
|
+
async function multiselect2(options) {
|
|
92
|
+
const result = await p.multiselect({
|
|
93
|
+
message: options.message,
|
|
94
|
+
options: options.options,
|
|
95
|
+
required: options.required,
|
|
96
|
+
initialValues: options.initialValues
|
|
97
|
+
});
|
|
98
|
+
return handleCancel(result);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export {
|
|
102
|
+
pc,
|
|
103
|
+
intro2 as intro,
|
|
104
|
+
outro2 as outro,
|
|
105
|
+
withSpinner,
|
|
106
|
+
createSpinner,
|
|
107
|
+
note2 as note,
|
|
108
|
+
log2 as log,
|
|
109
|
+
logInfo,
|
|
110
|
+
logSuccess,
|
|
111
|
+
logWarning,
|
|
112
|
+
logError,
|
|
113
|
+
select2 as select,
|
|
114
|
+
confirm2 as confirm,
|
|
115
|
+
text2 as text,
|
|
116
|
+
multiselect2 as multiselect
|
|
117
|
+
};
|
|
118
|
+
//# sourceMappingURL=chunk-CZNPG4UI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/prompts.ts"],"sourcesContent":["/**\n * Shared clack/prompts utilities for UILint CLI\n * Provides branded intro/outro, spinners, and common UI patterns\n */\n\nimport * as p from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { readFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { fileURLToPath } from \"url\";\n\n/**\n * Get the CLI version from package.json\n */\nfunction getCLIVersion(): string {\n try {\n const __dirname = dirname(fileURLToPath(import.meta.url));\n const pkgPath = join(__dirname, \"..\", \"..\", \"package.json\");\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as {\n version?: string;\n };\n return pkg.version || \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n\n/**\n * Branded UILint intro with logo and version\n */\nexport function intro(title?: string): void {\n const version = getCLIVersion();\n const header = pc.bold(pc.cyan(\"◆ UILint\")) + pc.dim(` v${version}`);\n \n console.log();\n p.intro(title ? `${header} ${pc.dim(\"·\")} ${title}` : header);\n}\n\n/**\n * Styled outro with next steps\n */\nexport function outro(message: string): void {\n p.outro(pc.green(message));\n}\n\n/**\n * Cancel message when user exits\n */\nexport function cancel(message = \"Operation cancelled.\"): void {\n p.cancel(pc.yellow(message));\n process.exit(0);\n}\n\n/**\n * Check if user cancelled a prompt\n */\nexport function isCancel(value: unknown): value is symbol {\n return p.isCancel(value);\n}\n\n/**\n * Handle cancel check - exits if cancelled\n */\nexport function handleCancel<T>(value: T | symbol): T {\n if (p.isCancel(value)) {\n cancel();\n process.exit(0);\n }\n return value as T;\n}\n\n/**\n * Spinner wrapper with automatic error handling\n */\nexport async function withSpinner<T>(\n message: string,\n fn: (() => Promise<T>) | ((spinner: ReturnType<typeof p.spinner>) => Promise<T>)\n): Promise<T> {\n const s = p.spinner();\n s.start(message);\n try {\n const result =\n fn.length >= 1\n ? await (fn as (spinner: ReturnType<typeof p.spinner>) => Promise<T>)(s)\n : await (fn as () => Promise<T>)();\n s.stop(pc.green(\"✓ \") + message);\n return result;\n } catch (error) {\n s.stop(pc.red(\"✗ \") + message);\n throw error;\n }\n}\n\n/**\n * Spinner that can be updated\n */\nexport function createSpinner() {\n return p.spinner();\n}\n\n/**\n * Display a note box\n */\nexport function note(message: string, title?: string): void {\n p.note(message, title);\n}\n\n/**\n * Display a log message\n */\nexport function log(message: string): void {\n p.log.message(message);\n}\n\n/**\n * Display an info message\n */\nexport function logInfo(message: string): void {\n p.log.info(message);\n}\n\n/**\n * Display a success message\n */\nexport function logSuccess(message: string): void {\n p.log.success(message);\n}\n\n/**\n * Display a warning message\n */\nexport function logWarning(message: string): void {\n p.log.warn(message);\n}\n\n/**\n * Display an error message\n */\nexport function logError(message: string): void {\n p.log.error(message);\n}\n\n/**\n * Display a step message\n */\nexport function logStep(message: string): void {\n p.log.step(message);\n}\n\n/**\n * Select prompt wrapper\n */\nexport async function select<T extends string>(options: {\n message: string;\n options: Array<{ value: T; label: string; hint?: string }>;\n initialValue?: T;\n}): Promise<T> {\n const result = await p.select({\n message: options.message,\n options: options.options as { value: T; label: string; hint?: string }[],\n initialValue: options.initialValue,\n } as Parameters<typeof p.select>[0]);\n return handleCancel(result) as T;\n}\n\n/**\n * Confirm prompt wrapper\n */\nexport async function confirm(options: {\n message: string;\n initialValue?: boolean;\n}): Promise<boolean> {\n const result = await p.confirm({\n message: options.message,\n initialValue: options.initialValue ?? true,\n });\n return handleCancel(result);\n}\n\n/**\n * Text input prompt wrapper\n */\nexport async function text(options: {\n message: string;\n placeholder?: string;\n defaultValue?: string;\n validate?: (value: string) => string | Error | undefined;\n}): Promise<string> {\n const result = await p.text(options);\n return handleCancel(result);\n}\n\n/**\n * Multiselect prompt wrapper\n */\nexport async function multiselect<T extends string>(options: {\n message: string;\n options: Array<{ value: T; label: string; hint?: string }>;\n required?: boolean;\n initialValues?: T[];\n}): Promise<T[]> {\n const result = await p.multiselect({\n message: options.message,\n options: options.options as { value: T; label: string; hint?: string }[],\n required: options.required,\n initialValues: options.initialValues,\n } as Parameters<typeof p.multiselect>[0]);\n return handleCancel(result) as T[];\n}\n\n/**\n * Group of tasks displayed together\n */\nexport async function group<T extends Record<string, unknown>>(\n prompts: p.PromptGroup<T>,\n options?: p.PromptGroupOptions<T>\n): Promise<T> {\n const result = await p.group(prompts, options);\n return result;\n}\n\n// Re-export picocolors for consistent styling\nexport { pc };\n"],"mappings":";;;AAKA,YAAY,OAAO;AACnB,OAAO,QAAQ;AACf,SAAS,oBAAoB;AAC7B,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAK9B,SAAS,gBAAwB;AAC/B,MAAI;AACF,UAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AACxD,UAAM,UAAU,KAAK,WAAW,MAAM,MAAM,cAAc;AAC1D,UAAM,MAAM,KAAK,MAAM,aAAa,SAAS,OAAO,CAAC;AAGrD,WAAO,IAAI,WAAW;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,SAASA,OAAM,OAAsB;AAC1C,QAAM,UAAU,cAAc;AAC9B,QAAM,SAAS,GAAG,KAAK,GAAG,KAAK,eAAU,CAAC,IAAI,GAAG,IAAI,KAAK,OAAO,EAAE;AAEnE,UAAQ,IAAI;AACZ,EAAE,QAAM,QAAQ,GAAG,MAAM,IAAI,GAAG,IAAI,MAAG,CAAC,IAAI,KAAK,KAAK,MAAM;AAC9D;AAKO,SAASC,OAAM,SAAuB;AAC3C,EAAE,QAAM,GAAG,MAAM,OAAO,CAAC;AAC3B;AAKO,SAASC,QAAO,UAAU,wBAA8B;AAC7D,EAAE,SAAO,GAAG,OAAO,OAAO,CAAC;AAC3B,UAAQ,KAAK,CAAC;AAChB;AAYO,SAAS,aAAgB,OAAsB;AACpD,MAAM,WAAS,KAAK,GAAG;AACrB,IAAAC,QAAO;AACP,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO;AACT;AAKA,eAAsB,YACpB,SACA,IACY;AACZ,QAAM,IAAM,UAAQ;AACpB,IAAE,MAAM,OAAO;AACf,MAAI;AACF,UAAM,SACJ,GAAG,UAAU,IACT,MAAO,GAA6D,CAAC,IACrE,MAAO,GAAwB;AACrC,MAAE,KAAK,GAAG,MAAM,SAAI,IAAI,OAAO;AAC/B,WAAO;AAAA,EACT,SAAS,OAAO;AACd,MAAE,KAAK,GAAG,IAAI,SAAI,IAAI,OAAO;AAC7B,UAAM;AAAA,EACR;AACF;AAKO,SAAS,gBAAgB;AAC9B,SAAS,UAAQ;AACnB;AAKO,SAASC,MAAK,SAAiB,OAAsB;AAC1D,EAAE,OAAK,SAAS,KAAK;AACvB;AAKO,SAASC,KAAI,SAAuB;AACzC,EAAE,MAAI,QAAQ,OAAO;AACvB;AAKO,SAAS,QAAQ,SAAuB;AAC7C,EAAE,MAAI,KAAK,OAAO;AACpB;AAKO,SAAS,WAAW,SAAuB;AAChD,EAAE,MAAI,QAAQ,OAAO;AACvB;AAKO,SAAS,WAAW,SAAuB;AAChD,EAAE,MAAI,KAAK,OAAO;AACpB;AAKO,SAAS,SAAS,SAAuB;AAC9C,EAAE,MAAI,MAAM,OAAO;AACrB;AAYA,eAAsBC,QAAyB,SAIhC;AACb,QAAM,SAAS,MAAQ,SAAO;AAAA,IAC5B,SAAS,QAAQ;AAAA,IACjB,SAAS,QAAQ;AAAA,IACjB,cAAc,QAAQ;AAAA,EACxB,CAAmC;AACnC,SAAO,aAAa,MAAM;AAC5B;AAKA,eAAsBC,SAAQ,SAGT;AACnB,QAAM,SAAS,MAAQ,UAAQ;AAAA,IAC7B,SAAS,QAAQ;AAAA,IACjB,cAAc,QAAQ,gBAAgB;AAAA,EACxC,CAAC;AACD,SAAO,aAAa,MAAM;AAC5B;AAKA,eAAsBC,MAAK,SAKP;AAClB,QAAM,SAAS,MAAQ,OAAK,OAAO;AACnC,SAAO,aAAa,MAAM;AAC5B;AAKA,eAAsBC,aAA8B,SAKnC;AACf,QAAM,SAAS,MAAQ,cAAY;AAAA,IACjC,SAAS,QAAQ;AAAA,IACjB,SAAS,QAAQ;AAAA,IACjB,UAAU,QAAQ;AAAA,IAClB,eAAe,QAAQ;AAAA,EACzB,CAAwC;AACxC,SAAO,aAAa,MAAM;AAC5B;","names":["intro","outro","cancel","cancel","note","log","select","confirm","text","multiselect"]}
|
|
@@ -162,10 +162,76 @@ async function runTestsWithCoverage(pm, projectPath) {
|
|
|
162
162
|
const { command, args } = getTestCoverageCommand(pm);
|
|
163
163
|
await spawnAsync(command, args, projectPath);
|
|
164
164
|
}
|
|
165
|
+
var UILINT_PACKAGES = [
|
|
166
|
+
"uilint",
|
|
167
|
+
"uilint-eslint",
|
|
168
|
+
"uilint-core",
|
|
169
|
+
"uilint-react"
|
|
170
|
+
];
|
|
171
|
+
function getInstalledUilintPackages(projectPath) {
|
|
172
|
+
const pkgJsonPath = join(projectPath, "package.json");
|
|
173
|
+
if (!existsSync(pkgJsonPath)) {
|
|
174
|
+
return /* @__PURE__ */ new Map();
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
|
|
178
|
+
const result = /* @__PURE__ */ new Map();
|
|
179
|
+
const allDeps = {
|
|
180
|
+
...pkgJson.dependencies,
|
|
181
|
+
...pkgJson.devDependencies
|
|
182
|
+
};
|
|
183
|
+
for (const pkg of UILINT_PACKAGES) {
|
|
184
|
+
if (allDeps[pkg]) {
|
|
185
|
+
result.set(pkg, allDeps[pkg]);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return result;
|
|
189
|
+
} catch {
|
|
190
|
+
return /* @__PURE__ */ new Map();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async function updatePackages(pm, projectPath, packages, options = { dev: true }) {
|
|
194
|
+
if (!packages.length) return;
|
|
195
|
+
const isDev = options.dev ?? true;
|
|
196
|
+
const packagesWithLatest = packages.map((pkg) => `${pkg}@latest`);
|
|
197
|
+
switch (pm) {
|
|
198
|
+
case "pnpm":
|
|
199
|
+
await spawnAsync(
|
|
200
|
+
"pnpm",
|
|
201
|
+
["add", ...isDev ? ["-D"] : [], ...packagesWithLatest],
|
|
202
|
+
projectPath
|
|
203
|
+
);
|
|
204
|
+
return;
|
|
205
|
+
case "yarn":
|
|
206
|
+
await spawnAsync(
|
|
207
|
+
"yarn",
|
|
208
|
+
["add", ...isDev ? ["-D"] : [], ...packagesWithLatest],
|
|
209
|
+
projectPath
|
|
210
|
+
);
|
|
211
|
+
return;
|
|
212
|
+
case "bun":
|
|
213
|
+
await spawnAsync(
|
|
214
|
+
"bun",
|
|
215
|
+
["add", ...isDev ? ["-d"] : [], ...packagesWithLatest],
|
|
216
|
+
projectPath
|
|
217
|
+
);
|
|
218
|
+
return;
|
|
219
|
+
case "npm":
|
|
220
|
+
default:
|
|
221
|
+
await spawnAsync(
|
|
222
|
+
"npm",
|
|
223
|
+
["install", isDev ? "--save-dev" : "--save", ...packagesWithLatest],
|
|
224
|
+
projectPath
|
|
225
|
+
);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
165
229
|
|
|
166
230
|
export {
|
|
167
231
|
detectPackageManager,
|
|
168
232
|
installDependencies,
|
|
169
|
-
runTestsWithCoverage
|
|
233
|
+
runTestsWithCoverage,
|
|
234
|
+
getInstalledUilintPackages,
|
|
235
|
+
updatePackages
|
|
170
236
|
};
|
|
171
|
-
//# sourceMappingURL=chunk-
|
|
237
|
+
//# sourceMappingURL=chunk-JPE27ROY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/package-manager.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"fs\";\nimport { spawn } from \"child_process\";\nimport { dirname, join } from \"path\";\n\nexport type PackageManager = \"pnpm\" | \"yarn\" | \"npm\" | \"bun\";\n\n/**\n * Detect which package manager a project uses by looking for lockfiles.\n * Walks up the directory tree to support monorepos.\n */\nexport function detectPackageManager(projectPath: string): PackageManager {\n // Monorepo-friendly detection: walk up to find the lockfile/workspace marker.\n let dir = projectPath;\n for (;;) {\n // pnpm\n if (existsSync(join(dir, \"pnpm-lock.yaml\"))) return \"pnpm\";\n if (existsSync(join(dir, \"pnpm-workspace.yaml\"))) return \"pnpm\";\n\n // yarn\n if (existsSync(join(dir, \"yarn.lock\"))) return \"yarn\";\n\n // bun\n if (existsSync(join(dir, \"bun.lockb\"))) return \"bun\";\n if (existsSync(join(dir, \"bun.lock\"))) return \"bun\";\n\n // npm\n if (existsSync(join(dir, \"package-lock.json\"))) return \"npm\";\n\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n // Default: npm (best-effort)\n return \"npm\";\n}\n\nfunction spawnAsync(\n command: string,\n args: string[],\n cwd: string\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd,\n // Capture output so we can surface it in installer summaries, while still\n // streaming to the user for a good UX.\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n shell: process.platform === \"win32\",\n });\n\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n const MAX_CAPTURE = 64 * 1024; // keep last 64KB per stream\n\n child.stdout?.on(\"data\", (chunk: Buffer) => {\n process.stdout.write(chunk);\n stdoutChunks.push(chunk);\n // keep bounded\n while (Buffer.concat(stdoutChunks).length > MAX_CAPTURE) stdoutChunks.shift();\n });\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n process.stderr.write(chunk);\n stderrChunks.push(chunk);\n while (Buffer.concat(stderrChunks).length > MAX_CAPTURE) stderrChunks.shift();\n });\n\n child.on(\"error\", (err) => {\n reject(err);\n });\n\n child.on(\"close\", (code) => {\n if (code === 0) {\n resolve();\n return;\n }\n\n const cmd = `${command} ${args.join(\" \")}`.trim();\n const stdout = Buffer.concat(stdoutChunks).toString(\"utf-8\").trim();\n const stderr = Buffer.concat(stderrChunks).toString(\"utf-8\").trim();\n const snippet = (stderr || stdout).trim();\n\n reject(\n new Error(\n `${cmd} exited with ${code}${\n snippet ? `\\n\\n--- output ---\\n${snippet}\\n--- end output ---` : \"\"\n }`\n )\n );\n });\n });\n}\n\n/**\n * Get the set of packages already installed in a project\n * (both dependencies and devDependencies)\n */\nfunction getInstalledPackages(projectPath: string): Set<string> {\n const pkgJsonPath = join(projectPath, \"package.json\");\n if (!existsSync(pkgJsonPath)) {\n return new Set();\n }\n\n try {\n const pkgJson = JSON.parse(readFileSync(pkgJsonPath, \"utf-8\")) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n\n const installed = new Set<string>();\n if (pkgJson.dependencies) {\n for (const name of Object.keys(pkgJson.dependencies)) {\n installed.add(name);\n }\n }\n if (pkgJson.devDependencies) {\n for (const name of Object.keys(pkgJson.devDependencies)) {\n installed.add(name);\n }\n }\n return installed;\n } catch {\n return new Set();\n }\n}\n\n/**\n * Extract package name from a package specifier (e.g., \"foo@^1.0.0\" -> \"foo\")\n */\nfunction getPackageName(specifier: string): string {\n // Handle scoped packages like @scope/pkg@version\n if (specifier.startsWith(\"@\")) {\n const slashIndex = specifier.indexOf(\"/\");\n if (slashIndex === -1) return specifier;\n\n const afterSlash = specifier.slice(slashIndex + 1);\n const atIndex = afterSlash.indexOf(\"@\");\n if (atIndex === -1) return specifier;\n return specifier.slice(0, slashIndex + 1 + atIndex);\n }\n\n // Handle unscoped packages like pkg@version\n const atIndex = specifier.indexOf(\"@\");\n if (atIndex === -1) return specifier;\n return specifier.slice(0, atIndex);\n}\n\n/**\n * Filter out packages that are already installed\n */\nfunction filterAlreadyInstalled(\n packages: string[],\n projectPath: string\n): string[] {\n const installed = getInstalledPackages(projectPath);\n return packages.filter((pkg) => {\n const name = getPackageName(pkg);\n return !installed.has(name);\n });\n}\n\nexport async function installDependencies(\n pm: PackageManager,\n projectPath: string,\n packages: string[],\n options: { dev?: boolean } = { dev: true }\n): Promise<void> {\n if (!packages.length) return;\n\n // Filter out packages that are already installed to avoid yarn/npm errors\n // when trying to add a regular dependency as a dev dependency or vice versa\n const packagesToInstall = filterAlreadyInstalled(packages, projectPath);\n if (!packagesToInstall.length) return;\n\n const isDev = options.dev ?? true;\n\n switch (pm) {\n case \"pnpm\":\n await spawnAsync(\n \"pnpm\",\n [\"add\", ...(isDev ? [\"-D\"] : []), ...packagesToInstall],\n projectPath\n );\n return;\n case \"yarn\":\n await spawnAsync(\n \"yarn\",\n [\"add\", ...(isDev ? [\"-D\"] : []), ...packagesToInstall],\n projectPath\n );\n return;\n case \"bun\":\n await spawnAsync(\n \"bun\",\n [\"add\", ...(isDev ? [\"-d\"] : []), ...packagesToInstall],\n projectPath\n );\n return;\n case \"npm\":\n default:\n await spawnAsync(\n \"npm\",\n [\"install\", isDev ? \"--save-dev\" : \"--save\", ...packagesToInstall],\n projectPath\n );\n return;\n }\n}\n\n/**\n * Get the command and arguments to run tests with coverage\n */\nexport function getTestCoverageCommand(pm: PackageManager): {\n command: string;\n args: string[];\n} {\n switch (pm) {\n case \"pnpm\":\n return { command: \"pnpm\", args: [\"test\", \"--\", \"--coverage\"] };\n case \"yarn\":\n return { command: \"yarn\", args: [\"test\", \"--coverage\"] };\n case \"bun\":\n return { command: \"bun\", args: [\"test\", \"--coverage\"] };\n case \"npm\":\n default:\n return { command: \"npm\", args: [\"test\", \"--\", \"--coverage\"] };\n }\n}\n\n/**\n * Run tests with coverage for a project\n */\nexport async function runTestsWithCoverage(\n pm: PackageManager,\n projectPath: string\n): Promise<void> {\n const { command, args } = getTestCoverageCommand(pm);\n await spawnAsync(command, args, projectPath);\n}\n\n/**\n * UILint packages that can be updated\n */\nexport const UILINT_PACKAGES = [\n \"uilint\",\n \"uilint-eslint\",\n \"uilint-core\",\n \"uilint-react\",\n] as const;\n\nexport type UilintPackage = (typeof UILINT_PACKAGES)[number];\n\n/**\n * Get installed uilint packages and their versions\n */\nexport function getInstalledUilintPackages(\n projectPath: string\n): Map<UilintPackage, string> {\n const pkgJsonPath = join(projectPath, \"package.json\");\n if (!existsSync(pkgJsonPath)) {\n return new Map();\n }\n\n try {\n const pkgJson = JSON.parse(readFileSync(pkgJsonPath, \"utf-8\")) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n\n const result = new Map<UilintPackage, string>();\n const allDeps = {\n ...pkgJson.dependencies,\n ...pkgJson.devDependencies,\n };\n\n for (const pkg of UILINT_PACKAGES) {\n if (allDeps[pkg]) {\n result.set(pkg, allDeps[pkg]);\n }\n }\n\n return result;\n } catch {\n return new Map();\n }\n}\n\n/**\n * Update packages to their latest versions\n */\nexport async function updatePackages(\n pm: PackageManager,\n projectPath: string,\n packages: string[],\n options: { dev?: boolean } = { dev: true }\n): Promise<void> {\n if (!packages.length) return;\n\n const isDev = options.dev ?? true;\n\n // Use @latest to update to latest version\n const packagesWithLatest = packages.map((pkg) => `${pkg}@latest`);\n\n switch (pm) {\n case \"pnpm\":\n await spawnAsync(\n \"pnpm\",\n [\"add\", ...(isDev ? [\"-D\"] : []), ...packagesWithLatest],\n projectPath\n );\n return;\n case \"yarn\":\n await spawnAsync(\n \"yarn\",\n [\"add\", ...(isDev ? [\"-D\"] : []), ...packagesWithLatest],\n projectPath\n );\n return;\n case \"bun\":\n await spawnAsync(\n \"bun\",\n [\"add\", ...(isDev ? [\"-d\"] : []), ...packagesWithLatest],\n projectPath\n );\n return;\n case \"npm\":\n default:\n await spawnAsync(\n \"npm\",\n [\"install\", isDev ? \"--save-dev\" : \"--save\", ...packagesWithLatest],\n projectPath\n );\n return;\n }\n}\n"],"mappings":"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","names":["atIndex"]}
|
|
@@ -3,109 +3,11 @@ import {
|
|
|
3
3
|
detectPackageManager,
|
|
4
4
|
installDependencies,
|
|
5
5
|
runTestsWithCoverage
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
|
|
8
|
-
// src/utils/prompts.ts
|
|
9
|
-
import * as p from "@clack/prompts";
|
|
10
|
-
import pc from "picocolors";
|
|
11
|
-
import { readFileSync } from "fs";
|
|
12
|
-
import { dirname, join } from "path";
|
|
13
|
-
import { fileURLToPath } from "url";
|
|
14
|
-
function getCLIVersion() {
|
|
15
|
-
try {
|
|
16
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
17
|
-
const pkgPath = join(__dirname, "..", "..", "package.json");
|
|
18
|
-
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
19
|
-
return pkg.version || "0.0.0";
|
|
20
|
-
} catch {
|
|
21
|
-
return "0.0.0";
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
function intro2(title) {
|
|
25
|
-
const version = getCLIVersion();
|
|
26
|
-
const header = pc.bold(pc.cyan("\u25C6 UILint")) + pc.dim(` v${version}`);
|
|
27
|
-
console.log();
|
|
28
|
-
p.intro(title ? `${header} ${pc.dim("\xB7")} ${title}` : header);
|
|
29
|
-
}
|
|
30
|
-
function outro2(message) {
|
|
31
|
-
p.outro(pc.green(message));
|
|
32
|
-
}
|
|
33
|
-
function cancel2(message = "Operation cancelled.") {
|
|
34
|
-
p.cancel(pc.yellow(message));
|
|
35
|
-
process.exit(0);
|
|
36
|
-
}
|
|
37
|
-
function handleCancel(value) {
|
|
38
|
-
if (p.isCancel(value)) {
|
|
39
|
-
cancel2();
|
|
40
|
-
process.exit(0);
|
|
41
|
-
}
|
|
42
|
-
return value;
|
|
43
|
-
}
|
|
44
|
-
async function withSpinner(message, fn) {
|
|
45
|
-
const s = p.spinner();
|
|
46
|
-
s.start(message);
|
|
47
|
-
try {
|
|
48
|
-
const result = fn.length >= 1 ? await fn(s) : await fn();
|
|
49
|
-
s.stop(pc.green("\u2713 ") + message);
|
|
50
|
-
return result;
|
|
51
|
-
} catch (error) {
|
|
52
|
-
s.stop(pc.red("\u2717 ") + message);
|
|
53
|
-
throw error;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
function createSpinner() {
|
|
57
|
-
return p.spinner();
|
|
58
|
-
}
|
|
59
|
-
function note2(message, title) {
|
|
60
|
-
p.note(message, title);
|
|
61
|
-
}
|
|
62
|
-
function log2(message) {
|
|
63
|
-
p.log.message(message);
|
|
64
|
-
}
|
|
65
|
-
function logInfo(message) {
|
|
66
|
-
p.log.info(message);
|
|
67
|
-
}
|
|
68
|
-
function logSuccess(message) {
|
|
69
|
-
p.log.success(message);
|
|
70
|
-
}
|
|
71
|
-
function logWarning(message) {
|
|
72
|
-
p.log.warn(message);
|
|
73
|
-
}
|
|
74
|
-
function logError(message) {
|
|
75
|
-
p.log.error(message);
|
|
76
|
-
}
|
|
77
|
-
async function select2(options) {
|
|
78
|
-
const result = await p.select({
|
|
79
|
-
message: options.message,
|
|
80
|
-
options: options.options,
|
|
81
|
-
initialValue: options.initialValue
|
|
82
|
-
});
|
|
83
|
-
return handleCancel(result);
|
|
84
|
-
}
|
|
85
|
-
async function confirm2(options) {
|
|
86
|
-
const result = await p.confirm({
|
|
87
|
-
message: options.message,
|
|
88
|
-
initialValue: options.initialValue ?? true
|
|
89
|
-
});
|
|
90
|
-
return handleCancel(result);
|
|
91
|
-
}
|
|
92
|
-
async function text2(options) {
|
|
93
|
-
const result = await p.text(options);
|
|
94
|
-
return handleCancel(result);
|
|
95
|
-
}
|
|
96
|
-
async function multiselect2(options) {
|
|
97
|
-
const result = await p.multiselect({
|
|
98
|
-
message: options.message,
|
|
99
|
-
options: options.options,
|
|
100
|
-
required: options.required,
|
|
101
|
-
initialValues: options.initialValues
|
|
102
|
-
});
|
|
103
|
-
return handleCancel(result);
|
|
104
|
-
}
|
|
6
|
+
} from "./chunk-JPE27ROY.js";
|
|
105
7
|
|
|
106
8
|
// src/utils/coverage-detect.ts
|
|
107
|
-
import { existsSync, readFileSync
|
|
108
|
-
import { join
|
|
9
|
+
import { existsSync, readFileSync, statSync } from "fs";
|
|
10
|
+
import { join } from "path";
|
|
109
11
|
var VITEST_CONFIG_FILES = [
|
|
110
12
|
"vitest.config.ts",
|
|
111
13
|
"vitest.config.js",
|
|
@@ -114,9 +16,9 @@ var VITEST_CONFIG_FILES = [
|
|
|
114
16
|
];
|
|
115
17
|
function checkPackageDeps(projectPath) {
|
|
116
18
|
try {
|
|
117
|
-
const pkgPath =
|
|
19
|
+
const pkgPath = join(projectPath, "package.json");
|
|
118
20
|
if (!existsSync(pkgPath)) return { hasVitest: false, hasCoveragePackage: false };
|
|
119
|
-
const pkg = JSON.parse(
|
|
21
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
120
22
|
const deps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
121
23
|
const hasVitest = "vitest" in deps;
|
|
122
24
|
const hasCoveragePackage = "@vitest/coverage-v8" in deps || "@vitest/coverage-istanbul" in deps;
|
|
@@ -127,7 +29,7 @@ function checkPackageDeps(projectPath) {
|
|
|
127
29
|
}
|
|
128
30
|
function findVitestConfig(projectPath) {
|
|
129
31
|
for (const configFile of VITEST_CONFIG_FILES) {
|
|
130
|
-
const configPath =
|
|
32
|
+
const configPath = join(projectPath, configFile);
|
|
131
33
|
if (existsSync(configPath)) {
|
|
132
34
|
return configPath;
|
|
133
35
|
}
|
|
@@ -136,7 +38,7 @@ function findVitestConfig(projectPath) {
|
|
|
136
38
|
}
|
|
137
39
|
function parseCoverageConfig(configPath) {
|
|
138
40
|
try {
|
|
139
|
-
const content =
|
|
41
|
+
const content = readFileSync(configPath, "utf-8");
|
|
140
42
|
const hasCoverageConfig = /coverage\s*:\s*\{/.test(content);
|
|
141
43
|
if (!hasCoverageConfig) {
|
|
142
44
|
return { hasCoverageConfig: false, coverageProvider: null };
|
|
@@ -149,7 +51,7 @@ function parseCoverageConfig(configPath) {
|
|
|
149
51
|
}
|
|
150
52
|
}
|
|
151
53
|
function findCoverageData(projectPath) {
|
|
152
|
-
const coverageDataPath =
|
|
54
|
+
const coverageDataPath = join(projectPath, "coverage", "coverage-final.json");
|
|
153
55
|
if (existsSync(coverageDataPath)) {
|
|
154
56
|
try {
|
|
155
57
|
const stats = statSync(coverageDataPath);
|
|
@@ -192,36 +94,36 @@ function detectCoverageSetup(projectPath) {
|
|
|
192
94
|
|
|
193
95
|
// src/utils/next-detect.ts
|
|
194
96
|
import { existsSync as existsSync2, readdirSync } from "fs";
|
|
195
|
-
import { join as
|
|
97
|
+
import { join as join2 } from "path";
|
|
196
98
|
function fileExists(projectPath, relPath) {
|
|
197
|
-
return existsSync2(
|
|
99
|
+
return existsSync2(join2(projectPath, relPath));
|
|
198
100
|
}
|
|
199
101
|
function detectNextAppRouter(projectPath) {
|
|
200
|
-
const roots = ["app",
|
|
102
|
+
const roots = ["app", join2("src", "app")];
|
|
201
103
|
const candidates = [];
|
|
202
104
|
let chosenRoot = null;
|
|
203
105
|
for (const root of roots) {
|
|
204
|
-
if (existsSync2(
|
|
106
|
+
if (existsSync2(join2(projectPath, root))) {
|
|
205
107
|
chosenRoot = root;
|
|
206
108
|
break;
|
|
207
109
|
}
|
|
208
110
|
}
|
|
209
111
|
if (!chosenRoot) return null;
|
|
210
112
|
const entryCandidates = [
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
113
|
+
join2(chosenRoot, "layout.tsx"),
|
|
114
|
+
join2(chosenRoot, "layout.jsx"),
|
|
115
|
+
join2(chosenRoot, "layout.ts"),
|
|
116
|
+
join2(chosenRoot, "layout.js"),
|
|
215
117
|
// Fallbacks (less ideal, but can work):
|
|
216
|
-
|
|
217
|
-
|
|
118
|
+
join2(chosenRoot, "page.tsx"),
|
|
119
|
+
join2(chosenRoot, "page.jsx")
|
|
218
120
|
];
|
|
219
121
|
for (const rel of entryCandidates) {
|
|
220
122
|
if (fileExists(projectPath, rel)) candidates.push(rel);
|
|
221
123
|
}
|
|
222
124
|
return {
|
|
223
125
|
appRoot: chosenRoot,
|
|
224
|
-
appRootAbs:
|
|
126
|
+
appRootAbs: join2(projectPath, chosenRoot),
|
|
225
127
|
candidates
|
|
226
128
|
};
|
|
227
129
|
}
|
|
@@ -265,7 +167,7 @@ function findNextAppRouterProjects(rootDir, options) {
|
|
|
265
167
|
if (!ent.isDirectory) continue;
|
|
266
168
|
if (ignoreDirs.has(ent.name)) continue;
|
|
267
169
|
if (ent.name.startsWith(".") && ent.name !== ".") continue;
|
|
268
|
-
walk(
|
|
170
|
+
walk(join2(dir, ent.name), depth + 1);
|
|
269
171
|
}
|
|
270
172
|
}
|
|
271
173
|
walk(rootDir, 0);
|
|
@@ -273,14 +175,14 @@ function findNextAppRouterProjects(rootDir, options) {
|
|
|
273
175
|
}
|
|
274
176
|
|
|
275
177
|
// src/utils/eslint-config-inject.ts
|
|
276
|
-
import { existsSync as existsSync3, readFileSync as
|
|
277
|
-
import { join as
|
|
178
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
179
|
+
import { join as join3, relative, dirname } from "path";
|
|
278
180
|
import { parseExpression, parseModule, generateCode } from "magicast";
|
|
279
181
|
import { findWorkspaceRoot } from "uilint-core/node";
|
|
280
182
|
var CONFIG_EXTENSIONS = [".ts", ".mjs", ".js", ".cjs"];
|
|
281
183
|
function findEslintConfigFile(projectPath) {
|
|
282
184
|
for (const ext of CONFIG_EXTENSIONS) {
|
|
283
|
-
const configPath =
|
|
185
|
+
const configPath = join3(projectPath, `eslint.config${ext}`);
|
|
284
186
|
if (existsSync3(configPath)) {
|
|
285
187
|
return configPath;
|
|
286
188
|
}
|
|
@@ -312,7 +214,7 @@ function getObjectPropertyValue(obj, keyName) {
|
|
|
312
214
|
function hasSpreadProperties(obj) {
|
|
313
215
|
if (!obj || obj.type !== "ObjectExpression") return false;
|
|
314
216
|
return (obj.properties ?? []).some(
|
|
315
|
-
(
|
|
217
|
+
(p) => p && (p.type === "SpreadElement" || p.type === "SpreadProperty")
|
|
316
218
|
);
|
|
317
219
|
}
|
|
318
220
|
var IGNORED_AST_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -530,8 +432,8 @@ function findExistingDefaultImportLocalName(program, from) {
|
|
|
530
432
|
function addLocalRuleImportsAst(mod, selectedRules, configPath, rulesRoot, fileExtension = ".js", isTypeScriptProject = false) {
|
|
531
433
|
const importNames = /* @__PURE__ */ new Map();
|
|
532
434
|
let changed = false;
|
|
533
|
-
const configDir =
|
|
534
|
-
const rulesDir =
|
|
435
|
+
const configDir = dirname(configPath);
|
|
436
|
+
const rulesDir = join3(rulesRoot, ".uilint", "rules");
|
|
535
437
|
const relativeRulesPath = relative(configDir, rulesDir).replace(/\\/g, "/");
|
|
536
438
|
const normalizedRulesPath = relativeRulesPath.startsWith("./") || relativeRulesPath.startsWith("../") ? relativeRulesPath : `./${relativeRulesPath}`;
|
|
537
439
|
const used = collectTopLevelBindings(mod.$ast);
|
|
@@ -564,8 +466,8 @@ function addLocalRuleRequiresAst(program, selectedRules, configPath, rulesRoot,
|
|
|
564
466
|
if (!program || program.type !== "Program") {
|
|
565
467
|
return { importNames, changed };
|
|
566
468
|
}
|
|
567
|
-
const configDir =
|
|
568
|
-
const rulesDir =
|
|
469
|
+
const configDir = dirname(configPath);
|
|
470
|
+
const rulesDir = join3(rulesRoot, ".uilint", "rules");
|
|
569
471
|
const relativeRulesPath = relative(configDir, rulesDir).replace(/\\/g, "/");
|
|
570
472
|
const normalizedRulesPath = relativeRulesPath.startsWith("./") || relativeRulesPath.startsWith("../") ? relativeRulesPath : `./${relativeRulesPath}`;
|
|
571
473
|
const used = collectTopLevelBindings(program);
|
|
@@ -629,7 +531,7 @@ function updateExistingUilintConfigBlock(configObj, selectedRules, ruleImportNam
|
|
|
629
531
|
const rulesObj = getObjectPropertyValue(configObj, "rules");
|
|
630
532
|
if (pluginsObj?.type === "ObjectExpression") {
|
|
631
533
|
const uilintPluginProp = pluginsObj.properties?.find(
|
|
632
|
-
(
|
|
534
|
+
(p) => (p.type === "ObjectProperty" || p.type === "Property") && (p.key?.type === "Identifier" && p.key.name === "uilint" || isStringLiteral(p.key) && p.key.value === "uilint")
|
|
633
535
|
);
|
|
634
536
|
if (uilintPluginProp) {
|
|
635
537
|
const uilintValue = uilintPluginProp.value;
|
|
@@ -648,7 +550,7 @@ function updateExistingUilintConfigBlock(configObj, selectedRules, ruleImportNam
|
|
|
648
550
|
}
|
|
649
551
|
for (const [ruleId, importName] of ruleImportNames.entries()) {
|
|
650
552
|
const exists = pluginRulesObj.properties?.some(
|
|
651
|
-
(
|
|
553
|
+
(p) => (p.type === "ObjectProperty" || p.type === "Property") && isStringLiteral(p.key) && p.key.value === ruleId
|
|
652
554
|
);
|
|
653
555
|
if (!exists) {
|
|
654
556
|
const propCode = `{ "${ruleId}": ${importName} }`;
|
|
@@ -668,7 +570,7 @@ function updateExistingUilintConfigBlock(configObj, selectedRules, ruleImportNam
|
|
|
668
570
|
2
|
|
669
571
|
)}]` : `"${rule.defaultSeverity}"`;
|
|
670
572
|
const existingPropIndex = rulesObj.properties?.findIndex(
|
|
671
|
-
(
|
|
573
|
+
(p) => (p.type === "ObjectProperty" || p.type === "Property") && isStringLiteral(p.key) && p.key.value === ruleKey
|
|
672
574
|
);
|
|
673
575
|
const propCode = `{ "${ruleKey}": ${valueCode} }`;
|
|
674
576
|
const tempObj = parseExpression(propCode).$ast;
|
|
@@ -782,7 +684,7 @@ async function installEslintPlugin(opts) {
|
|
|
782
684
|
};
|
|
783
685
|
}
|
|
784
686
|
const configFilename = getEslintConfigFilename(configPath);
|
|
785
|
-
const original =
|
|
687
|
+
const original = readFileSync2(configPath, "utf-8");
|
|
786
688
|
const isCommonJS = configPath.endsWith(".cjs");
|
|
787
689
|
const ast = getUilintEslintConfigInfoFromSourceAst(original);
|
|
788
690
|
if ("error" in ast) {
|
|
@@ -834,9 +736,9 @@ async function installEslintPlugin(opts) {
|
|
|
834
736
|
};
|
|
835
737
|
}
|
|
836
738
|
let modifiedAst = false;
|
|
837
|
-
const localRulesDir =
|
|
739
|
+
const localRulesDir = join3(opts.projectPath, ".uilint", "rules");
|
|
838
740
|
const workspaceRoot = findWorkspaceRoot(opts.projectPath);
|
|
839
|
-
const workspaceRulesDir =
|
|
741
|
+
const workspaceRulesDir = join3(workspaceRoot, ".uilint", "rules");
|
|
840
742
|
const rulesRoot = existsSync3(localRulesDir) ? opts.projectPath : workspaceRoot;
|
|
841
743
|
const isTypeScriptConfig = configPath.endsWith(".ts");
|
|
842
744
|
let fileExtension = isTypeScriptConfig ? "" : ".js";
|
|
@@ -928,7 +830,7 @@ async function uninstallEslintPlugin(options) {
|
|
|
928
830
|
};
|
|
929
831
|
}
|
|
930
832
|
try {
|
|
931
|
-
const original =
|
|
833
|
+
const original = readFileSync2(configPath, "utf-8");
|
|
932
834
|
let updated = original.replace(
|
|
933
835
|
/^import\s+\{[^}]*\}\s+from\s+["'][^"']*\.uilint\/rules[^"']*["'];?\s*$/gm,
|
|
934
836
|
""
|
|
@@ -1042,7 +944,7 @@ function extractOptionsFromValueNode(valueNode) {
|
|
|
1042
944
|
function readRuleConfigsFromConfig(configPath) {
|
|
1043
945
|
const configs = /* @__PURE__ */ new Map();
|
|
1044
946
|
try {
|
|
1045
|
-
const source =
|
|
947
|
+
const source = readFileSync2(configPath, "utf-8");
|
|
1046
948
|
const mod = parseModule(source);
|
|
1047
949
|
const found = findExportedConfigArrayExpression(mod);
|
|
1048
950
|
if (!found) {
|
|
@@ -1083,7 +985,7 @@ function findRulePropertyInConfigArray(arrayExpr, ruleId) {
|
|
|
1083
985
|
}
|
|
1084
986
|
function updateRuleSeverityInConfig(configPath, ruleId, severity) {
|
|
1085
987
|
try {
|
|
1086
|
-
const source =
|
|
988
|
+
const source = readFileSync2(configPath, "utf-8");
|
|
1087
989
|
const mod = parseModule(source);
|
|
1088
990
|
const found = findExportedConfigArrayExpression(mod);
|
|
1089
991
|
if (!found) {
|
|
@@ -1134,7 +1036,7 @@ function updateRuleSeverityInConfig(configPath, ruleId, severity) {
|
|
|
1134
1036
|
}
|
|
1135
1037
|
function updateRuleConfigInConfig(configPath, ruleId, severity, options) {
|
|
1136
1038
|
try {
|
|
1137
|
-
const source =
|
|
1039
|
+
const source = readFileSync2(configPath, "utf-8");
|
|
1138
1040
|
const mod = parseModule(source);
|
|
1139
1041
|
const found = findExportedConfigArrayExpression(mod);
|
|
1140
1042
|
if (!found) {
|
|
@@ -1168,10 +1070,10 @@ function updateRuleConfigInConfig(configPath, ruleId, severity, options) {
|
|
|
1168
1070
|
}
|
|
1169
1071
|
|
|
1170
1072
|
// src/utils/coverage-prepare.ts
|
|
1171
|
-
import { readFileSync as
|
|
1073
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
1172
1074
|
function injectCoverageConfig(vitestConfigPath) {
|
|
1173
1075
|
try {
|
|
1174
|
-
const content =
|
|
1076
|
+
const content = readFileSync3(vitestConfigPath, "utf-8");
|
|
1175
1077
|
if (/coverage\s*:\s*\{/.test(content)) {
|
|
1176
1078
|
return false;
|
|
1177
1079
|
}
|
|
@@ -1266,21 +1168,6 @@ function needsCoveragePreparation(setup) {
|
|
|
1266
1168
|
}
|
|
1267
1169
|
|
|
1268
1170
|
export {
|
|
1269
|
-
pc,
|
|
1270
|
-
intro2 as intro,
|
|
1271
|
-
outro2 as outro,
|
|
1272
|
-
withSpinner,
|
|
1273
|
-
createSpinner,
|
|
1274
|
-
note2 as note,
|
|
1275
|
-
log2 as log,
|
|
1276
|
-
logInfo,
|
|
1277
|
-
logSuccess,
|
|
1278
|
-
logWarning,
|
|
1279
|
-
logError,
|
|
1280
|
-
select2 as select,
|
|
1281
|
-
confirm2 as confirm,
|
|
1282
|
-
text2 as text,
|
|
1283
|
-
multiselect2 as multiselect,
|
|
1284
1171
|
detectNextAppRouter,
|
|
1285
1172
|
findNextAppRouterProjects,
|
|
1286
1173
|
findEslintConfigFile,
|
|
@@ -1296,4 +1183,4 @@ export {
|
|
|
1296
1183
|
prepareCoverage,
|
|
1297
1184
|
needsCoveragePreparation
|
|
1298
1185
|
};
|
|
1299
|
-
//# sourceMappingURL=chunk-
|
|
1186
|
+
//# sourceMappingURL=chunk-KNZVCCXM.js.map
|