@hestjs/scalar 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,212 @@
1
+ /**
2
+ * 生成基础 OpenAPI 文档结构
3
+ */
4
+ export function generateBaseOpenApiSpec(config) {
5
+ return {
6
+ openapi: '3.0.0',
7
+ info: {
8
+ title: config.title,
9
+ version: config.version,
10
+ description: config.description || `${config.title} API Documentation`,
11
+ },
12
+ servers: config.servers || [
13
+ {
14
+ url: 'http://localhost:3000',
15
+ description: 'Development server',
16
+ },
17
+ ],
18
+ paths: {},
19
+ components: {
20
+ schemas: {},
21
+ responses: {},
22
+ parameters: {},
23
+ securitySchemes: {},
24
+ },
25
+ };
26
+ }
27
+ /**
28
+ * 从类元数据生成 OpenAPI schema
29
+ */
30
+ export function generateSchemaFromClass(target) {
31
+ const properties = Reflect.getMetadata('api:properties', target) || {};
32
+ const schema = {
33
+ type: 'object',
34
+ properties: {},
35
+ };
36
+ const required = [];
37
+ for (const [propertyKey, metadata] of Object.entries(properties)) {
38
+ const propMetadata = metadata;
39
+ schema.properties[propertyKey] = {
40
+ type: getTypeString(propMetadata.type),
41
+ description: propMetadata.description,
42
+ example: propMetadata.example,
43
+ };
44
+ if (propMetadata.enum) {
45
+ schema.properties[propertyKey].enum = propMetadata.enum;
46
+ }
47
+ if (propMetadata.required) {
48
+ required.push(propertyKey);
49
+ }
50
+ }
51
+ if (required.length > 0) {
52
+ schema.required = required;
53
+ }
54
+ return schema;
55
+ }
56
+ /**
57
+ * 从控制器生成 OpenAPI 路径
58
+ */
59
+ export function generatePathsFromController(controller, basePath = '') {
60
+ const paths = {};
61
+ const controllerTags = Reflect.getMetadata('api:tags', controller) || [];
62
+ // 获取控制器的所有方法
63
+ const prototype = controller.prototype;
64
+ const methodNames = Object.getOwnPropertyNames(prototype).filter(name => name !== 'constructor' && typeof prototype[name] === 'function');
65
+ for (const methodName of methodNames) {
66
+ const routeMetadata = Reflect.getMetadata('route', prototype, methodName);
67
+ if (!routeMetadata)
68
+ continue;
69
+ const { method, path } = routeMetadata;
70
+ const fullPath = `${basePath}${path}`;
71
+ if (!paths[fullPath]) {
72
+ paths[fullPath] = {};
73
+ }
74
+ const operation = generateOperationFromMethod(controller, methodName, controllerTags);
75
+ paths[fullPath][method.toLowerCase()] = operation;
76
+ }
77
+ return paths;
78
+ }
79
+ /**
80
+ * 从方法生成 OpenAPI 操作
81
+ */
82
+ function generateOperationFromMethod(controller, methodName, tags) {
83
+ const prototype = controller.prototype;
84
+ const operation = {
85
+ tags,
86
+ };
87
+ // 获取操作元数据
88
+ const operationMetadata = Reflect.getMetadata('api:operation', prototype, methodName);
89
+ if (operationMetadata) {
90
+ operation.summary = operationMetadata.summary;
91
+ operation.description = operationMetadata.description;
92
+ operation.operationId = operationMetadata.operationId || `${controller.name}_${methodName}`;
93
+ }
94
+ // 获取参数元数据
95
+ const parametersMetadata = Reflect.getMetadata('api:parameters', controller) || {};
96
+ if (parametersMetadata[methodName]) {
97
+ operation.parameters = parametersMetadata[methodName].map((param) => ({
98
+ name: param.name,
99
+ in: param.in,
100
+ description: param.description,
101
+ required: param.required || param.in === 'path',
102
+ schema: {
103
+ type: getTypeString(param.type),
104
+ example: param.example,
105
+ },
106
+ }));
107
+ }
108
+ // 获取请求体元数据
109
+ const bodyMetadata = Reflect.getMetadata('api:body', prototype, methodName);
110
+ if (bodyMetadata) {
111
+ operation.requestBody = {
112
+ description: bodyMetadata.description,
113
+ required: bodyMetadata.required,
114
+ content: {
115
+ 'application/json': {
116
+ schema: bodyMetadata.type ? generateSchemaFromClass(bodyMetadata.type) : {},
117
+ },
118
+ },
119
+ };
120
+ }
121
+ // 获取响应元数据
122
+ const responsesMetadata = Reflect.getMetadata('api:responses', controller) || {};
123
+ if (responsesMetadata[methodName]) {
124
+ operation.responses = {};
125
+ for (const response of responsesMetadata[methodName]) {
126
+ operation.responses[response.status] = {
127
+ description: response.description,
128
+ content: response.type ? {
129
+ 'application/json': {
130
+ schema: response.schema || generateSchemaFromClass(response.type),
131
+ },
132
+ } : undefined,
133
+ };
134
+ }
135
+ }
136
+ else {
137
+ // 默认响应
138
+ operation.responses = {
139
+ 200: {
140
+ description: 'Success',
141
+ },
142
+ };
143
+ }
144
+ return operation;
145
+ }
146
+ /**
147
+ * 获取类型字符串
148
+ */
149
+ function getTypeString(type) {
150
+ if (!type)
151
+ return 'string';
152
+ if (type === String)
153
+ return 'string';
154
+ if (type === Number)
155
+ return 'number';
156
+ if (type === Boolean)
157
+ return 'boolean';
158
+ if (type === Date)
159
+ return 'string';
160
+ if (Array.isArray(type))
161
+ return 'array';
162
+ return 'object';
163
+ }
164
+ /**
165
+ * 合并多个 OpenAPI 文档
166
+ */
167
+ export function mergeOpenApiSpecs(...specs) {
168
+ const merged = {
169
+ openapi: '3.0.0',
170
+ info: {},
171
+ servers: [],
172
+ paths: {},
173
+ components: {
174
+ schemas: {},
175
+ responses: {},
176
+ parameters: {},
177
+ securitySchemes: {},
178
+ },
179
+ };
180
+ for (const spec of specs) {
181
+ const specObj = spec;
182
+ // 合并基本信息(使用第一个非空的)
183
+ if (specObj.info && !merged.info.title) {
184
+ merged.info = { ...specObj.info };
185
+ }
186
+ // 合并服务器
187
+ if (specObj.servers) {
188
+ merged.servers.push(...specObj.servers);
189
+ }
190
+ // 合并路径
191
+ if (specObj.paths) {
192
+ Object.assign(merged.paths, specObj.paths);
193
+ }
194
+ // 合并组件
195
+ if (specObj.components) {
196
+ if (specObj.components.schemas) {
197
+ Object.assign(merged.components.schemas, specObj.components.schemas);
198
+ }
199
+ if (specObj.components.responses) {
200
+ Object.assign(merged.components.responses, specObj.components.responses);
201
+ }
202
+ if (specObj.components.parameters) {
203
+ Object.assign(merged.components.parameters, specObj.components.parameters);
204
+ }
205
+ if (specObj.components.securitySchemes) {
206
+ Object.assign(merged.components.securitySchemes, specObj.components.securitySchemes);
207
+ }
208
+ }
209
+ }
210
+ return merged;
211
+ }
212
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@hestjs/scalar",
3
+ "version": "0.1.0",
4
+ "description": "HestJS Scalar API Reference Integration - Beautiful API documentation for HestJS applications",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "README.md",
10
+ "LICENSE"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "dev": "tsc --watch",
15
+ "clean": "rm -rf dist",
16
+ "check-types": "tsc --noEmit",
17
+ "prepublishOnly": "npm run clean && npm run build",
18
+ "publish:npm": "npm publish --access public"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/aqz236/hest.git"
23
+ },
24
+ "homepage": "https://github.com/aqz236/hest#readme",
25
+ "bugs": {
26
+ "url": "https://github.com/aqz236/hest/issues"
27
+ },
28
+ "author": "aqz236",
29
+ "license": "MIT",
30
+ "dependencies": {
31
+ "@hestjs/core": "0.1.8",
32
+ "@scalar/hono-api-reference": "^0.5.173",
33
+ "@scalar/openapi-to-markdown": "^0.1.2",
34
+ "@scalar/themes": "^0.13.11",
35
+ "hono": "^4.8.9"
36
+ },
37
+ "optionalDependencies": {
38
+ "@scalar/hono-api-reference": "^0.9.12",
39
+ "@scalar/openapi-to-markdown": "^0.2.23",
40
+ "ajv": "^8.17.1"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^24.1.0",
44
+ "typescript": "5.8.3"
45
+ },
46
+ "peerDependencies": {
47
+ "@hestjs/core": ">=0.1.0",
48
+ "hono": ">=4.0.0",
49
+ "typescript": ">=5.0.0"
50
+ },
51
+ "exports": {
52
+ ".": {
53
+ "import": "./dist/index.js",
54
+ "require": "./dist/index.js",
55
+ "types": "./dist/index.d.ts"
56
+ }
57
+ },
58
+ "keywords": [
59
+ "hestjs",
60
+ "scalar",
61
+ "api-reference",
62
+ "openapi",
63
+ "swagger",
64
+ "documentation",
65
+ "hono",
66
+ "typescript"
67
+ ]
68
+ }