Skip to content

Commit

Permalink
feat(reference): support native fragment deref/resolve - AsyncAPI 2.x (
Browse files Browse the repository at this point in the history
…#2945)

This native support includes resolving external and internal
references within the AsyncAPI 2.x fragment.

Refs #2934
  • Loading branch information
char0n committed Jul 13, 2023
1 parent d33a92d commit 2b75f78
Show file tree
Hide file tree
Showing 3 changed files with 210 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,8 @@ const AsyncApi2DereferenceVisitor = stampit({
return undefined;
}

// @ts-ignore
const reference = await this.toReference(referencingElement.$ref?.toValue());
const retrievalURI = reference.uri;
const { uri: retrievalURI } = reference;
const $refBaseURI = url.resolve(retrievalURI, referencingElement.$ref?.toValue());

this.indirections.push(referencingElement);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ const AsyncApi2ResolveVisitor = stampit({
},

async crawlChannelItemElement(channelItemElement: ChannelItemElement) {
// @ts-ignore
const reference = await this.toReference(channelItemElement.$ref?.toValue());

this.indirections.push(channelItemElement);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,145 +14,245 @@ describe('dereference', function () {
context('strategies', function () {
context('asyncapi-2', function () {
context('Reference Object', function () {
context('given single ReferenceElement passed to dereferenceApiDOM', function () {
context('given dereferencing using local file system', function () {
const fixturePath = path.join(__dirname, 'fixtures', 'external-only', 'root.json');
context(
'given single ReferenceElement passed to dereferenceApiDOM with internal references',
function () {
context('given dereferencing using local file system', function () {
const fixturePath = path.join(__dirname, 'fixtures', 'internal-only', 'root.json');

specify('should dereference', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
});
const referenceElement = evaluate(
'/components/parameters/externalRef',
parseResult.api as AsyncApi2Element,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: { baseURI: fixturePath },
specify('should dereference', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
});
const referenceElement = evaluate(
'/components/parameters/userId',
parseResult.api as AsyncApi2Element,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: {
baseURI: `${fixturePath}#/components/parameters/userId`,
},
});

assert.isTrue(isParameterElement(dereferenced));
});

assert.isTrue(isParameterElement(dereferenced));
specify('should dereference and contain metadata about origin', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
});
const referenceElement = evaluate(
'/components/parameters/userId',
parseResult.api as AsyncApi2Element,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: { baseURI: `${fixturePath}#/components/parameters/userId` },
});

assert.match(
dereferenced.meta.get('ref-origin').toValue(),
/internal-only\/root\.json$/,
);
});
});

specify('should dereference and contain metadata about origin', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
context('given dereferencing using HTTP protocol', function () {
const fixturePath = path.join(__dirname, 'fixtures', 'internal-only', 'root.json');
const httpPort = 8123;
let httpServer: ServerTerminable;

beforeEach(function () {
const cwd = path.join(__dirname, 'fixtures', 'internal-only');
httpServer = createHTTPServer({ port: httpPort, cwd });
});
const referenceElement = evaluate(
'/components/parameters/externalRef',
parseResult.api as AsyncApi2Element,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: { baseURI: fixturePath },

afterEach(async function () {
await httpServer.terminate();
});

assert.match(
dereferenced.meta.get('ref-origin').toValue(),
/external-only\/ex\.json$/,
);
});
});
specify('should dereference', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
});
const referenceElement = evaluate(
'/components/parameters/userId',
parseResult.api as AsyncApi2Element,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: {
baseURI: `http://localhost:${httpPort}/root.json#/components/parameters/userId`,
},
});

context('given dereferencing using HTTP protocol', function () {
const fixturePath = path.join(__dirname, 'fixtures', 'external-only', 'root.json');
const httpPort = 8123;
let httpServer: ServerTerminable;
assert.isTrue(isParameterElement(dereferenced));
});

beforeEach(function () {
const cwd = path.join(__dirname, 'fixtures', 'external-only');
httpServer = createHTTPServer({ port: httpPort, cwd });
});
specify('should dereference and contain metadata about origin', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
});
const referenceElement = evaluate(
'/components/parameters/userId',
parseResult.api as AsyncApi2Element,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: {
baseURI: `http://localhost:${httpPort}/root.json#/components/parameters/userId`,
},
});

afterEach(async function () {
await httpServer.terminate();
assert.match(dereferenced.meta.get('ref-origin').toValue(), /\/root\.json$/);
});
});
},
);

specify('should dereference', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
});
const referenceElement = evaluate(
'/components/parameters/externalRef',
parseResult.api as AsyncApi2Element,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: { baseURI: `http://localhost:${httpPort}/root.json` },
context(
'given single ReferenceElement passed to dereferenceApiDOM with external references',
function () {
context('given dereferencing using local file system', function () {
const fixturePath = path.join(__dirname, 'fixtures', 'external-only', 'root.json');

specify('should dereference', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
});
const referenceElement = evaluate(
'/components/parameters/externalRef',
parseResult.api as AsyncApi2Element,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: { baseURI: fixturePath },
});

assert.isTrue(isParameterElement(dereferenced));
});

assert.isTrue(isParameterElement(dereferenced));
specify('should dereference and contain metadata about origin', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
});
const referenceElement = evaluate(
'/components/parameters/externalRef',
parseResult.api as AsyncApi2Element,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: { baseURI: fixturePath },
});

