UNPKG

16.9 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.selectSchemaType = exports.searchAllSubSchema = exports.setId = exports.getId = exports.getSubSchema = void 0;
4const tslib_1 = require("tslib");
5const JsonPointer = tslib_1.__importStar(require("../jsonPointer"));
6const schemaId_1 = tslib_1.__importDefault(require("./schemaId"));
7const type_1 = require("./type");
8function getSubSchema(rootSchema, pointer, id) {
9 const content = JsonPointer.get(rootSchema.content, JsonPointer.parse(pointer));
10 if (id == null) {
11 const subId = typeof content === 'boolean'
12 ? undefined
13 : getId(rootSchema.type, content);
14 const getParentIds = (s, result) => {
15 result.push(s.id.getAbsoluteId());
16 return s.rootSchema == null
17 ? result
18 : getParentIds(s.rootSchema, result);
19 };
20 if (subId) {
21 id = new schemaId_1.default(subId, getParentIds(rootSchema, []));
22 }
23 else {
24 id = new schemaId_1.default(pointer, getParentIds(rootSchema, []));
25 }
26 }
27 return {
28 type: rootSchema.type,
29 id,
30 content,
31 rootSchema,
32 };
33}
34exports.getSubSchema = getSubSchema;
35const Draft04Id = 'id';
36const Draft07Id = '$id';
37function getId(type, content) {
38 var _a, _b;
39 if ((0, type_1.isJsonSchemaDraft04)(content, type)) {
40 return (_a = content[Draft04Id]) !== null && _a !== void 0 ? _a : '';
41 }
42 else {
43 return (_b = content[Draft07Id]) !== null && _b !== void 0 ? _b : '';
44 }
45}
46exports.getId = getId;
47function setId(type, content, id) {
48 var _a, _b;
49 if ((0, type_1.isJsonSchemaDraft04)(content, type)) {
50 (_a = content[Draft04Id]) !== null && _a !== void 0 ? _a : (content[Draft04Id] = id);
51 }
52 else {
53 (_b = content[Draft07Id]) !== null && _b !== void 0 ? _b : (content[Draft07Id] = id);
54 }
55}
56exports.setId = setId;
57function searchAllSubSchema(schema, onFoundSchema, onFoundReference) {
58 const walkArray = (array, paths, parentIds) => {
59 if (array == null) {
60 return;
61 }
62 array.forEach((item, index) => {
63 walk(item, paths.concat(index.toString()), parentIds);
64 });
65 };
66 const walkObject = (obj, paths, parentIds) => {
67 if (obj == null) {
68 return;
69 }
70 Object.keys(obj).forEach((key) => {
71 const sub = obj[key];
72 if (sub != null) {
73 walk(sub, paths.concat(key), parentIds);
74 }
75 });
76 };
77 const walkMaybeArray = (item, paths, parentIds) => {
78 if (Array.isArray(item)) {
79 walkArray(item, paths, parentIds);
80 }
81 else {
82 walk(item, paths, parentIds);
83 }
84 };
85 const walk = (s, paths, parentIds) => {
86 if (s == null || typeof s !== 'object') {
87 return;
88 }
89 const id = getId(schema.type, s);
90 if (id && typeof id === 'string') {
91 const schemaId = new schemaId_1.default(id, parentIds);
92 const subSchema = {
93 type: schema.type,
94 id: schemaId,
95 content: s,
96 rootSchema: schema,
97 };
98 onFoundSchema(subSchema);
99 parentIds = parentIds.concat([schemaId.getAbsoluteId()]);
100 }
101 if (typeof s.$ref === 'string') {
102 const schemaId = new schemaId_1.default(s.$ref, parentIds);
103 s.$ref = schemaId.getAbsoluteId();
104 onFoundReference(schemaId);
105 }
106 walkArray(s.allOf, paths.concat('allOf'), parentIds);
107 walkArray(s.anyOf, paths.concat('anyOf'), parentIds);
108 walkArray(s.oneOf, paths.concat('oneOf'), parentIds);
109 walk(s.not, paths.concat('not'), parentIds);
110 walkMaybeArray(s.items, paths.concat('items'), parentIds);
111 walk(s.additionalItems, paths.concat('additionalItems'), parentIds);
112 walk(s.additionalProperties, paths.concat('additionalProperties'), parentIds);
113 walkObject(s.definitions, paths.concat('definitions'), parentIds);
114 walkObject(s.properties, paths.concat('properties'), parentIds);
115 walkObject(s.patternProperties, paths.concat('patternProperties'), parentIds);
116 walkMaybeArray(s.dependencies, paths.concat('dependencies'), parentIds);
117 if (schema.type === 'Draft07') {
118 if ('propertyNames' in s) {
119 walk(s.propertyNames, paths.concat('propertyNames'), parentIds);
120 walk(s.contains, paths.concat('contains'), parentIds);
121 walk(s.if, paths.concat('if'), parentIds);
122 walk(s.then, paths.concat('then'), parentIds);
123 walk(s.else, paths.concat('else'), parentIds);
124 }
125 }
126 };
127 function searchOpenApiSubSchema(openApi) {
128 function createId(paths) {
129 return '#/' + paths.join('/');
130 }
131 function convertKeyToTypeName(key) {
132 key = key.replace(/\/(.)/g, (_match, p1) => {
133 return p1.toUpperCase();
134 });
135 return key
136 .replace(/}/g, '')
137 .replace(/{/g, '$')
138 .replace(/^\//, '')
139 .replace(/[^0-9A-Za-z_$]+/g, '_');
140 }
141 function setSubIdToAnyObject(f, obj, keys) {
142 if (obj == null) {
143 return;
144 }
145 Object.keys(obj).forEach((key) => {
146 const item = obj[key];
147 if (item != null) {
148 f(item, keys.concat(convertKeyToTypeName(key)));
149 }
150 });
151 }
152 function setSubIdToParameterObject(obj, keys) {
153 if (obj == null) {
154 return;
155 }
156 addParameterSchema(Object.entries(obj), keys);
157 }
158 function setSubIdToParameters(array, keys) {
159 if (array == null) {
160 return;
161 }
162 addParameterSchema(array.map((item, index) => {
163 const key = 'name' in item ? item.name : `${index}`;
164 return [key, item];
165 }), keys);
166 }
167 function addParameterSchema(input, keys) {
168 const map = new Map();
169 const pushItem = (key, po) => {
170 let work = map.get(key);
171 if (work == null) {
172 work = [];
173 map.set(key, work);
174 }
175 work.push(po);
176 };
177 for (const [key, item] of input) {
178 if ('schema' in item) {
179 setSubId(item.schema, keys.concat(key));
180 pushItem(item.in, [key, item]);
181 }
182 if ('content' in item) {
183 setSubIdToMediaTypes(item.content, keys.concat(key));
184 pushItem(item.in, [key, item]);
185 }
186 if ('$ref' in item) {
187 setSubId(item, keys.concat(key));
188 }
189 if ('type' in item && item.in !== undefined) {
190 setSubId(item, keys.concat(key));
191 pushItem(item.in, [key, item]);
192 }
193 }
194 for (const [key, params] of map) {
195 const [paths, obj] = buildParameterSchema(key, params, keys);
196 setSubId(obj, paths);
197 }
198 }
199 function buildParameterSchema(inType, params, keys) {
200 const paths = keys
201 .slice(0, keys.length - 1)
202 .concat(inType + 'Parameters');
203 const properties = {};
204 params.forEach(([key, _]) => {
205 properties[key] = {
206 $ref: createId(keys.concat(key)),
207 };
208 });
209 return [
210 paths,
211 {
212 id: createId(paths),
213 type: 'object',
214 properties,
215 required: params
216 .filter(([_, item]) => item.required === true)
217 .map(([_, item]) => item.name),
218 },
219 ];
220 }
221 const setSubIdToResponsesV2 = (responses, keys) => setSubIdToAnyObject(setSubIdToResponseV2, responses, keys);
222 function setSubIdToResponseV2(response, keys) {
223 if (response == null) {
224 return;
225 }
226 if ('schema' in response) {
227 const s = response.schema;
228 if (s != null && s.type === 'file') {
229 return;
230 }
231 setSubId(s, keys);
232 }
233 }
234 function setSubIdToOperationV2(ops, keys) {
235 if (ops == null) {
236 return;
237 }
238 const operationId = ops.operationId;
239 if (operationId) {
240 keys = [keys[0], convertKeyToTypeName(operationId)];
241 }
242 setSubIdToParameters(ops.parameters, keys.concat('parameters'));
243 setSubIdToResponsesV2(ops.responses, keys.concat('responses'));
244 }
245 const setSubIdToPathsV2 = (paths, keys) => setSubIdToAnyObject(setSubIdToPathItemV2, paths, keys);
246 function setSubIdToPathItemV2(pathItem, keys) {
247 setSubIdToParameters(pathItem.parameters, keys.concat('parameters'));
248 setSubIdToOperationV2(pathItem.get, keys.concat('get'));
249 setSubIdToOperationV2(pathItem.put, keys.concat('put'));
250 setSubIdToOperationV2(pathItem.post, keys.concat('post'));
251 setSubIdToOperationV2(pathItem.delete, keys.concat('delete'));
252 setSubIdToOperationV2(pathItem.options, keys.concat('options'));
253 setSubIdToOperationV2(pathItem.head, keys.concat('head'));
254 setSubIdToOperationV2(pathItem.patch, keys.concat('patch'));
255 }
256 function setSubIdToMediaTypes(types, keys) {
257 if (types == null) {
258 return;
259 }
260 for (const mime of Object.keys(types)) {
261 if (/^text\/|^(?:application\/x-www-form-urlencoded$|^application\/([a-z0-9-_.]+\+)?json)$|^application\/octet-stream$|^application\/jwt$|^application\/vnd.apple.pkpass$|^multipart\/form-data$|^image\//.test(mime)) {
262 const mt = types[mime];
263 if (mt != null) {
264 setSubId(mt.schema, keys);
265 }
266 }
267 }
268 }
269 const setSubIdToRequestBodies = (bodies, keys) => setSubIdToAnyObject(setSubIdToRequestBody, bodies, keys);
270 function setSubIdToRequestBody(body, keys) {
271 if (body == null) {
272 return;
273 }
274 if ('content' in body) {
275 setSubIdToMediaTypes(body.content, keys);
276 }
277 else if ('$ref' in body) {
278 setSubId(body, keys);
279 }
280 else {
281 setSubId({ type: 'object' }, keys);
282 }
283 }
284 const setSubIdToResponsesV3 = (responses, keys) => setSubIdToAnyObject(setSubIdToResponseV3, responses, keys);
285 function setSubIdToResponseV3(response, keys) {
286 if (response == null) {
287 return;
288 }
289 if ('content' in response) {
290 setSubIdToMediaTypes(response.content, keys);
291 }
292 else if ('$ref' in response) {
293 setSubId(response, keys);
294 }
295 else {
296 setSubId({ type: 'object' }, keys);
297 }
298 }
299 function setSubIdToOperationV3(ops, keys) {
300 if (ops == null) {
301 return;
302 }
303 const operationId = ops.operationId;
304 if (operationId) {
305 keys = [keys[0], convertKeyToTypeName(operationId)];
306 }
307 setSubIdToParameters(ops.parameters, keys.concat('parameters'));
308 setSubIdToRequestBody(ops.requestBody, keys.concat('requestBody'));
309 setSubIdToResponsesV3(ops.responses, keys.concat('responses'));
310 }
311 const setSubIdToPathsV3 = (paths, keys) => setSubIdToAnyObject(setSubIdToPathItemV3, paths, keys);
312 function setSubIdToPathItemV3(pathItem, keys) {
313 setSubIdToParameters(pathItem.parameters, keys.concat('parameters'));
314 setSubIdToOperationV3(pathItem.get, keys.concat('get'));
315 setSubIdToOperationV3(pathItem.put, keys.concat('put'));
316 setSubIdToOperationV3(pathItem.post, keys.concat('post'));
317 setSubIdToOperationV3(pathItem.delete, keys.concat('delete'));
318 setSubIdToOperationV3(pathItem.options, keys.concat('options'));
319 setSubIdToOperationV3(pathItem.head, keys.concat('head'));
320 setSubIdToOperationV3(pathItem.patch, keys.concat('patch'));
321 setSubIdToOperationV3(pathItem.trace, keys.concat('trace'));
322 }
323 function setSubIdToObject(obj, paths) {
324 if (obj == null) {
325 return;
326 }
327 Object.keys(obj).forEach((key) => {
328 const sub = obj[key];
329 setSubId(sub, paths.concat(key));
330 });
331 }
332 function setSubId(s, paths) {
333 switch (typeof s) {
334 case 'object': {
335 const id = createId(paths);
336 setId(schema.type, s, id);
337 walk(s, paths, []);
338 break;
339 }
340 case 'boolean': {
341 const id = createId(paths);
342 const schemaId = new schemaId_1.default(id, []);
343 const subSchema = {
344 type: schema.type,
345 id: schemaId,
346 content: s,
347 rootSchema: schema,
348 };
349 onFoundSchema(subSchema);
350 break;
351 }
352 }
353 }
354 if ('swagger' in openApi) {
355 setSubIdToObject(openApi.definitions, ['definitions']);
356 setSubIdToParameterObject(openApi.parameters, ['parameters']);
357 setSubIdToResponsesV2(openApi.responses, ['responses']);
358 setSubIdToPathsV2(openApi.paths, ['paths']);
359 }
360 else {
361 if (openApi.components) {
362 const components = openApi.components;
363 setSubIdToObject(components.schemas, ['components', 'schemas']);
364 setSubIdToResponsesV3(components.responses, [
365 'components',
366 'responses',
367 ]);
368 setSubIdToParameterObject(components.parameters, [
369 'components',
370 'parameters',
371 ]);
372 setSubIdToRequestBodies(components.requestBodies, [
373 'components',
374 'requestBodies',
375 ]);
376 }
377 setSubIdToPathsV3(openApi.paths, ['paths']);
378 }
379 }
380 if (schema.openApiVersion != null) {
381 const obj = schema.content;
382 searchOpenApiSubSchema(obj);
383 return;
384 }
385 walk(schema.content, ['#'], []);
386}
387exports.searchAllSubSchema = searchAllSubSchema;
388function selectSchemaType(content) {
389 var _a;
390 if (typeof content === 'boolean') {
391 return { type: 'Draft07' };
392 }
393 if (typeof content !== 'object') {
394 throw new Error(`expect parameter of type object, received ${typeof content}`);
395 }
396 if ('$schema' in content) {
397 const schema = (_a = content['$schema']) !== null && _a !== void 0 ? _a : '';
398 if (/^https?:\/\/json-schema.org\/schema#?$/.test(schema)) {
399 return { type: 'Latest' };
400 }
401 const match = /^https?:\/\/json-schema\.org\/(?:draft\/(\d{4}-\d{2})|draft-(\d+))\/schema#?$/.exec(schema);
402 if (match) {
403 if (match[1] != null) {
404 switch (match[1]) {
405 case '2019-09':
406 return { type: '2019-09' };
407 case '2020-12':
408 return { type: '2020-12' };
409 }
410 }
411 const version = Number(match[2]);
412 if (version <= 4) {
413 return { type: 'Draft04' };
414 }
415 else {
416 return { type: 'Draft07' };
417 }
418 }
419 }
420 if ('swagger' in content && content.swagger === '2.0') {
421 return {
422 type: 'Draft04',
423 openApiVersion: 2,
424 };
425 }
426 if ('openapi' in content && content.openapi) {
427 const { openapi } = content;
428 if (/^3\.\d+\.\d+$/.test(openapi)) {
429 return {
430 type: 'Draft07',
431 openApiVersion: 3,
432 };
433 }
434 }
435 return { type: 'Draft04' };
436}
437exports.selectSchemaType = selectSchemaType;