@skmtc/core 0.30.1 → 0.31.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.
Files changed (57) hide show
  1. package/esm/context/generateTypes.d.ts +14 -2
  2. package/esm/context/generateTypes.js +3 -1
  3. package/esm/mod.d.ts +1 -0
  4. package/esm/mod.js +1 -0
  5. package/esm/oas/header/Header.d.ts +4 -2
  6. package/esm/oas/header/Header.js +12 -5
  7. package/esm/oas/mediaType/jsonMediaType.d.ts +50 -0
  8. package/esm/oas/mediaType/jsonMediaType.js +64 -0
  9. package/esm/oas/mediaType/toContentSchema.d.ts +8 -0
  10. package/esm/oas/mediaType/toContentSchema.js +6 -0
  11. package/esm/oas/operation/Operation.d.ts +10 -2
  12. package/esm/oas/operation/Operation.js +20 -7
  13. package/esm/oas/parameter/Parameter.d.ts +1 -1
  14. package/esm/oas/parameter/Parameter.js +7 -4
  15. package/esm/oas/requestBody/RequestBody.d.ts +11 -0
  16. package/esm/oas/requestBody/RequestBody.js +16 -2
  17. package/esm/oas/response/Response.d.ts +11 -0
  18. package/esm/oas/response/Response.js +16 -2
  19. package/esm/oas/webhook/Webhook.d.ts +4 -4
  20. package/esm/oas/webhook/Webhook.js +6 -6
  21. package/esm/parse/logBodyMediaTypes.d.ts +27 -0
  22. package/esm/parse/logBodyMediaTypes.js +50 -0
  23. package/esm/parse/v3-0/requestBody/toRequestBodiesV3.js +4 -1
  24. package/esm/parse/v3-0/response/toResponseV3.js +4 -1
  25. package/esm/parse/v3-1/requestBody/toRequestBodiesV3.js +4 -1
  26. package/esm/parse/v3-1/response/toResponseV3.js +4 -1
  27. package/esm/parse/v3-2/requestBody/toRequestBodiesV3.js +4 -1
  28. package/esm/parse/v3-2/response/toResponseV3.js +4 -1
  29. package/package.json +1 -1
  30. package/script/context/generateTypes.d.ts +14 -2
  31. package/script/context/generateTypes.js +3 -1
  32. package/script/mod.d.ts +1 -0
  33. package/script/mod.js +1 -0
  34. package/script/oas/header/Header.d.ts +4 -2
  35. package/script/oas/header/Header.js +12 -5
  36. package/script/oas/mediaType/jsonMediaType.d.ts +50 -0
  37. package/script/oas/mediaType/jsonMediaType.js +71 -0
  38. package/script/oas/mediaType/toContentSchema.d.ts +8 -0
  39. package/script/oas/mediaType/toContentSchema.js +10 -0
  40. package/script/oas/operation/Operation.d.ts +10 -2
  41. package/script/oas/operation/Operation.js +20 -7
  42. package/script/oas/parameter/Parameter.d.ts +1 -1
  43. package/script/oas/parameter/Parameter.js +7 -4
  44. package/script/oas/requestBody/RequestBody.d.ts +11 -0
  45. package/script/oas/requestBody/RequestBody.js +16 -2
  46. package/script/oas/response/Response.d.ts +11 -0
  47. package/script/oas/response/Response.js +16 -2
  48. package/script/oas/webhook/Webhook.d.ts +4 -4
  49. package/script/oas/webhook/Webhook.js +6 -6
  50. package/script/parse/logBodyMediaTypes.d.ts +27 -0
  51. package/script/parse/logBodyMediaTypes.js +54 -0
  52. package/script/parse/v3-0/requestBody/toRequestBodiesV3.js +4 -1
  53. package/script/parse/v3-0/response/toResponseV3.js +4 -1
  54. package/script/parse/v3-1/requestBody/toRequestBodiesV3.js +4 -1
  55. package/script/parse/v3-1/response/toResponseV3.js +4 -1
  56. package/script/parse/v3-2/requestBody/toRequestBodiesV3.js +4 -1
  57. package/script/parse/v3-2/response/toResponseV3.js +4 -1
