{"size": 15326, "ext": "js", "max_stars_repo_path": "node_modules/flow-typed/dist/commands/install.js", "max_stars_repo_name": "levensti/stevenli.org", "max_stars_repo_stars_event_min_datetime": null, "max_stars_repo_stars_event_max_datetime": null, "max_issues_repo_path": "node_modules/flow-typed/dist/commands/install.js", "max_issues_repo_name": "levensti/stevenli.org", "max_issues_repo_issues_event_min_datetime": "2022-02-25T23:52:02.000Z", "max_issues_repo_issues_event_max_datetime": "2022-03-30T10:36:08.000Z", "max_forks_repo_path": "node_modules/flow-typed/dist/commands/install.js", "max_forks_repo_name": "Owen-Oertell/owenoertell.com", "max_forks_repo_forks_event_min_datetime": null, "max_forks_repo_forks_event_max_datetime": null}
{"max_stars_count": null, "max_issues_count": 5, "max_forks_count": null, "avg_line_length": 35.6418604651, "max_line_length": 433, "alphanum_fraction": 0.65953282}
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.setup = setup;
exports.run = run;
exports._determineFlowVersion = determineFlowVersion;
exports._installNpmLibDefs = installNpmLibDefs;
exports._installNpmLibDef = installNpmLibDef;
exports.description = exports.name = void 0;

var _codeSign = require("../lib/codeSign");

var _fileUtils = require("../lib/fileUtils");

var _flowProjectUtils = require("../lib/flowProjectUtils");

var _flowVersion = require("../lib/flowVersion");

var _node = require("../lib/node");

var _npmLibDefs = require("../lib/npm/npmLibDefs");

var _npmProjectUtils = require("../lib/npm/npmProjectUtils");

var _cacheRepoUtils = require("../lib/cacheRepoUtils");

var _semver = require("../lib/semver");

var _safe = _interopRequireDefault(require("colors/safe"));

var _semver2 = _interopRequireDefault(require("semver"));

var _stubUtils = require("../lib/stubUtils");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

const name = 'install [explicitLibDefs...]';
exports.name = name;
const description = 'Installs libdefs into the ./flow-typed directory';
exports.description = description;

function setup(yargs) {
  return yargs.usage(`$0 ${name} - ${description}`).positional('explicitLibDefs', {
    describe: 'Explicitly specify packages to install',
    default: []
  }).options({
    flowVersion: {
      alias: 'f',
      describe: 'The Flow version that fetched libdefs must be compatible with',
      type: 'string'
    },
    verbose: {
      describe: 'Print additional, verbose info while installing libdefs',
      type: 'boolean',
      demandOption: false
    },
    skip: {
      alias: 's',
      describe: 'Do not generate stubs for missing libdefs',
      type: 'boolean',
      demandOption: false
    },
    libdefDir: {
      alias: 'l',
      describe: 'Use a custom directory to install libdefs',
      type: 'string',
      demandOption: false
    },
    cacheDir: {
      alias: 'c',
      describe: 'Directory (absolute or relative path, ~ is not supported) to store cache of libdefs',
      type: 'string',
      demandOption: false
    },
    packageDir: {
      alias: 'p',
      describe: 'The relative path of package.json where flow-bin is installed',
      type: 'string'
    },
    overwrite: {
      alias: 'o',
      describe: 'Overwrite an existing libdef',
      type: 'boolean',
      demandOption: false
    },
    ignoreDeps: {
      alias: 'i',
      describe: 'Dependency categories to ignore when installing definitions',
      choices: ['dev', 'bundled', 'peer'],
      type: 'array'
    },
    rootDir: {
      alias: 'r',
      describe: 'Directory of .flowconfig relative to node_modules',
      type: 'string'
    },
    useCacheUntil: {
      alias: 'u',
      describe: 'Use cache until specified time in milliseconds',
      type: 'number'
    }
  });
}

