Skip to content

Commit

Permalink
feat(reference): apply dereferencing architecture 2.0 to OpenAPI 3.0.x (
Browse files Browse the repository at this point in the history
#3917)

Refs #3916
  • Loading branch information
char0n committed Mar 13, 2024
1 parent 5963c3b commit cc3a970
Show file tree
Hide file tree
Showing 11 changed files with 632 additions and 233 deletions.
8 changes: 7 additions & 1 deletion packages/apidom-reference/src/dereference/index.ts
Expand Up @@ -79,7 +79,13 @@ const dereference = async (
parseResult = await parse(uri, options);
}

const mergedOptions = mergeOptions(options, { resolve: { baseURI: sanitizedURI } });
const mergedOptions = mergeOptions(options, {
resolve: { baseURI: sanitizedURI },
dereference: {
// if refSet was not provided, then we can work in mutable mode
immutable: options.dereference.immutable && refSet !== null,
},
});

return dereferenceApiDOM(parseResult, mergedOptions);
};
Expand Down
@@ -1,6 +1,5 @@
import stampit from 'stampit';
import { defaultTo, propEq } from 'ramda';
import { createNamespace, visit, Element } from '@swagger-api/apidom-core';
import { Element, createNamespace, visit, cloneDeep } from '@swagger-api/apidom-core';
import openApi3_0Namespace, {
getNodeType,
isOpenApi3_0Element,
Expand Down Expand Up @@ -41,15 +40,40 @@ const OpenApi3_0DereferenceStrategy: stampit.Stamp<IDereferenceStrategy> = stamp

async dereference(file: IFile, options: IReferenceOptions): Promise<Element> {
const namespace = createNamespace(openApi3_0Namespace);
const refSet = defaultTo(ReferenceSet(), options.dereference.refSet);
const refSet = options.dereference.refSet ?? ReferenceSet();
let reference;

if (!refSet.has(file.uri)) {
reference = Reference({ uri: file.uri, value: file.parseResult });
refSet.add(reference);
} else {
// pre-computed refSet was provided as configuration option
reference = refSet.find(propEq(file.uri, 'uri'));
reference = refSet.find((ref) => ref.uri === file.uri);
}

/**
* Clone refSet due the dereferencing process being mutable.
* We don't want to mutate the original refSet and the references.
*/
if (options.dereference.immutable) {
const immutableRefs = refSet.refs.map((ref) =>
Reference({
...ref,
uri: `immutable://${ref.uri}`,
}),
);
const mutableRefs = refSet.refs.map((ref) =>
Reference({
...ref,
value: cloneDeep(ref.value),
}),
);

refSet.clean();
mutableRefs.forEach((ref) => refSet.add(ref));
immutableRefs.forEach((ref) => refSet.add(ref));

reference = refSet.find((ref) => ref.uri === file.uri);
}

const visitor = OpenApi3_0DereferenceVisitor({ reference, namespace, options });
Expand All @@ -59,13 +83,30 @@ const OpenApi3_0DereferenceStrategy: stampit.Stamp<IDereferenceStrategy> = stamp
});

/**
* Release all memory if this refSet was not provided as an configuration option.
* Release all memory if this refSet was not provided as a configuration option.
* If provided as configuration option, then provider is responsible for cleanup.
*/
if (options.dereference.refSet === null) {
refSet.clean();
}

/**
* If immutable option is set, then we need to remove mutable refs from the refSet.
*/
if (options.dereference.immutable) {
const immutableRefs = refSet.refs
.filter((ref) => ref.uri.startsWith('immutable://'))
.map((ref) =>
Reference({
...ref,
uri: ref.uri.replace(/^immutable:\/\//, ''),
}),
);

refSet.clean();
immutableRefs.forEach((ref) => refSet.add(ref));
}

return dereferencedElement;
},
},
Expand Down

0 comments on commit cc3a970

Please sign in to comment.