@@ -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
- return context.withStackTrail(stackTrail, () => new OasResponse({
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
  };
@@ -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
- return context.withStackTrail(stackTrail, () => new OasRequestBody(fields, context));
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
- return context.withStackTrail(stackTrail, () => new OasResponse({
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
  };
@@ -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
- return context.withStackTrail(stackTrail, () => new OasRequestBody(fields, context));
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
- return context.withStackTrail(stackTrail, () => new OasResponse({
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skmtc/core",
3
- "version": "0.30.1",
3
+ "version": "0.31.0",
4
4
  "description": "Skmtc is a declarative code generation framework",
5
5
  "keywords": [
6
6
  "openapi",
@@ -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
- * definedor value matching `mediaType` from `content` property.
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. Defaults to `application/json`
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
- * definedor value matching `mediaType` from `content` property.
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. Defaults to `application/json`
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 = 'application/json') {
119
+ toSchema(mediaType) {
117
120
  if (this.schema) {
118
121
  return this.schema;
119
122
  }
120
- const schema = this.content?.[mediaType]?.schema;
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(`Schema not found for media type ${mediaType}`);
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;
@@ -0,0 +1,8 @@
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 schema a `toSchema(mediaType?)` lookup returns: an exact key lookup when
6
+ * `mediaType` is given, else the schema of `toJsonContent`.
7
+ */
8
+ export declare const toContentSchema: (content: Record<string, OasMediaType> | undefined, mediaType: string | undefined) => OasSchema | OasRef<"schema"> | undefined;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toContentSchema = void 0;
4
+ const jsonMediaType_js_1 = require("./jsonMediaType.js");
5
+ /**
6
+ * The schema a `toSchema(mediaType?)` lookup returns: an exact key lookup when
7
+ * `mediaType` is given, else the schema of `toJsonContent`.
8
+ */
9
+ const toContentSchema = (content, mediaType) => mediaType === undefined ? (0, jsonMediaType_js_1.toJsonContent)(content)?.schema : content?.[mediaType]?.schema;
10
+ exports.toContentSchema = toContentSchema;
@@ -60,6 +60,14 @@ export type OperationFields = {
60
60
  export type ToRequestBodyMapArgs = {
61
61
  schema: OasSchema | OasRef<'schema'>;
62
62
  requestBody: OasRequestBody;
63
+ /** The `content` key the schema was read from. */
64
+ mediaType: string;
65
+ /**
66
+ * The media type to send the body as: the explicit media type when one was
67
+ * passed, else `contentType` of `OasRequestBody.toJsonContent` (the
68
+ * JSON-like key, or `application/json` for a body read from `*\/*`).
69
+ */
70
+ contentType: string;
63
71
  };
64
72
  export declare class OasOperation extends OasBase {
65
73
  /** Type identifier for OAS operation objects */
@@ -120,7 +128,7 @@ export declare class OasOperation extends OasBase {
120
128
  * Maps the request body schema to a custom value using the provided mapping function.
121
129
  *
122
130
  * @param map - Function to transform the request body schema and metadata
123
- * @param mediaType - Media type to extract schema from (default: 'application/json')
131
+ * @param mediaType - Media type to extract schema from, an exact lookup. Omitted: the media type `OasRequestBody.toJsonContent` picks.
124
132
  * @returns Mapped value or undefined if no request body schema found
125
133
  */
126
134
  toRequestBody<V>(map: ({ schema, requestBody }: ToRequestBodyMapArgs) => V, mediaType?: string): V | undefined;
@@ -133,7 +141,7 @@ export declare class OasOperation extends OasBase {
133
141
  * {@link traverseSchema}.
134
142
  *
135
143
  * @param path - Schema path; `path[0]` must be `'SuccessResponse'` or `'RequestBody'`.
136
- * @param mediaType - Media type the body schema is read from (default `application/json`).
144
+ * @param mediaType - Media type the body schema is read from, an exact lookup. Omitted: the JSON media type (`application/json`, else the first JSON-like type, else `*\/*`).
137
145
  * @returns The schema at the path (may be an unresolved `$ref`).
138
146
  * @throws Error on an unknown root, a missing response/request body, or a non-navigable segment.
139
147
  */
@@ -167,13 +167,25 @@ class OasOperation extends OasBase_js_1.OasBase {
167
167
  * Maps the request body schema to a custom value using the provided mapping function.
168
168
  *
169
169
  * @param map - Function to transform the request body schema and metadata
170
- * @param mediaType - Media type to extract schema from (default: 'application/json')
170
+ * @param mediaType - Media type to extract schema from, an exact lookup. Omitted: the media type `OasRequestBody.toJsonContent` picks.
171
171
  * @returns Mapped value or undefined if no request body schema found
172
172
  */
173
- toRequestBody(map, mediaType = 'application/json') {
173
+ toRequestBody(map, mediaType) {
174
174
  const requestBody = this.requestBody?.resolve();
175
- const schema = requestBody?.content[mediaType]?.schema;
176
- return schema ? map({ schema, requestBody }) : undefined;
175
+ if (!requestBody) {
176
+ return undefined;
177
+ }
178
+ const chosen = mediaType === undefined
179
+ ? requestBody.toJsonContent()
180
+ : { mediaType, contentType: mediaType, schema: requestBody.toSchema(mediaType) };
181
+ return chosen?.schema
182
+ ? map({
183
+ schema: chosen.schema,
184
+ requestBody,
185
+ mediaType: chosen.mediaType,
186
+ contentType: chosen.contentType
187
+ })
188
+ : undefined;
177
189
  }
178
190
  /**
179
191
  * Navigate into this operation's response or request body schema along an
@@ -184,11 +196,11 @@ class OasOperation extends OasBase_js_1.OasBase {
184
196
  * {@link traverseSchema}.
185
197
  *
186
198
  * @param path - Schema path; `path[0]` must be `'SuccessResponse'` or `'RequestBody'`.
187
- * @param mediaType - Media type the body schema is read from (default `application/json`).
199
+ * @param mediaType - Media type the body schema is read from, an exact lookup. Omitted: the JSON media type (`application/json`, else the first JSON-like type, else `*\/*`).
188
200
  * @returns The schema at the path (may be an unresolved `$ref`).
189
201
  * @throws Error on an unknown root, a missing response/request body, or a non-navigable segment.
190
202
  */
191
- traverse(path, mediaType = 'application/json') {
203
+ traverse(path, mediaType) {
192
204
  const [root, ...rest] = path;
193
205
  let rootSchema;
194
206
  switch (root) {
@@ -203,7 +215,8 @@ class OasOperation extends OasBase_js_1.OasBase {
203
215
  }
204
216
  if (!rootSchema) {
205
217
  const label = root === 'SuccessResponse' ? 'success response' : 'request body';
206
- throw new Error(`Operation "${this.method} ${this.path}" has no ${label} schema for media type "${mediaType}"`);
218
+ const mediaTypeLabel = mediaType === undefined ? 'a JSON media type' : `media type "${mediaType}"`;
219
+ throw new Error(`Operation "${this.method} ${this.path}" has no ${label} schema for ${mediaTypeLabel}`);
207
220
  }
208
221
  return (0, traverseSchema_js_1.traverseSchema)(rootSchema, rest);
209
222
  }
@@ -243,7 +243,7 @@ export declare class OasParameter extends OasBase {
243
243
  * for the specified media type. When `content` has exactly one entry, its
244
244
  * schema is used whatever the media type.
245
245
  *
246
- * @param mediaType - Media type to extract schema from when using content definitions
246
+ * @param mediaType - Media type to extract schema from when using content definitions, an exact lookup. Omitted: the JSON media type (`application/json`, else the first JSON-like type, else `*\/*`).
247
247
  * @returns The parameter's schema object
248
248
  * @throws Error if no schema is found for the specified media type
249
249
  */
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OasParameter = void 0;
4
4
  require("../../_dnt.polyfills.js");
5
5
  const OasBase_js_1 = require("../../types/OasBase.js");
6
+ const toContentSchema_js_1 = require("../mediaType/toContentSchema.js");
6
7
  /**
7
8
  * Represents a Parameter Object in the OpenAPI Specification.
8
9
  *
@@ -298,19 +299,21 @@ class OasParameter extends OasBase_js_1.OasBase {
298
299
  * for the specified media type. When `content` has exactly one entry, its
299
300
  * schema is used whatever the media type.
300
301
  *
301
- * @param mediaType - Media type to extract schema from when using content definitions
302
+ * @param mediaType - Media type to extract schema from when using content definitions, an exact lookup. Omitted: the JSON media type (`application/json`, else the first JSON-like type, else `*\/*`).
302
303
  * @returns The parameter's schema object
303
304
  * @throws Error if no schema is found for the specified media type
304
305
  */
305
- toSchema(mediaType = 'application/json') {
306
+ toSchema(mediaType) {
306
307
  if (this.schema) {
307
308
  return this.schema;
308
309
  }
309
310
  const contentEntries = Object.values(this.content ?? {});
310
311
  const onlyEntry = contentEntries.length === 1 ? contentEntries[0] : undefined;
311
- const schema = this.content?.[mediaType]?.schema ?? onlyEntry?.schema;
312
+ const schema = (0, toContentSchema_js_1.toContentSchema)(this.content, mediaType) ?? onlyEntry?.schema;
312
313
  if (!schema) {
313
- throw new Error(`Schema not found for media type ${mediaType}`);
314
+ throw new Error(mediaType === undefined
315
+ ? 'Schema not found for a JSON media type'
316
+ : `Schema not found for media type "${mediaType}"`);
314
317
  }
315
318
  return schema;
316
319
  }
@@ -6,6 +6,7 @@ import type { ToJsonSchemaOptions } from '../schema/Schema.js';
6
6
  import type { OpenAPIV3 } from 'openapi-types';
7
7
  import { OasBase } from '../../types/OasBase.js';
8
8
  import type { ParseContextType } from '../../context/parseTypes.js';
9
+ import type { JsonContent } from '../mediaType/jsonMediaType.js';
9
10
  /**
10
11
  * Constructor fields for {@link OasRequestBody}.
11
12
  */
@@ -286,6 +287,16 @@ export declare class OasRequestBody extends OasBase {
286
287
  isRef(): this is OasRef<'requestBody'>;
287
288
  resolve(): OasRequestBody;
288
289
  resolveOnce(): OasRequestBody;
290
+ /**
291
+ * The body schema for `mediaType`, an exact key lookup. Without
292
+ * `mediaType`, the schema of the JSON media type that {@link toJsonContent}
293
+ * picks: `application/json`, else the first JSON-like type such as
294
+ * `application/json;v=1.0` or `application/vnd.api+json`, else `*\/*`
295
+ * when its schema is an object, array, union or `$ref`.
296
+ * `undefined` when there is no such media type or it has no schema.
297
+ */
289
298
  toSchema(mediaType?: string): OasSchema | OasRef<'schema'> | undefined;
299
+ /** The media type this body is read from (JSON-like, or `*\/*`), and its schema. See {@link toJsonContent}. */
300
+ toJsonContent(): JsonContent | undefined;
290
301
  toJsonSchema(options: ToJsonSchemaOptions): OpenAPIV3.RequestBodyObject;
291
302
  }
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OasRequestBody = void 0;
4
4
  require("../../_dnt.polyfills.js");
5
5
  const OasBase_js_1 = require("../../types/OasBase.js");
6
+ const jsonMediaType_js_1 = require("../mediaType/jsonMediaType.js");
7
+ const toContentSchema_js_1 = require("../mediaType/toContentSchema.js");
6
8
  /**
7
9
  * Represents a Request Body Object in the OpenAPI Specification.
8
10
  *
@@ -307,8 +309,20 @@ class OasRequestBody extends OasBase_js_1.OasBase {
307
309
  resolveOnce() {
308
310
  return this;
309
311
  }
310
- toSchema(mediaType = 'application/json') {
311
- return this.content?.[mediaType]?.schema;
312
+ /**
313
+ * The body schema for `mediaType`, an exact key lookup. Without
314
+ * `mediaType`, the schema of the JSON media type that {@link toJsonContent}
315
+ * picks: `application/json`, else the first JSON-like type such as
316
+ * `application/json;v=1.0` or `application/vnd.api+json`, else `*\/*`
317
+ * when its schema is an object, array, union or `$ref`.
318
+ * `undefined` when there is no such media type or it has no schema.
319
+ */
320
+ toSchema(mediaType) {
321
+ return (0, toContentSchema_js_1.toContentSchema)(this.content, mediaType);
322
+ }
323
+ /** The media type this body is read from (JSON-like, or `*\/*`), and its schema. See {@link toJsonContent}. */
324
+ toJsonContent() {
325
+ return (0, jsonMediaType_js_1.toJsonContent)(this.content);
312
326
  }
313
327
  toJsonSchema(options) {
314
328
  return {
@@ -8,6 +8,7 @@ import type { ToJsonSchemaOptions } from '../schema/Schema.js';
8
8
  import type { OpenAPIV3 } from 'openapi-types';
9
9
  import { OasBase } from '../../types/OasBase.js';
10
10
  import type { ParseContextType } from '../../context/parseTypes.js';
11
+ import type { JsonContent } from '../mediaType/jsonMediaType.js';
11
12
  /**
12
13
  * Constructor fields for {@link OasResponse}.
13
14
  */
@@ -220,7 +221,17 @@ export declare class OasResponse extends OasBase {
220
221
  isRef(): this is OasRef<'response'>;
221
222
  resolve(): OasResponse;
222
223
  resolveOnce(): OasResponse;
224
+ /**
225
+ * The body schema for `mediaType`, an exact key lookup. Without
226
+ * `mediaType`, the schema of the JSON media type that {@link toJsonContent}
227
+ * picks: `application/json`, else the first JSON-like type such as
228
+ * `application/json;v=1.0` or `application/vnd.api+json`, else `*\/*`
229
+ * when its schema is an object, array, union or `$ref`.
230
+ * `undefined` when there is no such media type or it has no schema.
231
+ */
223
232
  toSchema(mediaType?: string): OasSchema | OasRef<'schema'> | undefined;
233
+ /** The media type this response is read from (JSON-like, or `*\/*`), and its schema. See {@link toJsonContent}. */
234
+ toJsonContent(): JsonContent | undefined;
224
235
  toJsonSchema(options: ToJsonSchemaOptions): OpenAPIV3.ResponseObject & {
225
236
  summary?: string;
226
237
  };
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OasResponse = void 0;
4
4
  require("../../_dnt.polyfills.js");
5
5
  const OasBase_js_1 = require("../../types/OasBase.js");
6
+ const jsonMediaType_js_1 = require("../mediaType/jsonMediaType.js");
7
+ const toContentSchema_js_1 = require("../mediaType/toContentSchema.js");
6
8
  /**
7
9
  * Represents a Response Object in the OpenAPI Specification.
8
10
  *
@@ -247,8 +249,20 @@ class OasResponse extends OasBase_js_1.OasBase {
247
249
  resolveOnce() {
248
250
  return this;
249
251
  }
250
- toSchema(mediaType = 'application/json') {
251
- return this.content?.[mediaType]?.schema;
252
+ /**
253
+ * The body schema for `mediaType`, an exact key lookup. Without
254
+ * `mediaType`, the schema of the JSON media type that {@link toJsonContent}
255
+ * picks: `application/json`, else the first JSON-like type such as
256
+ * `application/json;v=1.0` or `application/vnd.api+json`, else `*\/*`
257
+ * when its schema is an object, array, union or `$ref`.
258
+ * `undefined` when there is no such media type or it has no schema.
259
+ */
260
+ toSchema(mediaType) {
261
+ return (0, toContentSchema_js_1.toContentSchema)(this.content, mediaType);
262
+ }
263
+ /** The media type this response is read from (JSON-like, or `*\/*`), and its schema. See {@link toJsonContent}. */
264
+ toJsonContent() {
265
+ return (0, jsonMediaType_js_1.toJsonContent)(this.content);
252
266
  }
253
267
  toJsonSchema(options) {
254
268
  return {