UNPKG

@mintlify/link-rot

Version:

Static checking for broken internal links

85 lines (84 loc) 4.2 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { generateOpenApiFromDocsConfig, getOpenApiFiles, getOpenApiFilesFromConfig, } from '@mintlify/prebuild'; import { generateOpenApiPagesForDocsConfig } from '@mintlify/scraping'; import { validateDocsConfig } from '@mintlify/validation'; import { readResolvedConfigJson } from './readConfig.js'; const DEFAULT_OUTPUT_DIR = 'api-reference'; /** * Extract virtual page paths that would be generated from OpenAPI specs. * These pages don't exist as files but are valid link targets. * * For docs.json (v2) configs, this walks the navigation tree so that per-spec * `directory` overrides and inherited directories are honored — matching the * slugs production generates. For mint.json (v1) or missing configs, it falls * back to generating page paths under the default `api-reference` directory. * * `$ref` pointers inside the config are resolved first, so navigation split * across multiple JSON files is walked end-to-end. */ export const getOpenApiPagePaths = (baseDir) => __awaiter(void 0, void 0, void 0, function* () { const pagePaths = []; try { const openApiFiles = yield getOpenApiFiles(baseDir); const docsConfig = yield readDocsConfig(baseDir); if (docsConfig) { const urlOpenApiFiles = yield safeGetOpenApiFilesFromConfig(docsConfig); const allOpenApiFiles = [...openApiFiles, ...urlOpenApiFiles]; const pagesAcc = {}; try { yield generateOpenApiFromDocsConfig(docsConfig.navigation, allOpenApiFiles, pagesAcc, { writeFiles: false, }); } catch (err) { console.warn(`Warning: Failed to extract OpenAPI pages from navigation: ${err}`); } pagePaths.push(...Object.keys(pagesAcc)); } // Also enumerate default-directory pages per local spec. This preserves // the previous behavior for configs that don't wire every OpenAPI file // into `navigation`, and keeps us permissive (extra virtual nodes can // only hide broken-link reports, never add false positives). for (const openApiFile of openApiFiles) { try { const { pagesAcc } = yield generateOpenApiPagesForDocsConfig(openApiFile.spec, { openApiFilePath: openApiFile.originalFileLocation, writeFiles: false, outDir: DEFAULT_OUTPUT_DIR, }); pagePaths.push(...Object.keys(pagesAcc)); } catch (err) { console.warn(`Warning: Failed to extract pages from OpenAPI spec ${openApiFile.originalFileLocation}: ${err}`); } } } catch (err) { console.warn(`Warning: Failed to categorize files for OpenAPI extraction: ${err}`); } return [...new Set(pagePaths)]; }); const readDocsConfig = (baseDir) => __awaiter(void 0, void 0, void 0, function* () { const resolved = yield readResolvedConfigJson(baseDir); if (!resolved || resolved.configFile !== 'docs.json') return null; const result = validateDocsConfig(resolved.json); return result.success ? result.data : null; }); const safeGetOpenApiFilesFromConfig = (docsConfig) => __awaiter(void 0, void 0, void 0, function* () { try { return yield getOpenApiFilesFromConfig('docs', docsConfig); } catch (err) { console.warn(`Warning: Failed to fetch URL-based OpenAPI specs: ${err}`); return []; } });