@betterstart/cli 0.1.25 → 0.1.26
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/cli.js +418 -30
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-SAPJG4NO.js";
|
|
5
5
|
|
|
6
6
|
// src/cli.ts
|
|
7
|
-
import { Command as
|
|
7
|
+
import { Command as Command8 } from "commander";
|
|
8
8
|
|
|
9
9
|
// src/commands/generate.ts
|
|
10
10
|
import path22 from "path";
|
|
@@ -901,8 +901,8 @@ function toPascalCase3(str) {
|
|
|
901
901
|
return str.split(/[-_\s]+/).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join("");
|
|
902
902
|
}
|
|
903
903
|
function toCamelCase(str) {
|
|
904
|
-
const
|
|
905
|
-
return
|
|
904
|
+
const p6 = toPascalCase3(str);
|
|
905
|
+
return p6.charAt(0).toLowerCase() + p6.slice(1);
|
|
906
906
|
}
|
|
907
907
|
function toKebabCase(str) {
|
|
908
908
|
return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
|
|
@@ -993,7 +993,7 @@ function generateFormAdminPages(schema, cwd, pagesDir, options) {
|
|
|
993
993
|
const adminDir = path4.join(cwd, pagesDir, "forms", kebab);
|
|
994
994
|
if (!fs4.existsSync(adminDir)) fs4.mkdirSync(adminDir, { recursive: true });
|
|
995
995
|
const files = [];
|
|
996
|
-
const rel = (
|
|
996
|
+
const rel = (p6) => path4.relative(cwd, p6);
|
|
997
997
|
const pagePath = path4.join(adminDir, "page.tsx");
|
|
998
998
|
if (!fs4.existsSync(pagePath) || options.force) {
|
|
999
999
|
fs4.writeFileSync(pagePath, generatePage(pascal, kebab), "utf-8");
|
|
@@ -1981,8 +1981,8 @@ function toPascalCase4(str) {
|
|
|
1981
1981
|
return str.split(/[-_\s]+/).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join("");
|
|
1982
1982
|
}
|
|
1983
1983
|
function toCamelCase2(str) {
|
|
1984
|
-
const
|
|
1985
|
-
return
|
|
1984
|
+
const p6 = toPascalCase4(str);
|
|
1985
|
+
return p6.charAt(0).toLowerCase() + p6.slice(1);
|
|
1986
1986
|
}
|
|
1987
1987
|
function toKebabCase3(str) {
|
|
1988
1988
|
return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
|
|
@@ -2697,8 +2697,8 @@ function toPascalCase5(str) {
|
|
|
2697
2697
|
return str.split(/[-_\s]+/).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join("");
|
|
2698
2698
|
}
|
|
2699
2699
|
function toCamelCase3(str) {
|
|
2700
|
-
const
|
|
2701
|
-
return
|
|
2700
|
+
const p6 = toPascalCase5(str);
|
|
2701
|
+
return p6.charAt(0).toLowerCase() + p6.slice(1);
|
|
2702
2702
|
}
|
|
2703
2703
|
function singularize2(str) {
|
|
2704
2704
|
if (str.endsWith("ies")) return `${str.slice(0, -3)}y`;
|
|
@@ -2758,11 +2758,11 @@ function generateActions(schema, cwd, actionsDir, options = {}) {
|
|
|
2758
2758
|
const listFieldsWithRels = findListFieldsWithRelationships(dbFields);
|
|
2759
2759
|
const hasListRels = listFieldsWithRels.length > 0;
|
|
2760
2760
|
const allListRelQueries = [];
|
|
2761
|
-
for (const { field: listField, path:
|
|
2761
|
+
for (const { field: listField, path: path42 } of listFieldsWithRels) {
|
|
2762
2762
|
const rels = (listField.fields || []).filter((f) => f.type === "relationship" && f.relationship);
|
|
2763
2763
|
for (const relField of rels) {
|
|
2764
2764
|
allListRelQueries.push({
|
|
2765
|
-
fieldPath:
|
|
2765
|
+
fieldPath: path42.join("_"),
|
|
2766
2766
|
relField,
|
|
2767
2767
|
relTable: toCamelCase3(relField.relationship),
|
|
2768
2768
|
listFieldName: listField.name
|
|
@@ -3421,8 +3421,8 @@ function toPascalCase6(str) {
|
|
|
3421
3421
|
return str.split(/[-_\s]+/).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join("");
|
|
3422
3422
|
}
|
|
3423
3423
|
function toCamelCase4(str) {
|
|
3424
|
-
const
|
|
3425
|
-
return
|
|
3424
|
+
const p6 = toPascalCase6(str);
|
|
3425
|
+
return p6.charAt(0).toLowerCase() + p6.slice(1);
|
|
3426
3426
|
}
|
|
3427
3427
|
function singularize3(str) {
|
|
3428
3428
|
if (str.endsWith("ies")) return `${str.slice(0, -3)}y`;
|
|
@@ -4564,8 +4564,8 @@ function toPascalCase9(str) {
|
|
|
4564
4564
|
return str.split(/[-_\s]+/).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join("");
|
|
4565
4565
|
}
|
|
4566
4566
|
function toCamelCase5(str) {
|
|
4567
|
-
const
|
|
4568
|
-
return
|
|
4567
|
+
const p6 = toPascalCase9(str);
|
|
4568
|
+
return p6.charAt(0).toLowerCase() + p6.slice(1);
|
|
4569
4569
|
}
|
|
4570
4570
|
function singularize6(str) {
|
|
4571
4571
|
if (str.endsWith("ies")) return `${str.slice(0, -3)}y`;
|
|
@@ -4813,8 +4813,8 @@ function toPascalCase10(str) {
|
|
|
4813
4813
|
return str.split(/[-_\s]+/).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join("");
|
|
4814
4814
|
}
|
|
4815
4815
|
function toCamelCase6(str) {
|
|
4816
|
-
const
|
|
4817
|
-
return
|
|
4816
|
+
const p6 = toPascalCase10(str);
|
|
4817
|
+
return p6.charAt(0).toLowerCase() + p6.slice(1);
|
|
4818
4818
|
}
|
|
4819
4819
|
function singularize7(str) {
|
|
4820
4820
|
if (str.endsWith("ies")) return `${str.slice(0, -3)}y`;
|
|
@@ -7045,8 +7045,8 @@ function toPascalCase16(str) {
|
|
|
7045
7045
|
return str.split(/[-_\s]+/).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join("");
|
|
7046
7046
|
}
|
|
7047
7047
|
function toCamelCase7(str) {
|
|
7048
|
-
const
|
|
7049
|
-
return
|
|
7048
|
+
const p6 = toPascalCase16(str);
|
|
7049
|
+
return p6.charAt(0).toLowerCase() + p6.slice(1);
|
|
7050
7050
|
}
|
|
7051
7051
|
function singularize12(str) {
|
|
7052
7052
|
if (str.endsWith("ies")) return `${str.slice(0, -3)}y`;
|
|
@@ -7640,6 +7640,9 @@ function detectPackageManager(cwd) {
|
|
|
7640
7640
|
}
|
|
7641
7641
|
return "npm";
|
|
7642
7642
|
}
|
|
7643
|
+
function installCommand(pm) {
|
|
7644
|
+
return pm === "yarn" ? "yarn" : `${pm} install`;
|
|
7645
|
+
}
|
|
7643
7646
|
function runCommand(pm, script) {
|
|
7644
7647
|
switch (pm) {
|
|
7645
7648
|
case "pnpm":
|
|
@@ -14097,8 +14100,8 @@ function toPascalCase17(str) {
|
|
|
14097
14100
|
return str.split(/[-_\s]+/).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join("");
|
|
14098
14101
|
}
|
|
14099
14102
|
function toCamelCase8(str) {
|
|
14100
|
-
const
|
|
14101
|
-
return
|
|
14103
|
+
const p6 = toPascalCase17(str);
|
|
14104
|
+
return p6.charAt(0).toLowerCase() + p6.slice(1);
|
|
14102
14105
|
}
|
|
14103
14106
|
function singularize13(str) {
|
|
14104
14107
|
if (str.endsWith("ies")) return `${str.slice(0, -3)}y`;
|
|
@@ -14339,33 +14342,418 @@ var updateDepsCommand = new Command5("update-deps").description("Install or upda
|
|
|
14339
14342
|
clack2.outro("Dependencies updated");
|
|
14340
14343
|
});
|
|
14341
14344
|
|
|
14342
|
-
// src/commands/
|
|
14343
|
-
import
|
|
14345
|
+
// src/commands/uninstall.ts
|
|
14346
|
+
import fs35 from "fs";
|
|
14344
14347
|
import path40 from "path";
|
|
14345
|
-
import * as
|
|
14348
|
+
import * as p5 from "@clack/prompts";
|
|
14349
|
+
import pc3 from "picocolors";
|
|
14346
14350
|
import { Command as Command6 } from "commander";
|
|
14347
|
-
|
|
14351
|
+
|
|
14352
|
+
// src/commands/uninstall-cleaners.ts
|
|
14353
|
+
import fs34 from "fs";
|
|
14354
|
+
function stripJsonComments2(input) {
|
|
14355
|
+
let result = "";
|
|
14356
|
+
let i = 0;
|
|
14357
|
+
while (i < input.length) {
|
|
14358
|
+
if (input[i] === '"') {
|
|
14359
|
+
let j = i + 1;
|
|
14360
|
+
while (j < input.length) {
|
|
14361
|
+
if (input[j] === "\\") {
|
|
14362
|
+
j += 2;
|
|
14363
|
+
continue;
|
|
14364
|
+
}
|
|
14365
|
+
if (input[j] === '"') {
|
|
14366
|
+
j++;
|
|
14367
|
+
break;
|
|
14368
|
+
}
|
|
14369
|
+
j++;
|
|
14370
|
+
}
|
|
14371
|
+
result += input.slice(i, j);
|
|
14372
|
+
i = j;
|
|
14373
|
+
} else if (input[i] === "/" && input[i + 1] === "/") {
|
|
14374
|
+
const nl = input.indexOf("\n", i);
|
|
14375
|
+
i = nl === -1 ? input.length : nl;
|
|
14376
|
+
} else if (input[i] === "/" && input[i + 1] === "*") {
|
|
14377
|
+
const end = input.indexOf("*/", i + 2);
|
|
14378
|
+
i = end === -1 ? input.length : end + 2;
|
|
14379
|
+
} else {
|
|
14380
|
+
result += input[i];
|
|
14381
|
+
i++;
|
|
14382
|
+
}
|
|
14383
|
+
}
|
|
14384
|
+
return result;
|
|
14385
|
+
}
|
|
14386
|
+
function cleanTsconfig(tsconfigPath) {
|
|
14387
|
+
if (!fs34.existsSync(tsconfigPath)) return [];
|
|
14388
|
+
const raw = fs34.readFileSync(tsconfigPath, "utf-8");
|
|
14389
|
+
const stripped = stripJsonComments2(raw).replace(/,\s*([\]}])/g, "$1");
|
|
14390
|
+
let tsconfig;
|
|
14391
|
+
try {
|
|
14392
|
+
tsconfig = JSON.parse(stripped);
|
|
14393
|
+
} catch {
|
|
14394
|
+
return [];
|
|
14395
|
+
}
|
|
14396
|
+
const compilerOptions = tsconfig.compilerOptions ?? {};
|
|
14397
|
+
const paths = compilerOptions.paths ?? {};
|
|
14398
|
+
const removed = [];
|
|
14399
|
+
for (const key of Object.keys(paths)) {
|
|
14400
|
+
if (key.startsWith("@cms/") || key === "@cms/*") {
|
|
14401
|
+
removed.push(key);
|
|
14402
|
+
delete paths[key];
|
|
14403
|
+
}
|
|
14404
|
+
}
|
|
14405
|
+
if (removed.length === 0) return [];
|
|
14406
|
+
if (Object.keys(paths).length === 0) {
|
|
14407
|
+
delete compilerOptions.paths;
|
|
14408
|
+
} else {
|
|
14409
|
+
compilerOptions.paths = paths;
|
|
14410
|
+
}
|
|
14411
|
+
tsconfig.compilerOptions = compilerOptions;
|
|
14412
|
+
fs34.writeFileSync(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
|
|
14413
|
+
`, "utf-8");
|
|
14414
|
+
return removed;
|
|
14415
|
+
}
|
|
14416
|
+
function cleanCss(cssPath) {
|
|
14417
|
+
if (!fs34.existsSync(cssPath)) return [];
|
|
14418
|
+
const content = fs34.readFileSync(cssPath, "utf-8");
|
|
14419
|
+
const lines = content.split("\n");
|
|
14420
|
+
const sourcePattern = /^@source\s+"[^"]*cms[^"]*";\s*$/;
|
|
14421
|
+
const removed = [];
|
|
14422
|
+
const kept = [];
|
|
14423
|
+
for (const line of lines) {
|
|
14424
|
+
if (sourcePattern.test(line)) {
|
|
14425
|
+
removed.push(line.trim());
|
|
14426
|
+
} else {
|
|
14427
|
+
kept.push(line);
|
|
14428
|
+
}
|
|
14429
|
+
}
|
|
14430
|
+
if (removed.length === 0) return [];
|
|
14431
|
+
const cleaned = kept.join("\n").replace(/\n{3,}/g, "\n\n");
|
|
14432
|
+
fs34.writeFileSync(cssPath, cleaned, "utf-8");
|
|
14433
|
+
return removed;
|
|
14434
|
+
}
|
|
14435
|
+
function cleanEnvFile(envPath) {
|
|
14436
|
+
if (!fs34.existsSync(envPath)) return [];
|
|
14437
|
+
const content = fs34.readFileSync(envPath, "utf-8");
|
|
14438
|
+
const lines = content.split("\n");
|
|
14439
|
+
const removed = [];
|
|
14440
|
+
const kept = [];
|
|
14441
|
+
const headerPattern = /^# =+$/;
|
|
14442
|
+
const headerTextPattern = /^# BetterStart CMS$/;
|
|
14443
|
+
for (let i = 0; i < lines.length; i++) {
|
|
14444
|
+
const line = lines[i];
|
|
14445
|
+
const trimmed = line.trim();
|
|
14446
|
+
if (trimmed.match(/^BETTERSTART_\w+=/)) {
|
|
14447
|
+
const key = trimmed.split("=")[0];
|
|
14448
|
+
removed.push(key);
|
|
14449
|
+
continue;
|
|
14450
|
+
}
|
|
14451
|
+
if (headerPattern.test(trimmed)) {
|
|
14452
|
+
const next = lines[i + 1]?.trim();
|
|
14453
|
+
const afterNext = lines[i + 2]?.trim();
|
|
14454
|
+
if (next && headerTextPattern.test(next) && afterNext && headerPattern.test(afterNext)) {
|
|
14455
|
+
i += 2;
|
|
14456
|
+
continue;
|
|
14457
|
+
}
|
|
14458
|
+
}
|
|
14459
|
+
if (trimmed.startsWith("#") && !headerPattern.test(trimmed)) {
|
|
14460
|
+
const nextNonEmpty = findNextNonEmptyLine(lines, i + 1);
|
|
14461
|
+
if (nextNonEmpty !== null && nextNonEmpty.match(/^BETTERSTART_\w+=/)) {
|
|
14462
|
+
continue;
|
|
14463
|
+
}
|
|
14464
|
+
}
|
|
14465
|
+
kept.push(line);
|
|
14466
|
+
}
|
|
14467
|
+
if (removed.length === 0) return [];
|
|
14468
|
+
let result = kept.join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
14469
|
+
if (result === "") {
|
|
14470
|
+
fs34.unlinkSync(envPath);
|
|
14471
|
+
} else {
|
|
14472
|
+
fs34.writeFileSync(envPath, `${result}
|
|
14473
|
+
`, "utf-8");
|
|
14474
|
+
}
|
|
14475
|
+
return removed;
|
|
14476
|
+
}
|
|
14477
|
+
function findNextNonEmptyLine(lines, startIndex) {
|
|
14478
|
+
for (let i = startIndex; i < lines.length; i++) {
|
|
14479
|
+
const trimmed = lines[i].trim();
|
|
14480
|
+
if (trimmed !== "") return trimmed;
|
|
14481
|
+
}
|
|
14482
|
+
return null;
|
|
14483
|
+
}
|
|
14484
|
+
function cleanPackageJsonDeps(pkgPath, allDeps, allDevDeps) {
|
|
14485
|
+
if (!fs34.existsSync(pkgPath)) return { removed: [], removedDev: [] };
|
|
14486
|
+
const content = fs34.readFileSync(pkgPath, "utf-8");
|
|
14487
|
+
let pkg;
|
|
14488
|
+
try {
|
|
14489
|
+
pkg = JSON.parse(content);
|
|
14490
|
+
} catch {
|
|
14491
|
+
return { removed: [], removedDev: [] };
|
|
14492
|
+
}
|
|
14493
|
+
const deps = pkg.dependencies ?? {};
|
|
14494
|
+
const devDeps = pkg.devDependencies ?? {};
|
|
14495
|
+
const depNames = new Set(allDeps.map((d) => d.split("@").slice(0, d.startsWith("@") ? 2 : 1).join("@")));
|
|
14496
|
+
const devDepNames = new Set(
|
|
14497
|
+
allDevDeps.map((d) => d.split("@").slice(0, d.startsWith("@") ? 2 : 1).join("@"))
|
|
14498
|
+
);
|
|
14499
|
+
const removed = [];
|
|
14500
|
+
for (const name of Object.keys(deps)) {
|
|
14501
|
+
if (depNames.has(name)) {
|
|
14502
|
+
delete deps[name];
|
|
14503
|
+
removed.push(name);
|
|
14504
|
+
}
|
|
14505
|
+
}
|
|
14506
|
+
const removedDev = [];
|
|
14507
|
+
for (const name of Object.keys(devDeps)) {
|
|
14508
|
+
if (devDepNames.has(name)) {
|
|
14509
|
+
delete devDeps[name];
|
|
14510
|
+
removedDev.push(name);
|
|
14511
|
+
}
|
|
14512
|
+
}
|
|
14513
|
+
if (removed.length === 0 && removedDev.length === 0) {
|
|
14514
|
+
return { removed: [], removedDev: [] };
|
|
14515
|
+
}
|
|
14516
|
+
pkg.dependencies = deps;
|
|
14517
|
+
pkg.devDependencies = devDeps;
|
|
14518
|
+
fs34.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
14519
|
+
`, "utf-8");
|
|
14520
|
+
return { removed, removedDev };
|
|
14521
|
+
}
|
|
14522
|
+
|
|
14523
|
+
// src/commands/uninstall.ts
|
|
14524
|
+
function findMainCss2(cwd) {
|
|
14525
|
+
const candidates = [
|
|
14526
|
+
"src/app/globals.css",
|
|
14527
|
+
"app/globals.css",
|
|
14528
|
+
"src/app/global.css",
|
|
14529
|
+
"app/global.css",
|
|
14530
|
+
"src/app/app.css",
|
|
14531
|
+
"app/app.css",
|
|
14532
|
+
"src/globals.css",
|
|
14533
|
+
"globals.css"
|
|
14534
|
+
];
|
|
14535
|
+
for (const candidate of candidates) {
|
|
14536
|
+
const filePath = path40.join(cwd, candidate);
|
|
14537
|
+
if (fs35.existsSync(filePath)) return filePath;
|
|
14538
|
+
}
|
|
14539
|
+
return void 0;
|
|
14540
|
+
}
|
|
14541
|
+
function isCLICreatedBiome(biomePath) {
|
|
14542
|
+
if (!fs35.existsSync(biomePath)) return false;
|
|
14543
|
+
try {
|
|
14544
|
+
const content = JSON.parse(fs35.readFileSync(biomePath, "utf-8"));
|
|
14545
|
+
return content.$schema?.includes("biomejs.dev") && content.formatter?.indentStyle === "space" && content.javascript?.formatter?.quoteStyle === "single" && Array.isArray(content.files?.ignore) && content.files.ignore.includes(".next");
|
|
14546
|
+
} catch {
|
|
14547
|
+
return false;
|
|
14548
|
+
}
|
|
14549
|
+
}
|
|
14550
|
+
function buildUninstallPlan(cwd) {
|
|
14551
|
+
const steps = [];
|
|
14552
|
+
const hasSrc = fs35.existsSync(path40.join(cwd, "src"));
|
|
14553
|
+
const appBase = hasSrc ? "src/app" : "app";
|
|
14554
|
+
const dirs = [];
|
|
14555
|
+
const cmsDir = path40.join(cwd, "cms");
|
|
14556
|
+
const cmsRouteGroup = path40.join(cwd, appBase, "(cms)");
|
|
14557
|
+
if (fs35.existsSync(cmsDir)) dirs.push("cms/");
|
|
14558
|
+
if (fs35.existsSync(cmsRouteGroup)) dirs.push(`${appBase}/(cms)/`);
|
|
14559
|
+
if (dirs.length > 0) {
|
|
14560
|
+
steps.push({
|
|
14561
|
+
label: "CMS directories",
|
|
14562
|
+
items: dirs,
|
|
14563
|
+
execute() {
|
|
14564
|
+
if (fs35.existsSync(cmsDir)) fs35.rmSync(cmsDir, { recursive: true, force: true });
|
|
14565
|
+
if (fs35.existsSync(cmsRouteGroup)) fs35.rmSync(cmsRouteGroup, { recursive: true, force: true });
|
|
14566
|
+
}
|
|
14567
|
+
});
|
|
14568
|
+
}
|
|
14569
|
+
const configFiles = [];
|
|
14570
|
+
const configPaths = [];
|
|
14571
|
+
const candidates = [
|
|
14572
|
+
["cms.config.ts", path40.join(cwd, "cms.config.ts")],
|
|
14573
|
+
["drizzle.config.ts", path40.join(cwd, "drizzle.config.ts")],
|
|
14574
|
+
["CMS.md", path40.join(cwd, "CMS.md")]
|
|
14575
|
+
];
|
|
14576
|
+
for (const [label, fullPath] of candidates) {
|
|
14577
|
+
if (fs35.existsSync(fullPath)) {
|
|
14578
|
+
configFiles.push(label);
|
|
14579
|
+
configPaths.push(fullPath);
|
|
14580
|
+
}
|
|
14581
|
+
}
|
|
14582
|
+
const biomePath = path40.join(cwd, "biome.json");
|
|
14583
|
+
if (isCLICreatedBiome(biomePath)) {
|
|
14584
|
+
configFiles.push("biome.json (CLI-created)");
|
|
14585
|
+
configPaths.push(biomePath);
|
|
14586
|
+
}
|
|
14587
|
+
if (configFiles.length > 0) {
|
|
14588
|
+
steps.push({
|
|
14589
|
+
label: "Config files",
|
|
14590
|
+
items: configFiles,
|
|
14591
|
+
execute() {
|
|
14592
|
+
for (const p6 of configPaths) {
|
|
14593
|
+
if (fs35.existsSync(p6)) fs35.unlinkSync(p6);
|
|
14594
|
+
}
|
|
14595
|
+
}
|
|
14596
|
+
});
|
|
14597
|
+
}
|
|
14598
|
+
const tsconfigPath = path40.join(cwd, "tsconfig.json");
|
|
14599
|
+
if (fs35.existsSync(tsconfigPath)) {
|
|
14600
|
+
const content = fs35.readFileSync(tsconfigPath, "utf-8");
|
|
14601
|
+
if (content.includes("@cms/")) {
|
|
14602
|
+
steps.push({
|
|
14603
|
+
label: "tsconfig.json path aliases",
|
|
14604
|
+
items: ["Remove all @cms/* paths from compilerOptions.paths"],
|
|
14605
|
+
execute() {
|
|
14606
|
+
cleanTsconfig(tsconfigPath);
|
|
14607
|
+
}
|
|
14608
|
+
});
|
|
14609
|
+
}
|
|
14610
|
+
}
|
|
14611
|
+
const cssFile = findMainCss2(cwd);
|
|
14612
|
+
if (cssFile) {
|
|
14613
|
+
const cssContent = fs35.readFileSync(cssFile, "utf-8");
|
|
14614
|
+
const sourcePattern = /^@source\s+"[^"]*cms[^"]*";\s*$/m;
|
|
14615
|
+
if (sourcePattern.test(cssContent)) {
|
|
14616
|
+
const relCss = path40.relative(cwd, cssFile);
|
|
14617
|
+
steps.push({
|
|
14618
|
+
label: `CSS @source lines (${relCss})`,
|
|
14619
|
+
items: ["Remove @source lines referencing cms/"],
|
|
14620
|
+
execute() {
|
|
14621
|
+
cleanCss(cssFile);
|
|
14622
|
+
}
|
|
14623
|
+
});
|
|
14624
|
+
}
|
|
14625
|
+
}
|
|
14626
|
+
const envPath = path40.join(cwd, ".env.local");
|
|
14627
|
+
if (fs35.existsSync(envPath)) {
|
|
14628
|
+
const envContent = fs35.readFileSync(envPath, "utf-8");
|
|
14629
|
+
const bsVars = envContent.split("\n").filter((l) => l.trim().match(/^BETTERSTART_\w+=/)).map((l) => l.split("=")[0]);
|
|
14630
|
+
if (bsVars.length > 0) {
|
|
14631
|
+
steps.push({
|
|
14632
|
+
label: ".env.local variables",
|
|
14633
|
+
items: bsVars,
|
|
14634
|
+
execute() {
|
|
14635
|
+
cleanEnvFile(envPath);
|
|
14636
|
+
}
|
|
14637
|
+
});
|
|
14638
|
+
}
|
|
14639
|
+
}
|
|
14640
|
+
const pkgPath = path40.join(cwd, "package.json");
|
|
14641
|
+
if (fs35.existsSync(pkgPath)) {
|
|
14642
|
+
const allCoreDeps = [...CORE_DEPS, ...EMAIL_DEPS];
|
|
14643
|
+
const allDevDeps = [...DEV_DEPS, ...BIOME_DEV_DEPS];
|
|
14644
|
+
const coreNames = new Set(
|
|
14645
|
+
allCoreDeps.map((d) => d.split("@").slice(0, d.startsWith("@") ? 2 : 1).join("@"))
|
|
14646
|
+
);
|
|
14647
|
+
const devNames = new Set(
|
|
14648
|
+
allDevDeps.map((d) => d.split("@").slice(0, d.startsWith("@") ? 2 : 1).join("@"))
|
|
14649
|
+
);
|
|
14650
|
+
const pkgContent = JSON.parse(fs35.readFileSync(pkgPath, "utf-8"));
|
|
14651
|
+
const deps = Object.keys(pkgContent.dependencies ?? {}).filter((n) => coreNames.has(n));
|
|
14652
|
+
const devDeps = Object.keys(pkgContent.devDependencies ?? {}).filter((n) => devNames.has(n));
|
|
14653
|
+
if (deps.length > 0 || devDeps.length > 0) {
|
|
14654
|
+
const items = [];
|
|
14655
|
+
if (deps.length > 0) items.push(`${deps.length} dependencies`);
|
|
14656
|
+
if (devDeps.length > 0) items.push(`${devDeps.length} devDependencies`);
|
|
14657
|
+
steps.push({
|
|
14658
|
+
label: "package.json dependencies",
|
|
14659
|
+
items,
|
|
14660
|
+
execute() {
|
|
14661
|
+
cleanPackageJsonDeps(pkgPath, allCoreDeps, allDevDeps);
|
|
14662
|
+
}
|
|
14663
|
+
});
|
|
14664
|
+
}
|
|
14665
|
+
}
|
|
14666
|
+
return steps;
|
|
14667
|
+
}
|
|
14668
|
+
var uninstallCommand = new Command6("uninstall").description("Remove all CMS files and undo modifications made by betterstart init").option("-f, --force", "Skip all confirmation prompts", false).option("--cwd <path>", "Project root path").action(async (options) => {
|
|
14348
14669
|
const cwd = options.cwd ? path40.resolve(options.cwd) : process.cwd();
|
|
14670
|
+
p5.intro(pc3.bgRed(pc3.white(" BetterStart Uninstall ")));
|
|
14671
|
+
const steps = buildUninstallPlan(cwd);
|
|
14672
|
+
if (steps.length === 0) {
|
|
14673
|
+
p5.log.info("Nothing to remove \u2014 project is already clean.");
|
|
14674
|
+
p5.outro("Done");
|
|
14675
|
+
return;
|
|
14676
|
+
}
|
|
14677
|
+
p5.log.warn(
|
|
14678
|
+
`Found ${steps.length} ${steps.length === 1 ? "area" : "areas"} to clean up:`
|
|
14679
|
+
);
|
|
14680
|
+
let completedCount = 0;
|
|
14681
|
+
for (const step of steps) {
|
|
14682
|
+
p5.log.message("");
|
|
14683
|
+
p5.log.step(pc3.bold(step.label));
|
|
14684
|
+
for (const item of step.items) {
|
|
14685
|
+
p5.log.message(` ${pc3.dim("\u2022")} ${item}`);
|
|
14686
|
+
}
|
|
14687
|
+
if (!options.force) {
|
|
14688
|
+
const confirmed = await p5.confirm({
|
|
14689
|
+
message: `Remove ${step.label}?`,
|
|
14690
|
+
initialValue: true
|
|
14691
|
+
});
|
|
14692
|
+
if (p5.isCancel(confirmed)) {
|
|
14693
|
+
p5.cancel("Uninstall cancelled.");
|
|
14694
|
+
process.exit(0);
|
|
14695
|
+
}
|
|
14696
|
+
if (!confirmed) {
|
|
14697
|
+
p5.log.info(pc3.dim(`Skipped: ${step.label}`));
|
|
14698
|
+
continue;
|
|
14699
|
+
}
|
|
14700
|
+
}
|
|
14701
|
+
step.execute();
|
|
14702
|
+
completedCount++;
|
|
14703
|
+
p5.log.success(`Removed: ${step.label}`);
|
|
14704
|
+
}
|
|
14705
|
+
p5.log.message("");
|
|
14706
|
+
if (completedCount === 0) {
|
|
14707
|
+
p5.log.info("No changes were made.");
|
|
14708
|
+
} else {
|
|
14709
|
+
const pm = detectPackageManager(cwd);
|
|
14710
|
+
p5.note(
|
|
14711
|
+
[
|
|
14712
|
+
`Run ${pc3.cyan(installCommand(pm))} to clean up node_modules.`,
|
|
14713
|
+
"",
|
|
14714
|
+
pc3.dim("Database tables were NOT dropped \u2014 drop them manually if needed.")
|
|
14715
|
+
].join("\n"),
|
|
14716
|
+
"Next steps"
|
|
14717
|
+
);
|
|
14718
|
+
}
|
|
14719
|
+
if (findMainCss2(cwd)) {
|
|
14720
|
+
p5.log.info(
|
|
14721
|
+
pc3.dim(
|
|
14722
|
+
"Note: @theme tokens were left in your CSS \u2014 they're harmless and may be shared with your own styles."
|
|
14723
|
+
)
|
|
14724
|
+
);
|
|
14725
|
+
}
|
|
14726
|
+
p5.outro(completedCount > 0 ? "Uninstall complete" : "Done");
|
|
14727
|
+
});
|
|
14728
|
+
|
|
14729
|
+
// src/commands/update-styles.ts
|
|
14730
|
+
import fs36 from "fs";
|
|
14731
|
+
import path41 from "path";
|
|
14732
|
+
import * as clack3 from "@clack/prompts";
|
|
14733
|
+
import { Command as Command7 } from "commander";
|
|
14734
|
+
var updateStylesCommand = new Command7("update-styles").description("Replace cms-globals.css with the latest version from the CLI").option("--cwd <path>", "Project root path").action(async (options) => {
|
|
14735
|
+
const cwd = options.cwd ? path41.resolve(options.cwd) : process.cwd();
|
|
14349
14736
|
clack3.intro("BetterStart Update Styles");
|
|
14350
14737
|
const config = await resolveConfig(cwd);
|
|
14351
14738
|
const cmsDir = config.paths?.cms ?? "./cms";
|
|
14352
|
-
const targetPath =
|
|
14353
|
-
if (!
|
|
14354
|
-
clack3.cancel(`cms-globals.css not found at ${
|
|
14739
|
+
const targetPath = path41.join(cwd, cmsDir, "cms-globals.css");
|
|
14740
|
+
if (!fs36.existsSync(targetPath)) {
|
|
14741
|
+
clack3.cancel(`cms-globals.css not found at ${path41.relative(cwd, targetPath)}`);
|
|
14355
14742
|
process.exit(1);
|
|
14356
14743
|
}
|
|
14357
|
-
|
|
14358
|
-
clack3.log.success(`Updated ${
|
|
14744
|
+
fs36.writeFileSync(targetPath, cmsGlobalsCssTemplate(), "utf-8");
|
|
14745
|
+
clack3.log.success(`Updated ${path41.relative(cwd, targetPath)}`);
|
|
14359
14746
|
clack3.outro("Styles updated");
|
|
14360
14747
|
});
|
|
14361
14748
|
|
|
14362
14749
|
// src/cli.ts
|
|
14363
|
-
var program = new
|
|
14750
|
+
var program = new Command8();
|
|
14364
14751
|
program.name("betterstart").description("Scaffold a full-featured CMS into any Next.js 16 application").version("0.1.0");
|
|
14365
14752
|
program.addCommand(initCommand);
|
|
14366
14753
|
program.addCommand(generateCommand);
|
|
14367
14754
|
program.addCommand(removeCommand);
|
|
14368
14755
|
program.addCommand(seedCommand);
|
|
14756
|
+
program.addCommand(uninstallCommand);
|
|
14369
14757
|
program.addCommand(updateDepsCommand);
|
|
14370
14758
|
program.addCommand(updateStylesCommand);
|
|
14371
14759
|
program.parse();
|