@driftdev/cli 1.12.0 → 1.12.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.
- package/dist/drift.js +88 -52
- package/package.json +2 -2
package/dist/drift.js
CHANGED
|
@@ -52,7 +52,7 @@ var init_global = () => {};
|
|
|
52
52
|
|
|
53
53
|
// src/drift.ts
|
|
54
54
|
import { readFileSync as readFileSync23 } from "node:fs";
|
|
55
|
-
import * as
|
|
55
|
+
import * as path35 from "node:path";
|
|
56
56
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
57
57
|
import { Command } from "commander";
|
|
58
58
|
|
|
@@ -80,12 +80,17 @@ var cached;
|
|
|
80
80
|
function getVersion() {
|
|
81
81
|
if (cached)
|
|
82
82
|
return cached;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
for (const rel of ["../package.json", "../../package.json"]) {
|
|
84
|
+
try {
|
|
85
|
+
const pkg = JSON.parse(readFileSync(join2(__dirname2, rel), "utf-8"));
|
|
86
|
+
if (pkg.name === "@driftdev/cli" && typeof pkg.version === "string") {
|
|
87
|
+
cached = pkg.version;
|
|
88
|
+
return pkg.version;
|
|
89
|
+
}
|
|
90
|
+
} catch {}
|
|
87
91
|
}
|
|
88
|
-
|
|
92
|
+
cached = "0.0.0";
|
|
93
|
+
return cached;
|
|
89
94
|
}
|
|
90
95
|
|
|
91
96
|
// src/cache/spec-cache.ts
|
|
@@ -4266,7 +4271,7 @@ function registerInitCommand(program) {
|
|
|
4266
4271
|
}
|
|
4267
4272
|
|
|
4268
4273
|
// src/commands/lint.ts
|
|
4269
|
-
import * as
|
|
4274
|
+
import * as path29 from "node:path";
|
|
4270
4275
|
import { buildExportRegistry, computeDrift as computeDrift4, detectProseDrift } from "@driftdev/sdk";
|
|
4271
4276
|
|
|
4272
4277
|
// src/formatters/lint.ts
|
|
@@ -4304,6 +4309,13 @@ function renderLint(data, next) {
|
|
|
4304
4309
|
}
|
|
4305
4310
|
|
|
4306
4311
|
// src/utils/annotations.ts
|
|
4312
|
+
import * as path28 from "node:path";
|
|
4313
|
+
function annotationPath(filePath) {
|
|
4314
|
+
if (!path28.isAbsolute(filePath))
|
|
4315
|
+
return filePath;
|
|
4316
|
+
const rel = path28.relative(process.cwd(), filePath);
|
|
4317
|
+
return rel.startsWith("..") ? filePath : rel;
|
|
4318
|
+
}
|
|
4307
4319
|
function escapeData(value) {
|
|
4308
4320
|
return value.replace(/%/g, "%25").replace(/\r/g, "%0D").replace(/\n/g, "%0A");
|
|
4309
4321
|
}
|
|
@@ -4314,7 +4326,7 @@ function emitAnnotations(issues, level = "error") {
|
|
|
4314
4326
|
for (const issue of issues) {
|
|
4315
4327
|
const props = [];
|
|
4316
4328
|
if (issue.filePath)
|
|
4317
|
-
props.push(`file=${escapeProperty(issue.filePath)}`);
|
|
4329
|
+
props.push(`file=${escapeProperty(annotationPath(issue.filePath))}`);
|
|
4318
4330
|
if (issue.line !== undefined)
|
|
4319
4331
|
props.push(`line=${issue.line}`);
|
|
4320
4332
|
props.push(`title=${escapeProperty(`drift: ${issue.export || "docs"}`)}`);
|
|
@@ -4377,9 +4389,9 @@ function registerLintCommand(program) {
|
|
|
4377
4389
|
formatOutput("lint", { issues: [], count: 0 }, startTime, version, renderLint);
|
|
4378
4390
|
return;
|
|
4379
4391
|
}
|
|
4380
|
-
let entryFile = entry ?
|
|
4392
|
+
let entryFile = entry ? path29.resolve(process.cwd(), entry) : undefined;
|
|
4381
4393
|
if (lang === "typescript" && !entryFile) {
|
|
4382
|
-
entryFile = config.entry ?
|
|
4394
|
+
entryFile = config.entry ? path29.resolve(process.cwd(), config.entry) : detectEntry();
|
|
4383
4395
|
}
|
|
4384
4396
|
const { apiSpec: spec } = await resolveTruth({
|
|
4385
4397
|
entry: entryFile,
|
|
@@ -4445,7 +4457,7 @@ function registerLintCommand(program) {
|
|
|
4445
4457
|
}
|
|
4446
4458
|
|
|
4447
4459
|
// src/commands/list.ts
|
|
4448
|
-
import * as
|
|
4460
|
+
import * as path30 from "node:path";
|
|
4449
4461
|
import { computeDrift as computeDrift5 } from "@driftdev/sdk";
|
|
4450
4462
|
import { listExports as listExports2 } from "@openpkg-ts/sdk";
|
|
4451
4463
|
|
|
@@ -4560,7 +4572,7 @@ function registerListCommand(program) {
|
|
|
4560
4572
|
} else {
|
|
4561
4573
|
let entryFile;
|
|
4562
4574
|
if (searchOrEntry && looksLikeFilePath(searchOrEntry)) {
|
|
4563
|
-
entryFile =
|
|
4575
|
+
entryFile = path30.resolve(process.cwd(), searchOrEntry);
|
|
4564
4576
|
} else if (searchOrEntry) {
|
|
4565
4577
|
entryFile = detectEntry();
|
|
4566
4578
|
searchTerm = searchOrEntry;
|
|
@@ -4817,7 +4829,7 @@ function diffArgs(command, args) {
|
|
|
4817
4829
|
// src/commands/release.ts
|
|
4818
4830
|
import { execSync as execSync4 } from "node:child_process";
|
|
4819
4831
|
import { existsSync as existsSync15, readFileSync as readFileSync20 } from "node:fs";
|
|
4820
|
-
import * as
|
|
4832
|
+
import * as path31 from "node:path";
|
|
4821
4833
|
import { computeDrift as computeDrift6 } from "@driftdev/sdk";
|
|
4822
4834
|
|
|
4823
4835
|
// src/formatters/release.ts
|
|
@@ -4865,7 +4877,7 @@ function getLastTag() {
|
|
|
4865
4877
|
}
|
|
4866
4878
|
}
|
|
4867
4879
|
function getPackageVersion(cwd) {
|
|
4868
|
-
const pkgPath =
|
|
4880
|
+
const pkgPath = path31.join(cwd, "package.json");
|
|
4869
4881
|
if (!existsSync15(pkgPath))
|
|
4870
4882
|
return null;
|
|
4871
4883
|
try {
|
|
@@ -4881,7 +4893,7 @@ function registerReleaseCommand(program) {
|
|
|
4881
4893
|
const cwd = process.cwd();
|
|
4882
4894
|
try {
|
|
4883
4895
|
const { config } = loadConfig();
|
|
4884
|
-
const entryFile = entry ?
|
|
4896
|
+
const entryFile = entry ? path31.resolve(cwd, entry) : config.entry ? path31.resolve(cwd, config.entry) : detectEntry();
|
|
4885
4897
|
const { spec } = await cachedExtract(entryFile);
|
|
4886
4898
|
const exports = spec.exports ?? [];
|
|
4887
4899
|
const total = exports.length;
|
|
@@ -5006,7 +5018,7 @@ function renderReport(data) {
|
|
|
5006
5018
|
// src/utils/scan-packages.ts
|
|
5007
5019
|
import { execSync as execSync5 } from "node:child_process";
|
|
5008
5020
|
import { existsSync as existsSync16, readFileSync as readFileSync21 } from "node:fs";
|
|
5009
|
-
import * as
|
|
5021
|
+
import * as path32 from "node:path";
|
|
5010
5022
|
import { computeDrift as computeDrift7 } from "@driftdev/sdk";
|
|
5011
5023
|
function detectPackageDirs2(cwd) {
|
|
5012
5024
|
const workspaces = detectWorkspaces(cwd);
|
|
@@ -5025,11 +5037,11 @@ async function scanAllPackages(cwd) {
|
|
|
5025
5037
|
const packageDirs = detectPackageDirs2(cwd);
|
|
5026
5038
|
const results = [];
|
|
5027
5039
|
for (const dir of packageDirs) {
|
|
5028
|
-
const absDir = dir === "." ? cwd :
|
|
5040
|
+
const absDir = dir === "." ? cwd : path32.join(cwd, dir);
|
|
5029
5041
|
if (!existsSync16(absDir))
|
|
5030
5042
|
continue;
|
|
5031
5043
|
let name = dir;
|
|
5032
|
-
const pkgPath =
|
|
5044
|
+
const pkgPath = path32.join(absDir, "package.json");
|
|
5033
5045
|
if (existsSync16(pkgPath)) {
|
|
5034
5046
|
try {
|
|
5035
5047
|
const pkg = JSON.parse(readFileSync21(pkgPath, "utf-8"));
|
|
@@ -5128,7 +5140,7 @@ function registerReportCommand(program) {
|
|
|
5128
5140
|
}
|
|
5129
5141
|
|
|
5130
5142
|
// src/commands/scan.ts
|
|
5131
|
-
import * as
|
|
5143
|
+
import * as path33 from "node:path";
|
|
5132
5144
|
import {
|
|
5133
5145
|
buildExportRegistry as buildExportRegistry2,
|
|
5134
5146
|
computeDrift as computeDrift8,
|
|
@@ -5144,13 +5156,15 @@ function renderScan(data, next) {
|
|
|
5144
5156
|
lines.push(indent(`${c.bold(data.packageName)}${c.gray(ver)}`));
|
|
5145
5157
|
lines.push("");
|
|
5146
5158
|
}
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5159
|
+
if (data.health !== undefined && data.coverage && data.lint) {
|
|
5160
|
+
const hColor = coverageColor(data.health);
|
|
5161
|
+
lines.push(indent(`Health ${hColor(`${data.health}%`)}`));
|
|
5162
|
+
const externalNote = data.coverage.external ? c.gray(` +${data.coverage.external} external (not resolvable here)`) : "";
|
|
5163
|
+
lines.push(indent(`Coverage ${coverageColor(data.coverage.score)(`${data.coverage.score}%`)} (${data.coverage.documented}/${data.coverage.total} exports)${externalNote}`));
|
|
5164
|
+
lines.push(indent(`Lint ${data.lint.count === 0 ? c.green("0 issues") : c.red(`${data.lint.count} issues`)}`));
|
|
5165
|
+
lines.push("");
|
|
5166
|
+
}
|
|
5167
|
+
if (data.lint && data.lint.count > 0) {
|
|
5154
5168
|
lines.push(indent("Issues"));
|
|
5155
5169
|
lines.push(indent(c.gray(separator())));
|
|
5156
5170
|
const shown = data.lint.issues.slice(0, 10);
|
|
@@ -5210,6 +5224,25 @@ function renderBatchScan(data) {
|
|
|
5210
5224
|
}
|
|
5211
5225
|
|
|
5212
5226
|
// src/commands/scan.ts
|
|
5227
|
+
function toDocsCoverageResult(run) {
|
|
5228
|
+
return {
|
|
5229
|
+
pass: run.pass,
|
|
5230
|
+
pages: run.pages.map((p) => ({
|
|
5231
|
+
page: p.page,
|
|
5232
|
+
type: p.type,
|
|
5233
|
+
status: p.status,
|
|
5234
|
+
baselineGaps: p.baselineGaps,
|
|
5235
|
+
counts: p.result.counts,
|
|
5236
|
+
failures: p.failures,
|
|
5237
|
+
warnings: p.warnings,
|
|
5238
|
+
gaps: p.result.gaps,
|
|
5239
|
+
ghosts: p.result.ghosts,
|
|
5240
|
+
inversions: p.result.inversions,
|
|
5241
|
+
documentedKeysFromOtherTypes: p.result.documentedKeysFromOtherTypes,
|
|
5242
|
+
annotated: p.result.annotated
|
|
5243
|
+
}))
|
|
5244
|
+
};
|
|
5245
|
+
}
|
|
5213
5246
|
function registerScanCommand(program) {
|
|
5214
5247
|
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)").option("--docs-map <file>", "Docs map (page→type) activating key-coverage mode: gaps/ghosts/inversions per page").option("--annotations", "Emit GitHub Actions ::error/::warning annotations for findings").action(async (entry, options) => {
|
|
5215
5248
|
const startTime = Date.now();
|
|
@@ -5289,10 +5322,31 @@ function registerScanCommand(program) {
|
|
|
5289
5322
|
process.exitCode = 1;
|
|
5290
5323
|
return;
|
|
5291
5324
|
}
|
|
5325
|
+
if (options.docsMap && !entry) {
|
|
5326
|
+
const loaded = loadDocsMap(options.docsMap);
|
|
5327
|
+
if (loaded.map.pages.every((p) => p.spec || p.entry)) {
|
|
5328
|
+
const run = await runDocsCoverage(loaded);
|
|
5329
|
+
const data2 = { pass: run.pass, docsCoverage: toDocsCoverageResult(run) };
|
|
5330
|
+
formatOutput("scan", data2, startTime, version, renderScan);
|
|
5331
|
+
if (options.annotations) {
|
|
5332
|
+
emitAnnotations(run.annotations.errors, "error");
|
|
5333
|
+
emitAnnotations(run.annotations.warnings, "warning");
|
|
5334
|
+
}
|
|
5335
|
+
if (!run.pass) {
|
|
5336
|
+
if (!shouldRenderHuman()) {
|
|
5337
|
+
const covFails = run.pages.flatMap((p) => p.failures.map((f) => `${p.page}: ${f}`));
|
|
5338
|
+
process.stderr.write(`scan failed: docs coverage: ${covFails.join(" | ")}
|
|
5339
|
+
`);
|
|
5340
|
+
}
|
|
5341
|
+
process.exitCode = 1;
|
|
5342
|
+
}
|
|
5343
|
+
return;
|
|
5344
|
+
}
|
|
5345
|
+
}
|
|
5292
5346
|
const { config } = loadConfig();
|
|
5293
|
-
let entryFile = entry ?
|
|
5347
|
+
let entryFile = entry ? path33.resolve(process.cwd(), entry) : undefined;
|
|
5294
5348
|
if (lang === "typescript" && !entryFile) {
|
|
5295
|
-
entryFile = config.entry ?
|
|
5349
|
+
entryFile = config.entry ? path33.resolve(process.cwd(), config.entry) : detectEntry();
|
|
5296
5350
|
}
|
|
5297
5351
|
const { apiSpec, packageName, packageVersion } = await resolveTruth({
|
|
5298
5352
|
entry: entryFile,
|
|
@@ -5374,25 +5428,7 @@ function registerScanCommand(program) {
|
|
|
5374
5428
|
pass,
|
|
5375
5429
|
packageName,
|
|
5376
5430
|
packageVersion,
|
|
5377
|
-
...docsCoverage ? {
|
|
5378
|
-
docsCoverage: {
|
|
5379
|
-
pass: docsCoverage.pass,
|
|
5380
|
-
pages: docsCoverage.pages.map((p) => ({
|
|
5381
|
-
page: p.page,
|
|
5382
|
-
type: p.type,
|
|
5383
|
-
status: p.status,
|
|
5384
|
-
baselineGaps: p.baselineGaps,
|
|
5385
|
-
counts: p.result.counts,
|
|
5386
|
-
failures: p.failures,
|
|
5387
|
-
warnings: p.warnings,
|
|
5388
|
-
gaps: p.result.gaps,
|
|
5389
|
-
ghosts: p.result.ghosts,
|
|
5390
|
-
inversions: p.result.inversions,
|
|
5391
|
-
documentedKeysFromOtherTypes: p.result.documentedKeysFromOtherTypes,
|
|
5392
|
-
annotated: p.result.annotated
|
|
5393
|
-
}))
|
|
5394
|
-
}
|
|
5395
|
-
} : {}
|
|
5431
|
+
...docsCoverage ? { docsCoverage: toDocsCoverageResult(docsCoverage) } : {}
|
|
5396
5432
|
};
|
|
5397
5433
|
let next;
|
|
5398
5434
|
if (issues.length > 0) {
|
|
@@ -5468,7 +5504,7 @@ function registerSemverCommand(program) {
|
|
|
5468
5504
|
|
|
5469
5505
|
// src/commands/validate.ts
|
|
5470
5506
|
import { readFileSync as readFileSync22 } from "node:fs";
|
|
5471
|
-
import * as
|
|
5507
|
+
import * as path34 from "node:path";
|
|
5472
5508
|
import { validateSpec } from "@openpkg-ts/spec";
|
|
5473
5509
|
|
|
5474
5510
|
// src/formatters/validate.ts
|
|
@@ -5494,7 +5530,7 @@ function registerValidateCommand(program) {
|
|
|
5494
5530
|
const startTime = Date.now();
|
|
5495
5531
|
const version = getVersion();
|
|
5496
5532
|
try {
|
|
5497
|
-
const filePath =
|
|
5533
|
+
const filePath = path34.resolve(process.cwd(), file);
|
|
5498
5534
|
const content = readFileSync22(filePath, "utf-8");
|
|
5499
5535
|
const spec = JSON.parse(content);
|
|
5500
5536
|
const result = validateSpec(spec);
|
|
@@ -5637,13 +5673,13 @@ function extractCapabilities(program) {
|
|
|
5637
5673
|
|
|
5638
5674
|
// src/drift.ts
|
|
5639
5675
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
5640
|
-
var __dirname3 =
|
|
5641
|
-
var packageJson = JSON.parse(readFileSync23(
|
|
5676
|
+
var __dirname3 = path35.dirname(__filename2);
|
|
5677
|
+
var packageJson = JSON.parse(readFileSync23(path35.join(__dirname3, "../package.json"), "utf-8"));
|
|
5642
5678
|
var program = new Command;
|
|
5643
5679
|
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) => {
|
|
5644
5680
|
const opts = program.opts();
|
|
5645
5681
|
if (opts.cwd) {
|
|
5646
|
-
process.chdir(
|
|
5682
|
+
process.chdir(path35.resolve(opts.cwd));
|
|
5647
5683
|
}
|
|
5648
5684
|
setOutputMode({ json: opts.json, human: opts.human });
|
|
5649
5685
|
setConfigPath(opts.config);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@driftdev/cli",
|
|
3
|
-
"version": "1.12.
|
|
3
|
+
"version": "1.12.2",
|
|
4
4
|
"description": "Drift CLI - detect when your docs drift from your code",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@driftdev/clarity-adapter": "^1.0.1",
|
|
49
49
|
"@driftdev/openapi-adapter": "^1.0.1",
|
|
50
|
-
"@driftdev/sdk": "^1.12.
|
|
50
|
+
"@driftdev/sdk": "^1.12.2",
|
|
51
51
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
52
52
|
"@openpkg-ts/sdk": "^0.43.0",
|
|
53
53
|
"@openpkg-ts/spec": "^0.43.0",
|