@mintlify/link-rot 3.0.892 → 3.0.894
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/graph.d.ts +2 -0
- package/dist/graph.js +28 -0
- package/dist/static-checking/getBrokenInternalLinks.d.ts +2 -0
- package/dist/static-checking/getBrokenInternalLinks.js +30 -3
- package/dist/static-checking/getNavigationHrefs.d.ts +4 -0
- package/dist/static-checking/getNavigationHrefs.js +41 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +6 -6
package/dist/graph.d.ts
CHANGED
|
@@ -43,6 +43,7 @@ export declare class Node {
|
|
|
43
43
|
relativeDir: string;
|
|
44
44
|
filename: string;
|
|
45
45
|
edges: Edge[];
|
|
46
|
+
headingSlugs: Set<string> | null;
|
|
46
47
|
constructor(label: string, paths?: MdxPath[]);
|
|
47
48
|
toString(): string;
|
|
48
49
|
equals(other: Node): boolean;
|
|
@@ -83,6 +84,7 @@ export declare class Graph {
|
|
|
83
84
|
private addEdge;
|
|
84
85
|
addEdgesBetweenNodes(): void;
|
|
85
86
|
precomputeFileResolutions(): void;
|
|
87
|
+
private getHeadingSlugsForPath;
|
|
86
88
|
getBrokenInternalLinks(): MdxPath[];
|
|
87
89
|
getAllInternalPaths(): string[];
|
|
88
90
|
}
|
package/dist/graph.js
CHANGED
|
@@ -150,6 +150,7 @@ export class Node {
|
|
|
150
150
|
this.label = label;
|
|
151
151
|
this.paths = paths;
|
|
152
152
|
this.edges = [];
|
|
153
|
+
this.headingSlugs = null;
|
|
153
154
|
this.relativeDir = normalizePath(dirname(label));
|
|
154
155
|
this.filename = basename(label);
|
|
155
156
|
this.label = join(this.relativeDir, this.filename);
|
|
@@ -339,6 +340,26 @@ export class Graph {
|
|
|
339
340
|
});
|
|
340
341
|
});
|
|
341
342
|
}
|
|
343
|
+
getHeadingSlugsForPath(pathString, nodeSet) {
|
|
344
|
+
var _a;
|
|
345
|
+
const resolvedFiles = this.fileResolutionMap.get(pathString);
|
|
346
|
+
if (resolvedFiles) {
|
|
347
|
+
for (const file of resolvedFiles) {
|
|
348
|
+
if (nodeSet.has(file)) {
|
|
349
|
+
const node = this.nodes[file];
|
|
350
|
+
if (node && node.headingSlugs !== null)
|
|
351
|
+
return node.headingSlugs;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
const directNode = this.nodes[pathString];
|
|
356
|
+
if (directNode && directNode.headingSlugs !== null)
|
|
357
|
+
return directNode.headingSlugs;
|
|
358
|
+
const indexNode = (_a = this.nodes[`${pathString}/index.mdx`]) !== null && _a !== void 0 ? _a : this.nodes[`${pathString}/index.md`];
|
|
359
|
+
if (indexNode && indexNode.headingSlugs !== null)
|
|
360
|
+
return indexNode.headingSlugs;
|
|
361
|
+
return undefined;
|
|
362
|
+
}
|
|
342
363
|
getBrokenInternalLinks() {
|
|
343
364
|
if (this.fileResolutionMap.size === 0) {
|
|
344
365
|
this.precomputeFileResolutions();
|
|
@@ -369,6 +390,13 @@ export class Graph {
|
|
|
369
390
|
if (!hasExistingFile && !hasValidRedirect) {
|
|
370
391
|
brokenLinks.push(path);
|
|
371
392
|
}
|
|
393
|
+
else if (path.anchorLink) {
|
|
394
|
+
const anchor = path.anchorLink.slice(1);
|
|
395
|
+
const headingSlugs = this.getHeadingSlugsForPath(pathString, nodeSet);
|
|
396
|
+
if (headingSlugs && !headingSlugs.has(anchor)) {
|
|
397
|
+
brokenLinks.push(path);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
372
400
|
}
|
|
373
401
|
}
|
|
374
402
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import type { TableOfContentsSectionType } from '@mintlify/common';
|
|
1
2
|
import { Node } from '../graph.js';
|
|
3
|
+
export declare const flattenTableOfContentsSlugs: (sections: TableOfContentsSectionType[]) => Set<string>;
|
|
2
4
|
export declare const decorateGraphNodeFromPageContent: (graphNode: Node, content: string) => Promise<void>;
|
|
3
5
|
/**
|
|
4
6
|
* Get all broken internal links used in the site
|
|
@@ -7,16 +7,28 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { coreRemark, isMintIgnored } from '@mintlify/common';
|
|
10
|
+
import { coreRemark, isMintIgnored, remarkComponentIds, remarkExtractTableOfContents, } from '@mintlify/common';
|
|
11
11
|
import { getMintIgnore } from '@mintlify/prebuild';
|
|
12
12
|
import fs from 'fs-extra';
|
|
13
13
|
import path from 'path';
|
|
14
14
|
import { visit } from 'unist-util-visit';
|
|
15
15
|
import { Graph, Wrapper } from '../graph.js';
|
|
16
16
|
import { getLinkPaths, getPagePaths } from '../prebuild.js';
|
|
17
|
+
import { getNavigationHrefs } from './getNavigationHrefs.js';
|
|
17
18
|
import { getOpenApiPagePaths } from './getOpenApiPagePaths.js';
|
|
18
19
|
import { getRedirects } from './getRedirects.js';
|
|
20
|
+
export const flattenTableOfContentsSlugs = (sections) => {
|
|
21
|
+
const slugs = new Set();
|
|
22
|
+
for (const section of sections) {
|
|
23
|
+
slugs.add(section.slug);
|
|
24
|
+
for (const slug of flattenTableOfContentsSlugs(section.children)) {
|
|
25
|
+
slugs.add(slug);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return slugs;
|
|
29
|
+
};
|
|
19
30
|
export const decorateGraphNodeFromPageContent = (graphNode, content) => __awaiter(void 0, void 0, void 0, function* () {
|
|
31
|
+
const mdxExtracts = {};
|
|
20
32
|
const visitLinks = () => {
|
|
21
33
|
return (tree) => {
|
|
22
34
|
visit(tree, (node) => {
|
|
@@ -49,8 +61,15 @@ export const decorateGraphNodeFromPageContent = (graphNode, content) => __awaite
|
|
|
49
61
|
return tree;
|
|
50
62
|
};
|
|
51
63
|
};
|
|
52
|
-
|
|
53
|
-
|
|
64
|
+
const processor = coreRemark()
|
|
65
|
+
.use(visitLinks)
|
|
66
|
+
.use(remarkComponentIds)
|
|
67
|
+
.use(remarkExtractTableOfContents, mdxExtracts);
|
|
68
|
+
const tree = processor.parse(content);
|
|
69
|
+
yield processor.run(tree);
|
|
70
|
+
graphNode.headingSlugs = mdxExtracts.tableOfContents
|
|
71
|
+
? flattenTableOfContentsSlugs(mdxExtracts.tableOfContents)
|
|
72
|
+
: new Set();
|
|
54
73
|
});
|
|
55
74
|
/**
|
|
56
75
|
* Get all broken internal links used in the site
|
|
@@ -78,6 +97,14 @@ export const getBrokenInternalLinks = (repoPath) => __awaiter(void 0, void 0, vo
|
|
|
78
97
|
catch (err) {
|
|
79
98
|
console.warn(`Warning: Failed to extract OpenAPI page paths: ${err}`);
|
|
80
99
|
}
|
|
100
|
+
const navResult = yield getNavigationHrefs(baseDir);
|
|
101
|
+
if (navResult) {
|
|
102
|
+
const configNode = graph.addNode(navResult.configFile);
|
|
103
|
+
for (const href of navResult.hrefs) {
|
|
104
|
+
const normalized = href === '/' || href === '' ? '/index' : href.replace(/^\/#/, '/index#');
|
|
105
|
+
configNode.addPath(normalized);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
81
108
|
const allSitePages = getPagePaths(baseDir);
|
|
82
109
|
const sitePages = allSitePages.filter((file) => !isMintIgnored(file, mintIgnoreGlobs));
|
|
83
110
|
yield Promise.all(sitePages.map((filePath) => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -0,0 +1,41 @@
|
|
|
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 fs from 'fs-extra';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
const collectHrefs = (obj) => {
|
|
13
|
+
if (typeof obj !== 'object' || obj === null)
|
|
14
|
+
return [];
|
|
15
|
+
if (Array.isArray(obj))
|
|
16
|
+
return obj.flatMap(collectHrefs);
|
|
17
|
+
const record = obj;
|
|
18
|
+
const hrefs = [];
|
|
19
|
+
if (typeof record.href === 'string') {
|
|
20
|
+
hrefs.push(record.href);
|
|
21
|
+
}
|
|
22
|
+
for (const value of Object.values(record)) {
|
|
23
|
+
hrefs.push(...collectHrefs(value));
|
|
24
|
+
}
|
|
25
|
+
return hrefs;
|
|
26
|
+
};
|
|
27
|
+
export const getNavigationHrefs = (baseDir) => __awaiter(void 0, void 0, void 0, function* () {
|
|
28
|
+
let configJson;
|
|
29
|
+
let configFile;
|
|
30
|
+
if (fs.existsSync(path.join(baseDir, 'docs.json'))) {
|
|
31
|
+
configJson = yield fs.readJSON(path.join(baseDir, 'docs.json'));
|
|
32
|
+
configFile = 'docs.json';
|
|
33
|
+
}
|
|
34
|
+
else if (fs.existsSync(path.join(baseDir, 'mint.json'))) {
|
|
35
|
+
configJson = yield fs.readJSON(path.join(baseDir, 'mint.json'));
|
|
36
|
+
configFile = 'mint.json';
|
|
37
|
+
}
|
|
38
|
+
if (!(configJson === null || configJson === void 0 ? void 0 : configJson.navigation) || !configFile)
|
|
39
|
+
return undefined;
|
|
40
|
+
return { hrefs: collectHrefs(configJson.navigation), configFile };
|
|
41
|
+
});
|