Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: References resolved wrong when parsing is done inside Promise.all() #168

Merged
merged 2 commits into from
Aug 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions lib/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ const OPERATIONS = ['publish', 'subscribe'];
const SPECIAL_SECURITY_TYPES = ['oauth2', 'openIdConnect'];
const PARSERS = {};
const xParserCircle = 'x-parser-circular';
const refParser = new $RefParser;

/**
* @module @asyncapi/parser
Expand Down Expand Up @@ -76,10 +75,11 @@ async function parse(asyncapiYAMLorJSON, options = {}) {

if (options.applyTraits === undefined) options.applyTraits = true;

const refParser = new $RefParser;
//because of Ajv lacks support for circular refs, parser should not resolve them before Ajv validation and first needs to ignore them and leave circular $refs to successfully validate the document
//this is done pair to advice from Ajv creator https://github.com/ajv-validator/ajv/issues/1122#issuecomment-559378449
//later we perform full dereference of circular refs if they occure
await dereference(parsedJSON, initialFormat, asyncapiYAMLorJSON, { ...options, dereference: { circular: 'ignore' } });
await dereference(refParser, parsedJSON, initialFormat, asyncapiYAMLorJSON, { ...options, dereference: { circular: 'ignore' } });

const ajv = new Ajv({
jsonPointers: true,
Expand All @@ -100,7 +100,7 @@ async function parse(asyncapiYAMLorJSON, options = {}) {
});

await customDocumentOperations(parsedJSON, asyncapiYAMLorJSON, initialFormat, options);
if (refParser.$refs.circular) await handleCircularRefs(parsedJSON, initialFormat, asyncapiYAMLorJSON, options);
if (refParser.$refs.circular) await handleCircularRefs(refParser, parsedJSON, initialFormat, asyncapiYAMLorJSON, options);
} catch (e) {
if (e instanceof ParserError) throw e;
throw new ParserError({
Expand Down Expand Up @@ -136,7 +136,7 @@ function parseFromUrl(url, fetchOptions, options) {
});
}

async function dereference(parsedJSON, initialFormat, asyncapiYAMLorJSON, options) {
async function dereference(refParser, parsedJSON, initialFormat, asyncapiYAMLorJSON, options) {
try {
return await refParser.dereference(options.path, parsedJSON, {
continueOnError: true,
Expand All @@ -158,8 +158,8 @@ async function dereference(parsedJSON, initialFormat, asyncapiYAMLorJSON, option
* In case of circular refs, this function dereferences the spec again to dereference circular dependencies
* Special property is added to the document that indicates it contains circular refs
*/
async function handleCircularRefs(parsedJSON, initialFormat, asyncapiYAMLorJSON, options) {
await dereference(parsedJSON, initialFormat, asyncapiYAMLorJSON, { ...options, dereference: { circular: true } });
async function handleCircularRefs(refParser, parsedJSON, initialFormat, asyncapiYAMLorJSON, options) {
await dereference(refParser, parsedJSON, initialFormat, asyncapiYAMLorJSON, { ...options, dereference: { circular: true } });
//mark entire document as containing circular references
parsedJSON[String(xParserCircle)] = true;
}
Expand Down
12 changes: 11 additions & 1 deletion test/parse_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,17 @@ const checkErrorWrapper = async (fn, validationObject) => {
describe('parse()', function() {
it('should parse YAML', async function() {
const result = await parser.parse(inputYAML, { path: __filename });
await expect(JSON.stringify(result.json())).to.equal(outputJSON);
expect(JSON.stringify(result.json())).to.equal(outputJSON);
});

it('should parse 2 AsyncAPI specs in Promise.all() and not fail with resolving references', async function() {
const input = [
parser.parse(inputYAML, { path: __filename }),
parser.parse(inputYAML, { path: __filename })
];
const result = await Promise.all(input);
expect(JSON.stringify(result[0].json())).to.equal(outputJSON);
expect(JSON.stringify(result[1].json())).to.equal(outputJSON);
});

it('should fail when asyncapi is not valid', async function() {
Expand Down