@mintlify/validation 0.1.889 → 0.1.891

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 (45) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +2 -0
  3. package/dist/openapi/componentRefs.d.ts +2 -0
  4. package/dist/openapi/componentRefs.js +19 -0
  5. package/dist/openapi/pathItemReferences.d.ts +6 -0
  6. package/dist/openapi/pathItemReferences.js +58 -0
  7. package/dist/openapi/utils.d.ts +1 -0
  8. package/dist/openapi/utils.js +1 -0
  9. package/dist/openapi/v2/buildRefUuidMap.js +2 -1
  10. package/dist/openapi/v2/contextualHash.d.ts +1 -0
  11. package/dist/openapi/v2/contextualHash.js +5 -0
  12. package/dist/openapi/v2/mapCallback.d.ts +4 -2
  13. package/dist/openapi/v2/mapCallback.js +44 -14
  14. package/dist/openapi/v2/mapCallbackComponents.js +2 -1
  15. package/dist/openapi/v2/mapExample.js +3 -8
  16. package/dist/openapi/v2/mapHeader.d.ts +1 -1
  17. package/dist/openapi/v2/mapHeader.js +4 -2
  18. package/dist/openapi/v2/mapMedia.js +32 -10
  19. package/dist/openapi/v2/mapMediaTypeComponents.d.ts +8 -0
  20. package/dist/openapi/v2/mapMediaTypeComponents.js +22 -0
  21. package/dist/openapi/v2/mapOperation.d.ts +4 -2
  22. package/dist/openapi/v2/mapOperation.js +20 -4
  23. package/dist/openapi/v2/mapParameter.d.ts +1 -1
  24. package/dist/openapi/v2/mapParameter.js +4 -4
  25. package/dist/openapi/v2/mapPath.d.ts +4 -2
  26. package/dist/openapi/v2/mapPath.js +22 -8
  27. package/dist/openapi/v2/mapPathComponents.js +10 -1
  28. package/dist/openapi/v2/mapPaths.js +16 -3
  29. package/dist/openapi/v2/mapRequestBody.d.ts +1 -1
  30. package/dist/openapi/v2/mapRequestBody.js +4 -4
  31. package/dist/openapi/v2/mapResponse.d.ts +1 -1
  32. package/dist/openapi/v2/mapResponse.js +4 -2
  33. package/dist/openapi/v2/mapSchemaComponents.js +4 -1
  34. package/dist/openapi/v2/mapSecurityRequirement.d.ts +1 -0
  35. package/dist/openapi/v2/mapSecurityRequirement.js +15 -6
  36. package/dist/openapi/v2/mapWebhooks.js +8 -2
  37. package/dist/openapi/v2/openApiToSchemaGraph.js +2 -0
  38. package/dist/openapi/v2/ownCopy.d.ts +1 -0
  39. package/dist/openapi/v2/ownCopy.js +11 -0
  40. package/dist/openapi/v2/replaceSchemaRefs.d.ts +7 -1
  41. package/dist/openapi/v2/replaceSchemaRefs.js +118 -12
  42. package/dist/openapi/v2/schemaGraphToOpenApi.js +51 -5
  43. package/dist/openapi/v2/types/index.d.ts +26 -8
  44. package/dist/tsconfig.build.tsbuildinfo +1 -1
  45. package/package.json +3 -3
@@ -1,4 +1,5 @@
1
1
  import { v4 as uuidv4 } from 'uuid';
2
+ import { activePathItemsOf, resolvePathItemReference } from '../pathItemReferences.js';
2
3
  import { getObjectById } from './getObjectById.js';
3
4
  import { mapPath } from './mapPath.js';
