@getcoherent/cli 0.6.43 → 0.6.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-662O2QEG.js → chunk-4I7ATX6G.js} +3 -3
- package/dist/{chunk-5AHG4NNX.js → chunk-E23FJX2I.js} +16 -1
- package/dist/{chunk-KJRBBLXT.js → chunk-VLBVBF6V.js} +1 -1
- package/dist/{code-generator-CV54KQFF.js → code-generator-YSGVHVNN.js} +3 -3
- package/dist/{design-constraints-EIP2XM7T.js → design-constraints-HGNEY3W3.js} +1 -1
- package/dist/index.js +139 -68
- package/dist/mock-data-validator-JEWUOMFY.js +70 -0
- package/dist/{plan-generator-YOPF773K.js → plan-generator-PIDLFRWZ.js} +2 -2
- package/package.json +2 -2
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
getPageGroup,
|
|
7
7
|
installPackages,
|
|
8
8
|
sanitizeMetadataStrings
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-VLBVBF6V.js";
|
|
10
10
|
import {
|
|
11
11
|
toKebabCase
|
|
12
12
|
} from "./chunk-4TLYDTT3.js";
|
|
@@ -2147,7 +2147,7 @@ async function regeneratePage(pageId, config, projectRoot) {
|
|
|
2147
2147
|
const code = await generator.generate(page, appType);
|
|
2148
2148
|
const route = page.route || "/";
|
|
2149
2149
|
const isAuth = isAuthRoute(route) || isAuthRoute(page.name || page.id || "");
|
|
2150
|
-
const { loadPlan: loadPlanForPath } = await import("./plan-generator-
|
|
2150
|
+
const { loadPlan: loadPlanForPath } = await import("./plan-generator-PIDLFRWZ.js");
|
|
2151
2151
|
const planForPath = loadPlanForPath(projectRoot);
|
|
2152
2152
|
const filePath = routeToFsPath(projectRoot, route, planForPath || isAuth);
|
|
2153
2153
|
await mkdir3(dirname3(filePath), { recursive: true });
|
|
@@ -2336,7 +2336,7 @@ export default function AppLayout({
|
|
|
2336
2336
|
{children}
|
|
2337
2337
|
</main>
|
|
2338
2338
|
<footer className="border-t px-4 py-3 text-xs text-muted-foreground">
|
|
2339
|
-
|
|
2339
|
+
\xA9 ${year} ${name}
|
|
2340
2340
|
</footer>
|
|
2341
2341
|
</SidebarInset>
|
|
2342
2342
|
</SidebarProvider>
|
|
@@ -93,6 +93,15 @@ COMPONENT VARIANT RULES (CRITICAL):
|
|
|
93
93
|
CONTENT (zero placeholders):
|
|
94
94
|
- NEVER: "Lorem ipsum", "Card content", "Description here"
|
|
95
95
|
- ALWAYS: Real, contextual content. Realistic metric names, values, dates.
|
|
96
|
+
|
|
97
|
+
MOCK/SAMPLE DATA (for demo arrays, fake users, fake tasks, etc.):
|
|
98
|
+
- Dates: ALWAYS ISO 8601 strings in data ("2024-06-15T10:30:00Z").
|
|
99
|
+
Display with date formatting: new Date(item.date).toLocaleDateString() or
|
|
100
|
+
Intl.RelativeTimeFormat, or date-fns if already imported.
|
|
101
|
+
BAD: { createdAt: "2 hours ago" }
|
|
102
|
+
GOOD: { createdAt: "2024-06-15T10:30:00Z" }
|
|
103
|
+
- Images: "/placeholder.svg?height=40&width=40" (Next.js placeholder). Never broken paths.
|
|
104
|
+
- IDs: sequential numbers (1, 2, 3) or short slugs ("proj-1"). Never random UUIDs.
|
|
96
105
|
`;
|
|
97
106
|
var DESIGN_QUALITY_COMMON = `
|
|
98
107
|
## DESIGN QUALITY \u2014 COMMON
|
|
@@ -509,11 +518,17 @@ EMPTY STATES: See the Empty State reference pattern in DESIGN QUALITY \u2014 APP
|
|
|
509
518
|
- Filtered empty: "No items match your filters." + reset filters button.
|
|
510
519
|
|
|
511
520
|
DATA FORMATTING:
|
|
512
|
-
- Dates: use relative for recent ("2 hours ago"
|
|
521
|
+
- Dates in rendered output: use relative for recent ("2 hours ago"), absolute for older ("Jan 26, 2026"). Never show raw ISO in the UI.
|
|
522
|
+
- Dates in source data (mock arrays, state): ALWAYS store as ISO 8601 strings. Compute display format at render time.
|
|
513
523
|
- Numbers: use Intl.NumberFormat or toLocaleString(). 1,234 not 1234. Always include separator for 1000+.
|
|
514
524
|
- Currency: $1,234.56 format. Symbol before number. Two decimal places for amounts.
|
|
515
525
|
- Percentages: one decimal max. "+12.5%" with sign for changes.
|
|
516
526
|
|
|
527
|
+
MOCK DATA IN COMPONENTS:
|
|
528
|
+
- All date/time values in sample data arrays MUST be valid ISO 8601 strings.
|
|
529
|
+
- Render with: new Date(item.date).toLocaleDateString(), Intl.RelativeTimeFormat, or date-fns if imported.
|
|
530
|
+
- NEVER store display strings ("2 hours ago", "Yesterday") in data \u2014 always compute from ISO date.
|
|
531
|
+
|
|
517
532
|
STATUS INDICATORS (dot + text):
|
|
518
533
|
- Pattern: <div className="flex items-center gap-2"><div className="size-2 rounded-full bg-emerald-500" /><span className="text-sm">Active</span></div>
|
|
519
534
|
- Colors: bg-emerald-500 (active/online), bg-destructive (error/offline), bg-yellow-500 (warning), bg-muted-foreground (inactive).
|
|
@@ -12,10 +12,10 @@ import {
|
|
|
12
12
|
regeneratePage,
|
|
13
13
|
scanAndInstallSharedDeps,
|
|
14
14
|
validateAndFixGeneratedCode
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import "./chunk-
|
|
15
|
+
} from "./chunk-4I7ATX6G.js";
|
|
16
|
+
import "./chunk-VLBVBF6V.js";
|
|
17
17
|
import "./chunk-4TLYDTT3.js";
|
|
18
|
-
import "./chunk-
|
|
18
|
+
import "./chunk-E23FJX2I.js";
|
|
19
19
|
import "./chunk-NOM47EB4.js";
|
|
20
20
|
import "./chunk-3RG5ZIWI.js";
|
|
21
21
|
export {
|
package/dist/index.js
CHANGED
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
warnIfVolatile,
|
|
35
35
|
warnInlineDuplicates,
|
|
36
36
|
writeFile
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-4I7ATX6G.js";
|
|
38
38
|
import {
|
|
39
39
|
COHERENT_REQUIRED_PACKAGES,
|
|
40
40
|
ensureUseClientIfNeeded,
|
|
@@ -52,7 +52,7 @@ import {
|
|
|
52
52
|
sanitizeMetadataStrings,
|
|
53
53
|
savePlan,
|
|
54
54
|
updateArchitecturePlan
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-VLBVBF6V.js";
|
|
56
56
|
import {
|
|
57
57
|
toKebabCase,
|
|
58
58
|
toTitleCase
|
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
getDesignQualityForType,
|
|
71
71
|
inferPageTypeFromRoute,
|
|
72
72
|
selectContextualRules
|
|
73
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-E23FJX2I.js";
|
|
74
74
|
import {
|
|
75
75
|
fixGlobalsCss,
|
|
76
76
|
generateV4GlobalsCss,
|
|
@@ -3896,7 +3896,7 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
|
|
|
3896
3896
|
if (plan && plan.sharedComponents.length > 0) {
|
|
3897
3897
|
spinner.start(`Phase 4.5/6 \u2014 Generating ${plan.sharedComponents.length} shared components from plan...`);
|
|
3898
3898
|
try {
|
|
3899
|
-
const { generateSharedComponentsFromPlan } = await import("./plan-generator-
|
|
3899
|
+
const { generateSharedComponentsFromPlan } = await import("./plan-generator-PIDLFRWZ.js");
|
|
3900
3900
|
const generated = await generateSharedComponentsFromPlan(
|
|
3901
3901
|
plan,
|
|
3902
3902
|
styleContext,
|
|
@@ -6224,7 +6224,7 @@ Return JSON: { "requests": [{ "type": "add-page", "changes": { "name": "${compon
|
|
|
6224
6224
|
}
|
|
6225
6225
|
try {
|
|
6226
6226
|
const { validateReuse } = await import("./reuse-validator-XR2ZEYC4.js");
|
|
6227
|
-
const { inferPageTypeFromRoute: inferPageTypeFromRoute2 } = await import("./design-constraints-
|
|
6227
|
+
const { inferPageTypeFromRoute: inferPageTypeFromRoute2 } = await import("./design-constraints-HGNEY3W3.js");
|
|
6228
6228
|
const manifest2 = await loadManifest7(projectRoot);
|
|
6229
6229
|
const reuseplan = projectRoot ? loadPlan(projectRoot) : null;
|
|
6230
6230
|
if (manifest2.shared.length > 0) {
|
|
@@ -8214,7 +8214,7 @@ async function fixCommand(opts = {}) {
|
|
|
8214
8214
|
}
|
|
8215
8215
|
}
|
|
8216
8216
|
const appDir = resolve8(projectRoot, "app");
|
|
8217
|
-
|
|
8217
|
+
let allTsxFiles = listTsxFiles(appDir);
|
|
8218
8218
|
const componentsTsxFiles = listTsxFiles(resolve8(projectRoot, "components"));
|
|
8219
8219
|
const allComponentIds = /* @__PURE__ */ new Set();
|
|
8220
8220
|
for (const file of [...allTsxFiles, ...componentsTsxFiles]) {
|
|
@@ -8377,25 +8377,29 @@ async function fixCommand(opts = {}) {
|
|
|
8377
8377
|
}
|
|
8378
8378
|
}
|
|
8379
8379
|
}
|
|
8380
|
-
|
|
8380
|
+
let userTsxFiles = allTsxFiles.filter((f) => !f.includes("/design-system/"));
|
|
8381
8381
|
let syntaxFixed = 0;
|
|
8382
8382
|
for (const file of userTsxFiles) {
|
|
8383
|
-
|
|
8384
|
-
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
|
|
8388
|
-
if (
|
|
8389
|
-
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8383
|
+
try {
|
|
8384
|
+
const content = readFileSync11(file, "utf-8");
|
|
8385
|
+
const fixed = fixUnescapedLtInJsx(
|
|
8386
|
+
fixEscapedClosingQuotes(sanitizeMetadataStrings(ensureUseClientIfNeeded(content)))
|
|
8387
|
+
);
|
|
8388
|
+
if (fixed !== content) {
|
|
8389
|
+
if (!dryRun) {
|
|
8390
|
+
const result = safeWrite(file, fixed, projectRoot, backups);
|
|
8391
|
+
if (result.ok) {
|
|
8392
|
+
modifiedFiles.push(file);
|
|
8393
|
+
syntaxFixed++;
|
|
8394
|
+
} else {
|
|
8395
|
+
console.log(chalk15.yellow(` \u26A0 Syntax fix rolled back for ${relative5(projectRoot, file)} (parse error)`));
|
|
8396
|
+
}
|
|
8393
8397
|
} else {
|
|
8394
|
-
|
|
8398
|
+
syntaxFixed++;
|
|
8395
8399
|
}
|
|
8396
|
-
} else {
|
|
8397
|
-
syntaxFixed++;
|
|
8398
8400
|
}
|
|
8401
|
+
} catch (err) {
|
|
8402
|
+
remaining.push(`${relative5(projectRoot, file)}: syntax fix error \u2014 ${err instanceof Error ? err.message : "unknown"}`);
|
|
8399
8403
|
}
|
|
8400
8404
|
}
|
|
8401
8405
|
if (syntaxFixed > 0) {
|
|
@@ -8404,8 +8408,8 @@ async function fixCommand(opts = {}) {
|
|
|
8404
8408
|
console.log(chalk15.green(` \u2714 ${verb} syntax: ${syntaxFixed} file(s) (use client, metadata, quotes)`));
|
|
8405
8409
|
}
|
|
8406
8410
|
try {
|
|
8407
|
-
const { loadPlan: loadPlan2 } = await import("./plan-generator-
|
|
8408
|
-
const { ensurePlanGroupLayouts: ensurePlanGroupLayouts2 } = await import("./code-generator-
|
|
8411
|
+
const { loadPlan: loadPlan2 } = await import("./plan-generator-PIDLFRWZ.js");
|
|
8412
|
+
const { ensurePlanGroupLayouts: ensurePlanGroupLayouts2 } = await import("./code-generator-YSGVHVNN.js");
|
|
8409
8413
|
const plan = loadPlan2(projectRoot);
|
|
8410
8414
|
if (plan) {
|
|
8411
8415
|
if (!dsm) {
|
|
@@ -8459,7 +8463,7 @@ async function fixCommand(opts = {}) {
|
|
|
8459
8463
|
const publicExists = existsSync15(publicLayoutPath);
|
|
8460
8464
|
const needsPublicLayout = !publicExists || !readFileSync11(publicLayoutPath, "utf-8").includes("<Header");
|
|
8461
8465
|
if (needsPublicLayout) {
|
|
8462
|
-
const { buildPublicLayoutCodeForSidebar } = await import("./code-generator-
|
|
8466
|
+
const { buildPublicLayoutCodeForSidebar } = await import("./code-generator-YSGVHVNN.js");
|
|
8463
8467
|
mkdirSync7(resolve8(projectRoot, "app", "(public)"), { recursive: true });
|
|
8464
8468
|
const publicResult = safeWrite(publicLayoutPath, buildPublicLayoutCodeForSidebar(), projectRoot, backups);
|
|
8465
8469
|
if (publicResult.ok) {
|
|
@@ -8508,7 +8512,7 @@ async function fixCommand(opts = {}) {
|
|
|
8508
8512
|
}
|
|
8509
8513
|
const themeTogglePath = resolve8(projectRoot, "components", "shared", "theme-toggle.tsx");
|
|
8510
8514
|
if (!existsSync15(themeTogglePath)) {
|
|
8511
|
-
const { generateThemeToggleCode } = await import("./code-generator-
|
|
8515
|
+
const { generateThemeToggleCode } = await import("./code-generator-YSGVHVNN.js");
|
|
8512
8516
|
mkdirSync7(resolve8(projectRoot, "components", "shared"), { recursive: true });
|
|
8513
8517
|
const themeResult = safeWrite(themeTogglePath, generateThemeToggleCode(), projectRoot, backups);
|
|
8514
8518
|
if (themeResult.ok) {
|
|
@@ -8529,7 +8533,7 @@ async function fixCommand(opts = {}) {
|
|
|
8529
8533
|
const isMinimal = appLayoutCode.length < 500 && !appLayoutCode.includes("Header") && !appLayoutCode.includes("Footer") && !appLayoutCode.includes("Sidebar") && !appLayoutCode.includes("SidebarProvider") && !appLayoutCode.includes("SidebarTrigger") && !appLayoutCode.includes("Sheet");
|
|
8530
8534
|
const navType = dsm.getConfig().navigation?.type || "header";
|
|
8531
8535
|
if (isMinimal && navType !== "none") {
|
|
8532
|
-
const { buildAppLayoutCode, buildGroupLayoutCode } = await import("./code-generator-
|
|
8536
|
+
const { buildAppLayoutCode, buildGroupLayoutCode } = await import("./code-generator-YSGVHVNN.js");
|
|
8533
8537
|
const isSidebar = navType === "sidebar" || navType === "both";
|
|
8534
8538
|
const newLayout = isSidebar ? buildAppLayoutCode(navType, dsm.getConfig().name) : buildGroupLayoutCode("header", dsm.getConfig().pages?.map((p) => p.name) || [], dsm.getConfig().name);
|
|
8535
8539
|
if (!dryRun) {
|
|
@@ -8544,26 +8548,34 @@ async function fixCommand(opts = {}) {
|
|
|
8544
8548
|
}
|
|
8545
8549
|
}
|
|
8546
8550
|
}
|
|
8551
|
+
allTsxFiles = listTsxFiles(appDir);
|
|
8552
|
+
userTsxFiles = allTsxFiles.filter((f) => !f.includes("/design-system/"));
|
|
8553
|
+
const sharedTsxFiles = listTsxFiles(resolve8(projectRoot, "components", "shared"));
|
|
8554
|
+
const allValidationFiles = [...userTsxFiles, ...sharedTsxFiles];
|
|
8547
8555
|
if (!skipQuality) {
|
|
8548
8556
|
let qualityFixCount = 0;
|
|
8549
8557
|
const qualityFixDetails = [];
|
|
8550
|
-
for (const file of
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
if (
|
|
8555
|
-
|
|
8556
|
-
|
|
8557
|
-
|
|
8558
|
+
for (const file of allValidationFiles) {
|
|
8559
|
+
try {
|
|
8560
|
+
const content = readFileSync11(file, "utf-8");
|
|
8561
|
+
const { code: autoFixed, fixes: fileFixes } = await autoFixCode(content);
|
|
8562
|
+
if (autoFixed !== content) {
|
|
8563
|
+
if (!dryRun) {
|
|
8564
|
+
const qResult = safeWrite(file, autoFixed, projectRoot, backups);
|
|
8565
|
+
if (qResult.ok) {
|
|
8566
|
+
modifiedFiles.push(file);
|
|
8567
|
+
qualityFixCount++;
|
|
8568
|
+
qualityFixDetails.push(...fileFixes);
|
|
8569
|
+
} else {
|
|
8570
|
+
console.log(chalk15.yellow(` \u26A0 Quality fix rolled back for ${relative5(projectRoot, file)} (parse error)`));
|
|
8571
|
+
}
|
|
8572
|
+
} else {
|
|
8558
8573
|
qualityFixCount++;
|
|
8559
8574
|
qualityFixDetails.push(...fileFixes);
|
|
8560
|
-
} else {
|
|
8561
|
-
console.log(chalk15.yellow(` \u26A0 Quality fix rolled back for ${relative5(projectRoot, file)} (parse error)`));
|
|
8562
8575
|
}
|
|
8563
|
-
} else {
|
|
8564
|
-
qualityFixCount++;
|
|
8565
|
-
qualityFixDetails.push(...fileFixes);
|
|
8566
8576
|
}
|
|
8577
|
+
} catch (err) {
|
|
8578
|
+
remaining.push(`${relative5(projectRoot, file)}: quality fix error \u2014 ${err instanceof Error ? err.message : "unknown"}`);
|
|
8567
8579
|
}
|
|
8568
8580
|
}
|
|
8569
8581
|
if (qualityFixCount > 0) {
|
|
@@ -8573,6 +8585,37 @@ async function fixCommand(opts = {}) {
|
|
|
8573
8585
|
console.log(chalk15.green(` \u2714 ${verb} ${uniqueFixes.length} quality issue type(s): ${uniqueFixes.join(", ")}`));
|
|
8574
8586
|
}
|
|
8575
8587
|
}
|
|
8588
|
+
try {
|
|
8589
|
+
const { validateMockData, applyMockDataFixes } = await import("./mock-data-validator-JEWUOMFY.js");
|
|
8590
|
+
let mockFixed = 0;
|
|
8591
|
+
for (const file of allValidationFiles) {
|
|
8592
|
+
try {
|
|
8593
|
+
const content = readFileSync11(file, "utf-8");
|
|
8594
|
+
const mockIssues = validateMockData(content);
|
|
8595
|
+
if (mockIssues.length > 0) {
|
|
8596
|
+
const fixed = applyMockDataFixes(content, mockIssues);
|
|
8597
|
+
if (fixed !== content && !dryRun) {
|
|
8598
|
+
const result = safeWrite(file, fixed, projectRoot, backups);
|
|
8599
|
+
if (result.ok) {
|
|
8600
|
+
mockFixed++;
|
|
8601
|
+
modifiedFiles.push(file);
|
|
8602
|
+
}
|
|
8603
|
+
} else if (dryRun) {
|
|
8604
|
+
mockFixed++;
|
|
8605
|
+
}
|
|
8606
|
+
}
|
|
8607
|
+
} catch (fileErr) {
|
|
8608
|
+
remaining.push(`${relative5(projectRoot, file)}: mock data fix error \u2014 ${fileErr instanceof Error ? fileErr.message : "unknown"}`);
|
|
8609
|
+
}
|
|
8610
|
+
}
|
|
8611
|
+
if (mockFixed > 0) {
|
|
8612
|
+
const verb = dryRun ? "Would fix" : "Fixed";
|
|
8613
|
+
fixes.push(`${verb} mock data in ${mockFixed} file(s)`);
|
|
8614
|
+
console.log(chalk15.green(` \u2714 ${verb} mock data: ${mockFixed} file(s)`));
|
|
8615
|
+
}
|
|
8616
|
+
} catch (importErr) {
|
|
8617
|
+
console.log(chalk15.dim(" \u2298 mock-data-validator not available, skipping"));
|
|
8618
|
+
}
|
|
8576
8619
|
for (const file of modifiedFiles) {
|
|
8577
8620
|
if (!backups.has(file)) continue;
|
|
8578
8621
|
const before = backups.get(file);
|
|
@@ -8587,29 +8630,34 @@ async function fixCommand(opts = {}) {
|
|
|
8587
8630
|
let totalErrors = 0;
|
|
8588
8631
|
let totalWarnings = 0;
|
|
8589
8632
|
const fileIssues = [];
|
|
8590
|
-
for (const file of
|
|
8591
|
-
|
|
8592
|
-
|
|
8593
|
-
|
|
8594
|
-
|
|
8595
|
-
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
|
|
8599
|
-
|
|
8600
|
-
|
|
8601
|
-
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
|
|
8633
|
+
for (const file of allValidationFiles) {
|
|
8634
|
+
try {
|
|
8635
|
+
const code = readFileSync11(file, "utf-8");
|
|
8636
|
+
const relativePath = file.replace(projectRoot + "/", "");
|
|
8637
|
+
const baseName = file.split("/").pop() || "";
|
|
8638
|
+
const isAuthPage = relativePath.includes("(auth)");
|
|
8639
|
+
const isSharedComponent = relativePath.includes("components/shared/");
|
|
8640
|
+
const isNonPageFile = baseName === "layout.tsx" || baseName === "AppNav.tsx" || baseName === "not-found.tsx" || baseName === "ShowWhenNotAuthRoute.tsx";
|
|
8641
|
+
const isHomePage = relativePath === "app/page.tsx";
|
|
8642
|
+
const isDesignSystem = relativePath.includes("design-system");
|
|
8643
|
+
if (isDesignSystem) continue;
|
|
8644
|
+
const issues = validatePageQuality(code);
|
|
8645
|
+
const suppressH1 = isNonPageFile || isAuthPage || isSharedComponent;
|
|
8646
|
+
const filteredIssues = issues.filter((i) => {
|
|
8647
|
+
if (suppressH1 && (i.type === "NO_H1" || i.type === "MULTIPLE_H1")) return false;
|
|
8648
|
+
if (isHomePage && i.type === "NO_EMPTY_STATE") return false;
|
|
8649
|
+
return true;
|
|
8650
|
+
});
|
|
8651
|
+
if (filteredIssues.length === 0) continue;
|
|
8652
|
+
const errors = filteredIssues.filter((i) => i.severity === "error").length;
|
|
8653
|
+
const warnings = filteredIssues.filter((i) => i.severity === "warning").length;
|
|
8654
|
+
totalErrors += errors;
|
|
8655
|
+
totalWarnings += warnings;
|
|
8656
|
+
const report = formatIssues(filteredIssues);
|
|
8657
|
+
fileIssues.push({ path: relativePath, report });
|
|
8658
|
+
} catch (err) {
|
|
8659
|
+
remaining.push(`${relative5(projectRoot, file)}: validation error \u2014 ${err instanceof Error ? err.message : "unknown"}`);
|
|
8660
|
+
}
|
|
8613
8661
|
}
|
|
8614
8662
|
try {
|
|
8615
8663
|
let manifest = await loadManifest9(project.root);
|
|
@@ -8690,6 +8738,29 @@ async function fixCommand(opts = {}) {
|
|
|
8690
8738
|
);
|
|
8691
8739
|
}
|
|
8692
8740
|
}
|
|
8741
|
+
try {
|
|
8742
|
+
const tsconfigPath = resolve8(projectRoot, "tsconfig.json");
|
|
8743
|
+
if (existsSync15(tsconfigPath)) {
|
|
8744
|
+
const { execSync: execSync2 } = await import("child_process");
|
|
8745
|
+
execSync2("npx tsc --noEmit --pretty 2>&1", {
|
|
8746
|
+
cwd: projectRoot,
|
|
8747
|
+
timeout: 3e4,
|
|
8748
|
+
encoding: "utf-8"
|
|
8749
|
+
});
|
|
8750
|
+
fixes.push("TypeScript compilation clean");
|
|
8751
|
+
console.log(chalk15.green(" \u2714 TypeScript compilation clean"));
|
|
8752
|
+
}
|
|
8753
|
+
} catch (err) {
|
|
8754
|
+
const output = (err.stdout || "") + (err.stderr || "");
|
|
8755
|
+
const errorLines = output.split("\n").filter((l) => l.includes("error TS"));
|
|
8756
|
+
if (errorLines.length > 0) {
|
|
8757
|
+
for (const line of errorLines.slice(0, 10)) {
|
|
8758
|
+
remaining.push(line.trim());
|
|
8759
|
+
}
|
|
8760
|
+
if (errorLines.length > 10) remaining.push(`... and ${errorLines.length - 10} more TypeScript errors`);
|
|
8761
|
+
console.log(chalk15.yellow(` \u26A0 TypeScript: ${errorLines.length} error(s)`));
|
|
8762
|
+
}
|
|
8763
|
+
}
|
|
8693
8764
|
if (fixes.length === 0 && totalErrors === 0 && totalWarnings === 0 && remaining.length === 0) {
|
|
8694
8765
|
console.log(chalk15.green("\n \u2705 Everything looks good \u2014 no issues found\n"));
|
|
8695
8766
|
console.log(chalk15.cyan(" Run: coherent preview\n"));
|
|
@@ -8965,7 +9036,7 @@ async function checkCommand(opts = {}) {
|
|
|
8965
9036
|
if (!skipShared) {
|
|
8966
9037
|
try {
|
|
8967
9038
|
const { validateReuse } = await import("./reuse-validator-XR2ZEYC4.js");
|
|
8968
|
-
const { inferPageTypeFromRoute: inferPageTypeFromRoute2 } = await import("./design-constraints-
|
|
9039
|
+
const { inferPageTypeFromRoute: inferPageTypeFromRoute2 } = await import("./design-constraints-HGNEY3W3.js");
|
|
8969
9040
|
const manifest = await loadManifest10(projectRoot);
|
|
8970
9041
|
const appDir = resolve9(projectRoot, "app");
|
|
8971
9042
|
const pageFiles = existsSync16(appDir) ? findTsxFiles(appDir) : [];
|
|
@@ -9816,7 +9887,7 @@ function checkMissingCssVars(projectRoot) {
|
|
|
9816
9887
|
function patchGlobalsCss(projectRoot, missingVars) {
|
|
9817
9888
|
const globalsPath = join15(projectRoot, "app", "globals.css");
|
|
9818
9889
|
if (!existsSync19(globalsPath) || missingVars.length === 0) return;
|
|
9819
|
-
const { writeFileSync:
|
|
9890
|
+
const { writeFileSync: writeFileSync12 } = __require("fs");
|
|
9820
9891
|
let content = readFileSync13(globalsPath, "utf-8");
|
|
9821
9892
|
const defaultValues = {
|
|
9822
9893
|
"--chart-1": "220 70% 50%",
|
|
@@ -9845,7 +9916,7 @@ function patchGlobalsCss(projectRoot, missingVars) {
|
|
|
9845
9916
|
const lightSectionEnd = content.indexOf("}");
|
|
9846
9917
|
if (lightSectionEnd > 0) {
|
|
9847
9918
|
content = content.slice(0, lightSectionEnd) + "\n" + injection + "\n" + content.slice(lightSectionEnd);
|
|
9848
|
-
|
|
9919
|
+
writeFileSync12(globalsPath, content, "utf-8");
|
|
9849
9920
|
}
|
|
9850
9921
|
}
|
|
9851
9922
|
|
|
@@ -10377,7 +10448,7 @@ async function syncCommand(options = {}) {
|
|
|
10377
10448
|
// src/commands/migrate.ts
|
|
10378
10449
|
import chalk28 from "chalk";
|
|
10379
10450
|
import ora10 from "ora";
|
|
10380
|
-
import { existsSync as existsSync21, mkdirSync as mkdirSync8, cpSync, rmSync as rmSync6, writeFileSync as
|
|
10451
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync8, cpSync, rmSync as rmSync6, writeFileSync as writeFileSync10, readFileSync as readFileSync15, readdirSync as readdirSync9 } from "fs";
|
|
10381
10452
|
import { join as join17 } from "path";
|
|
10382
10453
|
function backupDir(projectRoot) {
|
|
10383
10454
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
@@ -10402,7 +10473,7 @@ function createBackup2(projectRoot) {
|
|
|
10402
10473
|
function setGuard(projectRoot, backupPath) {
|
|
10403
10474
|
const guard = guardPath(projectRoot);
|
|
10404
10475
|
mkdirSync8(join17(projectRoot, ".coherent"), { recursive: true });
|
|
10405
|
-
|
|
10476
|
+
writeFileSync10(guard, JSON.stringify({ backup: backupPath, startedAt: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
10406
10477
|
}
|
|
10407
10478
|
function clearGuard(projectRoot) {
|
|
10408
10479
|
const guard = guardPath(projectRoot);
|
|
@@ -10506,7 +10577,7 @@ Found ${migratable.length} component(s) to migrate:`));
|
|
|
10506
10577
|
}
|
|
10507
10578
|
|
|
10508
10579
|
// src/utils/update-notifier.ts
|
|
10509
|
-
import { existsSync as existsSync22, mkdirSync as mkdirSync9, readFileSync as readFileSync16, writeFileSync as
|
|
10580
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync9, readFileSync as readFileSync16, writeFileSync as writeFileSync11 } from "fs";
|
|
10510
10581
|
import { join as join18 } from "path";
|
|
10511
10582
|
import { homedir } from "os";
|
|
10512
10583
|
import chalk29 from "chalk";
|
|
@@ -10529,7 +10600,7 @@ function readCache() {
|
|
|
10529
10600
|
function writeCache(data) {
|
|
10530
10601
|
try {
|
|
10531
10602
|
if (!existsSync22(CACHE_DIR)) mkdirSync9(CACHE_DIR, { recursive: true });
|
|
10532
|
-
|
|
10603
|
+
writeFileSync11(CACHE_FILE, JSON.stringify(data), "utf-8");
|
|
10533
10604
|
} catch (e) {
|
|
10534
10605
|
if (DEBUG5) console.error("Failed to write update cache:", e);
|
|
10535
10606
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import "./chunk-3RG5ZIWI.js";
|
|
2
|
+
|
|
3
|
+
// src/utils/mock-data-validator.ts
|
|
4
|
+
function generateRecentIsoDate(offsetHours = 0) {
|
|
5
|
+
const d = /* @__PURE__ */ new Date();
|
|
6
|
+
d.setHours(d.getHours() - offsetHours);
|
|
7
|
+
return d.toISOString();
|
|
8
|
+
}
|
|
9
|
+
function getLineAndCol(code, index) {
|
|
10
|
+
const lines = code.slice(0, index).split("\n");
|
|
11
|
+
return { line: lines.length, column: (lines[lines.length - 1]?.length ?? 0) + 1 };
|
|
12
|
+
}
|
|
13
|
+
function validateMockData(code) {
|
|
14
|
+
const issues = [];
|
|
15
|
+
let offset = 0;
|
|
16
|
+
const dateCtorRe = /new Date\(["']([^"']+)["']\)/g;
|
|
17
|
+
let m;
|
|
18
|
+
while ((m = dateCtorRe.exec(code)) !== null) {
|
|
19
|
+
const dateStr = m[1];
|
|
20
|
+
if (isNaN(new Date(dateStr).getTime())) {
|
|
21
|
+
const { line, column } = getLineAndCol(code, m.index);
|
|
22
|
+
const valueStart = m.index + m[0].indexOf(dateStr);
|
|
23
|
+
const valueEnd = valueStart + dateStr.length;
|
|
24
|
+
issues.push({
|
|
25
|
+
line,
|
|
26
|
+
column,
|
|
27
|
+
message: `Invalid Date: new Date("${dateStr}") will throw at runtime`,
|
|
28
|
+
fixable: true,
|
|
29
|
+
replacement: {
|
|
30
|
+
start: valueStart,
|
|
31
|
+
end: valueEnd,
|
|
32
|
+
text: generateRecentIsoDate(offset++)
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const mockFieldRe = /(?:timestamp|date|createdAt|updatedAt|time|startDate|endDate|dueDate)\s*:\s*["']((?:\d+\s+(?:hours?|minutes?|days?|weeks?|months?|years?)\s+ago)|yesterday|today|last\s+\w+|just\s+now|recently)["']/gi;
|
|
38
|
+
while ((m = mockFieldRe.exec(code)) !== null) {
|
|
39
|
+
const dateStr = m[1];
|
|
40
|
+
const { line, column } = getLineAndCol(code, m.index);
|
|
41
|
+
const fullMatch = m[0];
|
|
42
|
+
const valueStart = m.index + fullMatch.indexOf(dateStr);
|
|
43
|
+
const valueEnd = valueStart + dateStr.length;
|
|
44
|
+
issues.push({
|
|
45
|
+
line,
|
|
46
|
+
column,
|
|
47
|
+
message: `Mock data "${dateStr}" is a display string, not a valid Date \u2014 use ISO 8601`,
|
|
48
|
+
fixable: true,
|
|
49
|
+
replacement: {
|
|
50
|
+
start: valueStart,
|
|
51
|
+
end: valueEnd,
|
|
52
|
+
text: generateRecentIsoDate(offset++)
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return issues;
|
|
57
|
+
}
|
|
58
|
+
function applyMockDataFixes(code, issues) {
|
|
59
|
+
const fixable = issues.filter((i) => i.fixable && i.replacement).sort((a, b) => b.replacement.start - a.replacement.start);
|
|
60
|
+
let result = code;
|
|
61
|
+
for (const issue of fixable) {
|
|
62
|
+
const r = issue.replacement;
|
|
63
|
+
result = result.slice(0, r.start) + r.text + result.slice(r.end);
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
export {
|
|
68
|
+
applyMockDataFixes,
|
|
69
|
+
validateMockData
|
|
70
|
+
};
|
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
routeToKey,
|
|
12
12
|
savePlan,
|
|
13
13
|
updateArchitecturePlan
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-VLBVBF6V.js";
|
|
15
|
+
import "./chunk-E23FJX2I.js";
|
|
16
16
|
import "./chunk-NOM47EB4.js";
|
|
17
17
|
import "./chunk-3RG5ZIWI.js";
|
|
18
18
|
export {
|
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.45",
|
|
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.45"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@types/node": "^20.11.0",
|