hono-openapi 1.3.3 → 1.3.4
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 +62 -3
- package/dist/index.d.cts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +60 -4
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -55,6 +55,9 @@ function mergeParameters(...params) {
|
|
|
55
55
|
}, /* @__PURE__ */ new Map());
|
|
56
56
|
return Array.from(merged.values());
|
|
57
57
|
}
|
|
58
|
+
const specComponents = /* @__PURE__ */ new WeakMap();
|
|
59
|
+
const setSpecComponents = (spec, components) => specComponents.set(spec, components);
|
|
60
|
+
const getSpecComponents = (spec) => spec != null && typeof spec === "object" && specComponents.get(spec) || [];
|
|
58
61
|
const specsByPathContext = /* @__PURE__ */ new Map();
|
|
59
62
|
function getPathContext(path, pathContext) {
|
|
60
63
|
const context = [];
|
|
@@ -84,7 +87,7 @@ function mergeRequestBodies(previous, current) {
|
|
|
84
87
|
};
|
|
85
88
|
}
|
|
86
89
|
function mergeSpecs(route, ...specs) {
|
|
87
|
-
|
|
90
|
+
const merged = specs.reduce(
|
|
88
91
|
(prev, spec) => {
|
|
89
92
|
if (!spec || !prev) return prev;
|
|
90
93
|
for (const [key, value] of Object.entries(spec)) {
|
|
@@ -126,6 +129,8 @@ function mergeSpecs(route, ...specs) {
|
|
|
126
129
|
operationId: generateOperationId(route)
|
|
127
130
|
}
|
|
128
131
|
);
|
|
132
|
+
setSpecComponents(merged, specs.flatMap(getSpecComponents));
|
|
133
|
+
return merged;
|
|
129
134
|
}
|
|
130
135
|
function registerSchemaPath({ route, specs, paths }, pathContext = specsByPathContext) {
|
|
131
136
|
const path = toOpenAPIPath(route.path);
|
|
@@ -240,6 +245,52 @@ function removeExcludedPaths(paths, ctx) {
|
|
|
240
245
|
}
|
|
241
246
|
return newPaths;
|
|
242
247
|
}
|
|
248
|
+
const COMPONENTS_PREFIX = "#/components/";
|
|
249
|
+
const componentKey = (type, name) => `${type}/${name.replaceAll("~", "~0").replaceAll("/", "~1")}`;
|
|
250
|
+
const componentRefs = (value) => {
|
|
251
|
+
if (Array.isArray(value)) {
|
|
252
|
+
return value.flatMap(componentRefs);
|
|
253
|
+
}
|
|
254
|
+
if (value == null || typeof value !== "object") {
|
|
255
|
+
return [];
|
|
256
|
+
}
|
|
257
|
+
return Object.entries(value).flatMap(([key, item]) => {
|
|
258
|
+
if (key !== "$ref" || typeof item !== "string") {
|
|
259
|
+
return componentRefs(item);
|
|
260
|
+
}
|
|
261
|
+
return item.startsWith(COMPONENTS_PREFIX) ? [item.slice(COMPONENTS_PREFIX.length)] : [];
|
|
262
|
+
});
|
|
263
|
+
};
|
|
264
|
+
const reachableRefs = (refs, components, reached) => refs.reduce((seen, ref) => {
|
|
265
|
+
if (seen.has(ref)) {
|
|
266
|
+
return seen;
|
|
267
|
+
}
|
|
268
|
+
const [type, ...name] = ref.split("/");
|
|
269
|
+
const component = components[type]?.[name.join("/").replaceAll("~1", "/").replaceAll("~0", "~")];
|
|
270
|
+
return reachableRefs(componentRefs(component), components, seen.add(ref));
|
|
271
|
+
}, reached);
|
|
272
|
+
function documentedComponents(components, paths, documentation) {
|
|
273
|
+
const contributed = new Set(
|
|
274
|
+
Object.values(paths).flatMap((item) => item == null ? [] : Object.values(item)).flatMap(getSpecComponents).flatMap(
|
|
275
|
+
(operationComponents) => Object.entries(operationComponents).flatMap(
|
|
276
|
+
([type, entries]) => Object.keys(entries ?? {}).map((name) => componentKey(type, name))
|
|
277
|
+
)
|
|
278
|
+
)
|
|
279
|
+
);
|
|
280
|
+
const kept = reachableRefs(
|
|
281
|
+
componentRefs(documentation),
|
|
282
|
+
components,
|
|
283
|
+
contributed
|
|
284
|
+
);
|
|
285
|
+
return Object.fromEntries(
|
|
286
|
+
Object.entries(components).flatMap(([type, entries]) => {
|
|
287
|
+
const remaining = Object.entries(entries ?? {}).filter(
|
|
288
|
+
([name]) => kept.has(componentKey(type, name))
|
|
289
|
+
);
|
|
290
|
+
return remaining.length > 0 ? [[type, Object.fromEntries(remaining)]] : [];
|
|
291
|
+
})
|
|
292
|
+
);
|
|
293
|
+
}
|
|
243
294
|
|
|
244
295
|
const DEFAULT_OPTIONS = {
|
|
245
296
|
documentation: {},
|
|
@@ -309,10 +360,14 @@ async function generateSpecs(hono, options = DEFAULT_OPTIONS, c) {
|
|
|
309
360
|
if (resolvedDocumentation && documentation.components) {
|
|
310
361
|
documentation.components.responses = resolvedDocumentation.responses;
|
|
311
362
|
}
|
|
363
|
+
const documentedPaths = removeExcludedPaths(paths, ctx);
|
|
312
364
|
const components = mergeComponentsObjects(
|
|
313
365
|
documentation.components,
|
|
314
366
|
resolvedDocumentation?.components,
|
|
315
|
-
ctx.components
|
|
367
|
+
documentedComponents(ctx.components, documentedPaths, [
|
|
368
|
+
documentation,
|
|
369
|
+
resolvedDocumentation?.components
|
|
370
|
+
])
|
|
316
371
|
);
|
|
317
372
|
return {
|
|
318
373
|
openapi: "3.1.0",
|
|
@@ -327,7 +382,7 @@ async function generateSpecs(hono, options = DEFAULT_OPTIONS, c) {
|
|
|
327
382
|
...documentation.info
|
|
328
383
|
},
|
|
329
384
|
paths: {
|
|
330
|
-
...
|
|
385
|
+
...documentedPaths,
|
|
331
386
|
...documentation.paths
|
|
332
387
|
},
|
|
333
388
|
components
|
|
@@ -366,6 +421,7 @@ async function generatePaths(hono, ctx) {
|
|
|
366
421
|
ctx.components.parameters
|
|
367
422
|
);
|
|
368
423
|
ctx.components = mergeComponentsObjects(ctx.components, components);
|
|
424
|
+
setSpecComponents(routeSpecs, [components]);
|
|
369
425
|
registerSchemaPath(
|
|
370
426
|
{
|
|
371
427
|
route,
|
|
@@ -719,11 +775,14 @@ exports.VALIDATION_MARKER = VALIDATION_MARKER;
|
|
|
719
775
|
exports.clearSpecsContext = clearSpecsContext;
|
|
720
776
|
exports.describeResponse = describeResponse;
|
|
721
777
|
exports.describeRoute = describeRoute;
|
|
778
|
+
exports.documentedComponents = documentedComponents;
|
|
722
779
|
exports.generateSpecs = generateSpecs;
|
|
780
|
+
exports.getSpecComponents = getSpecComponents;
|
|
723
781
|
exports.loadVendor = loadVendor;
|
|
724
782
|
exports.openAPIRouteHandler = openAPIRouteHandler;
|
|
725
783
|
exports.registerSchemaPath = registerSchemaPath;
|
|
726
784
|
exports.removeExcludedPaths = removeExcludedPaths;
|
|
727
785
|
exports.resolver = resolver;
|
|
786
|
+
exports.setSpecComponents = setSpecComponents;
|
|
728
787
|
exports.uniqueSymbol = uniqueSymbol;
|
|
729
788
|
exports.validator = validator;
|
package/dist/index.d.cts
CHANGED
|
@@ -84,8 +84,10 @@ declare const uniqueSymbol: unique symbol;
|
|
|
84
84
|
declare const VALIDATION_MARKER = "__HonoOpenAPIValidator__";
|
|
85
85
|
declare const ALLOWED_METHODS: readonly ["GET", "PUT", "POST", "DELETE", "OPTIONS", "HEAD", "PATCH", "TRACE"];
|
|
86
86
|
type AllowedMethods = (typeof ALLOWED_METHODS)[number];
|
|
87
|
+
declare const setSpecComponents: (spec: object, components: OpenAPIV3_1.ComponentsObject[]) => WeakMap<object, OpenAPIV3_1.ComponentsObject[]>;
|
|
88
|
+
declare const getSpecComponents: (spec: unknown) => OpenAPIV3_1.ComponentsObject[];
|
|
87
89
|
declare function clearSpecsContext(): void;
|
|
88
|
-
declare function registerSchemaPath({ route, specs, paths }: RegisterSchemaPathOptions, pathContext?: Map<string, Omit<OpenAPIV3_1.OperationObject<{}>, "
|
|
90
|
+
declare function registerSchemaPath({ route, specs, paths }: RegisterSchemaPathOptions, pathContext?: Map<string, Omit<OpenAPIV3_1.OperationObject<{}>, "responses" | "operationId" | "requestBody"> & {
|
|
89
91
|
operationId?: string | ((route: RouterRoute) => string);
|
|
90
92
|
requestBody?: OpenAPIV3_1.ReferenceObject | (Omit<OpenAPIV3_1.RequestBodyObject, "content"> & {
|
|
91
93
|
content: ContentWithResolver;
|
|
@@ -100,6 +102,16 @@ declare function registerSchemaPath({ route, specs, paths }: RegisterSchemaPathO
|
|
|
100
102
|
operationId?: string | ((route: RouterRoute) => string);
|
|
101
103
|
}>): void;
|
|
102
104
|
declare function removeExcludedPaths(paths: OpenAPIV3_1.PathsObject, ctx: SpecContext): OpenAPIV3_1.PathsObject<{}, {}>;
|
|
105
|
+
/**
|
|
106
|
+
* Keeps the generated components that the documented operations brought in,
|
|
107
|
+
* and the ones `documentation` refers to, directly or through other
|
|
108
|
+
* components.
|
|
109
|
+
*
|
|
110
|
+
* Components are collected from every route while the paths are generated,
|
|
111
|
+
* including routes that are hidden or excluded afterwards. Without this, those
|
|
112
|
+
* routes would still publish the schemas only they use.
|
|
113
|
+
*/
|
|
114
|
+
declare function documentedComponents(components: OpenAPIV3_1.ComponentsObject, paths: OpenAPIV3_1.PathsObject, documentation: unknown): OpenAPIV3_1.ComponentsObject;
|
|
103
115
|
|
|
104
116
|
type PromiseOr<T> = T | Promise<T>;
|
|
105
117
|
type ResolverReturnType = ReturnType<typeof resolver> & {
|
|
@@ -279,4 +291,4 @@ declare function generateSpecs<E extends Env = BlankEnv, P extends string = stri
|
|
|
279
291
|
jsonSchemaDialect?: string;
|
|
280
292
|
}>;
|
|
281
293
|
|
|
282
|
-
export { ALLOWED_METHODS, type AllowedMethods, type ContentWithResolver, type DescribeRouteOptions, type GenerateSpecOptions, type HandlerUniqueProperty, type PromiseOr, type RegisterSchemaPathOptions, type ResolverReturnType, type ResponsesWithResolver, type SpecContext, VALIDATION_MARKER, clearSpecsContext, describeResponse, describeRoute, generateSpecs, loadVendor, openAPIRouteHandler, registerSchemaPath, removeExcludedPaths, resolver, uniqueSymbol, validator };
|
|
294
|
+
export { ALLOWED_METHODS, type AllowedMethods, type ContentWithResolver, type DescribeRouteOptions, type GenerateSpecOptions, type HandlerUniqueProperty, type PromiseOr, type RegisterSchemaPathOptions, type ResolverReturnType, type ResponsesWithResolver, type SpecContext, VALIDATION_MARKER, clearSpecsContext, describeResponse, describeRoute, documentedComponents, generateSpecs, getSpecComponents, loadVendor, openAPIRouteHandler, registerSchemaPath, removeExcludedPaths, resolver, setSpecComponents, uniqueSymbol, validator };
|
package/dist/index.d.ts
CHANGED
|
@@ -84,8 +84,10 @@ declare const uniqueSymbol: unique symbol;
|
|
|
84
84
|
declare const VALIDATION_MARKER = "__HonoOpenAPIValidator__";
|
|
85
85
|
declare const ALLOWED_METHODS: readonly ["GET", "PUT", "POST", "DELETE", "OPTIONS", "HEAD", "PATCH", "TRACE"];
|
|
86
86
|
type AllowedMethods = (typeof ALLOWED_METHODS)[number];
|
|
87
|
+
declare const setSpecComponents: (spec: object, components: OpenAPIV3_1.ComponentsObject[]) => WeakMap<object, OpenAPIV3_1.ComponentsObject[]>;
|
|
88
|
+
declare const getSpecComponents: (spec: unknown) => OpenAPIV3_1.ComponentsObject[];
|
|
87
89
|
declare function clearSpecsContext(): void;
|
|
88
|
-
declare function registerSchemaPath({ route, specs, paths }: RegisterSchemaPathOptions, pathContext?: Map<string, Omit<OpenAPIV3_1.OperationObject<{}>, "
|
|
90
|
+
declare function registerSchemaPath({ route, specs, paths }: RegisterSchemaPathOptions, pathContext?: Map<string, Omit<OpenAPIV3_1.OperationObject<{}>, "responses" | "operationId" | "requestBody"> & {
|
|
89
91
|
operationId?: string | ((route: RouterRoute) => string);
|
|
90
92
|
requestBody?: OpenAPIV3_1.ReferenceObject | (Omit<OpenAPIV3_1.RequestBodyObject, "content"> & {
|
|
91
93
|
content: ContentWithResolver;
|
|
@@ -100,6 +102,16 @@ declare function registerSchemaPath({ route, specs, paths }: RegisterSchemaPathO
|
|
|
100
102
|
operationId?: string | ((route: RouterRoute) => string);
|
|
101
103
|
}>): void;
|
|
102
104
|
declare function removeExcludedPaths(paths: OpenAPIV3_1.PathsObject, ctx: SpecContext): OpenAPIV3_1.PathsObject<{}, {}>;
|
|
105
|
+
/**
|
|
106
|
+
* Keeps the generated components that the documented operations brought in,
|
|
107
|
+
* and the ones `documentation` refers to, directly or through other
|
|
108
|
+
* components.
|
|
109
|
+
*
|
|
110
|
+
* Components are collected from every route while the paths are generated,
|
|
111
|
+
* including routes that are hidden or excluded afterwards. Without this, those
|
|
112
|
+
* routes would still publish the schemas only they use.
|
|
113
|
+
*/
|
|
114
|
+
declare function documentedComponents(components: OpenAPIV3_1.ComponentsObject, paths: OpenAPIV3_1.PathsObject, documentation: unknown): OpenAPIV3_1.ComponentsObject;
|
|
103
115
|
|
|
104
116
|
type PromiseOr<T> = T | Promise<T>;
|
|
105
117
|
type ResolverReturnType = ReturnType<typeof resolver> & {
|
|
@@ -279,4 +291,4 @@ declare function generateSpecs<E extends Env = BlankEnv, P extends string = stri
|
|
|
279
291
|
jsonSchemaDialect?: string;
|
|
280
292
|
}>;
|
|
281
293
|
|
|
282
|
-
export { ALLOWED_METHODS, type AllowedMethods, type ContentWithResolver, type DescribeRouteOptions, type GenerateSpecOptions, type HandlerUniqueProperty, type PromiseOr, type RegisterSchemaPathOptions, type ResolverReturnType, type ResponsesWithResolver, type SpecContext, VALIDATION_MARKER, clearSpecsContext, describeResponse, describeRoute, generateSpecs, loadVendor, openAPIRouteHandler, registerSchemaPath, removeExcludedPaths, resolver, uniqueSymbol, validator };
|
|
294
|
+
export { ALLOWED_METHODS, type AllowedMethods, type ContentWithResolver, type DescribeRouteOptions, type GenerateSpecOptions, type HandlerUniqueProperty, type PromiseOr, type RegisterSchemaPathOptions, type ResolverReturnType, type ResponsesWithResolver, type SpecContext, VALIDATION_MARKER, clearSpecsContext, describeResponse, describeRoute, documentedComponents, generateSpecs, getSpecComponents, loadVendor, openAPIRouteHandler, registerSchemaPath, removeExcludedPaths, resolver, setSpecComponents, uniqueSymbol, validator };
|
package/dist/index.js
CHANGED
|
@@ -53,6 +53,9 @@ function mergeParameters(...params) {
|
|
|
53
53
|
}, /* @__PURE__ */ new Map());
|
|
54
54
|
return Array.from(merged.values());
|
|
55
55
|
}
|
|
56
|
+
const specComponents = /* @__PURE__ */ new WeakMap();
|
|
57
|
+
const setSpecComponents = (spec, components) => specComponents.set(spec, components);
|
|
58
|
+
const getSpecComponents = (spec) => spec != null && typeof spec === "object" && specComponents.get(spec) || [];
|
|
56
59
|
const specsByPathContext = /* @__PURE__ */ new Map();
|
|
57
60
|
function getPathContext(path, pathContext) {
|
|
58
61
|
const context = [];
|
|
@@ -82,7 +85,7 @@ function mergeRequestBodies(previous, current) {
|
|
|
82
85
|
};
|
|
83
86
|
}
|
|
84
87
|
function mergeSpecs(route, ...specs) {
|
|
85
|
-
|
|
88
|
+
const merged = specs.reduce(
|
|
86
89
|
(prev, spec) => {
|
|
87
90
|
if (!spec || !prev) return prev;
|
|
88
91
|
for (const [key, value] of Object.entries(spec)) {
|
|
@@ -124,6 +127,8 @@ function mergeSpecs(route, ...specs) {
|
|
|
124
127
|
operationId: generateOperationId(route)
|
|
125
128
|
}
|
|
126
129
|
);
|
|
130
|
+
setSpecComponents(merged, specs.flatMap(getSpecComponents));
|
|
131
|
+
return merged;
|
|
127
132
|
}
|
|
128
133
|
function registerSchemaPath({ route, specs, paths }, pathContext = specsByPathContext) {
|
|
129
134
|
const path = toOpenAPIPath(route.path);
|
|
@@ -238,6 +243,52 @@ function removeExcludedPaths(paths, ctx) {
|
|
|
238
243
|
}
|
|
239
244
|
return newPaths;
|
|
240
245
|
}
|
|
246
|
+
const COMPONENTS_PREFIX = "#/components/";
|
|
247
|
+
const componentKey = (type, name) => `${type}/${name.replaceAll("~", "~0").replaceAll("/", "~1")}`;
|
|
248
|
+
const componentRefs = (value) => {
|
|
249
|
+
if (Array.isArray(value)) {
|
|
250
|
+
return value.flatMap(componentRefs);
|
|
251
|
+
}
|
|
252
|
+
if (value == null || typeof value !== "object") {
|
|
253
|
+
return [];
|
|
254
|
+
}
|
|
255
|
+
return Object.entries(value).flatMap(([key, item]) => {
|
|
256
|
+
if (key !== "$ref" || typeof item !== "string") {
|
|
257
|
+
return componentRefs(item);
|
|
258
|
+
}
|
|
259
|
+
return item.startsWith(COMPONENTS_PREFIX) ? [item.slice(COMPONENTS_PREFIX.length)] : [];
|
|
260
|
+
});
|
|
261
|
+
};
|
|
262
|
+
const reachableRefs = (refs, components, reached) => refs.reduce((seen, ref) => {
|
|
263
|
+
if (seen.has(ref)) {
|
|
264
|
+
return seen;
|
|
265
|
+
}
|
|
266
|
+
const [type, ...name] = ref.split("/");
|
|
267
|
+
const component = components[type]?.[name.join("/").replaceAll("~1", "/").replaceAll("~0", "~")];
|
|
268
|
+
return reachableRefs(componentRefs(component), components, seen.add(ref));
|
|
269
|
+
}, reached);
|
|
270
|
+
function documentedComponents(components, paths, documentation) {
|
|
271
|
+
const contributed = new Set(
|
|
272
|
+
Object.values(paths).flatMap((item) => item == null ? [] : Object.values(item)).flatMap(getSpecComponents).flatMap(
|
|
273
|
+
(operationComponents) => Object.entries(operationComponents).flatMap(
|
|
274
|
+
([type, entries]) => Object.keys(entries ?? {}).map((name) => componentKey(type, name))
|
|
275
|
+
)
|
|
276
|
+
)
|
|
277
|
+
);
|
|
278
|
+
const kept = reachableRefs(
|
|
279
|
+
componentRefs(documentation),
|
|
280
|
+
components,
|
|
281
|
+
contributed
|
|
282
|
+
);
|
|
283
|
+
return Object.fromEntries(
|
|
284
|
+
Object.entries(components).flatMap(([type, entries]) => {
|
|
285
|
+
const remaining = Object.entries(entries ?? {}).filter(
|
|
286
|
+
([name]) => kept.has(componentKey(type, name))
|
|
287
|
+
);
|
|
288
|
+
return remaining.length > 0 ? [[type, Object.fromEntries(remaining)]] : [];
|
|
289
|
+
})
|
|
290
|
+
);
|
|
291
|
+
}
|
|
241
292
|
|
|
242
293
|
const DEFAULT_OPTIONS = {
|
|
243
294
|
documentation: {},
|
|
@@ -307,10 +358,14 @@ async function generateSpecs(hono, options = DEFAULT_OPTIONS, c) {
|
|
|
307
358
|
if (resolvedDocumentation && documentation.components) {
|
|
308
359
|
documentation.components.responses = resolvedDocumentation.responses;
|
|
309
360
|
}
|
|
361
|
+
const documentedPaths = removeExcludedPaths(paths, ctx);
|
|
310
362
|
const components = mergeComponentsObjects(
|
|
311
363
|
documentation.components,
|
|
312
364
|
resolvedDocumentation?.components,
|
|
313
|
-
ctx.components
|
|
365
|
+
documentedComponents(ctx.components, documentedPaths, [
|
|
366
|
+
documentation,
|
|
367
|
+
resolvedDocumentation?.components
|
|
368
|
+
])
|
|
314
369
|
);
|
|
315
370
|
return {
|
|
316
371
|
openapi: "3.1.0",
|
|
@@ -325,7 +380,7 @@ async function generateSpecs(hono, options = DEFAULT_OPTIONS, c) {
|
|
|
325
380
|
...documentation.info
|
|
326
381
|
},
|
|
327
382
|
paths: {
|
|
328
|
-
...
|
|
383
|
+
...documentedPaths,
|
|
329
384
|
...documentation.paths
|
|
330
385
|
},
|
|
331
386
|
components
|
|
@@ -364,6 +419,7 @@ async function generatePaths(hono, ctx) {
|
|
|
364
419
|
ctx.components.parameters
|
|
365
420
|
);
|
|
366
421
|
ctx.components = mergeComponentsObjects(ctx.components, components);
|
|
422
|
+
setSpecComponents(routeSpecs, [components]);
|
|
367
423
|
registerSchemaPath(
|
|
368
424
|
{
|
|
369
425
|
route,
|
|
@@ -712,4 +768,4 @@ function describeResponse(handler, responses, options) {
|
|
|
712
768
|
});
|
|
713
769
|
}
|
|
714
770
|
|
|
715
|
-
export { ALLOWED_METHODS, VALIDATION_MARKER, clearSpecsContext, describeResponse, describeRoute, generateSpecs, loadVendor, openAPIRouteHandler, registerSchemaPath, removeExcludedPaths, resolver, uniqueSymbol, validator };
|
|
771
|
+
export { ALLOWED_METHODS, VALIDATION_MARKER, clearSpecsContext, describeResponse, describeRoute, documentedComponents, generateSpecs, getSpecComponents, loadVendor, openAPIRouteHandler, registerSchemaPath, removeExcludedPaths, resolver, setSpecComponents, uniqueSymbol, validator };
|