swagger-client 3.10.8 → 3.10.12
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/README.md +10 -2
- package/dist/swagger-client.browser.js +24191 -0
- package/dist/swagger-client.browser.min.js +3 -0
- package/dist/swagger-client.browser.min.js.map +1 -0
- package/es/commonjs.js +9 -0
- package/es/constants.js +2 -0
- package/es/execute/index.js +391 -0
- package/es/execute/oas3/build-request.js +149 -0
- package/es/execute/oas3/content-serializer.js +18 -0
- package/es/execute/oas3/parameter-builders.js +119 -0
- package/es/execute/oas3/style-serializer.js +232 -0
- package/es/execute/swagger2/build-request.js +119 -0
- package/es/execute/swagger2/parameter-builders.js +78 -0
- package/es/helpers.js +272 -0
- package/es/http.js +621 -0
- package/es/index.js +116 -0
- package/es/interfaces.js +145 -0
- package/es/internal/form-data-monkey-patch.js +94 -0
- package/es/resolver.js +123 -0
- package/es/specmap/helpers.js +62 -0
- package/es/specmap/index.js +613 -0
- package/es/specmap/lib/all-of.js +81 -0
- package/es/specmap/lib/context-tree.js +111 -0
- package/es/specmap/lib/create-error.js +24 -0
- package/es/specmap/lib/index.js +391 -0
- package/es/specmap/lib/parameters.js +31 -0
- package/es/specmap/lib/properties.js +23 -0
- package/es/specmap/lib/refs.js +516 -0
- package/es/subtree-resolver/index.js +92 -0
- package/lib/commonjs.js +10 -0
- package/lib/constants.js +7 -0
- package/lib/execute/index.js +421 -0
- package/lib/execute/oas3/build-request.js +161 -0
- package/lib/execute/oas3/content-serializer.js +21 -0
- package/lib/execute/oas3/parameter-builders.js +138 -0
- package/lib/execute/oas3/style-serializer.js +208 -0
- package/lib/execute/swagger2/build-request.js +120 -0
- package/lib/execute/swagger2/parameter-builders.js +88 -0
- package/lib/helpers.js +261 -0
- package/lib/http.js +470 -0
- package/lib/index.js +142 -0
- package/lib/interfaces.js +159 -0
- package/lib/internal/form-data-monkey-patch.js +83 -0
- package/lib/resolver.js +125 -0
- package/lib/specmap/helpers.js +65 -0
- package/lib/specmap/index.js +446 -0
- package/lib/specmap/lib/all-of.js +89 -0
- package/lib/specmap/lib/context-tree.js +111 -0
- package/lib/specmap/lib/create-error.js +25 -0
- package/lib/specmap/lib/index.js +402 -0
- package/lib/specmap/lib/parameters.js +42 -0
- package/lib/specmap/lib/properties.js +38 -0
- package/lib/specmap/lib/refs.js +509 -0
- package/lib/subtree-resolver/index.js +55 -0
- package/package.json +80 -106
- package/browser/index.js +0 -54
- package/dist/index.js +0 -4372
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.default = void 0;
|
|
5
|
+
|
|
6
|
+
var _crossFetch = require("cross-fetch");
|
|
7
|
+
|
|
8
|
+
var _jsYaml = _interopRequireDefault(require("js-yaml"));
|
|
9
|
+
|
|
10
|
+
var _querystringBrowser = _interopRequireDefault(require("querystring-browser"));
|
|
11
|
+
|
|
12
|
+
var _url = _interopRequireDefault(require("url"));
|
|
13
|
+
|
|
14
|
+
var _ = _interopRequireDefault(require("."));
|
|
15
|
+
|
|
16
|
+
var _createError = _interopRequireDefault(require("./create-error"));
|
|
17
|
+
|
|
18
|
+
var _helpers = require("../helpers");
|
|
19
|
+
|
|
20
|
+
var _constants = require("../../constants");
|
|
21
|
+
|
|
22
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
23
|
+
|
|
24
|
+
const ABSOLUTE_URL_REGEXP = new RegExp('^([a-z]+://|//)', 'i');
|
|
25
|
+
const JSONRefError = (0, _createError.default)('JSONRefError', function cb(message, extra, oriError) {
|
|
26
|
+
this.originalError = oriError;
|
|
27
|
+
Object.assign(this, extra || {});
|
|
28
|
+
});
|
|
29
|
+
const docCache = {};
|
|
30
|
+
const specmapRefs = new WeakMap();
|
|
31
|
+
const skipResolutionTestFns = [path => // OpenAPI 3.0 Response Media Type Example
|
|
32
|
+
// ["paths", *, *, "responses", *, "content", *, "example"]
|
|
33
|
+
path[0] === 'paths' && path[3] === 'responses' && path[5] === 'content' && path[7] === 'example', path => // OpenAPI 3.0 Request Body Media Type Example
|
|
34
|
+
// ["paths", *, *, "responses", *, "content", *, "example"]
|
|
35
|
+
path[0] === 'paths' && path[3] === 'requestBody' && path[4] === 'content' && path[6] === 'example'];
|
|
36
|
+
|
|
37
|
+
const shouldSkipResolution = path => skipResolutionTestFns.some(fn => fn(path)); // =========================
|
|
38
|
+
// Core
|
|
39
|
+
// =========================
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* This plugin resolves the JSON pointers.
|
|
43
|
+
* A major part of this plugin deals with cyclic references via 2 mechanisms.
|
|
44
|
+
* 1. If a pointer was already resolved before in this path, halt.
|
|
45
|
+
* 2. If the patch value points to one of the ancestors in this path, halt.
|
|
46
|
+
*
|
|
47
|
+
* Note that either one of these mechanism is sufficient, both must be in place.
|
|
48
|
+
* For examples:
|
|
49
|
+
*
|
|
50
|
+
* Given the following spec, #1 alone is insufficient because after the 2nd
|
|
51
|
+
* application, there will be a cyclic object reference.
|
|
52
|
+
* a.b.c: $ref-d
|
|
53
|
+
* d.e.f: $ref-a (per #1, safe to return patch as no immediate cycle)
|
|
54
|
+
*
|
|
55
|
+
* Given the following spec, #2 alone is insufficient because although there will
|
|
56
|
+
* never be any cyclic object reference, the plugin will keep producing patches.
|
|
57
|
+
* a: $ref-b
|
|
58
|
+
* b: $ref-a
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
const plugin = {
|
|
63
|
+
key: '$ref',
|
|
64
|
+
plugin: (ref, key, fullPath, specmap) => {
|
|
65
|
+
const specmapInstance = specmap.getInstance();
|
|
66
|
+
const parent = fullPath.slice(0, -1);
|
|
67
|
+
|
|
68
|
+
if ((0, _helpers.isFreelyNamed)(parent) || shouldSkipResolution(parent)) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const {
|
|
73
|
+
baseDoc
|
|
74
|
+
} = specmap.getContext(fullPath);
|
|
75
|
+
|
|
76
|
+
if (typeof ref !== 'string') {
|
|
77
|
+
return new JSONRefError('$ref: must be a string (JSON-Ref)', {
|
|
78
|
+
$ref: ref,
|
|
79
|
+
baseDoc,
|
|
80
|
+
fullPath
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const splitString = split(ref);
|
|
85
|
+
const refPath = splitString[0];
|
|
86
|
+
const pointer = splitString[1] || '';
|
|
87
|
+
let basePath;
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
basePath = baseDoc || refPath ? absoluteify(refPath, baseDoc) : null;
|
|
91
|
+
} catch (e) {
|
|
92
|
+
return wrapError(e, {
|
|
93
|
+
pointer,
|
|
94
|
+
$ref: ref,
|
|
95
|
+
basePath,
|
|
96
|
+
fullPath
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let promOrVal;
|
|
101
|
+
let tokens;
|
|
102
|
+
|
|
103
|
+
if (pointerAlreadyInPath(pointer, basePath, parent, specmap)) {
|
|
104
|
+
// Cyclic reference!
|
|
105
|
+
// if `useCircularStructures` is not set, just leave the reference
|
|
106
|
+
// unresolved, but absolutify it so that we don't leave an invalid $ref
|
|
107
|
+
// path in the content
|
|
108
|
+
if (!specmapInstance.useCircularStructures) {
|
|
109
|
+
const absolutifiedRef = (0, _helpers.absolutifyPointer)(ref, basePath);
|
|
110
|
+
|
|
111
|
+
if (ref === absolutifiedRef) {
|
|
112
|
+
// avoids endless looping
|
|
113
|
+
// without this, the ref plugin never stops seeing this $ref
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return _.default.replace(fullPath, absolutifiedRef);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (basePath == null) {
|
|
122
|
+
tokens = jsonPointerToArray(pointer);
|
|
123
|
+
promOrVal = specmap.get(tokens);
|
|
124
|
+
|
|
125
|
+
if (typeof promOrVal === 'undefined') {
|
|
126
|
+
promOrVal = new JSONRefError(`Could not resolve reference: ${ref}`, {
|
|
127
|
+
pointer,
|
|
128
|
+
$ref: ref,
|
|
129
|
+
baseDoc,
|
|
130
|
+
fullPath
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
promOrVal = extractFromDoc(basePath, pointer); // eslint-disable-next-line no-underscore-dangle
|
|
135
|
+
|
|
136
|
+
if (promOrVal.__value != null) {
|
|
137
|
+
promOrVal = promOrVal.__value; // eslint-disable-line no-underscore-dangle
|
|
138
|
+
} else {
|
|
139
|
+
promOrVal = promOrVal.catch(e => {
|
|
140
|
+
throw wrapError(e, {
|
|
141
|
+
pointer,
|
|
142
|
+
$ref: ref,
|
|
143
|
+
baseDoc,
|
|
144
|
+
fullPath
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (promOrVal instanceof Error) {
|
|
151
|
+
return [_.default.remove(fullPath), promOrVal];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const absolutifiedRef = (0, _helpers.absolutifyPointer)(ref, basePath);
|
|
155
|
+
|
|
156
|
+
const patch = _.default.replace(parent, promOrVal, {
|
|
157
|
+
$$ref: absolutifiedRef
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
if (basePath && basePath !== baseDoc) {
|
|
161
|
+
return [patch, _.default.context(parent, {
|
|
162
|
+
baseDoc: basePath
|
|
163
|
+
})];
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
// prevents circular values from being constructed, unless we specifically
|
|
168
|
+
// want that to happen
|
|
169
|
+
if (!patchValueAlreadyInPath(specmap.state, patch) || specmapInstance.useCircularStructures) {
|
|
170
|
+
return patch;
|
|
171
|
+
}
|
|
172
|
+
} catch (e) {
|
|
173
|
+
// if we're catching here, path traversal failed, so we should
|
|
174
|
+
// ditch without sending any patches back up.
|
|
175
|
+
//
|
|
176
|
+
// this is a narrow fix for the larger problem of patches being queued
|
|
177
|
+
// and then having the state they were generated against be modified
|
|
178
|
+
// before they are applied.
|
|
179
|
+
//
|
|
180
|
+
// TODO: re-engineer specmap patch/state management to avoid this
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
const mod = Object.assign(plugin, {
|
|
188
|
+
docCache,
|
|
189
|
+
absoluteify,
|
|
190
|
+
clearCache,
|
|
191
|
+
JSONRefError,
|
|
192
|
+
wrapError,
|
|
193
|
+
getDoc,
|
|
194
|
+
split,
|
|
195
|
+
extractFromDoc,
|
|
196
|
+
fetchJSON,
|
|
197
|
+
extract,
|
|
198
|
+
jsonPointerToArray,
|
|
199
|
+
unescapeJsonPointerToken
|
|
200
|
+
});
|
|
201
|
+
var _default = mod; // =========================
|
|
202
|
+
// Utilities
|
|
203
|
+
// =========================
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Resolves a path and its base to an abolute URL.
|
|
207
|
+
* @api public
|
|
208
|
+
*/
|
|
209
|
+
|
|
210
|
+
exports.default = _default;
|
|
211
|
+
|
|
212
|
+
function absoluteify(path, basePath) {
|
|
213
|
+
if (!ABSOLUTE_URL_REGEXP.test(path)) {
|
|
214
|
+
if (!basePath) {
|
|
215
|
+
throw new JSONRefError(`Tried to resolve a relative URL, without having a basePath. path: '${path}' basePath: '${basePath}'`);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return _url.default.resolve(basePath, path);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return path;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Wraps an error as JSONRefError.
|
|
225
|
+
* @param {Error} e the error.
|
|
226
|
+
* @param {Object} extra (optional) optional data.
|
|
227
|
+
* @return {Error} an instance of JSONRefError.
|
|
228
|
+
* @api public
|
|
229
|
+
*/
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
function wrapError(e, extra) {
|
|
233
|
+
let message;
|
|
234
|
+
|
|
235
|
+
if (e && e.response && e.response.body) {
|
|
236
|
+
message = `${e.response.body.code} ${e.response.body.message}`;
|
|
237
|
+
} else {
|
|
238
|
+
message = e.message;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return new JSONRefError(`Could not resolve reference: ${message}`, extra, e);
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Splits a pointer by the hash delimiter.
|
|
245
|
+
* @api public
|
|
246
|
+
*/
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
function split(ref) {
|
|
250
|
+
return (ref + '').split('#'); // eslint-disable-line prefer-template
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Extracts a pointer from its document.
|
|
254
|
+
* @param {String} docPath the absolute document URL.
|
|
255
|
+
* @param {String} pointer the pointer whose value is to be extracted.
|
|
256
|
+
* @return {Promise} a promise of the pointer value.
|
|
257
|
+
* @api public
|
|
258
|
+
*/
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
function extractFromDoc(docPath, pointer) {
|
|
262
|
+
const doc = docCache[docPath];
|
|
263
|
+
|
|
264
|
+
if (doc && !_.default.isPromise(doc)) {
|
|
265
|
+
// If doc is already available, return __value together with the promise.
|
|
266
|
+
// __value is for special handling in cycle check:
|
|
267
|
+
// pointerAlreadyInPath() won't work if patch.value is a promise,
|
|
268
|
+
// thus when that promise is finally resolved, cycle might happen (because
|
|
269
|
+
// `spec` and `docCache[basePath]` refer to the exact same object).
|
|
270
|
+
// See test "should resolve a cyclic spec when baseDoc is specified".
|
|
271
|
+
try {
|
|
272
|
+
const v = extract(pointer, doc);
|
|
273
|
+
return Object.assign(Promise.resolve(v), {
|
|
274
|
+
__value: v
|
|
275
|
+
});
|
|
276
|
+
} catch (e) {
|
|
277
|
+
return Promise.reject(e);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return getDoc(docPath).then(_doc => extract(pointer, _doc));
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Clears all document caches.
|
|
285
|
+
* @param {String} item (optional) the name of the cache item to be cleared.
|
|
286
|
+
* @api public
|
|
287
|
+
*/
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
function clearCache(item) {
|
|
291
|
+
if (typeof item !== 'undefined') {
|
|
292
|
+
delete docCache[item];
|
|
293
|
+
} else {
|
|
294
|
+
Object.keys(docCache).forEach(key => {
|
|
295
|
+
delete docCache[key];
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Fetches and caches a document.
|
|
301
|
+
* @param {String} docPath the absolute URL of the document.
|
|
302
|
+
* @return {Promise} a promise of the document content.
|
|
303
|
+
* @api public
|
|
304
|
+
*/
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
function getDoc(docPath) {
|
|
308
|
+
const val = docCache[docPath];
|
|
309
|
+
|
|
310
|
+
if (val) {
|
|
311
|
+
return _.default.isPromise(val) ? val : Promise.resolve(val);
|
|
312
|
+
} // NOTE: we need to use `mod.fetchJSON` in order to be able to overwrite it.
|
|
313
|
+
// Any tips on how to make this cleaner, please ping!
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
docCache[docPath] = mod.fetchJSON(docPath).then(doc => {
|
|
317
|
+
docCache[docPath] = doc;
|
|
318
|
+
return doc;
|
|
319
|
+
});
|
|
320
|
+
return docCache[docPath];
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Fetches a document.
|
|
324
|
+
* @param {String} docPath the absolute URL of the document.
|
|
325
|
+
* @return {Promise} a promise of the document content.
|
|
326
|
+
* @api public
|
|
327
|
+
*/
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
function fetchJSON(docPath) {
|
|
331
|
+
return (0, _crossFetch.fetch)(docPath, {
|
|
332
|
+
headers: {
|
|
333
|
+
Accept: _constants.ACCEPT_HEADER_VALUE_FOR_DOCUMENTS
|
|
334
|
+
},
|
|
335
|
+
loadSpec: true
|
|
336
|
+
}).then(res => res.text()).then(text => _jsYaml.default.safeLoad(text));
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Extracts a pointer from an object.
|
|
340
|
+
* @param {String[]} pointer the JSON pointer.
|
|
341
|
+
* @param {Object} obj an object whose value is to be extracted.
|
|
342
|
+
* @return {Object} the value to be extracted.
|
|
343
|
+
* @api public
|
|
344
|
+
*/
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
function extract(pointer, obj) {
|
|
348
|
+
const tokens = jsonPointerToArray(pointer);
|
|
349
|
+
|
|
350
|
+
if (tokens.length < 1) {
|
|
351
|
+
return obj;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const val = _.default.getIn(obj, tokens);
|
|
355
|
+
|
|
356
|
+
if (typeof val === 'undefined') {
|
|
357
|
+
throw new JSONRefError(`Could not resolve pointer: ${pointer} does not exist in document`, {
|
|
358
|
+
pointer
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return val;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Converts a JSON pointer to array.
|
|
366
|
+
* @api public
|
|
367
|
+
*/
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
function jsonPointerToArray(pointer) {
|
|
371
|
+
if (typeof pointer !== 'string') {
|
|
372
|
+
throw new TypeError(`Expected a string, got a ${typeof pointer}`);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (pointer[0] === '/') {
|
|
376
|
+
pointer = pointer.substr(1);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (pointer === '') {
|
|
380
|
+
return [];
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return pointer.split('/').map(unescapeJsonPointerToken);
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Unescapes a JSON pointer.
|
|
387
|
+
* @api public
|
|
388
|
+
*/
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
function unescapeJsonPointerToken(token) {
|
|
392
|
+
if (typeof token !== 'string') {
|
|
393
|
+
return token;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return _querystringBrowser.default.unescape(token.replace(/~1/g, '/').replace(/~0/g, '~'));
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Escapes a JSON pointer.
|
|
400
|
+
* @api public
|
|
401
|
+
*/
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
function escapeJsonPointerToken(token) {
|
|
405
|
+
return _querystringBrowser.default.escape(token.replace(/~/g, '~0').replace(/\//g, '~1'));
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function arrayToJsonPointer(arr) {
|
|
409
|
+
if (arr.length === 0) {
|
|
410
|
+
return '';
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return `/${arr.map(escapeJsonPointerToken).join('/')}`;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const pointerBoundaryChar = c => !c || c === '/' || c === '#';
|
|
417
|
+
|
|
418
|
+
function pointerIsAParent(pointer, parentPointer) {
|
|
419
|
+
if (pointerBoundaryChar(parentPointer)) {
|
|
420
|
+
// This is the root of the document, so its naturally a parent
|
|
421
|
+
return true;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const nextChar = pointer.charAt(parentPointer.length);
|
|
425
|
+
const lastParentChar = parentPointer.slice(-1);
|
|
426
|
+
return pointer.indexOf(parentPointer) === 0 && (!nextChar || nextChar === '/' || nextChar === '#') && lastParentChar !== '#';
|
|
427
|
+
} // =========================
|
|
428
|
+
// Private
|
|
429
|
+
// =========================
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Checks if this pointer points back to one or more pointers along the path.
|
|
433
|
+
*/
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
function pointerAlreadyInPath(pointer, basePath, parent, specmap) {
|
|
437
|
+
let refs = specmapRefs.get(specmap);
|
|
438
|
+
|
|
439
|
+
if (!refs) {
|
|
440
|
+
// Stores all resolved references of a specmap instance.
|
|
441
|
+
// Schema: path -> pointer (path's $ref value).
|
|
442
|
+
refs = {};
|
|
443
|
+
specmapRefs.set(specmap, refs);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const parentPointer = arrayToJsonPointer(parent);
|
|
447
|
+
const fullyQualifiedPointer = `${basePath || '<specmap-base>'}#${pointer}`; // dirty hack to strip `allof/[index]` from the path, in order to avoid cases
|
|
448
|
+
// where we get false negatives because:
|
|
449
|
+
// - we resolve a path, then
|
|
450
|
+
// - allOf plugin collapsed `allOf/[index]` out of the path, then
|
|
451
|
+
// - we try to work on a child $ref within that collapsed path.
|
|
452
|
+
//
|
|
453
|
+
// because of the path collapse, we lose track of it in our specmapRefs hash
|
|
454
|
+
// solution: always throw the allOf constructs out of paths we store
|
|
455
|
+
// TODO: solve this with a global register, or by writing more metadata in
|
|
456
|
+
// either allOf or refs plugin
|
|
457
|
+
|
|
458
|
+
const safeParentPointer = parentPointer.replace(/allOf\/\d+\/?/g, ''); // Case 1: direct cycle, e.g. a.b.c.$ref: '/a.b'
|
|
459
|
+
// Detect by checking that the parent path doesn't start with pointer.
|
|
460
|
+
// This only applies if the pointer is internal, i.e. basePath === rootPath (could be null)
|
|
461
|
+
|
|
462
|
+
const rootDoc = specmap.contextTree.get([]).baseDoc;
|
|
463
|
+
|
|
464
|
+
if (basePath == rootDoc && pointerIsAParent(safeParentPointer, pointer)) {
|
|
465
|
+
// eslint-disable-line
|
|
466
|
+
return true;
|
|
467
|
+
} // Case 2: indirect cycle
|
|
468
|
+
// ex1: a.$ref: '/b' & b.c.$ref: '/b/c'
|
|
469
|
+
// ex2: a.$ref: '/b/c' & b.c.$ref: '/b'
|
|
470
|
+
// Detect by retrieving all the $refs along the path of parent
|
|
471
|
+
// and checking if any starts with pointer or vice versa.
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
let currPath = '';
|
|
475
|
+
const hasIndirectCycle = parent.some(token => {
|
|
476
|
+
currPath = `${currPath}/${escapeJsonPointerToken(token)}`;
|
|
477
|
+
return refs[currPath] && refs[currPath].some(ref => {
|
|
478
|
+
return pointerIsAParent(ref, fullyQualifiedPointer) || pointerIsAParent(fullyQualifiedPointer, ref);
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
if (hasIndirectCycle) {
|
|
483
|
+
return true;
|
|
484
|
+
} // No cycle, this ref will be resolved, so stores it now for future detection.
|
|
485
|
+
// No need to store if has cycle, as parent path is a dead-end and won't be checked again.
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
refs[safeParentPointer] = (refs[safeParentPointer] || []).concat(fullyQualifiedPointer);
|
|
489
|
+
return undefined;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Checks if the value of this patch ends up pointing to an ancestor along the path.
|
|
493
|
+
*/
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
function patchValueAlreadyInPath(root, patch) {
|
|
497
|
+
const ancestors = [root];
|
|
498
|
+
patch.path.reduce((parent, p) => {
|
|
499
|
+
ancestors.push(parent[p]);
|
|
500
|
+
return parent[p];
|
|
501
|
+
}, root);
|
|
502
|
+
return pointToAncestor(patch.value);
|
|
503
|
+
|
|
504
|
+
function pointToAncestor(obj) {
|
|
505
|
+
return _.default.isObject(obj) && (ancestors.indexOf(obj) >= 0 || Object.keys(obj).some(k => {
|
|
506
|
+
return pointToAncestor(obj[k]);
|
|
507
|
+
}));
|
|
508
|
+
}
|
|
509
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.default = resolveSubtree;
|
|
5
|
+
|
|
6
|
+
var _get = _interopRequireDefault(require("lodash/get"));
|
|
7
|
+
|
|
8
|
+
var _resolver = _interopRequireDefault(require("../resolver"));
|
|
9
|
+
|
|
10
|
+
var _helpers = require("../helpers");
|
|
11
|
+
|
|
12
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
|
+
|
|
14
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
|
|
15
|
+
|
|
16
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
17
|
+
|
|
18
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
19
|
+
|
|
20
|
+
async function resolveSubtree(obj, path, opts = {}) {
|
|
21
|
+
const {
|
|
22
|
+
returnEntireTree,
|
|
23
|
+
baseDoc,
|
|
24
|
+
requestInterceptor,
|
|
25
|
+
responseInterceptor,
|
|
26
|
+
parameterMacro,
|
|
27
|
+
modelPropertyMacro,
|
|
28
|
+
useCircularStructures
|
|
29
|
+
} = opts;
|
|
30
|
+
const resolveOptions = {
|
|
31
|
+
pathDiscriminator: path,
|
|
32
|
+
baseDoc,
|
|
33
|
+
requestInterceptor,
|
|
34
|
+
responseInterceptor,
|
|
35
|
+
parameterMacro,
|
|
36
|
+
modelPropertyMacro,
|
|
37
|
+
useCircularStructures
|
|
38
|
+
};
|
|
39
|
+
const {
|
|
40
|
+
spec: normalized
|
|
41
|
+
} = (0, _helpers.normalizeSwagger)({
|
|
42
|
+
spec: obj
|
|
43
|
+
});
|
|
44
|
+
const result = await (0, _resolver.default)(_objectSpread(_objectSpread({}, resolveOptions), {}, {
|
|
45
|
+
spec: normalized,
|
|
46
|
+
allowMetaPatches: true,
|
|
47
|
+
skipNormalization: true
|
|
48
|
+
}));
|
|
49
|
+
|
|
50
|
+
if (!returnEntireTree && Array.isArray(path) && path.length) {
|
|
51
|
+
result.spec = (0, _get.default)(result.spec, path) || null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return result;
|
|
55
|
+
}
|