in packages/extensions/core/src/lib/plugins/profile-filter.ts [115:248]
async init() {
const currentDoc = await this.inputs[0].ReadObject<AnyObject>();
this.components = currentDoc["components"];
if (this.profilesToUse.length > 0) {
const resourcesTargets: Array<ResourceData> = [];
const operationTargets: Array<OperationData> = [];
for (const { key: profileName, value: profile } of visit(this.profiles)) {
if (this.profilesToUse.includes(profileName)) {
// get resources targets
for (const { key: namespace, value: namespaceValue } of visit(profile.resources)) {
for (const { key: version, value: resourceTypes } of visit(namespaceValue)) {
if (resourceTypes.length === 0) {
resourcesTargets.push({ apiVersion: version, profile: profileName, matches: [namespace] });
} else {
for (const resourceType of resourceTypes) {
resourcesTargets.push({
apiVersion: version,
profile: profileName,
matches: [namespace, ...resourceType.split("/")],
});
}
}
}
}
// get operations targets
for (const { key: path, value: apiVersion } of visit(profile.operations)) {
operationTargets.push({ apiVersion, profile: profileName, path });
}
}
}
for (const target of resourcesTargets) {
this.maxApiVersion = maximum([target.apiVersion, this.maxApiVersion]);
this.profilesApiVersions.push(target.apiVersion);
const apiVersion = target.apiVersion;
const profile = target.profile;
const weight = target.matches.length;
const pathRegex = this.getPathRegex(target.matches);
this.filterTargets.push({ apiVersion, profile, pathRegex, weight });
}
for (const target of operationTargets) {
const apiVersion = target.apiVersion;
const profile = target.profile;
const pathRegex = new RegExp(`^${target.path.replace(/[\[\$\.\?\(\)]/g, "\\$&")}$`, "gi");
this.filterTargets.push({ apiVersion, profile, pathRegex, weight: 0 });
}
} else if (this.apiVersions.length > 0) {
this.maxApiVersion = maximum([this.maxApiVersion, maximum(this.apiVersions)]);
}
// visit schemas and extract polymorphic references.
// Since the input is a tree-shaken document, anyOf, allOf, oneOf and not
// should be superficial fields in the schema (i.e. not nested)
if (this.components && this.components.schemas) {
for (const { value: schemaValue, key: schemaKey } of visit(this.components.schemas)) {
for (const { value: fieldValue, key: fieldName } of visit(schemaValue)) {
switch (fieldName) {
case "anyOf":
case "allOf":
case "oneOf":
for (const { value } of visit(fieldValue)) {
if (value.$ref) {
const schemaUid = value.$ref.split("/")[value.$ref.split("/").length - 1];
if (this.polymorphicReferences[schemaUid] === undefined) {
this.polymorphicReferences[schemaUid] = new Set<string>();
}
this.polymorphicReferences[schemaUid].add(schemaKey);
}
}
break;
case "not":
if (fieldValue.$ref) {
const schemaUid = fieldValue.$ref.split("/")[fieldValue.$ref.split("/").length - 1];
if (this.polymorphicReferences[schemaUid] === undefined) {
this.polymorphicReferences[schemaUid] = new Set<string>();
}
this.polymorphicReferences[schemaUid].add(schemaKey);
}
break;
default:
// nothing to do
break;
}
}
}
}
// crawl paths and keep everything referenced by them.
const paths = this.newObject(this.generated, "paths", "/paths");
this.visitPaths(paths, visit(currentDoc["paths"]));
// visit schemas that were marked to be kept
if (this.components && this.components.schemas) {
// create queue of stuff to check
const polyReferencedSchemasToCheck = new Array<string>();
const polyReferencedSchemasChecked = new Set<string>();
const prevSchemasToKeep = new Set<string>();
for (const schemaUid of this.componentsToKeep.schemas) {
// populate set and queue
prevSchemasToKeep.add(schemaUid);
if (this.polymorphicReferences[schemaUid] !== undefined) {
polyReferencedSchemasToCheck.push(schemaUid);
}
}
while (polyReferencedSchemasToCheck.length > 0) {
const referencedSchemaUid = polyReferencedSchemasToCheck.pop();
if (referencedSchemaUid !== undefined) {
polyReferencedSchemasChecked.add(referencedSchemaUid);
for (const polyRef of this.polymorphicReferences[referencedSchemaUid].values()) {
this.componentsToKeep.schemas.add(polyRef);
this.crawlObject(this.components.schemas[polyRef]);
if (prevSchemasToKeep.size !== this.componentsToKeep.schemas.size) {
const difference = new Set([...this.componentsToKeep.schemas].filter((x) => !prevSchemasToKeep.has(x)));
for (const newSchemaUid of difference) {
prevSchemasToKeep.add(newSchemaUid);
if (
this.polymorphicReferences[newSchemaUid] !==
undefined /* && !polyReferencedSchemasChecked.has(referencedSchemaUid) */
) {
polyReferencedSchemasToCheck.push(newSchemaUid);
}
}
}
}
}
}
}
}