diff --git a/example/index2.ts b/example/index2.ts index 19e75b4..35baf4d 100644 --- a/example/index2.ts +++ b/example/index2.ts @@ -3,44 +3,42 @@ import { swagger } from '../src/index' import { plugin } from './plugin' const app = new Elysia({ - // aot: false + // aot: false }) - .use( - swagger({ - documentation: { - info: { - title: 'Elysia', - version: '0.6.10' - }, - tags: [ - { - name: 'Test', - description: 'Hello' - } - ], - security: [ - {JwtAuth: []} - ], - components: { - schemas: { - User: { - description: 'string' - } - }, - securitySchemes: { - JwtAuth: { - type: 'http', - scheme: 'bearer', - bearerFormat: 'JWT', - description: 'Enter JWT Bearer token **_only_**' - } - } - } - }, - swaggerOptions: { - persistAuthorization: true - }, - }) - ) - .use(plugin) - .listen(3000) + .use( + swagger({ + documentation: { + info: { + title: 'Elysia', + version: '0.6.10' + }, + tags: [ + { + name: 'Test', + description: 'Hello' + } + ], + security: [{ JwtAuth: [] }], + components: { + schemas: { + User: { + description: 'string' + } + }, + securitySchemes: { + JwtAuth: { + type: 'http', + scheme: 'bearer', + bearerFormat: 'JWT', + description: 'Enter JWT Bearer token **_only_**' + } + } + } + }, + swaggerOptions: { + persistAuthorization: true + } + }) + ) + .use(plugin) + .listen(3000) diff --git a/example/multiple-instancies.ts b/example/multiple-instancies.ts new file mode 100644 index 0000000..3cff972 --- /dev/null +++ b/example/multiple-instancies.ts @@ -0,0 +1,35 @@ +import { Elysia } from 'elysia' +import { swagger } from '../src/index' + +const firstApp = new Elysia({ prefix: '/first' }) + +firstApp + .get('/first-route', () => { + return 'first route!' + }) + .use( + swagger({ + path: '/first-doc', + routes: firstApp.routes + }) + ) + +const secondApp = new Elysia({ prefix: '/second' }) + +secondApp + .get('/second-route', () => { + return 'second route!' + }) + .use( + swagger({ + path: '/second-doc', + routes: secondApp.routes + }) + ) + +const app = new Elysia({ + // aot: false +}) + .use(firstApp) + .use(secondApp) + .listen(3000) diff --git a/src/index.ts b/src/index.ts index 2a1a284..b034d2a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,7 +30,8 @@ export const swagger = async ( theme = `https://unpkg.com/swagger-ui-dist@${version}/swagger-ui.css`, autoDarkMode = true, excludeMethods = ['OPTIONS'], - excludeTags = [] + excludeTags = [], + routes }: ElysiaSwaggerConfig = { provider: 'scalar', scalarVersion: 'latest', @@ -96,8 +97,13 @@ export const swagger = async ( theme, stringifiedSwaggerOptions, autoDarkMode - ) - : ScalarRender(info, scalarVersion, scalarConfiguration, scalarCDN), + ) + : ScalarRender( + info, + scalarVersion, + scalarConfiguration, + scalarCDN + ), { headers: { 'content-type': 'text/html; charset=utf8' @@ -105,18 +111,33 @@ export const swagger = async ( } ) }).get(path === '/' ? '/json' : `${path}/json`, function openAPISchema() { - // @ts-expect-error Private property - const routes = app.getGlobalRoutes() as InternalRoute[] - - if (routes.length !== totalRoutes) { - const ALLOWED_METHODS = ['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS', 'HEAD', 'PATCH', 'TRACE'] - totalRoutes = routes.length - - routes.forEach((route: InternalRoute) => { + const allRoutes = routes + ? [...routes, ...app.routes] + : // @ts-expect-error Private property + (app.getGlobalRoutes() as InternalRoute[]) + + if (allRoutes.length !== totalRoutes) { + const ALLOWED_METHODS = [ + 'GET', + 'PUT', + 'POST', + 'DELETE', + 'OPTIONS', + 'HEAD', + 'PATCH', + 'TRACE' + ] + totalRoutes = allRoutes.length + + allRoutes.forEach((route: InternalRoute) => { if (route.hooks?.detail?.hide === true) return // TODO: route.hooks?.detail?.hide !== false add ability to hide: false to prevent excluding if (excludeMethods.includes(route.method)) return - if (ALLOWED_METHODS.includes(route.method) === false && route.method !== 'ALL') return + if ( + ALLOWED_METHODS.includes(route.method) === false && + route.method !== 'ALL' + ) + return if (route.method === 'ALL') { ALLOWED_METHODS.forEach((method) => { diff --git a/src/types.ts b/src/types.ts index 5370e38..adf20f8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,119 +1,127 @@ import type { OpenAPIV3 } from 'openapi-types' import type { ReferenceConfiguration } from '@scalar/types' import type { SwaggerUIOptions } from './swagger/types' +import type { InternalRoute } from 'elysia' export interface ElysiaSwaggerConfig { - /** - * Customize Swagger config, refers to Swagger 2.0 config - * - * @see https://swagger.io/specification/v2/ - */ - documentation?: Omit< - Partial, - | 'x-express-openapi-additional-middleware' - | 'x-express-openapi-validation-strict' - > - /** - * Choose your provider, Scalar or Swagger UI - * - * @default 'scalar' - * @see https://github.com/scalar/scalar - * @see https://github.com/swagger-api/swagger-ui - */ - provider?: 'scalar' | 'swagger-ui' - /** - * Version to use for Scalar cdn bundle - * - * @default 'latest' - * @see https://github.com/scalar/scalar - */ - scalarVersion?: string - /** - * Optional override to specifying the path for the Scalar bundle - * - * Custom URL or path to locally hosted Scalar bundle - * - * Lease blank to use default jsdeliver.net CDN - * - * @default '' - * @example 'https://unpkg.com/@scalar/api-reference@1.13.10/dist/browser/standalone.js' - * @example '/public/standalone.js' - * @see https://github.com/scalar/scalar - */ - scalarCDN?: string - /** - * Scalar configuration to customize scalar - *' - * @see https://github.com/scalar/scalar/blob/main/documentation/configuration.md - */ - scalarConfig?: ReferenceConfiguration - /** - * Version to use for swagger cdn bundle - * - * @see unpkg.com/swagger-ui-dist - * - * @default 4.18.2 - */ - version?: string - /** - * Determine if Swagger should exclude static files. - * - * @default true - */ - excludeStaticFile?: boolean - /** - * The endpoint to expose Swagger - * - * @default '/swagger' - */ - path?: Path - /** - * Paths to exclude from Swagger endpoint - * - * @default [] - */ - exclude?: string | RegExp | (string | RegExp)[] - /** - * Options to send to SwaggerUIBundle - * Currently, options that are defined as functions such as requestInterceptor - * and onComplete are not supported. - */ - swaggerOptions?: Omit< - Partial, - | 'dom_id' - | 'dom_node' - | 'spec' - | 'url' - | 'urls' - | 'layout' - | 'pluginsOptions' - | 'plugins' - | 'presets' - | 'onComplete' - | 'requestInterceptor' - | 'responseInterceptor' - | 'modelPropertyMacro' - | 'parameterMacro' - > - /** - * Custom Swagger CSS - */ - theme?: string | { - light: string - dark: string - } - /** - * Using poor man dark mode 😭 - */ - autoDarkMode?: boolean + /** + * Customize Swagger config, refers to Swagger 2.0 config + * + * @see https://swagger.io/specification/v2/ + */ + documentation?: Omit< + Partial, + | 'x-express-openapi-additional-middleware' + | 'x-express-openapi-validation-strict' + > + /** + * Choose your provider, Scalar or Swagger UI + * + * @default 'scalar' + * @see https://github.com/scalar/scalar + * @see https://github.com/swagger-api/swagger-ui + */ + provider?: 'scalar' | 'swagger-ui' + /** + * Version to use for Scalar cdn bundle + * + * @default 'latest' + * @see https://github.com/scalar/scalar + */ + scalarVersion?: string + /** + * Optional override to specifying the path for the Scalar bundle + * + * Custom URL or path to locally hosted Scalar bundle + * + * Lease blank to use default jsdeliver.net CDN + * + * @default '' + * @example 'https://unpkg.com/@scalar/api-reference@1.13.10/dist/browser/standalone.js' + * @example '/public/standalone.js' + * @see https://github.com/scalar/scalar + */ + scalarCDN?: string + /** + * Scalar configuration to customize scalar + *' + * @see https://github.com/scalar/scalar/blob/main/documentation/configuration.md + */ + scalarConfig?: ReferenceConfiguration + /** + * Version to use for swagger cdn bundle + * + * @see unpkg.com/swagger-ui-dist + * + * @default 4.18.2 + */ + version?: string + /** + * Determine if Swagger should exclude static files. + * + * @default true + */ + excludeStaticFile?: boolean + /** + * The endpoint to expose Swagger + * + * @default '/swagger' + */ + path?: Path + /** + * Paths to exclude from Swagger endpoint + * + * @default [] + */ + exclude?: string | RegExp | (string | RegExp)[] + /** + * Options to send to SwaggerUIBundle + * Currently, options that are defined as functions such as requestInterceptor + * and onComplete are not supported. + */ + swaggerOptions?: Omit< + Partial, + | 'dom_id' + | 'dom_node' + | 'spec' + | 'url' + | 'urls' + | 'layout' + | 'pluginsOptions' + | 'plugins' + | 'presets' + | 'onComplete' + | 'requestInterceptor' + | 'responseInterceptor' + | 'modelPropertyMacro' + | 'parameterMacro' + > + /** + * Custom Swagger CSS + */ + theme?: + | string + | { + light: string + dark: string + } + /** + * Using poor man dark mode 😭 + */ + autoDarkMode?: boolean - /** - * Exclude methods from Swagger - */ - excludeMethods?: string[] + /** + * Exclude methods from Swagger + */ + excludeMethods?: string[] - /** - * Exclude tags from Swagger or Scalar - */ - excludeTags?: string[] + /** + * Exclude tags from Swagger or Scalar + */ + excludeTags?: string[] + + /** + * specific route context + */ + routes?: InternalRoute[] }