driftfence 0.0.1 → 0.0.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/README.md +22 -2
- package/dist/{chunk-4RCBAET6.js → chunk-WK3NGHEY.js} +58 -28
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ DriftFence is a TypeScript Node.js CLI that catches outdated README and docs com
|
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Install from npm:
|
|
12
12
|
|
|
13
13
|
```sh
|
|
14
14
|
npm install -D driftfence
|
|
@@ -24,10 +24,14 @@ npx driftfence check
|
|
|
24
24
|
|
|
25
25
|
Check a specific project directory:
|
|
26
26
|
|
|
27
|
+
<!-- driftfence-ignore-start -->
|
|
28
|
+
|
|
27
29
|
```sh
|
|
28
30
|
npx driftfence check ./path/to/project
|
|
29
31
|
```
|
|
30
32
|
|
|
33
|
+
<!-- driftfence-ignore-end -->
|
|
34
|
+
|
|
31
35
|
## Example Output
|
|
32
36
|
|
|
33
37
|
The local clean demo exits with code 0:
|
|
@@ -44,6 +48,8 @@ npm run demo:drift
|
|
|
44
48
|
|
|
45
49
|
Example output from the drift fixture:
|
|
46
50
|
|
|
51
|
+
<!-- driftfence-ignore-start -->
|
|
52
|
+
|
|
47
53
|
```text
|
|
48
54
|
DriftFence found documentation drift.
|
|
49
55
|
|
|
@@ -60,6 +66,8 @@ Env vars:
|
|
|
60
66
|
4 issues found.
|
|
61
67
|
```
|
|
62
68
|
|
|
69
|
+
<!-- driftfence-ignore-end -->
|
|
70
|
+
|
|
63
71
|
## MVP Checks
|
|
64
72
|
|
|
65
73
|
DriftFence checks `README.md` and `docs/**/*.md` for documentation drift.
|
|
@@ -73,6 +81,8 @@ Current checks:
|
|
|
73
81
|
|
|
74
82
|
Package script references include commands like:
|
|
75
83
|
|
|
84
|
+
<!-- driftfence-ignore-start -->
|
|
85
|
+
|
|
76
86
|
```sh
|
|
77
87
|
npm run build
|
|
78
88
|
npm test
|
|
@@ -81,21 +91,31 @@ pnpm build
|
|
|
81
91
|
yarn build
|
|
82
92
|
```
|
|
83
93
|
|
|
94
|
+
<!-- driftfence-ignore-end -->
|
|
95
|
+
|
|
84
96
|
Env var checks currently support references like:
|
|
85
97
|
|
|
98
|
+
<!-- driftfence-ignore-start -->
|
|
99
|
+
|
|
86
100
|
```text
|
|
87
101
|
API_URL
|
|
88
102
|
DATABASE_URL
|
|
89
103
|
VITE_API_URL
|
|
90
104
|
```
|
|
91
105
|
|
|
106
|
+
<!-- driftfence-ignore-end -->
|
|
107
|
+
|
|
92
108
|
and source usages like:
|
|
93
109
|
|
|
110
|
+
<!-- driftfence-ignore-start -->
|
|
111
|
+
|
|
94
112
|
```ts
|
|
95
113
|
process.env.API_URL
|
|
96
114
|
import.meta.env.VITE_API_URL
|
|
97
115
|
```
|
|
98
116
|
|
|
117
|
+
<!-- driftfence-ignore-end -->
|
|
118
|
+
|
|
99
119
|
## Exit Codes
|
|
100
120
|
|
|
101
121
|
DriftFence uses stable CLI exit codes:
|
|
@@ -116,4 +136,4 @@ DriftFence uses stable CLI exit codes:
|
|
|
116
136
|
|
|
117
137
|
AI features are not included in the MVP.
|
|
118
138
|
|
|
119
|
-
DriftFence is deterministic-first: it checks concrete references in docs and code instead of guessing.
|
|
139
|
+
DriftFence is deterministic-first: it checks concrete references in docs and code instead of guessing.
|
|
@@ -126,7 +126,7 @@ async function readPackageJson(projectRoot) {
|
|
|
126
126
|
};
|
|
127
127
|
}
|
|
128
128
|
try {
|
|
129
|
-
return { packageJson: JSON.parse(rawPackageJson) };
|
|
129
|
+
return { packageJson: JSON.parse(stripBom(rawPackageJson)) };
|
|
130
130
|
} catch (error) {
|
|
131
131
|
return {
|
|
132
132
|
issue: {
|
|
@@ -156,6 +156,9 @@ function normalizeCommand(command) {
|
|
|
156
156
|
function hasOwn(object, key) {
|
|
157
157
|
return Object.prototype.hasOwnProperty.call(object, key);
|
|
158
158
|
}
|
|
159
|
+
function stripBom(content) {
|
|
160
|
+
return content.startsWith("\uFEFF") ? content.slice(1) : content;
|
|
161
|
+
}
|
|
159
162
|
function getErrorCode(error) {
|
|
160
163
|
return typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0;
|
|
161
164
|
}
|
|
@@ -238,6 +241,52 @@ function uniquePathReferences(references) {
|
|
|
238
241
|
// src/checkers/envVars.ts
|
|
239
242
|
import { readFile as readFile2, readdir } from "fs/promises";
|
|
240
243
|
import { join as join2, relative } from "path";
|
|
244
|
+
|
|
245
|
+
// src/markdown/extractMarkdownText.ts
|
|
246
|
+
import remarkParse from "remark-parse";
|
|
247
|
+
import { unified } from "unified";
|
|
248
|
+
var ignoreStart = "<!-- driftfence-ignore-start -->";
|
|
249
|
+
var ignoreEnd = "<!-- driftfence-ignore-end -->";
|
|
250
|
+
function extractMarkdownText(markdown) {
|
|
251
|
+
const tree = unified().use(remarkParse).parse(stripIgnoredMarkdownBlocks(markdown));
|
|
252
|
+
const references = [];
|
|
253
|
+
collectMarkdownText(tree, references);
|
|
254
|
+
return references;
|
|
255
|
+
}
|
|
256
|
+
function stripIgnoredMarkdownBlocks(markdown) {
|
|
257
|
+
let strippedMarkdown = "";
|
|
258
|
+
let position = 0;
|
|
259
|
+
while (position < markdown.length) {
|
|
260
|
+
const startIndex = markdown.indexOf(ignoreStart, position);
|
|
261
|
+
if (startIndex === -1) {
|
|
262
|
+
strippedMarkdown += markdown.slice(position);
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
strippedMarkdown += markdown.slice(position, startIndex);
|
|
266
|
+
const endIndex = markdown.indexOf(
|
|
267
|
+
ignoreEnd,
|
|
268
|
+
startIndex + ignoreStart.length
|
|
269
|
+
);
|
|
270
|
+
if (endIndex === -1) {
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
273
|
+
position = endIndex + ignoreEnd.length;
|
|
274
|
+
}
|
|
275
|
+
return strippedMarkdown;
|
|
276
|
+
}
|
|
277
|
+
function collectMarkdownText(node, references) {
|
|
278
|
+
if ((node.type === "code" || node.type === "inlineCode") && typeof node.value === "string") {
|
|
279
|
+
references.push({ kind: node.type, value: node.value });
|
|
280
|
+
}
|
|
281
|
+
if (!Array.isArray(node.children)) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
for (const child of node.children) {
|
|
285
|
+
collectMarkdownText(child, references);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// src/checkers/envVars.ts
|
|
241
290
|
var envVarPattern = /\b[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+\b/g;
|
|
242
291
|
var processEnvPattern = /\bprocess\.env\.([A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+)\b/g;
|
|
243
292
|
var importMetaEnvPattern = /\bimport\.meta\.env\.([A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+)\b/g;
|
|
@@ -273,11 +322,13 @@ function findEnvExampleNames(content) {
|
|
|
273
322
|
}
|
|
274
323
|
function findMarkdownEnvVarReferences(document) {
|
|
275
324
|
return uniqueEnvVarReferences(
|
|
276
|
-
[...document.content.matchAll(envVarPattern)].map(
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
325
|
+
[...stripIgnoredMarkdownBlocks(document.content).matchAll(envVarPattern)].map(
|
|
326
|
+
(match) => ({
|
|
327
|
+
name: match[0],
|
|
328
|
+
source: "markdown",
|
|
329
|
+
path: document.path
|
|
330
|
+
})
|
|
331
|
+
)
|
|
281
332
|
);
|
|
282
333
|
}
|
|
283
334
|
async function readEnvExampleNames(projectRoot) {
|
|
@@ -369,27 +420,6 @@ function getErrorCode2(error) {
|
|
|
369
420
|
return typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0;
|
|
370
421
|
}
|
|
371
422
|
|
|
372
|
-
// src/markdown/extractMarkdownText.ts
|
|
373
|
-
import remarkParse from "remark-parse";
|
|
374
|
-
import { unified } from "unified";
|
|
375
|
-
function extractMarkdownText(markdown) {
|
|
376
|
-
const tree = unified().use(remarkParse).parse(markdown);
|
|
377
|
-
const references = [];
|
|
378
|
-
collectMarkdownText(tree, references);
|
|
379
|
-
return references;
|
|
380
|
-
}
|
|
381
|
-
function collectMarkdownText(node, references) {
|
|
382
|
-
if ((node.type === "code" || node.type === "inlineCode") && typeof node.value === "string") {
|
|
383
|
-
references.push({ kind: node.type, value: node.value });
|
|
384
|
-
}
|
|
385
|
-
if (!Array.isArray(node.children)) {
|
|
386
|
-
return;
|
|
387
|
-
}
|
|
388
|
-
for (const child of node.children) {
|
|
389
|
-
collectMarkdownText(child, references);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
423
|
// src/markdown/readMarkdownDocuments.ts
|
|
394
424
|
import { readFile as readFile3, readdir as readdir2 } from "fs/promises";
|
|
395
425
|
import { join as join3, relative as relative2 } from "path";
|
|
@@ -567,9 +597,9 @@ export {
|
|
|
567
597
|
findPackageScriptReferences,
|
|
568
598
|
checkFilePaths,
|
|
569
599
|
findFilePathReferences,
|
|
600
|
+
extractMarkdownText,
|
|
570
601
|
checkEnvVars,
|
|
571
602
|
findEnvExampleNames,
|
|
572
|
-
extractMarkdownText,
|
|
573
603
|
readMarkdownDocuments,
|
|
574
604
|
formatReport,
|
|
575
605
|
checkProject
|
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED