@driftdev/cli 1.5.1 → 1.7.0
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/README.md +1 -1
- package/dist/drift.js +109 -59
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -123,7 +123,7 @@ drift scan --all --private # include private packages
|
|
|
123
123
|
|
|
124
124
|
## lint
|
|
125
125
|
|
|
126
|
-
Cross-reference JSDoc against code signatures. Detects
|
|
126
|
+
Cross-reference JSDoc against code signatures. Detects 17 drift types across 4 categories (structural, semantic, example, prose). Prose detection scans markdown files for broken import references, method calls that don't exist on any exported type, and references to deprecated APIs with no deprecation note.
|
|
127
127
|
|
|
128
128
|
```bash
|
|
129
129
|
drift lint # single package
|
package/dist/drift.js
CHANGED
|
@@ -51,8 +51,8 @@ function getGlobalConfigPath() {
|
|
|
51
51
|
var init_global = () => {};
|
|
52
52
|
|
|
53
53
|
// src/drift.ts
|
|
54
|
-
import { readFileSync as
|
|
55
|
-
import * as
|
|
54
|
+
import { readFileSync as readFileSync21 } from "node:fs";
|
|
55
|
+
import * as path31 from "node:path";
|
|
56
56
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
57
57
|
import { Command } from "commander";
|
|
58
58
|
|
|
@@ -2260,13 +2260,15 @@ function registerContextCommand(program) {
|
|
|
2260
2260
|
|
|
2261
2261
|
// src/commands/coverage.ts
|
|
2262
2262
|
import * as path16 from "node:path";
|
|
2263
|
+
import { isExternalExport } from "@driftdev/sdk";
|
|
2263
2264
|
|
|
2264
2265
|
// src/formatters/coverage.ts
|
|
2265
2266
|
function renderCoverage(data) {
|
|
2266
2267
|
const lines = [""];
|
|
2267
2268
|
const color = coverageColor(data.score);
|
|
2268
2269
|
const bar = progressBar(data.score);
|
|
2269
|
-
|
|
2270
|
+
const externalNote = data.external ? c.gray(` +${data.external} external (not resolvable here)`) : "";
|
|
2271
|
+
lines.push(indent(`Coverage ${color(`${data.score}%`)} ${bar} (${data.documented}/${data.total})${externalNote}`));
|
|
2270
2272
|
lines.push("");
|
|
2271
2273
|
if (data.undocumented.length > 0) {
|
|
2272
2274
|
lines.push(indent(c.gray("UNDOCUMENTED")));
|
|
@@ -2411,7 +2413,7 @@ function registerCoverageCommand(program) {
|
|
|
2411
2413
|
let totalAll = 0;
|
|
2412
2414
|
for (const pkg of packages) {
|
|
2413
2415
|
const { spec: spec2 } = await cachedExtract(pkg.entry);
|
|
2414
|
-
const exps = spec2.exports ?? [];
|
|
2416
|
+
const exps = (spec2.exports ?? []).filter((e) => !isExternalExport(e));
|
|
2415
2417
|
let doc = 0;
|
|
2416
2418
|
for (const e of exps) {
|
|
2417
2419
|
if (e.description?.trim())
|
|
@@ -2445,7 +2447,9 @@ function registerCoverageCommand(program) {
|
|
|
2445
2447
|
spec: options.spec,
|
|
2446
2448
|
abi: options.abi
|
|
2447
2449
|
});
|
|
2448
|
-
const
|
|
2450
|
+
const allExports = spec.exports ?? [];
|
|
2451
|
+
const exports = allExports.filter((exp) => !isExternalExport(exp));
|
|
2452
|
+
const external = allExports.length - exports.length;
|
|
2449
2453
|
const total = exports.length;
|
|
2450
2454
|
const undocumented = [];
|
|
2451
2455
|
for (const exp of exports) {
|
|
@@ -2455,7 +2459,13 @@ function registerCoverageCommand(program) {
|
|
|
2455
2459
|
}
|
|
2456
2460
|
const documented = total - undocumented.length;
|
|
2457
2461
|
const score = total > 0 ? Math.round(documented / total * 100) : 100;
|
|
2458
|
-
const data = {
|
|
2462
|
+
const data = {
|
|
2463
|
+
score,
|
|
2464
|
+
documented,
|
|
2465
|
+
total,
|
|
2466
|
+
undocumented,
|
|
2467
|
+
...external > 0 ? { external } : {}
|
|
2468
|
+
};
|
|
2459
2469
|
const next = undocumented.length > 0 ? {
|
|
2460
2470
|
suggested: "drift-enrich skill",
|
|
2461
2471
|
reason: `${undocumented.length} exports lack documentation`
|
|
@@ -3319,7 +3329,7 @@ function renderNotFound(exportName, suggestions, startTime, version) {
|
|
|
3319
3329
|
|
|
3320
3330
|
// src/commands/health.ts
|
|
3321
3331
|
import * as path22 from "node:path";
|
|
3322
|
-
import { computeDrift as computeDrift3 } from "@driftdev/sdk";
|
|
3332
|
+
import { computeDrift as computeDrift3, isExternalExport as isExternalExport2 } from "@driftdev/sdk";
|
|
3323
3333
|
|
|
3324
3334
|
// src/formatters/health.ts
|
|
3325
3335
|
function renderHealth(data, next) {
|
|
@@ -3334,7 +3344,8 @@ function renderHealth(data, next) {
|
|
|
3334
3344
|
lines.push(indent(`${sym.branch} completeness ${data.completeness}% (${data.undocumented} missing docs)`));
|
|
3335
3345
|
lines.push(indent(`${sym.end} accuracy ${data.accuracy}% (${data.drifted} stale signatures)`));
|
|
3336
3346
|
lines.push("");
|
|
3337
|
-
|
|
3347
|
+
const externalNote = data.external ? ` ${c.gray(sym.dot)} ${c.gray(`${data.external} external (not resolvable here)`)}` : "";
|
|
3348
|
+
lines.push(indent(`${data.totalExports} exports ${c.gray(sym.dot)} ${data.documented} documented ${c.gray(sym.dot)} ${data.drifted} drifted${externalNote}`));
|
|
3338
3349
|
lines.push("");
|
|
3339
3350
|
if (data.issues.length > 0) {
|
|
3340
3351
|
lines.push(indent("Top issues"));
|
|
@@ -3417,7 +3428,7 @@ function registerHealthCommand(program) {
|
|
|
3417
3428
|
let totalAll = 0;
|
|
3418
3429
|
for (const pkg of packages) {
|
|
3419
3430
|
const { spec: spec2 } = await cachedExtract(pkg.entry);
|
|
3420
|
-
const exps = spec2.exports ?? [];
|
|
3431
|
+
const exps = (spec2.exports ?? []).filter((e) => !isExternalExport2(e));
|
|
3421
3432
|
let doc = 0;
|
|
3422
3433
|
for (const e of exps) {
|
|
3423
3434
|
if (e.description?.trim())
|
|
@@ -3447,7 +3458,9 @@ function registerHealthCommand(program) {
|
|
|
3447
3458
|
packageName,
|
|
3448
3459
|
packageVersion
|
|
3449
3460
|
} = await resolveTruth({ entry: entryFile, lang, spec: options.spec, abi: options.abi });
|
|
3450
|
-
const
|
|
3461
|
+
const allExports = spec.exports ?? [];
|
|
3462
|
+
const exports = allExports.filter((exp) => !isExternalExport2(exp));
|
|
3463
|
+
const external = allExports.length - exports.length;
|
|
3451
3464
|
const total = exports.length;
|
|
3452
3465
|
let documented = 0;
|
|
3453
3466
|
for (const exp of exports) {
|
|
@@ -3465,6 +3478,7 @@ function registerHealthCommand(program) {
|
|
|
3465
3478
|
const health = computeHealth(total, documented, issues);
|
|
3466
3479
|
const data = {
|
|
3467
3480
|
...health,
|
|
3481
|
+
...external > 0 ? { external } : {},
|
|
3468
3482
|
packageName,
|
|
3469
3483
|
packageVersion
|
|
3470
3484
|
};
|
|
@@ -3894,14 +3908,8 @@ function registerInitCommand(program) {
|
|
|
3894
3908
|
}
|
|
3895
3909
|
|
|
3896
3910
|
// src/commands/lint.ts
|
|
3897
|
-
import
|
|
3898
|
-
import
|
|
3899
|
-
import {
|
|
3900
|
-
buildExportRegistry,
|
|
3901
|
-
computeDrift as computeDrift4,
|
|
3902
|
-
detectProseDrift,
|
|
3903
|
-
discoverMarkdownFiles
|
|
3904
|
-
} from "@driftdev/sdk";
|
|
3911
|
+
import * as path25 from "node:path";
|
|
3912
|
+
import { buildExportRegistry, computeDrift as computeDrift4, detectProseDrift } from "@driftdev/sdk";
|
|
3905
3913
|
|
|
3906
3914
|
// src/formatters/lint.ts
|
|
3907
3915
|
function renderLint(data, next) {
|
|
@@ -3937,9 +3945,47 @@ function renderLint(data, next) {
|
|
|
3937
3945
|
`);
|
|
3938
3946
|
}
|
|
3939
3947
|
|
|
3948
|
+
// src/utils/docs-corpus.ts
|
|
3949
|
+
import { readFileSync as readFileSync17, statSync as statSync2 } from "node:fs";
|
|
3950
|
+
import * as path24 from "node:path";
|
|
3951
|
+
import { discoverMarkdownFiles } from "@driftdev/sdk";
|
|
3952
|
+
function resolveDocsCorpus(cwd, docsPatterns, configDocs) {
|
|
3953
|
+
if (!docsPatterns || docsPatterns.length === 0) {
|
|
3954
|
+
return discoverMarkdownFiles(cwd, configDocs);
|
|
3955
|
+
}
|
|
3956
|
+
const include = [];
|
|
3957
|
+
for (const pattern of docsPatterns) {
|
|
3958
|
+
if (isDirectory(path24.resolve(cwd, pattern))) {
|
|
3959
|
+
include.push(path24.join(pattern, "**/*.md"), path24.join(pattern, "**/*.mdx"));
|
|
3960
|
+
} else {
|
|
3961
|
+
include.push(pattern);
|
|
3962
|
+
}
|
|
3963
|
+
}
|
|
3964
|
+
const files = discoverMarkdownFiles(cwd, { include });
|
|
3965
|
+
if (files.length === 0) {
|
|
3966
|
+
formatWarning(`--docs matched no markdown files: ${docsPatterns.join(", ")}`);
|
|
3967
|
+
}
|
|
3968
|
+
return files;
|
|
3969
|
+
}
|
|
3970
|
+
function isDirectory(p) {
|
|
3971
|
+
try {
|
|
3972
|
+
return statSync2(p).isDirectory();
|
|
3973
|
+
} catch {
|
|
3974
|
+
return false;
|
|
3975
|
+
}
|
|
3976
|
+
}
|
|
3977
|
+
function readPackageName(cwd = process.cwd()) {
|
|
3978
|
+
try {
|
|
3979
|
+
const pkgJson = JSON.parse(readFileSync17(path24.resolve(cwd, "package.json"), "utf-8"));
|
|
3980
|
+
return typeof pkgJson.name === "string" ? pkgJson.name : undefined;
|
|
3981
|
+
} catch {
|
|
3982
|
+
return;
|
|
3983
|
+
}
|
|
3984
|
+
}
|
|
3985
|
+
|
|
3940
3986
|
// src/commands/lint.ts
|
|
3941
3987
|
function registerLintCommand(program) {
|
|
3942
|
-
program.command("lint [entry]").description("Cross-reference docs against the API surface for accuracy issues").option("--all", "Run across all workspace packages").option("--private", "Include private packages in --all mode").option("--lang <language>", "Source language (inferred from --spec/--abi/.clar; default typescript)").option("--abi <path>", "ABI JSON file (required for --lang clarity)").option("--spec <path>", "OpenAPI document: path or URL (implies --lang openapi)").action(async (entry, options) => {
|
|
3988
|
+
program.command("lint [entry]").description("Cross-reference docs against the API surface for accuracy issues").option("--all", "Run across all workspace packages").option("--private", "Include private packages in --all mode").option("--lang <language>", "Source language (inferred from --spec/--abi/.clar; default typescript)").option("--abi <path>", "ABI JSON file (required for --lang clarity)").option("--spec <path>", "OpenAPI document: path or URL (implies --lang openapi)").option("--docs <patterns...>", "Markdown corpus for prose drift: glob patterns or directories (overrides repo-local defaults)").action(async (entry, options) => {
|
|
3943
3989
|
const startTime = Date.now();
|
|
3944
3990
|
const version = getVersion();
|
|
3945
3991
|
try {
|
|
@@ -3991,9 +4037,9 @@ function registerLintCommand(program) {
|
|
|
3991
4037
|
formatOutput("lint", { issues: [], count: 0 }, startTime, version, renderLint);
|
|
3992
4038
|
return;
|
|
3993
4039
|
}
|
|
3994
|
-
let entryFile = entry ?
|
|
4040
|
+
let entryFile = entry ? path25.resolve(process.cwd(), entry) : undefined;
|
|
3995
4041
|
if (lang === "typescript" && !entryFile) {
|
|
3996
|
-
entryFile = config.entry ?
|
|
4042
|
+
entryFile = config.entry ? path25.resolve(process.cwd(), config.entry) : detectEntry();
|
|
3997
4043
|
}
|
|
3998
4044
|
const { apiSpec: spec } = await resolveTruth({
|
|
3999
4045
|
entry: entryFile,
|
|
@@ -4014,14 +4060,12 @@ function registerLintCommand(program) {
|
|
|
4014
4060
|
});
|
|
4015
4061
|
}
|
|
4016
4062
|
}
|
|
4017
|
-
if (lang === "typescript")
|
|
4063
|
+
if (lang === "typescript" || options.docs)
|
|
4018
4064
|
try {
|
|
4019
|
-
const
|
|
4020
|
-
const pkgJson = JSON.parse(readFileSync17(pkgJsonPath, "utf-8"));
|
|
4021
|
-
const packageName = pkgJson.name;
|
|
4065
|
+
const packageName = readPackageName() ?? spec.meta?.name;
|
|
4022
4066
|
if (packageName) {
|
|
4023
4067
|
const registry = buildExportRegistry(spec);
|
|
4024
|
-
const markdownFiles =
|
|
4068
|
+
const markdownFiles = resolveDocsCorpus(process.cwd(), options.docs, config.docs);
|
|
4025
4069
|
const proseDrifts = detectProseDrift({ packageName, markdownFiles, registry });
|
|
4026
4070
|
for (const drift of proseDrifts) {
|
|
4027
4071
|
issues.push({
|
|
@@ -4059,7 +4103,7 @@ function registerLintCommand(program) {
|
|
|
4059
4103
|
}
|
|
4060
4104
|
|
|
4061
4105
|
// src/commands/list.ts
|
|
4062
|
-
import * as
|
|
4106
|
+
import * as path26 from "node:path";
|
|
4063
4107
|
import { computeDrift as computeDrift5 } from "@driftdev/sdk";
|
|
4064
4108
|
import { listExports as listExports2 } from "@openpkg-ts/sdk";
|
|
4065
4109
|
|
|
@@ -4174,7 +4218,7 @@ function registerListCommand(program) {
|
|
|
4174
4218
|
} else {
|
|
4175
4219
|
let entryFile;
|
|
4176
4220
|
if (searchOrEntry && looksLikeFilePath(searchOrEntry)) {
|
|
4177
|
-
entryFile =
|
|
4221
|
+
entryFile = path26.resolve(process.cwd(), searchOrEntry);
|
|
4178
4222
|
} else if (searchOrEntry) {
|
|
4179
4223
|
entryFile = detectEntry();
|
|
4180
4224
|
searchTerm = searchOrEntry;
|
|
@@ -4250,7 +4294,7 @@ function truthFlags(args) {
|
|
|
4250
4294
|
return out;
|
|
4251
4295
|
}
|
|
4252
4296
|
function runDrift(cliArgs, cwd) {
|
|
4253
|
-
return new Promise((
|
|
4297
|
+
return new Promise((resolve19) => {
|
|
4254
4298
|
const child = spawn(process.execPath, [process.argv[1], ...cliArgs, "--json"], {
|
|
4255
4299
|
cwd: cwd ?? process.cwd(),
|
|
4256
4300
|
env: { ...process.env, NO_COLOR: "1" },
|
|
@@ -4270,9 +4314,9 @@ function runDrift(cliArgs, cwd) {
|
|
|
4270
4314
|
try {
|
|
4271
4315
|
ok = JSON.parse(stdout).ok === true;
|
|
4272
4316
|
} catch {}
|
|
4273
|
-
|
|
4317
|
+
resolve19({ text, ok });
|
|
4274
4318
|
});
|
|
4275
|
-
child.on("error", (err) =>
|
|
4319
|
+
child.on("error", (err) => resolve19({ text: `Failed to run drift: ${err.message}`, ok: false }));
|
|
4276
4320
|
});
|
|
4277
4321
|
}
|
|
4278
4322
|
function toResult({ text, ok }) {
|
|
@@ -4386,7 +4430,7 @@ function diffArgs(command, args) {
|
|
|
4386
4430
|
// src/commands/release.ts
|
|
4387
4431
|
import { execSync as execSync4 } from "node:child_process";
|
|
4388
4432
|
import { existsSync as existsSync14, readFileSync as readFileSync18 } from "node:fs";
|
|
4389
|
-
import * as
|
|
4433
|
+
import * as path27 from "node:path";
|
|
4390
4434
|
import { computeDrift as computeDrift6 } from "@driftdev/sdk";
|
|
4391
4435
|
|
|
4392
4436
|
// src/formatters/release.ts
|
|
@@ -4434,7 +4478,7 @@ function getLastTag() {
|
|
|
4434
4478
|
}
|
|
4435
4479
|
}
|
|
4436
4480
|
function getPackageVersion(cwd) {
|
|
4437
|
-
const pkgPath =
|
|
4481
|
+
const pkgPath = path27.join(cwd, "package.json");
|
|
4438
4482
|
if (!existsSync14(pkgPath))
|
|
4439
4483
|
return null;
|
|
4440
4484
|
try {
|
|
@@ -4450,7 +4494,7 @@ function registerReleaseCommand(program) {
|
|
|
4450
4494
|
const cwd = process.cwd();
|
|
4451
4495
|
try {
|
|
4452
4496
|
const { config } = loadConfig();
|
|
4453
|
-
const entryFile = entry ?
|
|
4497
|
+
const entryFile = entry ? path27.resolve(cwd, entry) : config.entry ? path27.resolve(cwd, config.entry) : detectEntry();
|
|
4454
4498
|
const { spec } = await cachedExtract(entryFile);
|
|
4455
4499
|
const exports = spec.exports ?? [];
|
|
4456
4500
|
const total = exports.length;
|
|
@@ -4575,7 +4619,7 @@ function renderReport(data) {
|
|
|
4575
4619
|
// src/utils/scan-packages.ts
|
|
4576
4620
|
import { execSync as execSync5 } from "node:child_process";
|
|
4577
4621
|
import { existsSync as existsSync15, readFileSync as readFileSync19 } from "node:fs";
|
|
4578
|
-
import * as
|
|
4622
|
+
import * as path28 from "node:path";
|
|
4579
4623
|
import { computeDrift as computeDrift7 } from "@driftdev/sdk";
|
|
4580
4624
|
function detectPackageDirs2(cwd) {
|
|
4581
4625
|
const workspaces = detectWorkspaces(cwd);
|
|
@@ -4594,11 +4638,11 @@ async function scanAllPackages(cwd) {
|
|
|
4594
4638
|
const packageDirs = detectPackageDirs2(cwd);
|
|
4595
4639
|
const results = [];
|
|
4596
4640
|
for (const dir of packageDirs) {
|
|
4597
|
-
const absDir = dir === "." ? cwd :
|
|
4641
|
+
const absDir = dir === "." ? cwd : path28.join(cwd, dir);
|
|
4598
4642
|
if (!existsSync15(absDir))
|
|
4599
4643
|
continue;
|
|
4600
4644
|
let name = dir;
|
|
4601
|
-
const pkgPath =
|
|
4645
|
+
const pkgPath = path28.join(absDir, "package.json");
|
|
4602
4646
|
if (existsSync15(pkgPath)) {
|
|
4603
4647
|
try {
|
|
4604
4648
|
const pkg = JSON.parse(readFileSync19(pkgPath, "utf-8"));
|
|
@@ -4697,13 +4741,12 @@ function registerReportCommand(program) {
|
|
|
4697
4741
|
}
|
|
4698
4742
|
|
|
4699
4743
|
// src/commands/scan.ts
|
|
4700
|
-
import
|
|
4701
|
-
import * as path28 from "node:path";
|
|
4744
|
+
import * as path29 from "node:path";
|
|
4702
4745
|
import {
|
|
4703
4746
|
buildExportRegistry as buildExportRegistry2,
|
|
4704
4747
|
computeDrift as computeDrift8,
|
|
4705
4748
|
detectProseDrift as detectProseDrift2,
|
|
4706
|
-
|
|
4749
|
+
isExternalExport as isExternalExport3
|
|
4707
4750
|
} from "@driftdev/sdk";
|
|
4708
4751
|
|
|
4709
4752
|
// src/formatters/scan.ts
|
|
@@ -4716,7 +4759,8 @@ function renderScan(data, next) {
|
|
|
4716
4759
|
}
|
|
4717
4760
|
const hColor = coverageColor(data.health);
|
|
4718
4761
|
lines.push(indent(`Health ${hColor(`${data.health}%`)}`));
|
|
4719
|
-
|
|
4762
|
+
const externalNote = data.coverage.external ? c.gray(` +${data.coverage.external} external (not resolvable here)`) : "";
|
|
4763
|
+
lines.push(indent(`Coverage ${coverageColor(data.coverage.score)(`${data.coverage.score}%`)} (${data.coverage.documented}/${data.coverage.total} exports)${externalNote}`));
|
|
4720
4764
|
lines.push(indent(`Lint ${data.lint.count === 0 ? c.green("0 issues") : c.red(`${data.lint.count} issues`)}`));
|
|
4721
4765
|
lines.push("");
|
|
4722
4766
|
if (data.lint.count > 0) {
|
|
@@ -4766,7 +4810,7 @@ function renderBatchScan(data) {
|
|
|
4766
4810
|
|
|
4767
4811
|
// src/commands/scan.ts
|
|
4768
4812
|
function registerScanCommand(program) {
|
|
4769
|
-
program.command("scan [entry]").description("Run coverage + lint + prose drift in one pass").option("--min <n>", "Minimum health threshold (exit 1 if below)").option("--all", "Run across all workspace packages").option("--private", "Include private packages in --all mode").option("--lang <language>", "Source language (inferred from --spec/--abi/.clar; default typescript)").option("--abi <path>", "ABI JSON file (required for --lang clarity)").option("--spec <path>", "OpenAPI document: path or URL (implies --lang openapi)").action(async (entry, options) => {
|
|
4813
|
+
program.command("scan [entry]").description("Run coverage + lint + prose drift in one pass").option("--min <n>", "Minimum health threshold (exit 1 if below)").option("--all", "Run across all workspace packages").option("--private", "Include private packages in --all mode").option("--lang <language>", "Source language (inferred from --spec/--abi/.clar; default typescript)").option("--abi <path>", "ABI JSON file (required for --lang clarity)").option("--spec <path>", "OpenAPI document: path or URL (implies --lang openapi)").option("--docs <patterns...>", "Markdown corpus for prose drift: glob patterns or directories (overrides repo-local defaults)").action(async (entry, options) => {
|
|
4770
4814
|
const startTime = Date.now();
|
|
4771
4815
|
const version = getVersion();
|
|
4772
4816
|
try {
|
|
@@ -4804,7 +4848,7 @@ function registerScanCommand(program) {
|
|
|
4804
4848
|
let anyFail = false;
|
|
4805
4849
|
for (const pkg of packages) {
|
|
4806
4850
|
const { spec } = await cachedExtract(pkg.entry);
|
|
4807
|
-
const exps = spec.exports ?? [];
|
|
4851
|
+
const exps = (spec.exports ?? []).filter((e) => !isExternalExport3(e));
|
|
4808
4852
|
let documented2 = 0;
|
|
4809
4853
|
for (const e of exps) {
|
|
4810
4854
|
if (e.description?.trim())
|
|
@@ -4841,9 +4885,9 @@ function registerScanCommand(program) {
|
|
|
4841
4885
|
return;
|
|
4842
4886
|
}
|
|
4843
4887
|
const { config } = loadConfig();
|
|
4844
|
-
let entryFile = entry ?
|
|
4888
|
+
let entryFile = entry ? path29.resolve(process.cwd(), entry) : undefined;
|
|
4845
4889
|
if (lang === "typescript" && !entryFile) {
|
|
4846
|
-
entryFile = config.entry ?
|
|
4890
|
+
entryFile = config.entry ? path29.resolve(process.cwd(), config.entry) : detectEntry();
|
|
4847
4891
|
}
|
|
4848
4892
|
const { apiSpec, packageName, packageVersion } = await resolveTruth({
|
|
4849
4893
|
entry: entryFile,
|
|
@@ -4851,7 +4895,9 @@ function registerScanCommand(program) {
|
|
|
4851
4895
|
spec: options.spec,
|
|
4852
4896
|
abi: options.abi
|
|
4853
4897
|
});
|
|
4854
|
-
const
|
|
4898
|
+
const allExports = apiSpec.exports ?? [];
|
|
4899
|
+
const exports = allExports.filter((exp) => !isExternalExport3(exp));
|
|
4900
|
+
const external = allExports.length - exports.length;
|
|
4855
4901
|
const total = exports.length;
|
|
4856
4902
|
let documented = 0;
|
|
4857
4903
|
for (const exp of exports) {
|
|
@@ -4872,14 +4918,12 @@ function registerScanCommand(program) {
|
|
|
4872
4918
|
});
|
|
4873
4919
|
}
|
|
4874
4920
|
}
|
|
4875
|
-
if (lang === "typescript") {
|
|
4921
|
+
if (lang === "typescript" || options.docs) {
|
|
4876
4922
|
try {
|
|
4877
|
-
const
|
|
4878
|
-
const pkgJson = JSON.parse(readFileSync20(pkgJsonPath, "utf-8"));
|
|
4879
|
-
const pkgName = pkgJson.name;
|
|
4923
|
+
const pkgName = readPackageName() ?? packageName;
|
|
4880
4924
|
if (pkgName) {
|
|
4881
4925
|
const registry = buildExportRegistry2(apiSpec);
|
|
4882
|
-
const markdownFiles =
|
|
4926
|
+
const markdownFiles = resolveDocsCorpus(process.cwd(), options.docs, config.docs);
|
|
4883
4927
|
const proseDrifts = detectProseDrift2({
|
|
4884
4928
|
packageName: pkgName,
|
|
4885
4929
|
markdownFiles,
|
|
@@ -4908,7 +4952,13 @@ function registerScanCommand(program) {
|
|
|
4908
4952
|
}
|
|
4909
4953
|
const pass = min === undefined || h.health >= min;
|
|
4910
4954
|
const data = {
|
|
4911
|
-
coverage: {
|
|
4955
|
+
coverage: {
|
|
4956
|
+
score: coverageScore,
|
|
4957
|
+
documented,
|
|
4958
|
+
total,
|
|
4959
|
+
undocumented: total - documented,
|
|
4960
|
+
...external > 0 ? { external } : {}
|
|
4961
|
+
},
|
|
4912
4962
|
lint: { issues, count: issues.length },
|
|
4913
4963
|
health: h.health,
|
|
4914
4964
|
pass,
|
|
@@ -4981,8 +5031,8 @@ function registerSemverCommand(program) {
|
|
|
4981
5031
|
}
|
|
4982
5032
|
|
|
4983
5033
|
// src/commands/validate.ts
|
|
4984
|
-
import { readFileSync as
|
|
4985
|
-
import * as
|
|
5034
|
+
import { readFileSync as readFileSync20 } from "node:fs";
|
|
5035
|
+
import * as path30 from "node:path";
|
|
4986
5036
|
import { validateSpec } from "@openpkg-ts/spec";
|
|
4987
5037
|
|
|
4988
5038
|
// src/formatters/validate.ts
|
|
@@ -5008,8 +5058,8 @@ function registerValidateCommand(program) {
|
|
|
5008
5058
|
const startTime = Date.now();
|
|
5009
5059
|
const version = getVersion();
|
|
5010
5060
|
try {
|
|
5011
|
-
const filePath =
|
|
5012
|
-
const content =
|
|
5061
|
+
const filePath = path30.resolve(process.cwd(), file);
|
|
5062
|
+
const content = readFileSync20(filePath, "utf-8");
|
|
5013
5063
|
const spec = JSON.parse(content);
|
|
5014
5064
|
const result = validateSpec(spec);
|
|
5015
5065
|
const data = {
|
|
@@ -5134,13 +5184,13 @@ function extractCapabilities(program) {
|
|
|
5134
5184
|
|
|
5135
5185
|
// src/drift.ts
|
|
5136
5186
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
5137
|
-
var __dirname3 =
|
|
5138
|
-
var packageJson = JSON.parse(
|
|
5187
|
+
var __dirname3 = path31.dirname(__filename2);
|
|
5188
|
+
var packageJson = JSON.parse(readFileSync21(path31.join(__dirname3, "../package.json"), "utf-8"));
|
|
5139
5189
|
var program = new Command;
|
|
5140
5190
|
program.name("drift").description("drift — detect when your docs drift from your code").version(packageJson.version).option("--json", "Force JSON output (default when piped)").option("--human", "Force human-readable output (default in terminal)").option("--config <path>", "Path to drift config file").option("--cwd <dir>", "Run as if started in <dir>").option("--no-cache", "Bypass spec cache").option("--tools", "List all available tools for agent use (JSON)").hook("preAction", (_thisCommand) => {
|
|
5141
5191
|
const opts = program.opts();
|
|
5142
5192
|
if (opts.cwd) {
|
|
5143
|
-
process.chdir(
|
|
5193
|
+
process.chdir(path31.resolve(opts.cwd));
|
|
5144
5194
|
}
|
|
5145
5195
|
setOutputMode({ json: opts.json, human: opts.human });
|
|
5146
5196
|
setConfigPath(opts.config);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@driftdev/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Drift CLI - detect when your docs drift from your code",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@driftdev/clarity-adapter": "^1.0.1",
|
|
48
48
|
"@driftdev/openapi-adapter": "^1.0.1",
|
|
49
|
-
"@driftdev/sdk": "^1.
|
|
49
|
+
"@driftdev/sdk": "^1.7.0",
|
|
50
50
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
51
51
|
"@openpkg-ts/sdk": "^0.38.0",
|
|
52
52
|
"@openpkg-ts/spec": "^0.37.0",
|