@mintlify/cli
Version:
The Mintlify CLI
182 lines (181 loc) • 8.9 kB
JavaScript
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, } from '@mintlify/previewing';
import { render, Text } from 'ink';
import path from 'path';
import semver from 'semver';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import { LOCAL_LINKED_VERSION, MINIMUM_CLI_VERSION } from './constants.js';
import { checkPort, checkForMintJson, checkNodeVersion, upgradeConfig, checkForDocsJson, getCliVersion, getVersions, suppressConsoleWarnings, terminate, readLocalOpenApiFile, } from './helpers.js';
import { update } from './update.js';
export const cli = () => {
render(_jsx(Logs, {}));
return (yargs(hideBin(process.argv))
.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',
})
.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* () {
var _a, _b;
const port = yield checkPort(argv);
const packageName = (_b = (_a = process.argv[1]) === null || _a === void 0 ? void 0 : _a.split('/').pop()) !== null && _b !== void 0 ? _b : 'mintlify';
const cliVersion = getCliVersion();
if (cliVersion &&
cliVersion !== LOCAL_LINKED_VERSION &&
semver.lt(cliVersion, MINIMUM_CLI_VERSION)) {
yield update({ packageName, silent: true });
}
if (port != undefined) {
yield dev(Object.assign(Object.assign({}, argv), { port,
packageName, cliVersion: cli }));
}
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);
}
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) {
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(0);
}))
.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* () {
var _a, _b;
const packageName = (_b = (_a = process.argv[1]) === null || _a === void 0 ? void 0 : _a.split('/').pop()) !== null && _b !== void 0 ? _b : 'mintlify';
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(['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] }));
}))
// 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());
};