@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.
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/openapi/componentRefs.d.ts +2 -0
- package/dist/openapi/componentRefs.js +19 -0
- package/dist/openapi/pathItemReferences.d.ts +6 -0
- package/dist/openapi/pathItemReferences.js +58 -0
- package/dist/openapi/utils.d.ts +1 -0
- package/dist/openapi/utils.js +1 -0
- package/dist/openapi/v2/buildRefUuidMap.js +2 -1
- package/dist/openapi/v2/contextualHash.d.ts +1 -0
- package/dist/openapi/v2/contextualHash.js +5 -0
- package/dist/openapi/v2/mapCallback.d.ts +4 -2
- package/dist/openapi/v2/mapCallback.js +44 -14
- package/dist/openapi/v2/mapCallbackComponents.js +2 -1
- package/dist/openapi/v2/mapExample.js +3 -8
- package/dist/openapi/v2/mapHeader.d.ts +1 -1
- package/dist/openapi/v2/mapHeader.js +4 -2
- package/dist/openapi/v2/mapMedia.js +32 -10
- package/dist/openapi/v2/mapMediaTypeComponents.d.ts +8 -0
- package/dist/openapi/v2/mapMediaTypeComponents.js +22 -0
- package/dist/openapi/v2/mapOperation.d.ts +4 -2
- package/dist/openapi/v2/mapOperation.js +20 -4
- package/dist/openapi/v2/mapParameter.d.ts +1 -1
- package/dist/openapi/v2/mapParameter.js +4 -4
- package/dist/openapi/v2/mapPath.d.ts +4 -2
- package/dist/openapi/v2/mapPath.js +22 -8
- package/dist/openapi/v2/mapPathComponents.js +10 -1
- package/dist/openapi/v2/mapPaths.js +16 -3
- package/dist/openapi/v2/mapRequestBody.d.ts +1 -1
- package/dist/openapi/v2/mapRequestBody.js +4 -4
- package/dist/openapi/v2/mapResponse.d.ts +1 -1
- package/dist/openapi/v2/mapResponse.js +4 -2
- package/dist/openapi/v2/mapSchemaComponents.js +4 -1
- package/dist/openapi/v2/mapSecurityRequirement.d.ts +1 -0
- package/dist/openapi/v2/mapSecurityRequirement.js +15 -6
- package/dist/openapi/v2/mapWebhooks.js +8 -2
- package/dist/openapi/v2/openApiToSchemaGraph.js +2 -0
- package/dist/openapi/v2/ownCopy.d.ts +1 -0
- package/dist/openapi/v2/ownCopy.js +11 -0
- package/dist/openapi/v2/replaceSchemaRefs.d.ts +7 -1
- package/dist/openapi/v2/replaceSchemaRefs.js +118 -12
- package/dist/openapi/v2/schemaGraphToOpenApi.js +51 -5
- package/dist/openapi/v2/types/index.d.ts +26 -8
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- 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,
|
|
12
|
-
|
|
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({
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
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,
|
|
14
|
-
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
|
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
|
-
|
|
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] =
|
|
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] =
|
|
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
|
-
|
|
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 {};
|