xref: /expo/tools/src/Workspace.ts (revision a272999e)
1import JsonFile from '@expo/json-file';
2import path from 'path';
3
4import { EXPO_DIR } from './Constants';
5import { Package } from './Packages';
6import { spawnAsync, spawnJSONCommandAsync } from './Utils';
7
8const NATIVE_APPS_PATHS = [EXPO_DIR, path.join(EXPO_DIR, 'apps/bare-expo')];
9
10/**
11 * Workspace info for the single project.
12 */
13export type WorkspaceProjectInfo = {
14  location: string;
15  workspaceDependencies: string[];
16  mismatchedWorkspaceDependencies: string[];
17};
18
19/**
20 * An object with workspace's projects info.
21 */
22export type WorkspacesInfo = Record<string, WorkspaceProjectInfo>;
23
24/**
25 * Returns an object containing info for all projects in the workspace.
26 */
27export async function getInfoAsync(): Promise<WorkspacesInfo> {
28  const info = await spawnJSONCommandAsync<{ data: string }>('yarn', [
29    '--json',
30    'workspaces',
31    'info',
32  ]);
33  return JSON.parse(info.data);
34}
35
36/**
37 * Runs yarn in the root workspace directory.
38 */
39export async function installAsync(): Promise<void> {
40  await spawnAsync('yarn');
41}
42
43/**
44 * Returns an array of workspace's native apps, like Expo Client or BareExpo.
45 */
46export function getNativeApps(): Package[] {
47  return NATIVE_APPS_PATHS.map((appPath) => new Package(appPath));
48}
49
50/**
51 * Updates the dependency across all workspace projects to given version range.
52 */
53export async function updateDependencyAsync(dependencyName: string, versionRange: string) {
54  const projectLocations = Object.values(await getInfoAsync()).map(
55    (projectInfo) => projectInfo.location
56  );
57
58  await Promise.all(
59    projectLocations.map(async (location) => {
60      const jsonFile = new JsonFile(path.join(EXPO_DIR, location, 'package.json'));
61      const packageJson = await jsonFile.readAsync();
62
63      for (const dependencyType of ['dependencies', 'devDependencies', 'peerDependencies']) {
64        const dependencies = packageJson[dependencyType];
65        const currentVersion = dependencies?.[dependencyName];
66
67        if (dependencies && currentVersion && currentVersion !== '*') {
68          dependencies[dependencyName] = versionRange;
69        }
70      }
71      await jsonFile.writeAsync(packageJson);
72    })
73  );
74}
75