@mintlify/cli 4.0.1705 → 4.0.1706

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.
@@ -0,0 +1,122 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { jsx as _jsx } from "react/jsx-runtime";
11
+ import { buildGraph, getBrokenExternalLinks, getFilesLinksDependOn } from '@mintlify/link-rot';
12
+ import { addLog, clearLogs, BrokenLinksLog, ErrorLog, SpinnerLog, SuccessLog, WarningLog, } from '@mintlify/previewing';
13
+ import fs from 'node:fs/promises';
14
+ import path from 'path';
15
+ import { autoUpgradeIfNeeded, CMD_EXEC_PATH, findDocsRoot, terminate } from './helpers.js';
16
+ import { resolveExplicitFiles } from './resolveFiles.js';
17
+ export const brokenLinksHandler = (argv) => __awaiter(void 0, void 0, void 0, function* () {
18
+ var _a;
19
+ yield autoUpgradeIfNeeded();
20
+ addLog(_jsx(SpinnerLog, { message: "checking for broken links..." }));
21
+ try {
22
+ const docsRoot = yield findDocsRoot(CMD_EXEC_PATH);
23
+ const fileArgs = ((_a = argv.files) !== null && _a !== void 0 ? _a : []).map(String).filter(Boolean);
24
+ const sourceFiles = fileArgs.length > 0
25
+ ? new Set((yield resolveExplicitFiles(CMD_EXEC_PATH, fileArgs)).map((file) => path.relative(docsRoot, path.resolve(CMD_EXEC_PATH, file))))
26
+ : undefined;
27
+ // One unparseable page shouldn't hide every other result: report it and keep going
28
+ const parseErrorsByFile = new Map();
29
+ const graph = yield buildGraph(docsRoot, {
30
+ checkSnippets: argv['check-snippets'],
31
+ onParseError: (filePath, error) => parseErrorsByFile.set(filePath, error.message),
32
+ });
33
+ graph.precomputeFileResolutions();
34
+ // With --files, a failure elsewhere only matters when a selected link needs that
35
+ // file: an anchor pointing at it, or a snippet the selected page renders
36
+ const dependencies = sourceFiles
37
+ ? getFilesLinksDependOn(graph, sourceFiles, {
38
+ checkAnchors: argv['check-anchors'],
39
+ checkSnippets: argv['check-snippets'],
40
+ })
41
+ : undefined;
42
+ const parseErrors = [...parseErrorsByFile]
43
+ .filter(([filePath]) => !sourceFiles ||
44
+ sourceFiles.has(filePath) ||
45
+ (dependencies === null || dependencies === void 0 ? void 0 : dependencies.has(filePath.split(path.sep).join('/'))))
46
+ .map(([, message]) => message);
47
+ const brokenInternalLinks = graph
48
+ .getBrokenInternalLinks({
49
+ checkAnchors: argv['check-anchors'],
50
+ })
51
+ .filter(({ relativeDir, filename }) => !sourceFiles || sourceFiles.has(path.join(relativeDir, filename)));
52
+ const brokenLinksByFile = {};
53
+ brokenInternalLinks.forEach((mdxPath) => {
54
+ const filename = path.join(mdxPath.relativeDir, mdxPath.filename);
55
+ const existing = brokenLinksByFile[filename];
56
+ if (existing) {
57
+ existing.push(mdxPath.originalPath);
58
+ }
59
+ else {
60
+ brokenLinksByFile[filename] = [mdxPath.originalPath];
61
+ }
62
+ });
63
+ if (argv['check-external']) {
64
+ const brokenExternalLinks = yield getBrokenExternalLinks(graph, sourceFiles ? { sourceFiles } : undefined);
65
+ for (const result of brokenExternalLinks) {
66
+ for (const source of result.sources) {
67
+ const label = result.status
68
+ ? `${result.url} (${result.status})`
69
+ : `${result.url} (${result.error})`;
70
+ const existing = brokenLinksByFile[source.file];
71
+ if (existing) {
72
+ existing.push(label);
73
+ }
74
+ else {
75
+ brokenLinksByFile[source.file] = [label];
76
+ }
77
+ }
78
+ }
79
+ }
80
+ if (argv['check-redirects']) {
81
+ const brokenRedirects = graph.getBrokenRedirects();
82
+ if (brokenRedirects.length > 0) {
83
+ const configFilename = yield fs
84
+ .access(path.join(docsRoot, 'docs.json'))
85
+ .then(() => 'docs.json')
86
+ .catch(() => 'mint.json');
87
+ const labels = brokenRedirects.map(({ source, destination }) => `${source} → ${destination}`);
88
+ const existing = brokenLinksByFile[configFilename];
89
+ if (existing) {
90
+ existing.push(...labels);
91
+ }
92
+ else {
93
+ brokenLinksByFile[configFilename] = labels;
94
+ }
95
+ }
96
+ }
97
+ const hasBrokenLinks = Object.keys(brokenLinksByFile).length > 0;
98
+ if (!hasBrokenLinks && parseErrors.length === 0) {
99
+ clearLogs();
100
+ addLog(_jsx(SuccessLog, { message: "no broken links found" }));
101
+ yield terminate(0);
102
+ }
103
+ clearLogs();
104
+ if (hasBrokenLinks) {
105
+ addLog(_jsx(BrokenLinksLog, { brokenLinksByFile: brokenLinksByFile }));
106
+ }
107
+ else {
108
+ addLog(_jsx(SuccessLog, { message: "no broken links found in the files that parsed" }));
109
+ }
110
+ for (const message of parseErrors) {
111
+ addLog(_jsx(ErrorLog, { message: message }));
112
+ }
113
+ if (parseErrors.length > 0) {
114
+ addLog(_jsx(WarningLog, { message: `skipped ${parseErrors.length} file(s) that could not be parsed; links in them were not checked` }));
115
+ }
116
+ }
117
+ catch (err) {
118
+ addLog(_jsx(ErrorLog, { message: err instanceof Error ? err.message : 'unknown error' }));
119
+ yield terminate(1);
120
+ }
121
+ yield terminate(1);
122
+ });
package/bin/cli.js CHANGED
@@ -8,8 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
- import { buildGraph, getBrokenExternalLinks, getFilesLinksDependOn } from '@mintlify/link-rot';
12
- import { addLog, dev, exportSite, validateBuild, ErrorLog, SpinnerLog, SuccessLog, Logs, clearLogs, BrokenLinksLog, WarningLog, } from '@mintlify/previewing';
11
+ import { addLog, dev, exportSite, validateBuild, ErrorLog, SuccessLog, Logs, WarningLog, } from '@mintlify/previewing';
13
12
  import { thumbnailOverrideSchema } from '@mintlify/validation';
