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