hono-openapi 1.1.0 → 1.1.2
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/dist/index.cjs +50 -40
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +50 -40
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -75,6 +75,8 @@ function mergeSpecs(route, ...specs) {
|
|
|
75
75
|
const values = [...prev[key] ?? [], ...value];
|
|
76
76
|
if (key === "tags") {
|
|
77
77
|
prev[key] = Array.from(new Set(values));
|
|
78
|
+
} else if (key === "parameters") {
|
|
79
|
+
prev[key] = mergeParameters(values);
|
|
78
80
|
} else {
|
|
79
81
|
prev[key] = values;
|
|
80
82
|
}
|
|
@@ -136,57 +138,65 @@ function removeExcludedPaths(paths, ctx) {
|
|
|
136
138
|
const newPaths = {};
|
|
137
139
|
const _exclude = Array.isArray(exclude) ? exclude : [exclude];
|
|
138
140
|
for (const [key, value] of Object.entries(paths)) {
|
|
139
|
-
|
|
141
|
+
if (value == null) continue;
|
|
142
|
+
const isExplicitlyExcluded = _exclude.some((x) => {
|
|
140
143
|
if (typeof x === "string") return key === x;
|
|
141
144
|
return x.test(key);
|
|
142
145
|
});
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
+
schema.parameters = 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;
|
|
166
176
|
}
|
|
167
|
-
return false;
|
|
168
177
|
}
|
|
169
|
-
return
|
|
178
|
+
return false;
|
|
170
179
|
}
|
|
171
|
-
|
|
172
|
-
if (index === -1) {
|
|
173
|
-
schema.parameters.push({
|
|
174
|
-
schema: { type: "string" },
|
|
175
|
-
in: "path",
|
|
176
|
-
name: paramName,
|
|
177
|
-
required: true
|
|
178
|
-
});
|
|
180
|
+
return x.in === "path" && x.name === paramName;
|
|
179
181
|
}
|
|
182
|
+
);
|
|
183
|
+
if (index === -1) {
|
|
184
|
+
schema.parameters.push({
|
|
185
|
+
schema: { type: "string" },
|
|
186
|
+
in: "path",
|
|
187
|
+
name: paramName,
|
|
188
|
+
required: true
|
|
189
|
+
});
|
|
180
190
|
}
|
|
181
191
|
}
|
|
182
|
-
if (!schema.responses) {
|
|
183
|
-
schema.responses = {
|
|
184
|
-
200: {}
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
192
|
}
|
|
188
|
-
|
|
193
|
+
if (!schema.responses) {
|
|
194
|
+
schema.responses = {
|
|
195
|
+
200: {}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
189
198
|
}
|
|
199
|
+
newPaths[key] = value;
|
|
190
200
|
}
|
|
191
201
|
return newPaths;
|
|
192
202
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -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
|
|
|
@@ -165,7 +165,7 @@ type GenerateSpecOptions = {
|
|
|
165
165
|
*/
|
|
166
166
|
includeEmptyPaths: boolean;
|
|
167
167
|
/**
|
|
168
|
-
* 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).
|
|
169
169
|
*
|
|
170
170
|
* @default true
|
|
171
171
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -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
|
|
|
@@ -165,7 +165,7 @@ type GenerateSpecOptions = {
|
|
|
165
165
|
*/
|
|
166
166
|
includeEmptyPaths: boolean;
|
|
167
167
|
/**
|
|
168
|
-
* 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).
|
|
169
169
|
*
|
|
170
170
|
* @default true
|
|
171
171
|
*/
|
package/dist/index.js
CHANGED
|
@@ -73,6 +73,8 @@ function mergeSpecs(route, ...specs) {
|
|
|
73
73
|
const values = [...prev[key] ?? [], ...value];
|
|
74
74
|
if (key === "tags") {
|
|
75
75
|
prev[key] = Array.from(new Set(values));
|
|
76
|
+
} else if (key === "parameters") {
|
|
77
|
+
prev[key] = mergeParameters(values);
|
|
76
78
|
} else {
|
|
77
79
|
prev[key] = values;
|
|
78
80
|
}
|
|
@@ -134,57 +136,65 @@ function removeExcludedPaths(paths, ctx) {
|
|
|
134
136
|
const newPaths = {};
|
|
135
137
|
const _exclude = Array.isArray(exclude) ? exclude : [exclude];
|
|
136
138
|
for (const [key, value] of Object.entries(paths)) {
|
|
137
|
-
|
|
139
|
+
if (value == null) continue;
|
|
140
|
+
const isExplicitlyExcluded = _exclude.some((x) => {
|
|
138
141
|
if (typeof x === "string") return key === x;
|
|
139
142
|
return x.test(key);
|
|
140
143
|
});
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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
|
+
schema.parameters = 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;
|
|
164
174
|
}
|
|
165
|
-
return false;
|
|
166
175
|
}
|
|
167
|
-
return
|
|
176
|
+
return false;
|
|
168
177
|
}
|
|
169
|
-
|
|
170
|
-
if (index === -1) {
|
|
171
|
-
schema.parameters.push({
|
|
172
|
-
schema: { type: "string" },
|
|
173
|
-
in: "path",
|
|
174
|
-
name: paramName,
|
|
175
|
-
required: true
|
|
176
|
-
});
|
|
178
|
+
return x.in === "path" && x.name === paramName;
|
|
177
179
|
}
|
|
180
|
+
);
|
|
181
|
+
if (index === -1) {
|
|
182
|
+
schema.parameters.push({
|
|
183
|
+
schema: { type: "string" },
|
|
184
|
+
in: "path",
|
|
185
|
+
name: paramName,
|
|
186
|
+
required: true
|
|
187
|
+
});
|
|
178
188
|
}
|
|
179
189
|
}
|
|
180
|
-
if (!schema.responses) {
|
|
181
|
-
schema.responses = {
|
|
182
|
-
200: {}
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
190
|
}
|
|
186
|
-
|
|
191
|
+
if (!schema.responses) {
|
|
192
|
+
schema.responses = {
|
|
193
|
+
200: {}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
187
196
|
}
|
|
197
|
+
newPaths[key] = value;
|
|
188
198
|
}
|
|
189
199
|
return newPaths;
|
|
190
200
|
}
|
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.1.
|
|
4
|
+
"version": "1.1.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
7
7
|
"module": "dist/index.js",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
|
-
"@hono/standard-validator": "^0.
|
|
44
|
+
"@hono/standard-validator": "^0.2.0",
|
|
45
45
|
"@standard-community/standard-json": "^0.3.5",
|
|
46
|
-
"@standard-community/standard-openapi": "^0.2.
|
|
46
|
+
"@standard-community/standard-openapi": "^0.2.9",
|
|
47
47
|
"@types/json-schema": "^7.0.15",
|
|
48
48
|
"hono": "^4.8.3",
|
|
49
49
|
"openapi-types": "^12.1.3"
|