@scalar/oas-utils 0.1.17 → 0.2.1
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 +19 -0
- package/dist/entities/index.d.ts +2 -0
- package/dist/entities/index.d.ts.map +1 -0
- package/dist/entities/index.js +1 -0
- package/dist/entities/workspace/collection/collection.d.ts +314 -0
- package/dist/entities/workspace/collection/collection.d.ts.map +1 -0
- package/dist/entities/workspace/collection/collection.js +112 -0
- package/dist/entities/workspace/collection/index.d.ts +2 -0
- package/dist/entities/workspace/collection/index.d.ts.map +1 -0
- package/dist/entities/workspace/collection/index.js +1 -0
- package/dist/entities/workspace/cookie/cookie.d.ts +84 -0
- package/dist/entities/workspace/cookie/cookie.d.ts.map +1 -0
- package/dist/entities/workspace/cookie/cookie.js +44 -0
- package/dist/entities/workspace/cookie/index.d.ts +2 -0
- package/dist/entities/workspace/cookie/index.d.ts.map +1 -0
- package/dist/entities/workspace/cookie/index.js +1 -0
- package/dist/entities/workspace/environment/environment.d.ts +55 -0
- package/dist/entities/workspace/environment/environment.d.ts.map +1 -0
- package/dist/entities/workspace/environment/environment.js +23 -0
- package/dist/entities/workspace/environment/index.d.ts +2 -0
- package/dist/entities/workspace/environment/index.d.ts.map +1 -0
- package/dist/entities/workspace/environment/index.js +1 -0
- package/dist/entities/workspace/folder/folder.d.ts +36 -0
- package/dist/entities/workspace/folder/folder.d.ts.map +1 -0
- package/dist/entities/workspace/folder/folder.js +21 -0
- package/dist/entities/workspace/folder/index.d.ts +2 -0
- package/dist/entities/workspace/folder/index.d.ts.map +1 -0
- package/dist/entities/workspace/folder/index.js +1 -0
- package/dist/entities/workspace/index.d.ts +2 -0
- package/dist/entities/workspace/index.d.ts.map +1 -0
- package/dist/entities/workspace/index.js +1 -0
- package/dist/entities/workspace/security-schemes/index.d.ts +2 -0
- package/dist/entities/workspace/security-schemes/index.d.ts.map +1 -0
- package/dist/entities/workspace/security-schemes/index.js +1 -0
- package/dist/entities/workspace/security-schemes/security-schemes.d.ts +19 -0
- package/dist/entities/workspace/security-schemes/security-schemes.d.ts.map +1 -0
- package/dist/entities/workspace/security-schemes/security-schemes.js +15 -0
- package/dist/entities/workspace/server/index.d.ts +2 -0
- package/dist/entities/workspace/server/index.d.ts.map +1 -0
- package/dist/entities/workspace/server/index.js +1 -0
- package/dist/entities/workspace/server/server.d.ts +84 -0
- package/dist/entities/workspace/server/server.d.ts.map +1 -0
- package/dist/entities/workspace/server/server.js +46 -0
- package/dist/entities/workspace/shared/index.d.ts +2 -0
- package/dist/entities/workspace/shared/index.d.ts.map +1 -0
- package/dist/entities/workspace/shared/index.js +1 -0
- package/dist/entities/workspace/shared/utility.d.ts +6 -0
- package/dist/entities/workspace/shared/utility.d.ts.map +1 -0
- package/dist/entities/workspace/shared/utility.js +11 -0
- package/dist/entities/workspace/spec/components.d.ts +3 -0
- package/dist/entities/workspace/spec/components.d.ts.map +1 -0
- package/dist/entities/workspace/spec/index.d.ts +5 -0
- package/dist/entities/workspace/spec/index.d.ts.map +1 -0
- package/dist/entities/workspace/spec/index.js +2 -0
- package/dist/entities/workspace/spec/parameters.d.ts +16 -0
- package/dist/entities/workspace/spec/parameters.d.ts.map +1 -0
- package/dist/entities/workspace/spec/refs.d.ts +30 -0
- package/dist/entities/workspace/spec/refs.d.ts.map +1 -0
- package/dist/entities/workspace/spec/refs.js +9 -0
- package/dist/entities/workspace/spec/request-examples.d.ts +479 -0
- package/dist/entities/workspace/spec/request-examples.d.ts.map +1 -0
- package/dist/entities/workspace/spec/request-examples.js +68 -0
- package/dist/entities/workspace/spec/requests.d.ts +149 -0
- package/dist/entities/workspace/spec/requests.d.ts.map +1 -0
- package/dist/entities/workspace/spec/requests.js +52 -0
- package/dist/entities/workspace/spec/spec.d.ts +18 -0
- package/dist/entities/workspace/spec/spec.d.ts.map +1 -0
- package/dist/entities/workspace/spec/spec.js +8 -0
- package/dist/entities/workspace/workspace.d.ts +45 -0
- package/dist/entities/workspace/workspace.d.ts.map +1 -0
- package/dist/entities/workspace/workspace.js +20 -0
- package/dist/helpers/createHash.d.ts.map +1 -0
- package/dist/helpers/createHash.js +20 -0
- package/dist/helpers/deepMerge.d.ts +7 -0
- package/dist/helpers/deepMerge.d.ts.map +1 -0
- package/dist/helpers/deepMerge.js +28 -0
- package/dist/helpers/fetchSpecFromUrl.d.ts.map +1 -0
- package/dist/helpers/fetchSpecFromUrl.js +31 -0
- package/dist/helpers/httpMethods.d.ts +93 -0
- package/dist/helpers/httpMethods.d.ts.map +1 -0
- package/dist/helpers/httpMethods.js +64 -0
- package/dist/helpers/httpStatusCodes.d.ts.map +1 -0
- package/dist/helpers/httpStatusCodes.js +252 -0
- package/dist/helpers/index.d.ts +14 -0
- package/dist/helpers/index.d.ts.map +1 -0
- package/dist/helpers/index.js +13 -0
- package/dist/helpers/iterateTitle.d.ts +5 -0
- package/dist/helpers/iterateTitle.d.ts.map +1 -0
- package/dist/helpers/iterateTitle.js +15 -0
- package/dist/helpers/json2xml.d.ts.map +1 -0
- package/dist/helpers/json2xml.js +51 -0
- package/dist/{normalizeMimeType.d.ts → helpers/normalizeMimeType.d.ts} +1 -1
- package/dist/helpers/normalizeMimeType.d.ts.map +1 -0
- package/dist/helpers/normalizeMimeType.js +20 -0
- package/dist/{normalizeMimeTypeObject.d.ts → helpers/normalizeMimeTypeObject.d.ts} +1 -1
- package/dist/helpers/normalizeMimeTypeObject.d.ts.map +1 -0
- package/dist/helpers/normalizeMimeTypeObject.js +34 -0
- package/dist/helpers/objectMerge.d.ts +5 -0
- package/dist/helpers/objectMerge.d.ts.map +1 -0
- package/dist/helpers/objectMerge.js +16 -0
- package/dist/{parse.d.ts → helpers/parse.d.ts} +1 -1
- package/dist/helpers/parse.d.ts.map +1 -0
- package/dist/helpers/parse.js +89 -0
- package/dist/helpers/prettyPrintJson.d.ts.map +1 -0
- package/dist/helpers/prettyPrintJson.js +19 -0
- package/dist/helpers/schema-model.d.ts +5 -0
- package/dist/helpers/schema-model.d.ts.map +1 -0
- package/dist/helpers/schema-model.js +21 -0
- package/dist/{ssrState.d.ts → helpers/ssrState.d.ts} +1 -1
- package/dist/helpers/ssrState.d.ts.map +1 -0
- package/dist/helpers/ssrState.js +9 -0
- package/dist/index.d.ts +0 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -914
- package/dist/spec-getters/getExampleFromSchema.d.ts.map +1 -0
- package/dist/spec-getters/getExampleFromSchema.js +246 -0
- package/dist/{getParametersFromOperation.d.ts → spec-getters/getParametersFromOperation.d.ts} +1 -1
- package/dist/spec-getters/getParametersFromOperation.d.ts.map +1 -0
- package/dist/spec-getters/getParametersFromOperation.js +44 -0
- package/dist/{getRequestBodyFromOperation.d.ts → spec-getters/getRequestBodyFromOperation.d.ts} +1 -1
- package/dist/spec-getters/getRequestBodyFromOperation.d.ts.map +1 -0
- package/dist/spec-getters/getRequestBodyFromOperation.js +199 -0
- package/dist/{getRequestFromOperation.d.ts → spec-getters/getRequestFromOperation.d.ts} +5 -1
- package/dist/spec-getters/getRequestFromOperation.d.ts.map +1 -0
- package/dist/spec-getters/getRequestFromOperation.js +49 -0
- package/dist/spec-getters/index.d.ts +5 -0
- package/dist/spec-getters/index.d.ts.map +1 -0
- package/dist/spec-getters/index.js +4 -0
- package/dist/transforms/import-spec.d.ts +67 -0
- package/dist/transforms/import-spec.d.ts.map +1 -0
- package/dist/transforms/import-spec.js +136 -0
- package/dist/transforms/index.d.ts +2 -0
- package/dist/transforms/index.d.ts.map +1 -0
- package/dist/transforms/index.js +1 -0
- package/dist/types.d.ts +43 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +63 -14
- package/dist/createHash.d.ts.map +0 -1
- package/dist/fetchSpecFromUrl.d.ts.map +0 -1
- package/dist/getExampleFromSchema.d.ts.map +0 -1
- package/dist/getHarRequest.d.ts +0 -4
- package/dist/getHarRequest.d.ts.map +0 -1
- package/dist/getParametersFromOperation.d.ts.map +0 -1
- package/dist/getRequestBodyFromOperation.d.ts.map +0 -1
- package/dist/getRequestFromOperation.d.ts.map +0 -1
- package/dist/httpStatusCodes.d.ts.map +0 -1
- package/dist/json2xml.d.ts.map +0 -1
- package/dist/normalizeMimeType.d.ts.map +0 -1
- package/dist/normalizeMimeTypeObject.d.ts.map +0 -1
- package/dist/parse.d.ts.map +0 -1
- package/dist/prettyPrintJson.d.ts.map +0 -1
- package/dist/ssrState.d.ts.map +0 -1
- /package/dist/{createHash.d.ts → helpers/createHash.d.ts} +0 -0
- /package/dist/{fetchSpecFromUrl.d.ts → helpers/fetchSpecFromUrl.d.ts} +0 -0
- /package/dist/{httpStatusCodes.d.ts → helpers/httpStatusCodes.d.ts} +0 -0
- /package/dist/{json2xml.d.ts → helpers/json2xml.d.ts} +0 -0
- /package/dist/{prettyPrintJson.d.ts → helpers/prettyPrintJson.d.ts} +0 -0
- /package/dist/{getExampleFromSchema.d.ts → spec-getters/getExampleFromSchema.d.ts} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getExampleFromSchema.d.ts","sourceRoot":"","sources":["../../src/spec-getters/getExampleFromSchema.ts"],"names":[],"mappings":"AAsCA;;GAEG;AACH,eAAO,MAAM,oBAAoB,WACvB,OAAO,MAAM,EAAE,GAAG,CAAC,YACjB;IACR;;;QAGI;IACJ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,GAAG,CAAC,EAAE,OAAO,CAAA;IACb;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IACvB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,MAAM,EAAE,GAAG,CAAC,CAAA;IAC/B;;OAEG;IACH,8BAA8B,CAAC,EAAE,OAAO,CAAA;CACzC,UACM,MAAM,iBACE,OAAO,MAAM,EAAE,GAAG,CAAC,SAC3B,MAAM,KACZ,GAkSF,CAAA"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* We can use the `format` to generate some random values.
|
|
3
|
+
*/
|
|
4
|
+
function guessFromFormat(schema, fallback = '') {
|
|
5
|
+
const exampleValues = {
|
|
6
|
+
// 'date-time': '1970-01-01T00:00:00Z',
|
|
7
|
+
'date-time': new Date().toISOString(),
|
|
8
|
+
// 'date': '1970-01-01',
|
|
9
|
+
'date': new Date().toISOString().split('T')[0],
|
|
10
|
+
'email': 'hello@example.com',
|
|
11
|
+
'hostname': 'example.com',
|
|
12
|
+
// https://tools.ietf.org/html/rfc6531#section-3.3
|
|
13
|
+
'idn-email': 'jane.doe@example.com',
|
|
14
|
+
// https://tools.ietf.org/html/rfc5890#section-2.3.2.3
|
|
15
|
+
'idn-hostname': 'example.com',
|
|
16
|
+
'ipv4': '127.0.0.1',
|
|
17
|
+
'ipv6': '51d4:7fab:bfbf:b7d7:b2cb:d4b4:3dad:d998',
|
|
18
|
+
'iri-reference': '/entitiy/1',
|
|
19
|
+
// https://tools.ietf.org/html/rfc3987
|
|
20
|
+
'iri': 'https://example.com/entity/123',
|
|
21
|
+
'json-pointer': '/nested/objects',
|
|
22
|
+
'password': 'super-secret',
|
|
23
|
+
'regex': '/[a-z]/',
|
|
24
|
+
// https://tools.ietf.org/html/draft-handrews-relative-json-pointer-01
|
|
25
|
+
'relative-json-pointer': '1/nested/objects',
|
|
26
|
+
// full-time in https://tools.ietf.org/html/rfc3339#section-5.6
|
|
27
|
+
// 'time': '00:00:00Z',
|
|
28
|
+
'time': new Date().toISOString().split('T')[1].split('.')[0],
|
|
29
|
+
// either a URI or relative-reference https://tools.ietf.org/html/rfc3986#section-4.1
|
|
30
|
+
'uri-reference': '../folder',
|
|
31
|
+
'uri-template': 'https://example.com/{id}',
|
|
32
|
+
'uri': 'https://example.com',
|
|
33
|
+
'uuid': '123e4567-e89b-12d3-a456-426614174000',
|
|
34
|
+
};
|
|
35
|
+
return exampleValues[schema.format] ?? fallback;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* This function takes a properties object and generates an example response content.
|
|
39
|
+
*/
|
|
40
|
+
const getExampleFromSchema = (schema, options, level = 0, parentSchema, name) => {
|
|
41
|
+
// Break an infinite loop
|
|
42
|
+
if (level > 5) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
// Sometimes, we just want the structure and no values.
|
|
46
|
+
// But if `emptyString` is set, we do want to see some values.
|
|
47
|
+
const makeUpRandomData = !!options?.emptyString;
|
|
48
|
+
// Check if the property is read-only
|
|
49
|
+
if (options?.mode === 'write' && schema.readOnly) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
// Check if the property is write-only
|
|
53
|
+
if (options?.mode === 'read' && schema.writeOnly) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
// Use given variables as values
|
|
57
|
+
if (schema['x-variable']) {
|
|
58
|
+
const value = options?.variables?.[schema['x-variable']];
|
|
59
|
+
// Return the value if it’s defined
|
|
60
|
+
if (value !== undefined) {
|
|
61
|
+
// Type-casting
|
|
62
|
+
if (schema.type === 'number' || schema.type === 'integer') {
|
|
63
|
+
return parseInt(value, 10);
|
|
64
|
+
}
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Use the first example, if there’s an array
|
|
69
|
+
if (Array.isArray(schema.examples) && schema.examples.length > 0) {
|
|
70
|
+
return schema.examples[0];
|
|
71
|
+
}
|
|
72
|
+
// Use an example, if there’s one
|
|
73
|
+
if (schema.example !== undefined) {
|
|
74
|
+
return schema.example;
|
|
75
|
+
}
|
|
76
|
+
// Use a default value, if there’s one
|
|
77
|
+
if (schema.default !== undefined) {
|
|
78
|
+
return schema.default;
|
|
79
|
+
}
|
|
80
|
+
// enum: [ 'available', 'pending', 'sold' ]
|
|
81
|
+
if (schema.enum !== undefined) {
|
|
82
|
+
return schema.enum[0];
|
|
83
|
+
}
|
|
84
|
+
// Check if the property is required
|
|
85
|
+
const isObjectOrArray = schema.type === 'object' || schema.type === 'array';
|
|
86
|
+
if (!isObjectOrArray && options?.omitEmptyAndOptionalProperties === true) {
|
|
87
|
+
const isRequired = schema.required === true ||
|
|
88
|
+
parentSchema?.required === true ||
|
|
89
|
+
parentSchema?.required?.includes(name ?? schema.name);
|
|
90
|
+
if (!isRequired) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Object
|
|
95
|
+
if (schema.type === 'object' || schema.properties !== undefined) {
|
|
96
|
+
const response = {};
|
|
97
|
+
// Regular properties
|
|
98
|
+
if (schema.properties !== undefined) {
|
|
99
|
+
Object.keys(schema.properties).forEach((propertyName) => {
|
|
100
|
+
const property = schema.properties[propertyName];
|
|
101
|
+
const propertyXmlTagName = options?.xml ? property.xml?.name : undefined;
|
|
102
|
+
response[propertyXmlTagName ?? propertyName] = getExampleFromSchema(property, options, level + 1, schema, propertyName);
|
|
103
|
+
if (typeof response[propertyXmlTagName ?? propertyName] === 'undefined') {
|
|
104
|
+
delete response[propertyXmlTagName ?? propertyName];
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
if (schema.anyOf !== undefined) {
|
|
109
|
+
Object.assign(response, getExampleFromSchema(schema.anyOf[0]), options, level + 1);
|
|
110
|
+
}
|
|
111
|
+
else if (schema.oneOf !== undefined) {
|
|
112
|
+
Object.assign(response, getExampleFromSchema(schema.oneOf[0]), options, level + 1);
|
|
113
|
+
}
|
|
114
|
+
else if (schema.allOf !== undefined) {
|
|
115
|
+
Object.assign(response, ...schema.allOf
|
|
116
|
+
.map((item) => getExampleFromSchema(item, options, level + 1, schema))
|
|
117
|
+
.filter((item) => item !== undefined));
|
|
118
|
+
}
|
|
119
|
+
// Merge additionalProperties
|
|
120
|
+
if (schema.additionalProperties !== undefined &&
|
|
121
|
+
schema.additionalProperties !== false) {
|
|
122
|
+
const additionalSchema = getExampleFromSchema(schema.additionalProperties, options, level + 1);
|
|
123
|
+
// Merge objects, but not arrays
|
|
124
|
+
if (additionalSchema &&
|
|
125
|
+
typeof additionalSchema === 'object' &&
|
|
126
|
+
!Array.isArray(additionalSchema)) {
|
|
127
|
+
return {
|
|
128
|
+
...response,
|
|
129
|
+
...getExampleFromSchema(schema.additionalProperties, options, level + 1),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
// Add an example for nullable properties
|
|
133
|
+
if (additionalSchema === null) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
// Otherwise, add an example of key-value pair
|
|
137
|
+
const additionalProperties = getExampleFromSchema(schema.additionalProperties, {
|
|
138
|
+
...options,
|
|
139
|
+
// Let’s just add the additionalProperties, even if they are optional.
|
|
140
|
+
omitEmptyAndOptionalProperties: false,
|
|
141
|
+
}, level + 1);
|
|
142
|
+
return {
|
|
143
|
+
...response,
|
|
144
|
+
...(additionalProperties === undefined
|
|
145
|
+
? {}
|
|
146
|
+
: { '{{key}}': additionalProperties }),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return response;
|
|
150
|
+
}
|
|
151
|
+
// Array
|
|
152
|
+
if (schema.type === 'array' || schema.items !== undefined) {
|
|
153
|
+
const itemsXmlTagName = schema?.items?.xml?.name;
|
|
154
|
+
const wrapItems = !!(options?.xml && schema.xml?.wrapped && itemsXmlTagName);
|
|
155
|
+
if (schema.example !== undefined) {
|
|
156
|
+
return wrapItems ? { [itemsXmlTagName]: schema.example } : schema.example;
|
|
157
|
+
}
|
|
158
|
+
// Check whether the array has a anyOf, oneOf, or allOf rule
|
|
159
|
+
if (schema.items) {
|
|
160
|
+
// Check for all those rules
|
|
161
|
+
const rules = ['anyOf', 'oneOf', 'allOf'];
|
|
162
|
+
for (const rule of rules) {
|
|
163
|
+
// Skip early if the rule is not defined
|
|
164
|
+
if (!schema.items[rule]) {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
// Otherwise generate examples for the rule
|
|
168
|
+
const schemas = ['anyOf', 'oneOf'].includes(rule)
|
|
169
|
+
? // Use the first item only
|
|
170
|
+
schema.items[rule].slice(0, 1)
|
|
171
|
+
: // Use all items
|
|
172
|
+
schema.items[rule];
|
|
173
|
+
const exampleFromRule = schemas
|
|
174
|
+
.map((item) => getExampleFromSchema(item, options, level + 1, schema))
|
|
175
|
+
.filter((item) => item !== undefined);
|
|
176
|
+
return wrapItems
|
|
177
|
+
? [{ [itemsXmlTagName]: exampleFromRule }]
|
|
178
|
+
: exampleFromRule;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (schema.items?.type) {
|
|
182
|
+
const exampleFromSchema = getExampleFromSchema(schema.items, options, level + 1);
|
|
183
|
+
return wrapItems
|
|
184
|
+
? [{ [itemsXmlTagName]: exampleFromSchema }]
|
|
185
|
+
: [exampleFromSchema];
|
|
186
|
+
}
|
|
187
|
+
return [];
|
|
188
|
+
}
|
|
189
|
+
const exampleValues = {
|
|
190
|
+
string: makeUpRandomData
|
|
191
|
+
? guessFromFormat(schema, options?.emptyString)
|
|
192
|
+
: '',
|
|
193
|
+
boolean: true,
|
|
194
|
+
integer: schema.min ?? 1,
|
|
195
|
+
number: schema.min ?? 1,
|
|
196
|
+
array: [],
|
|
197
|
+
};
|
|
198
|
+
if (schema.type !== undefined && exampleValues[schema.type] !== undefined) {
|
|
199
|
+
return exampleValues[schema.type];
|
|
200
|
+
}
|
|
201
|
+
// Check if property has the `oneOf` key
|
|
202
|
+
if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0) {
|
|
203
|
+
// Get the first item from the `oneOf` array
|
|
204
|
+
const firstOneOfItem = schema.oneOf[0];
|
|
205
|
+
// Return an example for the first item
|
|
206
|
+
return getExampleFromSchema(firstOneOfItem, options, level + 1);
|
|
207
|
+
}
|
|
208
|
+
// Check if schema has the `allOf` key
|
|
209
|
+
if (Array.isArray(schema.allOf)) {
|
|
210
|
+
let example = null;
|
|
211
|
+
// Loop through all `allOf` schemas
|
|
212
|
+
schema.allOf.forEach((allOfItem) => {
|
|
213
|
+
// Return an example from the schema
|
|
214
|
+
const newExample = getExampleFromSchema(allOfItem, options, level + 1);
|
|
215
|
+
// Merge or overwrite the example
|
|
216
|
+
example =
|
|
217
|
+
typeof newExample === 'object' && typeof example === 'object'
|
|
218
|
+
? {
|
|
219
|
+
...(example ?? {}),
|
|
220
|
+
...newExample,
|
|
221
|
+
}
|
|
222
|
+
: Array.isArray(newExample) && Array.isArray(example)
|
|
223
|
+
? [...(example ?? {}), ...newExample]
|
|
224
|
+
: newExample;
|
|
225
|
+
});
|
|
226
|
+
return example;
|
|
227
|
+
}
|
|
228
|
+
// Check if schema is a union type
|
|
229
|
+
if (Array.isArray(schema.type)) {
|
|
230
|
+
// Return null if the type is nullable
|
|
231
|
+
if (schema.type.includes('null')) {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
// Return an example for the first type in the union
|
|
235
|
+
const exampleValue = exampleValues[schema.type[0]];
|
|
236
|
+
if (exampleValue !== undefined) {
|
|
237
|
+
return exampleValue;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
// Warn if the type is unknown …
|
|
241
|
+
console.warn(`[getExampleFromSchema] Unknown property type "${schema.type}".`);
|
|
242
|
+
// … and just return null for now.
|
|
243
|
+
return null;
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
export { getExampleFromSchema };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getParametersFromOperation.d.ts","sourceRoot":"","sources":["../../src/spec-getters/getParametersFromOperation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAGnE;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,oBAAoB,EAC/B,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,EACnE,YAAY,GAAE,OAAc,GAC3B,aAAa,EAAE,CAkCjB"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { getExampleFromSchema } from './getExampleFromSchema.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Get the query parameters from an operation.
|
|
5
|
+
*
|
|
6
|
+
* Example: [ { name: 'foobar', value: '' } ]
|
|
7
|
+
*
|
|
8
|
+
* - OpenAPI 3.x: Possible values are “query”, “header”, “path” or “cookie”.
|
|
9
|
+
* - Swagger 2.0: Possible values are "query", "header", "path", "formData" or "body".
|
|
10
|
+
*/
|
|
11
|
+
function getParametersFromOperation(operation, where, requiredOnly = true) {
|
|
12
|
+
const parameters = [
|
|
13
|
+
...(operation.pathParameters || []),
|
|
14
|
+
...(operation.information?.parameters || []),
|
|
15
|
+
];
|
|
16
|
+
const params = parameters
|
|
17
|
+
// query, path, header, cookie?
|
|
18
|
+
.filter((parameter) => parameter.in === where)
|
|
19
|
+
// don’t add optional parameters
|
|
20
|
+
.filter((parameter) => (requiredOnly && parameter.required) || !requiredOnly)
|
|
21
|
+
// transform them
|
|
22
|
+
.map((parameter) => ({
|
|
23
|
+
name: parameter.name,
|
|
24
|
+
description: parameter.description ?? null,
|
|
25
|
+
value: parameter.example
|
|
26
|
+
? parameter.example
|
|
27
|
+
: parameter.schema
|
|
28
|
+
? getExampleFromSchema(parameter.schema, { mode: 'write' })
|
|
29
|
+
: '',
|
|
30
|
+
required: parameter.required ?? false,
|
|
31
|
+
enabled: parameter.required ?? false,
|
|
32
|
+
}));
|
|
33
|
+
return params.sort((a, b) => {
|
|
34
|
+
if (a.required && !b.required) {
|
|
35
|
+
return -1; // Move a up if a is required and b is not
|
|
36
|
+
}
|
|
37
|
+
else if (!a.required && b.required) {
|
|
38
|
+
return 1; // Move b up if b is required and a is not
|
|
39
|
+
}
|
|
40
|
+
return 0; // Keep original order if both have the same required status
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { getParametersFromOperation };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getRequestBodyFromOperation.d.ts","sourceRoot":"","sources":["../../src/spec-getters/getRequestBodyFromOperation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAIjE;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,oBAAoB,EAC/B,kBAAkB,CAAC,EAAE,MAAM,GAAG,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA6NrC"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { json2xml } from '../helpers/json2xml.js';
|
|
2
|
+
import { normalizeMimeTypeObject } from '../helpers/normalizeMimeTypeObject.js';
|
|
3
|
+
import { prettyPrintJson } from '../helpers/prettyPrintJson.js';
|
|
4
|
+
import { getExampleFromSchema } from './getExampleFromSchema.js';
|
|
5
|
+
import { getParametersFromOperation } from './getParametersFromOperation.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Get the request body from the operation.
|
|
9
|
+
*/
|
|
10
|
+
function getRequestBodyFromOperation(operation, selectedExampleKey) {
|
|
11
|
+
// Define all supported mime types
|
|
12
|
+
const mimeTypes = [
|
|
13
|
+
'application/json',
|
|
14
|
+
'application/octet-stream',
|
|
15
|
+
'application/x-www-form-urlencoded',
|
|
16
|
+
'application/xml',
|
|
17
|
+
'multipart/form-data',
|
|
18
|
+
'text/plain',
|
|
19
|
+
];
|
|
20
|
+
// Get the content object from the operation
|
|
21
|
+
const originalContent = operation.information?.requestBody?.content;
|
|
22
|
+
const content = normalizeMimeTypeObject(originalContent);
|
|
23
|
+
// Find the first mime type that is supported
|
|
24
|
+
const mimeType = mimeTypes.find((currentMimeType) => !!content?.[currentMimeType]);
|
|
25
|
+
/** Examples */
|
|
26
|
+
const examples = content?.['application/json']?.examples;
|
|
27
|
+
// Let’s use the first example
|
|
28
|
+
const selectedExample = (examples ?? {})?.[selectedExampleKey ?? Object.keys(examples ?? {})[0]];
|
|
29
|
+
if (selectedExample) {
|
|
30
|
+
return {
|
|
31
|
+
postData: {
|
|
32
|
+
mimeType: 'application/json',
|
|
33
|
+
text: prettyPrintJson(selectedExample?.value),
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Body Parameters (Swagger 2.0)
|
|
39
|
+
*
|
|
40
|
+
* ”The payload that's appended to the HTTP request. Since there can only be one payload, there can only
|
|
41
|
+
* be one body parameter. The name of the body parameter has no effect on the parameter itself and is used
|
|
42
|
+
* for documentation purposes only. Since Form parameters are also in the payload, body and form
|
|
43
|
+
* parameters cannot exist together for the same operation.”
|
|
44
|
+
*/
|
|
45
|
+
const bodyParameters = getParametersFromOperation(operation, 'body', false);
|
|
46
|
+
if (bodyParameters.length > 0) {
|
|
47
|
+
return {
|
|
48
|
+
postData: {
|
|
49
|
+
mimeType: 'application/json',
|
|
50
|
+
text: prettyPrintJson(bodyParameters[0].value),
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* FormData Parameters (Swagger 2.0)
|
|
56
|
+
*
|
|
57
|
+
* “Form - Used to describe the payload of an HTTP request when either application/x-www-form-urlencoded,
|
|
58
|
+
* multipart/form-data or both are used as the content type of the request (in Swagger's definition, the
|
|
59
|
+
* consumes property of an operation). This is the only parameter type that can be used to send files,
|
|
60
|
+
* thus supporting the file type. Since form parameters are sent in the payload, they cannot be declared
|
|
61
|
+
* together with a body parameter for the same operation. Form parameters have a different format based on
|
|
62
|
+
* the content-type used (for further details, consult http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4):
|
|
63
|
+
* - application/x-www-form-urlencoded - Similar to the format of Query parameters but as a payload.
|
|
64
|
+
* For example, foo=1&bar=swagger - both foo and bar are form parameters. This is normally used for simple
|
|
65
|
+
* parameters that are being transferred.
|
|
66
|
+
* - multipart/form-data - each parameter takes a section in the payload with an internal header.
|
|
67
|
+
* For example, for the header Content-Disposition: form-data; name="submit-name" the name of the parameter is
|
|
68
|
+
* submit-name. This type of form parameters is more commonly used for file transfers.”
|
|
69
|
+
*/
|
|
70
|
+
const formDataParameters = getParametersFromOperation(operation, 'formData', false);
|
|
71
|
+
if (formDataParameters.length > 0) {
|
|
72
|
+
return {
|
|
73
|
+
postData: {
|
|
74
|
+
mimeType: 'application/x-www-form-urlencoded',
|
|
75
|
+
params: formDataParameters.map((parameter) => ({
|
|
76
|
+
name: parameter.name,
|
|
77
|
+
value: parameter.value,
|
|
78
|
+
})),
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
// If no mime type is supported, exit early
|
|
83
|
+
if (!mimeType) {
|
|
84
|
+
return {
|
|
85
|
+
postData: undefined,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
// Get the request body object for the mime type
|
|
89
|
+
const requestBodyObject = content?.[mimeType];
|
|
90
|
+
// Define the appropriate Content-Type headers
|
|
91
|
+
const headers = [
|
|
92
|
+
{
|
|
93
|
+
name: 'Content-Type',
|
|
94
|
+
value: mimeType,
|
|
95
|
+
},
|
|
96
|
+
];
|
|
97
|
+
// Get example from operation
|
|
98
|
+
const example = requestBodyObject?.example
|
|
99
|
+
? requestBodyObject?.example
|
|
100
|
+
: undefined;
|
|
101
|
+
// JSON
|
|
102
|
+
if (mimeType === 'application/json') {
|
|
103
|
+
const exampleFromSchema = requestBodyObject?.schema
|
|
104
|
+
? getExampleFromSchema(requestBodyObject?.schema, {
|
|
105
|
+
mode: 'write',
|
|
106
|
+
omitEmptyAndOptionalProperties: true,
|
|
107
|
+
})
|
|
108
|
+
: null;
|
|
109
|
+
const body = example ?? exampleFromSchema;
|
|
110
|
+
return {
|
|
111
|
+
headers,
|
|
112
|
+
postData: {
|
|
113
|
+
mimeType: mimeType,
|
|
114
|
+
text: typeof body === 'string' ? body : JSON.stringify(body, null, 2),
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
// XML
|
|
119
|
+
if (mimeType === 'application/xml') {
|
|
120
|
+
const exampleFromSchema = requestBodyObject?.schema
|
|
121
|
+
? getExampleFromSchema(requestBodyObject?.schema, {
|
|
122
|
+
xml: true,
|
|
123
|
+
mode: 'write',
|
|
124
|
+
omitEmptyAndOptionalProperties: true,
|
|
125
|
+
})
|
|
126
|
+
: null;
|
|
127
|
+
return {
|
|
128
|
+
headers,
|
|
129
|
+
postData: {
|
|
130
|
+
mimeType: mimeType,
|
|
131
|
+
text: example ?? json2xml(exampleFromSchema, ' '),
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
// Binary data
|
|
136
|
+
if (mimeType === 'application/octet-stream') {
|
|
137
|
+
return {
|
|
138
|
+
headers,
|
|
139
|
+
postData: {
|
|
140
|
+
mimeType: mimeType,
|
|
141
|
+
text: 'BINARY',
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
// Plain text
|
|
146
|
+
if (mimeType === 'text/plain') {
|
|
147
|
+
const exampleFromSchema = requestBodyObject?.schema
|
|
148
|
+
? getExampleFromSchema(requestBodyObject?.schema, {
|
|
149
|
+
xml: true,
|
|
150
|
+
mode: 'write',
|
|
151
|
+
omitEmptyAndOptionalProperties: true,
|
|
152
|
+
})
|
|
153
|
+
: null;
|
|
154
|
+
return {
|
|
155
|
+
headers,
|
|
156
|
+
postData: {
|
|
157
|
+
mimeType: mimeType,
|
|
158
|
+
text: example ?? exampleFromSchema ?? '',
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
// URL encoded data
|
|
163
|
+
if (mimeType === 'application/x-www-form-urlencoded') {
|
|
164
|
+
return {
|
|
165
|
+
headers,
|
|
166
|
+
postData: {
|
|
167
|
+
mimeType: mimeType,
|
|
168
|
+
// TODO: We have an object, but how do we get that kind of array from the object?
|
|
169
|
+
// Don’t forget to include nested properties … :|
|
|
170
|
+
// params: [
|
|
171
|
+
// {
|
|
172
|
+
// name: 'foo',
|
|
173
|
+
// value: 'bar',
|
|
174
|
+
// },
|
|
175
|
+
// ],
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
// URL encoded data
|
|
180
|
+
if (mimeType === 'multipart/form-data') {
|
|
181
|
+
return {
|
|
182
|
+
headers,
|
|
183
|
+
postData: {
|
|
184
|
+
mimeType: mimeType,
|
|
185
|
+
// TODO: We have an object, but how do we get that kind of array from the object?
|
|
186
|
+
// Don’t forget to include nested properties … :|
|
|
187
|
+
// params: [
|
|
188
|
+
// {
|
|
189
|
+
// name: 'foo',
|
|
190
|
+
// value: 'bar',
|
|
191
|
+
// },
|
|
192
|
+
// ],
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export { getRequestBodyFromOperation };
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import type { HarRequestWithPath, TransformedOperation } from '
|
|
1
|
+
import type { HarRequestWithPath, TransformedOperation } from '../types';
|
|
2
2
|
export declare const getRequestFromOperation: (operation: TransformedOperation, options?: {
|
|
3
|
+
/**
|
|
4
|
+
* If the path will be URL encoded, you may want to replace {curlyBrackets} with __UNDERSCORES__ to indicate an
|
|
5
|
+
* variable.
|
|
6
|
+
*/
|
|
3
7
|
replaceVariables?: boolean;
|
|
4
8
|
requiredOnly?: boolean;
|
|
5
9
|
}, selectedExampleKey?: string | number) => Partial<HarRequestWithPath>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getRequestFromOperation.d.ts","sourceRoot":"","sources":["../../src/spec-getters/getRequestFromOperation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,kBAAkB,EAGlB,oBAAoB,EACrB,MAAM,UAAU,CAAA;AAIjB,eAAO,MAAM,uBAAuB,cACvB,oBAAoB,YACrB;IACR;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,uBACoB,MAAM,GAAG,MAAM,KACnC,QAAQ,kBAAkB,CA8D5B,CAAA"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { getParametersFromOperation } from './getParametersFromOperation.js';
|
|
2
|
+
import { getRequestBodyFromOperation } from './getRequestBodyFromOperation.js';
|
|
3
|
+
|
|
4
|
+
const getRequestFromOperation = (operation, options, selectedExampleKey) => {
|
|
5
|
+
// Replace all variables of the format {something} with the uppercase variable name without the brackets
|
|
6
|
+
let path = operation.path;
|
|
7
|
+
// {id} -> 123
|
|
8
|
+
const pathParameters = getParametersFromOperation(operation, 'path', false);
|
|
9
|
+
if (pathParameters.length) {
|
|
10
|
+
const pathVariables = path.match(/{(.*?)}/g);
|
|
11
|
+
if (pathVariables) {
|
|
12
|
+
pathVariables.forEach((variable) => {
|
|
13
|
+
const variableName = variable.replace(/{|}/g, '');
|
|
14
|
+
if (pathParameters) {
|
|
15
|
+
const parameter = pathParameters.find((param) => param.name === variableName);
|
|
16
|
+
if (parameter?.value) {
|
|
17
|
+
path = path.replace(variable, parameter.value.toString());
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
// {id} -> __ID__
|
|
24
|
+
if (options?.replaceVariables === true) {
|
|
25
|
+
const pathVariables = path.match(/{(.*?)}/g);
|
|
26
|
+
if (pathVariables) {
|
|
27
|
+
pathVariables.forEach((variable) => {
|
|
28
|
+
const variableName = variable.replace(/{|}/g, '');
|
|
29
|
+
path = path.replace(variable, `__${variableName.toUpperCase()}__`);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const requestBody = getRequestBodyFromOperation(operation, selectedExampleKey);
|
|
34
|
+
return {
|
|
35
|
+
method: operation.httpVerb.toUpperCase(),
|
|
36
|
+
path,
|
|
37
|
+
headers: [
|
|
38
|
+
...getParametersFromOperation(operation, 'header', options?.requiredOnly),
|
|
39
|
+
...(requestBody?.headers ?? []),
|
|
40
|
+
],
|
|
41
|
+
// TODO: Sorry, something is off here and I don’t get it.
|
|
42
|
+
// @ts-ignore
|
|
43
|
+
postData: requestBody?.postData,
|
|
44
|
+
queryString: getParametersFromOperation(operation, 'query', options?.requiredOnly),
|
|
45
|
+
cookies: getParametersFromOperation(operation, 'cookie', options?.requiredOnly),
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export { getRequestFromOperation };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/spec-getters/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAA;AACtC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,+BAA+B,CAAA;AAC7C,cAAc,2BAA2B,CAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { getExampleFromSchema } from './getExampleFromSchema.js';
|
|
2
|
+
export { getParametersFromOperation } from './getParametersFromOperation.js';
|
|
3
|
+
export { getRequestBodyFromOperation } from './getRequestBodyFromOperation.js';
|
|
4
|
+
export { getRequestFromOperation } from './getRequestFromOperation.js';
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type Request } from '../entities/workspace/spec/index.js';
|
|
2
|
+
import type { AnyObject } from '../types';
|
|
3
|
+
/** Import an OpenAPI spec file and convert it to workspace entities */
|
|
4
|
+
export declare const importSpecToWorkspace: (spec: string | AnyObject) => Promise<{
|
|
5
|
+
tags: {
|
|
6
|
+
name: string;
|
|
7
|
+
description?: string | undefined;
|
|
8
|
+
}[];
|
|
9
|
+
folders: {
|
|
10
|
+
name: string;
|
|
11
|
+
uid: string;
|
|
12
|
+
childUids: string[];
|
|
13
|
+
description?: string | undefined;
|
|
14
|
+
}[];
|
|
15
|
+
servers: {
|
|
16
|
+
url: string;
|
|
17
|
+
uid: string;
|
|
18
|
+
description?: string | undefined;
|
|
19
|
+
variables?: Record<string, {
|
|
20
|
+
default: string;
|
|
21
|
+
uid: string;
|
|
22
|
+
enum?: string[] | undefined;
|
|
23
|
+
description?: string | undefined;
|
|
24
|
+
}> | null | undefined;
|
|
25
|
+
}[];
|
|
26
|
+
requests: Request[];
|
|
27
|
+
collection: {
|
|
28
|
+
uid: string;
|
|
29
|
+
spec: {
|
|
30
|
+
openapi: string;
|
|
31
|
+
serverUids: string[];
|
|
32
|
+
tags: {
|
|
33
|
+
name: string;
|
|
34
|
+
description?: string | undefined;
|
|
35
|
+
externalDocs?: {
|
|
36
|
+
url: string;
|
|
37
|
+
description?: string | undefined;
|
|
38
|
+
} | undefined;
|
|
39
|
+
}[];
|
|
40
|
+
info?: {
|
|
41
|
+
title: string;
|
|
42
|
+
version: string;
|
|
43
|
+
summary?: string | undefined;
|
|
44
|
+
description?: string | undefined;
|
|
45
|
+
termsOfService?: string | undefined;
|
|
46
|
+
contact?: {
|
|
47
|
+
name?: string | undefined;
|
|
48
|
+
url?: string | undefined;
|
|
49
|
+
email?: string | undefined;
|
|
50
|
+
} | undefined;
|
|
51
|
+
license?: {
|
|
52
|
+
name: string;
|
|
53
|
+
identifier?: string | undefined;
|
|
54
|
+
url?: string | undefined;
|
|
55
|
+
} | undefined;
|
|
56
|
+
} | undefined;
|
|
57
|
+
externalDocs?: {
|
|
58
|
+
url: string;
|
|
59
|
+
description?: string | undefined;
|
|
60
|
+
} | undefined;
|
|
61
|
+
};
|
|
62
|
+
selectedServerUid: string;
|
|
63
|
+
childUids: string[];
|
|
64
|
+
};
|
|
65
|
+
components: any;
|
|
66
|
+
}>;
|
|
67
|
+
//# sourceMappingURL=import-spec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-spec.d.ts","sourceRoot":"","sources":["../../src/transforms/import-spec.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,OAAO,EAAiB,MAAM,2BAA2B,CAAA;AAKvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAWxC,uEAAuE;AACvE,eAAO,MAAM,qBAAqB,SAAgB,MAAM,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmJnE,CAAA"}
|