@byyuurin/nitro-openapi 0.0.1 → 0.0.3

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 CHANGED
@@ -1 +1,88 @@
1
1
  # @byyuurin/nitro-openapi
2
+
3
+ > WIP
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm i -D @byyuurin/nitro-openapi
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ Enable openApi
14
+
15
+ ```ts
16
+ // nitor.config.ts
17
+ export default defineNitroConfig({
18
+ experimental: {
19
+ openAPI: true,
20
+ },
21
+ })
22
+ ```
23
+
24
+ Create nitor plugin:
25
+
26
+ ```ts
27
+ // plugins/swagger.ts
28
+ import { createOpenApiRegister } from '@byyuurin/nitro-openapi'
29
+ import type { OpenAPI3 } from 'openapi-typescript'
30
+
31
+ export const { register, merge, configExtends } = createOpenApiRegister({
32
+ // ...
33
+ })
34
+
35
+ export default defineNitroPlugin((nitro) => {
36
+ nitro.hooks.hook('beforeResponse', (event, context) => {
37
+ if (!/openapi.json/.test(event.path))
38
+ return
39
+
40
+ // merge config
41
+ const config = context.body as OpenAPI3
42
+ context.body = merge(config)
43
+ })
44
+ })
45
+ ```
46
+
47
+ Auto import
48
+
49
+ ```ts
50
+ // utils/swagger.ts
51
+ export { register } from '../plugins/swagger'
52
+ ```
53
+
54
+ Or custom register
55
+
56
+ ```ts
57
+ // utils/swagger.ts
58
+ import type { PathOperationItem, PathOperationMethod } from '@byyuurin/nitro-openapi'
59
+ import type { InternalApi } from 'nitropack'
60
+ import type { configExtends } from '../plugins/swagger'
61
+ import { register } from '../plugins/swagger'
62
+
63
+ type RouteMeta = PathOperationItem<typeof configExtends> & {
64
+ method?: PathOperationMethod
65
+ }
66
+
67
+ export function defineRouteMeta(
68
+ route: keyof InternalApi,
69
+ meta: RouteMeta,
70
+ ) {
71
+ const { method, ...operation } = meta
72
+ register(route, operation, method)
73
+ }
74
+ ```
75
+
76
+ Then use the register
77
+
78
+ ```ts
79
+ // route/**/*.ts
80
+
81
+ defineRouteMeta('/api/...', {
82
+ /* ... */
83
+ })
84
+
85
+ export default defineEventHandler(() => {
86
+ /* ... */
87
+ })
88
+ ```
package/dist/index.cjs ADDED
@@ -0,0 +1,159 @@
1
+ 'use strict';
2
+
3
+ const defu = require('defu');
4
+
5
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
6
+
7
+ const defu__default = /*#__PURE__*/_interopDefaultCompat(defu);
8
+
9
+ function createOpenApiRegister(defaults) {
10
+ const { paths = {}, components = {}, security = [], servers = [], info, tags = [] } = defaults;
11
+ const defineOperation = (operation) => operation;
12
+ function register(route, routeOperation, method = "get") {
13
+ const _route = normalizeRoute(route);
14
+ paths[_route] = defu__default(
15
+ { [method]: routeOperation },
16
+ paths[_route]
17
+ );
18
+ }
19
+ function merge(config) {
20
+ return mergeConfig(
21
+ config,
22
+ {
23
+ paths,
24
+ components,
25
+ security,
26
+ servers,
27
+ info,
28
+ tags
29
+ }
30
+ );
31
+ }
32
+ return {
33
+ configExtends: {
34
+ paths,
35
+ components,
36
+ security,
37
+ servers,
38
+ info,
39
+ tags
40
+ },
41
+ defineOperation,
42
+ register,
43
+ merge
44
+ };
45
+ }
46
+ function normalizeRoute(_route) {
47
+ let anonymousCtr = 0;
48
+ const route = _route.replace(/:(\w+)/g, (_, name) => `{${name}}`).replace(/\/(\*)\//g, () => `/{param${++anonymousCtr}}/`).replace(/\*\*{/, "{").replace(/\/(\*\*)$/g, () => `/{*param${++anonymousCtr}}`);
49
+ return route;
50
+ }
51
+ function mergeConfig(defaults, appends) {
52
+ const methods = /* @__PURE__ */ new Set(["delete", "get", "head", "options", "patch", "post", "put", "trace"]);
53
+ const { info } = appends;
54
+ const { paths = {} } = defaults;
55
+ for (const path in paths) {
56
+ const operations = paths[path];
57
+ if ("$ref" in operations)
58
+ continue;
59
+ paths[path] = Object.fromEntries(Object.entries(operations).map(([key, obj]) => {
60
+ if (methods.has(key))
61
+ return [key, normalizeSchema(obj)];
62
+ return [key, obj];
63
+ }));
64
+ }
65
+ return defu__default({ info }, defaults, appends);
66
+ }
67
+ function normalizeSchema(obj) {
68
+ if ("$ref" in obj)
69
+ return obj;
70
+ const { parameters = [] } = obj;
71
+ obj.parameters = parameters.map((p) => {
72
+ if ("$ref" in p)
73
+ return p;
74
+ return defu__default(p, {
75
+ schema: { type: "string" }
76
+ });
77
+ });
78
+ return obj;
79
+ }
80
+
81
+ function resolveSchemaObject(value, options = {}) {
82
+ const { allowExample = true, ...defaults } = options || {};
83
+ const resolveResult = (obj, example) => {
84
+ if (allowExample && example != null)
85
+ obj.example = example;
86
+ return { ...defaults, ...obj };
87
+ };
88
+ if (Array.isArray(value)) {
89
+ return resolveResult(
90
+ {
91
+ type: "array",
92
+ items: resolveSchemaObject(value[0], { allowExample: false })
93
+ },
94
+ value
95
+ );
96
+ }
97
+ const _type = typeof value;
98
+ switch (_type) {
99
+ case "function":
100
+ case "symbol":
101
+ case "undefined":
102
+ return { type: "null" };
103
+ case "object":
104
+ return resolveResult(
105
+ {
106
+ type: "object",
107
+ properties: Object.fromEntries(Object.entries(value).map(([k, v]) => [
108
+ k,
109
+ resolveSchemaObject(v, {
110
+ allowExample: false
111
+ })
112
+ ]))
113
+ },
114
+ value
115
+ );
116
+ case "bigint":
117
+ return resolveResult(
118
+ { type: "integer" },
119
+ value
120
+ );
121
+ case "string":
122
+ return resolveResult(
123
+ { type: "string" },
124
+ value || null
125
+ );
126
+ default:
127
+ return resolveResult(
128
+ { type: _type },
129
+ value
130
+ );
131
+ }
132
+ }
133
+ function toExampleSchema(example, description, options) {
134
+ if (typeof example !== "object") {
135
+ return resolveSchemaObject(
136
+ example,
137
+ typeof description === "string" ? { ...options, description } : {}
138
+ );
139
+ }
140
+ if (Array.isArray(example)) {
141
+ if (typeof description === "string")
142
+ return resolveSchemaObject(example, { ...options, description });
143
+ const schema2 = resolveSchemaObject(example, { allowExample: false });
144
+ schema2.items = toExampleSchema(example[0], description, options);
145
+ return schema2;
146
+ }
147
+ if (typeof description === "string")
148
+ return resolveSchemaObject(example, { ...options, description });
149
+ const schema = resolveSchemaObject(example, options);
150
+ schema.properties = Object.fromEntries(Object.entries(schema.properties).map(([p, item]) => [p, {
151
+ ...item,
152
+ ...typeof description === "object" ? { description: description?.[p] } : {}
153
+ }]));
154
+ return schema;
155
+ }
156
+
157
+ exports.createOpenApiRegister = createOpenApiRegister;
158
+ exports.resolveSchemaObject = resolveSchemaObject;
159
+ exports.toExampleSchema = toExampleSchema;
@@ -0,0 +1,105 @@
1
+ import * as openapi_typescript from 'openapi-typescript';
2
+ import { SchemaObject, ReferenceObject, PathItemObject, ResponseObject, MediaTypeObject, OperationObject, ParameterObject, RequestBodyObject, SecurityRequirementObject, OpenAPI3 } from 'openapi-typescript';
3
+
4
+ type ReferenceRef<T extends OpenApiRegisterConfig> = T extends {
5
+ components: infer C;
6
+ } ? {
7
+ [K in keyof C]: C[K] extends object ? `#/components/${K & string}/${keyof C[K] & string}` : never;
8
+ }[keyof C] : string;
9
+ type SchemaExtended<T extends string> = SchemaObject | ({
10
+ type: 'array';
11
+ prefixItems?: MaybeReference<SchemaExtended<T>, T>[];
12
+ items?: MaybeReference<SchemaExtended<T>, T> | MaybeReference<SchemaExtended<T>, T>[];
13
+ enum?: MaybeReference<SchemaExtended<T>, T>[];
14
+ description?: string;
15
+ } | {
16
+ type: 'object' | ['object', 'null'];
17
+ properties?: {
18
+ [name: string]: MaybeReference<SchemaExtended<T>, T>;
19
+ };
20
+ allOf?: MaybeReference<SchemaExtended<T>, T>[];
21
+ anyOf?: MaybeReference<SchemaExtended<T>, T>[];
22
+ enum?: MaybeReference<SchemaExtended<T>, T>[];
23
+ description?: string;
24
+ });
25
+ type ReferenceExtended<T extends string> = Omit<ReferenceObject, '$ref'> & {
26
+ $ref: T;
27
+ };
28
+ type MaybeReference<T, R extends string = string> = T | ReferenceExtended<R>;
29
+ type MaybeValueOrObject<ExampleT, ContentT> = ExampleT extends number | string | boolean ? ContentT : ExampleT extends (infer ArrayT)[] ? ContentT | MaybeValueOrObject<ArrayT, ContentT> : ExampleT extends Record<infer PropertyT, unknown> ? {
30
+ [key in PropertyT]?: ContentT;
31
+ } | ContentT : ContentT;
32
+ type PathOperations = Omit<PathItemObject, 'servers' | 'parameters' | `x-${string}`>;
33
+ type PathOperationMethod = keyof PathOperations;
34
+ type PathResponse<RefT extends string> = Omit<ResponseObject, 'content'> & {
35
+ content?: {
36
+ [contentType: string]: Omit<MediaTypeObject, 'schema'> & {
37
+ schema?: MaybeReference<SchemaExtended<RefT>, RefT>;
38
+ };
39
+ };
40
+ };
41
+ type PathOperationItem<T extends OpenApiRegisterConfig> = Omit<OperationObject, 'tags' | 'parameters' | 'requestBody' | 'responses' | 'security'> & {
42
+ tags?: T extends {
43
+ tags: infer Tags;
44
+ } ? Tags extends ({
45
+ name: infer Tag;
46
+ })[] ? Tag[] | string[] : string[] : string[];
47
+ parameters?: MaybeReference<ParameterObject & {
48
+ schema?: SchemaExtended<ReferenceRef<T>>;
49
+ }, ReferenceRef<T>>[];
50
+ requestBody?: MaybeReference<RequestBodyObject & {
51
+ content: {
52
+ [contentType: string]: MaybeReference<MediaTypeObject, ReferenceRef<T>>;
53
+ };
54
+ }, ReferenceRef<T>>;
55
+ responses?: {
56
+ [responseCode: string]: MaybeReference<PathResponse<ReferenceRef<T>>, ReferenceRef<T>>;
57
+ } & {
58
+ default?: MaybeReference<PathResponse<ReferenceRef<T>>, ReferenceRef<T>>;
59
+ };
60
+ security?: T extends {
61
+ components: infer C;
62
+ } ? C extends {
63
+ securitySchemes: infer S;
64
+ } ? {
65
+ [SecurityName in keyof S]?: string[];
66
+ }[] : SecurityRequirementObject[] : SecurityRequirementObject[];
67
+ };
68
+ type OpenApiRegisterConfig = Pick<Partial<OpenAPI3>, 'paths' | 'components' | 'security' | 'servers' | 'info' | 'tags'>;
69
+
70
+ declare function createOpenApiRegister<T extends OpenApiRegisterConfig = OpenApiRegisterConfig>(defaults: T): {
71
+ configExtends: T;
72
+ defineOperation: (operation: PathOperationItem<T>) => PathOperationItem<T>;
73
+ register: (route: string, routeOperation: MaybeReference<PathOperationItem<T>, ReferenceRef<T>>, method?: keyof PathOperations) => void;
74
+ merge: (config: Partial<OpenAPI3>) => Partial<OpenAPI3>;
75
+ };
76
+
77
+ type SchemaObjectOptions = SchemaObject & {
78
+ allowExample?: boolean;
79
+ };
80
+ declare function resolveSchemaObject(value: any, options?: SchemaObjectOptions): SchemaObject;
81
+ type ExampleDescription<ExampleT> = MaybeValueOrObject<ExampleT, string>;
82
+ declare function toExampleSchema<T = any>(example: T, description?: ExampleDescription<T>, options?: SchemaObject): {
83
+ [key: `x-${string}`]: any;
84
+ discriminator?: openapi_typescript.DiscriminatorObject | undefined;
85
+ xml?: openapi_typescript.XMLObject | undefined;
86
+ externalDocs?: openapi_typescript.ExternalDocumentationObject | undefined;
87
+ example?: any;
88
+ title?: string | undefined;
89
+ description?: string | undefined;
90
+ $comment?: string | undefined;
91
+ deprecated?: boolean | undefined;
92
+ readOnly?: boolean | undefined;
93
+ writeOnly?: boolean | undefined;
94
+ enum?: unknown[] | undefined;
95
+ const?: unknown;
96
+ default?: unknown;
97
+ format?: string | undefined;
98
+ nullable?: boolean | undefined;
99
+ oneOf?: (SchemaObject | openapi_typescript.ReferenceObject)[] | undefined;
100
+ allOf?: (SchemaObject | openapi_typescript.ReferenceObject)[] | undefined;
101
+ anyOf?: (SchemaObject | openapi_typescript.ReferenceObject)[] | undefined;
102
+ required?: string[] | undefined;
103
+ };
104
+
105
+ export { type MaybeReference, type MaybeValueOrObject, type OpenApiRegisterConfig, type PathOperationItem, type PathOperationMethod, type PathOperations, type PathResponse, type ReferenceExtended, type ReferenceRef, type SchemaExtended, createOpenApiRegister, resolveSchemaObject, toExampleSchema };
package/dist/index.d.mts CHANGED
@@ -1,18 +1,62 @@
1
1
  import * as openapi_typescript from 'openapi-typescript';
2
- import { ReferenceObject, PathItemObject, OperationObject, SecurityRequirementObject, OpenAPI3, SchemaObject } from 'openapi-typescript';
2
+ import { SchemaObject, ReferenceObject, PathItemObject, ResponseObject, MediaTypeObject, OperationObject, ParameterObject, RequestBodyObject, SecurityRequirementObject, OpenAPI3 } from 'openapi-typescript';
3
3
 
4
- type ReferenceSchema<T> = Omit<ReferenceObject, '$ref'> & {
4
+ type ReferenceRef<T extends OpenApiRegisterConfig> = T extends {
5
+ components: infer C;
6
+ } ? {
7
+ [K in keyof C]: C[K] extends object ? `#/components/${K & string}/${keyof C[K] & string}` : never;
8
+ }[keyof C] : string;
9
+ type SchemaExtended<T extends string> = SchemaObject | ({
10
+ type: 'array';
11
+ prefixItems?: MaybeReference<SchemaExtended<T>, T>[];
12
+ items?: MaybeReference<SchemaExtended<T>, T> | MaybeReference<SchemaExtended<T>, T>[];
13
+ enum?: MaybeReference<SchemaExtended<T>, T>[];
14
+ description?: string;
15
+ } | {
16
+ type: 'object' | ['object', 'null'];
17
+ properties?: {
18
+ [name: string]: MaybeReference<SchemaExtended<T>, T>;
19
+ };
20
+ allOf?: MaybeReference<SchemaExtended<T>, T>[];
21
+ anyOf?: MaybeReference<SchemaExtended<T>, T>[];
22
+ enum?: MaybeReference<SchemaExtended<T>, T>[];
23
+ description?: string;
24
+ });
25
+ type ReferenceExtended<T extends string> = Omit<ReferenceObject, '$ref'> & {
5
26
  $ref: T;
6
27
  };
7
- type MaybeReference<T, R = string> = T | ReferenceSchema<R>;
28
+ type MaybeReference<T, R extends string = string> = T | ReferenceExtended<R>;
29
+ type MaybeValueOrObject<ExampleT, ContentT> = ExampleT extends number | string | boolean ? ContentT : ExampleT extends (infer ArrayT)[] ? ContentT | MaybeValueOrObject<ArrayT, ContentT> : ExampleT extends Record<infer PropertyT, unknown> ? {
30
+ [key in PropertyT]?: ContentT;
31
+ } | ContentT : ContentT;
8
32
  type PathOperations = Omit<PathItemObject, 'servers' | 'parameters' | `x-${string}`>;
9
33
  type PathOperationMethod = keyof PathOperations;
10
- type PathOperationItem<T extends OpenApiRegisterConfig = Required<OpenApiRegisterConfig>> = Omit<OperationObject, 'security' | 'tags'> & {
34
+ type PathResponse<RefT extends string> = Omit<ResponseObject, 'content'> & {
35
+ content?: {
36
+ [contentType: string]: Omit<MediaTypeObject, 'schema'> & {
37
+ schema?: MaybeReference<SchemaExtended<RefT>, RefT>;
38
+ };
39
+ };
40
+ };
41
+ type PathOperationItem<T extends OpenApiRegisterConfig> = Omit<OperationObject, 'tags' | 'parameters' | 'requestBody' | 'responses' | 'security'> & {
11
42
  tags?: T extends {
12
43
  tags: infer Tags;
13
44
  } ? Tags extends ({
14
45
  name: infer Tag;
15
46
  })[] ? Tag[] | string[] : string[] : string[];
47
+ parameters?: MaybeReference<ParameterObject & {
48
+ schema?: SchemaExtended<ReferenceRef<T>>;
49
+ }, ReferenceRef<T>>[];
50
+ requestBody?: MaybeReference<RequestBodyObject & {
51
+ content: {
52
+ [contentType: string]: MaybeReference<MediaTypeObject, ReferenceRef<T>>;
53
+ };
54
+ }, ReferenceRef<T>>;
55
+ responses?: {
56
+ [responseCode: string]: MaybeReference<PathResponse<ReferenceRef<T>>, ReferenceRef<T>>;
57
+ } & {
58
+ default?: MaybeReference<PathResponse<ReferenceRef<T>>, ReferenceRef<T>>;
59
+ };
16
60
  security?: T extends {
17
61
  components: infer C;
18
62
  } ? C extends {
@@ -23,22 +67,19 @@ type PathOperationItem<T extends OpenApiRegisterConfig = Required<OpenApiRegiste
23
67
  };
24
68
  type OpenApiRegisterConfig = Pick<Partial<OpenAPI3>, 'paths' | 'components' | 'security' | 'servers' | 'info' | 'tags'>;
25
69
 
26
- declare function createOpenApiRegister<T extends OpenApiRegisterConfig = OpenApiRegisterConfig>(defaults?: T): {
70
+ declare function createOpenApiRegister<T extends OpenApiRegisterConfig = OpenApiRegisterConfig>(defaults: T): {
27
71
  configExtends: T;
28
- register: (route: string, routeOperation: MaybeReference<PathOperationItem<T>>, method?: keyof PathOperations) => void;
29
- merge: (config: Partial<OpenAPI3>) => {
30
- info: openapi_typescript.InfoObject | undefined;
31
- };
72
+ defineOperation: (operation: PathOperationItem<T>) => PathOperationItem<T>;
73
+ register: (route: string, routeOperation: MaybeReference<PathOperationItem<T>, ReferenceRef<T>>, method?: keyof PathOperations) => void;
74
+ merge: (config: Partial<OpenAPI3>) => Partial<OpenAPI3>;
32
75
  };
33
76
 
34
77
  type SchemaObjectOptions = SchemaObject & {
35
78
  allowExample?: boolean;
36
79
  };
37
80
  declare function resolveSchemaObject(value: any, options?: SchemaObjectOptions): SchemaObject;
38
- type ExampleDescription<ExampleT> = ExampleT extends number | string | boolean ? string : ExampleT extends (infer ArrayT)[] ? string | ExampleDescription<ArrayT> : ExampleT extends Record<infer PropertyT, unknown> ? {
39
- [key in PropertyT]?: string;
40
- } | string : string;
41
- declare function toExampleSchema<T = any>(example: T, description?: ExampleDescription<T>): {
81
+ type ExampleDescription<ExampleT> = MaybeValueOrObject<ExampleT, string>;
82
+ declare function toExampleSchema<T = any>(example: T, description?: ExampleDescription<T>, options?: SchemaObject): {
42
83
  [key: `x-${string}`]: any;
43
84
  discriminator?: openapi_typescript.DiscriminatorObject | undefined;
44
85
  xml?: openapi_typescript.XMLObject | undefined;
@@ -55,10 +96,10 @@ declare function toExampleSchema<T = any>(example: T, description?: ExampleDescr
55
96
  default?: unknown;
56
97
  format?: string | undefined;
57
98
  nullable?: boolean | undefined;
58
- oneOf?: (openapi_typescript.ReferenceObject | SchemaObject)[] | undefined;
59
- allOf?: (openapi_typescript.ReferenceObject | SchemaObject)[] | undefined;
60
- anyOf?: (openapi_typescript.ReferenceObject | SchemaObject)[] | undefined;
99
+ oneOf?: (SchemaObject | openapi_typescript.ReferenceObject)[] | undefined;
100
+ allOf?: (SchemaObject | openapi_typescript.ReferenceObject)[] | undefined;
101
+ anyOf?: (SchemaObject | openapi_typescript.ReferenceObject)[] | undefined;
61
102
  required?: string[] | undefined;
62
103
  };
63
104
 
64
- export { type MaybeReference, type OpenApiRegisterConfig, type PathOperationItem, type PathOperationMethod, type PathOperations, type ReferenceSchema, createOpenApiRegister, resolveSchemaObject, toExampleSchema };
105
+ export { type MaybeReference, type MaybeValueOrObject, type OpenApiRegisterConfig, type PathOperationItem, type PathOperationMethod, type PathOperations, type PathResponse, type ReferenceExtended, type ReferenceRef, type SchemaExtended, createOpenApiRegister, resolveSchemaObject, toExampleSchema };
package/dist/index.d.ts CHANGED
@@ -1,18 +1,62 @@
1
1
  import * as openapi_typescript from 'openapi-typescript';
2
- import { ReferenceObject, PathItemObject, OperationObject, SecurityRequirementObject, OpenAPI3, SchemaObject } from 'openapi-typescript';
2
+ import { SchemaObject, ReferenceObject, PathItemObject, ResponseObject, MediaTypeObject, OperationObject, ParameterObject, RequestBodyObject, SecurityRequirementObject, OpenAPI3 } from 'openapi-typescript';
3
3
 
4
- type ReferenceSchema<T> = Omit<ReferenceObject, '$ref'> & {
4
+ type ReferenceRef<T extends OpenApiRegisterConfig> = T extends {
5
+ components: infer C;
6
+ } ? {
7
+ [K in keyof C]: C[K] extends object ? `#/components/${K & string}/${keyof C[K] & string}` : never;
8
+ }[keyof C] : string;
9
+ type SchemaExtended<T extends string> = SchemaObject | ({
10
+ type: 'array';
11
+ prefixItems?: MaybeReference<SchemaExtended<T>, T>[];
12
+ items?: MaybeReference<SchemaExtended<T>, T> | MaybeReference<SchemaExtended<T>, T>[];
13
+ enum?: MaybeReference<SchemaExtended<T>, T>[];
14
+ description?: string;
15
+ } | {
16
+ type: 'object' | ['object', 'null'];
17
+ properties?: {
18
+ [name: string]: MaybeReference<SchemaExtended<T>, T>;
19
+ };
20
+ allOf?: MaybeReference<SchemaExtended<T>, T>[];
21
+ anyOf?: MaybeReference<SchemaExtended<T>, T>[];
22
+ enum?: MaybeReference<SchemaExtended<T>, T>[];
23
+ description?: string;
24
+ });
25
+ type ReferenceExtended<T extends string> = Omit<ReferenceObject, '$ref'> & {
5
26
  $ref: T;
6
27
  };
7
- type MaybeReference<T, R = string> = T | ReferenceSchema<R>;
28
+ type MaybeReference<T, R extends string = string> = T | ReferenceExtended<R>;
29
+ type MaybeValueOrObject<ExampleT, ContentT> = ExampleT extends number | string | boolean ? ContentT : ExampleT extends (infer ArrayT)[] ? ContentT | MaybeValueOrObject<ArrayT, ContentT> : ExampleT extends Record<infer PropertyT, unknown> ? {
30
+ [key in PropertyT]?: ContentT;
31
+ } | ContentT : ContentT;
8
32
  type PathOperations = Omit<PathItemObject, 'servers' | 'parameters' | `x-${string}`>;
9
33
  type PathOperationMethod = keyof PathOperations;
10
- type PathOperationItem<T extends OpenApiRegisterConfig = Required<OpenApiRegisterConfig>> = Omit<OperationObject, 'security' | 'tags'> & {
34
+ type PathResponse<RefT extends string> = Omit<ResponseObject, 'content'> & {
35
+ content?: {
36
+ [contentType: string]: Omit<MediaTypeObject, 'schema'> & {
37
+ schema?: MaybeReference<SchemaExtended<RefT>, RefT>;
38
+ };
39
+ };
40
+ };
41
+ type PathOperationItem<T extends OpenApiRegisterConfig> = Omit<OperationObject, 'tags' | 'parameters' | 'requestBody' | 'responses' | 'security'> & {
11
42
  tags?: T extends {
12
43
  tags: infer Tags;
13
44
  } ? Tags extends ({
14
45
  name: infer Tag;
15
46
  })[] ? Tag[] | string[] : string[] : string[];
47
+ parameters?: MaybeReference<ParameterObject & {
48
+ schema?: SchemaExtended<ReferenceRef<T>>;
49
+ }, ReferenceRef<T>>[];
50
+ requestBody?: MaybeReference<RequestBodyObject & {
51
+ content: {
52
+ [contentType: string]: MaybeReference<MediaTypeObject, ReferenceRef<T>>;
53
+ };
54
+ }, ReferenceRef<T>>;
55
+ responses?: {
56
+ [responseCode: string]: MaybeReference<PathResponse<ReferenceRef<T>>, ReferenceRef<T>>;
57
+ } & {
58
+ default?: MaybeReference<PathResponse<ReferenceRef<T>>, ReferenceRef<T>>;
59
+ };
16
60
  security?: T extends {
17
61
  components: infer C;
18
62
  } ? C extends {
@@ -23,22 +67,19 @@ type PathOperationItem<T extends OpenApiRegisterConfig = Required<OpenApiRegiste
23
67
  };
24
68
  type OpenApiRegisterConfig = Pick<Partial<OpenAPI3>, 'paths' | 'components' | 'security' | 'servers' | 'info' | 'tags'>;
25
69
 
26
- declare function createOpenApiRegister<T extends OpenApiRegisterConfig = OpenApiRegisterConfig>(defaults?: T): {
70
+ declare function createOpenApiRegister<T extends OpenApiRegisterConfig = OpenApiRegisterConfig>(defaults: T): {
27
71
  configExtends: T;
28
- register: (route: string, routeOperation: MaybeReference<PathOperationItem<T>>, method?: keyof PathOperations) => void;
29
- merge: (config: Partial<OpenAPI3>) => {
30
- info: openapi_typescript.InfoObject | undefined;
31
- };
72
+ defineOperation: (operation: PathOperationItem<T>) => PathOperationItem<T>;
73
+ register: (route: string, routeOperation: MaybeReference<PathOperationItem<T>, ReferenceRef<T>>, method?: keyof PathOperations) => void;
74
+ merge: (config: Partial<OpenAPI3>) => Partial<OpenAPI3>;
32
75
  };
33
76
 
34
77
  type SchemaObjectOptions = SchemaObject & {
35
78
  allowExample?: boolean;
36
79
  };
37
80
  declare function resolveSchemaObject(value: any, options?: SchemaObjectOptions): SchemaObject;
38
- type ExampleDescription<ExampleT> = ExampleT extends number | string | boolean ? string : ExampleT extends (infer ArrayT)[] ? string | ExampleDescription<ArrayT> : ExampleT extends Record<infer PropertyT, unknown> ? {
39
- [key in PropertyT]?: string;
40
- } | string : string;
41
- declare function toExampleSchema<T = any>(example: T, description?: ExampleDescription<T>): {
81
+ type ExampleDescription<ExampleT> = MaybeValueOrObject<ExampleT, string>;
82
+ declare function toExampleSchema<T = any>(example: T, description?: ExampleDescription<T>, options?: SchemaObject): {
42
83
  [key: `x-${string}`]: any;
43
84
  discriminator?: openapi_typescript.DiscriminatorObject | undefined;
44
85
  xml?: openapi_typescript.XMLObject | undefined;
@@ -55,10 +96,10 @@ declare function toExampleSchema<T = any>(example: T, description?: ExampleDescr
55
96
  default?: unknown;
56
97
  format?: string | undefined;
57
98
  nullable?: boolean | undefined;
58
- oneOf?: (openapi_typescript.ReferenceObject | SchemaObject)[] | undefined;
59
- allOf?: (openapi_typescript.ReferenceObject | SchemaObject)[] | undefined;
60
- anyOf?: (openapi_typescript.ReferenceObject | SchemaObject)[] | undefined;
99
+ oneOf?: (SchemaObject | openapi_typescript.ReferenceObject)[] | undefined;
100
+ allOf?: (SchemaObject | openapi_typescript.ReferenceObject)[] | undefined;
101
+ anyOf?: (SchemaObject | openapi_typescript.ReferenceObject)[] | undefined;
61
102
  required?: string[] | undefined;
62
103
  };
63
104
 
64
- export { type MaybeReference, type OpenApiRegisterConfig, type PathOperationItem, type PathOperationMethod, type PathOperations, type ReferenceSchema, createOpenApiRegister, resolveSchemaObject, toExampleSchema };
105
+ export { type MaybeReference, type MaybeValueOrObject, type OpenApiRegisterConfig, type PathOperationItem, type PathOperationMethod, type PathOperations, type PathResponse, type ReferenceExtended, type ReferenceRef, type SchemaExtended, createOpenApiRegister, resolveSchemaObject, toExampleSchema };
package/dist/index.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  import defu from 'defu';
2
2
 
3
- function createOpenApiRegister(defaults = {}) {
3
+ function createOpenApiRegister(defaults) {
4
4
  const { paths = {}, components = {}, security = [], servers = [], info, tags = [] } = defaults;
5
+ const defineOperation = (operation) => operation;
5
6
  function register(route, routeOperation, method = "get") {
6
7
  const _route = normalizeRoute(route);
7
8
  paths[_route] = defu(
@@ -31,6 +32,7 @@ function createOpenApiRegister(defaults = {}) {
31
32
  info,
32
33
  tags
33
34
  },
35
+ defineOperation,
34
36
  register,
35
37
  merge
36
38
  };
@@ -71,8 +73,7 @@ function normalizeSchema(obj) {
71
73
  }
72
74
 
73
75
  function resolveSchemaObject(value, options = {}) {
74
- const { allowExample = true, ...defaults } = options;
75
- const { description: _, ...inheritOptions } = options;
76
+ const { allowExample = true, ...defaults } = options || {};
76
77
  const resolveResult = (obj, example) => {
77
78
  if (allowExample && example != null)
78
79
  obj.example = example;
@@ -82,7 +83,7 @@ function resolveSchemaObject(value, options = {}) {
82
83
  return resolveResult(
83
84
  {
84
85
  type: "array",
85
- items: resolveSchemaObject(value[0], { ...inheritOptions, allowExample: false })
86
+ items: resolveSchemaObject(value[0], { allowExample: false })
86
87
  },
87
88
  value
88
89
  );
@@ -100,7 +101,6 @@ function resolveSchemaObject(value, options = {}) {
100
101
  properties: Object.fromEntries(Object.entries(value).map(([k, v]) => [
101
102
  k,
102
103
  resolveSchemaObject(v, {
103
- ...inheritOptions,
104
104
  allowExample: false
105
105
  })
106
106
  ]))
@@ -124,23 +124,23 @@ function resolveSchemaObject(value, options = {}) {
124
124
  );
125
125
  }
126
126
  }
127
- function toExampleSchema(example, description) {
127
+ function toExampleSchema(example, description, options) {
128
128
  if (typeof example !== "object") {
129
129
  return resolveSchemaObject(
130
130
  example,
131
- typeof description === "string" ? { description } : {}
131
+ typeof description === "string" ? { ...options, description } : {}
132
132
  );
133
133
  }
134
134
  if (Array.isArray(example)) {
135
135
  if (typeof description === "string")
136
- return resolveSchemaObject(example, { description });
136
+ return resolveSchemaObject(example, { ...options, description });
137
137
  const schema2 = resolveSchemaObject(example, { allowExample: false });
138
- schema2.items = toExampleSchema(example[0], description);
138
+ schema2.items = toExampleSchema(example[0], description, options);
139
139
  return schema2;
140
140
  }
141
141
  if (typeof description === "string")
142
- return resolveSchemaObject(example, { description });
143
- const schema = resolveSchemaObject(example);
142
+ return resolveSchemaObject(example, { ...options, description });
143
+ const schema = resolveSchemaObject(example, options);
144
144
  schema.properties = Object.fromEntries(Object.entries(schema.properties).map(([p, item]) => [p, {
145
145
  ...item,
146
146
  ...typeof description === "object" ? { description: description?.[p] } : {}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@byyuurin/nitro-openapi",
3
3
  "type": "module",
4
- "version": "0.0.1",
4
+ "version": "0.0.3",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/byyuurin/nitro-openapi",
@@ -12,7 +12,8 @@
12
12
  "exports": {
13
13
  ".": {
14
14
  "types": "./dist/index.d.ts",
15
- "import": "./dist/index.mjs"
15
+ "import": "./dist/index.mjs",
16
+ "require": "./dist/index.cjs"
16
17
  }
17
18
  },
18
19
  "main": "./dist/index.mjs",
@@ -21,29 +22,29 @@
21
22
  "*.d.ts",
22
23
  "dist"
23
24
  ],
24
- "scripts": {
25
- "build": "unbuild",
26
- "prepare": "nitropack prepare",
27
- "dev": "nitropack dev playground",
28
- "dev:build": "nitropack build playground",
29
- "dev:preview": "node playground/.output/server/index.mjs",
30
- "lint": "eslint .",
31
- "test": "vitest",
32
- "release": "bumpp && pnpm publish",
33
- "stub": "unbuild --stub"
34
- },
35
25
  "dependencies": {
36
26
  "defu": "^6.1.4",
37
27
  "openapi-typescript": "^6.7.4"
38
28
  },
39
29
  "devDependencies": {
40
- "@byyuurin/eslint-config": "^1.0.1",
41
- "bumpp": "^9.3.0",
30
+ "@byyuurin/eslint-config": "^1.0.2",
31
+ "bumpp": "^9.3.1",
42
32
  "nitropack": "latest",
43
33
  "unbuild": "^2.0.0",
44
- "vitest": "^1.3.0"
34
+ "vitest": "^1.3.1"
45
35
  },
46
36
  "resolutions": {
47
37
  "@byyuurin/nitro-openapi": "link:."
38
+ },
39
+ "scripts": {
40
+ "build": "unbuild",
41
+ "dev": "nitropack dev playground",
42
+ "dev:prepare": "nitropack prepare playground",
43
+ "dev:build": "nitropack build playground",
44
+ "dev:preview": "node playground/.output/server/index.mjs",
45
+ "lint": "eslint .",
46
+ "test": "vitest",
47
+ "release": "bumpp && pnpm publish",
48
+ "stub": "unbuild --stub"
48
49
  }
49
- }
50
+ }