@writechoice/mint-cli 0.0.1 → 0.0.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/README.md +46 -1
- package/bin/cli.js +64 -1
- package/package.json +1 -1
- package/src/commands/validate/links.js +25 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ CLI tool for Mintlify documentation validation and utilities.
|
|
|
15
15
|
### Global Installation
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
npm install -g writechoice
|
|
18
|
+
npm install -g @writechoice/mint-cli
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
### Local Development
|
|
@@ -40,6 +40,26 @@ npm link
|
|
|
40
40
|
|
|
41
41
|
## Usage
|
|
42
42
|
|
|
43
|
+
### Check Version
|
|
44
|
+
|
|
45
|
+
Check the installed version:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
writechoice --version
|
|
49
|
+
# or
|
|
50
|
+
writechoice -V
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Update to Latest Version
|
|
54
|
+
|
|
55
|
+
Update to the latest version from npm:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
writechoice update
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The CLI also automatically checks for updates and displays a notification when a new version is available.
|
|
62
|
+
|
|
43
63
|
### Validate Links
|
|
44
64
|
|
|
45
65
|
Validate all internal links and anchors in your MDX documentation:
|
|
@@ -122,6 +142,10 @@ The tool extracts internal links from MDX files in the following formats:
|
|
|
122
142
|
3. **JSX Card components**: `<Card href="/path/to/page" title="Card Title" />`
|
|
123
143
|
4. **JSX Button components**: `<Button href="/path/to/page#anchor">Button Text</Button>`
|
|
124
144
|
|
|
145
|
+
**Images are automatically ignored:**
|
|
146
|
+
- Markdown images: ``
|
|
147
|
+
- HTML images: `<img src="./image.png" />`
|
|
148
|
+
|
|
125
149
|
### Validation Process
|
|
126
150
|
|
|
127
151
|
1. **Local Validation**: First checks if the target MDX file exists locally
|
|
@@ -209,6 +233,27 @@ writechoice check links docs.example.com -o my_report.json
|
|
|
209
233
|
writechoice check links docs.example.com --fix-from-report my_report.json
|
|
210
234
|
```
|
|
211
235
|
|
|
236
|
+
## Updates
|
|
237
|
+
|
|
238
|
+
The CLI automatically checks for new versions and displays a notification when an update is available:
|
|
239
|
+
|
|
240
|
+
```
|
|
241
|
+
┌─────────────────────────────────────────────────┐
|
|
242
|
+
│ Update available: 0.0.2 → 0.0.3 │
|
|
243
|
+
│ Run: writechoice update │
|
|
244
|
+
└─────────────────────────────────────────────────┘
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
To update manually:
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
# Using the built-in update command (recommended)
|
|
251
|
+
writechoice update
|
|
252
|
+
|
|
253
|
+
# Or using npm directly
|
|
254
|
+
npm install -g @writechoice/mint-cli@latest
|
|
255
|
+
```
|
|
256
|
+
|
|
212
257
|
## Configuration
|
|
213
258
|
|
|
214
259
|
### Excluded Directories
|
package/bin/cli.js
CHANGED
|
@@ -4,6 +4,7 @@ import { Command } from "commander";
|
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
import { dirname, join } from "path";
|
|
6
6
|
import { readFileSync } from "fs";
|
|
7
|
+
import { execSync } from "child_process";
|
|
7
8
|
|
|
8
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
10
|
const __dirname = dirname(__filename);
|
|
@@ -16,7 +17,7 @@ const program = new Command();
|
|
|
16
17
|
program
|
|
17
18
|
.name("writechoice")
|
|
18
19
|
.description("CLI tool for Mintlify documentation validation and utilities")
|
|
19
|
-
.version(packageJson.version);
|
|
20
|
+
.version(packageJson.version, "-V, --version", "Output the current version");
|
|
20
21
|
|
|
21
22
|
// Validate command
|
|
22
23
|
const check = program.command("check").description("Validation commands for documentation");
|
|
@@ -41,4 +42,66 @@ check
|
|
|
41
42
|
await validateLinks(baseUrl, options);
|
|
42
43
|
});
|
|
43
44
|
|
|
45
|
+
// Update command
|
|
46
|
+
program
|
|
47
|
+
.command("update")
|
|
48
|
+
.description("Update @writechoice/mint-cli to the latest version")
|
|
49
|
+
.action(async () => {
|
|
50
|
+
console.log("Checking for updates...");
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
// Get latest version from npm
|
|
54
|
+
const latestVersion = execSync(
|
|
55
|
+
`npm view ${packageJson.name} version`,
|
|
56
|
+
{ encoding: "utf-8" }
|
|
57
|
+
).trim();
|
|
58
|
+
|
|
59
|
+
const currentVersion = packageJson.version;
|
|
60
|
+
|
|
61
|
+
if (latestVersion === currentVersion) {
|
|
62
|
+
console.log(`✓ You're already on the latest version (${currentVersion})`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
console.log(`\nUpdate available: ${currentVersion} → ${latestVersion}`);
|
|
67
|
+
console.log(`\nUpdating ${packageJson.name}...`);
|
|
68
|
+
|
|
69
|
+
// Update the package
|
|
70
|
+
execSync(`npm install -g ${packageJson.name}@latest`, {
|
|
71
|
+
stdio: "inherit",
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
console.log(`\n✓ Successfully updated to version ${latestVersion}`);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.error("Error checking for updates:", error.message);
|
|
77
|
+
console.log("\nYou can manually update with:");
|
|
78
|
+
console.log(` npm install -g ${packageJson.name}@latest`);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Check for updates on every command (non-blocking)
|
|
84
|
+
async function checkForUpdates() {
|
|
85
|
+
try {
|
|
86
|
+
const latestVersion = execSync(
|
|
87
|
+
`npm view ${packageJson.name} version 2>/dev/null`,
|
|
88
|
+
{ encoding: "utf-8", timeout: 2000 }
|
|
89
|
+
).trim();
|
|
90
|
+
|
|
91
|
+
const currentVersion = packageJson.version;
|
|
92
|
+
|
|
93
|
+
if (latestVersion && latestVersion !== currentVersion) {
|
|
94
|
+
console.log(`\n┌─────────────────────────────────────────────────┐`);
|
|
95
|
+
console.log(`│ Update available: ${currentVersion} → ${latestVersion.padEnd(24)} │`);
|
|
96
|
+
console.log(`│ Run: writechoice update │`);
|
|
97
|
+
console.log(`└─────────────────────────────────────────────────┘\n`);
|
|
98
|
+
}
|
|
99
|
+
} catch (error) {
|
|
100
|
+
// Silently fail - don't interrupt the user
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Run update check in background (don't block execution)
|
|
105
|
+
checkForUpdates();
|
|
106
|
+
|
|
44
107
|
program.parse();
|
package/package.json
CHANGED
|
@@ -35,7 +35,9 @@ const DEFAULT_CONCURRENCY = 25;
|
|
|
35
35
|
// Link extraction patterns
|
|
36
36
|
const LINK_PATTERNS = {
|
|
37
37
|
markdown: /\[([^\]]+?)\]\(([^)]+?)\)/g,
|
|
38
|
+
markdownImage: /!\[([^\]]*?)\]\(([^)]+?)\)/g,
|
|
38
39
|
htmlAnchor: /<a\s+href=["'](.*?)["'][^>]*?>(.*?)<\/a>/gs,
|
|
40
|
+
htmlImage: /<img[^>]+src=["'](.*?)["'][^>]*?>/gi,
|
|
39
41
|
jsxCard: /<Card[^>]+?href=["'](.*?)["'][^>]*?(?:title=["'](.*?)["'])?[^>]*?>/g,
|
|
40
42
|
jsxButton: /<Button[^>]+?href=["'](.*?)["'][^>]*?>(.*?)<\/Button>/gs,
|
|
41
43
|
};
|
|
@@ -213,9 +215,31 @@ function extractLinksFromFile(filePath, baseUrl, repoRoot, verbose = false) {
|
|
|
213
215
|
const { cleanedContent } = removeCodeBlocksAndFrontmatter(content);
|
|
214
216
|
const links = [];
|
|
215
217
|
|
|
216
|
-
//
|
|
218
|
+
// Collect all image positions to skip them
|
|
219
|
+
const imagePositions = new Set();
|
|
220
|
+
|
|
221
|
+
// Find all markdown images 
|
|
222
|
+
const markdownImages = [...cleanedContent.matchAll(LINK_PATTERNS.markdownImage)];
|
|
223
|
+
for (const match of markdownImages) {
|
|
224
|
+
imagePositions.add(match.index);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Find all HTML images <img src="url">
|
|
228
|
+
const htmlImages = [...cleanedContent.matchAll(LINK_PATTERNS.htmlImage)];
|
|
229
|
+
for (const match of htmlImages) {
|
|
230
|
+
imagePositions.add(match.index);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Extract markdown links [text](url) - skip images
|
|
217
234
|
const markdownMatches = [...cleanedContent.matchAll(LINK_PATTERNS.markdown)];
|
|
218
235
|
for (const match of markdownMatches) {
|
|
236
|
+
// Check if this is actually an image by looking at the character before '['
|
|
237
|
+
const charBefore = match.index > 0 ? cleanedContent[match.index - 1] : '';
|
|
238
|
+
if (charBefore === '!') {
|
|
239
|
+
// This is a markdown image , skip it
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
|
|
219
243
|
const linkText = match[1];
|
|
220
244
|
const href = match[2];
|
|
221
245
|
|