1 | import traverse from 'traverse';
|
---|
2 | import { url } from '@swagger-api/apidom-reference/configuration/empty';
|
---|
3 | import { DEFAULT_BASE_URL } from '../constants.js';
|
---|
4 |
|
---|
5 | // This will match if the direct parent's key exactly matches an item.
|
---|
6 | const freelyNamedKeyParents = ['properties'];
|
---|
7 |
|
---|
8 | // This will match if the grandparent's key exactly matches an item.
|
---|
9 | // NOTE that this is for finding non-free paths!
|
---|
10 | const nonFreelyNamedKeyGrandparents = ['properties'];
|
---|
11 |
|
---|
12 | // This will match if the joined parent path exactly matches an item.
|
---|
13 | //
|
---|
14 | // This is mostly useful for filtering out root-level reusable item names,
|
---|
15 | // for example `["definitions", "$ref"]`
|
---|
16 | const freelyNamedPaths = [
|
---|
17 | // Swagger 2.0
|
---|
18 | 'definitions', 'parameters', 'responses', 'securityDefinitions',
|
---|
19 | // OpenAPI 3.0
|
---|
20 | 'components/schemas', 'components/responses', 'components/parameters', 'components/securitySchemes'];
|
---|
21 |
|
---|
22 | // This will match if any of these items are substrings of the joined
|
---|
23 | // parent path.
|
---|
24 | //
|
---|
25 | // Warning! These are powerful. Beware of edge cases.
|
---|
26 | const freelyNamedAncestors = ['schema/example', 'items/example'];
|
---|
27 | export function isFreelyNamed(parentPath) {
|
---|
28 | const parentKey = parentPath[parentPath.length - 1];
|
---|
29 | const grandparentKey = parentPath[parentPath.length - 2];
|
---|
30 | const parentStr = parentPath.join('/');
|
---|
31 | return (
|
---|
32 | // eslint-disable-next-line max-len
|
---|
33 | freelyNamedKeyParents.indexOf(parentKey) > -1 && nonFreelyNamedKeyGrandparents.indexOf(grandparentKey) === -1 || freelyNamedPaths.indexOf(parentStr) > -1 || freelyNamedAncestors.some(el => parentStr.indexOf(el) > -1)
|
---|
34 | );
|
---|
35 | }
|
---|
36 | export function generateAbsoluteRefPatches(obj, basePath, {
|
---|
37 | specmap,
|
---|
38 | getBaseUrlForNodePath = path => specmap.getContext([...basePath, ...path]).baseDoc,
|
---|
39 | targetKeys = ['$ref', '$$ref']
|
---|
40 | } = {}) {
|
---|
41 | const patches = [];
|
---|
42 | traverse(obj).forEach(function callback() {
|
---|
43 | if (targetKeys.includes(this.key) && typeof this.node === 'string') {
|
---|
44 | const nodePath = this.path; // this node's path, relative to `obj`
|
---|
45 | const fullPath = basePath.concat(this.path);
|
---|
46 | const absolutifiedRefValue = absolutifyPointer(this.node, getBaseUrlForNodePath(nodePath));
|
---|
47 | patches.push(specmap.replace(fullPath, absolutifiedRefValue));
|
---|
48 | }
|
---|
49 | });
|
---|
50 | return patches;
|
---|
51 | }
|
---|
52 | export function absolutifyPointer(pointer, baseUrl) {
|
---|
53 | const [urlPart, fragmentPart] = pointer.split('#');
|
---|
54 | const safeBaseUrl = baseUrl !== null && baseUrl !== void 0 ? baseUrl : '';
|
---|
55 | const safeUrlPart = urlPart !== null && urlPart !== void 0 ? urlPart : '';
|
---|
56 | let newRefUrlPart;
|
---|
57 | if (!url.isHttpUrl(safeBaseUrl)) {
|
---|
58 | const absoluteBaseUrl = url.resolve(DEFAULT_BASE_URL, safeBaseUrl);
|
---|
59 | const absoluteRefUrlPart = url.resolve(absoluteBaseUrl, safeUrlPart);
|
---|
60 | const rawRefUrlPart = absoluteRefUrlPart.replace(DEFAULT_BASE_URL, '');
|
---|
61 | newRefUrlPart = safeUrlPart.startsWith('/') ? rawRefUrlPart : rawRefUrlPart.substring(1);
|
---|
62 | } else {
|
---|
63 | newRefUrlPart = url.resolve(safeBaseUrl, safeUrlPart);
|
---|
64 | }
|
---|
65 | return fragmentPart ? `${newRefUrlPart}#${fragmentPart}` : newRefUrlPart;
|
---|
66 | } |
---|