react-native-macos/scripts/utils/monorepo.js

156 строки
3.4 KiB
JavaScript

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
* @oncall react_native
*/
const {REPO_ROOT} = require('../consts');
const {promises: fs} = require('fs');
const glob = require('glob');
const path = require('path');
const WORKSPACES_CONFIG = 'packages/*';
/*::
export type PackageJson = {
name: string,
version: string,
private?: boolean,
dependencies?: Record<string, string>,
devDependencies?: Record<string, string>,
...
};
type PackagesFilter = $ReadOnly<{
includeReactNative: boolean,
includePrivate?: boolean,
}>;
export type PackageInfo = {
// The name of the package
name: string,
// The absolute path to the package
path: string,
// The parsed package.json contents
packageJson: PackageJson,
};
type ProjectInfo = {
[packageName: string]: PackageInfo,
};
*/
/**
* Locates monrepo packages and returns a mapping of package names to their
* metadata. Considers Yarn workspaces under `packages/`.
*/
async function getPackages(
filter /*: PackagesFilter */,
) /*: Promise<ProjectInfo> */ {
const {includeReactNative, includePrivate = false} = filter;
const packagesEntries = await Promise.all(
glob
.sync(`${WORKSPACES_CONFIG}/package.json`, {
cwd: REPO_ROOT,
absolute: true,
ignore: includeReactNative
? []
: ['packages/react-native/package.json'],
})
.map(parsePackageInfo),
);
return Object.fromEntries(
packagesEntries.filter(
([_, {packageJson}]) => packageJson.private !== true || includePrivate,
),
);
}
/**
* Get the parsed package metadata for the workspace root.
*/
async function getWorkspaceRoot() /*: Promise<PackageInfo> */ {
const [, packageInfo] = await parsePackageInfo(
path.join(REPO_ROOT, 'package.json'),
);
return packageInfo;
}
async function parsePackageInfo(
packageJsonPath /*: string */,
) /*: Promise<[string, PackageInfo]> */ {
const packagePath = path.dirname(packageJsonPath);
const packageJson /*: PackageJson */ = JSON.parse(
await fs.readFile(packageJsonPath, 'utf-8'),
);
return [
packageJson.name,
{
name: packageJson.name,
path: packagePath,
packageJson,
},
];
}
/**
* Update a given package with the package versions.
*/
async function updatePackageJson(
packagePath /*: string */,
packageJson /*: PackageJson */,
newPackageVersions /*: $ReadOnly<{[string]: string}> */,
) /*: Promise<void> */ {
const packageName = packageJson.name;
if (packageName in newPackageVersions) {
packageJson.version = newPackageVersions[packageName];
}
for (const dependencyField of ['dependencies', 'devDependencies']) {
const deps = packageJson[dependencyField];
if (deps == null) {
continue;
}
for (const dependency in newPackageVersions) {
if (dependency in deps) {
deps[dependency] = newPackageVersions[dependency];
}
}
}
return writePackageJson(path.join(packagePath, 'package.json'), packageJson);
}
/**
* Write a `package.json` file to disk.
*/
async function writePackageJson(
packageJsonPath /*: string */,
packageJson /*: PackageJson */,
) /*: Promise<void> */ {
return fs.writeFile(
packageJsonPath,
JSON.stringify(packageJson, null, 2) + '\n',
);
}
module.exports = {
getPackages,
getWorkspaceRoot,
updatePackageJson,
};