From 03e50ec59f5c28b31df8d9f0256b77076487f939 Mon Sep 17 00:00:00 2001 From: 3y3 <3y3@ya.ru> Date: Thu, 2 Jan 2025 09:04:38 +0300 Subject: [PATCH] feat: Implement `includer` export compatible with next cli --- src/includer/index.ts | 88 ++++++++++++++++++++++++++---------------- src/includer/models.ts | 8 +++- src/includer/utils.ts | 34 +++++++++++++++- 3 files changed, 95 insertions(+), 35 deletions(-) diff --git a/src/includer/index.ts b/src/includer/index.ts index 76cceb4..1fad2f5 100644 --- a/src/includer/index.ts +++ b/src/includer/index.ts @@ -5,7 +5,7 @@ import {readFileSync} from 'fs'; import {dump} from 'js-yaml'; import SwaggerParser from '@apidevtools/swagger-parser'; -import {matchFilter} from './utils'; +import {filterUsefullContent, matchFilter} from './utils'; import parsers from './parsers'; import generators from './ui'; import {RefsService} from './services/refs'; @@ -21,6 +21,7 @@ import { OpenAPISpec, OpenApiIncluderParams, OpenJSONSchema, + Run, V3Endpoint, V3Info, YfmPreset, @@ -46,6 +47,59 @@ export type Context = { refs: RefsService; }; +export async function includer(run: Run, params: OpenApiIncluderParams, tocPath: string) { + const {input, leadingPage = {}, filter, noindex, hidden, sandbox, tags = {}} = params; + + const ctx: Context = { + tag(id: string) { + return tags[id]; + }, + refs: new RefsService(), + }; + const vars = await run.vars.load(tocPath); + + const contentPath = join(run.input, input); + + const parser = new SwaggerParser(); + + try { + const data = (await parser.validate(contentPath, {validate: {spec: true}})) as OpenAPISpec; + + for (const file of Object.values(parser.$refs.values())) { + const schemas = Object.entries(file.components?.schemas || {}).concat( + Object.entries(file), + ); + for (const [refName, schema] of schemas) { + ctx.refs.add(refName, schema as OpenJSONSchema); + } + } + + const toc = await generateToc({data, leadingPage, filter, vars}, ctx); + const files = await generateContent( + { + data, + leadingPage, + contentPath, + filter, + noindex, + vars, + hidden, + sandbox, + }, + ctx, + ); + + return {toc, files}; + } catch (error) { + if (error && !(error instanceof OpenApiIncluderError)) { + // eslint-disable-next-line no-ex-assign + error = new OpenApiIncluderError(error.toString(), tocPath); + } + + throw error; + } +} + async function includerFunction(params: IncluderFunctionParams) { const { readBasePath, @@ -333,38 +387,6 @@ function handleEndpointRender(endpoint: V3Endpoint, pathPrefix?: string): YfmToc } as YfmToc; } -function filterUsefullContent( - filter: OpenApiIncluderParams['filter'] | undefined, - vars: YfmPreset, -) { - if (!filter) { - return (spec: Specification) => spec; - } - - return (spec: Specification): Specification => { - const endpointsByTag = new Map(); - const tags = new Map(); - - matchFilter(filter, vars, (endpoint, tag) => { - const tagId = tag?.id ?? null; - const collection = endpointsByTag.get(tagId) || []; - - collection.push(endpoint); - endpointsByTag.set(tagId, collection); - - if (tagId !== null) { - tags.set(tagId, {...tag, endpoints: collection}); - } - })(spec); - - return { - ...spec, - tags, - endpoints: endpointsByTag.get(null) || [], - }; - }; -} - export function sectionName(e: V3Endpoint): string { return e.summary ?? e.operationId ?? `${e.method} ${e.path}`; } diff --git a/src/includer/models.ts b/src/includer/models.ts index eddad31..74ab8bb 100644 --- a/src/includer/models.ts +++ b/src/includer/models.ts @@ -294,7 +294,6 @@ export type CustomTag = { }; export type OpenApiIncluderParams = { - allowAnonymousObjects?: boolean; input: string; leadingPage?: LeadingPageParams; filter?: OpenApiFilter; @@ -335,3 +334,10 @@ export type JSONSchemaUnionType = { unionOf: JSONSchemaType[]; }; export type JSONSchemaType = BaseJSONSchemaType | JSONSchemaUnionType | FoundRefType; + +export type Run = { + input: string; + vars: { + load(path: string): Promise; + }; +}; diff --git a/src/includer/utils.ts b/src/includer/utils.ts index 3406858..1b556c2 100644 --- a/src/includer/utils.ts +++ b/src/includer/utils.ts @@ -1,6 +1,6 @@ import {evalExp} from '@diplodoc/transform/lib/liquid/evaluation'; -import {OpenApiIncluderParams, Specification, V3Endpoint, V3Tag} from './models'; +import {OpenApiIncluderParams, Specification, V3Endpoint, V3Tag, YfmPreset} from './models'; export function concatNewLine(prefix: string, suffix: string) { return prefix.trim().length ? `${prefix}
${suffix}` : suffix; @@ -46,3 +46,35 @@ export function matchFilter( } }; } + +export function filterUsefullContent( + filter: OpenApiIncluderParams['filter'] | undefined, + vars: YfmPreset, +) { + if (!filter) { + return (spec: Specification) => spec; + } + + return (spec: Specification): Specification => { + const endpointsByTag = new Map(); + const tags = new Map(); + + matchFilter(filter, vars, (endpoint, tag) => { + const tagId = tag?.id ?? null; + const collection = endpointsByTag.get(tagId) || []; + + collection.push(endpoint); + endpointsByTag.set(tagId, collection); + + if (tagId !== null) { + tags.set(tagId, {...tag, endpoints: collection}); + } + })(spec); + + return { + ...spec, + tags, + endpoints: endpointsByTag.get(null) || [], + }; + }; +}