xref: /expo/tools/src/vendoring/index.ts (revision 9657025f)
1import chalk from 'chalk';
2import Table from 'cli-table3';
3import semver from 'semver';
4
5import { link } from '../Formatter';
6import logger from '../Logger';
7import * as Npm from '../Npm';
8import { getBundledVersionsAsync } from '../ProjectVersions';
9import {
10  VendoringModulePlatformConfig,
11  VendoringProvider,
12  VendoringTargetModulesConfig,
13} from './types';
14
15const VENDORING_PROVIDERS: Record<string, () => VendoringProvider> = {
16  ios: () => require('../vendoring/IosVendoring'),
17  android: () => require('../vendoring/AndroidVendoring'),
18};
19
20/**
21 * Delegates vendoring process to platform's provider.
22 */
23export async function vendorPlatformAsync(
24  platform: string,
25  sourceDirectory: string,
26  targetDirectory: string,
27  modulePlatformConfig?: VendoringModulePlatformConfig
28) {
29  const provider = VENDORING_PROVIDERS[platform]?.();
30
31  if (!provider) {
32    throw new Error(`No vendoring provider for platform "${platform}".`);
33  }
34  await provider.vendorAsync(sourceDirectory, targetDirectory, modulePlatformConfig);
35}
36
37/**
38 * Outputs a table with modules, their versions and status.
39 */
40export async function listAvailableVendoredModulesAsync(
41  modules: VendoringTargetModulesConfig,
42  onlyOutdated: boolean = false
43) {
44  const bundledNativeModules = await getBundledVersionsAsync();
45  const vendoredPackageNames = Object.keys(modules);
46  const packageViews: Npm.PackageViewType[] = await Promise.all(
47    vendoredPackageNames.map((packageName: string) => Npm.getPackageViewAsync(packageName))
48  );
49
50  const table = new Table({
51    head: ['Package name', 'Bundled', 'Latest', 'Up to date'],
52    colAligns: ['right', 'center', 'center', 'center'],
53  });
54
55  for (const packageName of vendoredPackageNames) {
56    const packageView = packageViews.shift();
57
58    if (!packageView) {
59      logger.error(`Couldn't get package view for ${chalk.green.bold(packageName)}.\n`);
60      continue;
61    }
62
63    const bundledVersion = bundledNativeModules[packageName];
64    const latestVersion = packageView['dist-tags'].latest;
65    const isOutdated = !bundledVersion || semver.gtr(latestVersion, bundledVersion);
66
67    if (!onlyOutdated || isOutdated) {
68      const { source } = modules[packageName];
69
70      table.push([
71        link(chalk.bold.green(packageName), source),
72        (bundledVersion ? chalk.cyan : chalk.gray)(bundledVersion),
73        chalk.cyan(latestVersion),
74        isOutdated ? '❌' : '✅',
75      ]);
76    }
77  }
78  logger.log(table.toString());
79}
80
81/**
82 * Returns an array of platforms that vendoring process is available for.
83 */
84export function getVendoringAvailablePlatforms(): string[] {
85  return Object.keys(VENDORING_PROVIDERS);
86}
87