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 = (0, tslib_1.__importStar)(require("../jsonPointer"));
|
6 | const schemaId_1 = (0, tslib_1.__importDefault)(require("./schemaId"));
|
7 | const type_1 = require("./type");
|
8 | function 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 | }
|
34 | exports.getSubSchema = getSubSchema;
|
35 | const Draft04Id = 'id';
|
36 | const Draft07Id = '$id';
|
37 | function 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 | }
|
46 | exports.getId = getId;
|
47 | function 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 | }
|
56 | exports.setId = setId;
|
57 | function 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 | f(item, keys.concat(convertKeyToTypeName(key)));
|
148 | });
|
149 | }
|
150 | function setSubIdToParameterObject(obj, keys) {
|
151 | if (obj == null) {
|
152 | return;
|
153 | }
|
154 | addParameterSchema(Object.entries(obj), keys);
|
155 | }
|
156 | function setSubIdToParameters(array, keys) {
|
157 | if (array == null) {
|
158 | return;
|
159 | }
|
160 | addParameterSchema(array.map((item, index) => {
|
161 | const key = 'name' in item ? item.name : `${index}`;
|
162 | return [key, item];
|
163 | }), keys);
|
164 | }
|
165 | function addParameterSchema(input, keys) {
|
166 | const map = new Map();
|
167 | const pushItem = (key, po) => {
|
168 | let work = map.get(key);
|
169 | if (work == null) {
|
170 | work = [];
|
171 | map.set(key, work);
|
172 | }
|
173 | work.push(po);
|
174 | };
|
175 | for (const [key, item] of input) {
|
176 | if ('schema' in item) {
|
177 | setSubId(item.schema, keys.concat(key));
|
178 | pushItem(item.in, [key, item]);
|
179 | }
|
180 | if ('content' in item) {
|
181 | setSubIdToMediaTypes(item.content, keys.concat(key));
|
182 | pushItem(item.in, [key, item]);
|
183 | }
|
184 | if ('$ref' in item) {
|
185 | setSubId(item, keys.concat(key));
|
186 | }
|
187 | if ('type' in item && item.in !== undefined) {
|
188 | setSubId(item, keys.concat(key));
|
189 | pushItem(item.in, [key, item]);
|
190 | }
|
191 | }
|
192 | for (const [key, params] of map) {
|
193 | const [paths, obj] = buildParameterSchema(key, params, keys);
|
194 | setSubId(obj, paths);
|
195 | }
|
196 | }
|
197 | function buildParameterSchema(inType, params, keys) {
|
198 | const paths = keys
|
199 | .slice(0, keys.length - 1)
|
200 | .concat(inType + 'Parameters');
|
201 | const properties = {};
|
202 | params.forEach(([key, _]) => {
|
203 | properties[key] = {
|
204 | $ref: createId(keys.concat(key)),
|
205 | };
|
206 | });
|
207 | return [
|
208 | paths,
|
209 | {
|
210 | id: createId(paths),
|
211 | type: 'object',
|
212 | properties,
|
213 | required: params
|
214 | .filter(([_, item]) => item.required === true)
|
215 | .map(([_, item]) => item.name),
|
216 | },
|
217 | ];
|
218 | }
|
219 | const setSubIdToResponsesV2 = (responses, keys) => setSubIdToAnyObject(setSubIdToResponseV2, responses, keys);
|
220 | function setSubIdToResponseV2(response, keys) {
|
221 | if (response == null) {
|
222 | return;
|
223 | }
|
224 | if ('schema' in response) {
|
225 | const s = response.schema;
|
226 | if (s != null && s.type === 'file') {
|
227 | return;
|
228 | }
|
229 | setSubId(s, keys);
|
230 | }
|
231 | }
|
232 | function setSubIdToOperationV2(ops, keys) {
|
233 | if (ops == null) {
|
234 | return;
|
235 | }
|
236 | const operationId = ops.operationId;
|
237 | if (operationId) {
|
238 | keys = [keys[0], convertKeyToTypeName(operationId)];
|
239 | }
|
240 | setSubIdToParameters(ops.parameters, keys.concat('parameters'));
|
241 | setSubIdToResponsesV2(ops.responses, keys.concat('responses'));
|
242 | }
|
243 | const setSubIdToPathsV2 = (paths, keys) => setSubIdToAnyObject(setSubIdToPathItemV2, paths, keys);
|
244 | function setSubIdToPathItemV2(pathItem, keys) {
|
245 | setSubIdToParameters(pathItem.parameters, keys.concat('parameters'));
|
246 | setSubIdToOperationV2(pathItem.get, keys.concat('get'));
|
247 | setSubIdToOperationV2(pathItem.put, keys.concat('put'));
|
248 | setSubIdToOperationV2(pathItem.post, keys.concat('post'));
|
249 | setSubIdToOperationV2(pathItem.delete, keys.concat('delete'));
|
250 | setSubIdToOperationV2(pathItem.options, keys.concat('options'));
|
251 | setSubIdToOperationV2(pathItem.head, keys.concat('head'));
|
252 | setSubIdToOperationV2(pathItem.patch, keys.concat('patch'));
|
253 | }
|
254 | function setSubIdToMediaTypes(types, keys) {
|
255 | if (types == null) {
|
256 | return;
|
257 | }
|
258 | for (const mime of Object.keys(types)) {
|
259 | if (/^text\/|^(?:application\/x-www-form-urlencoded$|^application\/([a-z0-9-_.]+\+)?json)$|^application\/octet-stream$|^multipart\/form-data$/.test(mime)) {
|
260 | const mt = types[mime];
|
261 | setSubId(mt.schema, keys);
|
262 | }
|
263 | }
|
264 | }
|
265 | const setSubIdToRequestBodies = (bodies, keys) => setSubIdToAnyObject(setSubIdToRequestBody, bodies, keys);
|
266 | function setSubIdToRequestBody(body, keys) {
|
267 | if (body == null) {
|
268 | return;
|
269 | }
|
270 | if ('content' in body) {
|
271 | setSubIdToMediaTypes(body.content, keys);
|
272 | }
|
273 | else if ('$ref' in body) {
|
274 | setSubId(body, keys);
|
275 | }
|
276 | else {
|
277 | setSubId({ type: 'object' }, keys);
|
278 | }
|
279 | }
|
280 | const setSubIdToResponsesV3 = (responses, keys) => setSubIdToAnyObject(setSubIdToResponseV3, responses, keys);
|
281 | function setSubIdToResponseV3(response, keys) {
|
282 | if (response == null) {
|
283 | return;
|
284 | }
|
285 | if ('content' in response) {
|
286 | setSubIdToMediaTypes(response.content, keys);
|
287 | }
|
288 | else if ('$ref' in response) {
|
289 | setSubId(response, keys);
|
290 | }
|
291 | else {
|
292 | setSubId({ type: 'object' }, keys);
|
293 | }
|
294 | }
|
295 | function setSubIdToOperationV3(ops, keys) {
|
296 | if (ops == null) {
|
297 | return;
|
298 | }
|
299 | const operationId = ops.operationId;
|
300 | if (operationId) {
|
301 | keys = [keys[0], convertKeyToTypeName(operationId)];
|
302 | }
|
303 | setSubIdToParameters(ops.parameters, keys.concat('parameters'));
|
304 | setSubIdToRequestBody(ops.requestBody, keys.concat('requestBody'));
|
305 | setSubIdToResponsesV3(ops.responses, keys.concat('responses'));
|
306 | }
|
307 | const setSubIdToPathsV3 = (paths, keys) => setSubIdToAnyObject(setSubIdToPathItemV3, paths, keys);
|
308 | function setSubIdToPathItemV3(pathItem, keys) {
|
309 | setSubIdToParameters(pathItem.parameters, keys.concat('parameters'));
|
310 | setSubIdToOperationV3(pathItem.get, keys.concat('get'));
|
311 | setSubIdToOperationV3(pathItem.put, keys.concat('put'));
|
312 | setSubIdToOperationV3(pathItem.post, keys.concat('post'));
|
313 | setSubIdToOperationV3(pathItem.delete, keys.concat('delete'));
|
314 | setSubIdToOperationV3(pathItem.options, keys.concat('options'));
|
315 | setSubIdToOperationV3(pathItem.head, keys.concat('head'));
|
316 | setSubIdToOperationV3(pathItem.patch, keys.concat('patch'));
|
317 | setSubIdToOperationV3(pathItem.trace, keys.concat('trace'));
|
318 | }
|
319 | function setSubIdToObject(obj, paths) {
|
320 | if (obj == null) {
|
321 | return;
|
322 | }
|
323 | Object.keys(obj).forEach((key) => {
|
324 | const sub = obj[key];
|
325 | setSubId(sub, paths.concat(key));
|
326 | });
|
327 | }
|
328 | function setSubId(s, paths) {
|
329 | switch (typeof s) {
|
330 | case 'object': {
|
331 | const id = createId(paths);
|
332 | setId(schema.type, s, id);
|
333 | walk(s, paths, []);
|
334 | break;
|
335 | }
|
336 | case 'boolean': {
|
337 | const id = createId(paths);
|
338 | const schemaId = new schemaId_1.default(id, []);
|
339 | const subSchema = {
|
340 | type: schema.type,
|
341 | id: schemaId,
|
342 | content: s,
|
343 | rootSchema: schema,
|
344 | };
|
345 | onFoundSchema(subSchema);
|
346 | break;
|
347 | }
|
348 | }
|
349 | }
|
350 | if ('swagger' in openApi) {
|
351 | setSubIdToObject(openApi.definitions, ['definitions']);
|
352 | setSubIdToParameterObject(openApi.parameters, ['parameters']);
|
353 | setSubIdToResponsesV2(openApi.responses, ['responses']);
|
354 | setSubIdToPathsV2(openApi.paths, ['paths']);
|
355 | }
|
356 | else {
|
357 | if (openApi.components) {
|
358 | const components = openApi.components;
|
359 | setSubIdToObject(components.schemas, ['components', 'schemas']);
|
360 | setSubIdToResponsesV3(components.responses, [
|
361 | 'components',
|
362 | 'responses',
|
363 | ]);
|
364 | setSubIdToParameterObject(components.parameters, [
|
365 | 'components',
|
366 | 'parameters',
|
367 | ]);
|
368 | setSubIdToRequestBodies(components.requestBodies, [
|
369 | 'components',
|
370 | 'requestBodies',
|
371 | ]);
|
372 | }
|
373 | setSubIdToPathsV3(openApi.paths, ['paths']);
|
374 | }
|
375 | }
|
376 | if (schema.openApiVersion != null) {
|
377 | const obj = schema.content;
|
378 | searchOpenApiSubSchema(obj);
|
379 | return;
|
380 | }
|
381 | walk(schema.content, ['#'], []);
|
382 | }
|
383 | exports.searchAllSubSchema = searchAllSubSchema;
|
384 | function selectSchemaType(content) {
|
385 | var _a;
|
386 | if (typeof content === 'boolean') {
|
387 | return { type: 'Draft07' };
|
388 | }
|
389 | if (typeof content !== 'object') {
|
390 | throw new Error(`expect parameter of type object, received ${typeof content}`);
|
391 | }
|
392 | if ('$schema' in content) {
|
393 | const schema = (_a = content['$schema']) !== null && _a !== void 0 ? _a : '';
|
394 | if (/^https?:\/\/json-schema.org\/schema#?$/.test(schema)) {
|
395 | return { type: 'Latest' };
|
396 | }
|
397 | const match = /^https?:\/\/json-schema\.org\/(?:draft\/(\d{4}-\d{2})|draft-(\d+))\/schema#?$/.exec(schema);
|
398 | if (match) {
|
399 | if (match[1] != null) {
|
400 | switch (match[1]) {
|
401 | case '2019-09':
|
402 | return { type: '2019-09' };
|
403 | case '2020-12':
|
404 | return { type: '2020-12' };
|
405 | }
|
406 | }
|
407 | const version = Number(match[2]);
|
408 | if (version <= 4) {
|
409 | return { type: 'Draft04' };
|
410 | }
|
411 | else {
|
412 | return { type: 'Draft07' };
|
413 | }
|
414 | }
|
415 | }
|
416 | if ('swagger' in content && content.swagger === '2.0') {
|
417 | return {
|
418 | type: 'Draft04',
|
419 | openApiVersion: 2,
|
420 | };
|
421 | }
|
422 | if ('openapi' in content && content.openapi) {
|
423 | const { openapi } = content;
|
424 | if (/^3\.\d+\.\d+$/.test(openapi)) {
|
425 | return {
|
426 | type: 'Draft07',
|
427 | openApiVersion: 3,
|
428 | };
|
429 | }
|
430 | }
|
431 | return { type: 'Draft04' };
|
432 | }
|
433 | exports.selectSchemaType = selectSchemaType;
|