Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,23 @@ import OpenApi3_1DereferenceVisitor from './visitor';
const visitAsync = visit[Symbol.for('nodejs.util.promisify.custom')];

// eslint-disable-next-line @typescript-eslint/naming-convention
const OpenApi3_1SwaggerClientDereferenceStrategy: stampit.Stamp<IDereferenceStrategy> = stampit(
DereferenceStrategy,
{
init() {
this.name = 'openapi-3-1';
interface IOpenApi3_1SwaggerClientDereferenceStrategy extends IDereferenceStrategy {
useCircularStructures: boolean;
}

// eslint-disable-next-line @typescript-eslint/naming-convention
const OpenApi3_1SwaggerClientDereferenceStrategy: stampit.Stamp<IOpenApi3_1SwaggerClientDereferenceStrategy> =
stampit(DereferenceStrategy, {
props: {
useCircularStructures: true,
},
init(
this: IOpenApi3_1SwaggerClientDereferenceStrategy,
{ useCircularStructures = this.useCircularStructures } = {},
) {
// @ts-ignore
this.name = 'openapi-3-1-swagger-client';
this.useCircularStructures = useCircularStructures;
},
methods: {
canDereference(file: IFile): boolean {
Expand All @@ -52,14 +64,19 @@ const OpenApi3_1SwaggerClientDereferenceStrategy: stampit.Stamp<IDereferenceStra
reference = refSet.find(propEq('uri', file.uri));
}

const visitor = OpenApi3_1DereferenceVisitor({ reference, namespace, options });
const visitor = OpenApi3_1DereferenceVisitor({
reference,
namespace,
options,
useCircularStructures: this.useCircularStructures,
});
const dereferencedElement = await visitAsync(refSet.rootRef.value, visitor, {
keyMap,
nodeTypeGetter: getNodeType,
});

/**
* Release all memory if this refSet was not provided as an configuration option.
* Release all memory if this refSet was not provided as a configuration option.
* If provided as configuration option, then provider is responsible for cleanup.
*/
if (options.dereference.refSet === null) {
Expand All @@ -69,7 +86,6 @@ const OpenApi3_1SwaggerClientDereferenceStrategy: stampit.Stamp<IDereferenceStra
return dereferencedElement;
},
},
},
);
});

export default OpenApi3_1SwaggerClientDereferenceStrategy;
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
maybeRefractToSchemaElement,
} from '../../../resolve/strategies/openapi-3-1/util';
import EvaluationJsonSchemaUriError from '../openapi-3-1/selectors/uri/errors/EvaluationJsonSchemaUriError';
import { isHttpUrl } from '../../../util/url';

// @ts-ignore
const visitAsync = visit[Symbol.for('nodejs.util.promisify.custom')];
Expand All @@ -55,13 +56,22 @@ const OpenApi3_1SwaggerClientDereferenceVisitor = stampit({
namespace: null,
reference: null,
options: null,
useCircularStructures: true,
},
init({ indirections = [], visited = new WeakSet(), reference, namespace, options }) {
init({
indirections = [],
visited = new WeakSet(),
reference,
namespace,
options,
useCircularStructures,
}) {
this.indirections = indirections;
this.visited = visited;
this.namespace = namespace;
this.reference = reference;
this.options = options;
this.useCircularStructures = useCircularStructures;
},
methods: {
toBaseURI(uri: string): string {
Expand Down Expand Up @@ -458,13 +468,28 @@ const OpenApi3_1SwaggerClientDereferenceVisitor = stampit({
);
}

// detect possible cycle and avoid it
if (!this.useCircularStructures && this.visited.has(referencedElement)) {
// make the referencing URL absolute if possible
if (isHttpUrl(reference.uri) && isStringElement(referencingElement.$ref)) {
const absoluteJSONPointerURL = url.resolve(
reference.uri,
referencingElement.$ref?.toValue(),
);
referencingElement.set('$ref', absoluteJSONPointerURL);
}
// skip processing this node
return false;
}

// dive deep into the fragment
const visitor: any = OpenApi3_1SwaggerClientDereferenceVisitor({
reference,
namespace: this.namespace,
indirections: [...this.indirections],
options: this.options,
visited: this.visited,
useCircularStructures: this.useCircularStructures,
});
referencedElement = await visitAsync(referencedElement, visitor, {
keyMap,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ 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';
import OpenApi3_1SwaggerClientDereferenceStrategy from '../../../../src/dereference/strategies/openapi-3-1-swagger-client';

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

export const before = () => {
// configure custom parser plugins globally
Expand Down Expand Up @@ -43,9 +45,20 @@ export const before = () => {

return resolver;
});

// configure custom dereference strategy globally
options.dereference.strategies = options.dereference.strategies.map((strategy) => {
// @ts-ignore
if (strategy.name === 'openapi-3-1') {
return OpenApi3_1SwaggerClientDereferenceStrategy();
}

return strategy;
});
};

export const after = () => {
options.parse.parsers = originalParsers;
options.resolve.resolvers = originalResolvers;
options.dereference.strategies = originalDereferenceStrategies;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[
{
"openapi": "3.1.0",
"components": {
"schemas": {
"User": {
"type": "object",
"properties": {
"profile": {
"properties": {
"parent": {
"$ref": "http://localhost:8123/ex.json#/$defs/UserProfile"
}
}
}
}
}
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$defs": {
"UserProfile": {
"properties": {
"parent": {
"$ref": "#/$defs/UserProfile"
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"openapi": "3.1.0",
"components": {
"schemas": {
"User": {
"type": "object",
"properties": {
"profile": {
"$ref": "./ex.json#/$defs/UserProfile"
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[
{
"openapi": "3.1.0",
"components": {
"schemas": {
"User": {
"type": "object",
"properties": {
"profile": {
"properties": {
"parent": {
"$ref": "#/$defs/UserProfile"
}
}
}
}
}
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$defs": {
"UserProfile": {
"properties": {
"parent": {
"$ref": "#/$defs/UserProfile"
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"openapi": "3.1.0",
"components": {
"schemas": {
"User": {
"type": "object",
"properties": {
"profile": {
"$ref": "./ex.json#/$defs/UserProfile"
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[
{
"openapi": "3.1.0",
"components": {
"schemas": {
"User": {
"type": "object",
"properties": {
"parent": {
"$ref": "http://localhost:8123/root.json#/components/schemas/User"
}
}
}
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"openapi": "3.1.0",
"components": {
"schemas": {
"User": {
"type": "object",
"properties": {
"parent": {
"$ref": "#/components/schemas/User"
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[
{
"openapi": "3.1.0",
"components": {
"schemas": {
"User": {
"type": "object",
"properties": {
"parent": {
"$ref": "#/components/schemas/User"
}
}
}
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"openapi": "3.1.0",
"components": {
"schemas": {
"User": {
"type": "object",
"properties": {
"parent": {
"$ref": "#/components/schemas/User"
}
}
}
}
}
}
Loading