UNPKG

@redocly/portal-plugin-async-api

Version:

Async API plugin for Redocly products

107 lines (91 loc) 3.62 kB
import * as asyncApi from '@asyncapi/parser'; import { AvroSchemaParser } from '@asyncapi/avro-schema-parser'; import path from 'node:path'; import type { AsyncAPIDocumentInterface } from '@asyncapi/parser'; import type { PageStaticData } from '@redocly/realm/dist/shared/types'; import type { Feature } from '@redocly/realm/dist/server/entitlements/entitlements.types'; import type { GetStaticDataFn, PageRouteDetails, ExternalPlugin, } from '@redocly/realm/dist/server/plugins/types'; import type { AsyncApiDocsSettings } from './config'; import { asyncApiDocsConfigSchema } from './config.js'; const ASYNCAPI_TEMPLATE_ID = 'asyncapi-docs'; const ASYNCAPI_SHARED_DATA_PREFIX = 'asyncapi-docs-'; export default function asyncAPIDocsPlugin(): ExternalPlugin { const parser = new asyncApi.Parser(); parser.registerSchemaParser(AvroSchemaParser()); return { id: 'asyncapi', requiredEntitlements: ['asyncapi' as Feature], redoclyConfigSchema: asyncApiDocsConfigSchema as any, loaders: { asyncapi: async (relativePath, { fs, cache, logger }) => { const absolutePath = path.join(fs.cwd, relativePath); const { data: yaml } = await cache.load<any>(relativePath, 'yaml'); if (!yaml.asyncapi) return undefined; const { document, diagnostics } = await asyncApi.fromFile(parser, absolutePath).parse(); diagnostics .filter((d) => d.severity === 0) .forEach(({ message, path }) => logger.error( `Cannot parse AsyncAPI schema: ${message} in '${relativePath}:${path.join('.')}'`, ), ); return document; }, }, processContent: async (actions, context) => { const asyncAPITemplateId = actions.createTemplate( ASYNCAPI_TEMPLATE_ID, '@redocly/portal-plugin-async-api/template.js', ); const config = await context.getConfig(); const globalSettings = (config as { asyncapi: AsyncApiDocsSettings } | undefined)?.asyncapi || {}; for (const record of await context.fs.scan(/(\.ya?ml|\.json)$/)) { if (await context.isPathIgnored(record.relativePath)) continue; const { relativePath } = record; const sharedDataId = `${ASYNCAPI_SHARED_DATA_PREFIX}${relativePath}`; try { const { data: document } = await context.cache.load<AsyncAPIDocumentInterface>( record.realRelativePath, 'asyncapi', ); if (!document) continue; await actions.createSharedData(sharedDataId, document?.json() ?? {}); actions.addRoute({ fsPath: relativePath, templateId: asyncAPITemplateId, getStaticData: buildGetStaticDataFn(globalSettings, context.withPathPrefix), metadata: { type: 'asyncapi', title: document?.json()?.info?.title ?? 'AsyncAPI', description: document?.json()?.info?.description ?? '', ...(document?.json()?.info?.['x-metadata'] ?? {}), }, sharedData: [{ key: 'AsyncApiDefinition', id: sharedDataId }], }); } catch (e) { console.error(e); } } }, }; function buildGetStaticDataFn( settings: AsyncApiDocsSettings, withPathPrefix: (url: string) => string, ): GetStaticDataFn<PageRouteDetails, PageStaticData> { return async function (route, _context) { return { props: { settings: { ...settings, baseUrlPath: withPathPrefix(route.slug), }, }, }; }; } }