Skip to content

Commit

Permalink
🧹 chore: merge main
Browse files Browse the repository at this point in the history
  • Loading branch information
SaltyAom committed Jul 15, 2024
2 parents ebf0e54 + 65bae78 commit 8e928ac
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 96 deletions.
150 changes: 75 additions & 75 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,118 +1,118 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { Elysia, type InternalRoute } from "elysia";
import { Elysia, type InternalRoute } from 'elysia'

import { SwaggerUIRender } from "./swagger";
import { ScalarRender } from "./scalar";
import { SwaggerUIRender } from './swagger'
import { ScalarRender } from './scalar'

import { filterPaths, registerSchemaPath } from "./utils";
import { filterPaths, registerSchemaPath } from './utils'

import type { OpenAPIV3 } from "openapi-types";
import type { ReferenceConfiguration } from "./scalar/types";
import type { ElysiaSwaggerConfig } from "./types";
import type { OpenAPIV3 } from 'openapi-types'
import type { ReferenceConfiguration } from './scalar/types'
import type { ElysiaSwaggerConfig } from './types'

/**
* Plugin for [elysia](https://github.com/elysiajs/elysia) that auto-generate Swagger page.
*
* @see https://github.com/elysiajs/elysia-swagger
*/
export const swagger = async <Path extends string = "/swagger">(
export const swagger = async <Path extends string = '/swagger'>(
{
provider = "scalar",
scalarVersion = "latest",
scalarCDN = "",
provider = 'scalar',
scalarVersion = 'latest',
scalarCDN = '',
scalarConfig = {},
documentation = {},
version = "5.9.0",
version = '5.9.0',
excludeStaticFile = true,
path = "/swagger" as Path,
path = '/swagger' as Path,
exclude = [],
swaggerOptions = {},
theme = `https://unpkg.com/swagger-ui-dist@${version}/swagger-ui.css`,
autoDarkMode = true,
excludeMethods = ["OPTIONS"],
excludeTags = [],
excludeMethods = ['OPTIONS'],
excludeTags = []
}: ElysiaSwaggerConfig<Path> = {
provider: "scalar",
scalarVersion: "latest",
scalarCDN: "",
provider: 'scalar',
scalarVersion: 'latest',
scalarCDN: '',
scalarConfig: {},
documentation: {},
version: "5.9.0",
version: '5.9.0',
excludeStaticFile: true,
path: "/swagger" as Path,
path: '/swagger' as Path,
exclude: [],
swaggerOptions: {},
autoDarkMode: true,
excludeMethods: ["OPTIONS"],
excludeTags: [],
},
excludeMethods: ['OPTIONS'],
excludeTags: []
}
) => {
const schema = {};
let totalRoutes = 0;
const schema = {}
let totalRoutes = 0

if (!version)
version = `https://unpkg.com/swagger-ui-dist@${version}/swagger-ui.css`;
version = `https://unpkg.com/swagger-ui-dist@${version}/swagger-ui.css`

const info = {
title: "Elysia Documentation",
description: "Development documentation",
version: "0.0.0",
...documentation.info,
};
title: 'Elysia Documentation',
description: 'Development documentation',
version: '0.0.0',
...documentation.info
}

const relativePath = path.startsWith("/") ? path.slice(1) : path;
const relativePath = path.startsWith('/') ? path.slice(1) : path

const app = new Elysia({ name: "@elysiajs/swagger" });
const app = new Elysia({ name: '@elysiajs/swagger' })

app.get(path, function documentation() {
const combinedSwaggerOptions = {
url: `${relativePath}/json`,
dom_id: "#swagger-ui",
...swaggerOptions,
};
dom_id: '#swagger-ui',
...swaggerOptions
}

const stringifiedSwaggerOptions = JSON.stringify(
combinedSwaggerOptions,
(key, value) => {
if (typeof value == "function") return undefined;
if (typeof value == 'function') return undefined

return value;
},
);
return value
}
)

const scalarConfiguration: ReferenceConfiguration = {
spec: {
...scalarConfig.spec,
url: `${relativePath}/json`,
url: `${relativePath}/json`
},
...scalarConfig,
};
...scalarConfig
}