async function run(args) {
  const cwd = typeof args.rootDir === 'string' ? _node.path.resolve(args.rootDir) : process.cwd();
  const packageDir = typeof args.packageDir === 'string' ? _node.path.resolve(args.packageDir) : cwd;
  const flowVersion = await determineFlowVersion(packageDir, args.flowVersion);
  const libdefDir = typeof args.libdefDir === 'string' ? args.libdefDir : 'flow-typed';

  if (args.ignoreDeps !== undefined && !Array.isArray(args.ignoreDeps)) {
    throw new Error('ignoreDeps is not array');
  }

  const ignoreDeps = (args.ignoreDeps || []).map(dep => {
    if (typeof dep !== 'string') {
      throw new Error('ignoreDeps should be array of strings');
    }

    return dep;
  });

  if (args.explicitLibDefs !== undefined && !Array.isArray(args.explicitLibDefs)) {
    throw new Error('explicitLibDefs is not array');
  }

  const explicitLibDefs = (args.explicitLibDefs || []).map(dep => {
    if (typeof dep !== 'string') {
      throw new Error('explicitLibDefs should be array of strings');
    }

    return dep;
  });
  const coreLibDefResult = await installCoreLibDefs();

  if (coreLibDefResult !== 0) {
    return coreLibDefResult;
  }

  if (args.cacheDir) {
    const cacheDir = _node.path.resolve(String(args.cacheDir));

    console.log('• Setting cache dir', cacheDir);
    (0, _cacheRepoUtils._setCustomCacheDir)(cacheDir);
  }

  const npmLibDefResult = await installNpmLibDefs({
    cwd,
    flowVersion,
    explicitLibDefs,
    libdefDir: libdefDir,
    verbose: Boolean(args.verbose),
    overwrite: Boolean(args.overwrite),
    skip: Boolean(args.skip),
    ignoreDeps: ignoreDeps,
    useCacheUntil: Number(args.useCacheUntil) || _cacheRepoUtils.CACHE_REPO_EXPIRY
  });

  if (npmLibDefResult !== 0) {
    return npmLibDefResult;
  }

  return 0;
}

async function determineFlowVersion(cwd, flowVersionArg) {
  if (flowVersionArg && typeof flowVersionArg === 'string') {
    // Be permissive if the prefix 'v' is left off
    let flowVersionStr = flowVersionArg[0] === 'v' ? flowVersionArg : `v${flowVersionArg}`;

    if (/^v[0-9]+\.[0-9]+$/.test(flowVersionStr)) {
      flowVersionStr = `${flowVersionStr}.0`;
    }

    return {
      kind: 'specific',
      ver: (0, _flowVersion.parseFlowSpecificVer)(flowVersionStr)
    };
  } else {
    return {
      kind: 'specific',
      ver: await (0, _npmProjectUtils.findFlowSpecificVer)(cwd)
    };
  }
}

async function installCoreLibDefs() {
  // TODO...
  return 0;
}

const FLOW_BUILT_IN_NPM_LIBS = ['react'];

