@doccov/cli 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/cli.js +83 -73
- package/package.json +2 -3
package/dist/cli.js
CHANGED
|
@@ -170,7 +170,6 @@ import {
|
|
|
170
170
|
serializeJSDoc
|
|
171
171
|
} from "@doccov/sdk";
|
|
172
172
|
import chalk from "chalk";
|
|
173
|
-
import ora from "ora";
|
|
174
173
|
|
|
175
174
|
// src/utils/llm-assertion-parser.ts
|
|
176
175
|
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
@@ -243,11 +242,6 @@ async function parseAssertionsWithLLM(code) {
|
|
|
243
242
|
// src/commands/check.ts
|
|
244
243
|
var defaultDependencies = {
|
|
245
244
|
createDocCov: (options) => new DocCov(options),
|
|
246
|
-
spinner: (text) => ora({
|
|
247
|
-
text,
|
|
248
|
-
discardStdin: false,
|
|
249
|
-
hideCursor: true
|
|
250
|
-
}),
|
|
251
245
|
log: console.log,
|
|
252
246
|
error: console.error
|
|
253
247
|
};
|
|
@@ -276,7 +270,7 @@ function groupByExport(drifts) {
|
|
|
276
270
|
return map;
|
|
277
271
|
}
|
|
278
272
|
function registerCheckCommand(program, dependencies = {}) {
|
|
279
|
-
const { createDocCov,
|
|
273
|
+
const { createDocCov, log, error } = {
|
|
280
274
|
...defaultDependencies,
|
|
281
275
|
...dependencies
|
|
282
276
|
};
|
|
@@ -315,15 +309,17 @@ function registerCheckCommand(program, dependencies = {}) {
|
|
|
315
309
|
}
|
|
316
310
|
const minCoverage = clampCoverage(options.minCoverage ?? 80);
|
|
317
311
|
const resolveExternalTypes = !options.skipResolve;
|
|
318
|
-
|
|
319
|
-
|
|
312
|
+
process.stdout.write(chalk.cyan(`> Analyzing documentation coverage...
|
|
313
|
+
`));
|
|
320
314
|
let specResult;
|
|
321
315
|
try {
|
|
322
316
|
const doccov = createDocCov({ resolveExternalTypes });
|
|
323
317
|
specResult = await doccov.analyzeFileWithDiagnostics(entryFile);
|
|
324
|
-
|
|
318
|
+
process.stdout.write(chalk.green(`✓ Documentation analysis complete
|
|
319
|
+
`));
|
|
325
320
|
} catch (analysisError) {
|
|
326
|
-
|
|
321
|
+
process.stdout.write(chalk.red(`✗ Failed to analyze documentation coverage
|
|
322
|
+
`));
|
|
327
323
|
throw analysisError;
|
|
328
324
|
}
|
|
329
325
|
if (!specResult) {
|
|
@@ -359,8 +355,8 @@ function registerCheckCommand(program, dependencies = {}) {
|
|
|
359
355
|
if (allExamples.length === 0) {
|
|
360
356
|
log(chalk.gray("No @example blocks found"));
|
|
361
357
|
} else {
|
|
362
|
-
|
|
363
|
-
|
|
358
|
+
process.stdout.write(chalk.cyan(`> Installing package for examples...
|
|
359
|
+
`));
|
|
364
360
|
const flatExamples = allExamples.flatMap((e) => e.examples);
|
|
365
361
|
const packageResult = await runExamplesWithPackage(flatExamples, {
|
|
366
362
|
packagePath: targetDir,
|
|
@@ -369,10 +365,12 @@ function registerCheckCommand(program, dependencies = {}) {
|
|
|
369
365
|
cwd: targetDir
|
|
370
366
|
});
|
|
371
367
|
if (!packageResult.installSuccess) {
|
|
372
|
-
|
|
368
|
+
process.stdout.write(chalk.red(`✗ Package install failed: ${packageResult.installError}
|
|
369
|
+
`));
|
|
373
370
|
log(chalk.yellow("Skipping example execution. Ensure the package is built."));
|
|
374
371
|
} else {
|
|
375
|
-
|
|
372
|
+
process.stdout.write(chalk.cyan(`> Running @example blocks...
|
|
373
|
+
`));
|
|
376
374
|
let examplesRun = 0;
|
|
377
375
|
let examplesFailed = 0;
|
|
378
376
|
let exampleIndex = 0;
|
|
@@ -442,9 +440,11 @@ function registerCheckCommand(program, dependencies = {}) {
|
|
|
442
440
|
}
|
|
443
441
|
}
|
|
444
442
|
if (examplesFailed > 0) {
|
|
445
|
-
|
|
443
|
+
process.stdout.write(chalk.red(`✗ ${examplesFailed}/${examplesRun} example(s) failed
|
|
444
|
+
`));
|
|
446
445
|
} else {
|
|
447
|
-
|
|
446
|
+
process.stdout.write(chalk.green(`✓ ${examplesRun} example(s) passed
|
|
447
|
+
`));
|
|
448
448
|
}
|
|
449
449
|
}
|
|
450
450
|
}
|
|
@@ -538,16 +538,18 @@ function registerCheckCommand(program, dependencies = {}) {
|
|
|
538
538
|
}
|
|
539
539
|
log(chalk.gray("Run without --dry-run to apply these changes."));
|
|
540
540
|
} else {
|
|
541
|
-
|
|
542
|
-
|
|
541
|
+
process.stdout.write(chalk.cyan(`> Applying fixes...
|
|
542
|
+
`));
|
|
543
543
|
const applyResult = await applyEdits(edits);
|
|
544
544
|
if (applyResult.errors.length > 0) {
|
|
545
|
-
|
|
545
|
+
process.stdout.write(chalk.yellow(`⚠ Some fixes could not be applied
|
|
546
|
+
`));
|
|
546
547
|
for (const err of applyResult.errors) {
|
|
547
548
|
error(chalk.red(` ${err.file}: ${err.error}`));
|
|
548
549
|
}
|
|
549
550
|
} else {
|
|
550
|
-
|
|
551
|
+
process.stdout.write(chalk.green(`✓ Applied ${applyResult.editsApplied} fix(es) to ${applyResult.filesModified} file(s)
|
|
552
|
+
`));
|
|
551
553
|
}
|
|
552
554
|
log("");
|
|
553
555
|
for (const [filePath, fileEdits] of editsByFile) {
|
|
@@ -943,7 +945,6 @@ import {
|
|
|
943
945
|
} from "@doccov/sdk";
|
|
944
946
|
import { normalize, validateSpec } from "@openpkg-ts/spec";
|
|
945
947
|
import chalk4 from "chalk";
|
|
946
|
-
import ora2 from "ora";
|
|
947
948
|
|
|
948
949
|
// src/utils/filter-options.ts
|
|
949
950
|
import chalk3 from "chalk";
|
|
@@ -999,11 +1000,6 @@ var mergeFilterOptions = (config, cliOptions) => {
|
|
|
999
1000
|
var defaultDependencies3 = {
|
|
1000
1001
|
createDocCov: (options) => new DocCov2(options),
|
|
1001
1002
|
writeFileSync: fs3.writeFileSync,
|
|
1002
|
-
spinner: (text) => ora2({
|
|
1003
|
-
text,
|
|
1004
|
-
discardStdin: false,
|
|
1005
|
-
hideCursor: true
|
|
1006
|
-
}),
|
|
1007
1003
|
log: console.log,
|
|
1008
1004
|
error: console.error
|
|
1009
1005
|
};
|
|
@@ -1028,7 +1024,7 @@ function formatDiagnosticOutput(prefix, diagnostic, baseDir) {
|
|
|
1028
1024
|
return `${prefix} ${locationPrefix}${diagnostic.message}`;
|
|
1029
1025
|
}
|
|
1030
1026
|
function registerGenerateCommand(program, dependencies = {}) {
|
|
1031
|
-
const { createDocCov, writeFileSync: writeFileSync2,
|
|
1027
|
+
const { createDocCov, writeFileSync: writeFileSync2, log, error } = {
|
|
1032
1028
|
...defaultDependencies3,
|
|
1033
1029
|
...dependencies
|
|
1034
1030
|
};
|
|
@@ -1083,8 +1079,8 @@ function registerGenerateCommand(program, dependencies = {}) {
|
|
|
1083
1079
|
for (const message of resolvedFilters.messages) {
|
|
1084
1080
|
log(chalk4.gray(`• ${message}`));
|
|
1085
1081
|
}
|
|
1086
|
-
|
|
1087
|
-
|
|
1082
|
+
process.stdout.write(chalk4.cyan(`> Generating OpenPkg spec...
|
|
1083
|
+
`));
|
|
1088
1084
|
let result;
|
|
1089
1085
|
try {
|
|
1090
1086
|
const doccov = createDocCov({
|
|
@@ -1097,9 +1093,11 @@ function registerGenerateCommand(program, dependencies = {}) {
|
|
|
1097
1093
|
}
|
|
1098
1094
|
} : {};
|
|
1099
1095
|
result = await doccov.analyzeFileWithDiagnostics(entryFile, analyzeOptions);
|
|
1100
|
-
|
|
1096
|
+
process.stdout.write(chalk4.green(`✓ Generated OpenPkg spec
|
|
1097
|
+
`));
|
|
1101
1098
|
} catch (generationError) {
|
|
1102
|
-
|
|
1099
|
+
process.stdout.write(chalk4.red(`✗ Failed to generate spec
|
|
1100
|
+
`));
|
|
1103
1101
|
throw generationError;
|
|
1104
1102
|
}
|
|
1105
1103
|
if (!result) {
|
|
@@ -1278,7 +1276,6 @@ import {
|
|
|
1278
1276
|
NodeFileSystem as NodeFileSystem3
|
|
1279
1277
|
} from "@doccov/sdk";
|
|
1280
1278
|
import chalk6 from "chalk";
|
|
1281
|
-
import ora3 from "ora";
|
|
1282
1279
|
|
|
1283
1280
|
// src/reports/markdown.ts
|
|
1284
1281
|
function bar(pct, width = 10) {
|
|
@@ -1480,16 +1477,20 @@ function registerReportCommand(program) {
|
|
|
1480
1477
|
} else {
|
|
1481
1478
|
entryFile = path6.resolve(targetDir, entryFile);
|
|
1482
1479
|
}
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1480
|
+
process.stdout.write(chalk6.cyan(`> Analyzing...
|
|
1481
|
+
`));
|
|
1482
|
+
try {
|
|
1483
|
+
const resolveExternalTypes = !options.skipResolve;
|
|
1484
|
+
const doccov = new DocCov3({ resolveExternalTypes });
|
|
1485
|
+
const result = await doccov.analyzeFileWithDiagnostics(entryFile);
|
|
1486
|
+
process.stdout.write(chalk6.green(`✓ Analysis complete
|
|
1487
|
+
`));
|
|
1488
|
+
spec = result.spec;
|
|
1489
|
+
} catch (analysisError) {
|
|
1490
|
+
process.stdout.write(chalk6.red(`✗ Analysis failed
|
|
1491
|
+
`));
|
|
1492
|
+
throw analysisError;
|
|
1493
|
+
}
|
|
1493
1494
|
}
|
|
1494
1495
|
const stats = computeStats(spec);
|
|
1495
1496
|
const format = options.output;
|
|
@@ -1532,7 +1533,6 @@ import {
|
|
|
1532
1533
|
NodeFileSystem as NodeFileSystem4
|
|
1533
1534
|
} from "@doccov/sdk";
|
|
1534
1535
|
import chalk7 from "chalk";
|
|
1535
|
-
import ora4 from "ora";
|
|
1536
1536
|
import { simpleGit } from "simple-git";
|
|
1537
1537
|
|
|
1538
1538
|
// src/utils/github-url.ts
|
|
@@ -1660,16 +1660,11 @@ async function generateBuildPlan(repoDir) {
|
|
|
1660
1660
|
// src/commands/scan.ts
|
|
1661
1661
|
var defaultDependencies5 = {
|
|
1662
1662
|
createDocCov: (options) => new DocCov4(options),
|
|
1663
|
-
spinner: (text) => ora4({
|
|
1664
|
-
text,
|
|
1665
|
-
discardStdin: false,
|
|
1666
|
-
hideCursor: true
|
|
1667
|
-
}),
|
|
1668
1663
|
log: console.log,
|
|
1669
1664
|
error: console.error
|
|
1670
1665
|
};
|
|
1671
1666
|
function registerScanCommand(program, dependencies = {}) {
|
|
1672
|
-
const { createDocCov,
|
|
1667
|
+
const { createDocCov, log, error } = {
|
|
1673
1668
|
...defaultDependencies5,
|
|
1674
1669
|
...dependencies
|
|
1675
1670
|
};
|
|
@@ -1685,8 +1680,8 @@ function registerScanCommand(program, dependencies = {}) {
|
|
|
1685
1680
|
log("");
|
|
1686
1681
|
tempDir = path8.join(os.tmpdir(), `doccov-scan-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
1687
1682
|
fs7.mkdirSync(tempDir, { recursive: true });
|
|
1688
|
-
|
|
1689
|
-
|
|
1683
|
+
process.stdout.write(chalk7.cyan(`> Cloning ${parsed.owner}/${parsed.repo}...
|
|
1684
|
+
`));
|
|
1690
1685
|
try {
|
|
1691
1686
|
const git = simpleGit({
|
|
1692
1687
|
timeout: {
|
|
@@ -1707,9 +1702,11 @@ function registerScanCommand(program, dependencies = {}) {
|
|
|
1707
1702
|
} finally {
|
|
1708
1703
|
process.env = originalEnv;
|
|
1709
1704
|
}
|
|
1710
|
-
|
|
1705
|
+
process.stdout.write(chalk7.green(`✓ Cloned ${parsed.owner}/${parsed.repo}
|
|
1706
|
+
`));
|
|
1711
1707
|
} catch (cloneError) {
|
|
1712
|
-
|
|
1708
|
+
process.stdout.write(chalk7.red(`✗ Failed to clone repository
|
|
1709
|
+
`));
|
|
1713
1710
|
const message = cloneError instanceof Error ? cloneError.message : String(cloneError);
|
|
1714
1711
|
if (message.includes("Authentication failed") || message.includes("could not read Username") || message.includes("terminal prompts disabled") || message.includes("Invalid username or password") || message.includes("Permission denied")) {
|
|
1715
1712
|
throw new Error(`Authentication required: This repository appears to be private. ` + `Public repositories only are currently supported.
|
|
@@ -1728,8 +1725,8 @@ function registerScanCommand(program, dependencies = {}) {
|
|
|
1728
1725
|
if (options.skipInstall) {
|
|
1729
1726
|
log(chalk7.gray("Skipping dependency installation (--skip-install)"));
|
|
1730
1727
|
} else {
|
|
1731
|
-
|
|
1732
|
-
|
|
1728
|
+
process.stdout.write(chalk7.cyan(`> Installing dependencies...
|
|
1729
|
+
`));
|
|
1733
1730
|
const installErrors = [];
|
|
1734
1731
|
try {
|
|
1735
1732
|
const { execSync } = await import("node:child_process");
|
|
@@ -1778,16 +1775,19 @@ function registerScanCommand(program, dependencies = {}) {
|
|
|
1778
1775
|
}
|
|
1779
1776
|
}
|
|
1780
1777
|
if (installed) {
|
|
1781
|
-
|
|
1778
|
+
process.stdout.write(chalk7.green(`✓ Dependencies installed
|
|
1779
|
+
`));
|
|
1782
1780
|
} else {
|
|
1783
|
-
|
|
1781
|
+
process.stdout.write(chalk7.yellow(`⚠ Could not install dependencies (analysis may be limited)
|
|
1782
|
+
`));
|
|
1784
1783
|
for (const err of installErrors) {
|
|
1785
1784
|
log(chalk7.gray(` ${err}`));
|
|
1786
1785
|
}
|
|
1787
1786
|
}
|
|
1788
1787
|
} catch (outerError) {
|
|
1789
1788
|
const msg = outerError instanceof Error ? outerError.message : String(outerError);
|
|
1790
|
-
|
|
1789
|
+
process.stdout.write(chalk7.yellow(`⚠ Could not install dependencies: ${msg.slice(0, 100)}
|
|
1790
|
+
`));
|
|
1791
1791
|
for (const err of installErrors) {
|
|
1792
1792
|
log(chalk7.gray(` ${err}`));
|
|
1793
1793
|
}
|
|
@@ -1818,13 +1818,14 @@ function registerScanCommand(program, dependencies = {}) {
|
|
|
1818
1818
|
packageName = pkg.name;
|
|
1819
1819
|
log(chalk7.gray(`Analyzing package: ${packageName}`));
|
|
1820
1820
|
}
|
|
1821
|
-
|
|
1822
|
-
|
|
1821
|
+
process.stdout.write(chalk7.cyan(`> Detecting entry point...
|
|
1822
|
+
`));
|
|
1823
1823
|
let entryPath;
|
|
1824
1824
|
const targetFs = mono.isMonorepo ? new NodeFileSystem4(targetDir) : fileSystem;
|
|
1825
1825
|
let buildFailed = false;
|
|
1826
1826
|
const runLlmFallback = async (reason) => {
|
|
1827
|
-
|
|
1827
|
+
process.stdout.write(chalk7.cyan(`> ${reason}, trying LLM fallback...
|
|
1828
|
+
`));
|
|
1828
1829
|
const plan = await generateBuildPlan(targetDir);
|
|
1829
1830
|
if (!plan) {
|
|
1830
1831
|
return null;
|
|
@@ -1858,45 +1859,54 @@ function registerScanCommand(program, dependencies = {}) {
|
|
|
1858
1859
|
const buildInfo = await detectBuildInfo(targetFs);
|
|
1859
1860
|
const needsBuildStep = entry.isDeclarationOnly && buildInfo.exoticIndicators.wasm;
|
|
1860
1861
|
if (needsBuildStep) {
|
|
1861
|
-
|
|
1862
|
+
process.stdout.write(chalk7.cyan(`> Detected .d.ts entry with WASM indicators...
|
|
1863
|
+
`));
|
|
1862
1864
|
const llmEntry = await runLlmFallback("WASM project detected");
|
|
1863
1865
|
if (llmEntry) {
|
|
1864
1866
|
entryPath = path8.join(targetDir, llmEntry);
|
|
1865
1867
|
if (buildFailed) {
|
|
1866
|
-
|
|
1868
|
+
process.stdout.write(chalk7.green(`✓ Entry point: ${llmEntry} (using pre-committed declarations)
|
|
1869
|
+
`));
|
|
1867
1870
|
log(chalk7.gray(" Coverage may be limited - generated .d.ts files typically lack JSDoc"));
|
|
1868
1871
|
} else {
|
|
1869
|
-
|
|
1872
|
+
process.stdout.write(chalk7.green(`✓ Entry point: ${llmEntry} (from LLM fallback - WASM project)
|
|
1873
|
+
`));
|
|
1870
1874
|
}
|
|
1871
1875
|
} else {
|
|
1872
1876
|
entryPath = path8.join(targetDir, entry.path);
|
|
1873
|
-
|
|
1877
|
+
process.stdout.write(chalk7.green(`✓ Entry point: ${entry.path} (from ${entry.source})
|
|
1878
|
+
`));
|
|
1874
1879
|
log(chalk7.yellow(" ⚠ WASM project detected but no API key - analysis may be limited"));
|
|
1875
1880
|
}
|
|
1876
1881
|
} else {
|
|
1877
1882
|
entryPath = path8.join(targetDir, entry.path);
|
|
1878
|
-
|
|
1883
|
+
process.stdout.write(chalk7.green(`✓ Entry point: ${entry.path} (from ${entry.source})
|
|
1884
|
+
`));
|
|
1879
1885
|
}
|
|
1880
1886
|
} catch (entryError) {
|
|
1881
1887
|
const llmEntry = await runLlmFallback("Heuristics failed");
|
|
1882
1888
|
if (llmEntry) {
|
|
1883
1889
|
entryPath = path8.join(targetDir, llmEntry);
|
|
1884
|
-
|
|
1890
|
+
process.stdout.write(chalk7.green(`✓ Entry point: ${llmEntry} (from LLM fallback)
|
|
1891
|
+
`));
|
|
1885
1892
|
} else {
|
|
1886
|
-
|
|
1893
|
+
process.stdout.write(chalk7.red(`✗ Could not detect entry point (set OPENAI_API_KEY for smart fallback)
|
|
1894
|
+
`));
|
|
1887
1895
|
throw entryError;
|
|
1888
1896
|
}
|
|
1889
1897
|
}
|
|
1890
|
-
|
|
1891
|
-
|
|
1898
|
+
process.stdout.write(chalk7.cyan(`> Analyzing documentation coverage...
|
|
1899
|
+
`));
|
|
1892
1900
|
let result;
|
|
1893
1901
|
try {
|
|
1894
1902
|
const resolveExternalTypes = !options.skipResolve;
|
|
1895
1903
|
const doccov = createDocCov({ resolveExternalTypes });
|
|
1896
1904
|
result = await doccov.analyzeFileWithDiagnostics(entryPath);
|
|
1897
|
-
|
|
1905
|
+
process.stdout.write(chalk7.green(`✓ Analysis complete
|
|
1906
|
+
`));
|
|
1898
1907
|
} catch (analysisError) {
|
|
1899
|
-
|
|
1908
|
+
process.stdout.write(chalk7.red(`✗ Analysis failed
|
|
1909
|
+
`));
|
|
1900
1910
|
throw analysisError;
|
|
1901
1911
|
}
|
|
1902
1912
|
const spec = result.spec;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@doccov/cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"description": "DocCov CLI - Documentation coverage and drift detection for TypeScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -49,13 +49,12 @@
|
|
|
49
49
|
"@ai-sdk/anthropic": "^1.0.0",
|
|
50
50
|
"@ai-sdk/openai": "^1.0.0",
|
|
51
51
|
"@inquirer/prompts": "^7.8.0",
|
|
52
|
-
"@doccov/sdk": "^0.3.
|
|
52
|
+
"@doccov/sdk": "^0.3.7",
|
|
53
53
|
"@openpkg-ts/spec": "^0.3.1",
|
|
54
54
|
"ai": "^4.0.0",
|
|
55
55
|
"chalk": "^5.4.1",
|
|
56
56
|
"commander": "^14.0.0",
|
|
57
57
|
"glob": "^11.0.0",
|
|
58
|
-
"ora": "^8.2.0",
|
|
59
58
|
"simple-git": "^3.27.0",
|
|
60
59
|
"zod": "^3.23.8"
|
|
61
60
|
},
|