UNPKG

@redocly/cli

Version:

[@Redocly](https://redocly.com) CLI is your all-in-one OpenAPI utility. It builds, manages, improves, and quality-checks your OpenAPI descriptions, all of which comes in handy for various phases of the API Lifecycle. Create your own rulesets to make API g

128 lines (127 loc) 5.54 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.previewDocs = previewDocs; exports.debounce = debounce; const colorette = require("colorette"); const chockidar = require("chokidar"); const openapi_core_1 = require("@redocly/openapi-core"); const miscellaneous_1 = require("../../utils/miscellaneous"); const preview_server_1 = require("./preview-server/preview-server"); async function previewDocs({ argv, config: configFromFile, }) { let isAuthorizedWithRedocly = false; let redocOptions = {}; let config = await reloadConfig(configFromFile); const apis = await (0, miscellaneous_1.getFallbackApisOrExit)(argv.api ? [argv.api] : [], config); const api = apis[0]; let cachedBundle; const deps = new Set(); async function getBundle() { return cachedBundle; } async function updateBundle() { process.stdout.write('\nBundling...\n\n'); try { const { bundle: openapiBundle, problems, fileDependencies, } = await (0, openapi_core_1.bundle)({ ref: api.path, config, }); const removed = [...deps].filter((x) => !fileDependencies.has(x)); watcher.unwatch(removed); watcher.add([...fileDependencies]); deps.clear(); fileDependencies.forEach(deps.add, deps); const fileTotals = (0, openapi_core_1.getTotals)(problems); if (fileTotals.errors === 0) { process.stdout.write(fileTotals.errors === 0 ? `Created a bundle for ${api.alias || api.path} ${fileTotals.warnings > 0 ? 'with warnings' : 'successfully'}\n` : colorette.yellow(`Created a bundle for ${api.alias || api.path} with errors. Docs may be broken or not accurate\n`)); } return openapiBundle.parsed; } catch (e) { (0, miscellaneous_1.handleError)(e, api.path); } } setImmediate(() => { cachedBundle = updateBundle(); }); // initial cache const isAuthorized = isAuthorizedWithRedocly || redocOptions.licenseKey; if (!isAuthorized) { process.stderr.write(`Using Redoc community edition.\nLogin with redocly ${colorette.blue('login')} or use an enterprise license key to preview with the premium docs.\n\n`); } const hotClients = await (0, preview_server_1.default)(argv.port, argv.host, { getBundle, getOptions: () => redocOptions, useRedocPro: isAuthorized && !redocOptions.useCommunityEdition, }); const watchPaths = [api.path, config.configFile].filter((e) => !!e); const watcher = chockidar.watch(watchPaths, { disableGlobbing: true, ignoreInitial: true, }); const debouncedUpdatedBundle = debounce(async () => { cachedBundle = updateBundle(); await cachedBundle; hotClients.broadcast('{"type": "reload", "bundle": true}'); }, 2000); const changeHandler = async (type, file) => { process.stdout.write(`${colorette.green('watch')} ${type} ${colorette.blue(file)}\n`); if (file === config.configFile) { config = await reloadConfig(); hotClients.broadcast(JSON.stringify({ type: 'reload' })); return; } debouncedUpdatedBundle(); }; watcher.on('change', changeHandler.bind(undefined, 'changed')); watcher.on('add', changeHandler.bind(undefined, 'added')); watcher.on('unlink', changeHandler.bind(undefined, 'removed')); watcher.on('ready', () => { process.stdout.write(`\n 👀 Watching ${colorette.blue(api.path)} and all related resources for changes\n\n`); }); async function reloadConfig(config) { if (!config) { try { config = (await (0, miscellaneous_1.loadConfigAndHandleErrors)({ configPath: argv.config })); } catch (err) { config = new openapi_core_1.Config({ apis: {}, styleguide: {} }); } } const redoclyClient = new openapi_core_1.RedoclyClient(); isAuthorizedWithRedocly = await redoclyClient.isAuthorizedWithRedocly(); const resolvedConfig = (0, openapi_core_1.getMergedConfig)(config, argv.api); const { styleguide } = resolvedConfig; styleguide.skipPreprocessors(argv['skip-preprocessor']); styleguide.skipDecorators(argv['skip-decorator']); const referenceDocs = resolvedConfig.theme?.openapi; redocOptions = { ...referenceDocs, useCommunityEdition: argv['use-community-edition'] || referenceDocs?.useCommunityEdition, licenseKey: process.env.REDOCLY_LICENSE_KEY || referenceDocs?.licenseKey, whiteLabel: true, }; return resolvedConfig; } } // eslint-disable-next-line @typescript-eslint/ban-types function debounce(func, wait, immediate) { let timeout; return function executedFunction(...args) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-this-alias const context = this; const later = () => { timeout = null; if (!immediate) func.apply(context, args); }; const callNow = immediate && !timeout; if (timeout) clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; }