async function installNpmLibDefs({
  cwd,
  flowVersion,
  explicitLibDefs,
  libdefDir,
  verbose,
  overwrite,
  skip,
  ignoreDeps,
  useCacheUntil
}) {
  const flowProjectRoot = await (0, _flowProjectUtils.findFlowRoot)(cwd);

  if (flowProjectRoot === null) {
    console.error('Error: Unable to find a flow project in the current dir or any of ' + "it's parent dirs!\n" + 'Please run this command from within a Flow project.');
    return 1;
  }

  const libdefsToSearchFor = new Map(); // If a specific pkg/version was specified, only add those packages.
  // Otherwise, extract dependencies from the package.json

  if (explicitLibDefs.length > 0) {
    for (var i = 0; i < explicitLibDefs.length; i++) {
      const term = explicitLibDefs[i];
      const termMatches = term.match(/(@[^@\/]+\/)?([^@]+)@(.+)/);

      if (termMatches == null) {
        const pkgJsonData = await (0, _npmProjectUtils.getPackageJsonData)(cwd);
        const pkgJsonDeps = (0, _npmProjectUtils.getPackageJsonDependencies)(pkgJsonData, []);
        const packageVersion = pkgJsonDeps[term];

        if (packageVersion) {
          libdefsToSearchFor.set(term, packageVersion);
        } else {
          console.error('ERROR: Package not found from package.json.\n' + 'Please specify version for the package in the format of `foo@1.2.3`');
          return 1;
        }
      } else {
        const [_, npmScope, pkgName, pkgVerStr] = termMatches;
        const scopedPkgName = npmScope != null ? npmScope + pkgName : pkgName;
        libdefsToSearchFor.set(scopedPkgName, pkgVerStr);
      }
    }

    console.log(`• Searching for ${libdefsToSearchFor.size} libdefs...`);
  } else {
    const pkgJsonData = await (0, _npmProjectUtils.getPackageJsonData)(cwd);
    const pkgJsonDeps = (0, _npmProjectUtils.getPackageJsonDependencies)(pkgJsonData, ignoreDeps);

    for (const pkgName in pkgJsonDeps) {
      libdefsToSearchFor.set(pkgName, pkgJsonDeps[pkgName]);
    }

    if (libdefsToSearchFor.size === 0) {
      console.error("No dependencies were found in this project's package.json!");
      return 0;
    }

    if (verbose) {
      libdefsToSearchFor.forEach((ver, name) => {
        console.log(`• Found package.json dependency: ${name}@${ver}`);
      });
    } else {
      console.log(`• Found ${libdefsToSearchFor.size} dependencies in package.json to ` + `install libdefs for. Searching...`);
    }
  }

  const libDefsToSearchForEntries = [...libdefsToSearchFor.entries()]; // Search for the requested libdefs

  const libDefsToInstall = new Map();
  const outdatedLibDefsToInstall = [];
  const unavailableLibDefs = [];
  await Promise.all(libDefsToSearchForEntries.map(async ([name, ver]) => {
    if (FLOW_BUILT_IN_NPM_LIBS.indexOf(name) !== -1) {
      return;
    }

    const libDef = await (0, _npmLibDefs.findNpmLibDef)(name, ver, flowVersion, useCacheUntil);

    if (libDef === null) {
      unavailableLibDefs.push({
        name,
        ver
      });
    } else {
      libDefsToInstall.set(name, libDef);
      const libDefLower = (0, _semver.getRangeLowerBound)(libDef.version);
      const depLower = (0, _semver.getRangeLowerBound)(ver);

      if (_semver2.default.lt(libDefLower, depLower)) {
        outdatedLibDefsToInstall.push([libDef, {
          name,
          ver
        }]);
      }
    }
  })); // Scan libdefs that are already installed

  const libDefsToUninstall = new Map();
  const alreadyInstalledLibDefs = await (0, _npmLibDefs.getInstalledNpmLibDefs)(_node.path.join(flowProjectRoot), libdefDir);
  [...alreadyInstalledLibDefs.entries()].forEach(([filePath, npmLibDef]) => {
    const fullFilePath = _node.path.join(flowProjectRoot, filePath);

    switch (npmLibDef.kind) {
      case 'LibDef':
        // If a libdef is already installed for some dependency, we need to
        // uninstall it before installing the new (potentially updated) ver
        const libDef = npmLibDef.libDef;
        const scopedPkgName = (0, _npmLibDefs.getScopedPackageName)(libDef);

        if (libDefsToInstall.has(scopedPkgName)) {
          libDefsToUninstall.set(scopedPkgName, fullFilePath);
        }

        break;

      case 'Stub':
        break;

      default:
        npmLibDef;
    }
  });

  if (libDefsToInstall.size > 0) {
    console.log(`• Installing ${libDefsToInstall.size} libDefs...`);

    const flowTypedDirPath = _node.path.join(flowProjectRoot, libdefDir, 'npm');

    await (0, _fileUtils.mkdirp)(flowTypedDirPath);
    const results = await Promise.all([...libDefsToInstall.values()].map(async libDef => {
      const toUninstall = libDefsToUninstall.get((0, _npmLibDefs.getScopedPackageName)(libDef));

      if (toUninstall != null) {
        await _node.fs.unlink(toUninstall);
      }

      return installNpmLibDef(libDef, flowTypedDirPath, overwrite);
    }));

    if (results.some(res => !res)) {
      return 1;
    }
  }

  if ((verbose || unavailableLibDefs.length === 0) && outdatedLibDefsToInstall.length > 0) {
    console.log('• The following installed libdefs are compatible with your ' + 'dependencies, but may not include all minor and patch changes for ' + 'your specific dependency version:\n');
    outdatedLibDefsToInstall.forEach(([libDef, {
      name: pkgName,
      ver: pkgVersion
    }]) => {
      console.log('  • libdef: %s (satisfies %s)', _safe.default.yellow(`${libDef.name}_${libDef.version}`), _safe.default.bold(`${pkgName}@${pkgVersion}`));
      const libDefPlural = outdatedLibDefsToInstall.length > 1 ? ['versioned updates', 'these packages'] : ['a versioned update', 'this package'];
      console.log(`\n` + `  Consider submitting ${libDefPlural[0]} for ${libDefPlural[1]} to \n` + `  https://github.com/flowtype/flow-typed/\n`);
    });
  }

  if (unavailableLibDefs.length > 0 && unavailableLibDefs.length === explicitLibDefs.length) {
    // If the user specified an explicit library to be installed, don't generate
    // a stub if no libdef exists -- just inform them that one doesn't exist
    console.log(_safe.default.red(`!! No flow@${(0, _flowVersion.toSemverString)(flowVersion)}-compatible libdefs ` + `found in flow-typed for the explicitly requested libdefs. !!`) + '\n' + '\n' + 'Consider using `%s` to generate an empty libdef that you can fill in.', _safe.default.bold(`flow-typed create-stub ${explicitLibDefs.join(' ')}`));
    return 1;
  } else {
    const pnpResolver = await (0, _npmProjectUtils.loadPnpResolver)((await (0, _npmProjectUtils.getPackageJsonData)(cwd))); // If a package that's missing a flow-typed libdef has any .flow files,
    // we'll skip generating a stub for it.

    const untypedMissingLibDefs = [];
    const typedMissingLibDefs = [];
    await Promise.all(unavailableLibDefs.map(async ({
      name: pkgName,
      ver: pkgVer
    }) => {
      const hasFlowFiles = await (0, _stubUtils.pkgHasFlowFiles)(cwd, pkgName, pnpResolver);

      if (hasFlowFiles) {
        typedMissingLibDefs.push([pkgName, pkgVer]);
      } else {
        untypedMissingLibDefs.push([pkgName, pkgVer]);
      }
    }));

    if (untypedMissingLibDefs.length > 0 && !skip) {
      console.log('• Generating stubs for untyped dependencies...');
      await Promise.all(untypedMissingLibDefs.map(async ([pkgName, pkgVerStr]) => {
        await (0, _stubUtils.createStub)(flowProjectRoot, pkgName, pkgVerStr, overwrite, pnpResolver,
        /* typescript */
        false, libdefDir);
      }));
      console.log(_safe.default.red(`\n!! No flow@${(0, _flowVersion.toSemverString)(flowVersion)}-compatible libdefs ` + `found in flow-typed for the above untyped dependencies !!`));
      const plural = unavailableLibDefs.length > 1 ? ['libdefs', 'these packages', 'them'] : ['a libdef', 'this package', 'it'];
      console.log(`\n` + `We've generated ${'`'}any${'`'}-typed stubs for ${plural[1]}, but ` + `consider submitting \n` + `${plural[0]} for ${plural[2]} to ` + `${_safe.default.bold('https://github.com/flowtype/flow-typed/')}\n`);
    }
  }

  return 0;
}

