Skip to content

Commit

Permalink
fix(resolver): don't skip normalization of OpenAPI 3.1.0 specs (#3575)
Browse files Browse the repository at this point in the history
Refs #1396

Co-authored-by: Vladimir Gorej <[email protected]>
  • Loading branch information
glowcloud and char0n authored Jul 15, 2024
1 parent f471e6c commit bc4a40c
Show file tree
Hide file tree
Showing 14 changed files with 63 additions and 64 deletions.
10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,11 @@
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime-corejs3": "^7.22.15",
"@swagger-api/apidom-core": ">=1.0.0-alpha.5 <1.0.0-beta.0",
"@swagger-api/apidom-error": ">=1.0.0-alpha.5 <1.0.0-beta.0",
"@swagger-api/apidom-json-pointer": ">=1.0.0-alpha.5 <1.0.0-beta.0",
"@swagger-api/apidom-ns-openapi-3-1": ">=1.0.0-alpha.5 <1.0.0-beta.0",
"@swagger-api/apidom-reference": ">=1.0.0-alpha.5 <1.0.0-beta.0",
"@swagger-api/apidom-core": ">=1.0.0-alpha.6 <1.0.0-beta.0",
"@swagger-api/apidom-error": ">=1.0.0-alpha.6 <1.0.0-beta.0",
"@swagger-api/apidom-json-pointer": ">=1.0.0-alpha.6 <1.0.0-beta.0",
"@swagger-api/apidom-ns-openapi-3-1": ">=1.0.0-alpha.6 <1.0.0-beta.0",
"@swagger-api/apidom-reference": ">=1.0.0-alpha.6 <1.0.0-beta.0",
"cookie": "~0.6.0",
"deepmerge": "~4.3.0",
"fast-json-patch": "^3.0.0-1",
Expand Down
2 changes: 1 addition & 1 deletion src/resolver/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const resolve = async (options) => {
spec ||
(await makeFetchJSON(httpClient, { requestInterceptor, responseInterceptor })(retrievalURI));
const strategyOptions = { ...options, spec: retrievedSpec };
const strategy = options.strategies.find((strg) => strg.match(strategyOptions));
const strategy = options.strategies.find((strg) => strg.match(retrievedSpec));

return strategy.resolve(strategyOptions);
};
Expand Down
2 changes: 1 addition & 1 deletion src/resolver/strategies/generic/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const genericStrategy = {
match() {
return true;
},
normalize({ spec }) {
normalize(spec) {
const { spec: normalized } = normalize({ spec });
return normalized;
},
Expand Down
18 changes: 12 additions & 6 deletions src/resolver/strategies/generic/resolve.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import mapSpec, { plugins } from '../../specmap/index.js';
import normalize from './normalize.js';
import { makeFetchJSON } from '../../utils/index.js';
import * as optionsUtil from '../../utils/options.js';

Expand All @@ -13,16 +12,18 @@ export default async function resolveGenericStrategy(options) {
parameterMacro,
requestInterceptor,
responseInterceptor,
skipNormalization,
skipNormalization = false,
useCircularStructures,
strategies,
} = options;

const retrievalURI = optionsUtil.retrievalURI(options);
const httpClient = optionsUtil.httpClient(options);
const strategy = strategies.find((strg) => strg.match(spec));

return doResolve(spec);

function doResolve(_spec) {
async function doResolve(_spec) {
if (retrievalURI) {
plugins.refs.docCache[retrievalURI] = _spec;
}
Expand All @@ -45,7 +46,7 @@ export default async function resolveGenericStrategy(options) {
}

// mapSpec is where the hard work happens
return mapSpec({
const result = await mapSpec({
spec: _spec,
context: { baseDoc: retrievalURI },
plugins: plugs,
Expand All @@ -54,7 +55,12 @@ export default async function resolveGenericStrategy(options) {
parameterMacro,
modelPropertyMacro,
useCircularStructures,
// eslint-disable-next-line camelcase
}).then(skipNormalization ? async (a) => a : normalize);
});

if (!skipNormalization) {
result.spec = strategy.normalize(result.spec);
}

return result;
}
}
4 changes: 2 additions & 2 deletions src/resolver/strategies/openapi-2/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ export { clearCache } from '../generic/index.js';

const openApi2Strategy = {
name: 'openapi-2',
match({ spec }) {
match(spec) {
return isOpenAPI2(spec);
},
normalize({ spec }) {
normalize(spec) {
const { spec: normalized } = normalize({ spec });
return normalized;
},
Expand Down
4 changes: 2 additions & 2 deletions src/resolver/strategies/openapi-3-0/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ export { clearCache } from '../generic/index.js';

const openApi30Strategy = {
name: 'openapi-3-0',
match({ spec }) {
match(spec) {
return isOpenAPI30(spec);
},
normalize({ spec }) {
normalize(spec) {
const { spec: normalized } = normalize({ spec });
return normalized;
},
Expand Down
20 changes: 17 additions & 3 deletions src/resolver/strategies/openapi-3-1-apidom/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
import { isPlainObject } from 'ramda-adjunct';
import { isElement } from '@swagger-api/apidom-core';

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 }) {
match(spec) {
return isOpenAPI31(spec);
},
normalize({ spec }) {
return pojoAdapter(normalize)(spec);
normalize(spec) {
// pre-normalization - happens only once before the first lazy dereferencing and in JavaScript context
if (!isElement(spec) && isPlainObject(spec) && !spec.$$normalized) {
const preNormalized = pojoAdapter(normalize)(spec);
preNormalized.$$normalized = true;
return preNormalized;
}
// post-normalization - happens after each dereferencing and in ApiDOM context
if (isElement(spec)) {
return normalize(spec);
}

return spec;
},
async resolve(options) {
return resolveOpenAPI31Strategy(options);
Expand Down
17 changes: 9 additions & 8 deletions src/resolver/strategies/openapi-3-1-apidom/normalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import {
} from '@swagger-api/apidom-ns-openapi-3-1';

import opId from '../../../helpers/op-id.js';
import resolveOpenAPI31Strategy from './resolve.js';

const normalize = (element) => {
if (!isObjectElement(element)) return element;
if (element.hasKey('$$normalized')) return element;

const plugins = [
refractorPluginNormalizeOperationIds({
Expand All @@ -36,7 +36,6 @@ const normalize = (element) => {
visitorOptions: { keyMap, nodeTypeGetter: getNodeType },
});

normalized.set('$$normalized', true);
return normalized;
};

Expand All @@ -46,18 +45,20 @@ const normalize = (element) => {
* Plain Old JavaScript Objects and returns Plain Old JavaScript Objects.
*/
export const pojoAdapter = (normalizeFn) => (spec) => {
if (spec?.$$normalized) return spec;
if (pojoAdapter.cache.has(spec)) return pojoAdapter.cache.get(spec);

const openApiElement = OpenApi3_1Element.refract(spec);
openApiElement.classes.push('result');

const normalized = normalizeFn(openApiElement);
const value = toValue(normalized);

pojoAdapter.cache.set(spec, value);
/**
* We're setting the cache here to avoid repeated refracting
* in `openapi-3-1-apidom` strategy resolve method.
*/
resolveOpenAPI31Strategy.cache.set(value, normalized);

return value;
return toValue(normalized);
};
pojoAdapter.cache = new WeakMap();

export default normalize;
/* eslint-enable camelcase */
5 changes: 3 additions & 2 deletions src/resolver/strategies/openapi-3-1-apidom/resolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import OpenAPI3_1ResolveStrategy from '@swagger-api/apidom-reference/resolve/str

import { DEFAULT_BASE_URL } from '../../../constants.js';
import * as optionsUtil from '../../utils/options.js';
import normalize from './normalize.js';
import HTTPResolverSwaggerClient from '../../apidom/reference/resolve/resolvers/http-swagger-client/index.js';
import JSONParser from '../../apidom/reference/parse/parsers/json/index.js';
import YAMLParser from '../../apidom/reference/parse/parsers/yaml-1-2/index.js';
Expand Down Expand Up @@ -62,9 +61,11 @@ const resolveOpenAPI31Strategy = async (options) => {
parameterMacro = null,
modelPropertyMacro = null,
mode = 'non-strict',
strategies,
} = options;
try {
const { cache } = resolveOpenAPI31Strategy;
const strategy = strategies.find((strg) => strg.match(spec));

// determining BaseURI
const cwd = url.isHttpUrl(url.cwd()) ? url.cwd() : DEFAULT_BASE_URL;
Expand Down Expand Up @@ -155,7 +156,7 @@ const resolveOpenAPI31Strategy = async (options) => {
},
});
const transcluded = transclude(fragmentElement, dereferenced, openApiElement);
const normalized = skipNormalization ? transcluded : normalize(transcluded);
const normalized = skipNormalization ? transcluded : strategy.normalize(transcluded);

return { spec: toValue(normalized), errors };
} catch (error) {
Expand Down
10 changes: 6 additions & 4 deletions src/subtree-resolver/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import resolve from '../resolver/index.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';
import { isOpenAPI31 } from '../helpers/openapi-predicates.js';

const resolveSubtree = async (obj, path, options = {}) => {
const {
Expand All @@ -47,13 +48,14 @@ const resolveSubtree = async (obj, path, options = {}) => {
useCircularStructures,
strategies,
};
const strategy = strategies.find((strg) => strg.match(resolveOptions));
const normalized = strategy.normalize(resolveOptions);
const strategy = strategies.find((strg) => strg.match(obj));
const normalized = strategy.normalize(obj);

const result = await resolve({
...resolveOptions,
spec: normalized,
...resolveOptions,
allowMetaPatches: true,
skipNormalization: true,
skipNormalization: !isOpenAPI31(obj),
});

if (!returnEntireTree && Array.isArray(path) && path.length) {
Expand Down
Loading

0 comments on commit bc4a40c

Please sign in to comment.