@xyd-js/openapi 0.1.0-xyd.11 → 0.1.0-xyd.13
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/CHANGELOG.md +16 -0
- package/__fixtures__/-2.complex.openai/input.yaml +39848 -0
- package/__fixtures__/-2.complex.openai/output.json +321646 -0
- package/__fixtures__/-2.complex.openai/pluginOasOpenai.ts +553 -0
- package/__fixtures__/1.basic/input.yaml +226 -0
- package/__fixtures__/1.basic/output.json +1919 -0
- package/__fixtures__/2.more/input.yaml +76 -0
- package/__fixtures__/2.more/output.json +292 -0
- package/__fixtures__/3.multiple-responses/input.yaml +48 -0
- package/__fixtures__/3.multiple-responses/output.json +266 -0
- package/__fixtures__/4.abc/input.yaml +639 -0
- package/__fixtures__/4.abc/output.json +3828 -0
- package/__fixtures__/5.xdocs.codeLanguages/input.yaml +231 -0
- package/__fixtures__/5.xdocs.codeLanguages/output.json +1879 -0
- package/__fixtures__/5.xdocs.sidebar/input.yaml +256 -0
- package/__fixtures__/5.xdocs.sidebar/output.json +843 -0
- package/__fixtures__/6.codeSamples/input.yaml +75 -0
- package/__fixtures__/6.codeSamples/output.json +293 -0
- package/__tests__/oapSchemaToReferences.test.ts +88 -0
- package/__tests__/utils.ts +81 -0
- package/dist/index.cjs +1859 -162
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -4
- package/dist/index.d.ts +36 -4
- package/dist/index.js +1855 -155
- package/dist/index.js.map +1 -1
- package/index.ts +10 -2
- package/package.json +11 -6
- package/src/const.ts +5 -1
- package/src/converters/oas-componentSchemas.ts +205 -0
- package/src/converters/oas-examples.ts +417 -0
- package/src/{parameters.ts → converters/oas-parameters.ts} +17 -3
- package/src/converters/oas-paths.ts +354 -0
- package/src/{requestBody.ts → converters/oas-requestBody.ts} +30 -10
- package/src/converters/oas-responses.ts +76 -0
- package/src/converters/oas-schema.ts +141 -0
- package/src/index.ts +13 -5
- package/src/oas-core.ts +579 -0
- package/src/types.ts +18 -0
- package/src/utils.ts +103 -90
- package/src/xdocs/index.ts +18 -0
- package/src/xdocs/pluginSidebar.ts +580 -0
- package/src/xdocs/types.ts +26 -0
- package/vitest.config.ts +7 -0
- package/src/examples.ts +0 -116
- package/src/paths.ts +0 -103
- package/src/properties.ts +0 -37
- package/src/responses.ts +0 -38
- package/src/schema.ts +0 -62
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import {OpenAPIV3} from "openapi-types";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Reference,
|
|
5
|
+
Definition,
|
|
6
|
+
DefinitionProperty,
|
|
7
|
+
ReferenceType,
|
|
8
|
+
OpenAPIReferenceContext, SymbolDef,
|
|
9
|
+
ExampleGroup,
|
|
10
|
+
CodeBlockTab,
|
|
11
|
+
} from "@xyd-js/uniform";
|
|
12
|
+
|
|
13
|
+
import {OasJSONSchema, uniformOasOptions} from "../types";
|
|
14
|
+
import {schemaObjectToUniformDefinitionProperties} from "../oas-core";
|
|
15
|
+
|
|
16
|
+
export function schemaComponentsToUniformReferences(
|
|
17
|
+
openapi: OpenAPIV3.Document,
|
|
18
|
+
options?: uniformOasOptions,
|
|
19
|
+
): Reference[] {
|
|
20
|
+
const references: Reference[] = [];
|
|
21
|
+
|
|
22
|
+
if (!openapi.components?.schemas) {
|
|
23
|
+
return references;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
for (const [componentSchemaName, componentSchema] of Object.entries(openapi.components.schemas)) {
|
|
27
|
+
if (options?.regions && options.regions.length > 0) {
|
|
28
|
+
if (!options.regions.some(region => region === "/components/schemas/" + componentSchemaName)) {
|
|
29
|
+
continue
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if ('$ref' in componentSchema) {
|
|
34
|
+
console.warn(`Skipping reference object: ${componentSchemaName}`);
|
|
35
|
+
continue; // Skip reference objects
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let properties: DefinitionProperty[] = [];
|
|
39
|
+
let rootProperty: DefinitionProperty | undefined = undefined;
|
|
40
|
+
const respProperties = schemaObjectToUniformDefinitionProperties(componentSchema, false) || [];
|
|
41
|
+
if (Array.isArray(respProperties)) {
|
|
42
|
+
properties = respProperties
|
|
43
|
+
} else {
|
|
44
|
+
rootProperty = respProperties
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const symbolDef = definitionPropertyTypeDef(componentSchema)
|
|
48
|
+
|
|
49
|
+
const definition: Definition = {
|
|
50
|
+
title: componentSchemaName,
|
|
51
|
+
properties,
|
|
52
|
+
rootProperty,
|
|
53
|
+
meta: [],
|
|
54
|
+
symbolDef,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Create reference
|
|
58
|
+
const reference: Reference = {
|
|
59
|
+
title: componentSchemaName,
|
|
60
|
+
description: componentSchema.description || "",
|
|
61
|
+
canonical: `objects/${componentSchemaName}`,
|
|
62
|
+
definitions: [definition],
|
|
63
|
+
examples: {
|
|
64
|
+
groups: createSchemaExampleGroup(componentSchema as OpenAPIV3.SchemaObject)
|
|
65
|
+
},
|
|
66
|
+
type: ReferenceType.REST_COMPONENT_SCHEMA,
|
|
67
|
+
context: {
|
|
68
|
+
componentSchema: componentSchemaName,
|
|
69
|
+
group: ["Objects"]
|
|
70
|
+
} as OpenAPIReferenceContext
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// TODO: !!!! better api !!!!
|
|
74
|
+
reference.__UNSAFE_selector = function __UNSAFE_selector(selector: string) {
|
|
75
|
+
switch (selector) {
|
|
76
|
+
case "[schema]": {
|
|
77
|
+
return openapi
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
case "[component]": {
|
|
81
|
+
return componentSchema
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
default:
|
|
85
|
+
return null
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
references.push(reference);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return references;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function createSchemaExampleGroup(schema: OpenAPIV3.SchemaObject, map: any): ExampleGroup[] {
|
|
96
|
+
const example = generateSchemaExample(schema);
|
|
97
|
+
if (!example) {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const tabs: CodeBlockTab[] = [{
|
|
102
|
+
title: 'json',
|
|
103
|
+
language: 'json',
|
|
104
|
+
code: JSON.stringify(example, null, 2)
|
|
105
|
+
}];
|
|
106
|
+
|
|
107
|
+
return [{
|
|
108
|
+
description: 'Example',
|
|
109
|
+
examples: [{
|
|
110
|
+
codeblock: {
|
|
111
|
+
tabs
|
|
112
|
+
}
|
|
113
|
+
}]
|
|
114
|
+
}];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function definitionPropertyTypeDef(
|
|
118
|
+
schema: OpenAPIV3.SchemaObject | undefined,
|
|
119
|
+
) {
|
|
120
|
+
if (!schema) {
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
let typeDef: SymbolDef | undefined
|
|
125
|
+
let oasSchema = schema as OasJSONSchema
|
|
126
|
+
if (oasSchema.type === "array") {
|
|
127
|
+
oasSchema = oasSchema.items as OasJSONSchema
|
|
128
|
+
}
|
|
129
|
+
if (oasSchema?.__internal_getRefPath) {
|
|
130
|
+
const symbolId = oasSchema.__internal_getRefPath()
|
|
131
|
+
|
|
132
|
+
typeDef = {
|
|
133
|
+
id: symbolId,
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return typeDef
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function generateSchemaExample(
|
|
141
|
+
schema: OpenAPIV3.SchemaObject,
|
|
142
|
+
visitedExample?: Map<OpenAPIV3.SchemaObject, any>,
|
|
143
|
+
parent?: any
|
|
144
|
+
): any {
|
|
145
|
+
if (!schema) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
if (!visitedExample) {
|
|
149
|
+
visitedExample = new Map<OpenAPIV3.SchemaObject, any>();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const cached = visitedExample.get(schema)
|
|
153
|
+
if (cached) {
|
|
154
|
+
return JSON.parse(JSON.stringify(cached)); // Return a deep copy of the cached example
|
|
155
|
+
}
|
|
156
|
+
if (parent) {
|
|
157
|
+
visitedExample.set(schema, parent);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Handle examples array
|
|
161
|
+
if ('examples' in schema && Array.isArray(schema.examples)) {
|
|
162
|
+
const v = schema.examples[0];
|
|
163
|
+
visitedExample.set(schema, v);
|
|
164
|
+
return v; // Return the first example from the examples array
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Handle single example
|
|
168
|
+
if ('example' in schema && schema.example !== undefined) {
|
|
169
|
+
const v = schema.example;
|
|
170
|
+
visitedExample.set(schema, v);
|
|
171
|
+
return v; // Return the single example if it exists
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Handle object type with properties
|
|
175
|
+
if (schema.type === 'object' && schema.properties) {
|
|
176
|
+
const result: Record<string, any> = {};
|
|
177
|
+
for (const [propName, propSchema] of Object.entries(schema.properties)) {
|
|
178
|
+
result[propName] = generateSchemaExample(propSchema as OpenAPIV3.SchemaObject, visitedExample, result);
|
|
179
|
+
}
|
|
180
|
+
visitedExample.set(schema, result);
|
|
181
|
+
return result;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Handle array type
|
|
185
|
+
if (schema.type === 'array' && schema.items) {
|
|
186
|
+
const itemExample = generateSchemaExample(schema.items as OpenAPIV3.SchemaObject, visitedExample);
|
|
187
|
+
const v = itemExample ? [itemExample] : [];
|
|
188
|
+
visitedExample.set(schema, v);
|
|
189
|
+
|
|
190
|
+
return v; // Return an array with a single item example
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Handle primitive types with default values
|
|
194
|
+
switch (schema.type) {
|
|
195
|
+
case 'string':
|
|
196
|
+
return '';
|
|
197
|
+
case 'number':
|
|
198
|
+
case 'integer':
|
|
199
|
+
return 0;
|
|
200
|
+
case 'boolean':
|
|
201
|
+
return false;
|
|
202
|
+
default:
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import {OpenAPIV3} from "openapi-types";
|
|
2
|
+
import Oas from "oas";
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
import {Operation} from 'oas/operation'; // TODO: fix ts
|
|
5
|
+
import oasToSnippet from "@readme/oas-to-snippet";
|
|
6
|
+
import OpenAPISampler from "openapi-sampler";
|
|
7
|
+
import type {JSONSchema7} from "json-schema";
|
|
8
|
+
|
|
9
|
+
import {ExampleGroup, Example, CodeBlockTab} from "@xyd-js/uniform";
|
|
10
|
+
|
|
11
|
+
import {BUILT_IN_PROPERTIES} from "../const";
|
|
12
|
+
import {xDocsLanguages} from "../xdocs";
|
|
13
|
+
|
|
14
|
+
// TODO: custom snippet languages options
|
|
15
|
+
const DEFAULT_CODE_LANGUAGES = ["shell", "javascript", "python", "go"]
|
|
16
|
+
|
|
17
|
+
// TODO: option with another languages
|
|
18
|
+
export function oapExamples(
|
|
19
|
+
oas: Oas,
|
|
20
|
+
operation: Operation,
|
|
21
|
+
visitedExamples?: Map<JSONSchema7 | JSONSchema7[], any>
|
|
22
|
+
): ExampleGroup[] {
|
|
23
|
+
const exampleGroups = [
|
|
24
|
+
...reqExamples(operation, oas, visitedExamples),
|
|
25
|
+
...resBodyExmaples(operation, oas, visitedExamples),
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
return exampleGroups
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function langFallback(lang: string): string {
|
|
32
|
+
const langLower = lang.toLowerCase()
|
|
33
|
+
|
|
34
|
+
switch (langLower) {
|
|
35
|
+
case "curl": {
|
|
36
|
+
return "shell";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return langLower;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function smartDeepCopy<T>(obj: T, excludeProps: string[] = []): T {
|
|
44
|
+
const seen = new WeakMap();
|
|
45
|
+
|
|
46
|
+
function copy(value: any): any {
|
|
47
|
+
// Handle primitives and null
|
|
48
|
+
if (value === null || typeof value !== 'object') {
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Handle arrays
|
|
53
|
+
if (Array.isArray(value)) {
|
|
54
|
+
return value.map(copy);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Handle dates
|
|
58
|
+
if (value instanceof Date) {
|
|
59
|
+
return new Date(value);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Check for circular references
|
|
63
|
+
if (seen.has(value)) {
|
|
64
|
+
return seen.get(value);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Create new object
|
|
68
|
+
const result: any = {};
|
|
69
|
+
seen.set(value, result);
|
|
70
|
+
|
|
71
|
+
// Copy all properties except excluded ones
|
|
72
|
+
for (const [key, val] of Object.entries(value)) {
|
|
73
|
+
const propPath = key;
|
|
74
|
+
if (!excludeProps.some(prop => propPath.startsWith(prop))) {
|
|
75
|
+
result[key] = copy(val);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return copy(obj);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function excludeProperties(operation: Operation, excludeProps: string[]): Operation {
|
|
86
|
+
return smartDeepCopy(operation, excludeProps);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function reqExamples(operation: Operation, oas: Oas, vistedExamples?: Map<JSONSchema7 | JSONSchema7[], any>): ExampleGroup[] {
|
|
90
|
+
const exampleGroups: ExampleGroup[] = []
|
|
91
|
+
const examples: Example[] = []
|
|
92
|
+
const tabs: CodeBlockTab[] = []
|
|
93
|
+
|
|
94
|
+
// Handle x-codeSamples if present
|
|
95
|
+
if (operation.schema['x-codeSamples']) {
|
|
96
|
+
const codeSamples = operation.schema['x-codeSamples'] as Array<{ lang: string; source: string }>
|
|
97
|
+
const codeSampleTabs: CodeBlockTab[] = codeSamples.map(sample => ({
|
|
98
|
+
title: sample.lang,
|
|
99
|
+
language: langFallback(sample.lang),
|
|
100
|
+
code: sample.source
|
|
101
|
+
}))
|
|
102
|
+
|
|
103
|
+
if (codeSampleTabs.length > 0) {
|
|
104
|
+
examples.push({
|
|
105
|
+
codeblock: {
|
|
106
|
+
tabs: codeSampleTabs
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
exampleGroups.push({
|
|
111
|
+
description: "Example request",
|
|
112
|
+
examples
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
return exampleGroups
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Create a single object with all parameters grouped by their location
|
|
120
|
+
const paramData = operation.schema.parameters
|
|
121
|
+
? (operation.schema.parameters as OpenAPIV3.ParameterObject[]).reduce((acc, param) => {
|
|
122
|
+
const location = param.in || 'query'
|
|
123
|
+
if (!acc[location]) {
|
|
124
|
+
acc[location] = {}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let value = param.example
|
|
128
|
+
if (!value && param.schema) {
|
|
129
|
+
value = OpenAPISampler.sample(sanitizeSchema(param.schema as JSONSchema7))
|
|
130
|
+
}
|
|
131
|
+
if (value !== undefined) {
|
|
132
|
+
acc[location][param.name] = value
|
|
133
|
+
}
|
|
134
|
+
return acc
|
|
135
|
+
}, {} as Record<string, Record<string, any>>)
|
|
136
|
+
: {}
|
|
137
|
+
|
|
138
|
+
// Get request body data if it exists
|
|
139
|
+
let bodyData = {}
|
|
140
|
+
if (operation.schema.requestBody) {
|
|
141
|
+
const body = operation.schema.requestBody as OpenAPIV3.RequestBodyObject
|
|
142
|
+
const contentTypes = Object.keys(body.content)
|
|
143
|
+
|
|
144
|
+
if (contentTypes.length > 0) {
|
|
145
|
+
const contentType = contentTypes[contentTypes.length - 1]
|
|
146
|
+
const content = body.content[contentType]
|
|
147
|
+
let schema = content?.schema as JSONSchema7
|
|
148
|
+
|
|
149
|
+
if (schema) {
|
|
150
|
+
schema = fixAllOfBug(schema)
|
|
151
|
+
schema = sanitizeSchema(schema)
|
|
152
|
+
|
|
153
|
+
let requestData
|
|
154
|
+
if (content.examples) {
|
|
155
|
+
const requestExample = content.examples["request"]
|
|
156
|
+
if (requestExample && "value" in requestExample) {
|
|
157
|
+
requestData = requestExample.value
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (!requestData) {
|
|
162
|
+
requestData = OpenAPISampler.sample(schema)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (contentType === 'application/x-www-form-urlencoded') {
|
|
166
|
+
bodyData = {formData: requestData}
|
|
167
|
+
} else {
|
|
168
|
+
bodyData = {body: requestData}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Check if we have parameters or request body
|
|
175
|
+
const hasRequestBody = operation.schema.requestBody !== undefined
|
|
176
|
+
const hasParameters = Object.keys(paramData).length > 0
|
|
177
|
+
|
|
178
|
+
// Generate examples if we have either parameters or request body, or if we have neither
|
|
179
|
+
if (hasParameters || hasRequestBody || (!hasRequestBody && !hasParameters)) {
|
|
180
|
+
const langs = xDocsLanguages(operation.api) || DEFAULT_CODE_LANGUAGES
|
|
181
|
+
langs.forEach(lang => {
|
|
182
|
+
// TODO: needed for circural references - find better solution?
|
|
183
|
+
const operationCopy = excludeProperties(operation, ['api.components', 'api.paths']);
|
|
184
|
+
const {code} = oasToSnippet(oas, operationCopy, {
|
|
185
|
+
...paramData,
|
|
186
|
+
...bodyData
|
|
187
|
+
}, null, lang)
|
|
188
|
+
|
|
189
|
+
tabs.push({
|
|
190
|
+
title: lang,
|
|
191
|
+
language: lang,
|
|
192
|
+
code: code || ""
|
|
193
|
+
})
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
if (tabs.length > 0) {
|
|
197
|
+
examples.push({
|
|
198
|
+
codeblock: {
|
|
199
|
+
tabs
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (examples.length > 0) {
|
|
205
|
+
exampleGroups.push({
|
|
206
|
+
description: "Example request",
|
|
207
|
+
examples
|
|
208
|
+
})
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return exampleGroups
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function resBodyExmaples(operation: Operation, oas: Oas, vistedExamples?: Map<JSONSchema7 | JSONSchema7[], any>): ExampleGroup[] {
|
|
216
|
+
const exampleGroups: ExampleGroup[] = []
|
|
217
|
+
|
|
218
|
+
if (operation.schema.responses) {
|
|
219
|
+
const responses = operation.schema.responses as OpenAPIV3.ResponsesObject
|
|
220
|
+
|
|
221
|
+
const examples: Example[] = []
|
|
222
|
+
|
|
223
|
+
Object.entries(responses).forEach(([status, r]) => {
|
|
224
|
+
const response = r as OpenAPIV3.ResponseObject
|
|
225
|
+
if (!response.content) {
|
|
226
|
+
return
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const contentTypes = Object.keys(response.content)
|
|
230
|
+
if (contentTypes.length === 0) {
|
|
231
|
+
return
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const tabs: CodeBlockTab[] = []
|
|
235
|
+
|
|
236
|
+
for (const contentType of contentTypes) {
|
|
237
|
+
const content = response.content[contentType]
|
|
238
|
+
const schema = content?.schema as JSONSchema7
|
|
239
|
+
|
|
240
|
+
if (!schema) {
|
|
241
|
+
continue
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
let responseData
|
|
245
|
+
// Check for examples in the response content
|
|
246
|
+
if (content.examples) {
|
|
247
|
+
const responseExample = content.examples["response"]
|
|
248
|
+
if (responseExample && "value" in responseExample) {
|
|
249
|
+
responseData = responseExample.value
|
|
250
|
+
} else {
|
|
251
|
+
const namedExamples: Example[] = []
|
|
252
|
+
const exampleNames = Object.keys(content.examples)
|
|
253
|
+
|
|
254
|
+
exampleNames.forEach((exampleName) => {
|
|
255
|
+
const data = content?.examples?.[exampleName]
|
|
256
|
+
|
|
257
|
+
if (!data || !("value" in data) || typeof data.value != "object") {
|
|
258
|
+
return
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
namedExamples.push({
|
|
262
|
+
description: "",
|
|
263
|
+
codeblock: {
|
|
264
|
+
title: exampleName,
|
|
265
|
+
tabs: [
|
|
266
|
+
{
|
|
267
|
+
title: "application/json", // TODO: support multiple types
|
|
268
|
+
language: "json",
|
|
269
|
+
code: JSON.stringify(data.value, null, 2) || "",
|
|
270
|
+
}
|
|
271
|
+
]
|
|
272
|
+
}
|
|
273
|
+
})
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
if (namedExamples.length === 1) {
|
|
277
|
+
const firstCodeblock = namedExamples[0].codeblock
|
|
278
|
+
|
|
279
|
+
tabs.push(
|
|
280
|
+
...firstCodeblock.tabs.map(tab => ({
|
|
281
|
+
...tab,
|
|
282
|
+
title: contentType
|
|
283
|
+
}))
|
|
284
|
+
)
|
|
285
|
+
} else {
|
|
286
|
+
exampleGroups.push({
|
|
287
|
+
description: "",
|
|
288
|
+
examples: namedExamples
|
|
289
|
+
})
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
continue
|
|
293
|
+
}
|
|
294
|
+
} else if (content.example) {
|
|
295
|
+
responseData = content.example
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// If no example found, generate sample data from schema
|
|
299
|
+
if (!responseData) {
|
|
300
|
+
responseData = OpenAPISampler.sample(sanitizeSchema(schema))
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
let extension = "text"
|
|
304
|
+
switch (contentType) {
|
|
305
|
+
case "application/json":
|
|
306
|
+
case "application/problem+json":
|
|
307
|
+
case "application/vnd.api+json": {
|
|
308
|
+
extension = "json"
|
|
309
|
+
break
|
|
310
|
+
}
|
|
311
|
+
case "application/xml":
|
|
312
|
+
case "text/xml":
|
|
313
|
+
case "application/problem+xml": {
|
|
314
|
+
extension = "xml"
|
|
315
|
+
break
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
tabs.push({
|
|
320
|
+
title: contentType,
|
|
321
|
+
language: extension,
|
|
322
|
+
code: JSON.stringify(responseData, null, 2) || "",
|
|
323
|
+
})
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (tabs.length > 0) {
|
|
327
|
+
examples.push({
|
|
328
|
+
codeblock: {
|
|
329
|
+
title: status,
|
|
330
|
+
tabs
|
|
331
|
+
}
|
|
332
|
+
})
|
|
333
|
+
}
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
if (examples.length > 0) {
|
|
337
|
+
exampleGroups.push({
|
|
338
|
+
description: "Example response",
|
|
339
|
+
examples
|
|
340
|
+
})
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return exampleGroups
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* fixAllOfBug fixes below case:
|
|
349
|
+
*
|
|
350
|
+
* ```yaml
|
|
351
|
+
* allOf:
|
|
352
|
+
* - $ref: '#/components/schemas/SomeSchema'
|
|
353
|
+
* - type: object
|
|
354
|
+
* required:
|
|
355
|
+
* properties:
|
|
356
|
+
* ```
|
|
357
|
+
*
|
|
358
|
+
*/
|
|
359
|
+
function fixAllOfBug(schema: JSONSchema7) {
|
|
360
|
+
const modifiedSchema = {...schema}
|
|
361
|
+
|
|
362
|
+
if (schema?.allOf) {
|
|
363
|
+
schema.allOf.forEach((prop, i) => {
|
|
364
|
+
const propObj = prop as object
|
|
365
|
+
|
|
366
|
+
if ("properties" in propObj && !propObj["properties"]) {
|
|
367
|
+
delete modifiedSchema.allOf?.[i]
|
|
368
|
+
}
|
|
369
|
+
})
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return modifiedSchema
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
function sanitizeSchema(
|
|
377
|
+
schema: any,
|
|
378
|
+
vistedExamples: Map<JSONSchema7 | JSONSchema7[], any> = new Map(),
|
|
379
|
+
parent?: any
|
|
380
|
+
): any {
|
|
381
|
+
if (vistedExamples.has(schema)) {
|
|
382
|
+
const cached = vistedExamples.get(schema);
|
|
383
|
+
|
|
384
|
+
if (typeof cached === 'object') {
|
|
385
|
+
return JSON.parse(JSON.stringify(cached)); // Return a deep copy of the cached schema
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return cached
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (parent) {
|
|
392
|
+
vistedExamples.set(schema, parent);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (!schema || typeof schema !== 'object') {
|
|
396
|
+
vistedExamples.set(schema, schema);
|
|
397
|
+
return schema;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (Array.isArray(schema)) {
|
|
401
|
+
const v = schema.map(item => sanitizeSchema(item, vistedExamples));
|
|
402
|
+
vistedExamples.set(schema, v);
|
|
403
|
+
return v;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const cleaned: any = {};
|
|
407
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
408
|
+
if (key === "__UNSAFE_refPath") {
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
if (!BUILT_IN_PROPERTIES[key]) {
|
|
412
|
+
cleaned[key] = sanitizeSchema(value, vistedExamples, cleaned);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
vistedExamples.set(schema, cleaned);
|
|
416
|
+
return cleaned;
|
|
417
|
+
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {OpenAPIV3} from "openapi-types";
|
|
2
|
+
|
|
2
3
|
import {DefinitionProperty} from "@xyd-js/uniform";
|
|
3
4
|
|
|
5
|
+
import { schemaObjectToUniformDefinitionPropertyMeta } from "../oas-core";
|
|
6
|
+
|
|
4
7
|
// oapParametersToDefinitionProperties converts OpenAPI parameters to uniform DefinitionProperties
|
|
5
8
|
export function oapParametersToDefinitionProperties(
|
|
6
9
|
parameters: OpenAPIV3.ParameterObject[]
|
|
@@ -14,12 +17,23 @@ export function oapParametersToDefinitionProperties(
|
|
|
14
17
|
|
|
15
18
|
const schema = param.schema as OpenAPIV3.SchemaObject
|
|
16
19
|
|
|
20
|
+
const meta = [
|
|
21
|
+
...(schemaObjectToUniformDefinitionPropertyMeta(schema, param.name) || []),
|
|
22
|
+
...(schemaObjectToUniformDefinitionPropertyMeta(param, param.name) || []),
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
let oapV2Type = ""
|
|
26
|
+
if ("type" in param) {
|
|
27
|
+
oapV2Type = param.type as string
|
|
28
|
+
}
|
|
29
|
+
|
|
17
30
|
const property: DefinitionProperty = {
|
|
18
31
|
name: param.name,
|
|
19
|
-
type: schema
|
|
20
|
-
description: param.description || ""
|
|
32
|
+
type: schema?.type || oapV2Type || "",
|
|
33
|
+
description: param.description || "",
|
|
34
|
+
meta
|
|
21
35
|
}
|
|
22
|
-
|
|
36
|
+
|
|
23
37
|
parameterIn[param.in].push(property)
|
|
24
38
|
})
|
|
25
39
|
|