UNPKG

@mintlify/cli

Version:

The Mintlify CLI

230 lines (229 loc) 11.3 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 { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { validate, getOpenApiDocumentFromUrl, isAllowedLocalSchemaUrl } from '@mintlify/common'; import { getBrokenInternalLinks, renameFilesAndUpdateLinksInContent } from '@mintlify/link-rot'; import { addLog, dev, ErrorLog, SpinnerLog, SuccessLog, Logs, clearLogs, BrokenLinksLog, WarningLog, } from '@mintlify/previewing'; import { render, Text } from 'ink'; import path from 'path'; import yargs from 'yargs'; import { hideBin } from 'yargs/helpers'; import { accessibilityCheck } from './accessibilityCheck.js'; import { checkPort, checkForMintJson, checkNodeVersion, upgradeConfig, checkForDocsJson, getVersions, suppressConsoleWarnings, terminate, readLocalOpenApiFile, } from './helpers.js'; import { init } from './init.js'; import { mdxLinter } from './mdxLinter.js'; import { migrateMdx } from './migrateMdx.js'; import { update } from './update.js'; export const cli = ({ packageName = 'mint' }) => { render(_jsx(Logs, {})); return (yargs(hideBin(process.argv)) .scriptName(packageName) .middleware(checkNodeVersion) .middleware(suppressConsoleWarnings) .command('dev', 'initialize a local preview environment', (yargs) => yargs .option('open', { type: 'boolean', default: true, description: 'open a local preview in the browser', }) .option('local-schema', { type: 'boolean', default: false, hidden: true, description: 'use a locally hosted schema file (note: only https protocol is supported in production)', }) .option('client-version', { type: 'string', hidden: true, description: 'the version of the client to use for cli testing', }) .option('groups', { type: 'array', description: 'Mock user groups for local development and testing', example: '--groups admin user', }) .option('disable-openapi', { type: 'boolean', default: false, description: 'Disable OpenAPI file generation', }) .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'), (argv) => __awaiter(void 0, void 0, void 0, function* () { let nodeVersionString = process.version; if (nodeVersionString.charAt(0) === 'v') { nodeVersionString = nodeVersionString.slice(1); } const versionArr = nodeVersionString.split('.'); const majorVersion = parseInt(versionArr[0], 10); const minorVersion = parseInt(versionArr[1], 10); if (majorVersion >= 25) { addLog(_jsx(ErrorLog, { message: "mint dev is not supported on node versions 25+. Please downgrade to an LTS node version." })); yield terminate(1); } if (majorVersion < 20 || (majorVersion === 20 && minorVersion < 17)) { addLog(_jsx(ErrorLog, { message: "mint dev is not supported on node versions below 20.17 Please upgrade to an LTS node version." })); yield terminate(1); } const port = yield checkPort(argv); const { cli: cliVersion } = getVersions(); if (port != undefined) { yield dev(Object.assign(Object.assign({}, argv), { port, packageName, cliVersion })); } else { addLog(_jsx(ErrorLog, { message: "no available port found" })); yield terminate(1); } })) .command('openapi-check <filename>', 'check if an OpenAPI spec is valid', (yargs) => yargs .positional('filename', { 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, }) .option('local-schema', { type: 'boolean', default: false, description: 'use a locally hosted schema file (note: only https protocol is supported in production)', }), (_a) => __awaiter(void 0, [_a], void 0, function* ({ filename, 'local-schema': localSchema }) { try { if (isAllowedLocalSchemaUrl(filename, localSchema)) { yield getOpenApiDocumentFromUrl(filename); addLog(_jsx(SuccessLog, { message: "OpenAPI definition is valid." })); yield terminate(0); } if (filename.startsWith('http://') && !localSchema) { addLog(_jsx(WarningLog, { message: "include the --local-schema flag to check locally hosted OpenAPI files" })); addLog(_jsx(WarningLog, { message: "only https protocol is supported in production" })); yield terminate(0); } const document = yield readLocalOpenApiFile(filename); if (!document) { throw new Error('failed to parse OpenAPI spec: could not parse file correctly, please check for any syntax errors.'); } yield validate(document); addLog(_jsx(SuccessLog, { message: "OpenAPI definition is valid." })); } catch (err) { if (err && typeof err === 'object' && 'code' in err && err.code === 'ENOENT') { addLog(_jsx(ErrorLog, { message: `file not found, please check the path provided: ${filename}` })); } else { addLog(_jsx(ErrorLog, { message: err instanceof Error ? err.message : 'unknown error' })); } yield terminate(1); } yield terminate(0); })) .command('broken-links', 'check for invalid internal links', () => undefined, () => __awaiter(void 0, void 0, void 0, function* () { const hasMintJson = yield checkForMintJson(); if (!hasMintJson) { yield checkForDocsJson(); } addLog(_jsx(SpinnerLog, { message: "checking for broken links..." })); try { const brokenLinks = yield getBrokenInternalLinks(); if (brokenLinks.length === 0) { clearLogs(); addLog(_jsx(SuccessLog, { message: "no broken links found" })); yield terminate(0); } const brokenLinksByFile = {}; 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]; } }); clearLogs(); addLog(_jsx(BrokenLinksLog, { brokenLinksByFile: brokenLinksByFile })); } catch (err) { addLog(_jsx(ErrorLog, { message: err instanceof Error ? err.message : 'unknown error' })); yield terminate(1); } yield terminate(1); })) .command('rename <from> <to>', 'rename a file and update all 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']) .option('force', { type: 'boolean', default: false, description: 'rename files and skip errors', }) .epilog('example: `mintlify rename introduction.mdx overview.mdx`'), (_a) => __awaiter(void 0, [_a], void 0, function* ({ from, to, force }) { const hasMintJson = yield checkForMintJson(); if (!hasMintJson) { yield checkForDocsJson(); } yield renameFilesAndUpdateLinksInContent(from, to, force); yield terminate(0); })) .command('update', 'update the CLI to the latest version', () => undefined, () => __awaiter(void 0, void 0, void 0, function* () { yield update({ packageName }); yield terminate(0); })) .command('upgrade', 'upgrade mint.json file to docs.json (current format)', () => undefined, () => __awaiter(void 0, void 0, void 0, function* () { const hasMintJson = yield checkForMintJson(); if (!hasMintJson) { yield checkForDocsJson(); } yield upgradeConfig(); })) .command('migrate-mdx', 'migrate MDX OpenAPI endpoint pages to x-mint extensions and docs.json', () => undefined, () => __awaiter(void 0, void 0, void 0, function* () { yield migrateMdx(); yield terminate(0); })) .command(['a11y', 'accessibility-check', 'a11y-check', 'accessibility'], 'check for accessibility issues in documentation', () => undefined, () => __awaiter(void 0, void 0, void 0, function* () { const accessibilityCheckTerminateCode = yield accessibilityCheck(); const mdxLinterTerminateCode = yield mdxLinter(); yield terminate(accessibilityCheckTerminateCode || mdxLinterTerminateCode); })) .command(['version', 'v'], 'display the current version of the CLI and client', () => undefined, () => __awaiter(void 0, void 0, void 0, function* () { const { cli, client } = getVersions(); addLog(_jsxs(Text, { children: [_jsx(Text, { bold: true, color: "green", children: "cli version" }), ' ', cli] })); addLog(_jsxs(Text, { children: [_jsx(Text, { bold: true, color: "green", children: "client version" }), ' ', client] })); })) .command('new [directory]', 'Create a new Mintlify documentation site', (yargs) => yargs.positional('directory', { describe: 'The directory to initialize your documentation', type: 'string', default: '.', }), (_a) => __awaiter(void 0, [_a], void 0, function* ({ directory }) { try { yield init(directory); yield terminate(0); } catch (error) { addLog(_jsx(ErrorLog, { message: error instanceof Error ? error.message : 'error occurred' })); yield terminate(1); } })) // 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, default --version = -v .alias('h', 'help') .alias('v', 'version') .parse()); };