diff --git a/src/util.ts b/src/util.ts index 7810650..500f52c 100644 --- a/src/util.ts +++ b/src/util.ts @@ -8,6 +8,54 @@ import { ParserError } from './errors'; import type { AsyncAPIObject } from './spec-types'; +// Moved 'addXOrigins' to the start of the scope to avoid an ESLint error +// `'addXOrigins' was used before it was defined` +export function addXOrigins(asyncapiDocument: AsyncAPIObject) { + // VALUE from 'asyncapiDocument' becomes KEY for the + // underlying and recursive functions + Object.values(asyncapiDocument).forEach(async (key: any) => { + if (key && typeof key === 'object' && key !== '$ref') { + if (Object.keys(key).indexOf('$ref') !== -1) { + if (isExternalReference(key['$ref'])) { + key['x-origin'] = key['$ref']; + + // If an external `$ref` is found, the function goes into + // second-level recursion to see if there are more `$ref`s whose + // values need to be copied to the `x-origin` properties of the + // `$ref`ed file. + // If an external `$ref` is found again, the function goes into the + // third-level recursion, and so on, until it reaches a file that + // contains no external `$ref`s at all. + // Then it exits all the way up in the opposite direction. + + const inlineAsyncapiDocumentURI = key['$ref'].split('#/'); + const inlineAsyncapiDocumentPath = inlineAsyncapiDocumentURI[0]; + const inlineAsyncapiDocumentPointer = inlineAsyncapiDocumentURI[1]; + + let inlineAsyncapiDocument = inlineAsyncapiDocumentPath.startsWith( + 'http' + ) + ? yaml.load(await axios(inlineAsyncapiDocumentPath)) + : (yaml.load( + fs.readFileSync(inlineAsyncapiDocumentPath, 'utf-8') + ) as any); + + inlineAsyncapiDocument = + inlineAsyncapiDocument[inlineAsyncapiDocumentPointer]; + + if (inlineAsyncapiDocument) { + addXOrigins(inlineAsyncapiDocument as AsyncAPIObject); + merge(key, inlineAsyncapiDocument); + } + } + } else { + addXOrigins(key); + } + } + }); + return asyncapiDocument; +} + /** * @private */ @@ -39,7 +87,7 @@ export const toJS = (asyncapiYAMLorJSON: string | object) => { title: 'The provided yaml is not valid.', }); } - + return yaml.load(asyncapiYAMLorJSON); }; @@ -82,7 +130,7 @@ export const resolve = async ( }; /** - * + * * @param asyncapiDocument {AsyncAPIObject} * @returns {boolean} */ @@ -97,55 +145,11 @@ export function versionCheck(asyncapiDocuments: AsyncAPIObject[]): number { for (const asyncapiDocument of asyncapiDocuments) { const majorVersion = getSpecVersion(asyncapiDocument); if (majorVersion !== currentVersion) { - throw new Error('Unable to bundle specification file of different major versions'); + throw new Error( + 'Unable to bundle specification file of different major versions' + ); } currentVersion = majorVersion; } return currentVersion; } - -export function addXOrigins(asyncapiDocument: AsyncAPIObject) { - // VALUE from 'asyncapiDocument' becomes KEY for the - // underlying and recursive functions - Object.values(asyncapiDocument).forEach(async (key: any) => { - if (key && typeof key === 'object' && key !== '$ref') { - if (Object.keys(key).indexOf('$ref') !== -1) { - if (isExternalReference(key['$ref'])) { - key['x-origin'] = key['$ref']; - - // If an external `$ref` is found, the function goes into - // second-level recursion to see if there are more `$ref`s whose - // values need to be copied to the `x-origin` properties of the - // `$ref`ed file. - // If an external `$ref` is found again, the function goes into the - // third-level recursion, and so on, until it reaches a file that - // contains no external `$ref`s at all. - // Then it exits all the way up in the opposite direction. - - const inlineAsyncapiDocumentURI = key['$ref'].split('#/'); - const inlineAsyncapiDocumentPath = inlineAsyncapiDocumentURI[0]; - const inlineAsyncapiDocumentPointer = inlineAsyncapiDocumentURI[1]; - - let inlineAsyncapiDocument = inlineAsyncapiDocumentPath.startsWith( - 'http' - ) - ? yaml.load(await axios(inlineAsyncapiDocumentPath)) - : (yaml.load( - fs.readFileSync(inlineAsyncapiDocumentPath, 'utf-8') - ) as any); - - inlineAsyncapiDocument = - inlineAsyncapiDocument[inlineAsyncapiDocumentPointer]; - - if (inlineAsyncapiDocument) { - addXOrigins(inlineAsyncapiDocument as AsyncAPIObject); - merge(key, inlineAsyncapiDocument); - } - } - } else { - addXOrigins(key); - } - } - }); - return asyncapiDocument; -} diff --git a/src/v3/parser.ts b/src/v3/parser.ts index 28800fa..4474628 100644 --- a/src/v3/parser.ts +++ b/src/v3/parser.ts @@ -1,6 +1,6 @@ import $RefParser, {$Refs} from '@apidevtools/json-schema-ref-parser'; -import { JSONPath } from 'jsonpath-plus'; -import { merge } from 'lodash'; +// import { JSONPath } from 'jsonpath-plus'; +// import { merge } from 'lodash'; import { addXOrigins } from '../util'; import { AsyncAPIObject } from 'spec-types'; @@ -23,64 +23,78 @@ class ExternalComponents { } } -function crawlChannelPropertiesForRefs(JSONSchema: any) { - return JSONPath({ - json: JSONSchema, - path: '$.channels.*.messages.*.[\'$ref\']', - }); -} +// function crawlChannelPropertiesForRefs(JSONSchema: any) { +// return JSONPath({ +// json: JSONSchema, +// path: '$.channels.*.messages.*.[\'$ref\']', +// }); +// } export function isExternalReference(ref: string): boolean { return typeof ref === 'string' && !ref.startsWith('#'); } -async function resolveExternalRefs(parsedJSON: any, $refs: $Refs) { - const componentObj: any = { messages: {} }; - JSONPath({ - json: parsedJSON, - resultType: 'all', - path: '$.channels.*.messages.*', - }).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; - } - parent[String(parentProperty)][ - '$ref' - ] = `#/components/messages/${component.getKey()}`; - } - } - ); +// async function resolveExternalRefs(parsedJSON: any, $refs: $Refs) { +// const componentObj: any = { messages: {} }; +// JSONPath({ +// json: parsedJSON, +// resultType: 'all', +// path: '$.channels.*.messages.*', +// }).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; +// } +// parent[String(parentProperty)][ +// '$ref' +// ] = `#/components/messages/${component.getKey()}`; +// } +// } +// ); - return componentObj; -} +// return componentObj; +// } + +// async function resolveExternalRefsForOperation(parsedJSON: any, $refs: $Refs) { +// JSONPath({ +// json: parsedJSON, +// resultType: 'all', +// path: '$.operations.*.messages.*' +// }).forEach( +// ({parent, parentProperty}: {parent: any, parentProperty: string}) => { +// parent.forEach((reference: any) => { +// const ref = reference['$ref']; +// if (isExternalReference(ref)) { +// const value: any = $refs.get(ref); +// const component = new ExternalComponents(ref, value); +// parent[String(parentProperty)]['$ref'] = `#/components/messages/${component.getKey()}`; +// } +// }); +// } +// ); +// } +import { Parser } from '@asyncapi/parser'; +const parser = new Parser(); -async function resolveExternalRefsForOperation(parsedJSON: any, $refs: $Refs) { - JSONPath({ - json: parsedJSON, - resultType: 'all', - path: '$.operations.*.messages.*' - }).forEach( - ({parent, parentProperty}: {parent: any, parentProperty: string}) => { - parent.forEach((reference: any) => { - const ref = reference['$ref']; - if (isExternalReference(ref)) { - const value: any = $refs.get(ref); - const component = new ExternalComponents(ref, value); - parent[String(parentProperty)]['$ref'] = `#/components/messages/${component.getKey()}`; - } - }); - } - ); -} export async function parse(JSONSchema: any) { addXOrigins(JSONSchema); + const { document } = await parser.parse(JSONSchema); + +if (document) { + // => Example AsyncAPI specification + let channel = document.channels()[2]; + channel = JSON.parse(JSON.stringify(channel)); + for (const value of Object.values(channel)) { + console.log(!!value.parameters); + } + // console.log(channel); +} await $RefParser.dereference(JSONSchema, { dereference: { circular: false,