async function installNpmLibDef(npmLibDef, npmDir, overwrite) {
  const scopedDir = npmLibDef.scope === null ? npmDir : _node.path.join(npmDir, npmLibDef.scope);
  (0, _fileUtils.mkdirp)(scopedDir);
  const fileName = `${npmLibDef.name}_${npmLibDef.version}.js`;

  const filePath = _node.path.join(scopedDir, fileName); // Find the libDef in the cached repo


  try {
    const terseFilePath = _node.path.relative(_node.path.resolve(npmDir, '..', '..'), filePath);

    if (!overwrite && (await _node.fs.exists(filePath))) {
      console.error('  • %s\n' + '    %s\n    %s\n    └> %s', _safe.default.bold(_safe.default.red(`${terseFilePath} already exists and appears to have been manually ` + `written or changed!`)), _safe.default.green(`Consider contributing your changes back to flow-typed repository :)`), `Read more at https://github.com/flowtype/flow-typed/wiki/Contributing-Library-Definitions`, 'Use --overwrite to overwrite the existing libdef.');
      return true;
    }

    const repoVersion = await (0, _npmLibDefs.getNpmLibDefVersionHash)((0, _cacheRepoUtils.getCacheRepoDir)(), npmLibDef);
    const codeSignPreprocessor = (0, _codeSign.signCodeStream)(repoVersion);
    await (0, _fileUtils.copyFile)(npmLibDef.path, filePath, codeSignPreprocessor);
    console.log(_safe.default.bold('  • %s\n' + '    └> %s'), fileName, _safe.default.green(`.${_node.path.sep}${terseFilePath}`)); // Remove any lingering stubs

    console.log(npmLibDef.name);
    console.log(scopedDir);
    const stubName = `${npmLibDef.name}_vx.x.x.js`;

    const stubPath = _node.path.join(scopedDir, stubName);

    if (overwrite && (await _node.fs.exists(stubPath))) {
      await _node.fs.unlink(stubPath);
    }

    return true;
  } catch (e) {
    console.error(`  !! Failed to install ${npmLibDef.name} at ${filePath}`);
    console.error(`  ERROR: ${e.message}`);
    return false;
  }
}