-
-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
54 additions
and
123 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,98 +1,58 @@ | ||
import $RefParser from '@apidevtools/json-schema-ref-parser'; | ||
import { JSONPath } from 'jsonpath-plus'; | ||
import { merge } from 'lodash'; | ||
import { Parser } from '@asyncapi/parser'; | ||
import { addXOrigins } from './util'; | ||
|
||
import type { $Refs } from '@apidevtools/json-schema-ref-parser'; | ||
import type { AsyncAPIObject, ComponentsObject, MessageObject } from './spec-types'; | ||
import { AsyncAPIObject } 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; | ||
} | ||
const parser = new Parser(); | ||
|
||
/** | ||
* 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; | ||
} | ||
} | ||
} | ||
addXOrigins(JSONSchema); | ||
|
||
const dereferencedJSONSchema = await $RefParser.dereference(JSONSchema, { | ||
dereference: { | ||
circular: false, | ||
// excludedPathMatcher: (path: string): boolean => { | ||
// return ( | ||
// // prettier-ignore | ||
// !!(/#\/channels\/[a-zA-Z0-9]*\/servers/).exec(path) || | ||
// !!(/#\/operations\/[a-zA-Z0-9]*\/channel/).exec(path) || | ||
// !!(/#\/operations\/[a-zA-Z0-9]*\/messages/).exec(path) || | ||
// !!(/#\/operations\/[a-zA-Z0-9]*\/reply\/channel/).exec(path) || | ||
// !!(/#\/operations\/[a-zA-Z0-9]*\/reply\/messages/).exec(path) || | ||
// !!(/#\/components\/channels\/[a-zA-Z0-9]*\/servers/).exec(path) || | ||
// !!(/#\/components\/operations\/[a-zA-Z0-9]*\/channel/).exec(path) || | ||
// !!(/#\/components\/operations\/[a-zA-Z0-9]*\/messages/).exec(path) || | ||
// !!(/#\/components\/operations\/[a-zA-Z0-9]*\/reply\/channel/).exec( | ||
// path | ||
// ) || | ||
// !!(/#\/components\/operations\/[a-zA-Z0-9]*\/reply\/messages/).exec( | ||
// path | ||
// ) | ||
// ); | ||
// }, | ||
}, | ||
}); | ||
|
||
const result = await parser.validate( | ||
JSON.parse(JSON.stringify(dereferencedJSONSchema)) | ||
); | ||
|
||
// If Parser's `validate()` function returns a non-empty array, that means | ||
// there were errors during validation. Thus, the array is outputted as a list | ||
// of remarks, and the program exits without doing anything further. | ||
// if (result.length !== 0) { | ||
// console.log( | ||
// 'Validation of the resulting AsyncAPI Document failed.\nList of remarks:\n', | ||
// result | ||
// ); | ||
// throw new Error(); | ||
// } | ||
|
||
return result; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters