UNPKG

@mintlify/prebuild

Version:

Helpful functions for Mintlify's prebuild step

127 lines (126 loc) 6.33 kB
import { stringifyTree, containsUpdates } from '@mintlify/common'; import { upgradeToDocsConfig } from '@mintlify/validation'; import { outputFile } from 'fs-extra'; import { join } from 'path'; import { updateDocsConfigFile } from './docsConfig/index.js'; import { updateMintConfigFile } from './mintConfig/index.js'; import { readPageContents, readSnippetsV2Contents } from './read/readContent.js'; import { resolveImportsAndWriteFiles } from './resolveImportsAndWriteFiles.js'; import { updateFavicons } from './updateFavicons.js'; import { updateGeneratedDocsNav, updateGeneratedNav } from './updateGeneratedNav.js'; import { writeAsyncApiFiles } from './write/writeAsyncApiFiles.js'; import { writeFiles, writeFile } from './write/writeFiles.js'; import { writeOpenApiData } from './write/writeOpenApiData.js'; import { writeRssFiles } from './write/writeRssFiles.js'; export const update = async ({ contentDirectoryPath, staticFilenames, openApiFiles, asyncApiFiles, contentFilenames, snippets, snippetV2Filenames, docsConfigPath, localSchema, groups, mintIgnore, disableOpenApi, strict, }) => { const mintConfigResult = await updateMintConfigFile(contentDirectoryPath, openApiFiles, localSchema, strict); // we used the original mint config without openapi pages injected // because we will do it in `updateDocsConfigFile`, this will avoid duplicated openapi pages const docsConfig = mintConfigResult != null ? upgradeToDocsConfig(mintConfigResult.originalMintConfig) : undefined; const { docsConfig: newDocsConfig, pagesAcc, newOpenApiFiles, newAsyncApiFiles, customLanguages, } = await updateDocsConfigFile({ contentDirectoryPath, openApiFiles, asyncApiFiles, docsConfig: docsConfigPath ? undefined : docsConfig, localSchema, disableOpenApi, strict, }); const pagePromises = readPageContents({ contentDirectoryPath, openApiFiles: newOpenApiFiles, asyncApiFiles: newAsyncApiFiles, contentFilenames, pagesAcc, }); const snippetV2Promises = readSnippetsV2Contents(contentDirectoryPath, snippetV2Filenames); const [snippetV2Contents, { mdxFilesWithNoImports, filesWithImports }] = await Promise.all([ snippetV2Promises, pagePromises, ]); // Filter pages with rss: true in frontmatter OR pages that contain Update components const rssPages = mdxFilesWithNoImports.filter((page) => page.metadata.rss === true || containsUpdates(page.tree)); // Also include RSS pages that have imports (e.g., changelog entries as separate snippet files) // For these, we need to extract the snippets using the importMap and include the component names // so they can be properly resolved on the server side const rssPagesWithImports = filesWithImports .filter((file) => { // Check if the file has rss: true metadata if (file.metadata?.rss === true) { return true; } // Check if the file itself contains Update components if (containsUpdates(file.tree)) { return true; } // Check if any of the imported snippets contain Update components const importedSnippets = Object.keys(file.importMap).map((importPath) => snippetV2Contents.find((s) => s.filename === importPath)); return importedSnippets.some((snippet) => snippet && containsUpdates(snippet.tree)); }) .map((file) => { // Extract snippets referenced by this page using its importMap // Map component names (import specifiers) to snippets for proper injection const referencedSnippets = []; for (const [importPath, importSpecifiers] of Object.entries(file.importMap)) { const snippet = snippetV2Contents.find((s) => s.filename === importPath); if (snippet) { // Get all the import names (component names) for this snippet const importNames = importSpecifiers.map((spec) => spec.name); referencedSnippets.push({ ...snippet, importNames, }); } } return { targetPath: join('src', '_props', file.filename), sourcePath: join(contentDirectoryPath, file.filename), tree: file.tree, metadata: file.metadata, snippets: referencedSnippets, }; }); const allRssPages = [...rssPages, ...rssPagesWithImports]; const writeDevGroupsPromise = groups && groups.length > 0 ? outputFile('src/_props/dev-groups.json', JSON.stringify({ groups }, null, 2), { flag: 'w' }) : Promise.resolve(); const writeMintIgnorePromise = mintIgnore && mintIgnore.length > 0 ? outputFile('src/_props/mint-ignore.json', JSON.stringify(mintIgnore, null, 2), { flag: 'w', }) : Promise.resolve(); await Promise.all([ writeDevGroupsPromise, writeMintIgnorePromise, resolveImportsAndWriteFiles({ openApiFiles: newOpenApiFiles, asyncApiFiles: newAsyncApiFiles, pagesAcc, snippetsV2: snippetV2Contents, filesWithImports, }), writeFile(customLanguages, 'src/_props/customLanguages.json'), writeOpenApiData(newOpenApiFiles), writeAsyncApiFiles(newAsyncApiFiles), writeRssFiles(newDocsConfig, allRssPages, contentDirectoryPath, snippetV2Contents), updateFavicons(newDocsConfig, contentDirectoryPath), ...writeMdxFilesWithNoImports(mdxFilesWithNoImports), ...writeFiles(contentDirectoryPath, 'public', [...staticFilenames, ...snippets]), ]); await updateGeneratedDocsNav(pagesAcc, newDocsConfig.navigation); if (mintConfigResult?.mintConfig) { await updateGeneratedNav(pagesAcc, mintConfigResult.mintConfig.navigation); } return newDocsConfig; }; export const writeMdxFilesWithNoImports = (mdxFilesWithNoImports) => { return mdxFilesWithNoImports.map(async (response) => { const { targetPath, tree } = response; await outputFile(targetPath, stringifyTree(tree), { flag: 'w', }); }); }; export * from './mintConfig/index.js'; export * from './docsConfig/index.js'; export * from './ConfigUpdater.js';