async function getServicesFromSpecRepo()

in eng/scripts/inventory-dashboard/src/addEmptyDataPoints.ts [163:254]


async function getServicesFromSpecRepo(packages: PackageList, apiSpecsDirPath: string): Promise<PackageList> {
  // empty PackageList to be returned
  const additionalPackages: PackageList = {};
  // get list of service dirs from specs dir
  const serviceDirs = fs.readdirSync(apiSpecsDirPath);
  // loop through service dirs
  for (let serviceDir of serviceDirs) {
    let serviceName: string = "";
    // if the the serviceDir maps to a key in ../data-and-rules/apiSpecMap.json, use the service-display-name property from the value object as the serviceName
    if (typeof apiSpecMap[serviceDir] === 'object' && apiSpecMap[serviceDir].hasOwnProperty('service-display-name')) {
      serviceName = apiSpecMap[serviceDir]['service-display-name'];
    } else {
      serviceName = serviceDir;
    }
    // if specDir is a dir, read it's contents and loop through them
    if (fs.lstatSync(path.join(apiSpecsDirPath, serviceDir)).isDirectory()) {
      const apiSpecDirs = fs.readdirSync(path.join(apiSpecsDirPath, serviceDir));
      for (let apiSpecDir of apiSpecDirs) {
        // determine SDK name
        let sdkName: string = "Unable to determine Service Name";
        // if the serviceDir maps to a key in ../data-and-rules/apiSpecMap.json, and it's value object has an api-display-name property, with a property that matches the apiSpecDir, use the value of that property as the sdkName
        if (typeof apiSpecMap[serviceDir] === 'object' && apiSpecMap[serviceDir].hasOwnProperty('api-display-names') && typeof apiSpecMap[serviceDir]['api-display-names'] === 'object' && apiSpecMap[serviceDir]['api-display-names'].hasOwnProperty(apiSpecDir)) {
          sdkName = apiSpecMap[serviceDir]['api-display-names'][apiSpecDir];
        } else {
          // if apiSpecDir is data-plane or resource-manager, sdkName should be the same as serviceName, else it should be the same as apiSpecDir
          sdkName = apiSpecDir === 'data-plane' || apiSpecDir === 'resource-manager' || apiSpecDir === 'resource-management' ? serviceName : apiSpecDir;
        }
        // Determine the plane 
        let plane: Plane = "UNABLE TO BE DETERMINED";
        if (apiSpecDir === 'data-plane') { plane = "data"; }
        else if (apiSpecDir === 'resource-manager' || apiSpecDir === 'resource-management' || apiSpecDir === 'control-plane') { plane = 'mgmt'; sdkName = `Resource Management - ${sdkName}`; }
        else {
          // if apiSpecDir ends in .management regardless of case, print out attention log 
          if (apiSpecDir.toLowerCase().endsWith('.management')) {
            plane = 'mgmt';
            sdkName = `Resource Management - ${sdkName}`;
          } else {
            plane = 'data';
          }
        }

        // skip service api spec if it's in the list of services to hide
        if ((servicesToHide[serviceName] !== undefined && Array.isArray(servicesToHide[serviceName]) && servicesToHide[serviceName].includes(plane)) || (servicesToHide[`${serviceName}|${sdkName}`] !== undefined && Array.isArray(servicesToHide[`${serviceName}|${sdkName}`]) && servicesToHide[`${serviceName}|${sdkName}`].includes(plane))) {
          if ((Array.isArray(servicesToHide[serviceName]) && servicesToHide[serviceName].includes(plane)) || (Array.isArray(servicesToHide[`${serviceName}|${sdkName}`]) && servicesToHide[`${serviceName}|${sdkName}`].includes(plane))) {
            continue;
          }
        }

        // Check if stable spec exists 
        if (fs.lstatSync(path.join(apiSpecsDirPath, serviceDir, apiSpecDir)).isDirectory()) {
          const apiSpecDirContents = fs.readdirSync(path.join(apiSpecsDirPath, serviceDir, apiSpecDir));
          if (apiSpecDir === 'data-plane' || apiSpecDir === 'resource-manager' || apiSpecDir === 'resource-management') {
            const filteredApiSpecDirContents = apiSpecDirContents.filter(s => s.startsWith('Microsoft.'));
            if (filteredApiSpecDirContents.length <= 0) { log.warn(`${serviceDir}/${apiSpecDir} has no dir that starts with "Microsoft."`); }
            else {
              const microsoftDir = filteredApiSpecDirContents[0];
              const microsoftDirContents = fs.readdirSync(path.join(apiSpecsDirPath, serviceDir, apiSpecDir, microsoftDir));
              const filteredMicrosoftDirContents = microsoftDirContents.filter(s => s === "stable");
              // If no stable api was found skip
              if (filteredMicrosoftDirContents.length <= 0) { log.info(`No stable API Spec found for ${serviceDir}/${apiSpecDir}`); continue; }
            }
          } else {
            //TODO - check if TypeSpec api has stable version, if not skip
          }
        }

        // loop through Tier 1 languages and create empty package if it doesn't exist
        for (let language of Tier1Languages) {
          // create pkg key
          const key = (serviceName + sdkName + plane + language).toLowerCase();
          // If package doesn't exist in list already, add it.
          if (packages[key] === undefined && additionalPackages[key] === undefined) {
            additionalPackages[key] = {
              Service: serviceName,
              ServiceId: 0,
              SDK: sdkName,
              Plane: plane,
              Language: language,
              Track1: TrackSpecificsDefault,
              Track2: { ...TrackSpecificsDefault, Package: `Missing: Created from API in specs repo: ${serviceDir}/${apiSpecDir}` },
              PercentComplete: undefined,
              LatestRelease: ''
            };
            log.info(`Adding Empty Package from Specs Repo.\n\tEmpty Package: ${JSON.stringify(additionalPackages[key])}\n\tREST Spec Dir: ${serviceDir}/${apiSpecDir}`);
          }
        }

      }
    }
  }
  return additionalPackages;
}