14
13
  import { render, Text } from 'ink';
15
14
  import fs from 'node:fs/promises';
@@ -20,6 +19,7 @@ import { accessibilityCheck } from './accessibilityCheck.js';
20
19
  import { addDomain } from './addDomain.js';
21
20
  import { createAgentClaimLink } from './agent-claim.js';
22
21
  import { analyticsBuilder } from './analytics/index.js';
22
+ import { brokenLinksHandler } from './brokenLinks.js';
23
23
  import { comingSoon } from './comingSoon.js';
24
24
  import { setTelemetryEnabled } from './config.js';
25
25
  import { getConfigValue, setConfigValue, clearConfigValue } from './config.js';
@@ -27,7 +27,7 @@ import { API_URL } from './constants.js';
27
27
  import { DEPLOY_HELP, deploymentInstructions } from './deploy-instructions.js';
28
28
  import { formatDeployment, prepareAgentDeployment } from './deploy.js';
29
29
  import { formatHandler } from './format.js';
30
- import { CMD_EXEC_PATH, checkPort, checkNodeVersion, autoUpgradeIfNeeded, findDocsRoot, getVersions, isAI, suppressConsoleWarnings, terminate, } from './helpers.js';
30
+ import { CMD_EXEC_PATH, checkPort, checkNodeVersion, autoUpgradeIfNeeded, getVersions, isAI, suppressConsoleWarnings, terminate, } from './helpers.js';
31
31
  import { init } from './init.js';
32
32
  import { getAccessToken } from './keyring.js';
33
33
  import { login } from './login.js';
@@ -36,7 +36,6 @@ import { mdxLinter } from './mdxLinter.js';
36
36
  import { createTelemetryMiddleware } from './middlewares/telemetryMiddleware.js';
37
37
  import { ogCommand } from './og.js';
38
38
  import { buildOverlayRegistryForCheck, checkOpenApiFile, getOpenApiFilenamesFromDocsConfig, } from './openApiCheck.js';
39
- import { resolveExplicitFiles } from './resolveFiles.js';
40
39
  import { scoreHandler } from './score/index.js';
41
40
  import { sendPublishPrompt, signup } from './signup.js';
42
41
  import { status, getCliSubdomains } from './status.js';
@@ -362,112 +361,7 @@ export const cli = ({ packageName = 'mint' }) => {
362
361
  description: 'also check that docs.json redirect destinations resolve to valid paths',
363
362
  })
364
363
  .example('mint broken-links --files introduction.mdx', 'Check a specific page')
