@mintlify/cli 4.0.1337 → 4.0.1339
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/__test__/brokenLinks.test.ts +59 -1
- package/bin/cli.js +19 -4
- package/bin/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/src/cli.tsx +30 -5
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { buildGraph, getBrokenExternalLinks } from '@mintlify/link-rot';
|
|
2
2
|
import { MdxPath } from '@mintlify/link-rot/dist/graph.js';
|
|
3
3
|
import { addLog, clearLogs } from '@mintlify/previewing';
|
|
4
|
+
import path from 'node:path';
|
|
4
5
|
import { mockProcessExit } from 'vitest-mock-process';
|
|
5
6
|
|
|
6
|
-
import {
|
|
7
|
+
import { resolveExplicitFiles } from '../src/deslop/resolveFiles.js';
|
|
8
|
+
import { checkForMintJson, CMD_EXEC_PATH } from '../src/helpers.js';
|
|
7
9
|
import { runCommand } from './utils.js';
|
|
8
10
|
|
|
9
11
|
vi.mock('@mintlify/previewing', async (importOriginal) => {
|
|
@@ -19,6 +21,11 @@ vi.mock('../src/helpers.js', async (importOriginal) => {
|
|
|
19
21
|
};
|
|
20
22
|
});
|
|
21
23
|
|
|
24
|
+
vi.mock('../src/deslop/resolveFiles.js', () => ({
|
|
25
|
+
resolveChangedFiles: vi.fn(),
|
|
26
|
+
resolveExplicitFiles: vi.fn(),
|
|
27
|
+
}));
|
|
28
|
+
|
|
22
29
|
const mockGraph = {
|
|
23
30
|
precomputeFileResolutions: vi.fn(),
|
|
24
31
|
getBrokenInternalLinks: vi.fn().mockReturnValue([]),
|
|
@@ -42,6 +49,7 @@ describe('brokenLinks', () => {
|
|
|
42
49
|
beforeEach(() => {
|
|
43
50
|
vi.clearAllMocks();
|
|
44
51
|
vi.mocked(buildGraph).mockResolvedValue(mockGraph as never);
|
|
52
|
+
vi.mocked(resolveExplicitFiles).mockResolvedValue([]);
|
|
45
53
|
mockGraph.getBrokenInternalLinks.mockReturnValue([]);
|
|
46
54
|
});
|
|
47
55
|
|
|
@@ -94,6 +102,42 @@ describe('brokenLinks', () => {
|
|
|
94
102
|
expect(processExitMock).toHaveBeenCalledWith(1);
|
|
95
103
|
});
|
|
96
104
|
|
|
105
|
+
it('checks only files matching the provided option', async () => {
|
|
106
|
+
vi.mocked(checkForMintJson).mockResolvedValueOnce(true);
|
|
107
|
+
vi.mocked(resolveExplicitFiles).mockResolvedValueOnce(['guides/selected.mdx']);
|
|
108
|
+
mockGraph.getBrokenInternalLinks.mockReturnValue([
|
|
109
|
+
{
|
|
110
|
+
relativeDir: 'guides',
|
|
111
|
+
filename: 'selected.mdx',
|
|
112
|
+
originalPath: '/api/selected-invalid',
|
|
113
|
+
pathType: 'internal',
|
|
114
|
+
} as MdxPath,
|
|
115
|
+
{
|
|
116
|
+
relativeDir: 'guides',
|
|
117
|
+
filename: 'other.mdx',
|
|
118
|
+
originalPath: '/api/other-invalid',
|
|
119
|
+
pathType: 'internal',
|
|
120
|
+
} as MdxPath,
|
|
121
|
+
]);
|
|
122
|
+
|
|
123
|
+
await runCommand('broken-links', '--files', 'guides/selected.mdx', 'guides/**/*.mdx');
|
|
124
|
+
|
|
125
|
+
expect(resolveExplicitFiles).toHaveBeenCalledWith(CMD_EXEC_PATH, [
|
|
126
|
+
'guides/selected.mdx',
|
|
127
|
+
'guides/**/*.mdx',
|
|
128
|
+
]);
|
|
129
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
130
|
+
expect.objectContaining({
|
|
131
|
+
props: {
|
|
132
|
+
brokenLinksByFile: {
|
|
133
|
+
[path.join('guides', 'selected.mdx')]: ['/api/selected-invalid'],
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
})
|
|
137
|
+
);
|
|
138
|
+
expect(processExitMock).toHaveBeenCalledWith(1);
|
|
139
|
+
});
|
|
140
|
+
|
|
97
141
|
it('fails when checking throws error', async () => {
|
|
98
142
|
vi.mocked(checkForMintJson).mockResolvedValueOnce(true);
|
|
99
143
|
vi.mocked(buildGraph).mockRejectedValueOnce(new Error('some error'));
|
|
@@ -118,6 +162,7 @@ describe('brokenLinks --check-external', () => {
|
|
|
118
162
|
beforeEach(() => {
|
|
119
163
|
vi.clearAllMocks();
|
|
120
164
|
vi.mocked(buildGraph).mockResolvedValue(mockGraph as never);
|
|
165
|
+
vi.mocked(resolveExplicitFiles).mockResolvedValue([]);
|
|
121
166
|
mockGraph.getBrokenInternalLinks.mockReturnValue([]);
|
|
122
167
|
});
|
|
123
168
|
|
|
@@ -160,6 +205,19 @@ describe('brokenLinks --check-external', () => {
|
|
|
160
205
|
expect(processExitMock).toHaveBeenCalledWith(1);
|
|
161
206
|
});
|
|
162
207
|
|
|
208
|
+
it('checks external links only from matching files', async () => {
|
|
209
|
+
vi.mocked(checkForMintJson).mockResolvedValueOnce(true);
|
|
210
|
+
vi.mocked(resolveExplicitFiles).mockResolvedValueOnce(['selected.mdx']);
|
|
211
|
+
vi.mocked(getBrokenExternalLinks).mockResolvedValueOnce([]);
|
|
212
|
+
|
|
213
|
+
await runCommand('broken-links', '--files', 'selected.mdx', '--check-external');
|
|
214
|
+
|
|
215
|
+
expect(getBrokenExternalLinks).toHaveBeenCalledWith(mockGraph, {
|
|
216
|
+
sourceFiles: new Set(['selected.mdx']),
|
|
217
|
+
});
|
|
218
|
+
expect(processExitMock).toHaveBeenCalledWith(0);
|
|
219
|
+
});
|
|
220
|
+
|
|
163
221
|
it('fails when external link checking throws error', async () => {
|
|
164
222
|
vi.mocked(checkForMintJson).mockResolvedValueOnce(true);
|
|
165
223
|
vi.mocked(getBrokenExternalLinks).mockRejectedValueOnce(new Error('network error'));
|
package/bin/cli.js
CHANGED
|
@@ -21,6 +21,7 @@ import { setTelemetryEnabled } from './config.js';
|
|
|
21
21
|
import { getConfigValue, setConfigValue, clearConfigValue } from './config.js';
|
|
22
22
|
import { API_URL } from './constants.js';
|
|
23
23
|
import { deslopHandler } from './deslop/index.js';
|
|
24
|
+
import { resolveExplicitFiles } from './deslop/resolveFiles.js';
|
|
24
25
|
import { CMD_EXEC_PATH, checkPort, checkNodeVersion, autoUpgradeIfNeeded, getVersions, isAI, suppressConsoleWarnings, terminate, } from './helpers.js';
|
|
25
26
|
import { init } from './init.js';
|
|
26
27
|
import { getAccessToken } from './keyring.js';
|
|
@@ -232,6 +233,11 @@ export const cli = ({ packageName = 'mint' }) => {
|
|
|
232
233
|
yield terminate(valid ? 0 : 1);
|
|
233
234
|
}))
|
|
234
235
|
.command('broken-links', 'Check for broken links', (yargs) => yargs
|
|
236
|
+
.option('files', {
|
|
237
|
+
type: 'string',
|
|
238
|
+
array: true,
|
|
239
|
+
description: 'Files or globs to check (defaults to the whole site)',
|
|
240
|
+
})
|
|
235
241
|
.option('check-anchors', {
|
|
236
242
|
type: 'boolean',
|
|
237
243
|
default: false,
|
|
@@ -251,17 +257,26 @@ export const cli = ({ packageName = 'mint' }) => {
|
|
|
251
257
|
type: 'boolean',
|
|
252
258
|
default: false,
|
|
253
259
|
description: 'also check that docs.json redirect destinations resolve to valid paths',
|
|
254
|
-
})
|
|
260
|
+
})
|
|
261
|
+
.example('mint broken-links --files introduction.mdx', 'Check a specific page')
|
|
262
|
+
.example('mint broken-links --files "guides/**/*.mdx"', 'Check pages matching a glob'), (argv) => __awaiter(void 0, void 0, void 0, function* () {
|
|
263
|
+
var _a;
|
|
255
264
|
yield autoUpgradeIfNeeded();
|
|
256
265
|
addLog(_jsx(SpinnerLog, { message: "checking for broken links..." }));
|
|
257
266
|
try {
|
|
267
|
+
const fileArgs = ((_a = argv.files) !== null && _a !== void 0 ? _a : []).map(String).filter(Boolean);
|
|
268
|
+
const sourceFiles = fileArgs.length > 0
|
|
269
|
+
? new Set((yield resolveExplicitFiles(CMD_EXEC_PATH, fileArgs)).map((file) => path.normalize(file)))
|
|
270
|
+
: undefined;
|
|
258
271
|
const graph = yield buildGraph(undefined, {
|
|
259
272
|
checkSnippets: argv['check-snippets'],
|
|
260
273
|
});
|
|
261
274
|
graph.precomputeFileResolutions();
|
|
262
|
-
const brokenInternalLinks = graph
|
|
275
|
+
const brokenInternalLinks = graph
|
|
276
|
+
.getBrokenInternalLinks({
|
|
263
277
|
checkAnchors: argv['check-anchors'],
|
|
264
|
-
})
|
|
278
|
+
})
|
|
279
|
+
.filter(({ relativeDir, filename }) => !sourceFiles || sourceFiles.has(path.join(relativeDir, filename)));
|
|
265
280
|
const brokenLinksByFile = {};
|
|
266
281
|
brokenInternalLinks.forEach((mdxPath) => {
|
|
267
282
|
const filename = path.join(mdxPath.relativeDir, mdxPath.filename);
|
|
@@ -274,7 +289,7 @@ export const cli = ({ packageName = 'mint' }) => {
|
|
|
274
289
|
}
|
|
275
290
|
});
|
|
276
291
|
if (argv['check-external']) {
|
|
277
|
-
const brokenExternalLinks = yield getBrokenExternalLinks(graph);
|
|
292
|
+
const brokenExternalLinks = yield getBrokenExternalLinks(graph, sourceFiles ? { sourceFiles } : undefined);
|
|
278
293
|
for (const result of brokenExternalLinks) {
|
|
279
294
|
for (const source of result.sources) {
|
|
280
295
|
const label = result.status
|