@doccov/cli 0.30.0 → 0.30.2

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.
Files changed (2) hide show
  1. package/dist/cli.js +79 -16
  2. package/package.json +3 -3
package/dist/cli.js CHANGED
@@ -1068,8 +1068,12 @@ function bar2(pct, width = 10) {
1068
1068
  }
1069
1069
  function renderMarkdown(stats, options = {}) {
1070
1070
  const limit = options.limit ?? 20;
1071
+ const { reportUrl } = options;
1071
1072
  const lines = [];
1072
1073
  lines.push(`# DocCov Report: ${stats.packageName}@${stats.version}`);
1074
+ if (reportUrl) {
1075
+ lines.push(`[View full report →](${reportUrl})`);
1076
+ }
1073
1077
  lines.push("");
1074
1078
  if (stats.health) {
1075
1079
  const h = stats.health;
@@ -1111,19 +1115,42 @@ function renderMarkdown(stats, options = {}) {
1111
1115
  lines.push(`| ${k.kind} | ${k.count} | ${k.avgScore}% |`);
1112
1116
  }
1113
1117
  }
1114
- const lowExports = stats.exports.filter((e) => e.score < 100).slice(0, limit);
1115
- if (lowExports.length > 0) {
1118
+ const undocExports = stats.exports.filter((e) => e.score === 0);
1119
+ if (undocExports.length > 0) {
1120
+ lines.push("");
1121
+ lines.push("## Undocumented Exports");
1116
1122
  lines.push("");
1117
- lines.push("## Lowest Coverage Exports");
1123
+ lines.push("| Export | Kind | Missing |");
1124
+ lines.push("|--------|------|---------|");
1125
+ for (const e of undocExports.slice(0, limit)) {
1126
+ lines.push(`| \`${e.name}\` | ${e.kind} | ${e.missing.join(", ") || "-"} |`);
1127
+ }
1128
+ if (undocExports.length > limit) {
1129
+ const moreText = `${undocExports.length - limit} more`;
1130
+ if (reportUrl) {
1131
+ lines.push(`| [${moreText} →](${reportUrl}#undocumented) | | |`);
1132
+ } else {
1133
+ lines.push(`| ... | | ${moreText} |`);
1134
+ }
1135
+ }
1136
+ }
1137
+ const partialExports = stats.exports.filter((e) => e.score > 0 && e.score < 100);
1138
+ if (partialExports.length > 0) {
1139
+ lines.push("");
1140
+ lines.push("## Partial Coverage Exports");
1118
1141
  lines.push("");
1119
1142
  lines.push("| Export | Kind | Score | Missing |");
1120
1143
  lines.push("|--------|------|-------|---------|");
1121
- for (const e of lowExports) {
1144
+ for (const e of partialExports.slice(0, limit)) {
1122
1145
  lines.push(`| \`${e.name}\` | ${e.kind} | ${e.score}% | ${e.missing.join(", ") || "-"} |`);
1123
1146
  }
1124
- const totalLow = stats.exports.filter((e) => e.score < 100).length;
1125
- if (totalLow > limit) {
1126
- lines.push(`| ... | | | ${totalLow - limit} more |`);
1147
+ if (partialExports.length > limit) {
1148
+ const moreText = `${partialExports.length - limit} more`;
1149
+ if (reportUrl) {
1150
+ lines.push(`| [${moreText} →](${reportUrl}#partial) | | | |`);
1151
+ } else {
1152
+ lines.push(`| ... | | | ${moreText} |`);
1153
+ }
1127
1154
  }
1128
1155
  }
1129
1156
  if (stats.driftIssues.length > 0) {
@@ -1158,7 +1185,12 @@ function renderMarkdown(stats, options = {}) {
1158
1185
  lines.push(`| \`${d.exportName}\` | ${d.issue}${hint} |`);
1159
1186
  }
1160
1187
  if (issues.length > 10) {
1161
- lines.push(`| ... | ${issues.length - 10} more ${category} issues |`);
1188
+ const moreText = `${issues.length - 10} more ${category} issues`;
1189
+ if (reportUrl) {
1190
+ lines.push(`| [${moreText} →](${reportUrl}#drift-${category}) | |`);
1191
+ } else {
1192
+ lines.push(`| ... | ${moreText} |`);
1193
+ }
1162
1194
  }
1163
1195
  lines.push("");
1164
1196
  }
@@ -1178,7 +1210,32 @@ function renderMarkdown(stats, options = {}) {
1178
1210
  lines.push(`| \`${f.name}\` | ${definedIn} | ${refs}${moreRefs} |`);
1179
1211
  }
1180
1212
  if (stats.apiSurface.forgotten.length > limit) {
1181
- lines.push(`| ... | | ${stats.apiSurface.forgotten.length - limit} more |`);
1213
+ const moreText = `${stats.apiSurface.forgotten.length - limit} more`;
1214
+ if (reportUrl) {
1215
+ lines.push(`| [${moreText} →](${reportUrl}#api-surface) | | |`);
1216
+ } else {
1217
+ lines.push(`| ... | | ${moreText} |`);
1218
+ }
1219
+ }
1220
+ }
1221
+ if (stats.staleRefs && stats.staleRefs.length > 0) {
1222
+ lines.push("");
1223
+ lines.push("## Stale References");
1224
+ lines.push("");
1225
+ lines.push(`**${stats.staleRefs.length} stale reference(s)** found in documentation`);
1226
+ lines.push("");
1227
+ lines.push("| File | Line | Export |");
1228
+ lines.push("|------|------|--------|");
1229
+ for (const ref of stats.staleRefs.slice(0, limit)) {
1230
+ lines.push(`| ${ref.file} | ${ref.line} | \`${ref.exportName}\` |`);
1231
+ }
1232
+ if (stats.staleRefs.length > limit) {
1233
+ const moreText = `${stats.staleRefs.length - limit} more`;
1234
+ if (reportUrl) {
1235
+ lines.push(`| [${moreText} →](${reportUrl}#stale-refs) | | |`);
1236
+ } else {
1237
+ lines.push(`| ... | | ${moreText} |`);
1238
+ }
1182
1239
  }
1183
1240
  }
1184
1241
  lines.push("");
@@ -1192,7 +1249,7 @@ import { getExportAnalysis, getExportDrift as getExportDrift2, isFixableDrift }
1192
1249
  import {
1193
1250
  DRIFT_CATEGORIES as DRIFT_CATEGORIES2
1194
1251
  } from "@doccov/spec";
1195
- function computeStats(openpkg, doccov) {
1252
+ function computeStats(openpkg, doccov, options = {}) {
1196
1253
  const exports = openpkg.exports ?? [];
1197
1254
  const signals = {
1198
1255
  description: { covered: 0, total: 0 },
@@ -1287,13 +1344,14 @@ function computeStats(openpkg, doccov) {
1287
1344
  driftByCategory,
1288
1345
  driftSummary,
1289
1346
  apiSurface: doccov.apiSurface,
1290
- health: doccov.summary.health
1347
+ health: doccov.summary.health,
1348
+ staleRefs: options.staleRefs
1291
1349
  };
1292
1350
  }
1293
1351
  // src/reports/writer.ts
1294
1352
  import * as fs3 from "node:fs";
1295
1353
  import * as path5 from "node:path";
1296
- import { DEFAULT_REPORT_DIR, getDoccovDir, getReportPath } from "@doccov/sdk";
1354
+ import { DEFAULT_REPORT_DIR, findProjectRoot, getDoccovDir, getReportPath } from "@doccov/sdk";
1297
1355
  import chalk5 from "chalk";
1298
1356
  function writeReport(options) {
1299
1357
  const { format, content, outputPath, cwd = process.cwd(), silent = false } = options;
@@ -1304,7 +1362,8 @@ function writeReport(options) {
1304
1362
  fs3.mkdirSync(dir, { recursive: true });
1305
1363
  }
1306
1364
  fs3.writeFileSync(reportPath, content);
1307
- const relativePath = path5.relative(cwd, reportPath);
1365
+ const projectRoot = findProjectRoot(cwd);
1366
+ const relativePath = path5.relative(projectRoot, reportPath);
1308
1367
  if (!silent) {
1309
1368
  console.log(chalk5.green(`✓ Wrote ${format} report to ${relativePath}`));
1310
1369
  }
@@ -1563,15 +1622,17 @@ function handleNonTextOutput(options, deps) {
1563
1622
  minApiSurface,
1564
1623
  typecheckErrors,
1565
1624
  runtimeErrors,
1625
+ staleRefs,
1566
1626
  limit,
1567
1627
  stdout,
1568
1628
  outputPath,
1569
1629
  cwd
1570
1630
  } = options;
1571
1631
  const { log } = deps;
1572
- const stats = computeStats(openpkg, doccov);
1632
+ const stats = computeStats(openpkg, doccov, { staleRefs });
1573
1633
  const report = generateReportFromDocCov(openpkg, doccov);
1574
- const jsonContent = JSON.stringify(report, null, 2);
1634
+ const extendedReport = staleRefs.length > 0 ? { ...report, staleRefs } : report;
1635
+ const jsonContent = JSON.stringify(extendedReport, null, 2);
1575
1636
  const healthScore = doccov.summary.health?.score ?? stats.coverageScore;
1576
1637
  let formatContent;
1577
1638
  switch (format) {
@@ -1600,7 +1661,8 @@ function handleNonTextOutput(options, deps) {
1600
1661
  const apiSurfaceFailed = minApiSurface !== undefined && apiSurfaceScore < minApiSurface;
1601
1662
  const hasTypecheckErrors = typecheckErrors.length > 0;
1602
1663
  const hasRuntimeErrors = runtimeErrors > 0;
1603
- return !(healthFailed || apiSurfaceFailed || hasTypecheckErrors || hasRuntimeErrors);
1664
+ const hasStaleRefs = staleRefs.length > 0;
1665
+ return !(healthFailed || apiSurfaceFailed || hasTypecheckErrors || hasRuntimeErrors || hasStaleRefs);
1604
1666
  }
1605
1667
  function displayApiSurfaceOutput(doccov, deps) {
1606
1668
  const { log } = deps;
@@ -3787,6 +3849,7 @@ function registerCheckCommand(program, dependencies = {}) {
3787
3849
  minApiSurface,
3788
3850
  typecheckErrors,
3789
3851
  runtimeErrors: runtimeDrifts.length,
3852
+ staleRefs,
3790
3853
  limit: parseInt(options.limit, 10) || 20,
3791
3854
  stdout: options.stdout,
3792
3855
  outputPath: options.output,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doccov/cli",
3
- "version": "0.30.0",
3
+ "version": "0.30.2",
4
4
  "description": "DocCov CLI - Documentation coverage and drift detection for TypeScript",
5
5
  "keywords": [
6
6
  "typescript",
@@ -48,10 +48,10 @@
48
48
  "dependencies": {
49
49
  "@ai-sdk/anthropic": "^1.0.0",
50
50
  "@ai-sdk/openai": "^1.0.0",
51
- "@doccov/sdk": "^0.30.0",
51
+ "@doccov/sdk": "^0.30.1",
52
52
  "@doccov/spec": "^0.27.0",
53
53
  "@inquirer/prompts": "^7.8.0",
54
- "@openpkg-ts/spec": "^0.12.0",
54
+ "@openpkg-ts/spec": "^0.19.0",
55
55
  "ai": "^4.0.0",
56
56
  "chalk": "^5.4.1",
57
57
  "cheerio": "^1.1.2",