-
-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathparser.ts
98 lines (90 loc) · 2.56 KB
/
parser.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import $RefParser from '@apidevtools/json-schema-ref-parser';
import { JSONPath } from 'jsonpath-plus';
import { merge } from 'lodash';
import type { $Refs } from '@apidevtools/json-schema-ref-parser';
import type { AsyncAPIObject, ComponentsObject, MessageObject } from './spec-types';
/**
* @class
* @private
*/
class ExternalComponents {
ref;
resolvedJSON;
constructor(ref: string, resolvedJSON: string) {
this.ref = ref;
this.resolvedJSON = resolvedJSON;
}
getKey() {
const keys = this.ref.split('/');
return keys[keys.length - 1];
}
getValue() {
return this.resolvedJSON;
}
}
/**
* @private
*/
function crawlChannelPropertiesForRefs(JSONSchema: AsyncAPIObject) {
// eslint-disable-next-line
return JSONPath({ json: JSONSchema, path: `$.channels.*.*.message['$ref']` });
}
/**
* Checks if `ref` is an external reference.
* @param {string} ref
* @returns {boolean}
* @private
*/
export function isExternalReference(ref: string): boolean {
return typeof ref === 'string' && !ref.startsWith('#');
}
/**
*
* @param {Object[]} parsedJSON
* @param {$RefParser} $refs
* @returns {ExternalComponents}
* @private
*/
async function resolveExternalRefs(parsedJSON: AsyncAPIObject, $refs: $Refs) {
const componentObj: ComponentsObject = { messages: {} };
JSONPath({
json: parsedJSON,
resultType: 'all',
path: '$.channels.*.*.message',
}).forEach(
({ parent, parentProperty }: { parent: any; parentProperty: string }) => {
const ref = parent[String(parentProperty)]['$ref'];
if (isExternalReference(ref)) {
const value: any = $refs.get(ref);
const component = new ExternalComponents(ref, value);
if (componentObj.messages) {
componentObj.messages[String(component.getKey())] =
component.getValue() as unknown as MessageObject;
}
parent[String(parentProperty)][
'$ref'
] = `#/components/messages/${component.getKey()}`;
}
}
);
return componentObj;
}
/**
* Resolves external references and updates $refs.
* @param {Object[]} JSONSchema
* @private
*/
export async function parse(JSONSchema: AsyncAPIObject) {
const $ref: any = await $RefParser.resolve(JSONSchema);
const refs = crawlChannelPropertiesForRefs(JSONSchema);
for (const ref of refs) {
if (isExternalReference(ref)) {
const componentObject = await resolveExternalRefs(JSONSchema, $ref);
if (JSONSchema.components) {
merge(JSONSchema.components, componentObject);
} else {
JSONSchema.components = componentObject;
}
}
}
}