@skmtc/core 0.30.1 → 0.32.0
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/esm/context/generateTypes.d.ts +14 -2
- package/esm/context/generateTypes.js +3 -1
- package/esm/mod.d.ts +1 -0
- package/esm/mod.js +1 -0
- package/esm/oas/header/Header.d.ts +4 -2
- package/esm/oas/header/Header.js +12 -5
- package/esm/oas/mediaType/jsonMediaType.d.ts +50 -0
- package/esm/oas/mediaType/jsonMediaType.js +64 -0
- package/esm/oas/mediaType/toContentSchema.d.ts +8 -0
- package/esm/oas/mediaType/toContentSchema.js +6 -0
- package/esm/oas/operation/Operation.d.ts +10 -2
- package/esm/oas/operation/Operation.js +20 -7
- package/esm/oas/parameter/Parameter.d.ts +1 -1
- package/esm/oas/parameter/Parameter.js +7 -4
- package/esm/oas/pathItem/PathItem.d.ts +5 -0
- package/esm/oas/pathItem/PathItem.js +8 -0
- package/esm/oas/requestBody/RequestBody.d.ts +11 -0
- package/esm/oas/requestBody/RequestBody.js +16 -2
- package/esm/oas/response/Response.d.ts +11 -0
- package/esm/oas/response/Response.js +16 -2
- package/esm/oas/webhook/Webhook.d.ts +4 -4
- package/esm/oas/webhook/Webhook.js +6 -6
- package/esm/parse/logBodyMediaTypes.d.ts +27 -0
- package/esm/parse/logBodyMediaTypes.js +50 -0
- package/esm/parse/v3-0/parameter/toParameterV3.d.ts +3 -2
- package/esm/parse/v3-0/parameter/toParameterV3.js +3 -2
- package/esm/parse/v3-0/pathItem/toPathItemV3.js +11 -1
- package/esm/parse/v3-0/requestBody/toRequestBodiesV3.js +4 -1
- package/esm/parse/v3-0/response/toResponseV3.js +4 -1
- package/esm/parse/v3-1/parameter/toParameterV3.d.ts +3 -2
- package/esm/parse/v3-1/parameter/toParameterV3.js +3 -2
- package/esm/parse/v3-1/pathItem/toPathItemV3.js +11 -1
- package/esm/parse/v3-1/requestBody/toRequestBodiesV3.js +4 -1
- package/esm/parse/v3-1/response/toResponseV3.js +4 -1
- package/esm/parse/v3-2/parameter/toParameterV3.d.ts +2 -2
- package/esm/parse/v3-2/parameter/toParameterV3.js +3 -2
- package/esm/parse/v3-2/pathItem/toPathItemV3.js +11 -1
- package/esm/parse/v3-2/requestBody/toRequestBodiesV3.js +4 -1
- package/esm/parse/v3-2/response/toResponseV3.js +4 -1
- package/package.json +1 -1
- package/script/context/generateTypes.d.ts +14 -2
- package/script/context/generateTypes.js +3 -1
- package/script/mod.d.ts +1 -0
- package/script/mod.js +1 -0
- package/script/oas/header/Header.d.ts +4 -2
- package/script/oas/header/Header.js +12 -5
- package/script/oas/mediaType/jsonMediaType.d.ts +50 -0
- package/script/oas/mediaType/jsonMediaType.js +71 -0
- package/script/oas/mediaType/toContentSchema.d.ts +8 -0
- package/script/oas/mediaType/toContentSchema.js +10 -0
- package/script/oas/operation/Operation.d.ts +10 -2
- package/script/oas/operation/Operation.js +20 -7
- package/script/oas/parameter/Parameter.d.ts +1 -1
- package/script/oas/parameter/Parameter.js +7 -4
- package/script/oas/pathItem/PathItem.d.ts +5 -0
- package/script/oas/pathItem/PathItem.js +8 -0
- package/script/oas/requestBody/RequestBody.d.ts +11 -0
- package/script/oas/requestBody/RequestBody.js +16 -2
- package/script/oas/response/Response.d.ts +11 -0
- package/script/oas/response/Response.js +16 -2
- package/script/oas/webhook/Webhook.d.ts +4 -4
- package/script/oas/webhook/Webhook.js +6 -6
- package/script/parse/logBodyMediaTypes.d.ts +27 -0
- package/script/parse/logBodyMediaTypes.js +54 -0
- package/script/parse/v3-0/parameter/toParameterV3.d.ts +3 -2
- package/script/parse/v3-0/parameter/toParameterV3.js +3 -2
- package/script/parse/v3-0/pathItem/toPathItemV3.js +11 -1
- package/script/parse/v3-0/requestBody/toRequestBodiesV3.js +4 -1
- package/script/parse/v3-0/response/toResponseV3.js +4 -1
- package/script/parse/v3-1/parameter/toParameterV3.d.ts +3 -2
- package/script/parse/v3-1/parameter/toParameterV3.js +3 -2
- package/script/parse/v3-1/pathItem/toPathItemV3.js +11 -1
- package/script/parse/v3-1/requestBody/toRequestBodiesV3.js +4 -1
- package/script/parse/v3-1/response/toResponseV3.js +4 -1
- package/script/parse/v3-2/parameter/toParameterV3.d.ts +2 -2
- package/script/parse/v3-2/parameter/toParameterV3.js +3 -2
- package/script/parse/v3-2/pathItem/toPathItemV3.js +11 -1
- package/script/parse/v3-2/requestBody/toRequestBodiesV3.js +4 -1
- package/script/parse/v3-2/response/toResponseV3.js +4 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { isAnyMediaType, toJsonContent, toMediaTypeEssence } from '../oas/mediaType/jsonMediaType.js';
|
|
2
|
+
/**
|
|
3
|
+
* Log at most one issue for a parsed response or request body, from the same
|
|
4
|
+
* choice the lookups make (`toJsonContent`), so the issue and the lookup
|
|
5
|
+
* cannot disagree. Called after the body is built, so a body that fails to
|
|
6
|
+
* parse logs nothing.
|
|
7
|
+
*
|
|
8
|
+
* - `WILDCARD_MEDIA_TYPE` (`warning`): the body is read from `*\/*` as JSON,
|
|
9
|
+
* though the document does not say its format.
|
|
10
|
+
* - `NO_JSON_MEDIA_TYPE` (`debug`): no lookup reads the body, and its keys
|
|
11
|
+
* include a range (`*\/*` with a scalar schema, `application/*`), so its
|
|
12
|
+
* format is unknown.
|
|
13
|
+
*
|
|
14
|
+
* A body with only specific non-JSON types (`multipart/form-data`,
|
|
15
|
+
* `application/octet-stream`, `text/plain`) logs nothing: that is a normal
|
|
16
|
+
* text, form or binary body.
|
|
17
|
+
*/
|
|
18
|
+
export const logBodyMediaTypes = ({ content, stackTrail, context }) => {
|
|
19
|
+
const mediaTypes = Object.keys(content ?? {});
|
|
20
|
+
if (mediaTypes.length === 0) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const listed = mediaTypes.map(mediaType => `"${mediaType}"`).join(', ');
|
|
24
|
+
// `parent` is only the keys: the issue log serializes it on every issue.
|
|
25
|
+
const parent = { mediaTypes };
|
|
26
|
+
const chosen = toJsonContent(content);
|
|
27
|
+
if (chosen !== undefined) {
|
|
28
|
+
if (isAnyMediaType(chosen.mediaType)) {
|
|
29
|
+
context.logIssue({
|
|
30
|
+
key: 'content',
|
|
31
|
+
level: 'warning',
|
|
32
|
+
type: 'WILDCARD_MEDIA_TYPE',
|
|
33
|
+
message: `Content has no JSON media type (${listed}), so the body is read from "*/*" as JSON although the document does not say its format`,
|
|
34
|
+
parent,
|
|
35
|
+
stackTrail
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (mediaTypes.some(mediaType => toMediaTypeEssence(mediaType).includes('*'))) {
|
|
41
|
+
context.logIssue({
|
|
42
|
+
key: 'content',
|
|
43
|
+
level: 'debug',
|
|
44
|
+
type: 'NO_JSON_MEDIA_TYPE',
|
|
45
|
+
message: `Content names only a media type range or non-JSON types (${listed}), so no lookup without a media type reads its schema`,
|
|
46
|
+
parent,
|
|
47
|
+
stackTrail
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { ParseContextType } from '../../../context/parseTypes.js';
|
|
2
|
-
import type { OasParameterLocation } from '../../../oas/parameter/parameter-types.js';
|
|
2
|
+
import type { OasParameterLocation, OasParameterStyle } from '../../../oas/parameter/parameter-types.js';
|
|
3
3
|
import type { OpenAPIV3 } from 'openapi-types';
|
|
4
4
|
import { OasParameter } from '../../../oas/parameter/Parameter.js';
|
|
5
5
|
import type { OasRef } from '../../../oas/ref/Ref.js';
|
|
6
6
|
import type { StackTrail } from '../../../context/StackTrail.js';
|
|
7
7
|
type ParameterLocation = Exclude<OasParameterLocation, 'querystring'>;
|
|
8
|
+
type ParameterStyle = Exclude<OasParameterStyle, 'cookie'>;
|
|
8
9
|
export type ToParameterListV3Args = {
|
|
9
10
|
parameters: (OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject)[] | undefined;
|
|
10
11
|
stackTrail: StackTrail;
|
|
@@ -35,7 +36,7 @@ export type ToStyleArgs = {
|
|
|
35
36
|
};
|
|
36
37
|
export type ToExplodeArgs = {
|
|
37
38
|
explode: boolean | undefined;
|
|
38
|
-
style:
|
|
39
|
+
style: ParameterStyle;
|
|
39
40
|
stackTrail: StackTrail;
|
|
40
41
|
};
|
|
41
42
|
export {};
|
|
@@ -72,14 +72,15 @@ const toParameterV3 = ({ parameter, stackTrail, context }) => {
|
|
|
72
72
|
}
|
|
73
73
|
// Set missing 'required' to true for path parameters and false for others
|
|
74
74
|
const defaultRequired = typeof required === 'undefined' ? (parsedLocation === 'path' ? true : false) : required;
|
|
75
|
+
const parsedStyle = stackTrail.trace('style', st => toStyle({ style, location: parsedLocation, stackTrail: st }));
|
|
75
76
|
const fields = {
|
|
76
77
|
name,
|
|
77
78
|
location: parsedLocation,
|
|
78
79
|
description,
|
|
79
80
|
required: defaultRequired,
|
|
80
81
|
deprecated,
|
|
81
|
-
style:
|
|
82
|
-
explode: stackTrail.trace('explode', st => toExplode({ explode, style, stackTrail: st })),
|
|
82
|
+
style: parsedStyle,
|
|
83
|
+
explode: stackTrail.trace('explode', st => toExplode({ explode, style: parsedStyle, stackTrail: st })),
|
|
83
84
|
allowEmptyValue,
|
|
84
85
|
allowReserved,
|
|
85
86
|
schema: stackTrail.trace('schema', st => toOptionalSchemaV3({ schema, stackTrail: st, context })),
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import { toParameterListV3 } from '../parameter/toParameterV3.js';
|
|
2
2
|
import { OasPathItem } from '../../../oas/pathItem/PathItem.js';
|
|
3
|
+
import { toOptionalServersV3 } from '../server/toServerV3.js';
|
|
4
|
+
import { tryParseAt } from '../../../context/tryParseAt.js';
|
|
3
5
|
import { toSpecificationExtensionsV3 } from '../specificationExtensions/toSpecificationExtensionsV3.js';
|
|
4
6
|
export const toPathItemV3 = ({ pathItem, stackTrail, context }) => {
|
|
5
|
-
const { summary, description, parameters, ...skipped } = pathItem;
|
|
7
|
+
const { summary, description, parameters, servers, ...skipped } = pathItem;
|
|
6
8
|
return new OasPathItem({
|
|
7
9
|
summary,
|
|
8
10
|
description,
|
|
9
11
|
parameters: stackTrail.trace('parameters', st => toParameterListV3({ parameters, stackTrail: st, context })),
|
|
12
|
+
servers: tryParseAt({
|
|
13
|
+
stackTrail,
|
|
14
|
+
key: 'servers',
|
|
15
|
+
context,
|
|
16
|
+
type: 'INVALID_OPERATION',
|
|
17
|
+
parent: pathItem,
|
|
18
|
+
fn: st => toOptionalServersV3({ servers, stackTrail: st, context })
|
|
19
|
+
}),
|
|
10
20
|
extensionFields: toSpecificationExtensionsV3({
|
|
11
21
|
skipped,
|
|
12
22
|
parent: pathItem,
|
|
@@ -3,6 +3,7 @@ import { toRefV31 } from '../ref/toRefV31.js';
|
|
|
3
3
|
import { toMediaTypeItemsV3 } from '../mediaType/toMediaTypeItemV3.js';
|
|
4
4
|
import { OasRequestBody } from '../../../oas/requestBody/RequestBody.js';
|
|
5
5
|
import { toSpecificationExtensionsV3 } from '../specificationExtensions/toSpecificationExtensionsV3.js';
|
|
6
|
+
import { logBodyMediaTypes } from '../../logBodyMediaTypes.js';
|
|
6
7
|
export const toRequestBodyV3 = ({ requestBody, stackTrail, context }) => {
|
|
7
8
|
if (!requestBody) {
|
|
8
9
|
return undefined;
|
|
@@ -26,7 +27,9 @@ export const toRequestBodyV3 = ({ requestBody, stackTrail, context }) => {
|
|
|
26
27
|
required,
|
|
27
28
|
extensionFields
|
|
28
29
|
};
|
|
29
|
-
|
|
30
|
+
const parsed = context.withStackTrail(stackTrail, () => new OasRequestBody(fields, context));
|
|
31
|
+
logBodyMediaTypes({ content: fields.content, stackTrail, context });
|
|
32
|
+
return parsed;
|
|
30
33
|
};
|
|
31
34
|
export const toRequestBodiesV3 = ({ requestBodies, stackTrail, context }) => {
|
|
32
35
|
if (!requestBodies) {
|
|
@@ -6,6 +6,7 @@ import { toOptionalMediaTypeItemsV3 } from '../mediaType/toMediaTypeItemV3.js';
|
|
|
6
6
|
import { OasResponse } from '../../../oas/response/Response.js';
|
|
7
7
|
import { toSpecificationExtensionsV3 } from '../specificationExtensions/toSpecificationExtensionsV3.js';
|
|
8
8
|
import { tryParseAt } from '../../../context/tryParseAt.js';
|
|
9
|
+
import { logBodyMediaTypes } from '../../logBodyMediaTypes.js';
|
|
9
10
|
export const toResponsesV3 = ({ responses, stackTrail, context }) => {
|
|
10
11
|
const output = {};
|
|
11
12
|
const entries = Object.entries(responses);
|
|
@@ -45,11 +46,13 @@ export const toResponseV3 = ({ response, stackTrail, context }) => {
|
|
|
45
46
|
const parsedHeaders = stackTrail.trace('headers', st => toHeadersV3({ headers, stackTrail: st, context }));
|
|
46
47
|
const parsedLinks = stackTrail.trace('links', st => toLinksV3({ links, stackTrail: st, context }));
|
|
47
48
|
const parsedContent = stackTrail.trace('content', st => toOptionalMediaTypeItemsV3({ content, stackTrail: st, context }));
|
|
48
|
-
|
|
49
|
+
const parsed = context.withStackTrail(stackTrail, () => new OasResponse({
|
|
49
50
|
description,
|
|
50
51
|
headers: parsedHeaders,
|
|
51
52
|
links: parsedLinks,
|
|
52
53
|
content: parsedContent,
|
|
53
54
|
extensionFields
|
|
54
55
|
}, context));
|
|
56
|
+
logBodyMediaTypes({ content: parsedContent, stackTrail, context });
|
|
57
|
+
return parsed;
|
|
55
58
|
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { ParseContextType } from '../../../context/parseTypes.js';
|
|
2
|
-
import type { OasParameterLocation } from '../../../oas/parameter/parameter-types.js';
|
|
2
|
+
import type { OasParameterLocation, OasParameterStyle } from '../../../oas/parameter/parameter-types.js';
|
|
3
3
|
import type { OpenAPIV3 } from 'openapi-types';
|
|
4
4
|
import { OasParameter } from '../../../oas/parameter/Parameter.js';
|
|
5
5
|
import type { OasRef } from '../../../oas/ref/Ref.js';
|
|
6
6
|
import type { StackTrail } from '../../../context/StackTrail.js';
|
|
7
7
|
type ParameterLocation = Exclude<OasParameterLocation, 'querystring'>;
|
|
8
|
+
type ParameterStyle = Exclude<OasParameterStyle, 'cookie'>;
|
|
8
9
|
export type ToParameterListV3Args = {
|
|
9
10
|
parameters: (OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject)[] | undefined;
|
|
10
11
|
stackTrail: StackTrail;
|
|
@@ -35,7 +36,7 @@ export type ToStyleArgs = {
|
|
|
35
36
|
};
|
|
36
37
|
export type ToExplodeArgs = {
|
|
37
38
|
explode: boolean | undefined;
|
|
38
|
-
style:
|
|
39
|
+
style: ParameterStyle;
|
|
39
40
|
stackTrail: StackTrail;
|
|
40
41
|
};
|
|
41
42
|
export {};
|
|
@@ -72,14 +72,15 @@ const toParameterV3 = ({ parameter, stackTrail, context }) => {
|
|
|
72
72
|
}
|
|
73
73
|
// Set missing 'required' to true for path parameters and false for others
|
|
74
74
|
const defaultRequired = typeof required === 'undefined' ? (parsedLocation === 'path' ? true : false) : required;
|
|
75
|
+
const parsedStyle = stackTrail.trace('style', st => toStyle({ style, location: parsedLocation, stackTrail: st }));
|
|
75
76
|
const fields = {
|
|
76
77
|
name,
|
|
77
78
|
location: parsedLocation,
|
|
78
79
|
description,
|
|
79
80
|
required: defaultRequired,
|
|
80
81
|
deprecated,
|
|
81
|
-
style:
|
|
82
|
-
explode: stackTrail.trace('explode', st => toExplode({ explode, style, stackTrail: st })),
|
|
82
|
+
style: parsedStyle,
|
|
83
|
+
explode: stackTrail.trace('explode', st => toExplode({ explode, style: parsedStyle, stackTrail: st })),
|
|
83
84
|
allowEmptyValue,
|
|
84
85
|
allowReserved,
|
|
85
86
|
schema: stackTrail.trace('schema', st => toOptionalSchemaV3({ schema, stackTrail: st, context })),
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import { toParameterListV3 } from '../parameter/toParameterV3.js';
|
|
2
2
|
import { OasPathItem } from '../../../oas/pathItem/PathItem.js';
|
|
3
|
+
import { toOptionalServersV3 } from '../server/toServerV3.js';
|
|
4
|
+
import { tryParseAt } from '../../../context/tryParseAt.js';
|
|
3
5
|
import { toSpecificationExtensionsV3 } from '../specificationExtensions/toSpecificationExtensionsV3.js';
|
|
4
6
|
export const toPathItemV3 = ({ pathItem, stackTrail, context }) => {
|
|
5
|
-
const { summary, description, parameters, ...skipped } = pathItem;
|
|
7
|
+
const { summary, description, parameters, servers, ...skipped } = pathItem;
|
|
6
8
|
return new OasPathItem({
|
|
7
9
|
summary,
|
|
8
10
|
description,
|
|
9
11
|
parameters: stackTrail.trace('parameters', st => toParameterListV3({ parameters, stackTrail: st, context })),
|
|
12
|
+
servers: tryParseAt({
|
|
13
|
+
stackTrail,
|
|
14
|
+
key: 'servers',
|
|
15
|
+
context,
|
|
16
|
+
type: 'INVALID_OPERATION',
|
|
17
|
+
parent: pathItem,
|
|
18
|
+
fn: st => toOptionalServersV3({ servers, stackTrail: st, context })
|
|
19
|
+
}),
|
|
10
20
|
extensionFields: toSpecificationExtensionsV3({
|
|
11
21
|
skipped,
|
|
12
22
|
parent: pathItem,
|
|
@@ -3,6 +3,7 @@ import { toRefV31 } from '../ref/toRefV31.js';
|
|
|
3
3
|
import { toMediaTypeItemsV3 } from '../mediaType/toMediaTypeItemV3.js';
|
|
4
4
|
import { OasRequestBody } from '../../../oas/requestBody/RequestBody.js';
|
|
5
5
|
import { toSpecificationExtensionsV3 } from '../specificationExtensions/toSpecificationExtensionsV3.js';
|
|
6
|
+
import { logBodyMediaTypes } from '../../logBodyMediaTypes.js';
|
|
6
7
|
export const toRequestBodyV3 = ({ requestBody, stackTrail, context }) => {
|
|
7
8
|
if (!requestBody) {
|
|
8
9
|
return undefined;
|
|
@@ -26,7 +27,9 @@ export const toRequestBodyV3 = ({ requestBody, stackTrail, context }) => {
|
|
|
26
27
|
required,
|
|
27
28
|
extensionFields
|
|
28
29
|
};
|
|
29
|
-
|
|
30
|
+
const parsed = context.withStackTrail(stackTrail, () => new OasRequestBody(fields, context));
|
|
31
|
+
logBodyMediaTypes({ content: fields.content, stackTrail, context });
|
|
32
|
+
return parsed;
|
|
30
33
|
};
|
|
31
34
|
export const toRequestBodiesV3 = ({ requestBodies, stackTrail, context }) => {
|
|
32
35
|
if (!requestBodies) {
|
|
@@ -6,6 +6,7 @@ import { toOptionalMediaTypeItemsV3 } from '../mediaType/toMediaTypeItemV3.js';
|
|
|
6
6
|
import { OasResponse } from '../../../oas/response/Response.js';
|
|
7
7
|
import { toSpecificationExtensionsV3 } from '../specificationExtensions/toSpecificationExtensionsV3.js';
|
|
8
8
|
import { tryParseAt } from '../../../context/tryParseAt.js';
|
|
9
|
+
import { logBodyMediaTypes } from '../../logBodyMediaTypes.js';
|
|
9
10
|
export const toResponsesV3 = ({ responses, stackTrail, context }) => {
|
|
10
11
|
const output = {};
|
|
11
12
|
const entries = Object.entries(responses);
|
|
@@ -45,11 +46,13 @@ export const toResponseV3 = ({ response, stackTrail, context }) => {
|
|
|
45
46
|
const parsedHeaders = stackTrail.trace('headers', st => toHeadersV3({ headers, stackTrail: st, context }));
|
|
46
47
|
const parsedLinks = stackTrail.trace('links', st => toLinksV3({ links, stackTrail: st, context }));
|
|
47
48
|
const parsedContent = stackTrail.trace('content', st => toOptionalMediaTypeItemsV3({ content, stackTrail: st, context }));
|
|
48
|
-
|
|
49
|
+
const parsed = context.withStackTrail(stackTrail, () => new OasResponse({
|
|
49
50
|
description,
|
|
50
51
|
headers: parsedHeaders,
|
|
51
52
|
links: parsedLinks,
|
|
52
53
|
content: parsedContent,
|
|
53
54
|
extensionFields
|
|
54
55
|
}, context));
|
|
56
|
+
logBodyMediaTypes({ content: parsedContent, stackTrail, context });
|
|
57
|
+
return parsed;
|
|
55
58
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ParseContextType } from '../../../context/parseTypes.js';
|
|
2
|
-
import { type OasParameterLocation } from '../../../oas/parameter/parameter-types.js';
|
|
2
|
+
import { type OasParameterLocation, type OasParameterStyle } from '../../../oas/parameter/parameter-types.js';
|
|
3
3
|
import type { OpenAPIV3 } from 'openapi-types';
|
|
4
4
|
import { OasParameter } from '../../../oas/parameter/Parameter.js';
|
|
5
5
|
import type { OasRef } from '../../../oas/ref/Ref.js';
|
|
@@ -34,6 +34,6 @@ export type ToStyleArgs = {
|
|
|
34
34
|
};
|
|
35
35
|
export type ToExplodeArgs = {
|
|
36
36
|
explode: boolean | undefined;
|
|
37
|
-
style:
|
|
37
|
+
style: OasParameterStyle | undefined;
|
|
38
38
|
stackTrail: StackTrail;
|
|
39
39
|
};
|
|
@@ -91,14 +91,15 @@ const toParameterV3 = ({ parameter, stackTrail, context }) => {
|
|
|
91
91
|
}
|
|
92
92
|
// Set missing 'required' to true for path parameters and false for others
|
|
93
93
|
const defaultRequired = typeof required === 'undefined' ? (parsedLocation === 'path' ? true : false) : required;
|
|
94
|
+
const parsedStyle = stackTrail.trace('style', st => toStyle({ style, location: parsedLocation, stackTrail: st }));
|
|
94
95
|
const fields = {
|
|
95
96
|
name,
|
|
96
97
|
location: parsedLocation,
|
|
97
98
|
description,
|
|
98
99
|
required: defaultRequired,
|
|
99
100
|
deprecated,
|
|
100
|
-
style:
|
|
101
|
-
explode: stackTrail.trace('explode', st => toExplode({ explode, style, stackTrail: st })),
|
|
101
|
+
style: parsedStyle,
|
|
102
|
+
explode: stackTrail.trace('explode', st => toExplode({ explode, style: parsedStyle, stackTrail: st })),
|
|
102
103
|
allowEmptyValue,
|
|
103
104
|
allowReserved,
|
|
104
105
|
schema: stackTrail.trace('schema', st => toOptionalSchemaV3({ schema, stackTrail: st, context })),
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
import { toParameterListV3 } from '../parameter/toParameterV3.js';
|
|
2
2
|
import { OasPathItem } from '../../../oas/pathItem/PathItem.js';
|
|
3
|
+
import { toOptionalServersV3 } from '../server/toServerV3.js';
|
|
4
|
+
import { tryParseAt } from '../../../context/tryParseAt.js';
|
|
3
5
|
import { toSpecificationExtensionsV3 } from '../specificationExtensions/toSpecificationExtensionsV3.js';
|
|
4
6
|
import { isEmpty } from '../../../helpers/isEmpty.js';
|
|
5
7
|
export const toPathItemV3 = ({ pathItem, stackTrail, context }) => {
|
|
6
|
-
const { summary, description, parameters, ...skipped } = pathItem;
|
|
8
|
+
const { summary, description, parameters, servers, ...skipped } = pathItem;
|
|
7
9
|
return new OasPathItem({
|
|
8
10
|
summary,
|
|
9
11
|
description,
|
|
10
12
|
parameters: stackTrail.trace('parameters', st => toParameterListV3({ parameters, stackTrail: st, context })),
|
|
13
|
+
servers: tryParseAt({
|
|
14
|
+
stackTrail,
|
|
15
|
+
key: 'servers',
|
|
16
|
+
context,
|
|
17
|
+
type: 'INVALID_OPERATION',
|
|
18
|
+
parent: pathItem,
|
|
19
|
+
fn: st => toOptionalServersV3({ servers, stackTrail: st, context })
|
|
20
|
+
}),
|
|
11
21
|
extensionFields: toSpecificationExtensionsV3({
|
|
12
22
|
skipped,
|
|
13
23
|
parent: pathItem,
|
|
@@ -3,6 +3,7 @@ import { toRefV31 } from '../ref/toRefV31.js';
|
|
|
3
3
|
import { toMediaTypeItemsV3 } from '../mediaType/toMediaTypeItemV3.js';
|
|
4
4
|
import { OasRequestBody } from '../../../oas/requestBody/RequestBody.js';
|
|
5
5
|
import { toSpecificationExtensionsV3 } from '../specificationExtensions/toSpecificationExtensionsV3.js';
|
|
6
|
+
import { logBodyMediaTypes } from '../../logBodyMediaTypes.js';
|
|
6
7
|
export const toRequestBodyV3 = ({ requestBody, stackTrail, context }) => {
|
|
7
8
|
if (!requestBody) {
|
|
8
9
|
return undefined;
|
|
@@ -26,7 +27,9 @@ export const toRequestBodyV3 = ({ requestBody, stackTrail, context }) => {
|
|
|
26
27
|
required,
|
|
27
28
|
extensionFields
|
|
28
29
|
};
|
|
29
|
-
|
|
30
|
+
const parsed = context.withStackTrail(stackTrail, () => new OasRequestBody(fields, context));
|
|
31
|
+
logBodyMediaTypes({ content: fields.content, stackTrail, context });
|
|
32
|
+
return parsed;
|
|
30
33
|
};
|
|
31
34
|
export const toRequestBodiesV3 = ({ requestBodies, stackTrail, context }) => {
|
|
32
35
|
if (!requestBodies) {
|
|
@@ -6,6 +6,7 @@ import { toOptionalMediaTypeItemsV3 } from '../mediaType/toMediaTypeItemV3.js';
|
|
|
6
6
|
import { OasResponse } from '../../../oas/response/Response.js';
|
|
7
7
|
import { toSpecificationExtensionsV3 } from '../specificationExtensions/toSpecificationExtensionsV3.js';
|
|
8
8
|
import { tryParseAt } from '../../../context/tryParseAt.js';
|
|
9
|
+
import { logBodyMediaTypes } from '../../logBodyMediaTypes.js';
|
|
9
10
|
export const toResponsesV3 = ({ responses, stackTrail, context }) => {
|
|
10
11
|
const output = {};
|
|
11
12
|
const entries = Object.entries(responses);
|
|
@@ -45,7 +46,7 @@ export const toResponseV3 = ({ response, stackTrail, context }) => {
|
|
|
45
46
|
const parsedHeaders = stackTrail.trace('headers', st => toHeadersV3({ headers, stackTrail: st, context }));
|
|
46
47
|
const parsedLinks = stackTrail.trace('links', st => toLinksV3({ links, stackTrail: st, context }));
|
|
47
48
|
const parsedContent = stackTrail.trace('content', st => toOptionalMediaTypeItemsV3({ content, stackTrail: st, context }));
|
|
48
|
-
|
|
49
|
+
const parsed = context.withStackTrail(stackTrail, () => new OasResponse({
|
|
49
50
|
summary,
|
|
50
51
|
description,
|
|
51
52
|
headers: parsedHeaders,
|
|
@@ -53,4 +54,6 @@ export const toResponseV3 = ({ response, stackTrail, context }) => {
|
|
|
53
54
|
content: parsedContent,
|
|
54
55
|
extensionFields
|
|
55
56
|
}, context));
|
|
57
|
+
logBodyMediaTypes({ content: parsedContent, stackTrail, context });
|
|
58
|
+
return parsed;
|
|
56
59
|
};
|
package/package.json
CHANGED
|
@@ -154,8 +154,20 @@ export type AnyOasDocument = OpenAPIV2.Document | OpenAPIV3.Document | OpenAPIV3
|
|
|
154
154
|
* The TS type and the valibot schema below stay in sync via the
|
|
155
155
|
* `v.GenericSchema<OasIssueType>` annotation — adding a variant in one
|
|
156
156
|
* place without the other fails to type-check.
|
|
157
|
+
*
|
|
158
|
+
* Media type issues, at most one per response or request body, from the
|
|
159
|
+
* choice `toJsonContent` makes on its parsed `content`:
|
|
160
|
+
*
|
|
161
|
+
* - `WILDCARD_MEDIA_TYPE` (`warning`) — the body has no JSON media type
|
|
162
|
+
* (see `isJsonMediaType`) and is read from `*\/*` as JSON, since its schema
|
|
163
|
+
* there is an object, array, union or `$ref`. The document does not say the
|
|
164
|
+
* format; springdoc writes `*\/*` for every response.
|
|
165
|
+
* - `NO_JSON_MEDIA_TYPE` (`debug`) — no lookup without a media type reads the
|
|
166
|
+
* body, and its keys include a range: `application/*`, or `*\/*` with a
|
|
167
|
+
* scalar schema (a text body or a file). A body with only specific
|
|
168
|
+
* non-JSON types (`multipart/form-data`, `text/plain`) logs nothing.
|
|
157
169
|
*/
|
|
158
|
-
export type OasIssueType = 'UNEXPECTED_PROPERTY' | 'MISSING_OBJECT_TYPE' | 'MISSING_STRING_TYPE' | 'MISSING_ARRAY_TYPE' | 'MISSING_BOOLEAN_TYPE' | 'INVALID_EXAMPLE' | 'INVALID_ENUM' | 'INVALID_DEFAULT' | 'INVALID_NULLABLE' | 'UNEXPECTED_FORMAT' | 'INVALID_RESPONSE' | 'INVALID_FORMAT' | 'INVALID_OPERATION' | 'INVALID_SCHEMA' | 'INVALID_PARAMETER' | 'INVALID_SECURITY_SCHEME' | 'INVALID_DEPENDENCY_REF' | 'EXAMPLE_AND_EXAMPLES_DEFINED' | 'INVALID_TAG_PARENT' | 'UNSUPPORTED_OPERATION_METHOD';
|
|
170
|
+
export type OasIssueType = 'UNEXPECTED_PROPERTY' | 'MISSING_OBJECT_TYPE' | 'MISSING_STRING_TYPE' | 'MISSING_ARRAY_TYPE' | 'MISSING_BOOLEAN_TYPE' | 'INVALID_EXAMPLE' | 'INVALID_ENUM' | 'INVALID_DEFAULT' | 'INVALID_NULLABLE' | 'UNEXPECTED_FORMAT' | 'INVALID_RESPONSE' | 'INVALID_FORMAT' | 'INVALID_OPERATION' | 'INVALID_SCHEMA' | 'INVALID_PARAMETER' | 'INVALID_SECURITY_SCHEME' | 'INVALID_DEPENDENCY_REF' | 'EXAMPLE_AND_EXAMPLES_DEFINED' | 'INVALID_TAG_PARENT' | 'UNSUPPORTED_OPERATION_METHOD' | 'WILDCARD_MEDIA_TYPE' | 'NO_JSON_MEDIA_TYPE';
|
|
159
171
|
/**
|
|
160
172
|
* Valibot schema for {@link OasIssueType}. Annotation deliberately omitted
|
|
161
173
|
* so the precise literal-union output type flows through to consumers
|
|
@@ -163,7 +175,7 @@ export type OasIssueType = 'UNEXPECTED_PROPERTY' | 'MISSING_OBJECT_TYPE' | 'MISS
|
|
|
163
175
|
* this list and {@link OasIssueType} is caught by `assertSchemaMatchesType`
|
|
164
176
|
* below.
|
|
165
177
|
*/
|
|
166
|
-
export declare const oasIssueType: v.UnionSchema<[v.LiteralSchema<"UNEXPECTED_PROPERTY", undefined>, v.LiteralSchema<"MISSING_OBJECT_TYPE", undefined>, v.LiteralSchema<"MISSING_STRING_TYPE", undefined>, v.LiteralSchema<"MISSING_ARRAY_TYPE", undefined>, v.LiteralSchema<"MISSING_BOOLEAN_TYPE", undefined>, v.LiteralSchema<"INVALID_EXAMPLE", undefined>, v.LiteralSchema<"INVALID_ENUM", undefined>, v.LiteralSchema<"INVALID_DEFAULT", undefined>, v.LiteralSchema<"INVALID_NULLABLE", undefined>, v.LiteralSchema<"UNEXPECTED_FORMAT", undefined>, v.LiteralSchema<"INVALID_RESPONSE", undefined>, v.LiteralSchema<"INVALID_FORMAT", undefined>, v.LiteralSchema<"INVALID_OPERATION", undefined>, v.LiteralSchema<"INVALID_SCHEMA", undefined>, v.LiteralSchema<"INVALID_PARAMETER", undefined>, v.LiteralSchema<"INVALID_SECURITY_SCHEME", undefined>, v.LiteralSchema<"INVALID_DEPENDENCY_REF", undefined>, v.LiteralSchema<"EXAMPLE_AND_EXAMPLES_DEFINED", undefined>, v.LiteralSchema<"INVALID_TAG_PARENT", undefined>, v.LiteralSchema<"UNSUPPORTED_OPERATION_METHOD", undefined>], undefined>;
|
|
178
|
+
export declare const oasIssueType: v.UnionSchema<[v.LiteralSchema<"UNEXPECTED_PROPERTY", undefined>, v.LiteralSchema<"MISSING_OBJECT_TYPE", undefined>, v.LiteralSchema<"MISSING_STRING_TYPE", undefined>, v.LiteralSchema<"MISSING_ARRAY_TYPE", undefined>, v.LiteralSchema<"MISSING_BOOLEAN_TYPE", undefined>, v.LiteralSchema<"INVALID_EXAMPLE", undefined>, v.LiteralSchema<"INVALID_ENUM", undefined>, v.LiteralSchema<"INVALID_DEFAULT", undefined>, v.LiteralSchema<"INVALID_NULLABLE", undefined>, v.LiteralSchema<"UNEXPECTED_FORMAT", undefined>, v.LiteralSchema<"INVALID_RESPONSE", undefined>, v.LiteralSchema<"INVALID_FORMAT", undefined>, v.LiteralSchema<"INVALID_OPERATION", undefined>, v.LiteralSchema<"INVALID_SCHEMA", undefined>, v.LiteralSchema<"INVALID_PARAMETER", undefined>, v.LiteralSchema<"INVALID_SECURITY_SCHEME", undefined>, v.LiteralSchema<"INVALID_DEPENDENCY_REF", undefined>, v.LiteralSchema<"EXAMPLE_AND_EXAMPLES_DEFINED", undefined>, v.LiteralSchema<"INVALID_TAG_PARENT", undefined>, v.LiteralSchema<"UNSUPPORTED_OPERATION_METHOD", undefined>, v.LiteralSchema<"WILDCARD_MEDIA_TYPE", undefined>, v.LiteralSchema<"NO_JSON_MEDIA_TYPE", undefined>], undefined>;
|
|
167
179
|
export type GenerateResult = {
|
|
168
180
|
files: Map<string, FileBase>;
|
|
169
181
|
previews: Record<string, Preview>;
|
|
@@ -62,7 +62,9 @@ exports.oasIssueType = v.union([
|
|
|
62
62
|
v.literal('INVALID_DEPENDENCY_REF'),
|
|
63
63
|
v.literal('EXAMPLE_AND_EXAMPLES_DEFINED'),
|
|
64
64
|
v.literal('INVALID_TAG_PARENT'),
|
|
65
|
-
v.literal('UNSUPPORTED_OPERATION_METHOD')
|
|
65
|
+
v.literal('UNSUPPORTED_OPERATION_METHOD'),
|
|
66
|
+
v.literal('WILDCARD_MEDIA_TYPE'),
|
|
67
|
+
v.literal('NO_JSON_MEDIA_TYPE')
|
|
66
68
|
]);
|
|
67
69
|
// Compile-time drift detector: this binding fails to type-check if
|
|
68
70
|
// `OasIssueType` and the literal list above disagree in either
|
package/script/mod.d.ts
CHANGED
|
@@ -146,6 +146,7 @@ export * from './oas/info/info-types.js';
|
|
|
146
146
|
export * from './oas/license/License.js';
|
|
147
147
|
export * from './oas/license/license-types.js';
|
|
148
148
|
export * from './oas/mediaType/MediaType.js';
|
|
149
|
+
export * from './oas/mediaType/jsonMediaType.js';
|
|
149
150
|
export * from './oas/integer/Integer.js';
|
|
150
151
|
export * from './oas/integer/integer-types.js';
|
|
151
152
|
export * from './parse/v3-0/integer/toInteger.js';
|
package/script/mod.js
CHANGED
|
@@ -162,6 +162,7 @@ __exportStar(require("./oas/info/info-types.js"), exports);
|
|
|
162
162
|
__exportStar(require("./oas/license/License.js"), exports);
|
|
163
163
|
__exportStar(require("./oas/license/license-types.js"), exports);
|
|
164
164
|
__exportStar(require("./oas/mediaType/MediaType.js"), exports);
|
|
165
|
+
__exportStar(require("./oas/mediaType/jsonMediaType.js"), exports);
|
|
165
166
|
__exportStar(require("./oas/integer/Integer.js"), exports);
|
|
166
167
|
__exportStar(require("./oas/integer/integer-types.js"), exports);
|
|
167
168
|
__exportStar(require("./parse/v3-0/integer/toInteger.js"), exports);
|
|
@@ -77,9 +77,11 @@ export declare class OasHeader {
|
|
|
77
77
|
resolve(): OasHeader;
|
|
78
78
|
resolveOnce(): OasHeader;
|
|
79
79
|
/** Returns schema for the header. Either, `schema` property if
|
|
80
|
-
*
|
|
80
|
+
* defined or value matching `mediaType` from `content` property. When
|
|
81
|
+
* `content` has exactly one entry (the spec requires one), its schema is
|
|
82
|
+
* used whatever the media type, as in `OasParameter.toSchema`.
|
|
81
83
|
*
|
|
82
|
-
* @param mediaType - Optional media type to get schema for.
|
|
84
|
+
* @param mediaType - Optional media type to get schema for, an exact lookup. Omitted: the JSON media type (`application/json`, else the first JSON-like type, else `*\/*`).
|
|
83
85
|
*/
|
|
84
86
|
toSchema(mediaType?: string): OasSchema | OasRef<'schema'>;
|
|
85
87
|
toJsonSchema(options: ToJsonSchemaOptions): OpenAPIV3.HeaderObject;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.OasHeader = void 0;
|
|
4
|
+
const toContentSchema_js_1 = require("../mediaType/toContentSchema.js");
|
|
4
5
|
/**
|
|
5
6
|
* Represents a Header Object in the OpenAPI Specification.
|
|
6
7
|
*
|
|
@@ -109,17 +110,23 @@ class OasHeader {
|
|
|
109
110
|
return this;
|
|
110
111
|
}
|
|
111
112
|
/** Returns schema for the header. Either, `schema` property if
|
|
112
|
-
*
|
|
113
|
+
* defined or value matching `mediaType` from `content` property. When
|
|
114
|
+
* `content` has exactly one entry (the spec requires one), its schema is
|
|
115
|
+
* used whatever the media type, as in `OasParameter.toSchema`.
|
|
113
116
|
*
|
|
114
|
-
* @param mediaType - Optional media type to get schema for.
|
|
117
|
+
* @param mediaType - Optional media type to get schema for, an exact lookup. Omitted: the JSON media type (`application/json`, else the first JSON-like type, else `*\/*`).
|
|
115
118
|
*/
|
|
116
|
-
toSchema(mediaType
|
|
119
|
+
toSchema(mediaType) {
|
|
117
120
|
if (this.schema) {
|
|
118
121
|
return this.schema;
|
|
119
122
|
}
|
|
120
|
-
const
|
|
123
|
+
const contentEntries = Object.values(this.content ?? {});
|
|
124
|
+
const onlyEntry = contentEntries.length === 1 ? contentEntries[0] : undefined;
|
|
125
|
+
const schema = (0, toContentSchema_js_1.toContentSchema)(this.content, mediaType) ?? onlyEntry?.schema;
|
|
121
126
|
if (!schema) {
|
|
122
|
-
throw new Error(
|
|
127
|
+
throw new Error(mediaType === undefined
|
|
128
|
+
? 'Schema not found for a JSON media type'
|
|
129
|
+
: `Schema not found for media type "${mediaType}"`);
|
|
123
130
|
}
|
|
124
131
|
return schema;
|
|
125
132
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { OasRef } from '../ref/Ref.js';
|
|
2
|
+
import type { OasSchema } from '../schema/Schema.js';
|
|
3
|
+
import type { OasMediaType } from './MediaType.js';
|
|
4
|
+
/**
|
|
5
|
+
* The media type without its parameters, trimmed and lowercased:
|
|
6
|
+
* `Application/JSON; charset=utf-8` → `application/json`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const toMediaTypeEssence: (mediaType: string) => string;
|
|
9
|
+
/**
|
|
10
|
+
* True when a body of this media type is one JSON value: `application/json`,
|
|
11
|
+
* or any `application/…+json` (the RFC 6839 structured syntax suffix, e.g.
|
|
12
|
+
* `application/vnd.api+json`, `application/ld+json`,
|
|
13
|
+
* `application/problem+json`). Parameters and case are ignored, so
|
|
14
|
+
* `application/json;v=1.0` is JSON.
|
|
15
|
+
*
|
|
16
|
+
* False for everything else, including:
|
|
17
|
+
* - `text/json`: not registered; RFC 8259 registers only `application/json`.
|
|
18
|
+
* - `application/x-ndjson`, `application/jsonl`: a stream of JSON values, not
|
|
19
|
+
* one value.
|
|
20
|
+
* - ranges such as `*\/*`, `application/*` and `application/*+json`: they do
|
|
21
|
+
* not name one type.
|
|
22
|
+
* - names without the suffix, such as `application/vnd.goa.error`, even when
|
|
23
|
+
* the API sends JSON under them.
|
|
24
|
+
*/
|
|
25
|
+
export declare const isJsonMediaType: (mediaType: string) => boolean;
|
|
26
|
+
/** True when the media type is the full range `*\/*`, parameters and case ignored. */
|
|
27
|
+
export declare const isAnyMediaType: (mediaType: string) => boolean;
|
|
28
|
+
/** The media type a body is read from, and its schema. */
|
|
29
|
+
export type JsonContent = {
|
|
30
|
+
/** The key in `content`: a JSON-like media type, or `*\/*` (with any parameters). */
|
|
31
|
+
mediaType: string;
|
|
32
|
+
/**
|
|
33
|
+
* The media type to send or expect the body as: `mediaType` when it is
|
|
34
|
+
* JSON-like, `application/json` when the body is read from `*\/*`.
|
|
35
|
+
*/
|
|
36
|
+
contentType: string;
|
|
37
|
+
schema: OasSchema | OasRef<'schema'> | undefined;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Choose the media type a body is read from: `application/json` exactly when
|
|
41
|
+
* it is a key, else the first JSON-like key in document order (see
|
|
42
|
+
* {@link isJsonMediaType}), else the `*\/*` key when its schema is an object,
|
|
43
|
+
* array, union or `$ref`. `*\/*` admits JSON, and documents use it for JSON
|
|
44
|
+
* bodies (springdoc writes it for every response); the parser logs
|
|
45
|
+
* `WILDCARD_MEDIA_TYPE` for every body read this way. `undefined` otherwise:
|
|
46
|
+
* there is no fall back to a specific non-JSON type, to a narrower range such
|
|
47
|
+
* as `application/*`, or to a scalar schema under `*\/*`, since a consumer
|
|
48
|
+
* would read that body as JSON.
|
|
49
|
+
*/
|
|
50
|
+
export declare const toJsonContent: (content: Record<string, OasMediaType> | undefined) => JsonContent | undefined;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toJsonContent = exports.isAnyMediaType = exports.isJsonMediaType = exports.toMediaTypeEssence = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* The media type without its parameters, trimmed and lowercased:
|
|
6
|
+
* `Application/JSON; charset=utf-8` → `application/json`.
|
|
7
|
+
*/
|
|
8
|
+
const toMediaTypeEssence = (mediaType) => (mediaType.split(';')[0] ?? '').trim().toLowerCase();
|
|
9
|
+
exports.toMediaTypeEssence = toMediaTypeEssence;
|
|
10
|
+
/**
|
|
11
|
+
* True when a body of this media type is one JSON value: `application/json`,
|
|
12
|
+
* or any `application/…+json` (the RFC 6839 structured syntax suffix, e.g.
|
|
13
|
+
* `application/vnd.api+json`, `application/ld+json`,
|
|
14
|
+
* `application/problem+json`). Parameters and case are ignored, so
|
|
15
|
+
* `application/json;v=1.0` is JSON.
|
|
16
|
+
*
|
|
17
|
+
* False for everything else, including:
|
|
18
|
+
* - `text/json`: not registered; RFC 8259 registers only `application/json`.
|
|
19
|
+
* - `application/x-ndjson`, `application/jsonl`: a stream of JSON values, not
|
|
20
|
+
* one value.
|
|
21
|
+
* - ranges such as `*\/*`, `application/*` and `application/*+json`: they do
|
|
22
|
+
* not name one type.
|
|
23
|
+
* - names without the suffix, such as `application/vnd.goa.error`, even when
|
|
24
|
+
* the API sends JSON under them.
|
|
25
|
+
*/
|
|
26
|
+
const isJsonMediaType = (mediaType) => {
|
|
27
|
+
const essence = (0, exports.toMediaTypeEssence)(mediaType);
|
|
28
|
+
return essence === 'application/json' || /^application\/[^/*\s]+\+json$/.test(essence);
|
|
29
|
+
};
|
|
30
|
+
exports.isJsonMediaType = isJsonMediaType;
|
|
31
|
+
/** True when the media type is the full range `*\/*`, parameters and case ignored. */
|
|
32
|
+
const isAnyMediaType = (mediaType) => (0, exports.toMediaTypeEssence)(mediaType) === '*/*';
|
|
33
|
+
exports.isAnyMediaType = isAnyMediaType;
|
|
34
|
+
/**
|
|
35
|
+
* True when a schema under `*\/*` can be read as one JSON value: an object,
|
|
36
|
+
* array, union or `$ref`. A scalar is not: under `*\/*` a `string` is usually
|
|
37
|
+
* a text body, and `string` with `format: binary` a file.
|
|
38
|
+
*/
|
|
39
|
+
const isJsonShaped = (schema) => schema !== undefined &&
|
|
40
|
+
(schema.isRef() || schema.type === 'object' || schema.type === 'array' || schema.type === 'union');
|
|
41
|
+
/**
|
|
42
|
+
* Choose the media type a body is read from: `application/json` exactly when
|
|
43
|
+
* it is a key, else the first JSON-like key in document order (see
|
|
44
|
+
* {@link isJsonMediaType}), else the `*\/*` key when its schema is an object,
|
|
45
|
+
* array, union or `$ref`. `*\/*` admits JSON, and documents use it for JSON
|
|
46
|
+
* bodies (springdoc writes it for every response); the parser logs
|
|
47
|
+
* `WILDCARD_MEDIA_TYPE` for every body read this way. `undefined` otherwise:
|
|
48
|
+
* there is no fall back to a specific non-JSON type, to a narrower range such
|
|
49
|
+
* as `application/*`, or to a scalar schema under `*\/*`, since a consumer
|
|
50
|
+
* would read that body as JSON.
|
|
51
|
+
*/
|
|
52
|
+
const toJsonContent = (content) => {
|
|
53
|
+
if (!content) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
const mediaTypes = Object.keys(content);
|
|
57
|
+
const jsonMediaType = 'application/json' in content ? 'application/json' : mediaTypes.find(exports.isJsonMediaType);
|
|
58
|
+
if (jsonMediaType !== undefined) {
|
|
59
|
+
return {
|
|
60
|
+
mediaType: jsonMediaType,
|
|
61
|
+
contentType: jsonMediaType,
|
|
62
|
+
schema: content[jsonMediaType]?.schema
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const anyMediaType = mediaTypes.find(exports.isAnyMediaType);
|
|
66
|
+
const schema = anyMediaType === undefined ? undefined : content[anyMediaType]?.schema;
|
|
67
|
+
return anyMediaType !== undefined && isJsonShaped(schema)
|
|
68
|
+
? { mediaType: anyMediaType, contentType: 'application/json', schema }
|
|
69
|
+
: undefined;
|
|
70
|
+
};
|
|
71
|
+
exports.toJsonContent = toJsonContent;
|