Skip to content

Commit

Permalink
feat(reference): add swagger-client OpenAPI 3.1 dereferene strategy (#…
Browse files Browse the repository at this point in the history
…2326)

This is just an initial version with no additional supported options.

Refs #2289
  • Loading branch information
char0n authored Dec 2, 2022
1 parent a93b820 commit 40dbf2a
Show file tree
Hide file tree
Showing 282 changed files with 7,169 additions and 12 deletions.
2 changes: 1 addition & 1 deletion packages/apidom-reference/src/parse/parsers/Parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ParseResultElement } from '@swagger-api/apidom-core';
import { Parser as IParser } from '../../types';
import { NotImplementedError } from '../../util/errors';

const Parser = stampit({
const Parser: stampit.Stamp<IParser> = stampit({
props: {
name: '',
/**
Expand Down
22 changes: 11 additions & 11 deletions packages/apidom-reference/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,24 +76,24 @@ export interface ReferenceSet {
}

export interface ReferenceParserOptions {
readonly mediaType: string;
readonly parsers: Array<Parser>;
readonly parserOpts: Record<string, any>;
mediaType: string;
parsers: Array<Parser>;
parserOpts: Record<string, any>;
}

export interface ReferenceResolveOptions {
baseURI: string;
readonly resolvers: Array<Resolver>;
readonly resolverOpts: Record<string, any>;
readonly strategies: Array<ResolveStrategy>;
readonly external: boolean;
readonly maxDepth: number;
resolvers: Array<Resolver>;
resolverOpts: Record<string, any>;
strategies: Array<ResolveStrategy>;
external: boolean;
maxDepth: number;
}

export interface ReferenceDereferenceOptions {
readonly strategies: Array<DereferenceStrategy>;
readonly refSet: null | ReferenceSet;
readonly maxDepth: number;
strategies: Array<DereferenceStrategy>;
refSet: null | ReferenceSet;
maxDepth: number;
}

export interface ReferenceOptions {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// @ts-ignore
import SwaggerClient from 'swagger-client';

import options from '../../../../src/options';
import JsonParser from './helpers/parsers/json';
import YamlParser from './helpers/parsers/yaml1-2';
import OpenApiJson3_1Parser from './helpers/parsers/openapi-json-3-1';
import OpenApiYaml3_1Parser from './helpers/parsers/openapi-yaml-3-1';
import HttpResolverSwaggerClient from '../../../../src/resolve/resolvers/HttpResolverSwaggerClient';

const originalParsers = [...options.parse.parsers];
const originalResolvers = [...options.resolve.resolvers];

export const before = () => {
// configure custom parser plugins globally
options.parse.parsers = options.parse.parsers.map((parser) => {
// @ts-ignore
if (parser.name === 'json') {
return JsonParser({ allowEmpty: true, sourceMap: false });
}
// @ts-ignore
if (parser.name === 'yaml-1-2') {
return YamlParser({ allowEmpty: true, sourceMap: false });
}
// @ts-ignore
if (parser.name === 'openapi-json-3-1') {
return OpenApiJson3_1Parser({ allowEmpty: true, sourceMap: false });
}
// @ts-ignore
if (parser.name === 'openapi-yaml-3-1') {
return OpenApiYaml3_1Parser({ allowEmpty: true, sourceMap: false });
}

return parser;
});

// configure custom resolver plugins globally
options.resolve.resolvers = options.resolve.resolvers.map((resolver) => {
// @ts-ignore
if (resolver.name === 'http-axios') {
return HttpResolverSwaggerClient({ swaggerHTTPClient: SwaggerClient.http });
}

return resolver;
});
};

export const after = () => {
options.parse.parsers = originalParsers;
options.resolve.resolvers = originalResolvers;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[
{
"openapi": "3.1.0",
"components": {
"callbacks": {
"callback1": {
"{$method}": {
"description": "description of callback2"
}
},
"callback2": {
"{$method}": {
"description": "description of callback2"
}
}
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
openapi: 3.1.0
components:
callbacks:
callback1:
"$ref": "#/components/callbacks/callback2"
callback2:
"{$method}":
description: description of callback2
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[
{
"openapi": "3.1.0",
"paths": {
"/path": {
"get": {
"callbacks": {
"callback": {
"{$method}": {
"description": "description of callback2"
}
}
}
}
}
},
"components": {
"callbacks": {
"callback": {
"{$method}": {
"description": "description of callback2"
}
}
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
openapi: 3.1.0
paths:
"/path":
get:
callbacks:
callback:
"$ref": "#/components/callbacks/callback"
components:
callbacks:
callback:
"{$method}":
description: description of callback2
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import path from 'node:path';
import { assert } from 'chai';
import { toValue } from '@swagger-api/apidom-core';
import { mediaTypes } from '@swagger-api/apidom-ns-openapi-3-1';

import { loadJsonFile } from '../../../../helpers';
import { dereference } from '../../../../../src';
import * as bootstrap from '../bootstrap';

const rootFixturePath = path.join(__dirname, 'fixtures');

describe('dereference', function () {
before(function () {
bootstrap.before();
});

after(function () {
bootstrap.after();
});

context('strategies', function () {
context('openapi-3-1swagger-client', function () {
context('Callback Object', function () {
context('given in components/callbacks field', function () {
const fixturePath = path.join(rootFixturePath, 'components-callbacks');

specify('should dereference', async function () {
const rootFilePath = path.join(fixturePath, 'root.yaml');
const actual = await dereference(rootFilePath, {
parse: { mediaType: mediaTypes.latest('yaml') },
});
const expected = loadJsonFile(path.join(fixturePath, 'dereferenced.json'));

assert.deepEqual(toValue(actual), expected);
});
});

context('given in Operation Object', function () {
const fixturePath = path.join(rootFixturePath, 'operation-object');

specify('should dereference', async function () {
const rootFilePath = path.join(fixturePath, 'root.yaml');
const actual = await dereference(rootFilePath, {
parse: { mediaType: mediaTypes.latest('yaml') },
});
const expected = loadJsonFile(path.join(fixturePath, 'dereferenced.json'));

assert.deepEqual(toValue(actual), expected);
});
});
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import path from 'node:path';
import { assert } from 'chai';
import {
mediaTypes,
ExampleElement,
isExampleElement,
OpenApi3_1Element,
} from '@swagger-api/apidom-ns-openapi-3-1';
import { evaluate } from '@swagger-api/apidom-json-pointer';

import * as bootstrap from '../bootstrap';
import { parse, dereferenceApiDOM } from '../../../../../src';

describe('dereference', function () {
before(function () {
bootstrap.before();
});

after(function () {
bootstrap.after();
});

context('strategies', function () {
context('openapi-3-1swagger-client', function () {
context('Example Object', function () {
context('given single ExampleElement passed to dereferenceApiDOM', function () {
const fixturePath = path.join(__dirname, 'fixtures', 'external-value-json', 'root.json');

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

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

specify('should dereference and contain metadata about origin', async function () {
const parseResult = await parse(fixturePath, {
parse: { mediaType: mediaTypes.latest('json') },
});
const exampleElement = evaluate(
'/components/examples/example1',
parseResult.api as OpenApi3_1Element,
);
const dereferenced = (await dereferenceApiDOM(exampleElement, {
parse: { mediaType: mediaTypes.latest('json') },
resolve: { baseURI: fixturePath },
})) as ExampleElement;

assert.match(
dereferenced.value?.meta.get('ref-origin').toValue(),
/external-value-json\/ex\.json$/,
);
});
});
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[
{
"openapi": "3.1.0",
"components": {
"examples": {
"example1": {
"description": "example1 description",
"value": 1
},
"example2": {
"description": "example1 description",
"value": 1
}
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"openapi": "3.1.0",
"components": {
"examples": {
"example1": {
"description": "example1 description",
"value": 1
},
"example2": {
"$ref": "#/components/examples/example1"
}
}
}
}

Large diffs are not rendered by default.

Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"openapi": "3.1.0",
"components": {
"examples": {
"example1": {
"description": "example1 description",
"externalValue": "./favicon.ico"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[
{
"openapi": "3.1.0",
"components": {
"examples": {
"example1": {
"description": "example1 description",
"externalValue": "./ex.json"
}
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"openapi": "3.1.0",
"components": {
"examples": {
"example1": {
"description": "example1 description",
"externalValue": "./ex.json"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[
{
"openapi": "3.1.0",
"components": {
"examples": {
"example1": {
"description": "example1 description",
"value": {
"prop1": "value1",
"prop2": "value2"
},
"externalValue": "./ex.json"
}
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"prop1": "value1",
"prop2": "value2"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"openapi": "3.1.0",
"components": {
"examples": {
"example1": {
"description": "example1 description",
"externalValue": "./ex.json"
}
}
}
}
Loading

0 comments on commit 40dbf2a

Please sign in to comment.