{"size": 2675, "ext": "js", "max_stars_repo_path": "lib/Shoulder.js", "max_stars_repo_name": "alexjeffburke/shoulder", "max_stars_repo_stars_event_min_datetime": "2019-04-29T20:49:46.000Z", "max_stars_repo_stars_event_max_datetime": "2020-10-19T04:34:20.000Z", "max_issues_repo_path": "lib/Shoulder.js", "max_issues_repo_name": "alexjeffburke/shoulder", "max_issues_repo_issues_event_min_datetime": null, "max_issues_repo_issues_event_max_datetime": null, "max_forks_repo_path": "lib/Shoulder.js", "max_forks_repo_name": "alexjeffburke/shoulder", "max_forks_repo_forks_event_min_datetime": null, "max_forks_repo_forks_event_max_datetime": null}
{"max_stars_count": 4, "max_issues_count": null, "max_forks_count": null, "avg_line_length": 26.2254901961, "max_line_length": 78, "alphanum_fraction": 0.6482242991}
const ModuleStats = require('./ModuleStats');
const Project = require('./Project');
const ProjectStats = require('./ProjectStats');
const outputters = require('./outputters');

function makeRequirementFromMetric(metric) {
  switch (metric) {
    case 'downloads':
      return 'npmName';
    case 'stars':
      return 'repoUrl';
    default:
      throw new Error(`Shoulder: unsupported metric ${metric}`);
  }
}

function verifyProjects(requirement, projects, options) {
  options = options || {};
  const ProjectStatsConstructor = options._ProjectStats || ProjectStats;
  const warn = options._warn || console.warn;

  return Promise.all(
    projects.map(project =>
      project.verify(requirement).catch(error => {
        if (error.isNotFatal) {
          warn(error.message);
          return null;
        } else {
          throw error;
        }
      })
    )
  )
    .then(projects => projects.filter(Boolean))
    .then(projects => new ProjectStatsConstructor(projects));
}

class Shoulder {
  constructor(options) {
    options = options || {};

    if (!options.package) {
      throw new Error('Shoulder: missing package');
    }

    const outputter =
      typeof options.outputter === 'string'
        ? outputters[options.outputter]
        : () => {};
    if (!outputter) {
      throw new Error(`Shoulder: unsupported outputter ${options.outputter}`);
    }

    this.packageName = options.package;
    this.outputter = outputter;
  }

  output(projectNames, outputterOptions) {
    this.outputter(projectNames, outputterOptions);
  }

  run(options) {
    options = options || {};
    const cwd = options.cwd;
    const packageName = this.packageName;

    options = options || {};
    const metricName = options.metric;
    let requirement;
    try {
      requirement = makeRequirementFromMetric(metricName);
    } catch (error) {
      return Promise.reject(error);
    }

    const statsOptions = {
      librariesIoApiKey: options.librariesIoApiKey || null
    };

    options = options || {};
    const ModuleStatsConstructor = options._ModuleStats || ModuleStats;

    const moduleStats = new ModuleStatsConstructor(packageName, statsOptions);
    return moduleStats
      .fetchDependents()
      .then(dependents => dependents.map(dependent => new Project(dependent)))
      .then(projects => verifyProjects(requirement, projects, options))
      .then(projectStats =>
        projectStats.outputProjectNamesForMetric(metricName)
      )
      .then(projectNames => {
        this.output(projectNames, { cwd, packageName });

        return projectNames;
      });
  }
}

Shoulder.verifyProjects = verifyProjects;

module.exports = Shoulder;