365
- .example('mint broken-links --files "guides/**/*.mdx"', 'Check pages matching a glob'), (argv) => __awaiter(void 0, void 0, void 0, function* () {
366
- var _a;
367
- yield autoUpgradeIfNeeded();
368
- addLog(_jsx(SpinnerLog, { message: "checking for broken links..." }));
369
- try {
370
- const docsRoot = yield findDocsRoot(CMD_EXEC_PATH);
371
- const fileArgs = ((_a = argv.files) !== null && _a !== void 0 ? _a : []).map(String).filter(Boolean);
372
- const sourceFiles = fileArgs.length > 0
373
- ? new Set((yield resolveExplicitFiles(CMD_EXEC_PATH, fileArgs)).map((file) => path.relative(docsRoot, path.resolve(CMD_EXEC_PATH, file))))
374
- : undefined;
375
- // One unparseable page shouldn't hide every other result: report it and keep going
376
- const parseErrorsByFile = new Map();
377
- const graph = yield buildGraph(docsRoot, {
378
- checkSnippets: argv['check-snippets'],
379
- onParseError: (filePath, error) => parseErrorsByFile.set(filePath, error.message),
380
- });
381
- graph.precomputeFileResolutions();
382
- // With --files, a failure elsewhere only matters when a selected link needs that
383
- // file: an anchor pointing at it, or a snippet the selected page renders
384
- const dependencies = sourceFiles
385
- ? getFilesLinksDependOn(graph, sourceFiles, {
386
- checkAnchors: argv['check-anchors'],
387
- checkSnippets: argv['check-snippets'],
388
- })
389
- : undefined;
390
- const parseErrors = [...parseErrorsByFile]
391
- .filter(([filePath]) => !sourceFiles ||
392
- sourceFiles.has(filePath) ||
393
- (dependencies === null || dependencies === void 0 ? void 0 : dependencies.has(filePath.split(path.sep).join('/'))))
394
- .map(([, message]) => message);
395
- const brokenInternalLinks = graph
396
- .getBrokenInternalLinks({
397
- checkAnchors: argv['check-anchors'],
398
- })
399
- .filter(({ relativeDir, filename }) => !sourceFiles || sourceFiles.has(path.join(relativeDir, filename)));
400
- const brokenLinksByFile = {};
401
- brokenInternalLinks.forEach((mdxPath) => {
402
- const filename = path.join(mdxPath.relativeDir, mdxPath.filename);
403
- const existing = brokenLinksByFile[filename];
404
- if (existing) {
405
- existing.push(mdxPath.originalPath);
406
- }
407
- else {
408
- brokenLinksByFile[filename] = [mdxPath.originalPath];
409
- }
410
- });
411
- if (argv['check-external']) {
412
- const brokenExternalLinks = yield getBrokenExternalLinks(graph, sourceFiles ? { sourceFiles } : undefined);
413
- for (const result of brokenExternalLinks) {
414
- for (const source of result.sources) {
415
- const label = result.status
416
- ? `${result.url} (${result.status})`
417
- : `${result.url} (${result.error})`;
418
- const existing = brokenLinksByFile[source.file];
419
- if (existing) {
420
- existing.push(label);
421
- }
422
- else {
423
- brokenLinksByFile[source.file] = [label];
424
- }
425
- }
426
- }
427
- }
428
- if (argv['check-redirects']) {
429
- const brokenRedirects = graph.getBrokenRedirects();
430
- if (brokenRedirects.length > 0) {
431
- const configFilename = yield fs
432
- .access(path.join(docsRoot, 'docs.json'))
433
- .then(() => 'docs.json')
434
- .catch(() => 'mint.json');
435
- const labels = brokenRedirects.map(({ source, destination }) => `${source} → ${destination}`);
436
- const existing = brokenLinksByFile[configFilename];
437
- if (existing) {
438
- existing.push(...labels);
439
- }
440
- else {
441
- brokenLinksByFile[configFilename] = labels;
442
- }
443
- }
444
- }
445
- const hasBrokenLinks = Object.keys(brokenLinksByFile).length > 0;
446
- if (!hasBrokenLinks && parseErrors.length === 0) {
447
- clearLogs();
448
- addLog(_jsx(SuccessLog, { message: "no broken links found" }));
449
- yield terminate(0);
450
- }
451
- clearLogs();
452
- if (hasBrokenLinks) {
453
- addLog(_jsx(BrokenLinksLog, { brokenLinksByFile: brokenLinksByFile }));
454
- }
455
- else {
456
- addLog(_jsx(SuccessLog, { message: "no broken links found in the files that parsed" }));
457
- }
458
- for (const message of parseErrors) {
459
- addLog(_jsx(ErrorLog, { message: message }));
460
- }
461
- if (parseErrors.length > 0) {
462
- addLog(_jsx(WarningLog, { message: `skipped ${parseErrors.length} file(s) that could not be parsed; links in them were not checked` }));
463
- }
464
- }
465
- catch (err) {
466
- addLog(_jsx(ErrorLog, { message: err instanceof Error ? err.message : 'unknown error' }));
467
- yield terminate(1);
468
- }
469
- yield terminate(1);
470
- }))
364
+ .example('mint broken-links --files "guides/**/*.mdx"', 'Check pages matching a glob'), (argv) => brokenLinksHandler(argv))
471
365
  .command('status', 'View current authentication status', () => undefined, () => __awaiter(void 0, void 0, void 0, function* () {
472
366
  yield status();
473
367
  yield terminate(0);