mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Reorganise shared script utils (#52473)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/52473 Shared utils that were located in the root of `scripts/` are now colocated closer to their dependencies or moved to `scripts/shared/` — simplifying the root directory layout. Changelog: [Internal] Reviewed By: robhogan Differential Revision: D77873875 fbshipit-source-id: e04dba41a1ef811d32793931033fdfa93afad0cd
This commit is contained in:
committed by
Facebook GitHub Bot
parent
6dfe59e1df
commit
fc5e33b582
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* 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-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
const {
|
||||
PACKAGES_DIR,
|
||||
PRIVATE_DIR,
|
||||
RN_INTEGRATION_TESTS_RUNNER_DIR,
|
||||
SCRIPTS_DIR,
|
||||
} = require('./consts');
|
||||
|
||||
let isRegisteredForMonorepo = false;
|
||||
|
||||
/**
|
||||
* Calling this function enables all Node.js packages to run from source when
|
||||
* developing in the React Native repo.
|
||||
*
|
||||
* A call should located in each entry point file in a package (i.e. for all
|
||||
* paths in "exports"), inside a special `if` condition that will be compiled
|
||||
* away on build.
|
||||
*
|
||||
* ```js
|
||||
* // Place in a package entry point
|
||||
* if (!process.env.BUILD_EXCLUDE_BABEL_REGISTER) {
|
||||
* require('../../../scripts/shared/babelRegister').registerForMonorepo();
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
function registerForMonorepo() {
|
||||
if (isRegisteredForMonorepo) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (process.env.FBSOURCE_ENV === '1') {
|
||||
// $FlowExpectedError[cannot-resolve-module] - Won't resolve in OSS
|
||||
require('@fb-tools/babel-register');
|
||||
} else {
|
||||
require('metro-babel-register')([
|
||||
PACKAGES_DIR,
|
||||
PRIVATE_DIR,
|
||||
SCRIPTS_DIR,
|
||||
RN_INTEGRATION_TESTS_RUNNER_DIR,
|
||||
]);
|
||||
}
|
||||
|
||||
isRegisteredForMonorepo = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling this function enables entry points under scripts/ to run from source.
|
||||
*
|
||||
* ```js
|
||||
* // Place in a script entry point
|
||||
* require('../shared/babelRegister').registerForScript();
|
||||
* ```
|
||||
*/
|
||||
function registerForScript() {
|
||||
registerForMonorepo();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
registerForMonorepo,
|
||||
registerForScript,
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* The absolute path to the repo root.
|
||||
*/
|
||||
const REPO_ROOT /*: string */ = path.resolve(__dirname, '../..');
|
||||
|
||||
/**
|
||||
* The absolute path to the packages directory (note: this directory alone may
|
||||
* not match the "workspaces" config in package.json).
|
||||
*/
|
||||
const PACKAGES_DIR /*: string */ = path.join(REPO_ROOT, 'packages');
|
||||
|
||||
/**
|
||||
* The absolute path to the repo private directory.
|
||||
*/
|
||||
const PRIVATE_DIR /*: string */ = path.join(REPO_ROOT, 'private');
|
||||
|
||||
/**
|
||||
* The absolute path to the repo scripts directory.
|
||||
*/
|
||||
const SCRIPTS_DIR /*: string */ = path.join(REPO_ROOT, 'scripts');
|
||||
|
||||
/**
|
||||
* The absolute path to the react-native package.
|
||||
*/
|
||||
const REACT_NATIVE_PACKAGE_DIR /*: string */ = path.join(
|
||||
REPO_ROOT,
|
||||
'packages',
|
||||
'react-native',
|
||||
);
|
||||
|
||||
/**
|
||||
* The absolute path to the rn-tester package.
|
||||
*/
|
||||
const RN_TESTER_DIR /*: string */ = path.join(
|
||||
REPO_ROOT,
|
||||
'packages',
|
||||
'rn-tester',
|
||||
);
|
||||
|
||||
/**
|
||||
* The absolute path to the RN integration tests runner directory.
|
||||
*/
|
||||
const RN_INTEGRATION_TESTS_RUNNER_DIR /*: string */ = path.join(
|
||||
REPO_ROOT,
|
||||
'jest',
|
||||
'integration',
|
||||
'runner',
|
||||
);
|
||||
|
||||
module.exports = {
|
||||
PACKAGES_DIR,
|
||||
PRIVATE_DIR,
|
||||
REACT_NATIVE_PACKAGE_DIR,
|
||||
REPO_ROOT,
|
||||
RN_TESTER_DIR,
|
||||
SCRIPTS_DIR,
|
||||
RN_INTEGRATION_TESTS_RUNNER_DIR,
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 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-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const childProcess = require('child_process');
|
||||
|
||||
/*::
|
||||
type Commit = string;
|
||||
*/
|
||||
|
||||
function isGitRepo() /*: boolean */ {
|
||||
try {
|
||||
const result = childProcess.execSync(
|
||||
'git rev-parse --is-inside-work-tree',
|
||||
{
|
||||
encoding: 'utf8',
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
},
|
||||
);
|
||||
return result.trim() === 'true';
|
||||
} catch (error) {
|
||||
console.error(`Failed to check git repository status: ${error}`);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
module.exports = isGitRepo;
|
||||
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
const {REPO_ROOT} = require('./consts');
|
||||
const {promises: fs} = require('fs');
|
||||
const glob = require('glob');
|
||||
const path = require('path');
|
||||
|
||||
const WORKSPACES_CONFIG = '{packages,private}/*';
|
||||
|
||||
/*::
|
||||
export type PackageJson = {
|
||||
name: string,
|
||||
version: string,
|
||||
private?: boolean,
|
||||
dependencies?: Record<string, string>,
|
||||
devDependencies?: Record<string, string>,
|
||||
main?: 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,
|
||||
};
|
||||
|
||||
export 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(
|
||||
{path: packagePath, packageJson} /*: PackageInfo */,
|
||||
newPackageVersions /*: $ReadOnly<{[string]: string}> */,
|
||||
) /*: Promise<void> */ {
|
||||
const packageName = packageJson.name;
|
||||
|
||||
if (packageName in newPackageVersions) {
|
||||
packageJson.version = newPackageVersions[packageName];
|
||||
}
|
||||
|
||||
for (const dependencyField of [
|
||||
'dependencies',
|
||||
'devDependencies',
|
||||
] /*:: as const */) {
|
||||
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,
|
||||
};
|
||||
Reference in New Issue
Block a user