visitSchemas()

in packages/extensions/core/src/lib/plugins/subset-schemas-deduplicator.ts [61:139]


  visitSchemas<T>(container: ProxyObject<Record<string, T>>, originalNodes: () => Iterable<Node>) {
    const xMsMetadata = "x-ms-metadata";
    const updatedSchemas: any = {};

    // get all the schemas and associate them with their uid
    // this will allow us to place the value in the right place at the end
    const schemas: Array<AnyObject> = [];
    for (const { key, value } of originalNodes()) {
      if (value.type === "object" || value.type === undefined) {
        // only do subset reduction on objects
        schemas.push({ value, uid: key });
      } else {
        updatedSchemas[key] = value;
      }
    }

    // sort by apiVersion from latest to oldest
    schemas.sort((a, b) => {
      const aMaxVersion = maximum(a.value[xMsMetadata].apiVersions);
      const bMaxVersion = maximum(b.value[xMsMetadata].apiVersions);
      return gt(aMaxVersion, bMaxVersion) ? -1 : lt(aMaxVersion, bMaxVersion) ? 1 : 0;
    });

    // deduplicate/reduce
    for (const { value: currentSchema } of visit(schemas)) {
      for (const { value: anotherSchema } of visit(schemas)) {
        const currentSchemaName = currentSchema.value[xMsMetadata].name;
        const anotherSchemaName = anotherSchema.value[xMsMetadata].name;
        if (currentSchemaName === anotherSchemaName && currentSchema.uid !== anotherSchema.uid) {
          const skipList = ["description", "enum", "readOnly", "required", "x-ms-original", "x-ms-examples"];
          const additiveFieldsList = ["properties", "allOf", "required"];

          // filter out metadata
          const { "x-ms-metadata": metadataAnotherSchema, ...filteredAnotherSchema } = anotherSchema.value;
          const { "x-ms-metadata": metadataCurrentSchema, ...filteredCurrentSchema } = currentSchema.value;

          const subsetRelation = getSubsetRelation(
            filteredAnotherSchema,
            filteredCurrentSchema,
            additiveFieldsList,
            skipList,
          );
          if (subsetRelation.isSubset !== false) {
            const supersetEquivSchema = getSupersetSchema(
              filteredAnotherSchema,
              filteredCurrentSchema,
              additiveFieldsList,
              subsetRelation,
              `#/components/schemas/${anotherSchema.uid}`,
            );
            const subsetEquivSchema = getSubsetSchema(filteredAnotherSchema, subsetRelation);

            // gs: added -- ensure that properties left beg
            if (currentSchema.value.required && supersetEquivSchema.properties) {
              const sesNames = Object.getOwnPropertyNames(supersetEquivSchema.properties);
              supersetEquivSchema.required = currentSchema.value.required.filter(
                (each: any) => sesNames.indexOf(each) > -1,
              );
            }

            // replace with equivalent schema and put back metadata.
            currentSchema.value = { "x-ms-metadata": metadataCurrentSchema, ...supersetEquivSchema };
            anotherSchema.value = { "x-ms-metadata": metadataAnotherSchema, ...subsetEquivSchema };
          }
        }
      }
    }

    // get back updated schemas

    for (const schema of schemas) {
      updatedSchemas[schema.uid] = schema.value;
    }

    // finish up
    for (const { key, pointer } of originalNodes()) {
      container[key] = { value: updatedSchemas[key], pointer, recurse: true };
    }
  }