@getcoherent/cli 0.6.37 → 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 +279 -148
- 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,45 +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
|
-
const
|
|
8547
|
-
if (
|
|
8548
|
-
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8635
|
+
const sidebarComponentPath2 = resolve10(projectRoot, "components", "shared", "sidebar.tsx");
|
|
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) {
|
|
8642
|
+
if (!dsm) {
|
|
8643
|
+
dsm = new DesignSystemManager9(project.configPath);
|
|
8644
|
+
await dsm.load();
|
|
8645
|
+
}
|
|
8646
|
+
const { PageGenerator } = await import("@getcoherent/core");
|
|
8647
|
+
const gen = new PageGenerator(dsm.getConfig());
|
|
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
|
+
}
|
|
8554
8655
|
}
|
|
8555
8656
|
}
|
|
8556
8657
|
const rootPagePath = resolve10(projectRoot, "app", "page.tsx");
|
|
8557
8658
|
const publicPagePath = resolve10(projectRoot, "app", "(public)", "page.tsx");
|
|
8558
|
-
if (
|
|
8659
|
+
if (existsSync17(rootPagePath) && !existsSync17(publicPagePath)) {
|
|
8559
8660
|
const { renameSync } = await import("fs");
|
|
8560
8661
|
mkdirSync7(resolve10(projectRoot, "app", "(public)"), { recursive: true });
|
|
8561
8662
|
renameSync(rootPagePath, publicPagePath);
|
|
@@ -8563,27 +8664,42 @@ async function fixCommand(opts = {}) {
|
|
|
8563
8664
|
console.log(chalk15.green(" \u2714 Moved app/page.tsx \u2192 app/(public)/page.tsx (gets Header/Footer)"));
|
|
8564
8665
|
}
|
|
8565
8666
|
const themeTogglePath = resolve10(projectRoot, "components", "shared", "theme-toggle.tsx");
|
|
8566
|
-
if (!
|
|
8667
|
+
if (!existsSync17(themeTogglePath)) {
|
|
8567
8668
|
const { generateThemeToggleCode } = await import("./code-generator-D3ZHOO4M.js");
|
|
8568
8669
|
mkdirSync7(resolve10(projectRoot, "components", "shared"), { recursive: true });
|
|
8569
|
-
|
|
8570
|
-
|
|
8571
|
-
|
|
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
|
+
}
|
|
8572
8677
|
}
|
|
8573
8678
|
}
|
|
8574
8679
|
}
|
|
8575
|
-
} catch {
|
|
8680
|
+
} catch (err) {
|
|
8681
|
+
console.log(chalk15.yellow(` \u26A0 Layout repair skipped: ${err instanceof Error ? err.message : "unknown error"}`));
|
|
8576
8682
|
}
|
|
8577
8683
|
if (!skipQuality) {
|
|
8578
8684
|
let qualityFixCount = 0;
|
|
8579
8685
|
const qualityFixDetails = [];
|
|
8580
8686
|
for (const file of userTsxFiles) {
|
|
8581
|
-
const content =
|
|
8687
|
+
const content = readFileSync13(file, "utf-8");
|
|
8582
8688
|
const { code: autoFixed, fixes: fileFixes } = await autoFixCode(content);
|
|
8583
8689
|
if (autoFixed !== content) {
|
|
8584
|
-
if (!dryRun)
|
|
8585
|
-
|
|
8586
|
-
|
|
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
|
+
}
|
|
8587
8703
|
}
|
|
8588
8704
|
}
|
|
8589
8705
|
if (qualityFixCount > 0) {
|
|
@@ -8593,11 +8709,22 @@ async function fixCommand(opts = {}) {
|
|
|
8593
8709
|
console.log(chalk15.green(` \u2714 ${verb} ${uniqueFixes.length} quality issue type(s): ${uniqueFixes.join(", ")}`));
|
|
8594
8710
|
}
|
|
8595
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
|
+
}
|
|
8596
8723
|
let totalErrors = 0;
|
|
8597
8724
|
let totalWarnings = 0;
|
|
8598
8725
|
const fileIssues = [];
|
|
8599
8726
|
for (const file of allTsxFiles) {
|
|
8600
|
-
const code = dryRun ?
|
|
8727
|
+
const code = dryRun ? readFileSync13(file, "utf-8") : readFileSync13(file, "utf-8");
|
|
8601
8728
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
8602
8729
|
const baseName = file.split("/").pop() || "";
|
|
8603
8730
|
const isAuthPage = relativePath.includes("(auth)");
|
|
@@ -8648,8 +8775,8 @@ async function fixCommand(opts = {}) {
|
|
|
8648
8775
|
}
|
|
8649
8776
|
for (const entry of manifest.shared) {
|
|
8650
8777
|
const actualUsedIn = findPagesImporting(project.root, entry.name, entry.file);
|
|
8651
|
-
const
|
|
8652
|
-
const fullActual =
|
|
8778
|
+
const layoutPaths = isUsedInLayout(project.root, entry.name);
|
|
8779
|
+
const fullActual = [.../* @__PURE__ */ new Set([...actualUsedIn, ...layoutPaths])];
|
|
8653
8780
|
if (!arraysEqual(fullActual, entry.usedIn || [])) {
|
|
8654
8781
|
entry.usedIn = fullActual;
|
|
8655
8782
|
manifestModified = true;
|
|
@@ -8686,12 +8813,16 @@ async function fixCommand(opts = {}) {
|
|
|
8686
8813
|
}
|
|
8687
8814
|
for (const entry of manifest.shared) {
|
|
8688
8815
|
const actualUsedIn = findPagesImporting(project.root, entry.name, entry.file);
|
|
8689
|
-
const
|
|
8690
|
-
if (actualUsedIn.length === 0 &&
|
|
8816
|
+
const layoutPaths2 = isUsedInLayout(project.root, entry.name);
|
|
8817
|
+
if (actualUsedIn.length === 0 && layoutPaths2.length === 0) {
|
|
8691
8818
|
remaining.push(`${entry.id} (${entry.name}) \u2014 unused. Remove: coherent components shared remove ${entry.id}`);
|
|
8692
8819
|
}
|
|
8693
8820
|
}
|
|
8694
|
-
} 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
|
+
}
|
|
8695
8826
|
}
|
|
8696
8827
|
if (fixes.length === 0 && totalErrors === 0 && totalWarnings === 0 && remaining.length === 0) {
|
|
8697
8828
|
console.log(chalk15.green("\n \u2705 Everything looks good \u2014 no issues found\n"));
|
|
@@ -8722,7 +8853,7 @@ async function fixCommand(opts = {}) {
|
|
|
8722
8853
|
// src/commands/check.ts
|
|
8723
8854
|
import chalk16 from "chalk";
|
|
8724
8855
|
import { resolve as resolve11 } from "path";
|
|
8725
|
-
import { readdirSync as readdirSync8, readFileSync as
|
|
8856
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync14, statSync as statSync3, existsSync as existsSync18 } from "fs";
|
|
8726
8857
|
import { loadManifest as loadManifest10 } from "@getcoherent/core";
|
|
8727
8858
|
var EXCLUDED_DIRS = /* @__PURE__ */ new Set(["node_modules", "design-system"]);
|
|
8728
8859
|
function findTsxFiles(dir) {
|
|
@@ -8779,7 +8910,7 @@ async function checkCommand(opts = {}) {
|
|
|
8779
8910
|
"NATIVE_TABLE"
|
|
8780
8911
|
]);
|
|
8781
8912
|
for (const file of files) {
|
|
8782
|
-
const code =
|
|
8913
|
+
const code = readFileSync14(file, "utf-8");
|
|
8783
8914
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
8784
8915
|
const baseName = file.split("/").pop() || "";
|
|
8785
8916
|
const isAuthPage = relativePath.includes("(auth)");
|
|
@@ -8821,7 +8952,7 @@ async function checkCommand(opts = {}) {
|
|
|
8821
8952
|
routeSet.add("/");
|
|
8822
8953
|
routeSet.add("#");
|
|
8823
8954
|
for (const file of files) {
|
|
8824
|
-
const code =
|
|
8955
|
+
const code = readFileSync14(file, "utf-8");
|
|
8825
8956
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
8826
8957
|
const lines = code.split("\n");
|
|
8827
8958
|
const linkHrefRe = /href\s*=\s*["'](\/[a-z0-9/-]*)["']/gi;
|
|
@@ -8854,7 +8985,7 @@ async function checkCommand(opts = {}) {
|
|
|
8854
8985
|
if (manifest.shared.length > 0) {
|
|
8855
8986
|
for (const entry of manifest.shared) {
|
|
8856
8987
|
const fullPath = resolve11(project.root, entry.file);
|
|
8857
|
-
if (!
|
|
8988
|
+
if (!existsSync18(fullPath)) {
|
|
8858
8989
|
result.pages.withErrors++;
|
|
8859
8990
|
if (!opts.json) console.log(chalk16.red(`
|
|
8860
8991
|
\u2717 Missing shared component file: ${entry.id} (${entry.file})`));
|
|
@@ -8879,7 +9010,7 @@ async function checkCommand(opts = {}) {
|
|
|
8879
9010
|
let _nameMismatch = 0;
|
|
8880
9011
|
for (const entry of manifest.shared) {
|
|
8881
9012
|
const filePath = resolve11(projectRoot, entry.file);
|
|
8882
|
-
const fileExists =
|
|
9013
|
+
const fileExists = existsSync18(filePath);
|
|
8883
9014
|
if (!fileExists) {
|
|
8884
9015
|
_orphaned++;
|
|
8885
9016
|
if (!opts.json) {
|
|
@@ -8889,7 +9020,7 @@ async function checkCommand(opts = {}) {
|
|
|
8889
9020
|
continue;
|
|
8890
9021
|
}
|
|
8891
9022
|
try {
|
|
8892
|
-
const code =
|
|
9023
|
+
const code = readFileSync14(filePath, "utf-8");
|
|
8893
9024
|
const actualExports = extractExportedComponentNames(code);
|
|
8894
9025
|
if (actualExports.length > 0 && !actualExports.includes(entry.name)) {
|
|
8895
9026
|
_nameMismatch++;
|
|
@@ -8905,10 +9036,10 @@ async function checkCommand(opts = {}) {
|
|
|
8905
9036
|
} catch {
|
|
8906
9037
|
}
|
|
8907
9038
|
const actualUsedIn = findPagesImporting(projectRoot, entry.name, entry.file);
|
|
8908
|
-
const
|
|
8909
|
-
const totalUsage = actualUsedIn.length +
|
|
9039
|
+
const layoutPaths = isUsedInLayout(projectRoot, entry.name);
|
|
9040
|
+
const totalUsage = actualUsedIn.length + layoutPaths.length;
|
|
8910
9041
|
const manifestUsedIn = entry.usedIn || [];
|
|
8911
|
-
const fullActual =
|
|
9042
|
+
const fullActual = [.../* @__PURE__ */ new Set([...actualUsedIn, ...layoutPaths])];
|
|
8912
9043
|
const isStale = manifestUsedIn.length !== fullActual.length || !manifestUsedIn.every((p) => fullActual.includes(p));
|
|
8913
9044
|
if (isStale) _staleUsedIn++;
|
|
8914
9045
|
if (totalUsage === 0) {
|
|
@@ -8919,7 +9050,7 @@ async function checkCommand(opts = {}) {
|
|
|
8919
9050
|
}
|
|
8920
9051
|
} else {
|
|
8921
9052
|
consistent++;
|
|
8922
|
-
const usageDesc =
|
|
9053
|
+
const usageDesc = layoutPaths.length > 0 ? `layout(${layoutPaths.length}) + ${actualUsedIn.length} page(s)` : `${actualUsedIn.length} page(s)`;
|
|
8923
9054
|
if (!opts.json) {
|
|
8924
9055
|
const staleNote = isStale ? chalk16.yellow(" [usedIn stale]") : "";
|
|
8925
9056
|
console.log(chalk16.green(` \u2714 ${entry.id} (${entry.name})`) + chalk16.dim(` \u2014 ${usageDesc}`) + staleNote);
|
|
@@ -8957,7 +9088,7 @@ async function checkCommand(opts = {}) {
|
|
|
8957
9088
|
id: e.id,
|
|
8958
9089
|
name: e.name,
|
|
8959
9090
|
type: e.type,
|
|
8960
|
-
status:
|
|
9091
|
+
status: existsSync18(resolve11(projectRoot, e.file)) ? "ok" : "unused",
|
|
8961
9092
|
message: "",
|
|
8962
9093
|
suggestions: void 0
|
|
8963
9094
|
}))
|
|
@@ -8971,11 +9102,11 @@ async function checkCommand(opts = {}) {
|
|
|
8971
9102
|
const { inferPageTypeFromRoute: inferPageTypeFromRoute2 } = await import("./design-constraints-EIP2XM7T.js");
|
|
8972
9103
|
const manifest = await loadManifest10(projectRoot);
|
|
8973
9104
|
const appDir = resolve11(projectRoot, "app");
|
|
8974
|
-
const pageFiles =
|
|
9105
|
+
const pageFiles = existsSync18(appDir) ? findTsxFiles(appDir) : [];
|
|
8975
9106
|
if (manifest.shared.length > 0 && pageFiles.length > 0) {
|
|
8976
9107
|
const reuseWarnings = [];
|
|
8977
9108
|
for (const file of pageFiles) {
|
|
8978
|
-
const code =
|
|
9109
|
+
const code = readFileSync14(file, "utf-8");
|
|
8979
9110
|
const relativePath = file.replace(projectRoot + "/", "");
|
|
8980
9111
|
const route = "/" + relativePath.replace(/^app\//, "").replace(/\/page\.tsx$/, "").replace(/^\(.*?\)\//, "");
|
|
8981
9112
|
const pageType = inferPageTypeFromRoute2(route);
|
|
@@ -9086,12 +9217,12 @@ import {
|
|
|
9086
9217
|
generateSharedComponent as generateSharedComponent4,
|
|
9087
9218
|
integrateSharedLayoutIntoRootLayout as integrateSharedLayoutIntoRootLayout2
|
|
9088
9219
|
} from "@getcoherent/core";
|
|
9089
|
-
import { existsSync as
|
|
9220
|
+
import { existsSync as existsSync19 } from "fs";
|
|
9090
9221
|
import { resolve as resolve12 } from "path";
|
|
9091
9222
|
|
|
9092
9223
|
// src/utils/ds-files.ts
|
|
9093
9224
|
import { mkdir as mkdir3, writeFile as writeFile4 } from "fs/promises";
|
|
9094
|
-
import { join as
|
|
9225
|
+
import { join as join13, dirname as dirname5 } from "path";
|
|
9095
9226
|
import { DesignSystemGenerator } from "@getcoherent/core";
|
|
9096
9227
|
var SHARED_DS_KEYS = [
|
|
9097
9228
|
"app/design-system/shared/page.tsx",
|
|
@@ -9105,7 +9236,7 @@ async function writeDesignSystemFiles(projectRoot, config2, options) {
|
|
|
9105
9236
|
const toWrite = options?.sharedOnly ? new Map([...files].filter(([path3]) => SHARED_DS_KEYS.includes(path3))) : files;
|
|
9106
9237
|
const written = [];
|
|
9107
9238
|
for (const [relativePath, content] of toWrite) {
|
|
9108
|
-
const fullPath =
|
|
9239
|
+
const fullPath = join13(projectRoot, relativePath);
|
|
9109
9240
|
await mkdir3(dirname5(fullPath), { recursive: true });
|
|
9110
9241
|
await writeFile4(fullPath, content, "utf-8");
|
|
9111
9242
|
written.push(relativePath);
|
|
@@ -9241,7 +9372,7 @@ function createComponentsCommand() {
|
|
|
9241
9372
|
if (updated) console.log(chalk22.cyan(" Updated app/layout.tsx to use shared layout components.\n"));
|
|
9242
9373
|
}
|
|
9243
9374
|
const sharedPagePath = resolve12(project.root, "app/design-system/shared/page.tsx");
|
|
9244
|
-
if (!
|
|
9375
|
+
if (!existsSync19(sharedPagePath)) {
|
|
9245
9376
|
try {
|
|
9246
9377
|
const dsm = new DesignSystemManager10(project.configPath);
|
|
9247
9378
|
await dsm.load();
|
|
@@ -9267,8 +9398,8 @@ function createComponentsCommand() {
|
|
|
9267
9398
|
import chalk23 from "chalk";
|
|
9268
9399
|
import ora6 from "ora";
|
|
9269
9400
|
import { writeFile as writeFile5, mkdir as mkdir4 } from "fs/promises";
|
|
9270
|
-
import { resolve as resolve13, join as
|
|
9271
|
-
import { existsSync as
|
|
9401
|
+
import { resolve as resolve13, join as join14, dirname as dirname6 } from "path";
|
|
9402
|
+
import { existsSync as existsSync20 } from "fs";
|
|
9272
9403
|
import {
|
|
9273
9404
|
FigmaClient,
|
|
9274
9405
|
parseFigmaFileResponse,
|
|
@@ -9415,7 +9546,7 @@ async function importFigmaAction(urlOrKey, opts) {
|
|
|
9415
9546
|
stats.filesWritten.push(filePath);
|
|
9416
9547
|
return;
|
|
9417
9548
|
}
|
|
9418
|
-
const fullPath =
|
|
9549
|
+
const fullPath = join14(projectRoot, filePath);
|
|
9419
9550
|
await mkdir4(dirname6(fullPath), { recursive: true });
|
|
9420
9551
|
await writeFile5(fullPath, content, "utf-8");
|
|
9421
9552
|
stats.filesWritten.push(filePath);
|
|
@@ -9517,7 +9648,7 @@ async function importFigmaAction(urlOrKey, opts) {
|
|
|
9517
9648
|
spinner.start("Updating design-system.config.ts...");
|
|
9518
9649
|
const configPath = resolve13(projectRoot, DESIGN_SYSTEM_CONFIG_PATH);
|
|
9519
9650
|
const dsm = new DesignSystemManager11(configPath);
|
|
9520
|
-
if (
|
|
9651
|
+
if (existsSync20(configPath)) {
|
|
9521
9652
|
await dsm.load();
|
|
9522
9653
|
const existing = dsm.getConfig();
|
|
9523
9654
|
dsm.updateConfig({
|
|
@@ -9546,8 +9677,8 @@ export const config = ${JSON.stringify(fullConfig, null, 2)} as const
|
|
|
9546
9677
|
stats.configUpdated = true;
|
|
9547
9678
|
spinner.succeed("design-system.config.ts updated");
|
|
9548
9679
|
spinner.start("Ensuring root layout...");
|
|
9549
|
-
const layoutPath =
|
|
9550
|
-
if (!
|
|
9680
|
+
const layoutPath = join14(projectRoot, "app/layout.tsx");
|
|
9681
|
+
if (!existsSync20(layoutPath)) {
|
|
9551
9682
|
await mkdir4(dirname6(layoutPath), { recursive: true });
|
|
9552
9683
|
await writeFile5(layoutPath, MINIMAL_ROOT_LAYOUT, "utf-8");
|
|
9553
9684
|
stats.filesWritten.push("app/layout.tsx");
|
|
@@ -9637,8 +9768,8 @@ async function dsRegenerateCommand() {
|
|
|
9637
9768
|
// src/commands/update.ts
|
|
9638
9769
|
import chalk25 from "chalk";
|
|
9639
9770
|
import ora8 from "ora";
|
|
9640
|
-
import { readFileSync as
|
|
9641
|
-
import { join as
|
|
9771
|
+
import { readFileSync as readFileSync15, existsSync as existsSync21 } from "fs";
|
|
9772
|
+
import { join as join15 } from "path";
|
|
9642
9773
|
import { DesignSystemManager as DesignSystemManager13, CLI_VERSION as CLI_VERSION4 } from "@getcoherent/core";
|
|
9643
9774
|
|
|
9644
9775
|
// src/utils/migrations.ts
|
|
@@ -9807,20 +9938,20 @@ var EXPECTED_CSS_VARS = [
|
|
|
9807
9938
|
"--sidebar-ring"
|
|
9808
9939
|
];
|
|
9809
9940
|
function checkMissingCssVars(projectRoot) {
|
|
9810
|
-
const globalsPath =
|
|
9811
|
-
if (!
|
|
9941
|
+
const globalsPath = join15(projectRoot, "app", "globals.css");
|
|
9942
|
+
if (!existsSync21(globalsPath)) return [];
|
|
9812
9943
|
try {
|
|
9813
|
-
const content =
|
|
9944
|
+
const content = readFileSync15(globalsPath, "utf-8");
|
|
9814
9945
|
return EXPECTED_CSS_VARS.filter((v) => !content.includes(v));
|
|
9815
9946
|
} catch {
|
|
9816
9947
|
return [];
|
|
9817
9948
|
}
|
|
9818
9949
|
}
|
|
9819
9950
|
function patchGlobalsCss(projectRoot, missingVars) {
|
|
9820
|
-
const globalsPath =
|
|
9821
|
-
if (!
|
|
9822
|
-
const { writeFileSync:
|
|
9823
|
-
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");
|
|
9824
9955
|
const defaultValues = {
|
|
9825
9956
|
"--chart-1": "220 70% 50%",
|
|
9826
9957
|
"--chart-2": "160 60% 45%",
|
|
@@ -9848,7 +9979,7 @@ function patchGlobalsCss(projectRoot, missingVars) {
|
|
|
9848
9979
|
const lightSectionEnd = content.indexOf("}");
|
|
9849
9980
|
if (lightSectionEnd > 0) {
|
|
9850
9981
|
content = content.slice(0, lightSectionEnd) + "\n" + injection + "\n" + content.slice(lightSectionEnd);
|
|
9851
|
-
|
|
9982
|
+
writeFileSync14(globalsPath, content, "utf-8");
|
|
9852
9983
|
}
|
|
9853
9984
|
}
|
|
9854
9985
|
|
|
@@ -9898,26 +10029,26 @@ async function undoCommand(options) {
|
|
|
9898
10029
|
// src/commands/sync.ts
|
|
9899
10030
|
import chalk27 from "chalk";
|
|
9900
10031
|
import ora9 from "ora";
|
|
9901
|
-
import { existsSync as
|
|
9902
|
-
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";
|
|
9903
10034
|
import { readdir as readdir3, readFile as readFile4 } from "fs/promises";
|
|
9904
10035
|
import { DesignSystemManager as DesignSystemManager14 } from "@getcoherent/core";
|
|
9905
10036
|
import { loadManifest as loadManifest12, saveManifest as saveManifest6, findSharedComponent } from "@getcoherent/core";
|
|
9906
10037
|
function extractTokensFromProject(projectRoot) {
|
|
9907
10038
|
const lightColors = {};
|
|
9908
10039
|
const darkColors = {};
|
|
9909
|
-
const globalsPath =
|
|
9910
|
-
if (
|
|
9911
|
-
const css =
|
|
10040
|
+
const globalsPath = join16(projectRoot, "app", "globals.css");
|
|
10041
|
+
if (existsSync22(globalsPath)) {
|
|
10042
|
+
const css = readFileSync16(globalsPath, "utf-8");
|
|
9912
10043
|
const rootMatch = css.match(/:root\s*\{([^}]+)\}/s);
|
|
9913
10044
|
if (rootMatch) parseVarsInto(rootMatch[1], lightColors);
|
|
9914
10045
|
const darkMatch = css.match(/\.dark\s*\{([^}]+)\}/s);
|
|
9915
10046
|
if (darkMatch) parseVarsInto(darkMatch[1], darkColors);
|
|
9916
10047
|
}
|
|
9917
|
-
const layoutPath =
|
|
10048
|
+
const layoutPath = join16(projectRoot, "app", "layout.tsx");
|
|
9918
10049
|
let layoutCode = "";
|
|
9919
|
-
if (
|
|
9920
|
-
layoutCode =
|
|
10050
|
+
if (existsSync22(layoutPath)) {
|
|
10051
|
+
layoutCode = readFileSync16(layoutPath, "utf-8");
|
|
9921
10052
|
const rootInline = layoutCode.match(/:root\s*\{([^}]+)\}/s);
|
|
9922
10053
|
if (rootInline && Object.keys(lightColors).length === 0) {
|
|
9923
10054
|
parseVarsInto(rootInline[1], lightColors);
|
|
@@ -9935,7 +10066,7 @@ function extractTokensFromProject(projectRoot) {
|
|
|
9935
10066
|
defaultMode = "dark";
|
|
9936
10067
|
}
|
|
9937
10068
|
let radius;
|
|
9938
|
-
const allCss = [
|
|
10069
|
+
const allCss = [existsSync22(globalsPath) ? readFileSync16(globalsPath, "utf-8") : "", layoutCode].join("\n");
|
|
9939
10070
|
const radiusMatch = allCss.match(/--radius:\s*([^;]+);/);
|
|
9940
10071
|
if (radiusMatch) radius = radiusMatch[1].trim();
|
|
9941
10072
|
return {
|
|
@@ -9958,14 +10089,14 @@ function parseVarsInto(block, target) {
|
|
|
9958
10089
|
}
|
|
9959
10090
|
async function detectCustomComponents(projectRoot, allPageCode) {
|
|
9960
10091
|
const results = [];
|
|
9961
|
-
const componentsDir =
|
|
9962
|
-
if (!
|
|
10092
|
+
const componentsDir = join16(projectRoot, "components");
|
|
10093
|
+
if (!existsSync22(componentsDir)) return results;
|
|
9963
10094
|
const files = [];
|
|
9964
10095
|
await walkForTsx(componentsDir, files, ["ui"]);
|
|
9965
10096
|
const fileResults = await Promise.all(
|
|
9966
10097
|
files.map(async (filePath) => {
|
|
9967
10098
|
const code = await readFile4(filePath, "utf-8");
|
|
9968
|
-
const relFile =
|
|
10099
|
+
const relFile = relative6(projectRoot, filePath);
|
|
9969
10100
|
const exportedNames = extractExportedComponentNames2(code);
|
|
9970
10101
|
return exportedNames.map((name) => ({
|
|
9971
10102
|
name,
|
|
@@ -9986,7 +10117,7 @@ async function walkForTsx(dir, files, skipDirs) {
|
|
|
9986
10117
|
return;
|
|
9987
10118
|
}
|
|
9988
10119
|
for (const e of entries) {
|
|
9989
|
-
const full =
|
|
10120
|
+
const full = join16(dir, e.name);
|
|
9990
10121
|
if (e.isDirectory()) {
|
|
9991
10122
|
if (skipDirs.includes(e.name) || e.name.startsWith(".")) continue;
|
|
9992
10123
|
await walkForTsx(full, files, skipDirs);
|
|
@@ -10060,14 +10191,14 @@ async function discoverPages(appDir) {
|
|
|
10060
10191
|
return;
|
|
10061
10192
|
}
|
|
10062
10193
|
for (const entry of entries) {
|
|
10063
|
-
const full =
|
|
10194
|
+
const full = join16(dir, entry.name);
|
|
10064
10195
|
if (entry.isDirectory()) {
|
|
10065
10196
|
if (["design-system", "api", "_not-found"].includes(entry.name)) continue;
|
|
10066
10197
|
if (entry.name.startsWith(".")) continue;
|
|
10067
10198
|
await walk(full);
|
|
10068
10199
|
} else if (entry.name === "page.tsx" || entry.name === "page.jsx") {
|
|
10069
10200
|
const code = await readFile4(full, "utf-8");
|
|
10070
|
-
const routeDir = dirname7(
|
|
10201
|
+
const routeDir = dirname7(relative6(appDir, full));
|
|
10071
10202
|
let route = routeDir === "." ? "/" : "/" + routeDir;
|
|
10072
10203
|
route = route.replace(/\/\([^)]+\)/g, "");
|
|
10073
10204
|
if (!route.startsWith("/")) route = "/" + route;
|
|
@@ -10149,8 +10280,8 @@ async function syncCommand(options = {}) {
|
|
|
10149
10280
|
if (dryRun) console.log(chalk27.yellow(" [dry-run] No files will be written\n"));
|
|
10150
10281
|
const spinner = ora9("Scanning project files...").start();
|
|
10151
10282
|
try {
|
|
10152
|
-
const appDir =
|
|
10153
|
-
if (!
|
|
10283
|
+
const appDir = join16(project.root, "app");
|
|
10284
|
+
if (!existsSync22(appDir)) {
|
|
10154
10285
|
spinner.fail("No app/ directory found");
|
|
10155
10286
|
process.exit(1);
|
|
10156
10287
|
}
|
|
@@ -10380,53 +10511,53 @@ async function syncCommand(options = {}) {
|
|
|
10380
10511
|
// src/commands/migrate.ts
|
|
10381
10512
|
import chalk28 from "chalk";
|
|
10382
10513
|
import ora10 from "ora";
|
|
10383
|
-
import { existsSync as
|
|
10384
|
-
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";
|
|
10385
10516
|
function backupDir(projectRoot) {
|
|
10386
10517
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
10387
|
-
return
|
|
10518
|
+
return join17(projectRoot, ".coherent", "backups", `pre-migrate-${ts}`);
|
|
10388
10519
|
}
|
|
10389
10520
|
function guardPath(projectRoot) {
|
|
10390
|
-
return
|
|
10521
|
+
return join17(projectRoot, ".coherent", "migration-in-progress");
|
|
10391
10522
|
}
|
|
10392
10523
|
function createBackup2(projectRoot) {
|
|
10393
|
-
const uiDir =
|
|
10524
|
+
const uiDir = join17(projectRoot, "components", "ui");
|
|
10394
10525
|
const dest = backupDir(projectRoot);
|
|
10395
10526
|
mkdirSync8(dest, { recursive: true });
|
|
10396
|
-
if (
|
|
10397
|
-
cpSync(uiDir,
|
|
10527
|
+
if (existsSync23(uiDir)) {
|
|
10528
|
+
cpSync(uiDir, join17(dest, "components-ui"), { recursive: true });
|
|
10398
10529
|
}
|
|
10399
|
-
const configPath =
|
|
10400
|
-
if (
|
|
10401
|
-
cpSync(configPath,
|
|
10530
|
+
const configPath = join17(projectRoot, "design-system.config.ts");
|
|
10531
|
+
if (existsSync23(configPath)) {
|
|
10532
|
+
cpSync(configPath, join17(dest, "design-system.config.ts"));
|
|
10402
10533
|
}
|
|
10403
10534
|
return dest;
|
|
10404
10535
|
}
|
|
10405
10536
|
function setGuard(projectRoot, backupPath) {
|
|
10406
10537
|
const guard = guardPath(projectRoot);
|
|
10407
|
-
mkdirSync8(
|
|
10408
|
-
|
|
10538
|
+
mkdirSync8(join17(projectRoot, ".coherent"), { recursive: true });
|
|
10539
|
+
writeFileSync12(guard, JSON.stringify({ backup: backupPath, startedAt: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
10409
10540
|
}
|
|
10410
10541
|
function clearGuard(projectRoot) {
|
|
10411
10542
|
const guard = guardPath(projectRoot);
|
|
10412
|
-
if (
|
|
10543
|
+
if (existsSync23(guard)) rmSync6(guard);
|
|
10413
10544
|
}
|
|
10414
10545
|
function rollback(projectRoot) {
|
|
10415
10546
|
const guard = guardPath(projectRoot);
|
|
10416
|
-
if (!
|
|
10547
|
+
if (!existsSync23(guard)) return false;
|
|
10417
10548
|
try {
|
|
10418
|
-
const data = JSON.parse(
|
|
10549
|
+
const data = JSON.parse(readFileSync17(guard, "utf-8"));
|
|
10419
10550
|
const backup = data.backup;
|
|
10420
|
-
if (!
|
|
10421
|
-
const uiBackup =
|
|
10422
|
-
const uiDir =
|
|
10423
|
-
if (
|
|
10424
|
-
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 });
|
|
10425
10556
|
cpSync(uiBackup, uiDir, { recursive: true });
|
|
10426
10557
|
}
|
|
10427
|
-
const configBackup =
|
|
10428
|
-
const configDest =
|
|
10429
|
-
if (
|
|
10558
|
+
const configBackup = join17(backup, "design-system.config.ts");
|
|
10559
|
+
const configDest = join17(projectRoot, "design-system.config.ts");
|
|
10560
|
+
if (existsSync23(configBackup)) {
|
|
10430
10561
|
cpSync(configBackup, configDest);
|
|
10431
10562
|
}
|
|
10432
10563
|
clearGuard(projectRoot);
|
|
@@ -10454,13 +10585,13 @@ async function migrateAction(options) {
|
|
|
10454
10585
|
return;
|
|
10455
10586
|
}
|
|
10456
10587
|
const guard = guardPath(projectRoot);
|
|
10457
|
-
if (
|
|
10588
|
+
if (existsSync23(guard)) {
|
|
10458
10589
|
console.log(chalk28.yellow("A migration is already in progress."));
|
|
10459
10590
|
console.log(chalk28.dim("Run `coherent migrate --rollback` to undo, or delete .coherent/migration-in-progress"));
|
|
10460
10591
|
return;
|
|
10461
10592
|
}
|
|
10462
|
-
const uiDir =
|
|
10463
|
-
if (!
|
|
10593
|
+
const uiDir = join17(projectRoot, "components", "ui");
|
|
10594
|
+
if (!existsSync23(uiDir)) {
|
|
10464
10595
|
console.log(chalk28.yellow("No components/ui directory found. Nothing to migrate."));
|
|
10465
10596
|
return;
|
|
10466
10597
|
}
|
|
@@ -10486,8 +10617,8 @@ Found ${migratable.length} component(s) to migrate:`));
|
|
|
10486
10617
|
setGuard(projectRoot, backup);
|
|
10487
10618
|
try {
|
|
10488
10619
|
for (const id of migratable) {
|
|
10489
|
-
const filePath =
|
|
10490
|
-
if (
|
|
10620
|
+
const filePath = join17(uiDir, `${id}.tsx`);
|
|
10621
|
+
if (existsSync23(filePath)) rmSync6(filePath);
|
|
10491
10622
|
}
|
|
10492
10623
|
const results = await provider.installBatch(migratable, projectRoot, { force: true });
|
|
10493
10624
|
let migrated = 0;
|
|
@@ -10509,20 +10640,20 @@ Found ${migratable.length} component(s) to migrate:`));
|
|
|
10509
10640
|
}
|
|
10510
10641
|
|
|
10511
10642
|
// src/utils/update-notifier.ts
|
|
10512
|
-
import { existsSync as
|
|
10513
|
-
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";
|
|
10514
10645
|
import { homedir } from "os";
|
|
10515
10646
|
import chalk29 from "chalk";
|
|
10516
10647
|
import { CLI_VERSION as CLI_VERSION5 } from "@getcoherent/core";
|
|
10517
10648
|
var DEBUG5 = process.env.COHERENT_DEBUG === "1";
|
|
10518
10649
|
var PACKAGE_NAME = "@getcoherent/cli";
|
|
10519
|
-
var CACHE_DIR =
|
|
10520
|
-
var CACHE_FILE =
|
|
10650
|
+
var CACHE_DIR = join18(homedir(), ".coherent");
|
|
10651
|
+
var CACHE_FILE = join18(CACHE_DIR, "update-check.json");
|
|
10521
10652
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
10522
10653
|
function readCache() {
|
|
10523
10654
|
try {
|
|
10524
|
-
if (!
|
|
10525
|
-
const raw =
|
|
10655
|
+
if (!existsSync24(CACHE_FILE)) return null;
|
|
10656
|
+
const raw = readFileSync18(CACHE_FILE, "utf-8");
|
|
10526
10657
|
return JSON.parse(raw);
|
|
10527
10658
|
} catch (e) {
|
|
10528
10659
|
if (DEBUG5) console.error("Failed to read update cache:", e);
|
|
@@ -10531,8 +10662,8 @@ function readCache() {
|
|
|
10531
10662
|
}
|
|
10532
10663
|
function writeCache(data) {
|
|
10533
10664
|
try {
|
|
10534
|
-
if (!
|
|
10535
|
-
|
|
10665
|
+
if (!existsSync24(CACHE_DIR)) mkdirSync9(CACHE_DIR, { recursive: true });
|
|
10666
|
+
writeFileSync13(CACHE_FILE, JSON.stringify(data), "utf-8");
|
|
10536
10667
|
} catch (e) {
|
|
10537
10668
|
if (DEBUG5) console.error("Failed to write update cache:", e);
|
|
10538
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",
|