async init()

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);
                }
              }
            }
          }
        }
      }
    }
  }