assert.match(
dereferenced.meta.get('ref-origin').toValue(),
/external-only\/ex\.json$/,
);
});
});

specify('should dereference and contain metadata about origin', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
context('given dereferencing using HTTP protocol', function () {
const fixturePath = path.join(__dirname, 'fixtures', 'external-only', 'root.json');
const httpPort = 8123;
let httpServer: ServerTerminable;

beforeEach(function () {
const cwd = path.join(__dirname, 'fixtures', 'external-only');
httpServer = createHTTPServer({ port: httpPort, cwd });
});
const referenceElement = evaluate(
'/components/parameters/externalRef',
parseResult.api as AsyncApi2Element,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: { baseURI: `http://localhost:${httpPort}/root.json` },

afterEach(async function () {
await httpServer.terminate();
});

assert.match(dereferenced.meta.get('ref-origin').toValue(), /\/ex\.json$/);
});
});

context('given dereferencing using HTTP protocol and absolute URLs', function () {
const fixturePath = path.join(
__dirname,
'fixtures',
'external-only-absolute-url',
'root.json',
);
const httpPort = 8123;
let httpServer: ServerTerminable;

beforeEach(function () {
const cwd = path.join(__dirname, 'fixtures', 'external-only-absolute-url');
httpServer = createHTTPServer({ port: httpPort, cwd });
});
specify('should dereference', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
});
const referenceElement = evaluate(
'/components/parameters/externalRef',
parseResult.api as AsyncApi2Element,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: { baseURI: `http://localhost:${httpPort}/root.json` },
});

afterEach(async function () {
await httpServer.terminate();
});
assert.isTrue(isParameterElement(dereferenced));
});

specify('should dereference', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
specify('should dereference and contain metadata about origin', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
});
const referenceElement = evaluate(
'/components/parameters/externalRef',
parseResult.api as AsyncApi2Element,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: { baseURI: `http://localhost:${httpPort}/root.json` },
});

assert.match(dereferenced.meta.get('ref-origin').toValue(), /\/ex\.json$/);
});
const referenceElement = evaluate(
'/components/parameters/externalRef',
parseResult.api as AsyncApi2Element,
});

context('given dereferencing using HTTP protocol and absolute URLs', function () {
const fixturePath = path.join(
__dirname,
'fixtures',
'external-only-absolute-url',
'root.json',
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: { baseURI: `http://localhost:${httpPort}/root.json` },
});
const httpPort = 8123;
let httpServer: ServerTerminable;

assert.isTrue(isParameterElement(dereferenced));
});
beforeEach(function () {
const cwd = path.join(__dirname, 'fixtures', 'external-only-absolute-url');
httpServer = createHTTPServer({ port: httpPort, cwd });
});

specify('should dereference and contain metadata about origin', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
afterEach(async function () {
await httpServer.terminate();
});
const referenceElement = evaluate(
'/components/parameters/externalRef',
parseResult.api as AsyncApi2Element,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: { baseURI: `http://localhost:${httpPort}/root.json` },

specify('should dereference', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
});
const referenceElement = evaluate(
'/components/parameters/externalRef',
parseResult.api as AsyncApi2Element,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: { baseURI: `http://localhost:${httpPort}/root.json` },
});

assert.isTrue(isParameterElement(dereferenced));
});

assert.match(dereferenced.meta.get('ref-origin').toValue(), /\/ex\.json$/);
specify('should dereference and contain metadata about origin', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
});
const referenceElement = evaluate(
'/components/parameters/externalRef',
parseResult.api as AsyncApi2Element,
);
const dereferenced = await dereferenceApiDOM(referenceElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: { baseURI: `http://localhost:${httpPort}/root.json` },
});

assert.match(dereferenced.meta.get('ref-origin').toValue(), /\/ex\.json$/);
});
});
});
});
},
);
});
});
});
Expand Down

0 comments on commit 2b75f78

Please sign in to comment.