Skip to content
This repository was archived by the owner on Aug 28, 2024. It is now read-only.

Commit aec9f22

Browse files
authored
feat: type custom extensions, custom extensions in schemas (#166)
* feat: better openapi types * docs(changeset): feat: types: allow any attribute in schemas * docs(changeset): feat: types: allow to type custom extensions * fix: TS issues
1 parent 1bb15dd commit aec9f22

File tree

3 files changed

+69
-54
lines changed

3 files changed

+69
-54
lines changed

.changeset/flat-spoons-learn.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@scalar/openapi-parser': patch
3+
---
4+
5+
feat: types: allow to type custom extensions

.changeset/loud-coats-sort.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@scalar/openapi-parser': patch
3+
---
4+
5+
feat: types: allow any attribute in schemas

packages/openapi-parser/src/types/openapi-types.ts

+59-54
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,26 @@
77
* We deal with user input and can’t assume they really stick to any official specification.
88
*/
99

10+
/** any other attribute, for example x-* extensions */
11+
type AnyOtherAttribute = {
12+
/** OpenAPI extension */
13+
[customExtension: `x-${string}`]: any
14+
/** Unknown attribute */
15+
[key: string]: any
16+
}
17+
1018
export namespace OpenAPI {
1119
// OpenAPI extensions can be declared using generics
1220
// e.g.:
1321
// OpenAPI.Document<{
1422
// 'x-foobar': Foobar
1523
// }>
16-
export type Document<
17-
T extends {
18-
// any other attribute
19-
[key: string]: any
20-
} = {},
21-
> = OpenAPIV2.Document<T> | OpenAPIV3.Document<T> | OpenAPIV3_1.Document<T>
22-
23-
export type Operation<T extends {} = {}> =
24+
export type Document<T extends AnyOtherAttribute = {}> =
25+
| OpenAPIV2.Document<T>
26+
| OpenAPIV3.Document<T>
27+
| OpenAPIV3_1.Document<T>
28+
29+
export type Operation<T = {}> =
2430
| OpenAPIV2.OperationObject<T>
2531
| OpenAPIV3.OperationObject<T>
2632
| OpenAPIV3_1.OperationObject<T>
@@ -64,20 +70,20 @@ export namespace OpenAPI {
6470
export namespace OpenAPIV3_1 {
6571
type Modify<T, R> = Omit<T, keyof R> & R
6672

67-
type PathsWebhooksComponents<T extends {} = {}> = {
73+
type PathsWebhooksComponents<T = {}> = {
6874
paths?: PathsObject<T>
6975
webhooks?: Record<string, PathItemObject | ReferenceObject>
7076
components?: ComponentsObject
7177
}
7278

73-
export type Document<T extends {} = {}> = Modify<
79+
export type Document<T = {}> = Modify<
7480
Omit<OpenAPIV3.Document<T>, 'paths' | 'components'>,
7581
{
7682
/**
7783
* Version of the OpenAPI specification
7884
* @see https://github.com/OAI/OpenAPI-Specification/tree/main/versions
7985
*/
80-
openapi: '3.1.0'
86+
openapi?: '3.1.0'
8187
info?: InfoObject
8288
jsonSchemaDialect?: string
8389
servers?: ServerObject[]
@@ -88,7 +94,9 @@ export namespace OpenAPIV3_1 {
8894
Omit<Partial<PathsWebhooksComponents<T>>, 'webhooks'>)
8995
| (Pick<PathsWebhooksComponents<T>, 'components'> &
9096
Omit<Partial<PathsWebhooksComponents<T>>, 'components'>)
91-
)
97+
) &
98+
T &
99+
AnyOtherAttribute
92100
>
93101

94102
export type InfoObject = Modify<
@@ -124,14 +132,14 @@ export namespace OpenAPIV3_1 {
124132
}
125133
>
126134

127-
export type PathsObject<T extends {} = {}, P extends {} = {}> = Record<
135+
export type PathsObject<T = {}, P extends {} = {}> = Record<
128136
string,
129137
(PathItemObject<T> & P) | undefined
130138
>
131139

132140
export type HttpMethods = OpenAPIV3.HttpMethods
133141

134-
export type PathItemObject<T extends {} = {}> = Modify<
142+
export type PathItemObject<T = {}> = Modify<
135143
OpenAPIV3.PathItemObject<T>,
136144
{
137145
servers?: ServerObject[]
@@ -141,7 +149,7 @@ export namespace OpenAPIV3_1 {
141149
[method in HttpMethods]?: OperationObject<T>
142150
}
143151

144-
export type OperationObject<T extends {} = {}> = Modify<
152+
export type OperationObject<T = {}> = Modify<
145153
OpenAPIV3.OperationObject<T>,
146154
{
147155
parameters?: (ReferenceObject | ParameterObject)[]
@@ -173,11 +181,13 @@ export namespace OpenAPIV3_1 {
173181
* 'items' will be always visible as optional
174182
* Casting schema object to ArraySchemaObject or NonArraySchemaObject will work fine
175183
*/
176-
export type SchemaObject =
184+
export type SchemaObject = (
177185
| ArraySchemaObject
178186
| NonArraySchemaObject
179187
| MixedSchemaObject
180188
| boolean
189+
) &
190+
AnyOtherAttribute
181191

182192
export interface ArraySchemaObject extends BaseSchemaObject {
183193
type?: ArraySchemaObjectType
@@ -299,8 +309,7 @@ export namespace OpenAPIV3_1 {
299309
}
300310

301311
export namespace OpenAPIV3 {
302-
export interface Document<T extends {} = {}> {
303-
[propName: string]: any
312+
export type Document<T = {}> = {
304313
/**
305314
* Version of the OpenAPI specification
306315
* @see https://github.com/OAI/OpenAPI-Specification/tree/main/versions
@@ -313,7 +322,8 @@ export namespace OpenAPIV3 {
313322
security?: SecurityRequirementObject[]
314323
tags?: TagObject[]
315324
externalDocs?: ExternalDocumentationObject
316-
}
325+
} & T &
326+
AnyOtherAttribute
317327

318328
export interface InfoObject {
319329
title?: string
@@ -347,7 +357,7 @@ export namespace OpenAPIV3 {
347357
description?: string
348358
}
349359

350-
export interface PathsObject<T extends {} = {}, P extends {} = {}> {
360+
export interface PathsObject<T = {}, P extends {} = {}> {
351361
[pattern: string]: (PathItemObject<T> & P) | undefined
352362
}
353363

@@ -366,19 +376,19 @@ export namespace OpenAPIV3 {
366376
TRACE = 'trace',
367377
}
368378

369-
export type PathItemObject<T extends {} = {}> = {
379+
export type PathItemObject<T = {}> = {
370380
$ref?: string
371381
summary?: string
372382
description?: string
373383
servers?: ServerObject[]
374384
parameters?: (ReferenceObject | ParameterObject)[]
375385
} & {
376386
[method in HttpMethods]?: OperationObject<T>
377-
}
387+
} & T &
388+
AnyOtherAttribute
378389

379-
export type OperationObject<T extends {} = {}> = {
390+
export type OperationObject<T = {}> = {
380391
tags?: string[]
381-
[key: string]: any
382392
summary?: string
383393
description?: string
384394
externalDocs?: ExternalDocumentationObject
@@ -390,7 +400,8 @@ export namespace OpenAPIV3 {
390400
deprecated?: boolean
391401
security?: SecurityRequirementObject[]
392402
servers?: ServerObject[]
393-
} & T
403+
} & T &
404+
AnyOtherAttribute
394405

395406
export interface ExternalDocumentationObject {
396407
description?: string
@@ -424,7 +435,8 @@ export namespace OpenAPIV3 {
424435
| 'string'
425436
| 'integer'
426437
export type ArraySchemaObjectType = 'array'
427-
export type SchemaObject = ArraySchemaObject | NonArraySchemaObject
438+
export type SchemaObject = (ArraySchemaObject | NonArraySchemaObject) &
439+
AnyOtherAttribute
428440

429441
export interface ArraySchemaObject extends BaseSchemaObject {
430442
type?: ArraySchemaObjectType
@@ -489,9 +501,8 @@ export namespace OpenAPIV3 {
489501
wrapped?: boolean
490502
}
491503

492-
export interface ReferenceObject {
504+
export interface ReferenceObject extends AnyOtherAttribute {
493505
$ref?: string
494-
[key: string]: any
495506
}
496507

497508
export interface ExampleObject {
@@ -526,12 +537,11 @@ export namespace OpenAPIV3 {
526537
[code: string]: ReferenceObject | ResponseObject
527538
}
528539

529-
export interface ResponseObject {
540+
export interface ResponseObject extends AnyOtherAttribute {
530541
description?: string
531542
headers?: { [header: string]: ReferenceObject | HeaderObject }
532543
content?: { [media: string]: MediaTypeObject }
533544
links?: { [link: string]: ReferenceObject | LinkObject }
534-
[key: string]: any
535545
}
536546

537547
export interface LinkObject {
@@ -617,19 +627,20 @@ export namespace OpenAPIV3 {
617627
openIdConnectUrl?: string
618628
}
619629

620-
export interface TagObject {
630+
export interface TagObject extends AnyOtherAttribute {
621631
name?: string
622632
description?: string
623633
externalDocs?: ExternalDocumentationObject
624-
[key: string]: any
625634
}
626635
}
627636

628637
export namespace OpenAPIV2 {
629-
export interface Document<T extends {} = {}> {
630-
[propName: string]: any
631-
/** To make it easier to use openapi as a type guard */
632-
openapi: undefined
638+
export type Document<T = {}> = {
639+
/**
640+
* Version of the OpenAPI specification
641+
* @see https://github.com/OAI/OpenAPI-Specification/tree/main/versions
642+
*/
643+
swagger?: '2.0'
633644
basePath?: string
634645
consumes?: MimeTypes
635646
definitions?: DefinitionsObject
@@ -643,19 +654,15 @@ export namespace OpenAPIV2 {
643654
schemes?: string[]
644655
security?: SecurityRequirementObject[]
645656
securityDefinitions?: SecurityDefinitionsObject
646-
/**
647-
* Version of the OpenAPI specification
648-
* @see https://github.com/OAI/OpenAPI-Specification/tree/main/versions
649-
*/
650-
swagger?: '2.0'
651657
tags?: TagObject[]
652-
}
658+
[key: string]: any
659+
} & T &
660+
AnyOtherAttribute
653661

654-
export interface TagObject {
662+
export interface TagObject extends AnyOtherAttribute {
655663
name?: string
656664
description?: string
657665
externalDocs?: ExternalDocumentationObject
658-
[key: string]: any
659666
}
660667

661668
export interface SecuritySchemeObjectBase {
@@ -727,9 +734,8 @@ export namespace OpenAPIV2 {
727734
[index: string]: string[]
728735
}
729736

730-
export interface ReferenceObject {
737+
export interface ReferenceObject extends AnyOtherAttribute {
731738
$ref: string
732-
[key: string]: any
733739
}
734740

735741
export type Response = ResponseObject | ReferenceObject
@@ -740,12 +746,11 @@ export namespace OpenAPIV2 {
740746

741747
export type Schema = SchemaObject | ReferenceObject
742748

743-
export interface ResponseObject {
749+
export interface ResponseObject extends AnyOtherAttribute {
744750
description?: string
745751
schema?: Schema
746752
headers?: HeadersObject
747753
examples?: ExampleObject
748-
[key: string]: any
749754
}
750755

751756
export interface HeadersObject {
@@ -760,9 +765,8 @@ export namespace OpenAPIV2 {
760765
[index: string]: any
761766
}
762767

763-
export type OperationObject<T extends {} = {}> = {
768+
export type OperationObject<T = {}> = {
764769
tags?: string[]
765-
[key: string]: any
766770
summary?: string
767771
description?: string
768772
externalDocs?: ExternalDocumentationObject
@@ -774,7 +778,8 @@ export namespace OpenAPIV2 {
774778
schemes?: string[]
775779
deprecated?: boolean
776780
security?: SecurityRequirementObject[]
777-
} & T
781+
} & T &
782+
AnyOtherAttribute
778783

779784
export interface ResponsesObject {
780785
[index: string]: Response | undefined
@@ -807,14 +812,14 @@ export namespace OpenAPIV2 {
807812
PATCH = 'patch',
808813
}
809814

810-
export type PathItemObject<T extends {} = {}> = {
815+
export type PathItemObject<T = {}> = {
811816
$ref?: string
812817
parameters?: Parameters
813818
} & {
814819
[method in HttpMethods]?: OperationObject<T>
815820
}
816821

817-
export interface PathsObject<T extends {} = {}> {
822+
export interface PathsObject<T = {}> {
818823
[index: string]: PathItemObject<T>
819824
}
820825

@@ -907,7 +912,7 @@ export namespace OpenAPIV2 {
907912
}
908913
}
909914

910-
export interface IJsonSchema {
915+
export interface IJsonSchema extends AnyOtherAttribute {
911916
id?: string
912917
$schema?: string
913918
title?: string

0 commit comments

Comments
 (0)