Skip to content

Commit

Permalink
feat(ns-openapi-3-1): add idempotence to parameter examples refractor…
Browse files Browse the repository at this point in the history
… plugin (#4142)

Refs #4134
  • Loading branch information
glowcloud authored May 27, 2024
1 parent 524cce2 commit 7cee6e9
Show file tree
Hide file tree
Showing 7 changed files with 247 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ const plugin =

// skip visiting this Header Object if it's already normalized
if (storage!.includes(headerJSONPointer)) {
console.dir('idempotent');
return;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { cloneDeep } from '@swagger-api/apidom-core';
import { Element, cloneDeep } from '@swagger-api/apidom-core';

import ParameterElement from '../../elements/Parameter';
import ExampleElement from '../../elements/Example';
import { Predicates } from '../toolbox';
import type { Toolbox } from '../toolbox';
import OpenApi3_1Element from '../../elements/OpenApi3-1';
import NormalizeStorage from './normalize-header-examples/NormalizeStorage';

/**
* Override of Schema.example and Schema.examples field inside the Parameter Objects.
Expand All @@ -15,20 +17,37 @@ import { Predicates } from '../toolbox';
*
* The example value SHALL override the example provided by the schema.
* Furthermore, if referencing a schema that contains an example, the examples value SHALL override the example provided by the schema.
*
* NOTE: this plugin is idempotent
*/
/* eslint-disable no-param-reassign */

interface PluginOptions {
storageField?: string;
}

const plugin =
() =>
({ predicates }: { predicates: Predicates }) => {
({ storageField = 'x-normalized' }: PluginOptions = {}) =>
(toolbox: Toolbox) => {
const { predicates, ancestorLineageToJSONPointer } = toolbox;
let storage: NormalizeStorage | undefined;

return {
visitor: {
OpenApi3_1Element: {
enter(element: OpenApi3_1Element) {
storage = new NormalizeStorage(element, storageField, 'parameter-examples');
},
leave() {
storage = undefined;
},
},
ParameterElement: {
leave(
parameterElement: ParameterElement,
key: any,
parent: any,
path: any,
ancestors: any[],
key: string | number,
parent: Element | undefined,
path: (string | number)[],
ancestors: [Element | Element[]],
) {
// skip visiting this Parameter Object
if (ancestors.some(predicates.isComponentsElement)) {
Expand All @@ -50,6 +69,17 @@ const plugin =
return;
}

const parameterJSONPointer = ancestorLineageToJSONPointer([
...ancestors,
parent!,
parameterElement,
]);

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

/**
* Parameter.examples and Schema.examples have preferences over the older
* and deprected `example` field.
Expand All @@ -65,9 +95,11 @@ const plugin =

if (typeof parameterElement.schema.examples !== 'undefined') {
parameterElement.schema.set('examples', examples);
storage!.append(parameterJSONPointer);
}
if (typeof parameterElement.schema.example !== 'undefined') {
parameterElement.schema.set('example', examples);
storage!.append(parameterJSONPointer);
}
return;
}
Expand All @@ -78,16 +110,17 @@ const plugin =
if (typeof parameterElement.example !== 'undefined') {
if (typeof parameterElement.schema.examples !== 'undefined') {
parameterElement.schema.set('examples', [cloneDeep(parameterElement.example)]);
storage!.append(parameterJSONPointer);
}
if (typeof parameterElement.schema.example !== 'undefined') {
parameterElement.schema.set('example', cloneDeep(parameterElement.example));
storage!.append(parameterJSONPointer);
}
}
},
},
},
};
};
/* eslint-enable */

export default plugin;
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe('refractor', function () {
});

context('given custom storage field', function () {
specify('should use custom sub-field to store normalized scopes', async function () {
specify('should use custom storage field to store normalized scopes', async function () {
const yamlDefinition = dedent`
openapi: 3.1.0
paths:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`refractor plugins normalize-parameter-examples should have idempotent characteristics 1`] = `
Object {
openapi: 3.1.0,
paths: Object {
/: Object {
get: Object {
parameters: Array [
Object {
examples: Object {
example1: Object {
value: 2,
},
},
in: query,
name: idempotent,
schema: Object {
example: 1,
type: number,
},
},
],
},
},
},
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
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,
refractorPluginNormalizeParameterExamples,
keyMap,
getNodeType,
} from '../../../../src';

describe('refractor', function () {
context('plugins', function () {
context('normalize-parameter-examples', function () {
specify('should have idempotent characteristics', async function () {
const yamlDefinition = dedent`
openapi: 3.1.0
paths:
/:
get:
parameters:
- in: query
name: idempotent
schema:
type: number
example: 1
examples:
example1:
value: 2
`;
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,
[refractorPluginNormalizeParameterExamples()],
options,
);
dispatchRefractorPlugins(
openApiElement,
[refractorPluginNormalizeParameterExamples()],
options,
);
dispatchRefractorPlugins(
openApiElement,
[refractorPluginNormalizeParameterExamples()],
options,
);

expect(toValue(apiDOM.result)).toMatchSnapshot();
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ Object {
],
},
},
x-normalized: Object {
parameter-examples: Array [
/paths/~1/parameters/0,
],
},
}
`;

Expand Down Expand Up @@ -56,6 +61,11 @@ Object {
],
},
},
x-normalized: Object {
parameter-examples: Array [
/paths/~1/parameters/0,
],
},
}
`;

Expand Down Expand Up @@ -84,6 +94,11 @@ Object {
],
},
},
x-normalized: Object {
parameter-examples: Array [
/paths/~1/parameters/0,
],
},
}
`;

Expand All @@ -108,6 +123,11 @@ Object {
],
},
},
x-normalized: Object {
parameter-examples: Array [
/paths/~1/parameters/0,
],
},
}
`;

Expand All @@ -129,6 +149,11 @@ Object {
],
},
},
x-normalized: Object {
parameter-examples: Array [
/paths/~1/parameters/0,
],
},
}
`;

Expand All @@ -152,6 +177,11 @@ Object {
],
},
},
x-normalized: Object {
parameter-examples: Array [
/paths/~1/parameters/0,
],
},
}
`;

Expand Down Expand Up @@ -182,6 +212,11 @@ Object {
],
},
},
x-normalized: Object {
parameter-examples: Array [
/paths/~1/parameters/0,
],
},
}
`;

Expand Down Expand Up @@ -209,6 +244,11 @@ Object {
],
},
},
x-normalized: Object {
parameter-examples: Array [
/paths/~1/parameters/0,
],
},
}
`;

Expand Down Expand Up @@ -236,5 +276,10 @@ Object {
],
},
},
x-normalized: Object {
parameter-examples: Array [
/paths/~1/parameters/0,
],
},
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { assert } from 'chai';
import dedent from 'dedent';
import { toValue } from '@swagger-api/apidom-core';
import { parse } from '@swagger-api/apidom-parser-adapter-yaml-1-2';

import { OpenApi3_1Element, refractorPluginNormalizeParameterExamples } from '../../../../src';

describe('refractor', function () {
context('plugins', function () {
context('normalize-parameter-examples', function () {
specify('should use sub-field to store normalized scopes', async function () {
const yamlDefinition = dedent`
openapi: 3.1.0
paths:
/:
get:
parameters:
- in: query
name: idempotent
schema:
type: number
example: 1
examples:
example1:
value: 2
`;
const apiDOM = await parse(yamlDefinition);
const openApiElement = OpenApi3_1Element.refract(apiDOM.result, {
plugins: [refractorPluginNormalizeParameterExamples()],
}) as OpenApi3_1Element;

assert.deepEqual(toValue(openApiElement.get('x-normalized')), {
'parameter-examples': ['/paths/~1/get/parameters/0'],
});
});

context('given custom storage field', function () {
specify('should use custom storage field to store normalized scopes', async function () {
const yamlDefinition = dedent`
openapi: 3.1.0
paths:
/:
get:
parameters:
- in: query
name: idempotent
schema:
type: number
example: 1
examples:
example1:
value: 2
`;
const apiDOM = await parse(yamlDefinition);
const openApiElement = OpenApi3_1Element.refract(apiDOM.result, {
plugins: [
refractorPluginNormalizeParameterExamples({
storageField: '$$normalized',
}),
],
}) as OpenApi3_1Element;

assert.deepEqual(toValue(openApiElement.get('$$normalized')), {
'parameter-examples': ['/paths/~1/get/parameters/0'],
});
});
});
});
});
});

0 comments on commit 7cee6e9

Please sign in to comment.