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

feat(resolver): expose resolve strategies #2854

Merged
merged 1 commit into from
Feb 23, 2023
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
23 changes: 19 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
import Url from 'url';

import Http, { makeHttp, serializeRes, serializeHeaders } from './http/index.js';
import Resolver from './resolver/index.js';
import { clearCache } from './resolver/strategies/openapi-2--3-0/index.js';
import resolve from './resolver/index.js';
import genericResolveStrategy from './resolver/strategies/generic/index.js';
import openApi2ResolveStrategy, { clearCache } from './resolver/strategies/openapi-2/index.js';
import openApi30ResolveStrategy from './resolver/strategies/openapi-3-0/index.js';
import openApi31ApiDOMResolveStrategy from './resolver/strategies/openapi-3-1-apidom/index.js';
import resolveSubtree from './subtree-resolver/index.js';
import { makeApisTagOperation } from './interfaces.js';
import { execute, buildRequest, baseUrl } from './execute/index.js';
Expand All @@ -17,8 +20,20 @@ import OpenApi3_1SwaggerClientDereferenceStrategy from './resolver/apidom/refere

Swagger.http = Http;
Swagger.makeHttp = makeHttp.bind(null, Swagger.http);
Swagger.resolve = Resolver;
Swagger.resolveSubtree = resolveSubtree;
Swagger.resolveStrategies = {
'openapi-3-1-apidom': openApi31ApiDOMResolveStrategy,
'openapi-3-0': openApi30ResolveStrategy,
'openapi-2-0': openApi2ResolveStrategy,
generic: genericResolveStrategy,
};
Swagger.resolve = async (options) => {
const mergedOptions = { strategies: Object.values(Swagger.resolveStrategies), ...options };
return resolve(mergedOptions);
};
Swagger.resolveSubtree = async (obj, path, options = {}) => {
const mergedOptions = { strategies: Object.values(Swagger.resolveStrategies), ...options };
return resolveSubtree(obj, path, mergedOptions);
};
Swagger.execute = execute;
Swagger.serializeRes = serializeRes;
Swagger.serializeHeaders = serializeHeaders;
Expand Down
13 changes: 6 additions & 7 deletions src/resolver/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// eslint-disable-next-line camelcase
import resolveOpenAPI2_30Strategy from './strategies/openapi-2--3-0/index.js';
import resolveOpenAPI31Strategy from './strategies/openapi-3-1/index.js';
import { makeFetchJSON } from './utils/index.js';
import * as optionsUtil from './utils/options.js';
import { isOpenAPI31 } from '../helpers/openapi-predicates.js';
import genericStrategy from './strategies/generic/index.js';
import openApi2Strategy from './strategies/openapi-2/index.js';
import openApi30Strategy from './strategies/openapi-3-0/index.js';