4
5
  export const mapPaths = ({ spec, refUuidMap, uuidObjectHashMap, hashedNodeMap, documentId, }) => {
@@ -8,13 +9,25 @@ export const mapPaths = ({ spec, refUuidMap, uuidObjectHashMap, hashedNodeMap, d
8
9
  const document = getObjectById({ uuidObjectHashMap, hashedNodeMap, id: documentId });
9
10
  if (!document)
10
11
  return;
11
- Object.entries(paths).forEach(([path, pathItem]) => {
12
- if (!pathItem)
12
+ Object.entries(paths).forEach(([path, rawPathItem]) => {
13
+ var _a;
14
+ if (!rawPathItem)
13
15
  return;
16
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- resolved items keep the PathObject shape
17
+ const pathItem = structuredClone((_a = resolvePathItemReference(rawPathItem, spec.components)) !== null && _a !== void 0 ? _a : rawPathItem);
14
18
  const uuid = uuidv4();
15
19
  // map to uuidObjectHashMap, hashedNodeMap
16
20
  // map path + operation in refUuidMap in mapPath
17
- mapPath({ pathItem, refUuidMap, uuidObjectHashMap, hashedNodeMap, uuid, path });
21
+ mapPath({
22
+ pathItem,
23
+ refUuidMap,
24
+ uuidObjectHashMap,
25
+ hashedNodeMap,
26
+ uuid,
27
+ path,
28
+ components: spec.components,
29
+ activePathItems: activePathItemsOf(rawPathItem),
30
+ });
18
31
  // add path to document
19
32
  document.paths.push(uuid);
20
33
  });
@@ -1,5 +1,5 @@
1
1
  import { HashedNodeMap, RequestBodyOrRefObject, RefUuidMap, UUID, UUIDObjectHashMap } from './types/index.js';
2
- export declare const mapRequestBody: ({ requestBody, refUuidMap, uuidObjectHashMap, hashedNodeMap, uuid, }: {
2
+ export declare const mapRequestBody: ({ requestBody: input, refUuidMap, uuidObjectHashMap, hashedNodeMap, uuid, }: {
3
3
  requestBody: RequestBodyOrRefObject;
4
4
  refUuidMap: RefUuidMap;
5
5
  uuidObjectHashMap: UUIDObjectHashMap;
@@ -1,17 +1,17 @@
1
1
  import hash from 'object-hash';
2
2
  import { v4 as uuidv4 } from 'uuid';
3
3
  import { mapMedia } from './mapMedia.js';
4
- export const mapRequestBody = ({ requestBody, refUuidMap, uuidObjectHashMap, hashedNodeMap, uuid, }) => {
4
+ import { ownCopy } from './ownCopy.js';
5
+ export const mapRequestBody = ({ requestBody: input, refUuidMap, uuidObjectHashMap, hashedNodeMap, uuid, }) => {
5
6
  // hash the raw object
6
- const objectHash = hash(requestBody);
7
+ const objectHash = hash(input);
7
8
  // map uuid and hash to uuidObjectHashMap
8
9
  uuidObjectHashMap[uuid] = objectHash;
9
10
  // if we've seen this exact object before, skip processing
10
11
  if (objectHash in hashedNodeMap) {
11
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
- requestBody = objectHash;
13
12
  return;
14
13
  }
14
+ const requestBody = ownCopy(input, ['content']);
15
15
  // if ref, replace with uuid
16
16
  if ('$ref' in requestBody && requestBody.$ref) {
17
17
  const refId = requestBody.$ref;
@@ -1,5 +1,5 @@
1
1
  import { RefUuidMap, UUIDObjectHashMap, ResponseOrRefObject, HashedNodeMap, UUID } from './types/index.js';
2
- export declare const mapResponse: ({ response, refUuidMap, uuidObjectHashMap, hashedNodeMap, uuid, }: {
2
+ export declare const mapResponse: ({ response: input, refUuidMap, uuidObjectHashMap, hashedNodeMap, uuid, }: {
3
3
  response: ResponseOrRefObject;
4
4
  refUuidMap: RefUuidMap;
5
5
  uuidObjectHashMap: UUIDObjectHashMap;
@@ -2,11 +2,13 @@ import hash from 'object-hash';
2
2
  import { v4 as uuidv4 } from 'uuid';
3
3
  import { mapHeader } from './mapHeader.js';
4
4
  import { mapMedia } from './mapMedia.js';
5
- export const mapResponse = ({ response, refUuidMap, uuidObjectHashMap, hashedNodeMap, uuid, }) => {
5
+ import { ownCopy } from './ownCopy.js';
6
+ export const mapResponse = ({ response: input, refUuidMap, uuidObjectHashMap, hashedNodeMap, uuid, }) => {
6
7
  // hash the raw object
7
- const objectHash = hash(response);
8
+ const objectHash = hash(input);
8
9
  // map uuid and hash to uuidObjectHashMap
9
10
  uuidObjectHashMap[uuid] = objectHash;
11
+ const response = ownCopy(input, ['headers', 'content']);
10
12
  // if ref, replace with uuid
11
13
  if ('$ref' in response && response.$ref) {
12
14
  const refId = response.$ref;
@@ -1,6 +1,6 @@
1
1
  import hash from 'object-hash';
2
2
  import { v4 as uuidv4 } from 'uuid';
3
- import { replaceSchemaRefs } from './replaceSchemaRefs.js';
3
+ import { bindDiscriminatorDefault, replaceSchemaRefs } from './replaceSchemaRefs.js';
4
4
  export const mapSchemaComponents = ({ spec, refUuidMap, uuidObjectHashMap, hashedNodeMap, }) => {
5
5
  var _a;
6
6
  const schemaComponents = (_a = spec.components) === null || _a === void 0 ? void 0 : _a.schemas;
@@ -21,4 +21,7 @@ export const mapSchemaComponents = ({ spec, refUuidMap, uuidObjectHashMap, hashe
21
21
  // add to hashedNodeMap
22
22
  hashedNodeMap[objectHash] = schema;
23
23
  });
24
+ Object.values(hashedNodeMap).forEach((schema) => {
25
+ bindDiscriminatorDefault({ schema, refUuidMap, uuidObjectHashMap, hashedNodeMap });
26
+ });
24
27
  };
@@ -1,4 +1,5 @@
1
1
  import { RefUuidMap, SecurityRequirementObject, UUIDObjectHashMap, HashedNodeMap, UUID } from './types/index.js';
2
+ export declare const resolveSecuritySchemeName: (key: string, refUuidMap: RefUuidMap) => string | undefined;
2
3
  export declare const mapSecurityRequirement: ({ security, refUuidMap, uuidObjectHashMap, hashedNodeMap, uuid, }: {
3
4
  security: SecurityRequirementObject;
4
5
  refUuidMap: RefUuidMap;
@@ -1,17 +1,26 @@
1
1
  import hash from 'object-hash';
2
2
  import { v4 as uuidv4 } from 'uuid';
3
+ import { getSecuritySchemeNameFromFragment } from '../componentRefs.js';
4
+ const SECURITY_SCHEMES_POINTER = '#/components/securitySchemes/';
5
+ export const resolveSecuritySchemeName = (key, refUuidMap) => {
6
+ const hasScheme = (name) => Object.prototype.hasOwnProperty.call(refUuidMap, `${SECURITY_SCHEMES_POINTER}${name}`);
7
+ if (hasScheme(key))
8
+ return key;
9
+ const name = getSecuritySchemeNameFromFragment(key);
10
+ if (name === undefined)
11
+ return undefined;
12
+ return hasScheme(name) ? name : undefined;
13
+ };
3
14
  export const mapSecurityRequirement = ({ security, refUuidMap, uuidObjectHashMap, hashedNodeMap, uuid, }) => {
4
15
  const securityRequirementObject = {};
5
16
  Object.entries(security).forEach(([securitySchemeName, securitySchemeScopes]) => {
6
17
  // create security requirement object
7
18
  // add $ref to matching security scheme from components.securitySchemes
8
19
  // add scopes to the security requirement object
9
- const refId = `#/components/securitySchemes/${securitySchemeName}`;
10
- const refUuid = refUuidMap[refId] || uuidv4();
11
- securityRequirementObject[securitySchemeName] = {
12
- $ref: refUuid,
13
- scopes: securitySchemeScopes,
14
- };
20
+ const schemeName = resolveSecuritySchemeName(securitySchemeName, refUuidMap);
21
+ const refId = schemeName === undefined ? undefined : `${SECURITY_SCHEMES_POINTER}${schemeName}`;
22
+ const refUuid = (refId && refUuidMap[refId]) || uuidv4();
23
+ securityRequirementObject[securitySchemeName] = Object.assign({ $ref: refUuid, scopes: securitySchemeScopes }, (schemeName !== undefined ? { schemeName } : {}));
15
24
  });
16
25
  const objectHash = hash(securityRequirementObject);
17
26
  uuidObjectHashMap[uuid] = objectHash;
@@ -1,4 +1,5 @@
1
1
  import { v4 as uuidv4 } from 'uuid';
2
+ import { activePathItemsOf, resolvePathItemReference } from '../pathItemReferences.js';
2
3
  import { getObjectById } from './getObjectById.js';
3
4
  import { mapPath } from './mapPath.js';
4
5
  export const mapWebhooks = ({ spec, refUuidMap, uuidObjectHashMap, hashedNodeMap, documentId, }) => {
@@ -10,9 +11,12 @@ export const mapWebhooks = ({ spec, refUuidMap, uuidObjectHashMap, hashedNodeMap
10
11
  const document = getObjectById({ uuidObjectHashMap, hashedNodeMap, id: documentId });
11
12
  if (!document)
12
13
  return;
13
- Object.entries(webhooks).forEach(([webhookPath, webhook]) => {
14
- if (!webhook)
14
+ Object.entries(webhooks).forEach(([webhookPath, rawWebhook]) => {
15
+ var _a;
16
+ if (!rawWebhook)
15
17
  return;
18
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- resolved items keep the PathObjectOrRef shape
19
+ const webhook = structuredClone((_a = resolvePathItemReference(rawWebhook, spec.components)) !== null && _a !== void 0 ? _a : rawWebhook);
16
20
  const uuid = uuidv4();
17
21
  // map to uuidObjectHashMap, hashedNodeMap
18
22
  // map path + operation in refUuidMap in mapPath
@@ -24,6 +28,8 @@ export const mapWebhooks = ({ spec, refUuidMap, uuidObjectHashMap, hashedNodeMap
24
28
  uuid,
25
29
  path: webhookPath,
26
30
  isWebhook: true,
31
+ components: spec.components,
32
+ activePathItems: activePathItemsOf(rawWebhook),
27
33
  });
28
34
  // add webhook to document
29
35
  document.webhooks.push(uuid);
@@ -4,6 +4,7 @@ import { mapCallbackComponents } from './mapCallbackComponents.js';
4
4
  import { mapDocument } from './mapDocument.js';
5
5
  import { mapExampleComponents } from './mapExampleComponents.js';
6
6
  import { mapHeaderComponents } from './mapHeaderComponents.js';
7
+ import { mapMediaTypeComponents } from './mapMediaTypeComponents.js';
7
8
  import { mapParameterComponents } from './mapParameterComponents.js';
8
9
  import { mapPathComponents } from './mapPathComponents.js';
9
10
  import { mapPaths } from './mapPaths.js';
@@ -29,6 +30,7 @@ export const openApiToSchemaGraph = ({ spec, originalFileLocation, }) => {
29
30
  // (starting with the components section, which already have uuids in refUuidMap)
30
31
  // document.components.schemas -> Schema
31
32
  mapSchemaComponents({ spec, refUuidMap, uuidObjectHashMap, hashedNodeMap });
33
+ mapMediaTypeComponents({ spec, refUuidMap, uuidObjectHashMap, hashedNodeMap });
32
34
  // document.components.responses -> Response, possibly Header, Schema, Example, Media, Encoding
33
35
  mapResponseComponents({ spec, refUuidMap, uuidObjectHashMap, hashedNodeMap });
34
36
  // document.components.parameters -> Parameter, possibly Schema, Example, Media, Encoding
@@ -0,0 +1 @@
1
+ export declare const ownCopy: <T extends object>(value: T, nestedRecords: readonly string[]) => T;
@@ -0,0 +1,11 @@
1
+ import { isObject } from '../utils.js';
2
+ export const ownCopy = (value, nestedRecords) => {
3
+ const copy = Object.assign({}, value);
4
+ for (const key of nestedRecords) {
5
+ const nested = Reflect.get(copy, key);
6
+ if (isObject(nested)) {
7
+ Reflect.set(copy, key, Object.assign({}, nested));
8
+ }
9
+ }
10
+ return copy;
11
+ };
@@ -1,4 +1,4 @@
1
- import { RefUuidMap, SchemaOrRefObject, UUIDObjectHashMap, HashedNodeMap, UUID } from './types/index.js';
1
+ import { RefUuidMap, SchemaOrRefObject, UUIDObjectHashMap, HashedNodeMap, UUID, GraphNode } from './types/index.js';
2
2
  export declare const replaceSchemaRefs: ({ schema, refUuidMap, uuidObjectHashMap, hashedNodeMap, schemaToUuidMap, }: {
3
3
  schema: SchemaOrRefObject;
4
4
  refUuidMap: RefUuidMap;
@@ -6,3 +6,9 @@ export declare const replaceSchemaRefs: ({ schema, refUuidMap, uuidObjectHashMap
6
6
  hashedNodeMap: HashedNodeMap;
7
7
  schemaToUuidMap?: WeakMap<SchemaOrRefObject, UUID>;
8
8
  }) => void;
9
+ export declare const bindDiscriminatorDefault: ({ schema, refUuidMap, uuidObjectHashMap, hashedNodeMap, }: {
10
+ schema: GraphNode;
11
+ refUuidMap: RefUuidMap;
12
+ uuidObjectHashMap: UUIDObjectHashMap;
13
+ hashedNodeMap: HashedNodeMap;
14
+ }) => void;
@@ -1,11 +1,13 @@
1
1
  import hash from 'object-hash';
2
- import { v4 as uuidv4 } from 'uuid';
2
+ import { v4 as uuidv4, validate as uuidValidate } from 'uuid';
3
+ import { getComponentNameFromRef } from '../componentRefs.js';
3
4
  export const replaceSchemaRefs = ({ schema, refUuidMap, uuidObjectHashMap, hashedNodeMap, schemaToUuidMap = new WeakMap(), }) => {
4
5
  if ('$ref' in schema) {
5
- const refId = schema.$ref;
6
- const uuid = refUuidMap[refId] || uuidv4();
7
- schema.$ref = uuid;
8
- return;
6
+ if (!uuidValidate(schema.$ref)) {
7
+ schema.$ref = lookupSchemaRef(schema.$ref, refUuidMap) || uuidv4();
8
+ }
9
+ if (Object.keys(schema).length === 1)
10
+ return;
9
11
  }
10
12
  if (schemaToUuidMap.has(schema)) {
11
13
  const value = schemaToUuidMap.get(schema);
@@ -141,15 +143,111 @@ export const replaceSchemaRefs = ({ schema, refUuidMap, uuidObjectHashMap, hashe
141
143
  const mapping = schema.discriminator.mapping;
142
144
  for (const key of Object.keys(mapping)) {
143
145
  const value = mapping[key];
144
- if (typeof value === 'string' && value.startsWith('#/')) {
145
- const uuid = refUuidMap[value];
146
- if (uuid) {
147
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
148
- mapping[key] = uuid;
149
- }
146
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
147
+ const uuid = typeof value === 'string' ? discriminatorTargetUuid(value, refUuidMap) : undefined;
148
+ if (uuid) {
149
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
150
+ mapping[key] = uuid;
150
151
  }
151
152
  }
152
153
  }
154
+ bindDiscriminatorDefault({ schema, refUuidMap, uuidObjectHashMap, hashedNodeMap });
155
+ };
156
+ const ALIAS_KEYS = new Set(['$ref', 'summary', 'description']);
157
+ export const bindDiscriminatorDefault = ({ schema, refUuidMap, uuidObjectHashMap, hashedNodeMap, }) => {
158
+ var _a, _b, _c;
159
+ if (typeof schema !== 'object' ||
160
+ !('discriminator' in schema) ||
161
+ typeof schema.discriminator !== 'object' ||
162
+ schema.discriminator === null ||
163
+ !('defaultMapping' in schema.discriminator) ||
164
+ typeof schema.discriminator.defaultMapping !== 'string') {
165
+ return;
166
+ }
167
+ const target = schema.discriminator.defaultMapping;
168
+ const uuid = (_a = discriminatorTargetUuid(target, refUuidMap)) !== null && _a !== void 0 ? _a : (target in uuidObjectHashMap ? target : undefined);
169
+ if (!uuid)
170
+ return;
171
+ const nodeOf = (nodeUuid) => {
172
+ const objectHash = uuidObjectHashMap[nodeUuid];
173
+ return objectHash === undefined ? undefined : hashedNodeMap[objectHash];
174
+ };
175
+ const { union, mapped } = unionVariantUuids(schema, nodeOf);
176
+ if (union.includes(target) || mapped.includes(target))
177
+ return;
178
+ const canonical = (nodeUuid) => {
179
+ const seen = new Set();
180
+ let current = nodeUuid;
181
+ while (!seen.has(current)) {
182
+ seen.add(current);
183
+ const node = nodeOf(current);
184
+ if (typeof node !== 'object' || !('$ref' in node) || typeof node.$ref !== 'string')
185
+ break;
186
+ if (Object.keys(node).some((key) => !ALIAS_KEYS.has(key)))
187
+ break;
188
+ current = node.$ref;
189
+ }
190
+ return current;
191
+ };
192
+ const canonicalDefault = canonical(uuid);
193
+ const pick = (candidates) => candidates.includes(uuid)
194
+ ? uuid
195
+ : candidates.find((candidate) => canonical(candidate) === canonicalDefault);
196
+ schema.discriminator.defaultMapping = (_c = (_b = pick(union)) !== null && _b !== void 0 ? _b : pick(mapped)) !== null && _c !== void 0 ? _c : uuid;
197
+ };
198
+ const uuidsIn = (members) => Array.isArray(members)
199
+ ? members.flatMap((member) => (typeof member === 'string' ? [member] : []))
200
+ : [];
201
+ const mappingUuids = (discriminator) => typeof discriminator === 'object' &&
202
+ discriminator !== null &&
203
+ 'mapping' in discriminator &&
204
+ typeof discriminator.mapping === 'object' &&
205
+ discriminator.mapping !== null
206
+ ? uuidsIn(Object.values(discriminator.mapping))
207
+ : [];
208
+ const unionVariantUuids = (holder, nodeOf, seen = new Set([holder])) => {
209
+ if (typeof holder !== 'object')
210
+ return { union: [], mapped: [] };
211
+ const composition = compositionOf(holder, nodeOf, new Set(seen));
212
+ const nested = uuidsIn(composition.allOf).flatMap((uuid) => {
213
+ const target = nodeOf(uuid);
214
+ if (target === undefined || seen.has(target))
215
+ return [];
216
+ seen.add(target);
217
+ return [unionVariantUuids(target, nodeOf, seen)];
218
+ });
219
+ return {
220
+ union: [
221
+ ...uuidsIn(composition.oneOf),
222
+ ...uuidsIn(composition.anyOf),
223
+ ...nested.flatMap((inner) => inner.union),
224
+ ],
225
+ mapped: [
226
+ ...mappingUuids(composition.discriminator),
227
+ ...nested.flatMap((inner) => inner.mapped),
228
+ ],
229
+ };
230
+ };
231
+ const compositionOf = (holder, nodeOf, seen) => {
232
+ if (typeof holder !== 'object')
233
+ return {};
234
+ const own = Object.assign(Object.assign(Object.assign(Object.assign({}, ('oneOf' in holder ? { oneOf: holder.oneOf } : {})), ('anyOf' in holder ? { anyOf: holder.anyOf } : {})), ('allOf' in holder ? { allOf: holder.allOf } : {})), ('discriminator' in holder ? { discriminator: holder.discriminator } : {}));
235
+ if (!('$ref' in holder) || typeof holder.$ref !== 'string')
236
+ return own;
237
+ const target = nodeOf(holder.$ref);
238
+ if (target === undefined || seen.has(target))
239
+ return own;
240
+ seen.add(target);
241
+ return Object.assign(Object.assign({}, compositionOf(target, nodeOf, seen)), own);
242
+ };
243
+ const discriminatorTargetUuid = (target, refUuidMap) => target.startsWith('#')
244
+ ? lookupSchemaRef(target, refUuidMap)
245
+ : refUuidMap[`#/components/schemas/${target.startsWith('./') ? target.slice(2) : target}`];
246
+ const lookupSchemaRef = (ref, refUuidMap) => {
247
+ const componentName = getComponentNameFromRef(ref, 'schemas');
248
+ return componentName === undefined
249
+ ? refUuidMap[ref]
250
+ : refUuidMap[`#/components/schemas/${componentName}`];
153
251
  };
154
252
  const processChildSchema = ({ childSchema, refUuidMap, uuidObjectHashMap, hashedNodeMap, schemaToUuidMap, }) => {
155
253
  if (typeof childSchema !== 'object') {
@@ -157,7 +255,8 @@ const processChildSchema = ({ childSchema, refUuidMap, uuidObjectHashMap, hashed
157
255
  }
158
256
  // preserve sibling properties when resolving $ref
159
257
  if ('$ref' in childSchema) {
160
- const refId = childSchema.$ref;
258
+ const componentName = getComponentNameFromRef(childSchema.$ref, 'schemas');
259
+ const refId = componentName === undefined ? childSchema.$ref : `#/components/schemas/${componentName}`;
161
260
  const refUuid = refUuidMap[refId] || uuidv4();
162
261
  // if no siblings, safe to return ref uuid directly
163
262
  const siblingKeys = Object.keys(childSchema).filter((key) => key !== '$ref');
@@ -174,6 +273,13 @@ const processChildSchema = ({ childSchema, refUuidMap, uuidObjectHashMap, hashed
174
273
  return childUuid;
175
274
  }
176
275
  uuidObjectHashMap[childUuid] = objectHash;
276
+ replaceSchemaRefs({
277
+ schema: childSchema,
278
+ refUuidMap,
279
+ uuidObjectHashMap,
280
+ hashedNodeMap,
281
+ schemaToUuidMap,
282
+ });
177
283
  hashedNodeMap[objectHash] = childSchema;
178
284
  schemaToUuidMap.set(childSchema, childUuid);
179
285
  return childUuid;
@@ -1,4 +1,5 @@
1
1
  import { httpMethods, isFixedHttpMethod } from '../types/endpoint.js';
2
+ import { resolveSecuritySchemeName } from './mapSecurityRequirement.js';
2
3
  /**
3
4
  * Converts a SchemaGraphData back to an OpenAPI specification.
4
5
  * Optionally filters to a specific operation if path and method are provided.
@@ -29,10 +30,14 @@ export function schemaGraphToOpenApi({ schemaGraphData, targetPath, targetMethod
29
30
  const usedSecuritySchemes = new Set();
30
31
  // Helper to transform security requirements from internal format to OpenAPI format
31
32
  const transformSecurityRequirement = (securityReq) => {
33
+ var _a;
32
34
  const transformed = {};
33
35
  for (const [key, value] of Object.entries(securityReq)) {
34
36
  // Track this security scheme as used
35
- usedSecuritySchemes.add(key);
37
+ const schemeName = typeof value === 'object' && !Array.isArray(value) && typeof value.schemeName === 'string'
38
+ ? value.schemeName
39
+ : ((_a = resolveSecuritySchemeName(key, refUuidMap)) !== null && _a !== void 0 ? _a : key);
40
+ usedSecuritySchemes.add(schemeName);
36
41
  if (typeof value === 'object' && !Array.isArray(value) && 'scopes' in value) {
37
42
  // Extract just the scopes array from internal format
38
43
  // Create a new array to avoid YAML anchor references
@@ -45,6 +50,12 @@ export function schemaGraphToOpenApi({ schemaGraphData, targetPath, targetMethod
45
50
  }
46
51
  return transformed;
47
52
  };
53
+ const toReferenceString = (refPath) => {
54
+ const match = /^(#\/components\/[^/]+\/)(.+)$/.exec(refPath);
55
+ if (!(match === null || match === void 0 ? void 0 : match[1]) || !match[2])
56
+ return refPath;
57
+ return `${match[1]}${match[2].replace(/%/g, '%25').replace(/~/g, '~0').replace(/\//g, '~1')}`;
58
+ };
48
59
  // Helper to convert UUID references back to $ref or inline objects
49
60
  const convertValue = (value, depth = 0) => {
50
61
  // Prevent infinite recursion - return empty object as fallback
@@ -58,7 +69,7 @@ export function schemaGraphToOpenApi({ schemaGraphData, targetPath, targetMethod
58
69
  // If this UUID corresponds to a component ref, use $ref
59
70
  if (refPath && refPath.startsWith('#/components/')) {
60
71
  usedComponents.add(refPath);
61
- return { $ref: refPath };
72
+ return { $ref: toReferenceString(refPath) };
62
73
  }
63
74
  // Otherwise try to resolve and inline it
64
75
  const resolved = resolveNode(value);
@@ -82,7 +93,7 @@ export function schemaGraphToOpenApi({ schemaGraphData, targetPath, targetMethod
82
93
  const refPath = uuidRefMap.get(refValue);
83
94
  if (refPath && refPath.startsWith('#/components/')) {
84
95
  usedComponents.add(refPath);
85
- convertedRef = refPath;
96
+ convertedRef = toReferenceString(refPath);
86
97
  }
87
98
  else {
88
99
  convertedRef = refValue;
@@ -100,19 +111,54 @@ export function schemaGraphToOpenApi({ schemaGraphData, targetPath, targetMethod
100
111
  const result = { $ref: convertedRef };
101
112
  for (const [key, val] of Object.entries(value)) {
102
113
  if (key !== '$ref') {
103
- result[key] = convertValue(val, depth + 1);
114
+ result[key] = convertProperty(key, val, depth + 1);
104
115
  }
105
116
  }
106
117
  return result;
107
118
  }
108
119
  const result = {};
109
120
  for (const [key, val] of Object.entries(value)) {
110
- result[key] = convertValue(val, depth + 1);
121
+ result[key] = convertProperty(key, val, depth + 1);
111
122
  }
112
123
  return result;
113
124
  }
114
125
  return value;
115
126
  };
127
+ const discriminatorTarget = (target, hops = 0) => {
128
+ if (typeof target !== 'string' || hops > 5)
129
+ return target;
130
+ const refPath = uuidRefMap.get(target);
131
+ if (refPath && refPath.startsWith('#/components/')) {
132
+ usedComponents.add(refPath);
133
+ return toReferenceString(refPath);
134
+ }
135
+ const resolved = resolveNode(target);
136
+ if (resolved && typeof resolved === 'object' && '$ref' in resolved) {
137
+ return discriminatorTarget(resolved.$ref, hops + 1);
138
+ }
139
+ return target;
140
+ };
141
+ const convertProperty = (key, val, depth) => {
142
+ if (key !== 'discriminator' ||
143
+ typeof val !== 'object' ||
144
+ val === null ||
145
+ Array.isArray(val) ||
146
+ !('propertyName' in val) ||
147
+ typeof val.propertyName !== 'string') {
148
+ return convertValue(val, depth);
149
+ }
150
+ const discriminator = Object.assign({}, val);
151
+ if (typeof discriminator.mapping === 'object' && discriminator.mapping !== null) {
152
+ discriminator.mapping = Object.fromEntries(Object.entries(discriminator.mapping).map(([name, target]) => [
153
+ name,
154
+ discriminatorTarget(target),
155
+ ]));
156
+ }
157
+ if ('defaultMapping' in discriminator) {
158
+ discriminator.defaultMapping = discriminatorTarget(discriminator.defaultMapping);
159
+ }
160
+ return discriminator;
161
+ };
116
162
  // Get the document root
117
163
  const docObj = resolveNode(documentId);
118
164
  if (!docObj) {
@@ -6,8 +6,13 @@ export type HashId = string;
6
6
  export type RefUuidMap = Record<string, UUID>;
7
7
  export type UUIDObjectHashMap = Record<UUID, HashId>;
8
8
  export type HashedNodeMap = Record<HashId, GraphNode>;
9
- export type GraphNode = SchemaOrRef | ResponseOrRef | HeaderOrRef | ParameterOrRef | Media | ExampleOrRef | RequestBodyOrRef | SecuritySchemeOrRef | CallbackOrRef | ServerObject | PathOrRef | Operation | SecurityRequirement | Document;
10
- export type SchemaObject = OpenAPIV3.SchemaObject | OpenAPIV3_1.SchemaObject;
9
+ export type GraphNode = SchemaOrRef | ResponseOrRef | HeaderOrRef | ParameterOrRef | Media | MediaRef | ExampleOrRef | RequestBodyOrRef | SecuritySchemeOrRef | CallbackOrRef | ServerObject | PathOrRef | Operation | SecurityRequirement | Document;
10
+ type DiscriminatorObject = OpenAPIV3.DiscriminatorObject & Pick<OpenAPIV3_2.DiscriminatorObject, 'defaultMapping'>;
11
+ export type SchemaObject = (OpenAPIV3.SchemaObject & {
12
+ discriminator?: DiscriminatorObject;
13
+ }) | (OpenAPIV3_1.SchemaObject & {
14
+ discriminator?: DiscriminatorObject;
15
+ });
11
16
  export type ArraySchemaObject = OpenAPIV3_1.ArraySchemaObject & {
12
17
  prefixItems?: SchemaObject[];
13
18
  };
@@ -37,7 +42,7 @@ export type SchemaOrRef = (SchemaOrRefObject & {
37
42
  oneOf?: never;
38
43
  not?: never;
39
44
  }) | HashId;
40
- export type ResponseObject = OpenAPIV3.ResponseObject | OpenAPIV3_1.ResponseObject;
45
+ export type ResponseObject = (Omit<OpenAPIV3.ResponseObject, 'description'> | Omit<OpenAPIV3_1.ResponseObject, 'description'>) & Pick<OpenAPIV3_2.ResponseObject, 'summary' | 'description'>;
41
46
  export type ResponseOrRefObject = ResponseObject | RefObject;
42
47
  export type ResponseOrRef = (ResponseObject & {
43
48
  headers?: {
@@ -96,17 +101,26 @@ export type ParameterOrRef = (ParameterObject & {
96
101
  examples?: never;
97
102
  content?: never;
98
103
  });
99
- export type MediaObject = OpenAPIV3.MediaTypeObject | (Omit<OpenAPIV3_1.MediaTypeObject, 'examples'> & {
104
+ export type MediaObject = OpenAPIV3.MediaTypeObject | (Omit<OpenAPIV3_1.MediaTypeObject, 'examples' | 'encoding'> & {
100
105
  examples?: Record<string, OpenAPIV3_1.ReferenceObject | ExampleObject>;
106
+ itemSchema?: OpenAPIV3_2.MediaTypeObject['itemSchema'];
107
+ encoding?: Record<string, EncodingObject>;
108
+ prefixEncoding?: EncodingObject[];
109
+ itemEncoding?: EncodingObject;
101
110
  });
111
+ export type EncodingObject = OpenAPIV3_1.EncodingObject & {
112
+ prefixEncoding?: EncodingObject[];
113
+ itemEncoding?: EncodingObject;
114
+ };
115
+ export type MediaRef = RefObject & {
116
+ $ref: UUID;
117
+ };
102
118
  export type Media = MediaObject & {
103
119
  schema?: UUID;
120
+ itemSchema?: UUID;
104
121
  examples?: {
105
122
  [name: string]: UUID;
106
123
  };
107
- encoding?: {
108
- [encoding: string]: UUID;
109
- };
110
124
  };
111
125
  export type ExampleObject = OpenAPIV3.ExampleObject | OpenAPIV3_1.ExampleObject | OpenAPIV3_2.ExampleObject;
112
126
  export type ExampleOrRefObject = ExampleObject | RefObject;
@@ -144,11 +158,12 @@ export type CallbackOrRef = (CallbackObject & {
144
158
  }) | (RefObject & {
145
159
  $ref: UUID;
146
160
  });
147
- export type ServerObject = OpenAPIV3.ServerObject | OpenAPIV3_1.ServerObject;
161
+ export type ServerObject = (OpenAPIV3.ServerObject | OpenAPIV3_1.ServerObject) & Pick<OpenAPIV3_2.ServerObject, 'name'>;
148
162
  export type PathObject = OpenAPIV3.PathItemObject | OpenAPIV3_1.PathItemObject;
149
163
  export type PathObjectOrRef = PathObject | RefObject;
150
164
  export type PathOrRef = (PathObject & {
151
165
  path: string;
166
+ isWebhook?: true;
152
167
  parameters?: UUID[];
153
168
  servers?: UUID[];
154
169
  } & {
@@ -159,6 +174,7 @@ export type PathOrRef = (PathObject & {
159
174
  $ref?: never;
160
175
  }) | (RefObject & {
161
176
  path: string;
177
+ isWebhook?: true;
162
178
  $ref: UUID;
163
179
  } & {
164
180
  parameters?: never;
@@ -195,6 +211,7 @@ export type SecurityRequirement = {
195
211
  [name: string]: {
196
212
  $ref?: UUID;
197
213
  scopes?: string[];
214
+ schemeName?: string;
198
215
  };
199
216
  };
200
217
  export type DocumentObject = OpenAPIV3.Document | OpenAPIV3_1.Document;
@@ -213,3 +230,4 @@ export type SchemaGraphData = {
213
230
  refUuidMap: RefUuidMap;
214
231
  };
215
232
  };
233
+ export {};