Skip to content

Commit

Permalink
feat(ns-openapi-3-1): make parameters plugin idempotent (#4150)
Browse files Browse the repository at this point in the history
Refs #4134
  • Loading branch information
glowcloud authored May 28, 2024
1 parent e28f053 commit 7fdf6b5
Show file tree
Hide file tree
Showing 7 changed files with 406 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { uniqWith, pathOr, last } from 'ramda';
import { StringElement, toValue } from '@swagger-api/apidom-core';
import { Element, StringElement, toValue } from '@swagger-api/apidom-core';
import { OperationParametersElement } from '@swagger-api/apidom-ns-openapi-3-0';

import ParameterElement from '../../elements/Parameter';
import PathItemElement from '../../elements/PathItem';
import OperationElement from '../../elements/Operation';
import { Predicates } from '../toolbox';
import type { Toolbox } from '../toolbox';
import OpenApi3_1Element from '../../elements/OpenApi3-1';
import NormalizeStorage from './normalize-header-examples/NormalizeStorage';

/**
* Inheritance of Parameter Objects.
Expand All @@ -15,11 +17,19 @@ import { Predicates } from '../toolbox';
* A list of parameters that are applicable for this operation. If a parameter is already defined at the Path Item,
* the new definition will override it but can never remove it. The list MUST NOT include duplicated parameters.
* A unique parameter is defined by a combination of a name and location.
*
* NOTE: this plugin is idempotent
*/

interface PluginOptions {
storageField?: string;
}

/* eslint-disable no-param-reassign */
const plugin =
() =>
({ predicates }: { predicates: Predicates }) => {
({ storageField = 'x-normalized' }: PluginOptions = {}) =>
(toolbox: Toolbox) => {
const { predicates, ancestorLineageToJSONPointer } = toolbox;
/**
* Establishes identity between two Parameter Objects.
*
Expand All @@ -40,16 +50,25 @@ const plugin =
};

const pathItemParameters: ParameterElement[][] = [];
let storage: NormalizeStorage | undefined;

return {
visitor: {
OpenApi3_1Element: {
enter(element: OpenApi3_1Element) {
storage = new NormalizeStorage(element, storageField, 'parameters');
},
leave() {
storage = undefined;
},
},
PathItemElement: {
enter(
pathItemElement: PathItemElement,
key: any,
parent: any,
path: any,
ancestors: any[],
key: string | number,
parent: Element | undefined,
path: (string | number)[],
ancestors: [Element | Element[]],
) {
// skip visiting this Path Item
if (ancestors.some(predicates.isComponentsElement)) {
Expand All @@ -69,14 +88,31 @@ const plugin =
},
},
OperationElement: {
leave(operationElement: OperationElement) {
leave(
operationElement: OperationElement,
key: string | number,
parent: Element | undefined,
path: (string | number)[],
ancestors: [Element | Element[]],
) {
const parentPathItemParameters = last(pathItemParameters);

// no Path Item Object parameters to inherit from
if (!Array.isArray(parentPathItemParameters) || parentPathItemParameters.length === 0) {
return;
}

const operationJSONPointer = ancestorLineageToJSONPointer([
...ancestors,
parent!,
operationElement,
]);

// skip visiting this Operation Object if it's already normalized
if (storage!.includes(operationJSONPointer)) {
return;
}

const operationParameters = pathOr(
[],
['parameters', 'content'],
Expand All @@ -90,6 +126,7 @@ const plugin =
]);

operationElement.parameters = new OperationParametersElement(mergedParameters);
storage!.append(operationJSONPointer);
},
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`refractor plugins normalize-parameters should have idempotent characteristics 1`] = `
Object {
openapi: 3.1.0,
paths: Object {
/: Object {
get: Object {
parameters: Array [
Object {
in: query,
name: param3,
},
],
},
parameters: Array [
Object {
in: query,
name: param1,
},
Object {
in: query,
name: param2,
},
],
},
},
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,15 @@ exports[`refractor plugins normalize-parameters given parameters are defined in
(StringElement))
(MemberElement
(StringElement)
(StringElement))))))))))))
(StringElement)))))))))))
(MemberElement
(StringElement)
(ObjectElement
(MemberElement
(StringElement)
(ArrayElement
(StringElement)
(StringElement))))))
`;

exports[`refractor plugins normalize-parameters given parameters are defined in Path Item Object and Operation Object defines identical parameter should replace parameter from closes Path Item 1`] = `
Expand Down Expand Up @@ -983,6 +991,42 @@ exports[`refractor plugins normalize-parameters given parameters are defined in
]
}
}
},
{
"element": "member",
"content": {
"key": {
"element": "string",
"content": "x-normalized"
},
"value": {
"element": "object",
"content": [
{
"element": "member",
"content": {
"key": {
"element": "string",
"content": "parameters"
},
"value": {
"element": "array",
"content": [
{
"element": "string",
"content": "/paths/~1/get/callbacks/myCallback/%7B%24url%7D/get"
},
{
"element": "string",
"content": "/paths/~1/get"
}
]
}
}
}
]
}
}
}
]
}
Expand Down Expand Up @@ -1067,7 +1111,15 @@ exports[`refractor plugins normalize-parameters given parameters are defined in
(StringElement))
(MemberElement
(StringElement)
(StringElement))))))))))))
(StringElement)))))))))))
(MemberElement
(StringElement)
(ObjectElement
(MemberElement
(StringElement)
(ArrayElement
(StringElement)
(StringElement))))))
`;

exports[`refractor plugins normalize-parameters given parameters are defined in Path Item Object and Operation Object doesn't defines empty parameters should inherit all parameters from closest Path Item 1`] = `
Expand Down Expand Up @@ -1149,5 +1201,13 @@ exports[`refractor plugins normalize-parameters given parameters are defined in
(StringElement))
(MemberElement
(StringElement)
(StringElement))))))))))))
(StringElement)))))))))))
(MemberElement
(StringElement)
(ObjectElement
(MemberElement
(StringElement)
(ArrayElement
(StringElement)
(StringElement))))))
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { expect } from 'chai';
import dedent from 'dedent';
import { toValue, dispatchRefractorPlugins } from '@swagger-api/apidom-core';
import { parse } from '@swagger-api/apidom-parser-adapter-yaml-1-2';

import {
createToolbox,
OpenApi3_1Element,
refractorPluginNormalizeParameters,
keyMap,
getNodeType,
} from '../../../../src';

describe('refractor', function () {
context('plugins', function () {
context('normalize-parameters', function () {
specify('should have idempotent characteristics', async function () {
const yamlDefinition = dedent`
openapi: 3.1.0
paths:
/:
parameters:
- name: param1
in: query
- name: param2
in: query
get:
parameters:
- name: param3
in: query
`;
const apiDOM = await parse(yamlDefinition);
const openApiElement = OpenApi3_1Element.refract(apiDOM.result) as OpenApi3_1Element;
const options = {
toolboxCreator: createToolbox,
visitorOptions: { keyMap, nodeTypeGetter: getNodeType },
};

dispatchRefractorPlugins(openApiElement, [refractorPluginNormalizeParameters()], options);
dispatchRefractorPlugins(openApiElement, [refractorPluginNormalizeParameters()], options);
dispatchRefractorPlugins(openApiElement, [refractorPluginNormalizeParameters()], options);

expect(toValue(apiDOM.result)).toMatchSnapshot();
});
});
});
});
Loading

0 comments on commit 7fdf6b5

Please sign in to comment.