Skip to content

Commit f9d460b

Browse files
committed
feat: add PoC of handling discriminator for allOf case in OpenAPI 3.1
1 parent 8c6e031 commit f9d460b

File tree

8 files changed

+1363
-12
lines changed

8 files changed

+1363
-12
lines changed

packages/apidom-ns-openapi-3-1/src/refractor/plugins/normalize-discriminator-mapping.ts

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import {
2-
cloneDeep,
2+
ArrayElement,
3+
cloneShallow,
34
Element,
45
isArrayElement,
6+
ObjectElement,
57
StringElement,
68
toValue,
79
} from '@swagger-api/apidom-core';
@@ -41,12 +43,15 @@ const plugin =
4143
(toolbox: Toolbox) => {
4244
const { ancestorLineageToJSONPointer } = toolbox;
4345
let storage: NormalizeStorage | undefined;
46+
let allOfDiscriminatorMapping: ObjectElement;
4447

4548
return {
4649
visitor: {
4750
OpenApi3_1Element: {
4851
enter(element: OpenApi3_1Element) {
4952
storage = new NormalizeStorage(element, storageField, 'discriminator-mapping');
53+
allOfDiscriminatorMapping =
54+
element.getMetaProperty('allOfDiscriminatorMapping') ?? new ObjectElement();
5055
},
5156
leave() {
5257
storage = undefined;
@@ -82,19 +87,33 @@ const plugin =
8287
return;
8388
}
8489

85-
// skip if neither oneOf nor anyOf is present
86-
if (!isArrayElement(schemaElement.oneOf) && !isArrayElement(schemaElement.anyOf)) {
90+
const parentElement = ancestors[ancestors.length - 1];
91+
const schemaName = schemaElement.getMetaProperty('schemaName');
92+
const allOfMapping = allOfDiscriminatorMapping.getMember(toValue(schemaName));
93+
const hasAllOfMapping =
94+
// @ts-ignore
95+
allOfMapping && !parentElement?.classes?.contains('json-schema-allOf');
96+
97+
// skip if neither oneOf, anyOf nor allOf is present
98+
if (
99+
!isArrayElement(schemaElement.oneOf) &&
100+
!isArrayElement(schemaElement.anyOf) &&
101+
!hasAllOfMapping
102+
) {
87103
return;
88104
}
89105

90106
const mapping =
91107
schemaElement.discriminator.get('mapping') ?? new DiscriminatorMappingElement();
92-
const normalizedMapping: DiscriminatorMappingElement = cloneDeep(mapping);
108+
const normalizedMapping: DiscriminatorMappingElement =
109+
new DiscriminatorMappingElement();
93110
let isNormalized = true;
94111

95112
const items = isArrayElement(schemaElement.oneOf)
96113
? schemaElement.oneOf
97-
: schemaElement.anyOf;
114+
: isArrayElement(schemaElement.anyOf)
115+
? schemaElement.anyOf
116+
: (allOfMapping.value as ArrayElement);
98117

99118
items!.forEach((item) => {
100119
if (!isSchemaElement(item)) {
@@ -114,7 +133,10 @@ const plugin =
114133
* handle external references and internal references
115134
* that don't point to components/schemas/<SchemaName>
116135
*/
117-
if (metaRefOrigin !== baseURI || (!metaSchemaName && metaRefFields)) {
136+
if (
137+
!hasAllOfMapping &&
138+
(metaRefOrigin !== baseURI || (!metaSchemaName && metaRefFields))
139+
) {
118140
let hasMatchingMapping = false;
119141

120142
mapping.forEach((mappingValue: StringElement, mappingKey: StringElement) => {
@@ -124,7 +146,7 @@ const plugin =
124146
?.get('$refBaseURI');
125147

126148
if (mappingValueSchemaRefBaseURI?.equals(metaRefFields?.$refBaseURI)) {
127-
normalizedMapping.set(toValue(mappingKey), cloneDeep(item));
149+
normalizedMapping.set(toValue(mappingKey), cloneShallow(item));
128150
hasMatchingMapping = true;
129151
}
130152
});
@@ -148,25 +170,29 @@ const plugin =
148170

149171
if (
150172
mappingValueSchemaName?.equals(metaSchemaName) &&
151-
mappingValueSchemaRefBaseURI?.equals(metaRefFields?.$refBaseURI)
173+
(!hasAllOfMapping ||
174+
mappingValueSchemaRefBaseURI?.equals(metaRefFields?.$refBaseURI))
152175
) {
153-
normalizedMapping.set(toValue(mappingKey), cloneDeep(item));
176+
normalizedMapping.set(toValue(mappingKey), cloneShallow(item));
154177
hasMatchingMapping = true;
155178
}
156179
});
157180

158181
// add a new mapping if no matching mapping was found
159182
if (!hasMatchingMapping) {
160-
normalizedMapping.set(metaSchemaName, cloneDeep(item));
183+
normalizedMapping.set(metaSchemaName, cloneShallow(item));
161184
}
162185
}
163186
});
164187

165-
// check if any mapping is not a Schema Object
188+
// check if any mapping is not a Schema Object or if any mapping was not normalized
189+
const mappingKeys = mapping.keys();
190+
const normalizedMappingKeys = normalizedMapping.keys();
166191
isNormalized =
167192
isNormalized &&
168193
normalizedMapping.filter((mappingValue: Element) => !isSchemaElement(mappingValue))
169-
.length === 0;
194+
.length === 0 &&
195+
mappingKeys.every((mappingKey: string) => normalizedMappingKeys.includes(mappingKey));
170196

171197
if (isNormalized) {
172198
schemaElement.discriminator.set('x-normalized-mapping', normalizedMapping);

0 commit comments

Comments
 (0)