viberails 0.5.1 → 0.5.3
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.cjs +96 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +96 -36
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -361,11 +361,10 @@ function buildMenuOptions(state, packageCount) {
|
|
|
361
361
|
hint: state.fileNamingValue
|
|
362
362
|
});
|
|
363
363
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
});
|
|
364
|
+
const isMonorepo = packageCount > 0;
|
|
365
|
+
const coverageLabel = isMonorepo ? "Default coverage target" : "Test coverage target";
|
|
366
|
+
const coverageHint = state.testCoverage === 0 ? "0 (disabled)" : isMonorepo ? `${state.testCoverage}% (per-package default)` : `${state.testCoverage}%`;
|
|
367
|
+
options.push({ value: "testCoverage", label: coverageLabel, hint: coverageHint });
|
|
369
368
|
options.push({
|
|
370
369
|
value: "enforceMissingTests",
|
|
371
370
|
label: "Enforce missing tests",
|
|
@@ -375,16 +374,16 @@ function buildMenuOptions(state, packageCount) {
|
|
|
375
374
|
options.push(
|
|
376
375
|
{
|
|
377
376
|
value: "coverageSummaryPath",
|
|
378
|
-
label: "Coverage summary path",
|
|
377
|
+
label: isMonorepo ? "Default coverage summary path" : "Coverage summary path",
|
|
379
378
|
hint: state.coverageSummaryPath
|
|
380
379
|
},
|
|
381
380
|
{
|
|
382
381
|
value: "coverageCommand",
|
|
383
|
-
label: "Coverage command",
|
|
382
|
+
label: isMonorepo ? "Default coverage command" : "Coverage command",
|
|
384
383
|
hint: state.coverageCommand ?? "auto-detect from package.json test runner"
|
|
385
384
|
}
|
|
386
385
|
);
|
|
387
|
-
if (
|
|
386
|
+
if (isMonorepo) {
|
|
388
387
|
options.push({
|
|
389
388
|
value: "packageOverrides",
|
|
390
389
|
label: "Per-package coverage overrides",
|
|
@@ -1676,6 +1675,58 @@ function displayRulesPreview(config) {
|
|
|
1676
1675
|
);
|
|
1677
1676
|
console.log("");
|
|
1678
1677
|
}
|
|
1678
|
+
function displayInitSummary(config, exemptedPackages) {
|
|
1679
|
+
const root = config.packages.find((p) => p.path === ".") ?? config.packages[0];
|
|
1680
|
+
const isMonorepo = config.packages.length > 1;
|
|
1681
|
+
const ok = import_chalk4.default.green("\u2713");
|
|
1682
|
+
const off = import_chalk4.default.dim("\u25CB");
|
|
1683
|
+
console.log("");
|
|
1684
|
+
console.log(` ${import_chalk4.default.bold("Rules to apply:")}`);
|
|
1685
|
+
console.log(` ${ok} Max file size: ${import_chalk4.default.cyan(`${config.rules.maxFileLines} lines`)}`);
|
|
1686
|
+
const fileNaming = root?.conventions?.fileNaming ?? config.packages.find((p) => p.conventions?.fileNaming)?.conventions?.fileNaming;
|
|
1687
|
+
if (config.rules.enforceNaming && fileNaming) {
|
|
1688
|
+
console.log(` ${ok} File naming: ${import_chalk4.default.cyan(fileNaming)}`);
|
|
1689
|
+
} else {
|
|
1690
|
+
console.log(` ${off} File naming: ${import_chalk4.default.dim("not enforced")}`);
|
|
1691
|
+
}
|
|
1692
|
+
const testPattern = root?.structure?.testPattern ?? config.packages.find((p) => p.structure?.testPattern)?.structure?.testPattern;
|
|
1693
|
+
if (config.rules.enforceMissingTests && testPattern) {
|
|
1694
|
+
console.log(` ${ok} Missing tests: ${import_chalk4.default.cyan(`enforced (${testPattern})`)}`);
|
|
1695
|
+
} else if (config.rules.enforceMissingTests) {
|
|
1696
|
+
console.log(` ${ok} Missing tests: ${import_chalk4.default.cyan("enforced")}`);
|
|
1697
|
+
} else {
|
|
1698
|
+
console.log(` ${off} Missing tests: ${import_chalk4.default.dim("not enforced")}`);
|
|
1699
|
+
}
|
|
1700
|
+
if (config.rules.testCoverage > 0) {
|
|
1701
|
+
if (isMonorepo) {
|
|
1702
|
+
const withCoverage = config.packages.filter(
|
|
1703
|
+
(p) => (p.rules?.testCoverage ?? config.rules.testCoverage) > 0
|
|
1704
|
+
);
|
|
1705
|
+
console.log(
|
|
1706
|
+
` ${ok} Coverage: ${import_chalk4.default.cyan(`${config.rules.testCoverage}%`)} default ${import_chalk4.default.dim(`(${withCoverage.length}/${config.packages.length} packages)`)}`
|
|
1707
|
+
);
|
|
1708
|
+
} else {
|
|
1709
|
+
console.log(` ${ok} Coverage: ${import_chalk4.default.cyan(`${config.rules.testCoverage}%`)}`);
|
|
1710
|
+
}
|
|
1711
|
+
} else {
|
|
1712
|
+
console.log(` ${off} Coverage: ${import_chalk4.default.dim("disabled")}`);
|
|
1713
|
+
}
|
|
1714
|
+
if (exemptedPackages.length > 0) {
|
|
1715
|
+
console.log(
|
|
1716
|
+
` ${import_chalk4.default.dim(" exempted:")} ${import_chalk4.default.dim(exemptedPackages.join(", "))} ${import_chalk4.default.dim("(types-only)")}`
|
|
1717
|
+
);
|
|
1718
|
+
}
|
|
1719
|
+
if (isMonorepo) {
|
|
1720
|
+
console.log(
|
|
1721
|
+
`
|
|
1722
|
+
${import_chalk4.default.dim(`${config.packages.length} packages scanned \xB7 warns on violation \xB7 use --enforce in CI`)}`
|
|
1723
|
+
);
|
|
1724
|
+
} else {
|
|
1725
|
+
console.log(`
|
|
1726
|
+
${import_chalk4.default.dim("warns on violation \xB7 use --enforce in CI to block")}`);
|
|
1727
|
+
}
|
|
1728
|
+
console.log("");
|
|
1729
|
+
}
|
|
1679
1730
|
|
|
1680
1731
|
// src/display-text.ts
|
|
1681
1732
|
function plainConfidenceLabel(convention) {
|
|
@@ -1716,10 +1767,13 @@ function formatConventionsText(scanResult) {
|
|
|
1716
1767
|
}
|
|
1717
1768
|
function formatRulesText(config) {
|
|
1718
1769
|
const root = config.packages.find((p) => p.path === ".") ?? config.packages[0];
|
|
1770
|
+
const isMonorepo = config.packages.length > 1;
|
|
1719
1771
|
const lines = [];
|
|
1720
1772
|
lines.push(`Max file size: ${config.rules.maxFileLines} lines`);
|
|
1721
1773
|
if (config.rules.testCoverage > 0) {
|
|
1722
|
-
|
|
1774
|
+
const label = isMonorepo ? "Default coverage target" : "Test coverage target";
|
|
1775
|
+
const suffix = isMonorepo ? " (per-package)" : "";
|
|
1776
|
+
lines.push(`${label}: ${config.rules.testCoverage}%${suffix}`);
|
|
1723
1777
|
} else {
|
|
1724
1778
|
lines.push("Test coverage target: disabled");
|
|
1725
1779
|
}
|
|
@@ -2435,30 +2489,35 @@ var path14 = __toESM(require("path"), 1);
|
|
|
2435
2489
|
var clack7 = __toESM(require("@clack/prompts"), 1);
|
|
2436
2490
|
var import_chalk8 = __toESM(require("chalk"), 1);
|
|
2437
2491
|
function checkCoveragePrereqs(projectRoot, scanResult) {
|
|
2438
|
-
const testRunner = scanResult.stack.testRunner;
|
|
2439
|
-
if (!testRunner) return [];
|
|
2440
|
-
const runner = testRunner.name;
|
|
2441
2492
|
const pm = scanResult.stack.packageManager.name;
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
installCommand: installed ? void 0 : `${addCmd} @vitest/coverage-v8`,
|
|
2452
|
-
reason: "Required for coverage percentage checks with vitest"
|
|
2453
|
-
}
|
|
2454
|
-
];
|
|
2493
|
+
const vitestPackages = scanResult.packages.filter((pkg) => pkg.stack.testRunner?.name === "vitest").map((pkg) => pkg.relativePath);
|
|
2494
|
+
const hasVitest = vitestPackages.length > 0 || scanResult.stack.testRunner?.name === "vitest";
|
|
2495
|
+
if (!hasVitest) return [];
|
|
2496
|
+
let installed = hasDependency(projectRoot, "@vitest/coverage-v8") || hasDependency(projectRoot, "@vitest/coverage-istanbul");
|
|
2497
|
+
if (!installed && vitestPackages.length > 0) {
|
|
2498
|
+
installed = vitestPackages.every((rel) => {
|
|
2499
|
+
const pkgDir = path14.join(projectRoot, rel);
|
|
2500
|
+
return hasDependency(pkgDir, "@vitest/coverage-v8") || hasDependency(pkgDir, "@vitest/coverage-istanbul");
|
|
2501
|
+
});
|
|
2455
2502
|
}
|
|
2456
|
-
|
|
2503
|
+
const addCmd = pm === "yarn" ? "yarn add -D" : pm === "npm" ? "npm install -D" : `${pm} add -D`;
|
|
2504
|
+
const affectedPackages = vitestPackages.length > 1 ? vitestPackages : void 0;
|
|
2505
|
+
const reason = affectedPackages ? `Required for coverage in: ${affectedPackages.join(", ")}` : "Required for coverage percentage checks with vitest";
|
|
2506
|
+
return [
|
|
2507
|
+
{
|
|
2508
|
+
label: "@vitest/coverage-v8",
|
|
2509
|
+
installed,
|
|
2510
|
+
installCommand: installed ? void 0 : `${addCmd} @vitest/coverage-v8`,
|
|
2511
|
+
reason,
|
|
2512
|
+
affectedPackages
|
|
2513
|
+
}
|
|
2514
|
+
];
|
|
2457
2515
|
}
|
|
2458
2516
|
function displayMissingPrereqs(prereqs) {
|
|
2459
2517
|
const missing = prereqs.filter((p) => !p.installed);
|
|
2460
2518
|
for (const m of missing) {
|
|
2461
|
-
|
|
2519
|
+
const suffix = m.affectedPackages ? ` \u2014 needed for coverage in: ${m.affectedPackages.join(", ")}` : ` \u2014 ${m.reason}`;
|
|
2520
|
+
console.log(` ${import_chalk8.default.yellow("!")} ${m.label} not installed${suffix}`);
|
|
2462
2521
|
if (m.installCommand) {
|
|
2463
2522
|
console.log(` Install: ${import_chalk8.default.cyan(m.installCommand)}`);
|
|
2464
2523
|
}
|
|
@@ -2467,15 +2526,19 @@ function displayMissingPrereqs(prereqs) {
|
|
|
2467
2526
|
async function promptMissingPrereqs(projectRoot, prereqs) {
|
|
2468
2527
|
const missing = prereqs.filter((p) => !p.installed);
|
|
2469
2528
|
if (missing.length === 0) return { disableCoverage: false };
|
|
2470
|
-
const prereqLines = prereqs.map(
|
|
2471
|
-
(p
|
|
2472
|
-
|
|
2529
|
+
const prereqLines = prereqs.map((p) => {
|
|
2530
|
+
if (p.installed) return `\u2713 ${p.label}`;
|
|
2531
|
+
const detail = p.affectedPackages ? `needed by: ${p.affectedPackages.join(", ")}` : p.reason;
|
|
2532
|
+
return `\u2717 ${p.label} \u2014 ${detail}`;
|
|
2533
|
+
}).join("\n");
|
|
2473
2534
|
clack7.note(prereqLines, "Coverage prerequisites");
|
|
2474
2535
|
let disableCoverage = false;
|
|
2475
2536
|
for (const m of missing) {
|
|
2476
2537
|
if (!m.installCommand) continue;
|
|
2538
|
+
const pkgCount = m.affectedPackages?.length;
|
|
2539
|
+
const message = pkgCount ? `${m.label} is not installed. Required for coverage in ${pkgCount} packages using vitest.` : `${m.label} is not installed. It is required for coverage percentage checks.`;
|
|
2477
2540
|
const choice = await clack7.select({
|
|
2478
|
-
message
|
|
2541
|
+
message,
|
|
2479
2542
|
options: [
|
|
2480
2543
|
{
|
|
2481
2544
|
value: "install",
|
|
@@ -2967,11 +3030,8 @@ async function initInteractive(projectRoot, configPath, options) {
|
|
|
2967
3030
|
);
|
|
2968
3031
|
}
|
|
2969
3032
|
clack8.note(formatScanResultsText(scanResult), "Scan results");
|
|
2970
|
-
const rulesLines = formatRulesText(config);
|
|
2971
3033
|
const exemptedPkgs = getExemptedPackages(config);
|
|
2972
|
-
|
|
2973
|
-
rulesLines.push(`Auto-exempted from coverage: ${exemptedPkgs.join(", ")} (types-only)`);
|
|
2974
|
-
clack8.note(rulesLines.join("\n"), "Rules");
|
|
3034
|
+
displayInitSummary(config, exemptedPkgs);
|
|
2975
3035
|
const decision = await promptInitDecision();
|
|
2976
3036
|
if (decision === "customize") {
|
|
2977
3037
|
const rootPkg = config.packages.find((p) => p.path === ".") ?? config.packages[0];
|
|
@@ -3153,7 +3213,7 @@ ${import_chalk12.default.bold("Synced:")}`);
|
|
|
3153
3213
|
}
|
|
3154
3214
|
|
|
3155
3215
|
// src/index.ts
|
|
3156
|
-
var VERSION = "0.5.
|
|
3216
|
+
var VERSION = "0.5.3";
|
|
3157
3217
|
var program = new import_commander.Command();
|
|
3158
3218
|
program.name("viberails").description("Guardrails for vibe coding").version(VERSION);
|
|
3159
3219
|
program.command("init", { isDefault: true }).description("Scan your project and set up enforcement guardrails").option("-y, --yes", "Non-interactive mode (use defaults, high-confidence only)").option("-f, --force", "Re-initialize, replacing existing config").action(async (options) => {
|