const resolve = async (options) => {
const { spec, requestInterceptor, responseInterceptor } = options;
Expand All @@ -14,10 +13,10 @@ const resolve = async (options) => {
spec ||
(await makeFetchJSON(httpClient, { requestInterceptor, responseInterceptor })(retrievalURI));
const strategyOptions = { ...options, spec: retrievedSpec };
const strategies = options.strategies || [openApi30Strategy, openApi2Strategy, genericStrategy];
const strategy = strategies.find((strg) => strg.match(strategyOptions));

return isOpenAPI31(retrievedSpec)
? resolveOpenAPI31Strategy(strategyOptions)
: resolveOpenAPI2_30Strategy(strategyOptions);
return strategy.resolve(strategyOptions);
};

export default resolve;
22 changes: 22 additions & 0 deletions src/resolver/strategies/generic/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import resolveGenericStrategy from './resolve.js';
import normalize from './normalize.js';
import { plugins } from '../../../specmap/index.js';

export function clearCache() {
plugins.refs.clearCache();
}

const genericStrategy = {
name: 'generic',
match() {
return true;
},
normalize({ spec }) {
const { spec: normalized } = normalize({ spec });
return normalized;
},
async resolve(options) {
return resolveGenericStrategy(options);
},
};
export default genericStrategy;
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
import mapSpec, { plugins } from '../../../specmap/index.js';
// eslint-disable-next-line camelcase
import normalize from './normalize.js';
import { makeFetchJSON } from '../../utils/index.js';
import * as optionsUtil from '../../utils/options.js';

// Wipe out the http cache
export function clearCache() {
plugins.refs.clearCache();
}

// eslint-disable-next-line camelcase
export default function resolveOpenAPI2_30Strategy(obj) {
export default async function resolveGenericStrategy(options) {
const {
spec,
mode,
Expand All @@ -22,10 +15,10 @@ export default function resolveOpenAPI2_30Strategy(obj) {
responseInterceptor,
skipNormalization,
useCircularStructures,
} = obj;
} = options;

const retrievalURI = optionsUtil.retrievalURI(obj);
const httpClient = optionsUtil.httpClient(obj);
const retrievalURI = optionsUtil.retrievalURI(options);
const httpClient = optionsUtil.httpClient(options);

return doResolve(spec);

Expand Down
20 changes: 20 additions & 0 deletions src/resolver/strategies/openapi-2/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import resolveOpenAPI2Strategy from './resolve.js';
import normalize from './normalize.js';
import { isOpenAPI2 } from '../../../helpers/openapi-predicates.js';

export { clearCache } from '../generic/index.js';

const openApi2Strategy = {
name: 'openapi-2',
match({ spec }) {
return isOpenAPI2(spec);
},
normalize({ spec }) {
const { spec: normalized } = normalize({ spec });
return normalized;
},
async resolve(options) {
return resolveOpenAPI2Strategy(options);
},
};
export default openApi2Strategy;
2 changes: 2 additions & 0 deletions src/resolver/strategies/openapi-2/normalize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable-next-line no-restricted-exports
export { default } from '../generic/normalize.js';
5 changes: 5 additions & 0 deletions src/resolver/strategies/openapi-2/resolve.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import resolveGenericStrategy from '../generic/resolve.js';

export default async function resolveOpenAPI2Strategy(options) {
return resolveGenericStrategy(options);
}
20 changes: 20 additions & 0 deletions src/resolver/strategies/openapi-3-0/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import resolveOpenAPI30Strategy from './resolve.js';
import normalize from './normalize.js';
import { isOpenAPI30 } from '../../../helpers/openapi-predicates.js';

export { clearCache } from '../generic/index.js';

const openApi30Strategy = {
name: 'openapi-3-0',
match({ spec }) {
return isOpenAPI30(spec);
},
normalize({ spec }) {
const { spec: normalized } = normalize({ spec });
return normalized;
},
async resolve(options) {
return resolveOpenAPI30Strategy(options);
},
};
export default openApi30Strategy;
2 changes: 2 additions & 0 deletions src/resolver/strategies/openapi-3-0/normalize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable-next-line no-restricted-exports
export { default } from '../generic/normalize.js';
5 changes: 5 additions & 0 deletions src/resolver/strategies/openapi-3-0/resolve.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import resolveGenericStrategy from '../generic/resolve.js';

export default async function resolveOpenAPI30Strategy(options) {
return resolveGenericStrategy(options);
}
17 changes: 17 additions & 0 deletions src/resolver/strategies/openapi-3-1-apidom/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import resolveOpenAPI31Strategy from './resolve.js';
import normalize, { pojoAdapter } from './normalize.js';
import { isOpenAPI31 } from '../../../helpers/openapi-predicates.js';

const openApi31ApiDOMStrategy = {
name: 'openapi-3-1-apidom',
match({ spec }) {
return isOpenAPI31(spec);
},
normalize({ spec }) {
return pojoAdapter(normalize)(spec);
},
async resolve(options) {
return resolveOpenAPI31Strategy(options);
},
};
export default openApi31ApiDOMStrategy;
30 changes: 14 additions & 16 deletions src/subtree-resolver/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@
// TODO: move the remarks above into project documentation
import get from 'lodash/get';

import { isOpenAPI31 } from '../helpers/openapi-predicates.js';
import resolve from '../resolver/index.js';
import normalizeOpenAPI2__30 from '../resolver/strategies/openapi-2--3-0/normalize.js'; // eslint-disable-line camelcase
import normalizeOpenAPI31, { pojoAdapter } from '../resolver/strategies/openapi-3-1/normalize.js';
import genericResolverStrategy from '../resolver/strategies/generic/index.js';
import openApi2ResolverStrategy from '../resolver/strategies/openapi-2/index.js';
import openApi30ResolverStrategy from '../resolver/strategies/openapi-3-0/index.js';

export default async function resolveSubtree(obj, path, opts = {}) {
export default async function resolveSubtree(obj, path, options = {}) {
const {
returnEntireTree,
baseDoc,
Expand All @@ -36,27 +36,25 @@ export default async function resolveSubtree(obj, path, opts = {}) {
parameterMacro,
modelPropertyMacro,
useCircularStructures,
} = opts;

} = options;
const strategies = options.strategies || [
openApi30ResolverStrategy,
openApi2ResolverStrategy,
genericResolverStrategy,
];
const resolveOptions = {
spec: obj,
pathDiscriminator: path,
baseDoc,
requestInterceptor,
responseInterceptor,
parameterMacro,
modelPropertyMacro,
useCircularStructures,
strategies,
};

let normalized;
if (isOpenAPI31(obj)) {
normalized = pojoAdapter(normalizeOpenAPI31)(obj);
} else {
({ spec: normalized } = normalizeOpenAPI2__30({
spec: obj,
}));
}

const strategy = strategies.find((strg) => strg.match(resolveOptions));
const normalized = strategy.normalize(resolveOptions);
const result = await resolve({
...resolveOptions,
spec: normalized,
Expand Down
6 changes: 3 additions & 3 deletions test/execute/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import AbortController from 'abort-controller';

import { execute, buildRequest, self as stubs } from '../../src/execute/index.js';
// eslint-disable-next-line camelcase
import normalizeOpenAPI2__30 from '../../src/resolver/strategies/openapi-2--3-0/normalize.js';
import normalize from '../../src/resolver/strategies/generic/normalize.js';

// Supported shape... { spec, operationId, parameters, securities, fetch }
// One can use operationId or pathItem + method
Expand Down Expand Up @@ -2033,7 +2033,7 @@ describe('execute', () => {
},
};

const resultSpec = normalizeOpenAPI2__30(spec);
const resultSpec = normalize(spec);
const warnSpy = jest.spyOn(console, 'warn');
const req = buildRequest({
spec: resultSpec.spec,
Expand Down Expand Up @@ -2087,7 +2087,7 @@ describe('execute', () => {
const oriWarn = global.console.warn;
global.console.warn = jest.fn();

const resultSpec = normalizeOpenAPI2__30(spec);
const resultSpec = normalize(spec);
const req = buildRequest({
spec: resultSpec.spec,
operationId: 'getPetsById',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// eslint-disable-next-line camelcase
import normalize from '../../../../src/resolver/strategies/openapi-2--3-0/normalize.js';
import normalize from '../../../../src/resolver/strategies/openapi-2/normalize.js';

describe('helpers', () => {
describe('normalize', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import path from 'node:path';
import { toValue, StringElement } from '@swagger-api/apidom-core';
import { OpenApi3_1Element } from '@swagger-api/apidom-ns-openapi-3-1';

import normalize from '../../../../../src/resolver/strategies/openapi-3-1/normalize.js';
import normalize from '../../../../../src/resolver/strategies/openapi-3-1-apidom/normalize.js';

const fixturesPath = path.join(__dirname, '__fixtures__');

Expand Down