1c94ad8a2SEvan Baconimport { getConfig } from '@expo/config'; 2c94ad8a2SEvan Baconimport * as PackageManager from '@expo/package-manager'; 3c94ad8a2SEvan Baconimport chalk from 'chalk'; 4c94ad8a2SEvan Bacon 5*8a424bebSJames Ideimport { fixPackagesAsync } from './installAsync'; 6*8a424bebSJames Ideimport { Options } from './resolveOptions'; 7c94ad8a2SEvan Baconimport * as Log from '../log'; 8c94ad8a2SEvan Baconimport { 9c94ad8a2SEvan Bacon getVersionedDependenciesAsync, 10c94ad8a2SEvan Bacon logIncorrectDependencies, 11c94ad8a2SEvan Bacon} from '../start/doctor/dependencies/validateDependenciesVersions'; 1229128565SEvan Baconimport { isInteractive } from '../utils/interactive'; 136fb32dddSKeith Kurakimport { learnMore } from '../utils/link'; 14c94ad8a2SEvan Baconimport { confirmAsync } from '../utils/prompts'; 156fb32dddSKeith Kurakimport { joinWithCommasAnd } from '../utils/strings'; 16c94ad8a2SEvan Bacon 17474a7a4bSEvan Baconconst debug = require('debug')('expo:install:check') as typeof console.log; 18474a7a4bSEvan Bacon 19c94ad8a2SEvan Bacon// Exposed for testing. 20c94ad8a2SEvan Baconexport async function checkPackagesAsync( 21c94ad8a2SEvan Bacon projectRoot: string, 22c94ad8a2SEvan Bacon { 23c94ad8a2SEvan Bacon packages, 24c94ad8a2SEvan Bacon packageManager, 25c94ad8a2SEvan Bacon options: { fix }, 26c94ad8a2SEvan Bacon packageManagerArguments, 27c94ad8a2SEvan Bacon }: { 28c94ad8a2SEvan Bacon /** 29c94ad8a2SEvan Bacon * List of packages to version 30c94ad8a2SEvan Bacon * @example ['uuid', 'react-native-reanimated@latest'] 31c94ad8a2SEvan Bacon */ 32c94ad8a2SEvan Bacon packages: string[]; 33c94ad8a2SEvan Bacon /** Package manager to use when installing the versioned packages. */ 348d3f3824SCedric van Putten packageManager: PackageManager.NodePackageManager; 35c94ad8a2SEvan Bacon 36c94ad8a2SEvan Bacon /** How the check should resolve */ 37c94ad8a2SEvan Bacon options: Pick<Options, 'fix'>; 38c94ad8a2SEvan Bacon /** 39c94ad8a2SEvan Bacon * Extra parameters to pass to the `packageManager` when installing versioned packages. 40c94ad8a2SEvan Bacon * @example ['--no-save'] 41c94ad8a2SEvan Bacon */ 42c94ad8a2SEvan Bacon packageManagerArguments: string[]; 43c94ad8a2SEvan Bacon } 44c94ad8a2SEvan Bacon) { 45c94ad8a2SEvan Bacon // Read the project Expo config without plugins. 46c94ad8a2SEvan Bacon const { exp, pkg } = getConfig(projectRoot, { 47c94ad8a2SEvan Bacon // Sometimes users will add a plugin to the config before installing the library, 48c94ad8a2SEvan Bacon // this wouldn't work unless we dangerously disable plugin serialization. 49c94ad8a2SEvan Bacon skipPlugins: true, 50c94ad8a2SEvan Bacon }); 51c94ad8a2SEvan Bacon 526fb32dddSKeith Kurak if (pkg.expo?.install?.exclude?.length) { 536fb32dddSKeith Kurak Log.log( 546fb32dddSKeith Kurak chalk`Skipped ${fix ? 'fixing' : 'checking'} dependencies: ${joinWithCommasAnd( 556fb32dddSKeith Kurak pkg.expo.install.exclude 566fb32dddSKeith Kurak )}. These dependencies are listed in {bold expo.install.exclude} in package.json. ${learnMore( 576fb32dddSKeith Kurak 'https://expo.dev/more/expo-cli/#configuring-dependency-validation' 586fb32dddSKeith Kurak )}` 596fb32dddSKeith Kurak ); 606fb32dddSKeith Kurak } 616fb32dddSKeith Kurak 62c94ad8a2SEvan Bacon const dependencies = await getVersionedDependenciesAsync(projectRoot, exp, pkg, packages); 63c94ad8a2SEvan Bacon 64c94ad8a2SEvan Bacon if (!dependencies.length) { 65c94ad8a2SEvan Bacon Log.exit(chalk.greenBright('Dependencies are up to date'), 0); 66c94ad8a2SEvan Bacon } 67c94ad8a2SEvan Bacon 68c94ad8a2SEvan Bacon logIncorrectDependencies(dependencies); 69c94ad8a2SEvan Bacon 70c94ad8a2SEvan Bacon const value = 71c94ad8a2SEvan Bacon // If `--fix` then always fix. 72c94ad8a2SEvan Bacon fix || 73c94ad8a2SEvan Bacon // Otherwise prompt to fix when not running in CI. 7429128565SEvan Bacon (isInteractive() && (await confirmAsync({ message: 'Fix dependencies?' }).catch(() => false))); 75c94ad8a2SEvan Bacon 76c94ad8a2SEvan Bacon if (value) { 778d3f3824SCedric van Putten debug('Installing fixed dependencies:', dependencies); 78c94ad8a2SEvan Bacon // Install the corrected dependencies. 798d3f3824SCedric van Putten return fixPackagesAsync(projectRoot, { 80c94ad8a2SEvan Bacon packageManager, 818d3f3824SCedric van Putten packages: dependencies, 82c94ad8a2SEvan Bacon packageManagerArguments, 83c94ad8a2SEvan Bacon sdkVersion: exp.sdkVersion!, 84c94ad8a2SEvan Bacon }); 85c94ad8a2SEvan Bacon } 86c94ad8a2SEvan Bacon // Exit with non-zero exit code if any of the dependencies are out of date. 87c94ad8a2SEvan Bacon Log.exit(chalk.red('Found outdated dependencies'), 1); 88c94ad8a2SEvan Bacon} 89