UNPKG

@mintlify/cli

Version:

The Mintlify CLI

167 lines (158 loc) 5.52 kB
import { validate, getOpenApiDocumentFromUrl } from '@mintlify/common'; import { getBrokenInternalLinks, renameFilesAndUpdateLinksInContent } from '@mintlify/link-rot'; import { dev } from '@mintlify/previewing'; import Chalk from 'chalk'; import fs from 'fs/promises'; import yaml from 'js-yaml'; import path from 'path'; import yargs from 'yargs'; import { hideBin } from 'yargs/helpers'; import { checkPort, checkForMintJson, checkNodeVersion, upgradeConfig, checkForDocsJson, } from './helpers.js'; export const cli = () => yargs(hideBin(process.argv)) .middleware(checkNodeVersion) .command( 'dev', 'Runs Mintlify project locally.', (yargs) => yargs .option('open', { type: 'boolean', default: true, description: 'Open 🌿 Mintlify in the browser', }) .usage('Usage: mintlify dev [options]') .example('mintlify dev', 'Run with default settings (opens in browser)') .example('mintlify dev --no-open', 'Run without opening in browser'), async (argv) => { const port = await checkPort(argv); if (port != undefined) { await dev({ ...argv, port, }); } else { console.error(`No available port found.`); } } ) .command( 'openapi-check <openapiFilenameOrUrl>', 'Validate an OpenAPI spec', (yargs) => yargs.positional('openapiFilenameOrUrl', { describe: 'The filename of the OpenAPI spec (e.g. ./openapi.yaml) or the URL to the OpenAPI spec (e.g. https://petstore3.swagger.io/api/v3/openapi.json)', type: 'string', demandOption: true, }), async ({ openapiFilenameOrUrl }) => { try { if (openapiFilenameOrUrl.startsWith('https://')) { await getOpenApiDocumentFromUrl(openapiFilenameOrUrl); console.log('✅ Your OpenAPI definition is valid.'); process.exit(0); } const pathname = path.resolve(process.cwd(), openapiFilenameOrUrl); const file = await fs.readFile(pathname, 'utf-8'); const document = yaml.load(file) as Record<string, unknown> | undefined; if (!document) { throw new Error( 'Failed to parse OpenAPI spec: could not parse file correctly, please check for any syntax errors.' ); } await validate(document); console.log('✅ Your OpenAPI definition is valid.'); } catch (err) { console.error(Chalk.red(err)); process.exit(1); } } ) .command( 'broken-links', 'Check for broken links in your Mintlify project.', () => undefined, async () => { const hasMintJson = await checkForMintJson(); if (!hasMintJson) { await checkForDocsJson(); } console.log(Chalk.bold('Checking for broken links...\n')); try { const brokenLinks = await getBrokenInternalLinks(); if (brokenLinks.length === 0) { console.log(Chalk.green('No broken links found.')); return; } const brokenLinksByFile: Record<string, string[]> = {}; brokenLinks.forEach((mdxPath) => { const filename = path.join(mdxPath.relativeDir, mdxPath.filename); const brokenLinksForFile = brokenLinksByFile[filename]; if (brokenLinksForFile) { brokenLinksForFile.push(mdxPath.originalPath); } else { brokenLinksByFile[filename] = [mdxPath.originalPath]; } }); Object.entries(brokenLinksByFile).forEach(([fileName, brokenLinks]) => { console.group(`${Chalk.underline(fileName)}`); console.log(brokenLinks.join('\n'), '\n'); console.groupEnd(); }); console.error(Chalk.yellow(`${brokenLinks.length} broken links found.`)); process.exit(1); } catch (err) { console.error(Chalk.red(err)); process.exit(1); } } ) .command( 'rename <from> <to>', 'Rename file in a Mintlify project and update the internal link references.', (yargs) => yargs .positional('from', { describe: 'The file to rename', type: 'string', }) .positional('to', { describe: 'The new name for the file', type: 'string', }) .demandOption(['from', 'to']) .epilog('Example: `mintlify rename introduction.mdx overview.mdx`'), async ({ from, to }) => { const hasMintJson = await checkForMintJson(); if (!hasMintJson) { await checkForDocsJson(); } await renameFilesAndUpdateLinksInContent(from, to); } ) .command( 'upgrade', 'Upgrade the mint.json file to v2 (docs.json)', () => undefined, async () => { const hasMintJson = await checkForMintJson(); if (!hasMintJson) { await checkForDocsJson(); } await upgradeConfig(); } ) // Print the help menu when the user enters an invalid command. .strictCommands() .demandCommand(1, 'Unknown command. See above for the list of supported commands.') // Alias option flags --help = -h, --version = -v .alias('h', 'help') .alias('v', 'version') .parse();