@mintlify/link-rot 3.0.1440 → 3.0.1441

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 CHANGED
@@ -33,10 +33,16 @@ export declare class MdxPath {
33
33
  private constructParsedPath;
34
34
  constructor(originalPath: string, relativeDir?: string, filename?: string, wrapper?: Wrapper | undefined);
35
35
  toString(): string;
36
- getResolvedFiles(allFiles: string[], baseDir: string): string[];
37
- resolvesTo(node: Node, allFiles: string[], baseDir: string): boolean;
36
+ getResolvedFiles(fileIndex: FileIndex, baseDir: string): string[];
37
+ resolvesTo(node: Node, fileIndex: FileIndex, baseDir: string): boolean;
38
38
  static filterMapInternalPaths(paths: string[]): string[];
39
39
  }
40
+ export declare class FileIndex {
41
+ private byDirAndName;
42
+ constructor(allFiles: string[]);
43
+ private static key;
44
+ lookup(dir: string, name: string, base: string): string[];
45
+ }
40
46
  export declare class Node {
41
47
  label: string;
42
48
  paths: MdxPath[];
package/dist/graph.js CHANGED
@@ -119,34 +119,25 @@ export class MdxPath {
119
119
  }
120
120
  return this.path.toString();
121
121
  }
122
- getResolvedFiles(allFiles, baseDir) {
123
- if (this.pathType !== PathType.INTERNAL)
122
+ getResolvedFiles(fileIndex, baseDir) {
123
+ if (this.pathType !== PathType.INTERNAL || this.path instanceof URL)
124
124
  return [];
125
- const parsedPath = this.path;
125
+ const { dir, name, base } = parse(this.toString());
126
126
  const resolvedFiles = [];
127
127
  if (existsSync(resolve(baseDir, this.toString()))) {
128
- resolvedFiles.push(join(parsedPath.dir, parsedPath.base));
128
+ resolvedFiles.push(join(dir, base));
129
129
  }
130
130
  // there may be multiple files/folders corresponding to the node
131
- for (const file of allFiles) {
132
- const fileWithoutLeadingSlash = file.startsWith('/') ? file.slice(1) : file;
133
- const parsedFilePath = parse(fileWithoutLeadingSlash);
134
- if (parsedFilePath.dir === parsedPath.dir && parsedFilePath.name === parsedPath.name) {
135
- resolvedFiles.push(fileWithoutLeadingSlash);
136
- }
137
- if (parsedFilePath.dir === parsedPath.dir && parsedPath.base === parsedFilePath.name) {
138
- // account for edge case when there is another . in the filename
139
- resolvedFiles.push(fileWithoutLeadingSlash);
140
- }
141
- }
131
+ // account for edge case when there is another . in the filename
132
+ resolvedFiles.push(...fileIndex.lookup(dir, name, base));
142
133
  return resolvedFiles;
143
134
  }
144
- resolvesTo(node, allFiles, baseDir) {
135
+ resolvesTo(node, fileIndex, baseDir) {
145
136
  if (this.pathType !== PathType.INTERNAL)
146
137
  return false;
147
138
  if (this.toString() === node.toString())
148
139
  return true;
149
- if (this.getResolvedFiles(allFiles, baseDir).includes(node.toString()))
140
+ if (this.getResolvedFiles(fileIndex, baseDir).includes(node.toString()))
150
141
  return true;
151
142
  return false;
152
143
  }
@@ -157,6 +148,31 @@ export class MdxPath {
157
148
  .map((path) => path.toString());
158
149
  }
159
150
  }
151
+ export class FileIndex {
152
+ constructor(allFiles) {
153
+ this.byDirAndName = new Map();
154
+ allFiles.forEach((file, order) => {
155
+ const fileWithoutLeadingSlash = file.startsWith('/') ? file.slice(1) : file;
156
+ const { dir, name } = parse(fileWithoutLeadingSlash);
157
+ const key = FileIndex.key(dir, name);
158
+ const entry = [order, fileWithoutLeadingSlash];
159
+ const bucket = this.byDirAndName.get(key);
160
+ if (bucket)
161
+ bucket.push(entry);
162
+ else
163
+ this.byDirAndName.set(key, [entry]);
164
+ });
165
+ }
166
+ static key(dir, name) {
167
+ return `${dir}\0${name}`;
168
+ }
169
+ lookup(dir, name, base) {
170
+ var _a, _b;
171
+ const byName = (_a = this.byDirAndName.get(FileIndex.key(dir, name))) !== null && _a !== void 0 ? _a : [];
172
+ const byBase = base === name ? [] : ((_b = this.byDirAndName.get(FileIndex.key(dir, base))) !== null && _b !== void 0 ? _b : []);
173
+ return [...byName, ...byBase].sort(([a], [b]) => a - b).map(([, file]) => file);
174
+ }
175
+ }
160
176
  /*
161
177
  * A node is a representation of a page
162
178
  * One node can contain multiple MdxPaths (corresponding to internal/external links in the page)
@@ -333,11 +349,11 @@ export class Graph {
333
349
  return newEdge;
334
350
  }
335
351
  addEdgesBetweenNodes() {
336
- const allFiles = getLinkPaths(this.baseDir, this.mintIgnoreGlobs);
352
+ const fileIndex = new FileIndex(getLinkPaths(this.baseDir, this.mintIgnoreGlobs));
337
353
  for (const node of Object.values(this.nodes)) {
338
354
  for (const path of node.paths) {
339
355
  if (path.pathType === PathType.INTERNAL) {
340
- const targetNode = Object.values(this.nodes).find((otherNode) => path.resolvesTo(otherNode, allFiles, this.baseDir));
356
+ const targetNode = Object.values(this.nodes).find((otherNode) => path.resolvesTo(otherNode, fileIndex, this.baseDir));
341
357
  if (targetNode) {
342
358
  const edge = this.addEdge(node, targetNode);
343
359
  node.addOutgoingEdge(edge);
@@ -347,14 +363,18 @@ export class Graph {
347
363
  }
348
364
  }
349
365
  precomputeFileResolutions() {
350
- const allFiles = getLinkPaths(this.baseDir, this.mintIgnoreGlobs);
366
+ const fileIndex = new FileIndex(getLinkPaths(this.baseDir, this.mintIgnoreGlobs));
367
+ const resolvedKeys = new Set();
351
368
  // Build resolution map for all internal paths
352
369
  Object.values(this.nodes).forEach((node) => {
353
370
  node.paths
354
371
  .filter((path) => path.pathType === PathType.INTERNAL)
355
372
  .forEach((path) => {
356
- const resolvedFiles = path.getResolvedFiles(allFiles, this.baseDir);
357
373
  const pathKey = path.toString();
374
+ if (resolvedKeys.has(pathKey))
375
+ return;
376
+ resolvedKeys.add(pathKey);
377
+ const resolvedFiles = path.getResolvedFiles(fileIndex, this.baseDir);
358
378
  this.fileResolutionMap.set(pathKey, new Set(resolvedFiles));
359
379
  });
360
380
  });
@@ -385,6 +405,7 @@ export class Graph {
385
405
  }
386
406
  const brokenLinks = [];
387
407
  const nodeSet = new Set(Object.values(this.nodes).map((node) => node.toString()));
408
+ const wildcardRedirects = [...this.redirectMap].filter(([source]) => /[:*]/.test(source));
388
409
  for (const node of Object.values(this.nodes)) {
389
410
  for (const path of node.paths) {
390
411
  if (path.pathType === PathType.INTERNAL) {
@@ -392,11 +413,11 @@ export class Graph {
392
413
  const resolvedFiles = this.fileResolutionMap.get(pathString);
393
414
  const hasExistingFile = (resolvedFiles && [...resolvedFiles].some((file) => nodeSet.has(file))) ||
394
415
  this.virtualNodes.has(pathString);
395
- let redirectDestination = this.redirectMap.get(pathString);
416
+ let redirectDestination = hasExistingFile ? undefined : this.redirectMap.get(pathString);
396
417
  let hasValidRedirect = redirectDestination &&
397
418
  (nodeSet.has(`${redirectDestination}.mdx`) || nodeSet.has(redirectDestination));
398
- if (!hasValidRedirect) {
399
- for (const [sourcePattern, destinationPattern] of this.redirectMap.entries()) {
419
+ if (!hasExistingFile && !hasValidRedirect) {
420
+ for (const [sourcePattern, destinationPattern] of wildcardRedirects) {
400
421
  if (this.matchesWildcardPattern(pathString, sourcePattern)) {
401
422
  redirectDestination = this.applyWildcardRedirect(pathString, sourcePattern, destinationPattern);
402
423
  hasValidRedirect =