@getcoherent/cli 0.6.38 → 0.6.40
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/index.js +279 -146
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -6980,14 +6980,28 @@ function findPagesImporting(projectRoot, componentName, componentFile) {
|
|
|
6980
6980
|
return results;
|
|
6981
6981
|
}
|
|
6982
6982
|
function isUsedInLayout(projectRoot, componentName) {
|
|
6983
|
-
const
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
|
|
6983
|
+
const appDir = join7(projectRoot, "app");
|
|
6984
|
+
const layoutPaths = [join7(appDir, "layout.tsx")];
|
|
6985
|
+
if (existsSync12(appDir)) {
|
|
6986
|
+
try {
|
|
6987
|
+
for (const entry of readdirSync4(appDir, { withFileTypes: true })) {
|
|
6988
|
+
if (entry.isDirectory() && entry.name.startsWith("(") && entry.name.endsWith(")")) {
|
|
6989
|
+
layoutPaths.push(join7(appDir, entry.name, "layout.tsx"));
|
|
6990
|
+
}
|
|
6991
|
+
}
|
|
6992
|
+
} catch {
|
|
6993
|
+
}
|
|
6990
6994
|
}
|
|
6995
|
+
const matched = [];
|
|
6996
|
+
for (const lp of [...new Set(layoutPaths)]) {
|
|
6997
|
+
try {
|
|
6998
|
+
if (readFileSync9(lp, "utf-8").includes(componentName)) {
|
|
6999
|
+
matched.push(relative3(projectRoot, lp));
|
|
7000
|
+
}
|
|
7001
|
+
} catch {
|
|
7002
|
+
}
|
|
7003
|
+
}
|
|
7004
|
+
return matched;
|
|
6991
7005
|
}
|
|
6992
7006
|
function findUnregisteredComponents(projectRoot, manifest) {
|
|
6993
7007
|
const results = [];
|
|
@@ -7114,8 +7128,8 @@ function reconcileComponents(projectRoot, manifest) {
|
|
|
7114
7128
|
result.updated.push({ id: entry.id, field: "name", from: oldName, to: entry.name });
|
|
7115
7129
|
}
|
|
7116
7130
|
const actualUsedIn = findPagesImporting(projectRoot, entry.name, entry.file);
|
|
7117
|
-
const
|
|
7118
|
-
const fullUsedIn =
|
|
7131
|
+
const layoutPaths = isUsedInLayout(projectRoot, entry.name);
|
|
7132
|
+
const fullUsedIn = [.../* @__PURE__ */ new Set([...actualUsedIn, ...layoutPaths])];
|
|
7119
7133
|
if (!arraysEqual(fullUsedIn, entry.usedIn || [])) {
|
|
7120
7134
|
result.updated.push({
|
|
7121
7135
|
id: entry.id,
|
|
@@ -8308,8 +8322,8 @@ async function regenerateDocsCommand() {
|
|
|
8308
8322
|
|
|
8309
8323
|
// src/commands/fix.ts
|
|
8310
8324
|
import chalk15 from "chalk";
|
|
8311
|
-
import { readdirSync as readdirSync7, readFileSync as
|
|
8312
|
-
import { resolve as resolve10, join as
|
|
8325
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync13, existsSync as existsSync17, rmSync as rmSync5, mkdirSync as mkdirSync7 } from "fs";
|
|
8326
|
+
import { resolve as resolve10, join as join12, relative as relative5 } from "path";
|
|
8313
8327
|
import {
|
|
8314
8328
|
DesignSystemManager as DesignSystemManager9,
|
|
8315
8329
|
ComponentManager as ComponentManager5,
|
|
@@ -8318,6 +8332,54 @@ import {
|
|
|
8318
8332
|
loadManifest as loadManifest9,
|
|
8319
8333
|
saveManifest as saveManifest5
|
|
8320
8334
|
} from "@getcoherent/core";
|
|
8335
|
+
|
|
8336
|
+
// src/commands/fix-validation.ts
|
|
8337
|
+
import { createRequire } from "module";
|
|
8338
|
+
import { existsSync as existsSync16, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "fs";
|
|
8339
|
+
import { join as join11 } from "path";
|
|
8340
|
+
var cachedTs = null;
|
|
8341
|
+
var cachedProjectRoot = null;
|
|
8342
|
+
function isValidTsx(code, projectRoot, ext = ".tsx") {
|
|
8343
|
+
if (ext !== ".tsx" && ext !== ".ts") return true;
|
|
8344
|
+
const pkgJson = join11(projectRoot, "package.json");
|
|
8345
|
+
if (!existsSync16(pkgJson)) return true;
|
|
8346
|
+
try {
|
|
8347
|
+
if (!cachedTs || cachedProjectRoot !== projectRoot) {
|
|
8348
|
+
const req = createRequire(pkgJson);
|
|
8349
|
+
cachedTs = req("typescript");
|
|
8350
|
+
cachedProjectRoot = projectRoot;
|
|
8351
|
+
}
|
|
8352
|
+
const sf = cachedTs.createSourceFile(
|
|
8353
|
+
"check.tsx",
|
|
8354
|
+
code,
|
|
8355
|
+
cachedTs.ScriptTarget.Latest,
|
|
8356
|
+
false,
|
|
8357
|
+
cachedTs.ScriptKind.TSX
|
|
8358
|
+
);
|
|
8359
|
+
const diagnostics = sf.parseDiagnostics;
|
|
8360
|
+
return !diagnostics || diagnostics.length === 0;
|
|
8361
|
+
} catch {
|
|
8362
|
+
return true;
|
|
8363
|
+
}
|
|
8364
|
+
}
|
|
8365
|
+
function safeWrite(filePath, newContent, projectRoot, backups) {
|
|
8366
|
+
if (!backups.has(filePath)) {
|
|
8367
|
+
try {
|
|
8368
|
+
backups.set(filePath, readFileSync12(filePath, "utf-8"));
|
|
8369
|
+
} catch {
|
|
8370
|
+
}
|
|
8371
|
+
}
|
|
8372
|
+
const ext = filePath.slice(filePath.lastIndexOf("."));
|
|
8373
|
+
writeFileSync10(filePath, newContent, "utf-8");
|
|
8374
|
+
if (!isValidTsx(newContent, projectRoot, ext)) {
|
|
8375
|
+
const original = backups.get(filePath);
|
|
8376
|
+
if (original) writeFileSync10(filePath, original, "utf-8");
|
|
8377
|
+
return { ok: false };
|
|
8378
|
+
}
|
|
8379
|
+
return { ok: true };
|
|
8380
|
+
}
|
|
8381
|
+
|
|
8382
|
+
// src/commands/fix.ts
|
|
8321
8383
|
function extractComponentIdsFromCode2(code) {
|
|
8322
8384
|
const ids = /* @__PURE__ */ new Set();
|
|
8323
8385
|
const allMatches = code.matchAll(/@\/components\/((?:ui\/)?[a-z0-9-]+)/g);
|
|
@@ -8335,7 +8397,7 @@ function listTsxFiles(dir) {
|
|
|
8335
8397
|
try {
|
|
8336
8398
|
const entries = readdirSync7(dir, { withFileTypes: true });
|
|
8337
8399
|
for (const e of entries) {
|
|
8338
|
-
const full =
|
|
8400
|
+
const full = join12(dir, e.name);
|
|
8339
8401
|
if (e.isDirectory() && e.name !== "node_modules" && !e.name.startsWith(".")) {
|
|
8340
8402
|
files.push(...listTsxFiles(full));
|
|
8341
8403
|
} else if (e.isFile() && e.name.endsWith(".tsx")) {
|
|
@@ -8358,14 +8420,16 @@ async function fixCommand(opts = {}) {
|
|
|
8358
8420
|
const projectRoot = project.root;
|
|
8359
8421
|
const fixes = [];
|
|
8360
8422
|
const remaining = [];
|
|
8423
|
+
const backups = /* @__PURE__ */ new Map();
|
|
8424
|
+
const modifiedFiles = [];
|
|
8361
8425
|
if (dryRun) {
|
|
8362
8426
|
console.log(chalk15.cyan("\ncoherent fix --dry-run\n"));
|
|
8363
8427
|
} else {
|
|
8364
8428
|
console.log(chalk15.cyan("\ncoherent fix\n"));
|
|
8365
8429
|
}
|
|
8366
8430
|
if (!skipCache) {
|
|
8367
|
-
const nextDir =
|
|
8368
|
-
if (
|
|
8431
|
+
const nextDir = join12(projectRoot, ".next");
|
|
8432
|
+
if (existsSync17(nextDir)) {
|
|
8369
8433
|
if (!dryRun) rmSync5(nextDir, { recursive: true, force: true });
|
|
8370
8434
|
fixes.push("Cleared build cache");
|
|
8371
8435
|
console.log(chalk15.green(" \u2714 Cleared build cache"));
|
|
@@ -8392,7 +8456,7 @@ async function fixCommand(opts = {}) {
|
|
|
8392
8456
|
const componentsTsxFiles = listTsxFiles(resolve10(projectRoot, "components"));
|
|
8393
8457
|
const allComponentIds = /* @__PURE__ */ new Set();
|
|
8394
8458
|
for (const file of [...allTsxFiles, ...componentsTsxFiles]) {
|
|
8395
|
-
const content =
|
|
8459
|
+
const content = readFileSync13(file, "utf-8");
|
|
8396
8460
|
extractComponentIdsFromCode2(content).forEach((id) => allComponentIds.add(id));
|
|
8397
8461
|
}
|
|
8398
8462
|
let dsm = null;
|
|
@@ -8412,7 +8476,7 @@ async function fixCommand(opts = {}) {
|
|
|
8412
8476
|
} else {
|
|
8413
8477
|
const fileName = toKebabCase(id) + ".tsx";
|
|
8414
8478
|
const filePath = resolve10(projectRoot, "components", "ui", fileName);
|
|
8415
|
-
if (!
|
|
8479
|
+
if (!existsSync17(filePath)) missingFiles.push(id);
|
|
8416
8480
|
}
|
|
8417
8481
|
}
|
|
8418
8482
|
const provider = getComponentProvider();
|
|
@@ -8464,13 +8528,22 @@ async function fixCommand(opts = {}) {
|
|
|
8464
8528
|
const userTsxFiles = allTsxFiles.filter((f) => !f.includes("/design-system/"));
|
|
8465
8529
|
let syntaxFixed = 0;
|
|
8466
8530
|
for (const file of userTsxFiles) {
|
|
8467
|
-
const content =
|
|
8531
|
+
const content = readFileSync13(file, "utf-8");
|
|
8468
8532
|
const fixed = fixUnescapedLtInJsx(
|
|
8469
8533
|
fixEscapedClosingQuotes(sanitizeMetadataStrings(ensureUseClientIfNeeded(content)))
|
|
8470
8534
|
);
|
|
8471
8535
|
if (fixed !== content) {
|
|
8472
|
-
if (!dryRun)
|
|
8473
|
-
|
|
8536
|
+
if (!dryRun) {
|
|
8537
|
+
const result = safeWrite(file, fixed, projectRoot, backups);
|
|
8538
|
+
if (result.ok) {
|
|
8539
|
+
modifiedFiles.push(file);
|
|
8540
|
+
syntaxFixed++;
|
|
8541
|
+
} else {
|
|
8542
|
+
console.log(chalk15.yellow(` \u26A0 Syntax fix rolled back for ${relative5(projectRoot, file)} (parse error)`));
|
|
8543
|
+
}
|
|
8544
|
+
} else {
|
|
8545
|
+
syntaxFixed++;
|
|
8546
|
+
}
|
|
8474
8547
|
}
|
|
8475
8548
|
}
|
|
8476
8549
|
if (syntaxFixed > 0) {
|
|
@@ -8493,7 +8566,7 @@ async function fixCommand(opts = {}) {
|
|
|
8493
8566
|
console.log(chalk15.green(` \u2714 Verified group layouts: ${layoutTypes}`));
|
|
8494
8567
|
const hasSidebar = plan.groups.some((g) => g.layout === "sidebar" || g.layout === "both");
|
|
8495
8568
|
const sidebarPath = resolve10(projectRoot, "components", "shared", "sidebar.tsx");
|
|
8496
|
-
if (hasSidebar && !
|
|
8569
|
+
if (hasSidebar && !existsSync17(sidebarPath) && !dryRun) {
|
|
8497
8570
|
if (!dsm) {
|
|
8498
8571
|
dsm = new DesignSystemManager9(project.configPath);
|
|
8499
8572
|
await dsm.load();
|
|
@@ -8502,14 +8575,18 @@ async function fixCommand(opts = {}) {
|
|
|
8502
8575
|
const generator = new PageGenerator(dsm.getConfig());
|
|
8503
8576
|
const sidebarCode = generator.generateSharedSidebarCode();
|
|
8504
8577
|
mkdirSync7(resolve10(projectRoot, "components", "shared"), { recursive: true });
|
|
8505
|
-
|
|
8506
|
-
|
|
8507
|
-
|
|
8578
|
+
const sidebarResult = safeWrite(sidebarPath, sidebarCode, projectRoot, backups);
|
|
8579
|
+
if (sidebarResult.ok) {
|
|
8580
|
+
fixes.push("Generated AppSidebar component (components/shared/sidebar.tsx)");
|
|
8581
|
+
console.log(chalk15.green(" \u2714 Generated AppSidebar component"));
|
|
8582
|
+
} else {
|
|
8583
|
+
console.log(chalk15.yellow(" \u26A0 AppSidebar generation failed validation"));
|
|
8584
|
+
}
|
|
8508
8585
|
}
|
|
8509
8586
|
if (hasSidebar && !dryRun) {
|
|
8510
8587
|
const rootLayoutPath = resolve10(projectRoot, "app", "layout.tsx");
|
|
8511
|
-
if (
|
|
8512
|
-
let rootCode =
|
|
8588
|
+
if (existsSync17(rootLayoutPath)) {
|
|
8589
|
+
let rootCode = readFileSync13(rootLayoutPath, "utf-8");
|
|
8513
8590
|
if (rootCode.includes("<Header")) {
|
|
8514
8591
|
rootCode = rootCode.replace(/import\s*\{[^}]*Header[^}]*\}[^;\n]*[;\n]?\s*/g, "").replace(/import\s*\{[^}]*Footer[^}]*\}[^;\n]*[;\n]?\s*/g, "").replace(/import\s+ShowWhenNotAuthRoute[^;\n]*[;\n]?\s*/g, "").replace(/<ShowWhenNotAuthRoute>[\s\S]*?<\/ShowWhenNotAuthRoute>/g, (match) => {
|
|
8515
8592
|
const inner = match.replace(/<\/?ShowWhenNotAuthRoute>/g, "").trim();
|
|
@@ -8517,50 +8594,74 @@ async function fixCommand(opts = {}) {
|
|
|
8517
8594
|
}).replace(/\s*<Header\s*\/>\s*/g, "\n").replace(/\s*<Footer\s*\/>\s*/g, "\n");
|
|
8518
8595
|
rootCode = rootCode.replace(/min-h-screen flex flex-col/g, "min-h-svh");
|
|
8519
8596
|
rootCode = rootCode.replace(/"flex-1 flex flex-col"/g, '"flex-1"');
|
|
8520
|
-
|
|
8521
|
-
|
|
8522
|
-
|
|
8597
|
+
const rootResult = safeWrite(rootLayoutPath, rootCode, projectRoot, backups);
|
|
8598
|
+
if (rootResult.ok) {
|
|
8599
|
+
fixes.push("Stripped Header/Footer from root layout (sidebar mode)");
|
|
8600
|
+
console.log(chalk15.green(" \u2714 Stripped Header/Footer from root layout (sidebar mode)"));
|
|
8601
|
+
} else {
|
|
8602
|
+
console.log(chalk15.yellow(" \u26A0 Root layout update rolled back (parse error)"));
|
|
8603
|
+
}
|
|
8523
8604
|
}
|
|
8524
8605
|
}
|
|
8525
8606
|
const publicLayoutPath = resolve10(projectRoot, "app", "(public)", "layout.tsx");
|
|
8526
|
-
const publicExists =
|
|
8527
|
-
const needsPublicLayout = !publicExists || !
|
|
8607
|
+
const publicExists = existsSync17(publicLayoutPath);
|
|
8608
|
+
const needsPublicLayout = !publicExists || !readFileSync13(publicLayoutPath, "utf-8").includes("<Header");
|
|
8528
8609
|
if (needsPublicLayout) {
|
|
8529
8610
|
const { buildPublicLayoutCodeForSidebar } = await import("./code-generator-D3ZHOO4M.js");
|
|
8530
8611
|
mkdirSync7(resolve10(projectRoot, "app", "(public)"), { recursive: true });
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8612
|
+
const publicResult = safeWrite(publicLayoutPath, buildPublicLayoutCodeForSidebar(), projectRoot, backups);
|
|
8613
|
+
if (publicResult.ok) {
|
|
8614
|
+
fixes.push("Added Header/Footer to (public) layout");
|
|
8615
|
+
console.log(chalk15.green(" \u2714 Added Header/Footer to (public) layout"));
|
|
8616
|
+
} else {
|
|
8617
|
+
console.log(chalk15.yellow(" \u26A0 Public layout generation failed validation"));
|
|
8618
|
+
}
|
|
8534
8619
|
}
|
|
8535
8620
|
const appLayoutPath = resolve10(projectRoot, "app", "(app)", "layout.tsx");
|
|
8536
|
-
if (
|
|
8537
|
-
let appLayoutCode =
|
|
8621
|
+
if (existsSync17(appLayoutPath) && dsm) {
|
|
8622
|
+
let appLayoutCode = readFileSync13(appLayoutPath, "utf-8");
|
|
8538
8623
|
const configName = dsm.getConfig().name;
|
|
8539
8624
|
if (configName && configName !== "My App" && appLayoutCode.includes("My App")) {
|
|
8540
8625
|
appLayoutCode = appLayoutCode.replace(/My App/g, configName);
|
|
8541
|
-
|
|
8542
|
-
|
|
8543
|
-
|
|
8626
|
+
const appResult = safeWrite(appLayoutPath, appLayoutCode, projectRoot, backups);
|
|
8627
|
+
if (appResult.ok) {
|
|
8628
|
+
fixes.push(`Replaced "My App" with "${configName}" in (app)/layout.tsx`);
|
|
8629
|
+
console.log(chalk15.green(` \u2714 Replaced "My App" with "${configName}" in (app)/layout.tsx`));
|
|
8630
|
+
} else {
|
|
8631
|
+
console.log(chalk15.yellow(" \u26A0 (app)/layout.tsx update rolled back (parse error)"));
|
|
8632
|
+
}
|
|
8544
8633
|
}
|
|
8545
8634
|
}
|
|
8546
8635
|
const sidebarComponentPath2 = resolve10(projectRoot, "components", "shared", "sidebar.tsx");
|
|
8547
|
-
if (
|
|
8548
|
-
const
|
|
8549
|
-
|
|
8636
|
+
if (existsSync17(sidebarComponentPath2)) {
|
|
8637
|
+
const existingSidebarCode = readFileSync13(sidebarComponentPath2, "utf-8");
|
|
8638
|
+
const sidebarConfigName = dsm?.getConfig().name ?? "";
|
|
8639
|
+
const hasWrongName = existingSidebarCode.includes("My App") && sidebarConfigName !== "My App";
|
|
8640
|
+
const hasTrigger = existingSidebarCode.includes("SidebarTrigger");
|
|
8641
|
+
if (hasWrongName || hasTrigger) {
|
|
8550
8642
|
if (!dsm) {
|
|
8551
8643
|
dsm = new DesignSystemManager9(project.configPath);
|
|
8552
8644
|
await dsm.load();
|
|
8553
8645
|
}
|
|
8554
8646
|
const { PageGenerator } = await import("@getcoherent/core");
|
|
8555
8647
|
const gen = new PageGenerator(dsm.getConfig());
|
|
8556
|
-
|
|
8557
|
-
|
|
8558
|
-
|
|
8648
|
+
const sidebarResult2 = safeWrite(
|
|
8649
|
+
sidebarComponentPath2,
|
|
8650
|
+
gen.generateSharedSidebarCode(),
|
|
8651
|
+
projectRoot,
|
|
8652
|
+
backups
|
|
8653
|
+
);
|
|
8654
|
+
if (sidebarResult2.ok) {
|
|
8655
|
+
fixes.push("Regenerated sidebar component");
|
|
8656
|
+
console.log(chalk15.green(" \u2714 Regenerated sidebar component"));
|
|
8657
|
+
} else {
|
|
8658
|
+
console.log(chalk15.yellow(" \u26A0 Sidebar regeneration failed validation \u2014 restored original"));
|
|
8659
|
+
}
|
|
8559
8660
|
}
|
|
8560
8661
|
}
|
|
8561
8662
|
const rootPagePath = resolve10(projectRoot, "app", "page.tsx");
|
|
8562
8663
|
const publicPagePath = resolve10(projectRoot, "app", "(public)", "page.tsx");
|
|
8563
|
-
if (
|
|
8664
|
+
if (existsSync17(rootPagePath) && !existsSync17(publicPagePath)) {
|
|
8564
8665
|
const { renameSync } = await import("fs");
|
|
8565
8666
|
mkdirSync7(resolve10(projectRoot, "app", "(public)"), { recursive: true });
|
|
8566
8667
|
renameSync(rootPagePath, publicPagePath);
|
|
@@ -8568,27 +8669,42 @@ async function fixCommand(opts = {}) {
|
|
|
8568
8669
|
console.log(chalk15.green(" \u2714 Moved app/page.tsx \u2192 app/(public)/page.tsx (gets Header/Footer)"));
|
|
8569
8670
|
}
|
|
8570
8671
|
const themeTogglePath = resolve10(projectRoot, "components", "shared", "theme-toggle.tsx");
|
|
8571
|
-
if (!
|
|
8672
|
+
if (!existsSync17(themeTogglePath)) {
|
|
8572
8673
|
const { generateThemeToggleCode } = await import("./code-generator-D3ZHOO4M.js");
|
|
8573
8674
|
mkdirSync7(resolve10(projectRoot, "components", "shared"), { recursive: true });
|
|
8574
|
-
|
|
8575
|
-
|
|
8576
|
-
|
|
8675
|
+
const themeResult = safeWrite(themeTogglePath, generateThemeToggleCode(), projectRoot, backups);
|
|
8676
|
+
if (themeResult.ok) {
|
|
8677
|
+
fixes.push("Generated ThemeToggle component (components/shared/theme-toggle.tsx)");
|
|
8678
|
+
console.log(chalk15.green(" \u2714 Generated ThemeToggle component"));
|
|
8679
|
+
} else {
|
|
8680
|
+
console.log(chalk15.yellow(" \u26A0 ThemeToggle generation failed validation"));
|
|
8681
|
+
}
|
|
8577
8682
|
}
|
|
8578
8683
|
}
|
|
8579
8684
|
}
|
|
8580
|
-
} catch {
|
|
8685
|
+
} catch (err) {
|
|
8686
|
+
console.log(chalk15.yellow(` \u26A0 Layout repair skipped: ${err instanceof Error ? err.message : "unknown error"}`));
|
|
8581
8687
|
}
|
|
8582
8688
|
if (!skipQuality) {
|
|
8583
8689
|
let qualityFixCount = 0;
|
|
8584
8690
|
const qualityFixDetails = [];
|
|
8585
8691
|
for (const file of userTsxFiles) {
|
|
8586
|
-
const content =
|
|
8692
|
+
const content = readFileSync13(file, "utf-8");
|
|
8587
8693
|
const { code: autoFixed, fixes: fileFixes } = await autoFixCode(content);
|
|
8588
8694
|
if (autoFixed !== content) {
|
|
8589
|
-
if (!dryRun)
|
|
8590
|
-
|
|
8591
|
-
|
|
8695
|
+
if (!dryRun) {
|
|
8696
|
+
const qResult = safeWrite(file, autoFixed, projectRoot, backups);
|
|
8697
|
+
if (qResult.ok) {
|
|
8698
|
+
modifiedFiles.push(file);
|
|
8699
|
+
qualityFixCount++;
|
|
8700
|
+
qualityFixDetails.push(...fileFixes);
|
|
8701
|
+
} else {
|
|
8702
|
+
console.log(chalk15.yellow(` \u26A0 Quality fix rolled back for ${relative5(projectRoot, file)} (parse error)`));
|
|
8703
|
+
}
|
|
8704
|
+
} else {
|
|
8705
|
+
qualityFixCount++;
|
|
8706
|
+
qualityFixDetails.push(...fileFixes);
|
|
8707
|
+
}
|
|
8592
8708
|
}
|
|
8593
8709
|
}
|
|
8594
8710
|
if (qualityFixCount > 0) {
|
|
@@ -8598,11 +8714,22 @@ async function fixCommand(opts = {}) {
|
|
|
8598
8714
|
console.log(chalk15.green(` \u2714 ${verb} ${uniqueFixes.length} quality issue type(s): ${uniqueFixes.join(", ")}`));
|
|
8599
8715
|
}
|
|
8600
8716
|
}
|
|
8717
|
+
for (const file of modifiedFiles) {
|
|
8718
|
+
if (!backups.has(file)) continue;
|
|
8719
|
+
const before = backups.get(file);
|
|
8720
|
+
const after = readFileSync13(file, "utf-8");
|
|
8721
|
+
const issues = verifyIncrementalEdit(before, after);
|
|
8722
|
+
if (issues.length > 0) {
|
|
8723
|
+
for (const issue of issues) {
|
|
8724
|
+
remaining.push(`${relative5(projectRoot, file)}: ${issue.message}`);
|
|
8725
|
+
}
|
|
8726
|
+
}
|
|
8727
|
+
}
|
|
8601
8728
|
let totalErrors = 0;
|
|
8602
8729
|
let totalWarnings = 0;
|
|
8603
8730
|
const fileIssues = [];
|
|
8604
8731
|
for (const file of allTsxFiles) {
|
|
8605
|
-
const code = dryRun ?
|
|
8732
|
+
const code = dryRun ? readFileSync13(file, "utf-8") : readFileSync13(file, "utf-8");
|
|
8606
8733
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
8607
8734
|
const baseName = file.split("/").pop() || "";
|
|
8608
8735
|
const isAuthPage = relativePath.includes("(auth)");
|
|
@@ -8653,8 +8780,8 @@ async function fixCommand(opts = {}) {
|
|
|
8653
8780
|
}
|
|
8654
8781
|
for (const entry of manifest.shared) {
|
|
8655
8782
|
const actualUsedIn = findPagesImporting(project.root, entry.name, entry.file);
|
|
8656
|
-
const
|
|
8657
|
-
const fullActual =
|
|
8783
|
+
const layoutPaths = isUsedInLayout(project.root, entry.name);
|
|
8784
|
+
const fullActual = [.../* @__PURE__ */ new Set([...actualUsedIn, ...layoutPaths])];
|
|
8658
8785
|
if (!arraysEqual(fullActual, entry.usedIn || [])) {
|
|
8659
8786
|
entry.usedIn = fullActual;
|
|
8660
8787
|
manifestModified = true;
|
|
@@ -8691,12 +8818,18 @@ async function fixCommand(opts = {}) {
|
|
|
8691
8818
|
}
|
|
8692
8819
|
for (const entry of manifest.shared) {
|
|
8693
8820
|
const actualUsedIn = findPagesImporting(project.root, entry.name, entry.file);
|
|
8694
|
-
const
|
|
8695
|
-
if (actualUsedIn.length === 0 &&
|
|
8821
|
+
const layoutPaths2 = isUsedInLayout(project.root, entry.name);
|
|
8822
|
+
if (actualUsedIn.length === 0 && layoutPaths2.length === 0) {
|
|
8696
8823
|
remaining.push(`${entry.id} (${entry.name}) \u2014 unused. Remove: coherent components shared remove ${entry.id}`);
|
|
8697
8824
|
}
|
|
8698
8825
|
}
|
|
8699
|
-
} catch {
|
|
8826
|
+
} catch (err) {
|
|
8827
|
+
const isNotFound = err instanceof Error && "code" in err && err.code === "ENOENT";
|
|
8828
|
+
if (!isNotFound) {
|
|
8829
|
+
console.log(
|
|
8830
|
+
chalk15.yellow(` \u26A0 Component manifest check skipped: ${err instanceof Error ? err.message : "unknown error"}`)
|
|
8831
|
+
);
|
|
8832
|
+
}
|
|
8700
8833
|
}
|
|
8701
8834
|
if (fixes.length === 0 && totalErrors === 0 && totalWarnings === 0 && remaining.length === 0) {
|
|
8702
8835
|
console.log(chalk15.green("\n \u2705 Everything looks good \u2014 no issues found\n"));
|
|
@@ -8727,7 +8860,7 @@ async function fixCommand(opts = {}) {
|
|
|
8727
8860
|
// src/commands/check.ts
|
|
8728
8861
|
import chalk16 from "chalk";
|
|
8729
8862
|
import { resolve as resolve11 } from "path";
|
|
8730
|
-
import { readdirSync as readdirSync8, readFileSync as
|
|
8863
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync14, statSync as statSync3, existsSync as existsSync18 } from "fs";
|
|
8731
8864
|
import { loadManifest as loadManifest10 } from "@getcoherent/core";
|
|
8732
8865
|
var EXCLUDED_DIRS = /* @__PURE__ */ new Set(["node_modules", "design-system"]);
|
|
8733
8866
|
function findTsxFiles(dir) {
|
|
@@ -8784,7 +8917,7 @@ async function checkCommand(opts = {}) {
|
|
|
8784
8917
|
"NATIVE_TABLE"
|
|
8785
8918
|
]);
|
|
8786
8919
|
for (const file of files) {
|
|
8787
|
-
const code =
|
|
8920
|
+
const code = readFileSync14(file, "utf-8");
|
|
8788
8921
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
8789
8922
|
const baseName = file.split("/").pop() || "";
|
|
8790
8923
|
const isAuthPage = relativePath.includes("(auth)");
|
|
@@ -8826,7 +8959,7 @@ async function checkCommand(opts = {}) {
|
|
|
8826
8959
|
routeSet.add("/");
|
|
8827
8960
|
routeSet.add("#");
|
|
8828
8961
|
for (const file of files) {
|
|
8829
|
-
const code =
|
|
8962
|
+
const code = readFileSync14(file, "utf-8");
|
|
8830
8963
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
8831
8964
|
const lines = code.split("\n");
|
|
8832
8965
|
const linkHrefRe = /href\s*=\s*["'](\/[a-z0-9/-]*)["']/gi;
|
|
@@ -8859,7 +8992,7 @@ async function checkCommand(opts = {}) {
|
|
|
8859
8992
|
if (manifest.shared.length > 0) {
|
|
8860
8993
|
for (const entry of manifest.shared) {
|
|
8861
8994
|
const fullPath = resolve11(project.root, entry.file);
|
|
8862
|
-
if (!
|
|
8995
|
+
if (!existsSync18(fullPath)) {
|
|
8863
8996
|
result.pages.withErrors++;
|
|
8864
8997
|
if (!opts.json) console.log(chalk16.red(`
|
|
8865
8998
|
\u2717 Missing shared component file: ${entry.id} (${entry.file})`));
|
|
@@ -8884,7 +9017,7 @@ async function checkCommand(opts = {}) {
|
|
|
8884
9017
|
let _nameMismatch = 0;
|
|
8885
9018
|
for (const entry of manifest.shared) {
|
|
8886
9019
|
const filePath = resolve11(projectRoot, entry.file);
|
|
8887
|
-
const fileExists =
|
|
9020
|
+
const fileExists = existsSync18(filePath);
|
|
8888
9021
|
if (!fileExists) {
|
|
8889
9022
|
_orphaned++;
|
|
8890
9023
|
if (!opts.json) {
|
|
@@ -8894,7 +9027,7 @@ async function checkCommand(opts = {}) {
|
|
|
8894
9027
|
continue;
|
|
8895
9028
|
}
|
|
8896
9029
|
try {
|
|
8897
|
-
const code =
|
|
9030
|
+
const code = readFileSync14(filePath, "utf-8");
|
|
8898
9031
|
const actualExports = extractExportedComponentNames(code);
|
|
8899
9032
|
if (actualExports.length > 0 && !actualExports.includes(entry.name)) {
|
|
8900
9033
|
_nameMismatch++;
|
|
@@ -8910,10 +9043,10 @@ async function checkCommand(opts = {}) {
|
|
|
8910
9043
|
} catch {
|
|
8911
9044
|
}
|
|
8912
9045
|
const actualUsedIn = findPagesImporting(projectRoot, entry.name, entry.file);
|
|
8913
|
-
const
|
|
8914
|
-
const totalUsage = actualUsedIn.length +
|
|
9046
|
+
const layoutPaths = isUsedInLayout(projectRoot, entry.name);
|
|
9047
|
+
const totalUsage = actualUsedIn.length + layoutPaths.length;
|
|
8915
9048
|
const manifestUsedIn = entry.usedIn || [];
|
|
8916
|
-
const fullActual =
|
|
9049
|
+
const fullActual = [.../* @__PURE__ */ new Set([...actualUsedIn, ...layoutPaths])];
|
|
8917
9050
|
const isStale = manifestUsedIn.length !== fullActual.length || !manifestUsedIn.every((p) => fullActual.includes(p));
|
|
8918
9051
|
if (isStale) _staleUsedIn++;
|
|
8919
9052
|
if (totalUsage === 0) {
|
|
@@ -8924,7 +9057,7 @@ async function checkCommand(opts = {}) {
|
|
|
8924
9057
|
}
|
|
8925
9058
|
} else {
|
|
8926
9059
|
consistent++;
|
|
8927
|
-
const usageDesc =
|
|
9060
|
+
const usageDesc = layoutPaths.length > 0 ? `layout(${layoutPaths.length}) + ${actualUsedIn.length} page(s)` : `${actualUsedIn.length} page(s)`;
|
|
8928
9061
|
if (!opts.json) {
|
|
8929
9062
|
const staleNote = isStale ? chalk16.yellow(" [usedIn stale]") : "";
|
|
8930
9063
|
console.log(chalk16.green(` \u2714 ${entry.id} (${entry.name})`) + chalk16.dim(` \u2014 ${usageDesc}`) + staleNote);
|
|
@@ -8962,7 +9095,7 @@ async function checkCommand(opts = {}) {
|
|
|
8962
9095
|
id: e.id,
|
|
8963
9096
|
name: e.name,
|
|
8964
9097
|
type: e.type,
|
|
8965
|
-
status:
|
|
9098
|
+
status: existsSync18(resolve11(projectRoot, e.file)) ? "ok" : "unused",
|
|
8966
9099
|
message: "",
|
|
8967
9100
|
suggestions: void 0
|
|
8968
9101
|
}))
|
|
@@ -8976,11 +9109,11 @@ async function checkCommand(opts = {}) {
|
|
|
8976
9109
|
const { inferPageTypeFromRoute: inferPageTypeFromRoute2 } = await import("./design-constraints-EIP2XM7T.js");
|
|
8977
9110
|
const manifest = await loadManifest10(projectRoot);
|
|
8978
9111
|
const appDir = resolve11(projectRoot, "app");
|
|
8979
|
-
const pageFiles =
|
|
9112
|
+
const pageFiles = existsSync18(appDir) ? findTsxFiles(appDir) : [];
|
|
8980
9113
|
if (manifest.shared.length > 0 && pageFiles.length > 0) {
|
|
8981
9114
|
const reuseWarnings = [];
|
|
8982
9115
|
for (const file of pageFiles) {
|
|
8983
|
-
const code =
|
|
9116
|
+
const code = readFileSync14(file, "utf-8");
|
|
8984
9117
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
8985
9118
|
const route = "/" + relativePath.replace(/^app\//, "").replace(/\/page\.tsx$/, "").replace(/^\(.*?\)\//, "");
|
|
8986
9119
|
const pageType = inferPageTypeFromRoute2(route);
|
|
@@ -9091,12 +9224,12 @@ import {
|
|
|
9091
9224
|
generateSharedComponent as generateSharedComponent4,
|
|
9092
9225
|
integrateSharedLayoutIntoRootLayout as integrateSharedLayoutIntoRootLayout2
|
|
9093
9226
|
} from "@getcoherent/core";
|
|
9094
|
-
import { existsSync as
|
|
9227
|
+
import { existsSync as existsSync19 } from "fs";
|
|
9095
9228
|
import { resolve as resolve12 } from "path";
|
|
9096
9229
|
|
|
9097
9230
|
// src/utils/ds-files.ts
|
|
9098
9231
|
import { mkdir as mkdir3, writeFile as writeFile4 } from "fs/promises";
|
|
9099
|
-
import { join as
|
|
9232
|
+
import { join as join13, dirname as dirname5 } from "path";
|
|
9100
9233
|
import { DesignSystemGenerator } from "@getcoherent/core";
|
|
9101
9234
|
var SHARED_DS_KEYS = [
|
|
9102
9235
|
"app/design-system/shared/page.tsx",
|
|
@@ -9110,7 +9243,7 @@ async function writeDesignSystemFiles(projectRoot, config2, options) {
|
|
|
9110
9243
|
const toWrite = options?.sharedOnly ? new Map([...files].filter(([path3]) => SHARED_DS_KEYS.includes(path3))) : files;
|
|
9111
9244
|
const written = [];
|
|
9112
9245
|
for (const [relativePath, content] of toWrite) {
|
|
9113
|
-
const fullPath =
|
|
9246
|
+
const fullPath = join13(projectRoot, relativePath);
|
|
9114
9247
|
await mkdir3(dirname5(fullPath), { recursive: true });
|
|
9115
9248
|
await writeFile4(fullPath, content, "utf-8");
|
|
9116
9249
|
written.push(relativePath);
|
|
@@ -9246,7 +9379,7 @@ function createComponentsCommand() {
|
|
|
9246
9379
|
if (updated) console.log(chalk22.cyan(" Updated app/layout.tsx to use shared layout components.\n"));
|
|
9247
9380
|
}
|
|
9248
9381
|
const sharedPagePath = resolve12(project.root, "app/design-system/shared/page.tsx");
|
|
9249
|
-
if (!
|
|
9382
|
+
if (!existsSync19(sharedPagePath)) {
|
|
9250
9383
|
try {
|
|
9251
9384
|
const dsm = new DesignSystemManager10(project.configPath);
|
|
9252
9385
|
await dsm.load();
|
|
@@ -9272,8 +9405,8 @@ function createComponentsCommand() {
|
|
|
9272
9405
|
import chalk23 from "chalk";
|
|
9273
9406
|
import ora6 from "ora";
|
|
9274
9407
|
import { writeFile as writeFile5, mkdir as mkdir4 } from "fs/promises";
|
|
9275
|
-
import { resolve as resolve13, join as
|
|
9276
|
-
import { existsSync as
|
|
9408
|
+
import { resolve as resolve13, join as join14, dirname as dirname6 } from "path";
|
|
9409
|
+
import { existsSync as existsSync20 } from "fs";
|
|
9277
9410
|
import {
|
|
9278
9411
|
FigmaClient,
|
|
9279
9412
|
parseFigmaFileResponse,
|
|
@@ -9420,7 +9553,7 @@ async function importFigmaAction(urlOrKey, opts) {
|
|
|
9420
9553
|
stats.filesWritten.push(filePath);
|
|
9421
9554
|
return;
|
|
9422
9555
|
}
|
|
9423
|
-
const fullPath =
|
|
9556
|
+
const fullPath = join14(projectRoot, filePath);
|
|
9424
9557
|
await mkdir4(dirname6(fullPath), { recursive: true });
|
|
9425
9558
|
await writeFile5(fullPath, content, "utf-8");
|
|
9426
9559
|
stats.filesWritten.push(filePath);
|
|
@@ -9522,7 +9655,7 @@ async function importFigmaAction(urlOrKey, opts) {
|
|
|
9522
9655
|
spinner.start("Updating design-system.config.ts...");
|
|
9523
9656
|
const configPath = resolve13(projectRoot, DESIGN_SYSTEM_CONFIG_PATH);
|
|
9524
9657
|
const dsm = new DesignSystemManager11(configPath);
|
|
9525
|
-
if (
|
|
9658
|
+
if (existsSync20(configPath)) {
|
|
9526
9659
|
await dsm.load();
|
|
9527
9660
|
const existing = dsm.getConfig();
|
|
9528
9661
|
dsm.updateConfig({
|
|
@@ -9551,8 +9684,8 @@ export const config = ${JSON.stringify(fullConfig, null, 2)} as const
|
|
|
9551
9684
|
stats.configUpdated = true;
|
|
9552
9685
|
spinner.succeed("design-system.config.ts updated");
|
|
9553
9686
|
spinner.start("Ensuring root layout...");
|
|
9554
|
-
const layoutPath =
|
|
9555
|
-
if (!
|
|
9687
|
+
const layoutPath = join14(projectRoot, "app/layout.tsx");
|
|
9688
|
+
if (!existsSync20(layoutPath)) {
|
|
9556
9689
|
await mkdir4(dirname6(layoutPath), { recursive: true });
|
|
9557
9690
|
await writeFile5(layoutPath, MINIMAL_ROOT_LAYOUT, "utf-8");
|
|
9558
9691
|
stats.filesWritten.push("app/layout.tsx");
|
|
@@ -9642,8 +9775,8 @@ async function dsRegenerateCommand() {
|
|
|
9642
9775
|
// src/commands/update.ts
|
|
9643
9776
|
import chalk25 from "chalk";
|
|
9644
9777
|
import ora8 from "ora";
|
|
9645
|
-
import { readFileSync as
|
|
9646
|
-
import { join as
|
|
9778
|
+
import { readFileSync as readFileSync15, existsSync as existsSync21 } from "fs";
|
|
9779
|
+
import { join as join15 } from "path";
|
|
9647
9780
|
import { DesignSystemManager as DesignSystemManager13, CLI_VERSION as CLI_VERSION4 } from "@getcoherent/core";
|
|
9648
9781
|
|
|
9649
9782
|
// src/utils/migrations.ts
|
|
@@ -9812,20 +9945,20 @@ var EXPECTED_CSS_VARS = [
|
|
|
9812
9945
|
"--sidebar-ring"
|
|
9813
9946
|
];
|
|
9814
9947
|
function checkMissingCssVars(projectRoot) {
|
|
9815
|
-
const globalsPath =
|
|
9816
|
-
if (!
|
|
9948
|
+
const globalsPath = join15(projectRoot, "app", "globals.css");
|
|
9949
|
+
if (!existsSync21(globalsPath)) return [];
|
|
9817
9950
|
try {
|
|
9818
|
-
const content =
|
|
9951
|
+
const content = readFileSync15(globalsPath, "utf-8");
|
|
9819
9952
|
return EXPECTED_CSS_VARS.filter((v) => !content.includes(v));
|
|
9820
9953
|
} catch {
|
|
9821
9954
|
return [];
|
|
9822
9955
|
}
|
|
9823
9956
|
}
|
|
9824
9957
|
function patchGlobalsCss(projectRoot, missingVars) {
|
|
9825
|
-
const globalsPath =
|
|
9826
|
-
if (!
|
|
9827
|
-
const { writeFileSync:
|
|
9828
|
-
let content =
|
|
9958
|
+
const globalsPath = join15(projectRoot, "app", "globals.css");
|
|
9959
|
+
if (!existsSync21(globalsPath) || missingVars.length === 0) return;
|
|
9960
|
+
const { writeFileSync: writeFileSync14 } = __require("fs");
|
|
9961
|
+
let content = readFileSync15(globalsPath, "utf-8");
|
|
9829
9962
|
const defaultValues = {
|
|
9830
9963
|
"--chart-1": "220 70% 50%",
|
|
9831
9964
|
"--chart-2": "160 60% 45%",
|
|
@@ -9853,7 +9986,7 @@ function patchGlobalsCss(projectRoot, missingVars) {
|
|
|
9853
9986
|
const lightSectionEnd = content.indexOf("}");
|
|
9854
9987
|
if (lightSectionEnd > 0) {
|
|
9855
9988
|
content = content.slice(0, lightSectionEnd) + "\n" + injection + "\n" + content.slice(lightSectionEnd);
|
|
9856
|
-
|
|
9989
|
+
writeFileSync14(globalsPath, content, "utf-8");
|
|
9857
9990
|
}
|
|
9858
9991
|
}
|
|
9859
9992
|
|
|
@@ -9903,26 +10036,26 @@ async function undoCommand(options) {
|
|
|
9903
10036
|
// src/commands/sync.ts
|
|
9904
10037
|
import chalk27 from "chalk";
|
|
9905
10038
|
import ora9 from "ora";
|
|
9906
|
-
import { existsSync as
|
|
9907
|
-
import { join as
|
|
10039
|
+
import { existsSync as existsSync22, readFileSync as readFileSync16 } from "fs";
|
|
10040
|
+
import { join as join16, relative as relative6, dirname as dirname7 } from "path";
|
|
9908
10041
|
import { readdir as readdir3, readFile as readFile4 } from "fs/promises";
|
|
9909
10042
|
import { DesignSystemManager as DesignSystemManager14 } from "@getcoherent/core";
|
|
9910
10043
|
import { loadManifest as loadManifest12, saveManifest as saveManifest6, findSharedComponent } from "@getcoherent/core";
|
|
9911
10044
|
function extractTokensFromProject(projectRoot) {
|
|
9912
10045
|
const lightColors = {};
|
|
9913
10046
|
const darkColors = {};
|
|
9914
|
-
const globalsPath =
|
|
9915
|
-
if (
|
|
9916
|
-
const css =
|
|
10047
|
+
const globalsPath = join16(projectRoot, "app", "globals.css");
|
|
10048
|
+
if (existsSync22(globalsPath)) {
|
|
10049
|
+
const css = readFileSync16(globalsPath, "utf-8");
|
|
9917
10050
|
const rootMatch = css.match(/:root\s*\{([^}]+)\}/s);
|
|
9918
10051
|
if (rootMatch) parseVarsInto(rootMatch[1], lightColors);
|
|
9919
10052
|
const darkMatch = css.match(/\.dark\s*\{([^}]+)\}/s);
|
|
9920
10053
|
if (darkMatch) parseVarsInto(darkMatch[1], darkColors);
|
|
9921
10054
|
}
|
|
9922
|
-
const layoutPath =
|
|
10055
|
+
const layoutPath = join16(projectRoot, "app", "layout.tsx");
|
|
9923
10056
|
let layoutCode = "";
|
|
9924
|
-
if (
|
|
9925
|
-
layoutCode =
|
|
10057
|
+
if (existsSync22(layoutPath)) {
|
|
10058
|
+
layoutCode = readFileSync16(layoutPath, "utf-8");
|
|
9926
10059
|
const rootInline = layoutCode.match(/:root\s*\{([^}]+)\}/s);
|
|
9927
10060
|
if (rootInline && Object.keys(lightColors).length === 0) {
|
|
9928
10061
|
parseVarsInto(rootInline[1], lightColors);
|
|
@@ -9940,7 +10073,7 @@ function extractTokensFromProject(projectRoot) {
|
|
|
9940
10073
|
defaultMode = "dark";
|
|
9941
10074
|
}
|
|
9942
10075
|
let radius;
|
|
9943
|
-
const allCss = [
|
|
10076
|
+
const allCss = [existsSync22(globalsPath) ? readFileSync16(globalsPath, "utf-8") : "", layoutCode].join("\n");
|
|
9944
10077
|
const radiusMatch = allCss.match(/--radius:\s*([^;]+);/);
|
|
9945
10078
|
if (radiusMatch) radius = radiusMatch[1].trim();
|
|
9946
10079
|
return {
|
|
@@ -9963,14 +10096,14 @@ function parseVarsInto(block, target) {
|
|
|
9963
10096
|
}
|
|
9964
10097
|
async function detectCustomComponents(projectRoot, allPageCode) {
|
|
9965
10098
|
const results = [];
|
|
9966
|
-
const componentsDir =
|
|
9967
|
-
if (!
|
|
10099
|
+
const componentsDir = join16(projectRoot, "components");
|
|
10100
|
+
if (!existsSync22(componentsDir)) return results;
|
|
9968
10101
|
const files = [];
|
|
9969
10102
|
await walkForTsx(componentsDir, files, ["ui"]);
|
|
9970
10103
|
const fileResults = await Promise.all(
|
|
9971
10104
|
files.map(async (filePath) => {
|
|
9972
10105
|
const code = await readFile4(filePath, "utf-8");
|
|
9973
|
-
const relFile =
|
|
10106
|
+
const relFile = relative6(projectRoot, filePath);
|
|
9974
10107
|
const exportedNames = extractExportedComponentNames2(code);
|
|
9975
10108
|
return exportedNames.map((name) => ({
|
|
9976
10109
|
name,
|
|
@@ -9991,7 +10124,7 @@ async function walkForTsx(dir, files, skipDirs) {
|
|
|
9991
10124
|
return;
|
|
9992
10125
|
}
|
|
9993
10126
|
for (const e of entries) {
|
|
9994
|
-
const full =
|
|
10127
|
+
const full = join16(dir, e.name);
|
|
9995
10128
|
if (e.isDirectory()) {
|
|
9996
10129
|
if (skipDirs.includes(e.name) || e.name.startsWith(".")) continue;
|
|
9997
10130
|
await walkForTsx(full, files, skipDirs);
|
|
@@ -10065,14 +10198,14 @@ async function discoverPages(appDir) {
|
|
|
10065
10198
|
return;
|
|
10066
10199
|
}
|
|
10067
10200
|
for (const entry of entries) {
|
|
10068
|
-
const full =
|
|
10201
|
+
const full = join16(dir, entry.name);
|
|
10069
10202
|
if (entry.isDirectory()) {
|
|
10070
10203
|
if (["design-system", "api", "_not-found"].includes(entry.name)) continue;
|
|
10071
10204
|
if (entry.name.startsWith(".")) continue;
|
|
10072
10205
|
await walk(full);
|
|
10073
10206
|
} else if (entry.name === "page.tsx" || entry.name === "page.jsx") {
|
|
10074
10207
|
const code = await readFile4(full, "utf-8");
|
|
10075
|
-
const routeDir = dirname7(
|
|
10208
|
+
const routeDir = dirname7(relative6(appDir, full));
|
|
10076
10209
|
let route = routeDir === "." ? "/" : "/" + routeDir;
|
|
10077
10210
|
route = route.replace(/\/\([^)]+\)/g, "");
|
|
10078
10211
|
if (!route.startsWith("/")) route = "/" + route;
|
|
@@ -10154,8 +10287,8 @@ async function syncCommand(options = {}) {
|
|
|
10154
10287
|
if (dryRun) console.log(chalk27.yellow(" [dry-run] No files will be written\n"));
|
|
10155
10288
|
const spinner = ora9("Scanning project files...").start();
|
|
10156
10289
|
try {
|
|
10157
|
-
const appDir =
|
|
10158
|
-
if (!
|
|
10290
|
+
const appDir = join16(project.root, "app");
|
|
10291
|
+
if (!existsSync22(appDir)) {
|
|
10159
10292
|
spinner.fail("No app/ directory found");
|
|
10160
10293
|
process.exit(1);
|
|
10161
10294
|
}
|
|
@@ -10385,53 +10518,53 @@ async function syncCommand(options = {}) {
|
|
|
10385
10518
|
// src/commands/migrate.ts
|
|
10386
10519
|
import chalk28 from "chalk";
|
|
10387
10520
|
import ora10 from "ora";
|
|
10388
|
-
import { existsSync as
|
|
10389
|
-
import { join as
|
|
10521
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync8, cpSync, rmSync as rmSync6, writeFileSync as writeFileSync12, readFileSync as readFileSync17, readdirSync as readdirSync9 } from "fs";
|
|
10522
|
+
import { join as join17 } from "path";
|
|
10390
10523
|
function backupDir(projectRoot) {
|
|
10391
10524
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
10392
|
-
return
|
|
10525
|
+
return join17(projectRoot, ".coherent", "backups", `pre-migrate-${ts}`);
|
|
10393
10526
|
}
|
|
10394
10527
|
function guardPath(projectRoot) {
|
|
10395
|
-
return
|
|
10528
|
+
return join17(projectRoot, ".coherent", "migration-in-progress");
|
|
10396
10529
|
}
|
|
10397
10530
|
function createBackup2(projectRoot) {
|
|
10398
|
-
const uiDir =
|
|
10531
|
+
const uiDir = join17(projectRoot, "components", "ui");
|
|
10399
10532
|
const dest = backupDir(projectRoot);
|
|
10400
10533
|
mkdirSync8(dest, { recursive: true });
|
|
10401
|
-
if (
|
|
10402
|
-
cpSync(uiDir,
|
|
10534
|
+
if (existsSync23(uiDir)) {
|
|
10535
|
+
cpSync(uiDir, join17(dest, "components-ui"), { recursive: true });
|
|
10403
10536
|
}
|
|
10404
|
-
const configPath =
|
|
10405
|
-
if (
|
|
10406
|
-
cpSync(configPath,
|
|
10537
|
+
const configPath = join17(projectRoot, "design-system.config.ts");
|
|
10538
|
+
if (existsSync23(configPath)) {
|
|
10539
|
+
cpSync(configPath, join17(dest, "design-system.config.ts"));
|
|
10407
10540
|
}
|
|
10408
10541
|
return dest;
|
|
10409
10542
|
}
|
|
10410
10543
|
function setGuard(projectRoot, backupPath) {
|
|
10411
10544
|
const guard = guardPath(projectRoot);
|
|
10412
|
-
mkdirSync8(
|
|
10413
|
-
|
|
10545
|
+
mkdirSync8(join17(projectRoot, ".coherent"), { recursive: true });
|
|
10546
|
+
writeFileSync12(guard, JSON.stringify({ backup: backupPath, startedAt: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
10414
10547
|
}
|
|
10415
10548
|
function clearGuard(projectRoot) {
|
|
10416
10549
|
const guard = guardPath(projectRoot);
|
|
10417
|
-
if (
|
|
10550
|
+
if (existsSync23(guard)) rmSync6(guard);
|
|
10418
10551
|
}
|
|
10419
10552
|
function rollback(projectRoot) {
|
|
10420
10553
|
const guard = guardPath(projectRoot);
|
|
10421
|
-
if (!
|
|
10554
|
+
if (!existsSync23(guard)) return false;
|
|
10422
10555
|
try {
|
|
10423
|
-
const data = JSON.parse(
|
|
10556
|
+
const data = JSON.parse(readFileSync17(guard, "utf-8"));
|
|
10424
10557
|
const backup = data.backup;
|
|
10425
|
-
if (!
|
|
10426
|
-
const uiBackup =
|
|
10427
|
-
const uiDir =
|
|
10428
|
-
if (
|
|
10429
|
-
if (
|
|
10558
|
+
if (!existsSync23(backup)) return false;
|
|
10559
|
+
const uiBackup = join17(backup, "components-ui");
|
|
10560
|
+
const uiDir = join17(projectRoot, "components", "ui");
|
|
10561
|
+
if (existsSync23(uiBackup)) {
|
|
10562
|
+
if (existsSync23(uiDir)) rmSync6(uiDir, { recursive: true });
|
|
10430
10563
|
cpSync(uiBackup, uiDir, { recursive: true });
|
|
10431
10564
|
}
|
|
10432
|
-
const configBackup =
|
|
10433
|
-
const configDest =
|
|
10434
|
-
if (
|
|
10565
|
+
const configBackup = join17(backup, "design-system.config.ts");
|
|
10566
|
+
const configDest = join17(projectRoot, "design-system.config.ts");
|
|
10567
|
+
if (existsSync23(configBackup)) {
|
|
10435
10568
|
cpSync(configBackup, configDest);
|
|
10436
10569
|
}
|
|
10437
10570
|
clearGuard(projectRoot);
|
|
@@ -10459,13 +10592,13 @@ async function migrateAction(options) {
|
|
|
10459
10592
|
return;
|
|
10460
10593
|
}
|
|
10461
10594
|
const guard = guardPath(projectRoot);
|
|
10462
|
-
if (
|
|
10595
|
+
if (existsSync23(guard)) {
|
|
10463
10596
|
console.log(chalk28.yellow("A migration is already in progress."));
|
|
10464
10597
|
console.log(chalk28.dim("Run `coherent migrate --rollback` to undo, or delete .coherent/migration-in-progress"));
|
|
10465
10598
|
return;
|
|
10466
10599
|
}
|
|
10467
|
-
const uiDir =
|
|
10468
|
-
if (!
|
|
10600
|
+
const uiDir = join17(projectRoot, "components", "ui");
|
|
10601
|
+
if (!existsSync23(uiDir)) {
|
|
10469
10602
|
console.log(chalk28.yellow("No components/ui directory found. Nothing to migrate."));
|
|
10470
10603
|
return;
|
|
10471
10604
|
}
|
|
@@ -10491,8 +10624,8 @@ Found ${migratable.length} component(s) to migrate:`));
|
|
|
10491
10624
|
setGuard(projectRoot, backup);
|
|
10492
10625
|
try {
|
|
10493
10626
|
for (const id of migratable) {
|
|
10494
|
-
const filePath =
|
|
10495
|
-
if (
|
|
10627
|
+
const filePath = join17(uiDir, `${id}.tsx`);
|
|
10628
|
+
if (existsSync23(filePath)) rmSync6(filePath);
|
|
10496
10629
|
}
|
|
10497
10630
|
const results = await provider.installBatch(migratable, projectRoot, { force: true });
|
|
10498
10631
|
let migrated = 0;
|
|
@@ -10514,20 +10647,20 @@ Found ${migratable.length} component(s) to migrate:`));
|
|
|
10514
10647
|
}
|
|
10515
10648
|
|
|
10516
10649
|
// src/utils/update-notifier.ts
|
|
10517
|
-
import { existsSync as
|
|
10518
|
-
import { join as
|
|
10650
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync9, readFileSync as readFileSync18, writeFileSync as writeFileSync13 } from "fs";
|
|
10651
|
+
import { join as join18 } from "path";
|
|
10519
10652
|
import { homedir } from "os";
|
|
10520
10653
|
import chalk29 from "chalk";
|
|
10521
10654
|
import { CLI_VERSION as CLI_VERSION5 } from "@getcoherent/core";
|
|
10522
10655
|
var DEBUG5 = process.env.COHERENT_DEBUG === "1";
|
|
10523
10656
|
var PACKAGE_NAME = "@getcoherent/cli";
|
|
10524
|
-
var CACHE_DIR =
|
|
10525
|
-
var CACHE_FILE =
|
|
10657
|
+
var CACHE_DIR = join18(homedir(), ".coherent");
|
|
10658
|
+
var CACHE_FILE = join18(CACHE_DIR, "update-check.json");
|
|
10526
10659
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
10527
10660
|
function readCache() {
|
|
10528
10661
|
try {
|
|
10529
|
-
if (!
|
|
10530
|
-
const raw =
|
|
10662
|
+
if (!existsSync24(CACHE_FILE)) return null;
|
|
10663
|
+
const raw = readFileSync18(CACHE_FILE, "utf-8");
|
|
10531
10664
|
return JSON.parse(raw);
|
|
10532
10665
|
} catch (e) {
|
|
10533
10666
|
if (DEBUG5) console.error("Failed to read update cache:", e);
|
|
@@ -10536,8 +10669,8 @@ function readCache() {
|
|
|
10536
10669
|
}
|
|
10537
10670
|
function writeCache(data) {
|
|
10538
10671
|
try {
|
|
10539
|
-
if (!
|
|
10540
|
-
|
|
10672
|
+
if (!existsSync24(CACHE_DIR)) mkdirSync9(CACHE_DIR, { recursive: true });
|
|
10673
|
+
writeFileSync13(CACHE_FILE, JSON.stringify(data), "utf-8");
|
|
10541
10674
|
} catch (e) {
|
|
10542
10675
|
if (DEBUG5) console.error("Failed to write update cache:", e);
|
|
10543
10676
|
}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.6.
|
|
6
|
+
"version": "0.6.40",
|
|
7
7
|
"description": "CLI interface for Coherent Design Method",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"main": "./dist/index.js",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"ora": "^7.0.1",
|
|
44
44
|
"prompts": "^2.4.2",
|
|
45
45
|
"zod": "^3.22.4",
|
|
46
|
-
"@getcoherent/core": "0.6.
|
|
46
|
+
"@getcoherent/core": "0.6.40"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@types/node": "^20.11.0",
|