@getcoherent/cli 0.6.38 → 0.6.39
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 +272 -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,69 @@ 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(sidebarComponentPath2, gen.generateSharedSidebarCode(), projectRoot, backups);
|
|
8649
|
+
if (sidebarResult2.ok) {
|
|
8650
|
+
fixes.push("Regenerated sidebar component");
|
|
8651
|
+
console.log(chalk15.green(" \u2714 Regenerated sidebar component"));
|
|
8652
|
+
} else {
|
|
8653
|
+
console.log(chalk15.yellow(" \u26A0 Sidebar regeneration failed validation \u2014 restored original"));
|
|
8654
|
+
}
|
|
8559
8655
|
}
|
|
8560
8656
|
}
|
|
8561
8657
|
const rootPagePath = resolve10(projectRoot, "app", "page.tsx");
|
|
8562
8658
|
const publicPagePath = resolve10(projectRoot, "app", "(public)", "page.tsx");
|
|
8563
|
-
if (
|
|
8659
|
+
if (existsSync17(rootPagePath) && !existsSync17(publicPagePath)) {
|
|
8564
8660
|
const { renameSync } = await import("fs");
|
|
8565
8661
|
mkdirSync7(resolve10(projectRoot, "app", "(public)"), { recursive: true });
|
|
8566
8662
|
renameSync(rootPagePath, publicPagePath);
|
|
@@ -8568,27 +8664,42 @@ async function fixCommand(opts = {}) {
|
|
|
8568
8664
|
console.log(chalk15.green(" \u2714 Moved app/page.tsx \u2192 app/(public)/page.tsx (gets Header/Footer)"));
|
|
8569
8665
|
}
|
|
8570
8666
|
const themeTogglePath = resolve10(projectRoot, "components", "shared", "theme-toggle.tsx");
|
|
8571
|
-
if (!
|
|
8667
|
+
if (!existsSync17(themeTogglePath)) {
|
|
8572
8668
|
const { generateThemeToggleCode } = await import("./code-generator-D3ZHOO4M.js");
|
|
8573
8669
|
mkdirSync7(resolve10(projectRoot, "components", "shared"), { recursive: true });
|
|
8574
|
-
|
|
8575
|
-
|
|
8576
|
-
|
|
8670
|
+
const themeResult = safeWrite(themeTogglePath, generateThemeToggleCode(), projectRoot, backups);
|
|
8671
|
+
if (themeResult.ok) {
|
|
8672
|
+
fixes.push("Generated ThemeToggle component (components/shared/theme-toggle.tsx)");
|
|
8673
|
+
console.log(chalk15.green(" \u2714 Generated ThemeToggle component"));
|
|
8674
|
+
} else {
|
|
8675
|
+
console.log(chalk15.yellow(" \u26A0 ThemeToggle generation failed validation"));
|
|
8676
|
+
}
|
|
8577
8677
|
}
|
|
8578
8678
|
}
|
|
8579
8679
|
}
|
|
8580
|
-
} catch {
|
|
8680
|
+
} catch (err) {
|
|
8681
|
+
console.log(chalk15.yellow(` \u26A0 Layout repair skipped: ${err instanceof Error ? err.message : "unknown error"}`));
|
|
8581
8682
|
}
|
|
8582
8683
|
if (!skipQuality) {
|
|
8583
8684
|
let qualityFixCount = 0;
|
|
8584
8685
|
const qualityFixDetails = [];
|
|
8585
8686
|
for (const file of userTsxFiles) {
|
|
8586
|
-
const content =
|
|
8687
|
+
const content = readFileSync13(file, "utf-8");
|
|
8587
8688
|
const { code: autoFixed, fixes: fileFixes } = await autoFixCode(content);
|
|
8588
8689
|
if (autoFixed !== content) {
|
|
8589
|
-
if (!dryRun)
|
|
8590
|
-
|
|
8591
|
-
|
|
8690
|
+
if (!dryRun) {
|
|
8691
|
+
const qResult = safeWrite(file, autoFixed, projectRoot, backups);
|
|
8692
|
+
if (qResult.ok) {
|
|
8693
|
+
modifiedFiles.push(file);
|
|
8694
|
+
qualityFixCount++;
|
|
8695
|
+
qualityFixDetails.push(...fileFixes);
|
|
8696
|
+
} else {
|
|
8697
|
+
console.log(chalk15.yellow(` \u26A0 Quality fix rolled back for ${relative5(projectRoot, file)} (parse error)`));
|
|
8698
|
+
}
|
|
8699
|
+
} else {
|
|
8700
|
+
qualityFixCount++;
|
|
8701
|
+
qualityFixDetails.push(...fileFixes);
|
|
8702
|
+
}
|
|
8592
8703
|
}
|
|
8593
8704
|
}
|
|
8594
8705
|
if (qualityFixCount > 0) {
|
|
@@ -8598,11 +8709,22 @@ async function fixCommand(opts = {}) {
|
|
|
8598
8709
|
console.log(chalk15.green(` \u2714 ${verb} ${uniqueFixes.length} quality issue type(s): ${uniqueFixes.join(", ")}`));
|
|
8599
8710
|
}
|
|
8600
8711
|
}
|
|
8712
|
+
for (const file of modifiedFiles) {
|
|
8713
|
+
if (!backups.has(file)) continue;
|
|
8714
|
+
const before = backups.get(file);
|
|
8715
|
+
const after = readFileSync13(file, "utf-8");
|
|
8716
|
+
const issues = verifyIncrementalEdit(before, after);
|
|
8717
|
+
if (issues.length > 0) {
|
|
8718
|
+
for (const issue of issues) {
|
|
8719
|
+
remaining.push(`${relative5(projectRoot, file)}: ${issue.message}`);
|
|
8720
|
+
}
|
|
8721
|
+
}
|
|
8722
|
+
}
|
|
8601
8723
|
let totalErrors = 0;
|
|
8602
8724
|
let totalWarnings = 0;
|
|
8603
8725
|
const fileIssues = [];
|
|
8604
8726
|
for (const file of allTsxFiles) {
|
|
8605
|
-
const code = dryRun ?
|
|
8727
|
+
const code = dryRun ? readFileSync13(file, "utf-8") : readFileSync13(file, "utf-8");
|
|
8606
8728
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
8607
8729
|
const baseName = file.split("/").pop() || "";
|
|
8608
8730
|
const isAuthPage = relativePath.includes("(auth)");
|
|
@@ -8653,8 +8775,8 @@ async function fixCommand(opts = {}) {
|
|
|
8653
8775
|
}
|
|
8654
8776
|
for (const entry of manifest.shared) {
|
|
8655
8777
|
const actualUsedIn = findPagesImporting(project.root, entry.name, entry.file);
|
|
8656
|
-
const
|
|
8657
|
-
const fullActual =
|
|
8778
|
+
const layoutPaths = isUsedInLayout(project.root, entry.name);
|
|
8779
|
+
const fullActual = [.../* @__PURE__ */ new Set([...actualUsedIn, ...layoutPaths])];
|
|
8658
8780
|
if (!arraysEqual(fullActual, entry.usedIn || [])) {
|
|
8659
8781
|
entry.usedIn = fullActual;
|
|
8660
8782
|
manifestModified = true;
|
|
@@ -8691,12 +8813,16 @@ async function fixCommand(opts = {}) {
|
|
|
8691
8813
|
}
|
|
8692
8814
|
for (const entry of manifest.shared) {
|
|
8693
8815
|
const actualUsedIn = findPagesImporting(project.root, entry.name, entry.file);
|
|
8694
|
-
const
|
|
8695
|
-
if (actualUsedIn.length === 0 &&
|
|
8816
|
+
const layoutPaths2 = isUsedInLayout(project.root, entry.name);
|
|
8817
|
+
if (actualUsedIn.length === 0 && layoutPaths2.length === 0) {
|
|
8696
8818
|
remaining.push(`${entry.id} (${entry.name}) \u2014 unused. Remove: coherent components shared remove ${entry.id}`);
|
|
8697
8819
|
}
|
|
8698
8820
|
}
|
|
8699
|
-
} catch {
|
|
8821
|
+
} catch (err) {
|
|
8822
|
+
const isNotFound = err instanceof Error && "code" in err && err.code === "ENOENT";
|
|
8823
|
+
if (!isNotFound) {
|
|
8824
|
+
console.log(chalk15.yellow(` \u26A0 Component manifest check skipped: ${err instanceof Error ? err.message : "unknown error"}`));
|
|
8825
|
+
}
|
|
8700
8826
|
}
|
|
8701
8827
|
if (fixes.length === 0 && totalErrors === 0 && totalWarnings === 0 && remaining.length === 0) {
|
|
8702
8828
|
console.log(chalk15.green("\n \u2705 Everything looks good \u2014 no issues found\n"));
|
|
@@ -8727,7 +8853,7 @@ async function fixCommand(opts = {}) {
|
|
|
8727
8853
|
// src/commands/check.ts
|
|
8728
8854
|
import chalk16 from "chalk";
|
|
8729
8855
|
import { resolve as resolve11 } from "path";
|
|
8730
|
-
import { readdirSync as readdirSync8, readFileSync as
|
|
8856
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync14, statSync as statSync3, existsSync as existsSync18 } from "fs";
|
|
8731
8857
|
import { loadManifest as loadManifest10 } from "@getcoherent/core";
|
|
8732
8858
|
var EXCLUDED_DIRS = /* @__PURE__ */ new Set(["node_modules", "design-system"]);
|
|
8733
8859
|
function findTsxFiles(dir) {
|
|
@@ -8784,7 +8910,7 @@ async function checkCommand(opts = {}) {
|
|
|
8784
8910
|
"NATIVE_TABLE"
|
|
8785
8911
|
]);
|
|
8786
8912
|
for (const file of files) {
|
|
8787
|
-
const code =
|
|
8913
|
+
const code = readFileSync14(file, "utf-8");
|
|
8788
8914
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
8789
8915
|
const baseName = file.split("/").pop() || "";
|
|
8790
8916
|
const isAuthPage = relativePath.includes("(auth)");
|
|
@@ -8826,7 +8952,7 @@ async function checkCommand(opts = {}) {
|
|
|
8826
8952
|
routeSet.add("/");
|
|
8827
8953
|
routeSet.add("#");
|
|
8828
8954
|
for (const file of files) {
|
|
8829
|
-
const code =
|
|
8955
|
+
const code = readFileSync14(file, "utf-8");
|
|
8830
8956
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
8831
8957
|
const lines = code.split("\n");
|
|
8832
8958
|
const linkHrefRe = /href\s*=\s*["'](\/[a-z0-9/-]*)["']/gi;
|
|
@@ -8859,7 +8985,7 @@ async function checkCommand(opts = {}) {
|
|
|
8859
8985
|
if (manifest.shared.length > 0) {
|
|
8860
8986
|
for (const entry of manifest.shared) {
|
|
8861
8987
|
const fullPath = resolve11(project.root, entry.file);
|
|
8862
|
-
if (!
|
|
8988
|
+
if (!existsSync18(fullPath)) {
|
|
8863
8989
|
result.pages.withErrors++;
|
|
8864
8990
|
if (!opts.json) console.log(chalk16.red(`
|
|
8865
8991
|
\u2717 Missing shared component file: ${entry.id} (${entry.file})`));
|
|
@@ -8884,7 +9010,7 @@ async function checkCommand(opts = {}) {
|
|
|
8884
9010
|
let _nameMismatch = 0;
|
|
8885
9011
|
for (const entry of manifest.shared) {
|
|
8886
9012
|
const filePath = resolve11(projectRoot, entry.file);
|
|
8887
|
-
const fileExists =
|
|
9013
|
+
const fileExists = existsSync18(filePath);
|
|
8888
9014
|
if (!fileExists) {
|
|
8889
9015
|
_orphaned++;
|
|
8890
9016
|
if (!opts.json) {
|
|
@@ -8894,7 +9020,7 @@ async function checkCommand(opts = {}) {
|
|
|
8894
9020
|
continue;
|
|
8895
9021
|
}
|
|
8896
9022
|
try {
|
|
8897
|
-
const code =
|
|
9023
|
+
const code = readFileSync14(filePath, "utf-8");
|
|
8898
9024
|
const actualExports = extractExportedComponentNames(code);
|
|
8899
9025
|
if (actualExports.length > 0 && !actualExports.includes(entry.name)) {
|
|
8900
9026
|
_nameMismatch++;
|
|
@@ -8910,10 +9036,10 @@ async function checkCommand(opts = {}) {
|
|
|
8910
9036
|
} catch {
|
|
8911
9037
|
}
|
|
8912
9038
|
const actualUsedIn = findPagesImporting(projectRoot, entry.name, entry.file);
|
|
8913
|
-
const
|
|
8914
|
-
const totalUsage = actualUsedIn.length +
|
|
9039
|
+
const layoutPaths = isUsedInLayout(projectRoot, entry.name);
|
|
9040
|
+
const totalUsage = actualUsedIn.length + layoutPaths.length;
|
|
8915
9041
|
const manifestUsedIn = entry.usedIn || [];
|
|
8916
|
-
const fullActual =
|
|
9042
|
+
const fullActual = [.../* @__PURE__ */ new Set([...actualUsedIn, ...layoutPaths])];
|
|
8917
9043
|
const isStale = manifestUsedIn.length !== fullActual.length || !manifestUsedIn.every((p) => fullActual.includes(p));
|
|
8918
9044
|
if (isStale) _staleUsedIn++;
|
|
8919
9045
|
if (totalUsage === 0) {
|
|
@@ -8924,7 +9050,7 @@ async function checkCommand(opts = {}) {
|
|
|
8924
9050
|
}
|
|
8925
9051
|
} else {
|
|
8926
9052
|
consistent++;
|
|
8927
|
-
const usageDesc =
|
|
9053
|
+
const usageDesc = layoutPaths.length > 0 ? `layout(${layoutPaths.length}) + ${actualUsedIn.length} page(s)` : `${actualUsedIn.length} page(s)`;
|
|
8928
9054
|
if (!opts.json) {
|
|
8929
9055
|
const staleNote = isStale ? chalk16.yellow(" [usedIn stale]") : "";
|
|
8930
9056
|
console.log(chalk16.green(` \u2714 ${entry.id} (${entry.name})`) + chalk16.dim(` \u2014 ${usageDesc}`) + staleNote);
|
|
@@ -8962,7 +9088,7 @@ async function checkCommand(opts = {}) {
|
|
|
8962
9088
|
id: e.id,
|
|
8963
9089
|
name: e.name,
|
|
8964
9090
|
type: e.type,
|
|
8965
|
-
status:
|
|
9091
|
+
status: existsSync18(resolve11(projectRoot, e.file)) ? "ok" : "unused",
|
|
8966
9092
|
message: "",
|
|
8967
9093
|
suggestions: void 0
|
|
8968
9094
|
}))
|
|
@@ -8976,11 +9102,11 @@ async function checkCommand(opts = {}) {
|
|
|
8976
9102
|
const { inferPageTypeFromRoute: inferPageTypeFromRoute2 } = await import("./design-constraints-EIP2XM7T.js");
|
|
8977
9103
|
const manifest = await loadManifest10(projectRoot);
|
|
8978
9104
|
const appDir = resolve11(projectRoot, "app");
|
|
8979
|
-
const pageFiles =
|
|
9105
|
+
const pageFiles = existsSync18(appDir) ? findTsxFiles(appDir) : [];
|
|
8980
9106
|
if (manifest.shared.length > 0 && pageFiles.length > 0) {
|
|
8981
9107
|
const reuseWarnings = [];
|
|
8982
9108
|
for (const file of pageFiles) {
|
|
8983
|
-
const code =
|
|
9109
|
+
const code = readFileSync14(file, "utf-8");
|
|
8984
9110
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
8985
9111
|
const route = "/" + relativePath.replace(/^app\//, "").replace(/\/page\.tsx$/, "").replace(/^\(.*?\)\//, "");
|
|
8986
9112
|
const pageType = inferPageTypeFromRoute2(route);
|
|
@@ -9091,12 +9217,12 @@ import {
|
|
|
9091
9217
|
generateSharedComponent as generateSharedComponent4,
|
|
9092
9218
|
integrateSharedLayoutIntoRootLayout as integrateSharedLayoutIntoRootLayout2
|
|
9093
9219
|
} from "@getcoherent/core";
|
|
9094
|
-
import { existsSync as
|
|
9220
|
+
import { existsSync as existsSync19 } from "fs";
|
|
9095
9221
|
import { resolve as resolve12 } from "path";
|
|
9096
9222
|
|
|
9097
9223
|
// src/utils/ds-files.ts
|
|
9098
9224
|
import { mkdir as mkdir3, writeFile as writeFile4 } from "fs/promises";
|
|
9099
|
-
import { join as
|
|
9225
|
+
import { join as join13, dirname as dirname5 } from "path";
|
|
9100
9226
|
import { DesignSystemGenerator } from "@getcoherent/core";
|
|
9101
9227
|
var SHARED_DS_KEYS = [
|
|
9102
9228
|
"app/design-system/shared/page.tsx",
|
|
@@ -9110,7 +9236,7 @@ async function writeDesignSystemFiles(projectRoot, config2, options) {
|
|
|
9110
9236
|
const toWrite = options?.sharedOnly ? new Map([...files].filter(([path3]) => SHARED_DS_KEYS.includes(path3))) : files;
|
|
9111
9237
|
const written = [];
|
|
9112
9238
|
for (const [relativePath, content] of toWrite) {
|
|
9113
|
-
const fullPath =
|
|
9239
|
+
const fullPath = join13(projectRoot, relativePath);
|
|
9114
9240
|
await mkdir3(dirname5(fullPath), { recursive: true });
|
|
9115
9241
|
await writeFile4(fullPath, content, "utf-8");
|
|
9116
9242
|
written.push(relativePath);
|
|
@@ -9246,7 +9372,7 @@ function createComponentsCommand() {
|
|
|
9246
9372
|
if (updated) console.log(chalk22.cyan(" Updated app/layout.tsx to use shared layout components.\n"));
|
|
9247
9373
|
}
|
|
9248
9374
|
const sharedPagePath = resolve12(project.root, "app/design-system/shared/page.tsx");
|
|
9249
|
-
if (!
|
|
9375
|
+
if (!existsSync19(sharedPagePath)) {
|
|
9250
9376
|
try {
|
|
9251
9377
|
const dsm = new DesignSystemManager10(project.configPath);
|
|
9252
9378
|
await dsm.load();
|
|
@@ -9272,8 +9398,8 @@ function createComponentsCommand() {
|
|
|
9272
9398
|
import chalk23 from "chalk";
|
|
9273
9399
|
import ora6 from "ora";
|
|
9274
9400
|
import { writeFile as writeFile5, mkdir as mkdir4 } from "fs/promises";
|
|
9275
|
-
import { resolve as resolve13, join as
|
|
9276
|
-
import { existsSync as
|
|
9401
|
+
import { resolve as resolve13, join as join14, dirname as dirname6 } from "path";
|
|
9402
|
+
import { existsSync as existsSync20 } from "fs";
|
|
9277
9403
|
import {
|
|
9278
9404
|
FigmaClient,
|
|
9279
9405
|
parseFigmaFileResponse,
|
|
@@ -9420,7 +9546,7 @@ async function importFigmaAction(urlOrKey, opts) {
|
|
|
9420
9546
|
stats.filesWritten.push(filePath);
|
|
9421
9547
|
return;
|
|
9422
9548
|
}
|
|
9423
|
-
const fullPath =
|
|
9549
|
+
const fullPath = join14(projectRoot, filePath);
|
|
9424
9550
|
await mkdir4(dirname6(fullPath), { recursive: true });
|
|
9425
9551
|
await writeFile5(fullPath, content, "utf-8");
|
|
9426
9552
|
stats.filesWritten.push(filePath);
|
|
@@ -9522,7 +9648,7 @@ async function importFigmaAction(urlOrKey, opts) {
|
|
|
9522
9648
|
spinner.start("Updating design-system.config.ts...");
|
|
9523
9649
|
const configPath = resolve13(projectRoot, DESIGN_SYSTEM_CONFIG_PATH);
|
|
9524
9650
|
const dsm = new DesignSystemManager11(configPath);
|
|
9525
|
-
if (
|
|
9651
|
+
if (existsSync20(configPath)) {
|
|
9526
9652
|
await dsm.load();
|
|
9527
9653
|
const existing = dsm.getConfig();
|
|
9528
9654
|
dsm.updateConfig({
|
|
@@ -9551,8 +9677,8 @@ export const config = ${JSON.stringify(fullConfig, null, 2)} as const
|
|
|
9551
9677
|
stats.configUpdated = true;
|
|
9552
9678
|
spinner.succeed("design-system.config.ts updated");
|
|
9553
9679
|
spinner.start("Ensuring root layout...");
|
|
9554
|
-
const layoutPath =
|
|
9555
|
-
if (!
|
|
9680
|
+
const layoutPath = join14(projectRoot, "app/layout.tsx");
|
|
9681
|
+
if (!existsSync20(layoutPath)) {
|
|
9556
9682
|
await mkdir4(dirname6(layoutPath), { recursive: true });
|
|
9557
9683
|
await writeFile5(layoutPath, MINIMAL_ROOT_LAYOUT, "utf-8");
|
|
9558
9684
|
stats.filesWritten.push("app/layout.tsx");
|
|
@@ -9642,8 +9768,8 @@ async function dsRegenerateCommand() {
|
|
|
9642
9768
|
// src/commands/update.ts
|
|
9643
9769
|
import chalk25 from "chalk";
|
|
9644
9770
|
import ora8 from "ora";
|
|
9645
|
-
import { readFileSync as
|
|
9646
|
-
import { join as
|
|
9771
|
+
import { readFileSync as readFileSync15, existsSync as existsSync21 } from "fs";
|
|
9772
|
+
import { join as join15 } from "path";
|
|
9647
9773
|
import { DesignSystemManager as DesignSystemManager13, CLI_VERSION as CLI_VERSION4 } from "@getcoherent/core";
|
|
9648
9774
|
|
|
9649
9775
|
// src/utils/migrations.ts
|
|
@@ -9812,20 +9938,20 @@ var EXPECTED_CSS_VARS = [
|
|
|
9812
9938
|
"--sidebar-ring"
|
|
9813
9939
|
];
|
|
9814
9940
|
function checkMissingCssVars(projectRoot) {
|
|
9815
|
-
const globalsPath =
|
|
9816
|
-
if (!
|
|
9941
|
+
const globalsPath = join15(projectRoot, "app", "globals.css");
|
|
9942
|
+
if (!existsSync21(globalsPath)) return [];
|
|
9817
9943
|
try {
|
|
9818
|
-
const content =
|
|
9944
|
+
const content = readFileSync15(globalsPath, "utf-8");
|
|
9819
9945
|
return EXPECTED_CSS_VARS.filter((v) => !content.includes(v));
|
|
9820
9946
|
} catch {
|
|
9821
9947
|
return [];
|
|
9822
9948
|
}
|
|
9823
9949
|
}
|
|
9824
9950
|
function patchGlobalsCss(projectRoot, missingVars) {
|
|
9825
|
-
const globalsPath =
|
|
9826
|
-
if (!
|
|
9827
|
-
const { writeFileSync:
|
|
9828
|
-
let content =
|
|
9951
|
+
const globalsPath = join15(projectRoot, "app", "globals.css");
|
|
9952
|
+
if (!existsSync21(globalsPath) || missingVars.length === 0) return;
|
|
9953
|
+
const { writeFileSync: writeFileSync14 } = __require("fs");
|
|
9954
|
+
let content = readFileSync15(globalsPath, "utf-8");
|
|
9829
9955
|
const defaultValues = {
|
|
9830
9956
|
"--chart-1": "220 70% 50%",
|
|
9831
9957
|
"--chart-2": "160 60% 45%",
|
|
@@ -9853,7 +9979,7 @@ function patchGlobalsCss(projectRoot, missingVars) {
|
|
|
9853
9979
|
const lightSectionEnd = content.indexOf("}");
|
|
9854
9980
|
if (lightSectionEnd > 0) {
|
|
9855
9981
|
content = content.slice(0, lightSectionEnd) + "\n" + injection + "\n" + content.slice(lightSectionEnd);
|
|
9856
|
-
|
|
9982
|
+
writeFileSync14(globalsPath, content, "utf-8");
|
|
9857
9983
|
}
|
|
9858
9984
|
}
|
|
9859
9985
|
|
|
@@ -9903,26 +10029,26 @@ async function undoCommand(options) {
|
|
|
9903
10029
|
// src/commands/sync.ts
|
|
9904
10030
|
import chalk27 from "chalk";
|
|
9905
10031
|
import ora9 from "ora";
|
|
9906
|
-
import { existsSync as
|
|
9907
|
-
import { join as
|
|
10032
|
+
import { existsSync as existsSync22, readFileSync as readFileSync16 } from "fs";
|
|
10033
|
+
import { join as join16, relative as relative6, dirname as dirname7 } from "path";
|
|
9908
10034
|
import { readdir as readdir3, readFile as readFile4 } from "fs/promises";
|
|
9909
10035
|
import { DesignSystemManager as DesignSystemManager14 } from "@getcoherent/core";
|
|
9910
10036
|
import { loadManifest as loadManifest12, saveManifest as saveManifest6, findSharedComponent } from "@getcoherent/core";
|
|
9911
10037
|
function extractTokensFromProject(projectRoot) {
|
|
9912
10038
|
const lightColors = {};
|
|
9913
10039
|
const darkColors = {};
|
|
9914
|
-
const globalsPath =
|
|
9915
|
-
if (
|
|
9916
|
-
const css =
|
|
10040
|
+
const globalsPath = join16(projectRoot, "app", "globals.css");
|
|
10041
|
+
if (existsSync22(globalsPath)) {
|
|
10042
|
+
const css = readFileSync16(globalsPath, "utf-8");
|
|
9917
10043
|
const rootMatch = css.match(/:root\s*\{([^}]+)\}/s);
|
|
9918
10044
|
if (rootMatch) parseVarsInto(rootMatch[1], lightColors);
|
|
9919
10045
|
const darkMatch = css.match(/\.dark\s*\{([^}]+)\}/s);
|
|
9920
10046
|
if (darkMatch) parseVarsInto(darkMatch[1], darkColors);
|
|
9921
10047
|
}
|
|
9922
|
-
const layoutPath =
|
|
10048
|
+
const layoutPath = join16(projectRoot, "app", "layout.tsx");
|
|
9923
10049
|
let layoutCode = "";
|
|
9924
|
-
if (
|
|
9925
|
-
layoutCode =
|
|
10050
|
+
if (existsSync22(layoutPath)) {
|
|
10051
|
+
layoutCode = readFileSync16(layoutPath, "utf-8");
|
|
9926
10052
|
const rootInline = layoutCode.match(/:root\s*\{([^}]+)\}/s);
|
|
9927
10053
|
if (rootInline && Object.keys(lightColors).length === 0) {
|
|
9928
10054
|
parseVarsInto(rootInline[1], lightColors);
|
|
@@ -9940,7 +10066,7 @@ function extractTokensFromProject(projectRoot) {
|
|
|
9940
10066
|
defaultMode = "dark";
|
|
9941
10067
|
}
|
|
9942
10068
|
let radius;
|
|
9943
|
-
const allCss = [
|
|
10069
|
+
const allCss = [existsSync22(globalsPath) ? readFileSync16(globalsPath, "utf-8") : "", layoutCode].join("\n");
|
|
9944
10070
|
const radiusMatch = allCss.match(/--radius:\s*([^;]+);/);
|
|
9945
10071
|
if (radiusMatch) radius = radiusMatch[1].trim();
|
|
9946
10072
|
return {
|
|
@@ -9963,14 +10089,14 @@ function parseVarsInto(block, target) {
|
|
|
9963
10089
|
}
|
|
9964
10090
|
async function detectCustomComponents(projectRoot, allPageCode) {
|
|
9965
10091
|
const results = [];
|
|
9966
|
-
const componentsDir =
|
|
9967
|
-
if (!
|
|
10092
|
+
const componentsDir = join16(projectRoot, "components");
|
|
10093
|
+
if (!existsSync22(componentsDir)) return results;
|
|
9968
10094
|
const files = [];
|
|
9969
10095
|
await walkForTsx(componentsDir, files, ["ui"]);
|
|
9970
10096
|
const fileResults = await Promise.all(
|
|
9971
10097
|
files.map(async (filePath) => {
|
|
9972
10098
|
const code = await readFile4(filePath, "utf-8");
|
|
9973
|
-
const relFile =
|
|
10099
|
+
const relFile = relative6(projectRoot, filePath);
|
|
9974
10100
|
const exportedNames = extractExportedComponentNames2(code);
|
|
9975
10101
|
return exportedNames.map((name) => ({
|
|
9976
10102
|
name,
|
|
@@ -9991,7 +10117,7 @@ async function walkForTsx(dir, files, skipDirs) {
|
|
|
9991
10117
|
return;
|
|
9992
10118
|
}
|
|
9993
10119
|
for (const e of entries) {
|
|
9994
|
-
const full =
|
|
10120
|
+
const full = join16(dir, e.name);
|
|
9995
10121
|
if (e.isDirectory()) {
|
|
9996
10122
|
if (skipDirs.includes(e.name) || e.name.startsWith(".")) continue;
|
|
9997
10123
|
await walkForTsx(full, files, skipDirs);
|
|
@@ -10065,14 +10191,14 @@ async function discoverPages(appDir) {
|
|
|
10065
10191
|
return;
|
|
10066
10192
|
}
|
|
10067
10193
|
for (const entry of entries) {
|
|
10068
|
-
const full =
|
|
10194
|
+
const full = join16(dir, entry.name);
|
|
10069
10195
|
if (entry.isDirectory()) {
|
|
10070
10196
|
if (["design-system", "api", "_not-found"].includes(entry.name)) continue;
|
|
10071
10197
|
if (entry.name.startsWith(".")) continue;
|
|
10072
10198
|
await walk(full);
|
|
10073
10199
|
} else if (entry.name === "page.tsx" || entry.name === "page.jsx") {
|
|
10074
10200
|
const code = await readFile4(full, "utf-8");
|
|
10075
|
-
const routeDir = dirname7(
|
|
10201
|
+
const routeDir = dirname7(relative6(appDir, full));
|
|
10076
10202
|
let route = routeDir === "." ? "/" : "/" + routeDir;
|
|
10077
10203
|
route = route.replace(/\/\([^)]+\)/g, "");
|
|
10078
10204
|
if (!route.startsWith("/")) route = "/" + route;
|
|
@@ -10154,8 +10280,8 @@ async function syncCommand(options = {}) {
|
|
|
10154
10280
|
if (dryRun) console.log(chalk27.yellow(" [dry-run] No files will be written\n"));
|
|
10155
10281
|
const spinner = ora9("Scanning project files...").start();
|
|
10156
10282
|
try {
|
|
10157
|
-
const appDir =
|
|
10158
|
-
if (!
|
|
10283
|
+
const appDir = join16(project.root, "app");
|
|
10284
|
+
if (!existsSync22(appDir)) {
|
|
10159
10285
|
spinner.fail("No app/ directory found");
|
|
10160
10286
|
process.exit(1);
|
|
10161
10287
|
}
|
|
@@ -10385,53 +10511,53 @@ async function syncCommand(options = {}) {
|
|
|
10385
10511
|
// src/commands/migrate.ts
|
|
10386
10512
|
import chalk28 from "chalk";
|
|
10387
10513
|
import ora10 from "ora";
|
|
10388
|
-
import { existsSync as
|
|
10389
|
-
import { join as
|
|
10514
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync8, cpSync, rmSync as rmSync6, writeFileSync as writeFileSync12, readFileSync as readFileSync17, readdirSync as readdirSync9 } from "fs";
|
|
10515
|
+
import { join as join17 } from "path";
|
|
10390
10516
|
function backupDir(projectRoot) {
|
|
10391
10517
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
10392
|
-
return
|
|
10518
|
+
return join17(projectRoot, ".coherent", "backups", `pre-migrate-${ts}`);
|
|
10393
10519
|
}
|
|
10394
10520
|
function guardPath(projectRoot) {
|
|
10395
|
-
return
|
|
10521
|
+
return join17(projectRoot, ".coherent", "migration-in-progress");
|
|
10396
10522
|
}
|
|
10397
10523
|
function createBackup2(projectRoot) {
|
|
10398
|
-
const uiDir =
|
|
10524
|
+
const uiDir = join17(projectRoot, "components", "ui");
|
|
10399
10525
|
const dest = backupDir(projectRoot);
|
|
10400
10526
|
mkdirSync8(dest, { recursive: true });
|
|
10401
|
-
if (
|
|
10402
|
-
cpSync(uiDir,
|
|
10527
|
+
if (existsSync23(uiDir)) {
|
|
10528
|
+
cpSync(uiDir, join17(dest, "components-ui"), { recursive: true });
|
|
10403
10529
|
}
|
|
10404
|
-
const configPath =
|
|
10405
|
-
if (
|
|
10406
|
-
cpSync(configPath,
|
|
10530
|
+
const configPath = join17(projectRoot, "design-system.config.ts");
|
|
10531
|
+
if (existsSync23(configPath)) {
|
|
10532
|
+
cpSync(configPath, join17(dest, "design-system.config.ts"));
|
|
10407
10533
|
}
|
|
10408
10534
|
return dest;
|
|
10409
10535
|
}
|
|
10410
10536
|
function setGuard(projectRoot, backupPath) {
|
|
10411
10537
|
const guard = guardPath(projectRoot);
|
|
10412
|
-
mkdirSync8(
|
|
10413
|
-
|
|
10538
|
+
mkdirSync8(join17(projectRoot, ".coherent"), { recursive: true });
|
|
10539
|
+
writeFileSync12(guard, JSON.stringify({ backup: backupPath, startedAt: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
10414
10540
|
}
|
|
10415
10541
|
function clearGuard(projectRoot) {
|
|
10416
10542
|
const guard = guardPath(projectRoot);
|
|
10417
|
-
if (
|
|
10543
|
+
if (existsSync23(guard)) rmSync6(guard);
|
|
10418
10544
|
}
|
|
10419
10545
|
function rollback(projectRoot) {
|
|
10420
10546
|
const guard = guardPath(projectRoot);
|
|
10421
|
-
if (!
|
|
10547
|
+
if (!existsSync23(guard)) return false;
|
|
10422
10548
|
try {
|
|
10423
|
-
const data = JSON.parse(
|
|
10549
|
+
const data = JSON.parse(readFileSync17(guard, "utf-8"));
|
|
10424
10550
|
const backup = data.backup;
|
|
10425
|
-
if (!
|
|
10426
|
-
const uiBackup =
|
|
10427
|
-
const uiDir =
|
|
10428
|
-
if (
|
|
10429
|
-
if (
|
|
10551
|
+
if (!existsSync23(backup)) return false;
|
|
10552
|
+
const uiBackup = join17(backup, "components-ui");
|
|
10553
|
+
const uiDir = join17(projectRoot, "components", "ui");
|
|
10554
|
+
if (existsSync23(uiBackup)) {
|
|
10555
|
+
if (existsSync23(uiDir)) rmSync6(uiDir, { recursive: true });
|
|
10430
10556
|
cpSync(uiBackup, uiDir, { recursive: true });
|
|
10431
10557
|
}
|
|
10432
|
-
const configBackup =
|
|
10433
|
-
const configDest =
|
|
10434
|
-
if (
|
|
10558
|
+
const configBackup = join17(backup, "design-system.config.ts");
|
|
10559
|
+
const configDest = join17(projectRoot, "design-system.config.ts");
|
|
10560
|
+
if (existsSync23(configBackup)) {
|
|
10435
10561
|
cpSync(configBackup, configDest);
|
|
10436
10562
|
}
|
|
10437
10563
|
clearGuard(projectRoot);
|
|
@@ -10459,13 +10585,13 @@ async function migrateAction(options) {
|
|
|
10459
10585
|
return;
|
|
10460
10586
|
}
|
|
10461
10587
|
const guard = guardPath(projectRoot);
|
|
10462
|
-
if (
|
|
10588
|
+
if (existsSync23(guard)) {
|
|
10463
10589
|
console.log(chalk28.yellow("A migration is already in progress."));
|
|
10464
10590
|
console.log(chalk28.dim("Run `coherent migrate --rollback` to undo, or delete .coherent/migration-in-progress"));
|
|
10465
10591
|
return;
|
|
10466
10592
|
}
|
|
10467
|
-
const uiDir =
|
|
10468
|
-
if (!
|
|
10593
|
+
const uiDir = join17(projectRoot, "components", "ui");
|
|
10594
|
+
if (!existsSync23(uiDir)) {
|
|
10469
10595
|
console.log(chalk28.yellow("No components/ui directory found. Nothing to migrate."));
|
|
10470
10596
|
return;
|
|
10471
10597
|
}
|
|
@@ -10491,8 +10617,8 @@ Found ${migratable.length} component(s) to migrate:`));
|
|
|
10491
10617
|
setGuard(projectRoot, backup);
|
|
10492
10618
|
try {
|
|
10493
10619
|
for (const id of migratable) {
|
|
10494
|
-
const filePath =
|
|
10495
|
-
if (
|
|
10620
|
+
const filePath = join17(uiDir, `${id}.tsx`);
|
|
10621
|
+
if (existsSync23(filePath)) rmSync6(filePath);
|
|
10496
10622
|
}
|
|
10497
10623
|
const results = await provider.installBatch(migratable, projectRoot, { force: true });
|
|
10498
10624
|
let migrated = 0;
|
|
@@ -10514,20 +10640,20 @@ Found ${migratable.length} component(s) to migrate:`));
|
|
|
10514
10640
|
}
|
|
10515
10641
|
|
|
10516
10642
|
// src/utils/update-notifier.ts
|
|
10517
|
-
import { existsSync as
|
|
10518
|
-
import { join as
|
|
10643
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync9, readFileSync as readFileSync18, writeFileSync as writeFileSync13 } from "fs";
|
|
10644
|
+
import { join as join18 } from "path";
|
|
10519
10645
|
import { homedir } from "os";
|
|
10520
10646
|
import chalk29 from "chalk";
|
|
10521
10647
|
import { CLI_VERSION as CLI_VERSION5 } from "@getcoherent/core";
|
|
10522
10648
|
var DEBUG5 = process.env.COHERENT_DEBUG === "1";
|
|
10523
10649
|
var PACKAGE_NAME = "@getcoherent/cli";
|
|
10524
|
-
var CACHE_DIR =
|
|
10525
|
-
var CACHE_FILE =
|
|
10650
|
+
var CACHE_DIR = join18(homedir(), ".coherent");
|
|
10651
|
+
var CACHE_FILE = join18(CACHE_DIR, "update-check.json");
|
|
10526
10652
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
10527
10653
|
function readCache() {
|
|
10528
10654
|
try {
|
|
10529
|
-
if (!
|
|
10530
|
-
const raw =
|
|
10655
|
+
if (!existsSync24(CACHE_FILE)) return null;
|
|
10656
|
+
const raw = readFileSync18(CACHE_FILE, "utf-8");
|
|
10531
10657
|
return JSON.parse(raw);
|
|
10532
10658
|
} catch (e) {
|
|
10533
10659
|
if (DEBUG5) console.error("Failed to read update cache:", e);
|
|
@@ -10536,8 +10662,8 @@ function readCache() {
|
|
|
10536
10662
|
}
|
|
10537
10663
|
function writeCache(data) {
|
|
10538
10664
|
try {
|
|
10539
|
-
if (!
|
|
10540
|
-
|
|
10665
|
+
if (!existsSync24(CACHE_DIR)) mkdirSync9(CACHE_DIR, { recursive: true });
|
|
10666
|
+
writeFileSync13(CACHE_FILE, JSON.stringify(data), "utf-8");
|
|
10541
10667
|
} catch (e) {
|
|
10542
10668
|
if (DEBUG5) console.error("Failed to write update cache:", e);
|
|
10543
10669
|
}
|
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.39",
|
|
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.39"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@types/node": "^20.11.0",
|