return new Response(
provider === "swagger-ui"
provider === 'swagger-ui'
? SwaggerUIRender(
info,
version,
theme,
stringifiedSwaggerOptions,
autoDarkMode,
autoDarkMode
)
: ScalarRender(scalarVersion, scalarConfiguration, scalarCDN),
{
headers: {
"content-type": "text/html; charset=utf8",
},
},
);
}).get(path === "/" ? "/json" : `${path}/json`, function openAPISchema() {
'content-type': 'text/html; charset=utf8'
}
}
)
}).get(path === '/' ? '/json' : `${path}/json`, function openAPISchema() {
// @ts-expect-error Private property
const routes = app.getGlobalRoutes() as InternalRoute[];
const routes = app.getGlobalRoutes() as InternalRoute[]

if (routes.length !== totalRoutes) {
totalRoutes = routes.length;
totalRoutes = routes.length

routes.forEach((route: InternalRoute) => {
if (excludeMethods.includes(route.method)) return;
if (excludeMethods.includes(route.method)) return

registerSchemaPath({
schema,
Expand All @@ -121,45 +121,45 @@ export const swagger = async <Path extends string = "/swagger">(
path: route.path,
// @ts-ignore
models: app.definitions?.type,
contentType: route.hooks.type,
});
});
contentType: route.hooks.type
})
})
}

return {
openapi: "3.0.3",
openapi: '3.0.3',
...{
...documentation,
tags: documentation.tags?.filter(
(tag) => !excludeTags?.includes(tag?.name),
(tag) => !excludeTags?.includes(tag?.name)
),
info: {
title: "Elysia Documentation",
description: "Development documentation",
version: "0.0.0",
...documentation.info,
},
title: 'Elysia Documentation',
description: 'Development documentation',
version: '0.0.0',
...documentation.info
}
},
paths: {
...filterPaths(schema, {
...filterPaths(schema, relativePath, {
excludeStaticFile,
exclude: Array.isArray(exclude) ? exclude : [exclude],
exclude: Array.isArray(exclude) ? exclude : [exclude]
}),
...documentation.paths,
...documentation.paths
},
components: {
...documentation.components,
schemas: {
// @ts-ignore
...app.definitions?.type,
...documentation.components?.schemas,
},
},
} satisfies OpenAPIV3.Document;
});
...documentation.components?.schemas
}
}
} satisfies OpenAPIV3.Document
})

// This is intentional to prevent deeply nested type
return app;
};
return app
}

export default swagger;
export type { ElysiaSwaggerConfig }
export default swagger
49 changes: 28 additions & 21 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable @typescript-eslint/no-unused-vars */
import path from 'path'
import type { HTTPMethod, LocalHook } from 'elysia'

import { Kind, type TSchema } from '@sinclair/typebox'
Expand Down Expand Up @@ -295,30 +296,36 @@ export const registerSchemaPath = ({
}

export const filterPaths = (
paths: Record<string, any>,
{
excludeStaticFile = true,
exclude = []
}: {
excludeStaticFile: boolean
exclude: (string | RegExp)[]
}
paths: Record<string, any>,
docsPath: string,
{
excludeStaticFile = true,
exclude = []
}: {
excludeStaticFile: boolean
exclude: (string | RegExp)[]
}
) => {
const newPaths: Record<string, any> = {}

for (const [key, value] of Object.entries(paths))
if (
!exclude.some((x) => {
if (typeof x === 'string') return key === x

return x.test(key)
}) &&
!key.includes('/swagger') &&
!key.includes('*') &&
(excludeStaticFile ? !key.includes('.') : true)
) {
Object.keys(value).forEach((method) => {
const schema = value[method]
// exclude docs path and OpenAPI json path
const excludePaths = [`/${docsPath}`, `/${docsPath}/json`].map((p) =>
path.normalize(p)
)

for (const [key, value] of Object.entries(paths))
if (
!exclude.some((x) => {
if (typeof x === 'string') return key === x

return x.test(key)
}) &&
!excludePaths.includes(key) &&
!key.includes('*') &&
(excludeStaticFile ? !key.includes('.') : true)
) {
Object.keys(value).forEach((method) => {
const schema = value[method]

if (key.includes('{')) {
if (!schema.parameters) schema.parameters = []
Expand Down

0 comments on commit 8e928ac

Please sign in to comment.