hono-openapi 1.0.8 → 1.1.1
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.
- package/README.md +2 -2
- package/dist/index.cjs +58 -43
- package/dist/index.d.cts +9 -8
- package/dist/index.d.ts +9 -8
- package/dist/index.js +58 -44
- package/package.json +8 -5
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://npmjs.org/package/hono-openapi "View this project on NPM")
|
|
5
5
|
[](https://www.npmjs.com/package/hono-openapi)
|
|
6
6
|
|
|
7
|
-
This can automatically generate the OpenAPI specification for the Hono
|
|
7
|
+
This can automatically generate the OpenAPI specification for the Hono App using your validation schema, which can be used to generate client libraries, documentation, and more.
|
|
8
8
|
|
|
9
9
|
This lib supports all the validation libs which are [Standard Schema](https://standardschema.dev/) compliant.
|
|
10
10
|
|
|
@@ -19,5 +19,5 @@ Visit our [contributing docs](https://github.com/rhinobase/hono-openapi/blob/mai
|
|
|
19
19
|
|
|
20
20
|
## Credits
|
|
21
21
|
|
|
22
|
-
- The idea for this project was inspired by [ElysiaJS](https://elysiajs.com/) and their amazing work on generating [OpenAPI](https://elysiajs.com/
|
|
22
|
+
- The idea for this project was inspired by [ElysiaJS](https://elysiajs.com/) and their amazing work on generating [OpenAPI](https://elysiajs.com/patterns/openapi) specifications.
|
|
23
23
|
- This project would not have been possible without the work of [Sam Chung](https://github.com/samchungy) and his [Zod OpenAPI](https://github.com/samchungy/zod-openapi) package.
|
package/dist/index.cjs
CHANGED
|
@@ -61,6 +61,9 @@ function getPathContext(path) {
|
|
|
61
61
|
}
|
|
62
62
|
return context;
|
|
63
63
|
}
|
|
64
|
+
function clearSpecsContext() {
|
|
65
|
+
specsByPathContext.clear();
|
|
66
|
+
}
|
|
64
67
|
function mergeSpecs(route, ...specs) {
|
|
65
68
|
return specs.reduce(
|
|
66
69
|
(prev, spec) => {
|
|
@@ -72,6 +75,8 @@ function mergeSpecs(route, ...specs) {
|
|
|
72
75
|
const values = [...prev[key] ?? [], ...value];
|
|
73
76
|
if (key === "tags") {
|
|
74
77
|
prev[key] = Array.from(new Set(values));
|
|
78
|
+
} else if (key === "parameters") {
|
|
79
|
+
prev[key] = mergeParameters(values);
|
|
75
80
|
} else {
|
|
76
81
|
prev[key] = values;
|
|
77
82
|
}
|
|
@@ -133,57 +138,65 @@ function removeExcludedPaths(paths, ctx) {
|
|
|
133
138
|
const newPaths = {};
|
|
134
139
|
const _exclude = Array.isArray(exclude) ? exclude : [exclude];
|
|
135
140
|
for (const [key, value] of Object.entries(paths)) {
|
|
136
|
-
|
|
141
|
+
if (value == null) continue;
|
|
142
|
+
const isExplicitlyExcluded = _exclude.some((x) => {
|
|
137
143
|
if (typeof x === "string") return key === x;
|
|
138
144
|
return x.test(key);
|
|
139
145
|
});
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
146
|
+
if (isExplicitlyExcluded) continue;
|
|
147
|
+
const isWildcardWithoutParameters = key.includes("*") && !key.includes("{");
|
|
148
|
+
if (isWildcardWithoutParameters) continue;
|
|
149
|
+
if (excludeStaticFile) {
|
|
150
|
+
const hasPathParameters = key.includes("{");
|
|
151
|
+
const lastSegment = key.split("/").pop() || "";
|
|
152
|
+
const looksLikeStaticFile = lastSegment.includes(".");
|
|
153
|
+
const shouldExcludeAsStaticFile = !hasPathParameters && looksLikeStaticFile;
|
|
154
|
+
if (shouldExcludeAsStaticFile) continue;
|
|
155
|
+
}
|
|
156
|
+
for (const method of Object.keys(value)) {
|
|
157
|
+
const schema = value[method];
|
|
158
|
+
if (schema == null) continue;
|
|
159
|
+
if (key.includes("{")) {
|
|
160
|
+
if (!schema.parameters) schema.parameters = [];
|
|
161
|
+
const pathParameters = key.split("/").filter(
|
|
162
|
+
(x) => x.startsWith("{") && !schema.parameters.find(
|
|
163
|
+
(params) => params.in === "path" && params.name === x.slice(1, x.length - 1)
|
|
164
|
+
)
|
|
165
|
+
);
|
|
166
|
+
for (const param of pathParameters) {
|
|
167
|
+
const paramName = param.slice(1, param.length - 1);
|
|
168
|
+
const index = schema.parameters.findIndex(
|
|
169
|
+
(x) => {
|
|
170
|
+
if ("$ref" in x) {
|
|
171
|
+
const pos = x.$ref.split("/").pop();
|
|
172
|
+
if (pos) {
|
|
173
|
+
const param2 = ctx.components.parameters?.[pos];
|
|
174
|
+
if (param2 && !("$ref" in param2)) {
|
|
175
|
+
return param2.in === "path" && param2.name === paramName;
|
|
163
176
|
}
|
|
164
|
-
return false;
|
|
165
177
|
}
|
|
166
|
-
return
|
|
178
|
+
return false;
|
|
167
179
|
}
|
|
168
|
-
|
|
169
|
-
if (index === -1) {
|
|
170
|
-
schema.parameters.push({
|
|
171
|
-
schema: { type: "string" },
|
|
172
|
-
in: "path",
|
|
173
|
-
name: paramName,
|
|
174
|
-
required: true
|
|
175
|
-
});
|
|
180
|
+
return x.in === "path" && x.name === paramName;
|
|
176
181
|
}
|
|
182
|
+
);
|
|
183
|
+
if (index === -1) {
|
|
184
|
+
schema.parameters.push({
|
|
185
|
+
schema: { type: "string" },
|
|
186
|
+
in: "path",
|
|
187
|
+
name: paramName,
|
|
188
|
+
required: true
|
|
189
|
+
});
|
|
177
190
|
}
|
|
178
191
|
}
|
|
179
|
-
if (!schema.responses) {
|
|
180
|
-
schema.responses = {
|
|
181
|
-
200: {}
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
192
|
}
|
|
185
|
-
|
|
193
|
+
if (!schema.responses) {
|
|
194
|
+
schema.responses = {
|
|
195
|
+
200: {}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
186
198
|
}
|
|
199
|
+
newPaths[key] = value;
|
|
187
200
|
}
|
|
188
201
|
return newPaths;
|
|
189
202
|
}
|
|
@@ -213,6 +226,7 @@ async function generateSpecs(hono, options = DEFAULT_OPTIONS, c) {
|
|
|
213
226
|
}
|
|
214
227
|
};
|
|
215
228
|
const _documentation = ctx.options.documentation ?? {};
|
|
229
|
+
clearSpecsContext();
|
|
216
230
|
const paths = await generatePaths(hono, ctx);
|
|
217
231
|
for (const path in paths) {
|
|
218
232
|
for (const method in paths[path]) {
|
|
@@ -426,12 +440,12 @@ function loadVendor(vendor, fn) {
|
|
|
426
440
|
standardOpenapi.loadVendor(vendor, fn.toOpenAPISchema);
|
|
427
441
|
}
|
|
428
442
|
}
|
|
429
|
-
function resolver(schema,
|
|
443
|
+
function resolver(schema, userDefinedOptions) {
|
|
430
444
|
return {
|
|
431
445
|
vendor: schema["~standard"].vendor,
|
|
432
446
|
validate: schema["~standard"].validate,
|
|
433
|
-
toJSONSchema: () => standardJson.toJsonSchema(schema,
|
|
434
|
-
toOpenAPISchema: () => standardOpenapi.toOpenAPISchema(schema,
|
|
447
|
+
toJSONSchema: (customOptions) => standardJson.toJsonSchema(schema, { ...userDefinedOptions, ...customOptions }),
|
|
448
|
+
toOpenAPISchema: (customOptions) => standardOpenapi.toOpenAPISchema(schema, { ...userDefinedOptions, ...customOptions })
|
|
435
449
|
};
|
|
436
450
|
}
|
|
437
451
|
function validator(target, schema, hook, options) {
|
|
@@ -489,6 +503,7 @@ function describeResponse(handler, responses, options) {
|
|
|
489
503
|
}
|
|
490
504
|
|
|
491
505
|
exports.ALLOWED_METHODS = ALLOWED_METHODS;
|
|
506
|
+
exports.clearSpecsContext = clearSpecsContext;
|
|
492
507
|
exports.describeResponse = describeResponse;
|
|
493
508
|
exports.describeRoute = describeRoute;
|
|
494
509
|
exports.generateSpecs = generateSpecs;
|
package/dist/index.d.cts
CHANGED
|
@@ -74,11 +74,11 @@ declare function loadVendor(vendor: string, fn: {
|
|
|
74
74
|
* @param schema Validation schema
|
|
75
75
|
* @returns Resolver result
|
|
76
76
|
*/
|
|
77
|
-
declare function resolver<Schema extends StandardSchemaV1>(schema: Schema,
|
|
77
|
+
declare function resolver<Schema extends StandardSchemaV1>(schema: Schema, userDefinedOptions?: Record<string, unknown>): {
|
|
78
78
|
vendor: string;
|
|
79
79
|
validate: (value: unknown) => StandardSchemaV1.Result<unknown> | Promise<StandardSchemaV1.Result<unknown>>;
|
|
80
|
-
toJSONSchema: () => JSONSchema7 | Promise<JSONSchema7>;
|
|
81
|
-
toOpenAPISchema: () => Promise<{
|
|
80
|
+
toJSONSchema: (customOptions?: Record<string, unknown>) => JSONSchema7 | Promise<JSONSchema7>;
|
|
81
|
+
toOpenAPISchema: (customOptions?: Record<string, unknown>) => Promise<{
|
|
82
82
|
schema: OpenAPIV3_1.SchemaObject;
|
|
83
83
|
components: OpenAPIV3_1.ComponentsObject | undefined;
|
|
84
84
|
}>;
|
|
@@ -121,9 +121,9 @@ type ResponseObject<T extends Partial<Record<StatusCode, StandardSchemaV1>>> = {
|
|
|
121
121
|
});
|
|
122
122
|
};
|
|
123
123
|
type Num<T> = T extends `${infer N extends number}` ? N : T;
|
|
124
|
-
type HandlerResponse<T extends Partial<Record<StatusCode, StandardSchemaV1>> = Partial<Record<StatusCode, StandardSchemaV1>>> = {
|
|
125
|
-
[K in keyof T]: T[K] extends StandardSchemaV1 ?
|
|
126
|
-
}[keyof T]
|
|
124
|
+
type HandlerResponse<T extends Partial<Record<StatusCode, StandardSchemaV1>> = Partial<Record<StatusCode, StandardSchemaV1>>> = PromiseOr<{
|
|
125
|
+
[K in keyof T]: T[K] extends StandardSchemaV1 ? TypedResponse<StandardSchemaV1.InferOutput<T[K]>, Num<K> extends StatusCode ? Num<K> : never> : never;
|
|
126
|
+
}[keyof T]>;
|
|
127
127
|
type Handler<E extends Env, P extends string, I extends Input, T extends Partial<Record<StatusCode, StandardSchemaV1>> = Partial<Record<StatusCode, StandardSchemaV1>>> = (c: Context<E, P, I>, next: Next) => HandlerResponse<T>;
|
|
128
128
|
declare function describeResponse<E extends Env, P extends string, I extends Input, T extends Partial<Record<StatusCode, StandardSchemaV1>> = Partial<Record<StatusCode, StandardSchemaV1>>>(handler: Handler<E, P, I, T>, responses: ResponseObject<T>, options?: Record<string, unknown>): Handler<E, P, I, T>;
|
|
129
129
|
|
|
@@ -133,6 +133,7 @@ declare function describeResponse<E extends Env, P extends string, I extends Inp
|
|
|
133
133
|
declare const uniqueSymbol: unique symbol;
|
|
134
134
|
declare const ALLOWED_METHODS: readonly ["GET", "PUT", "POST", "DELETE", "OPTIONS", "HEAD", "PATCH", "TRACE"];
|
|
135
135
|
type AllowedMethods = (typeof ALLOWED_METHODS)[number];
|
|
136
|
+
declare function clearSpecsContext(): void;
|
|
136
137
|
declare function registerSchemaPath({ route, specs, paths, }: RegisterSchemaPathOptions): void;
|
|
137
138
|
declare function removeExcludedPaths(paths: OpenAPIV3_1.PathsObject, ctx: SpecContext): OpenAPIV3_1.PathsObject<{}, {}>;
|
|
138
139
|
|
|
@@ -164,7 +165,7 @@ type GenerateSpecOptions = {
|
|
|
164
165
|
*/
|
|
165
166
|
includeEmptyPaths: boolean;
|
|
166
167
|
/**
|
|
167
|
-
* Determine if Swagger should exclude static files.
|
|
168
|
+
* Determine if Swagger should exclude static files (by checking if the last path segment contains a period).
|
|
168
169
|
*
|
|
169
170
|
* @default true
|
|
170
171
|
*/
|
|
@@ -276,4 +277,4 @@ declare function generateSpecs<E extends Env = BlankEnv, P extends string = stri
|
|
|
276
277
|
jsonSchemaDialect?: string;
|
|
277
278
|
}>;
|
|
278
279
|
|
|
279
|
-
export { ALLOWED_METHODS, type AllowedMethods, type DescribeRouteOptions, type GenerateSpecOptions, type HandlerUniqueProperty, type PromiseOr, type RegisterSchemaPathOptions, type ResolverReturnType, type SpecContext, describeResponse, describeRoute, generateSpecs, loadVendor, openAPIRouteHandler, registerSchemaPath, removeExcludedPaths, resolver, uniqueSymbol, validator };
|
|
280
|
+
export { ALLOWED_METHODS, type AllowedMethods, type DescribeRouteOptions, type GenerateSpecOptions, type HandlerUniqueProperty, type PromiseOr, type RegisterSchemaPathOptions, type ResolverReturnType, type SpecContext, clearSpecsContext, describeResponse, describeRoute, generateSpecs, loadVendor, openAPIRouteHandler, registerSchemaPath, removeExcludedPaths, resolver, uniqueSymbol, validator };
|
package/dist/index.d.ts
CHANGED
|
@@ -74,11 +74,11 @@ declare function loadVendor(vendor: string, fn: {
|
|
|
74
74
|
* @param schema Validation schema
|
|
75
75
|
* @returns Resolver result
|
|
76
76
|
*/
|
|
77
|
-
declare function resolver<Schema extends StandardSchemaV1>(schema: Schema,
|
|
77
|
+
declare function resolver<Schema extends StandardSchemaV1>(schema: Schema, userDefinedOptions?: Record<string, unknown>): {
|
|
78
78
|
vendor: string;
|
|
79
79
|
validate: (value: unknown) => StandardSchemaV1.Result<unknown> | Promise<StandardSchemaV1.Result<unknown>>;
|
|
80
|
-
toJSONSchema: () => JSONSchema7 | Promise<JSONSchema7>;
|
|
81
|
-
toOpenAPISchema: () => Promise<{
|
|
80
|
+
toJSONSchema: (customOptions?: Record<string, unknown>) => JSONSchema7 | Promise<JSONSchema7>;
|
|
81
|
+
toOpenAPISchema: (customOptions?: Record<string, unknown>) => Promise<{
|
|
82
82
|
schema: OpenAPIV3_1.SchemaObject;
|
|
83
83
|
components: OpenAPIV3_1.ComponentsObject | undefined;
|
|
84
84
|
}>;
|
|
@@ -121,9 +121,9 @@ type ResponseObject<T extends Partial<Record<StatusCode, StandardSchemaV1>>> = {
|
|
|
121
121
|
});
|
|
122
122
|
};
|
|
123
123
|
type Num<T> = T extends `${infer N extends number}` ? N : T;
|
|
124
|
-
type HandlerResponse<T extends Partial<Record<StatusCode, StandardSchemaV1>> = Partial<Record<StatusCode, StandardSchemaV1>>> = {
|
|
125
|
-
[K in keyof T]: T[K] extends StandardSchemaV1 ?
|
|
126
|
-
}[keyof T]
|
|
124
|
+
type HandlerResponse<T extends Partial<Record<StatusCode, StandardSchemaV1>> = Partial<Record<StatusCode, StandardSchemaV1>>> = PromiseOr<{
|
|
125
|
+
[K in keyof T]: T[K] extends StandardSchemaV1 ? TypedResponse<StandardSchemaV1.InferOutput<T[K]>, Num<K> extends StatusCode ? Num<K> : never> : never;
|
|
126
|
+
}[keyof T]>;
|
|
127
127
|
type Handler<E extends Env, P extends string, I extends Input, T extends Partial<Record<StatusCode, StandardSchemaV1>> = Partial<Record<StatusCode, StandardSchemaV1>>> = (c: Context<E, P, I>, next: Next) => HandlerResponse<T>;
|
|
128
128
|
declare function describeResponse<E extends Env, P extends string, I extends Input, T extends Partial<Record<StatusCode, StandardSchemaV1>> = Partial<Record<StatusCode, StandardSchemaV1>>>(handler: Handler<E, P, I, T>, responses: ResponseObject<T>, options?: Record<string, unknown>): Handler<E, P, I, T>;
|
|
129
129
|
|
|
@@ -133,6 +133,7 @@ declare function describeResponse<E extends Env, P extends string, I extends Inp
|
|
|
133
133
|
declare const uniqueSymbol: unique symbol;
|
|
134
134
|
declare const ALLOWED_METHODS: readonly ["GET", "PUT", "POST", "DELETE", "OPTIONS", "HEAD", "PATCH", "TRACE"];
|
|
135
135
|
type AllowedMethods = (typeof ALLOWED_METHODS)[number];
|
|
136
|
+
declare function clearSpecsContext(): void;
|
|
136
137
|
declare function registerSchemaPath({ route, specs, paths, }: RegisterSchemaPathOptions): void;
|
|
137
138
|
declare function removeExcludedPaths(paths: OpenAPIV3_1.PathsObject, ctx: SpecContext): OpenAPIV3_1.PathsObject<{}, {}>;
|
|
138
139
|
|
|
@@ -164,7 +165,7 @@ type GenerateSpecOptions = {
|
|
|
164
165
|
*/
|
|
165
166
|
includeEmptyPaths: boolean;
|
|
166
167
|
/**
|
|
167
|
-
* Determine if Swagger should exclude static files.
|
|
168
|
+
* Determine if Swagger should exclude static files (by checking if the last path segment contains a period).
|
|
168
169
|
*
|
|
169
170
|
* @default true
|
|
170
171
|
*/
|
|
@@ -276,4 +277,4 @@ declare function generateSpecs<E extends Env = BlankEnv, P extends string = stri
|
|
|
276
277
|
jsonSchemaDialect?: string;
|
|
277
278
|
}>;
|
|
278
279
|
|
|
279
|
-
export { ALLOWED_METHODS, type AllowedMethods, type DescribeRouteOptions, type GenerateSpecOptions, type HandlerUniqueProperty, type PromiseOr, type RegisterSchemaPathOptions, type ResolverReturnType, type SpecContext, describeResponse, describeRoute, generateSpecs, loadVendor, openAPIRouteHandler, registerSchemaPath, removeExcludedPaths, resolver, uniqueSymbol, validator };
|
|
280
|
+
export { ALLOWED_METHODS, type AllowedMethods, type DescribeRouteOptions, type GenerateSpecOptions, type HandlerUniqueProperty, type PromiseOr, type RegisterSchemaPathOptions, type ResolverReturnType, type SpecContext, clearSpecsContext, describeResponse, describeRoute, generateSpecs, loadVendor, openAPIRouteHandler, registerSchemaPath, removeExcludedPaths, resolver, uniqueSymbol, validator };
|
package/dist/index.js
CHANGED
|
@@ -59,6 +59,9 @@ function getPathContext(path) {
|
|
|
59
59
|
}
|
|
60
60
|
return context;
|
|
61
61
|
}
|
|
62
|
+
function clearSpecsContext() {
|
|
63
|
+
specsByPathContext.clear();
|
|
64
|
+
}
|
|
62
65
|
function mergeSpecs(route, ...specs) {
|
|
63
66
|
return specs.reduce(
|
|
64
67
|
(prev, spec) => {
|
|
@@ -70,6 +73,8 @@ function mergeSpecs(route, ...specs) {
|
|
|
70
73
|
const values = [...prev[key] ?? [], ...value];
|
|
71
74
|
if (key === "tags") {
|
|
72
75
|
prev[key] = Array.from(new Set(values));
|
|
76
|
+
} else if (key === "parameters") {
|
|
77
|
+
prev[key] = mergeParameters(values);
|
|
73
78
|
} else {
|
|
74
79
|
prev[key] = values;
|
|
75
80
|
}
|
|
@@ -131,57 +136,65 @@ function removeExcludedPaths(paths, ctx) {
|
|
|
131
136
|
const newPaths = {};
|
|
132
137
|
const _exclude = Array.isArray(exclude) ? exclude : [exclude];
|
|
133
138
|
for (const [key, value] of Object.entries(paths)) {
|
|
134
|
-
|
|
139
|
+
if (value == null) continue;
|
|
140
|
+
const isExplicitlyExcluded = _exclude.some((x) => {
|
|
135
141
|
if (typeof x === "string") return key === x;
|
|
136
142
|
return x.test(key);
|
|
137
143
|
});
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
144
|
+
if (isExplicitlyExcluded) continue;
|
|
145
|
+
const isWildcardWithoutParameters = key.includes("*") && !key.includes("{");
|
|
146
|
+
if (isWildcardWithoutParameters) continue;
|
|
147
|
+
if (excludeStaticFile) {
|
|
148
|
+
const hasPathParameters = key.includes("{");
|
|
149
|
+
const lastSegment = key.split("/").pop() || "";
|
|
150
|
+
const looksLikeStaticFile = lastSegment.includes(".");
|
|
151
|
+
const shouldExcludeAsStaticFile = !hasPathParameters && looksLikeStaticFile;
|
|
152
|
+
if (shouldExcludeAsStaticFile) continue;
|
|
153
|
+
}
|
|
154
|
+
for (const method of Object.keys(value)) {
|
|
155
|
+
const schema = value[method];
|
|
156
|
+
if (schema == null) continue;
|
|
157
|
+
if (key.includes("{")) {
|
|
158
|
+
if (!schema.parameters) schema.parameters = [];
|
|
159
|
+
const pathParameters = key.split("/").filter(
|
|
160
|
+
(x) => x.startsWith("{") && !schema.parameters.find(
|
|
161
|
+
(params) => params.in === "path" && params.name === x.slice(1, x.length - 1)
|
|
162
|
+
)
|
|
163
|
+
);
|
|
164
|
+
for (const param of pathParameters) {
|
|
165
|
+
const paramName = param.slice(1, param.length - 1);
|
|
166
|
+
const index = schema.parameters.findIndex(
|
|
167
|
+
(x) => {
|
|
168
|
+
if ("$ref" in x) {
|
|
169
|
+
const pos = x.$ref.split("/").pop();
|
|
170
|
+
if (pos) {
|
|
171
|
+
const param2 = ctx.components.parameters?.[pos];
|
|
172
|
+
if (param2 && !("$ref" in param2)) {
|
|
173
|
+
return param2.in === "path" && param2.name === paramName;
|
|
161
174
|
}
|
|
162
|
-
return false;
|
|
163
175
|
}
|
|
164
|
-
return
|
|
176
|
+
return false;
|
|
165
177
|
}
|
|
166
|
-
|
|
167
|
-
if (index === -1) {
|
|
168
|
-
schema.parameters.push({
|
|
169
|
-
schema: { type: "string" },
|
|
170
|
-
in: "path",
|
|
171
|
-
name: paramName,
|
|
172
|
-
required: true
|
|
173
|
-
});
|
|
178
|
+
return x.in === "path" && x.name === paramName;
|
|
174
179
|
}
|
|
180
|
+
);
|
|
181
|
+
if (index === -1) {
|
|
182
|
+
schema.parameters.push({
|
|
183
|
+
schema: { type: "string" },
|
|
184
|
+
in: "path",
|
|
185
|
+
name: paramName,
|
|
186
|
+
required: true
|
|
187
|
+
});
|
|
175
188
|
}
|
|
176
189
|
}
|
|
177
|
-
if (!schema.responses) {
|
|
178
|
-
schema.responses = {
|
|
179
|
-
200: {}
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
190
|
}
|
|
183
|
-
|
|
191
|
+
if (!schema.responses) {
|
|
192
|
+
schema.responses = {
|
|
193
|
+
200: {}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
184
196
|
}
|
|
197
|
+
newPaths[key] = value;
|
|
185
198
|
}
|
|
186
199
|
return newPaths;
|
|
187
200
|
}
|
|
@@ -211,6 +224,7 @@ async function generateSpecs(hono, options = DEFAULT_OPTIONS, c) {
|
|
|
211
224
|
}
|
|
212
225
|
};
|
|
213
226
|
const _documentation = ctx.options.documentation ?? {};
|
|
227
|
+
clearSpecsContext();
|
|
214
228
|
const paths = await generatePaths(hono, ctx);
|
|
215
229
|
for (const path in paths) {
|
|
216
230
|
for (const method in paths[path]) {
|
|
@@ -424,12 +438,12 @@ function loadVendor(vendor, fn) {
|
|
|
424
438
|
loadVendor$2(vendor, fn.toOpenAPISchema);
|
|
425
439
|
}
|
|
426
440
|
}
|
|
427
|
-
function resolver(schema,
|
|
441
|
+
function resolver(schema, userDefinedOptions) {
|
|
428
442
|
return {
|
|
429
443
|
vendor: schema["~standard"].vendor,
|
|
430
444
|
validate: schema["~standard"].validate,
|
|
431
|
-
toJSONSchema: () => toJsonSchema(schema,
|
|
432
|
-
toOpenAPISchema: () => toOpenAPISchema(schema,
|
|
445
|
+
toJSONSchema: (customOptions) => toJsonSchema(schema, { ...userDefinedOptions, ...customOptions }),
|
|
446
|
+
toOpenAPISchema: (customOptions) => toOpenAPISchema(schema, { ...userDefinedOptions, ...customOptions })
|
|
433
447
|
};
|
|
434
448
|
}
|
|
435
449
|
function validator(target, schema, hook, options) {
|
|
@@ -486,4 +500,4 @@ function describeResponse(handler, responses, options) {
|
|
|
486
500
|
});
|
|
487
501
|
}
|
|
488
502
|
|
|
489
|
-
export { ALLOWED_METHODS, describeResponse, describeRoute, generateSpecs, loadVendor, openAPIRouteHandler, registerSchemaPath, removeExcludedPaths, resolver, uniqueSymbol, validator };
|
|
503
|
+
export { ALLOWED_METHODS, clearSpecsContext, describeResponse, describeRoute, generateSpecs, loadVendor, openAPIRouteHandler, registerSchemaPath, removeExcludedPaths, resolver, uniqueSymbol, validator };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hono-openapi",
|
|
3
3
|
"description": "OpenAPI schema generator for Hono",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.1.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
7
7
|
"module": "dist/index.js",
|
|
@@ -25,8 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"repository": {
|
|
27
27
|
"type": "git",
|
|
28
|
-
"url": "git+https://github.com/rhinobase/hono-openapi.git"
|
|
29
|
-
"directory": "packages/core"
|
|
28
|
+
"url": "git+https://github.com/rhinobase/hono-openapi.git"
|
|
30
29
|
},
|
|
31
30
|
"bugs": {
|
|
32
31
|
"url": "https://github.com/rhinobase/hono-openapi/issues"
|
|
@@ -43,8 +42,8 @@
|
|
|
43
42
|
},
|
|
44
43
|
"peerDependencies": {
|
|
45
44
|
"@hono/standard-validator": "^0.1.2",
|
|
46
|
-
"@standard-community/standard-json": "^0.3.
|
|
47
|
-
"@standard-community/standard-openapi": "^0.2.
|
|
45
|
+
"@standard-community/standard-json": "^0.3.5",
|
|
46
|
+
"@standard-community/standard-openapi": "^0.2.8",
|
|
48
47
|
"@types/json-schema": "^7.0.15",
|
|
49
48
|
"hono": "^4.8.3",
|
|
50
49
|
"openapi-types": "^12.1.3"
|
|
@@ -66,8 +65,11 @@
|
|
|
66
65
|
"husky": "^9.1.7",
|
|
67
66
|
"is-ci": "^4.1.0",
|
|
68
67
|
"nano-staged": "^0.8.0",
|
|
68
|
+
"pkg-pr-new": "^0.0.60",
|
|
69
69
|
"pkgroll": "^2.13.1",
|
|
70
|
+
"typebox": "^1.0.17",
|
|
70
71
|
"typescript": "^5.8.3",
|
|
72
|
+
"sury": "^10.0.0",
|
|
71
73
|
"valibot": "^1.1.0",
|
|
72
74
|
"vitest": "^3.2.4",
|
|
73
75
|
"zod": "^3.23.8",
|
|
@@ -75,6 +77,7 @@
|
|
|
75
77
|
},
|
|
76
78
|
"scripts": {
|
|
77
79
|
"build": "pkgroll --clean-dist",
|
|
80
|
+
"lint": "biome check .",
|
|
78
81
|
"format": "biome check --write .",
|
|
79
82
|
"test": "vitest"
|
|
80
83
|
}
|