@rnx-kit/cli 0.17.3 → 0.17.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -20,6 +20,6 @@ export declare function getCoreCommands(): {
20
20
  options?: import("@react-native-community/cli-types").CommandOption<(ctx: BaseConfig) => import("@react-native-community/cli-types").OptionValue>[] | undefined;
21
21
  }[];
22
22
  export declare function uniquify(commands: Command[]): Command[];
23
- export declare function loadContext(userCommand: string, root?: string): Config;
23
+ export declare function loadContextForCommand(userCommand: string, root?: string): Config;
24
24
  export {};
25
25
  //# sourceMappingURL=context.d.ts.map
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getCoreCommands = getCoreCommands;
4
4
  exports.uniquify = uniquify;
5
- exports.loadContext = loadContext;
5
+ exports.loadContextForCommand = loadContextForCommand;
6
6
  const package_1 = require("@rnx-kit/tools-node/package");
7
7
  const cache_1 = require("@rnx-kit/tools-react-native/cache");
8
8
  const context_1 = require("@rnx-kit/tools-react-native/context");
@@ -39,7 +39,7 @@ function uniquify(commands) {
39
39
  }
40
40
  return Object.values(uniqueCommands);
41
41
  }
42
- function loadContext(userCommand, root = process.cwd()) {
42
+ function loadContextForCommand(userCommand, root = process.cwd()) {
43
43
  // The fast path avoids traversing project dependencies because we know what
44
44
  // information our commands depend on.
45
45
  const coreCommands = getCoreCommands();
@@ -76,7 +76,8 @@ function loadContext(userCommand, root = process.cwd()) {
76
76
  throw new Error("Unexpected access to `platforms`");
77
77
  },
78
78
  get project() {
79
- throw new Error("Unexpected access to `project`");
79
+ // Used by the build command
80
+ return (0, context_1.loadContext)(root).project;
80
81
  },
81
82
  };
82
83
  }
@@ -30,7 +30,7 @@ const context_1 = require("./context");
30
30
  const externalCommands_1 = require("./externalCommands");
31
31
  function main() {
32
32
  const [, , userCommand] = process.argv;
33
- const context = (0, context_1.loadContext)(userCommand);
33
+ const context = (0, context_1.loadContextForCommand)(userCommand);
34
34
  const allCommands = context.commands.concat((0, externalCommands_1.findExternalCommands)(context));
35
35
  const program = new commander_1.Command(path.basename(__filename, ".js"));
36
36
  for (const { name, description, detached, options = [], func, } of allCommands) {
@@ -0,0 +1,6 @@
1
+ import type { Config } from "@react-native-community/cli-types";
2
+ import ora from "ora";
3
+ import type { AndroidBuildParams } from "./types";
4
+ export type BuildResult = string | number | null;
5
+ export declare function buildAndroid(config: Config, buildParams: AndroidBuildParams, logger?: ora.Ora): Promise<BuildResult>;
6
+ //# sourceMappingURL=android.d.ts.map
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.buildAndroid = buildAndroid;
7
+ const ora_1 = __importDefault(require("ora"));
8
+ const watcher_1 = require("./watcher");
9
+ function buildAndroid(config, buildParams, logger = (0, ora_1.default)()) {
10
+ const { sourceDir } = config.project.android ?? {};
11
+ if (!sourceDir) {
12
+ logger.fail("No Android project was found");
13
+ process.exitCode = 1;
14
+ return Promise.resolve(null);
15
+ }
16
+ return import("@rnx-kit/tools-android").then(({ assemble }) => {
17
+ return new Promise((resolve) => {
18
+ const gradle = assemble(sourceDir, buildParams);
19
+ (0, watcher_1.watch)(gradle, logger, () => resolve(sourceDir), resolve);
20
+ });
21
+ });
22
+ }
23
+ //# sourceMappingURL=android.js.map
@@ -1,28 +1,9 @@
1
1
  import type { Ora } from "ora";
2
- export type DeviceType = "device" | "emulator" | "simulator";
3
- export type BuildConfiguration = "Debug" | "Release";
4
- type BuildParams = {
5
- platform: "ios" | "visionos";
6
- scheme?: string;
7
- destination?: DeviceType;
8
- configuration?: BuildConfiguration;
9
- archs?: string;
10
- isBuiltRemotely?: boolean;
11
- } | {
12
- platform: "macos";
13
- scheme?: string;
14
- configuration?: BuildConfiguration;
15
- isBuiltRemotely?: boolean;
16
- };
2
+ import type { AppleBuildParams } from "./types";
17
3
  export type BuildArgs = {
18
4
  xcworkspace: string;
19
5
  args: string[];
20
6
  };
21
7
  export type BuildResult = BuildArgs | number | null;
22
- export type InputParams = BuildParams & {
23
- device?: string;
24
- workspace?: string;
25
- };
26
- export declare function runBuild(xcworkspace: string, buildParams: BuildParams, logger: Ora): Promise<BuildResult>;
27
- export {};
8
+ export declare function runBuild(xcworkspace: string, buildParams: AppleBuildParams, logger: Ora): Promise<BuildResult>;
28
9
  //# sourceMappingURL=apple.d.ts.map
@@ -1,29 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runBuild = runBuild;
4
+ const watcher_1 = require("./watcher");
4
5
  function runBuild(xcworkspace, buildParams, logger) {
5
6
  return import("@rnx-kit/tools-apple").then(({ xcodebuild }) => {
6
7
  return new Promise((resolve) => {
7
- logger.start("Building...");
8
- const errors = [];
9
- const proc = xcodebuild(xcworkspace, buildParams, (text) => {
10
- const current = logger.text;
8
+ const onSuccess = () => resolve({ xcworkspace, args: build.spawnargs });
9
+ const build = xcodebuild(xcworkspace, buildParams, (text) => {
11
10
  logger.info(text);
12
- logger.start(current);
13
- });
14
- proc.stdout.on("data", () => (logger.text += "."));
15
- proc.stderr.on("data", (data) => errors.push(data));
16
- proc.on("close", (code) => {
17
- if (code === 0) {
18
- logger.succeed("Build succeeded");
19
- resolve({ xcworkspace, args: proc.spawnargs });
20
- }
21
- else {
22
- logger.fail(Buffer.concat(errors).toString());
23
- process.exitCode = code ?? 1;
24
- resolve(code);
25
- }
26
11
  });
12
+ (0, watcher_1.watch)(build, logger, onSuccess, resolve);
27
13
  });
28
14
  });
29
15
  }
@@ -1,5 +1,6 @@
1
1
  import type { Config } from "@react-native-community/cli-types";
2
2
  import ora from "ora";
3
- import type { BuildResult, InputParams } from "./apple";
4
- export declare function buildIOS(config: Config, buildParams: InputParams, logger?: ora.Ora): Promise<BuildResult>;
3
+ import type { BuildResult } from "./apple";
4
+ import type { AppleInputParams } from "./types";
5
+ export declare function buildIOS(config: Config, buildParams: AppleInputParams, logger?: ora.Ora): Promise<BuildResult>;
5
6
  //# sourceMappingURL=ios.d.ts.map
@@ -1,5 +1,6 @@
1
1
  import type { Config } from "@react-native-community/cli-types";
2
2
  import ora from "ora";
3
- import type { BuildResult, InputParams } from "./apple";
4
- export declare function buildMacOS(_config: Config, { workspace, ...buildParams }: InputParams, logger?: ora.Ora): Promise<BuildResult>;
3
+ import type { BuildResult } from "./apple";
4
+ import type { AppleInputParams } from "./types";
5
+ export declare function buildMacOS(_config: Config, { workspace, ...buildParams }: AppleInputParams, logger?: ora.Ora): Promise<BuildResult>;
5
6
  //# sourceMappingURL=macos.d.ts.map
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Copy of types from `@rnx-kit/tools-apple`. If Jest wasn't such a pain to
3
+ * configure, we would have added an `import type` at the top instead:
4
+ *
5
+ * import type { BuildParams as AndroidBuildParams } from "@rnx-kit/tools-android" with { "resolution-mode": "import" };
6
+ * import type { BuildParams as AppleBuildParams } from "@rnx-kit/tools-apple" with { "resolution-mode": "import" };
7
+ *
8
+ * But Jest doesn't like import attributes and it doesn't matter if we add
9
+ * `@babel/plugin-syntax-import-attributes` in the config.
10
+ *
11
+ * TOOD: Remove this file when we can migrate away from Jest in this package.
12
+ */
13
+ export type DeviceType = "device" | "emulator" | "simulator";
14
+ export type BuildConfiguration = "Debug" | "Release";
15
+ export type AndroidBuildParams = {
16
+ platform: "android";
17
+ destination?: DeviceType;
18
+ configuration?: BuildConfiguration;
19
+ archs?: string;
20
+ };
21
+ export type AppleBuildParams = {
22
+ platform: "ios" | "visionos";
23
+ scheme?: string;
24
+ destination?: DeviceType;
25
+ configuration?: BuildConfiguration;
26
+ archs?: string;
27
+ isBuiltRemotely?: boolean;
28
+ } | {
29
+ platform: "macos";
30
+ scheme?: string;
31
+ configuration?: BuildConfiguration;
32
+ isBuiltRemotely?: boolean;
33
+ };
34
+ export type AndroidInputParams = AndroidBuildParams & {
35
+ device?: string;
36
+ };
37
+ export type AppleInputParams = AppleBuildParams & {
38
+ device?: string;
39
+ workspace?: string;
40
+ };
41
+ export type InputParams = AndroidInputParams | AppleInputParams;
42
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ /**
3
+ * Copy of types from `@rnx-kit/tools-apple`. If Jest wasn't such a pain to
4
+ * configure, we would have added an `import type` at the top instead:
5
+ *
6
+ * import type { BuildParams as AndroidBuildParams } from "@rnx-kit/tools-android" with { "resolution-mode": "import" };
7
+ * import type { BuildParams as AppleBuildParams } from "@rnx-kit/tools-apple" with { "resolution-mode": "import" };
8
+ *
9
+ * But Jest doesn't like import attributes and it doesn't matter if we add
10
+ * `@babel/plugin-syntax-import-attributes` in the config.
11
+ *
12
+ * TOOD: Remove this file when we can migrate away from Jest in this package.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,4 @@
1
+ import type { ChildProcessWithoutNullStreams } from "node:child_process";
2
+ import type { Ora } from "ora";
3
+ export declare function watch(subproc: ChildProcessWithoutNullStreams, logger: Ora, onSuccess: () => void, onFail: (exitCode: number | null) => void): void;
4
+ //# sourceMappingURL=watcher.d.ts.map
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.watch = watch;
4
+ function watch(subproc, logger, onSuccess, onFail) {
5
+ subproc.stdout.on("data", () => (logger.text += "."));
6
+ const errors = [];
7
+ subproc.stderr.on("data", (data) => errors.push(data));
8
+ subproc.on("close", (code) => {
9
+ if (code === 0) {
10
+ logger.succeed("Build succeeded");
11
+ onSuccess();
12
+ }
13
+ else {
14
+ logger.fail(Buffer.concat(errors).toString());
15
+ process.exitCode = code ?? 1;
16
+ onFail(code);
17
+ }
18
+ });
19
+ logger.info(`Command: ${subproc.spawnargs.join(" ")}`);
20
+ logger.start("Building");
21
+ }
22
+ //# sourceMappingURL=watcher.js.map
package/lib/build.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import type { Config } from "@react-native-community/cli-types";
2
- import type { BuildConfiguration, DeviceType, InputParams } from "./build/apple";
2
+ import type { BuildConfiguration, DeviceType, InputParams } from "./build/types";
3
3
  declare function asConfiguration(configuration: string): BuildConfiguration;
4
4
  declare function asDestination(destination: string): DeviceType;
5
5
  declare function asSupportedPlatform(platform: string): InputParams["platform"];
6
- export declare function rnxBuild(_argv: string[], config: Config, buildParams: InputParams): Promise<import("./build/apple").BuildResult>;
6
+ export declare function rnxBuild(_argv: string[], config: Config, buildParams: InputParams): Promise<import("./build/android").BuildResult> | Promise<import("./build/apple").BuildResult>;
7
7
  export declare const rnxBuildCommand: {
8
8
  name: string;
9
9
  description: string;
package/lib/build.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.rnxBuildCommand = void 0;
4
4
  exports.rnxBuild = rnxBuild;
5
5
  const commander_1 = require("commander");
6
+ const android_1 = require("./build/android");
6
7
  const ios_1 = require("./build/ios");
7
8
  const macos_1 = require("./build/macos");
8
9
  function asConfiguration(configuration) {
@@ -26,16 +27,19 @@ function asDestination(destination) {
26
27
  }
27
28
  function asSupportedPlatform(platform) {
28
29
  switch (platform) {
30
+ case "android":
29
31
  case "ios":
30
32
  case "macos":
31
33
  case "visionos":
32
34
  return platform;
33
35
  default:
34
- throw new commander_1.InvalidArgumentError("Supported platforms: 'ios', 'macos', 'visionos'.");
36
+ throw new commander_1.InvalidArgumentError("Supported platforms: 'android', 'ios', 'macos', 'visionos'.");
35
37
  }
36
38
  }
37
39
  function rnxBuild(_argv, config, buildParams) {
38
40
  switch (buildParams.platform) {
41
+ case "android":
42
+ return (0, android_1.buildAndroid)(config, buildParams);
39
43
  case "ios":
40
44
  case "visionos":
41
45
  return (0, ios_1.buildIOS)(config, buildParams);
@@ -49,7 +53,7 @@ exports.rnxBuildCommand = {
49
53
  func: rnxBuild,
50
54
  options: [
51
55
  {
52
- name: "--platform <string>",
56
+ name: "-p, --platform <string>",
53
57
  description: "Target platform",
54
58
  parse: asSupportedPlatform,
55
59
  },
@@ -59,7 +63,7 @@ exports.rnxBuildCommand = {
59
63
  },
60
64
  {
61
65
  name: "--scheme <string>",
62
- description: "Name of scheme to build",
66
+ description: "Name of scheme to build (Apple platforms only)",
63
67
  },
64
68
  {
65
69
  name: "--configuration <string>",
@@ -19,5 +19,5 @@ export declare function getTargetPlatforms(overridePlatform?: AllPlatforms, targ
19
19
  * @param overridePlatform Override platform, typically from the command-line. When given, this overrides the list of target platforms.
20
20
  * @returns Array of platform-specific bundle configurations
21
21
  */
22
- export declare function getCliPlatformBundleConfigs(id?: string, overridePlatform?: AllPlatforms): CliPlatformBundleConfig[];
22
+ export declare function getCliPlatformBundleConfigs(id?: string, overridePlatform?: AllPlatforms, kitConfig?: import("@rnx-kit/config").KitConfig | undefined): CliPlatformBundleConfig[];
23
23
  //# sourceMappingURL=kit-config.d.ts.map
@@ -39,8 +39,7 @@ function getDefaultBundleParameters(platform) {
39
39
  * @param overridePlatform Override platform, typically from the command-line. When given, this overrides the list of target platforms.
40
40
  * @returns Array of platform-specific bundle configurations
41
41
  */
42
- function getCliPlatformBundleConfigs(id, overridePlatform) {
43
- const kitConfig = (0, config_1.getKitConfig)();
42
+ function getCliPlatformBundleConfigs(id, overridePlatform, kitConfig = (0, config_1.getKitConfig)()) {
44
43
  const maybeBundleConfig = kitConfig
45
44
  ? (0, config_1.getBundleConfig)(kitConfig, id)
46
45
  : undefined;
@@ -1,5 +1,6 @@
1
1
  import { bundle } from "@rnx-kit/metro-service";
2
2
  import type { ConfigT } from "metro-config";
3
+ import * as nodefs from "node:fs";
3
4
  import type { CliPlatformBundleConfig } from "./types";
4
5
  /**
5
6
  * Run the Metro bundler.
@@ -13,5 +14,5 @@ import type { CliPlatformBundleConfig } from "./types";
13
14
  * @param minify Optionally choose whether or not the bundle is minified. When not set, minification is controlled by the `dev` property.
14
15
  * @param output Output bundle format; defaults to plain JS
15
16
  */
16
- export declare function metroBundle(metroConfig: ConfigT, bundleConfig: CliPlatformBundleConfig, dev: boolean, minify?: boolean, output?: typeof bundle): Promise<void>;
17
+ export declare function metroBundle(metroConfig: ConfigT, bundleConfig: CliPlatformBundleConfig, dev: boolean, minify?: boolean, output?: typeof bundle, fs?: typeof nodefs): Promise<void>;
17
18
  //# sourceMappingURL=metro.d.ts.map
@@ -26,6 +26,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.metroBundle = metroBundle;
27
27
  const console_1 = require("@rnx-kit/console");
28
28
  const metro_service_1 = require("@rnx-kit/metro-service");
29
+ const nodefs = __importStar(require("node:fs"));
29
30
  const path = __importStar(require("node:path"));
30
31
  const filesystem_1 = require("../helpers/filesystem");
31
32
  const metro_config_1 = require("../helpers/metro-config");
@@ -41,7 +42,7 @@ const metro_config_1 = require("../helpers/metro-config");
41
42
  * @param minify Optionally choose whether or not the bundle is minified. When not set, minification is controlled by the `dev` property.
42
43
  * @param output Output bundle format; defaults to plain JS
43
44
  */
44
- async function metroBundle(metroConfig, bundleConfig, dev, minify, output = metro_service_1.bundle) {
45
+ async function metroBundle(metroConfig, bundleConfig, dev, minify, output = metro_service_1.bundle, fs = nodefs) {
45
46
  (0, console_1.info)(`Bundling ${bundleConfig.platform}...`);
46
47
  if (!dev && bundleConfig.treeShake) {
47
48
  if (minify != null) {
@@ -63,12 +64,12 @@ async function metroBundle(metroConfig, bundleConfig, dev, minify, output = metr
63
64
  minify,
64
65
  };
65
66
  // ensure all output directories exist
66
- (0, filesystem_1.ensureDir)(path.dirname(metroBundleArgs.bundleOutput));
67
+ (0, filesystem_1.ensureDir)(path.dirname(metroBundleArgs.bundleOutput), fs);
67
68
  if (metroBundleArgs.sourcemapOutput) {
68
- (0, filesystem_1.ensureDir)(path.dirname(metroBundleArgs.sourcemapOutput));
69
+ (0, filesystem_1.ensureDir)(path.dirname(metroBundleArgs.sourcemapOutput), fs);
69
70
  }
70
71
  if (metroBundleArgs.assetsDest) {
71
- (0, filesystem_1.ensureDir)(metroBundleArgs.assetsDest);
72
+ (0, filesystem_1.ensureDir)(metroBundleArgs.assetsDest, fs);
72
73
  }
73
74
  // create the bundle
74
75
  await output(metroBundleArgs, metroConfig);
@@ -2,7 +2,7 @@ import type { Config as CLIConfig } from "@react-native-community/cli-types";
2
2
  import type { PackageManifest } from "@rnx-kit/tools-node/package";
3
3
  import type { AllPlatforms } from "@rnx-kit/tools-react-native";
4
4
  import { parsePlatform } from "@rnx-kit/tools-react-native";
5
- import * as nodefs from "fs";
5
+ import * as nodefs from "node:fs";
6
6
  export type AndroidArchive = {
7
7
  targetName?: string;
8
8
  version?: string;
@@ -42,10 +42,10 @@ export type Context = {
42
42
  export type AssetsConfig = {
43
43
  getAssets?: (context: Context) => Promise<NativeAssets>;
44
44
  };
45
- export declare function versionOf(pkgName: string): string;
46
- export declare function assembleAarBundle(context: Context, packageName: string, { aar }: NativeAssets): Promise<void>;
45
+ export declare function versionOf(pkgName: string, fs?: typeof nodefs): string;
46
+ export declare function assembleAarBundle(context: Context, packageName: string, { aar }: NativeAssets, fs?: typeof nodefs): Promise<void>;
47
47
  export declare function copyAssets({ options: { assetsDest, xcassetsDest } }: Context, packageName: string, { assets, strings, xcassets }: NativeAssets, fs?: typeof nodefs): Promise<void>;
48
- export declare function gatherConfigs({ projectRoot, manifest, }: Context): Promise<Record<string, AssetsConfig | null> | undefined>;
48
+ export declare function gatherConfigs({ projectRoot, manifest }: Context, fs?: typeof nodefs): Promise<Record<string, AssetsConfig | null> | undefined>;
49
49
  /**
50
50
  * Copies additional assets not picked by bundlers into desired directory.
51
51
  *
@@ -99,7 +99,7 @@ export declare function gatherConfigs({ projectRoot, manifest, }: Context): Prom
99
99
  *
100
100
  * @param options Options dictate what gets copied where
101
101
  */
102
- export declare function copyProjectAssets(options: Options, { root: projectRoot, reactNativePath }: CLIConfig): Promise<void>;
102
+ export declare function copyProjectAssets(options: Options, { root: projectRoot, reactNativePath }: CLIConfig, fs?: typeof nodefs): Promise<void>;
103
103
  export declare const rnxCopyAssetsCommand: {
104
104
  name: string;
105
105
  description: string;
@@ -34,11 +34,10 @@ const properties_1 = require("@rnx-kit/tools-language/properties");
34
34
  const package_1 = require("@rnx-kit/tools-node/package");
35
35
  const path_1 = require("@rnx-kit/tools-node/path");
36
36
  const tools_react_native_1 = require("@rnx-kit/tools-react-native");
37
- const child_process_1 = require("child_process");
38
- const fs = __importStar(require("fs"));
39
- const nodefs = __importStar(require("fs"));
40
- const os = __importStar(require("os"));
41
- const path = __importStar(require("path"));
37
+ const node_child_process_1 = require("node:child_process");
38
+ const nodefs = __importStar(require("node:fs"));
39
+ const os = __importStar(require("node:os"));
40
+ const path = __importStar(require("node:path"));
42
41
  const filesystem_1 = require("./helpers/filesystem");
43
42
  const defaultAndroidConfig = {
44
43
  androidPluginVersion: "7.2.2",
@@ -49,7 +48,7 @@ const defaultAndroidConfig = {
49
48
  },
50
49
  kotlinVersion: "1.7.22",
51
50
  };
52
- function cloneFile(src, dest) {
51
+ function cloneFile(src, dest, fs = nodefs) {
53
52
  return fs.promises.copyFile(src, dest, fs.constants.COPYFILE_FICLONE);
54
53
  }
55
54
  function cp_r(source, destination, fs = nodefs) {
@@ -61,7 +60,7 @@ function ensureOption(options, opt, flag = opt) {
61
60
  process.exit(1);
62
61
  }
63
62
  }
64
- function findGradleProject(projectRoot) {
63
+ function findGradleProject(projectRoot, fs = nodefs) {
65
64
  if (fs.existsSync(path.join(projectRoot, "android", "build.gradle"))) {
66
65
  return path.join(projectRoot, "android");
67
66
  }
@@ -76,21 +75,21 @@ function gradleTargetName(packageName) {
76
75
  function isAssetsConfig(config) {
77
76
  return typeof config === "object" && config !== null && "getAssets" in config;
78
77
  }
79
- function versionOf(pkgName) {
80
- const packageDir = (0, package_1.findPackageDependencyDir)(pkgName);
78
+ function versionOf(pkgName, fs = nodefs) {
79
+ const packageDir = (0, package_1.findPackageDependencyDir)(pkgName, undefined, fs);
81
80
  if (!packageDir) {
82
81
  throw new Error(`Could not find module '${pkgName}'`);
83
82
  }
84
- const { version } = (0, package_1.readPackage)(packageDir);
83
+ const { version } = (0, package_1.readPackage)(packageDir, fs);
85
84
  return version;
86
85
  }
87
- function getAndroidPaths(context, packageName, { targetName, version, output }) {
88
- const projectRoot = (0, package_1.findPackageDependencyDir)(packageName);
86
+ function getAndroidPaths(context, packageName, { targetName, version, output }, fs = nodefs) {
87
+ const projectRoot = (0, package_1.findPackageDependencyDir)(packageName, undefined, fs);
89
88
  if (!projectRoot) {
90
89
  throw new Error(`Could not find module '${packageName}'`);
91
90
  }
92
91
  const gradleFriendlyName = targetName || gradleTargetName(packageName);
93
- const aarVersion = version || versionOf(packageName);
92
+ const aarVersion = version || versionOf(packageName, fs);
94
93
  switch (packageName) {
95
94
  case "hermes-engine":
96
95
  return {
@@ -98,7 +97,7 @@ function getAndroidPaths(context, packageName, { targetName, version, output })
98
97
  version: aarVersion,
99
98
  projectRoot,
100
99
  output: path.join(projectRoot, "android", "hermes-release.aar"),
101
- destination: path.join(context.options.assetsDest, "aar", `hermes-release-${versionOf(packageName)}.aar`),
100
+ destination: path.join(context.options.assetsDest, "aar", `hermes-release-${versionOf(packageName, fs)}.aar`),
102
101
  };
103
102
  case "react-native":
104
103
  return {
@@ -109,7 +108,7 @@ function getAndroidPaths(context, packageName, { targetName, version, output })
109
108
  destination: path.join(context.options.assetsDest, "aar", "react-native"),
110
109
  };
111
110
  default: {
112
- const androidProject = findGradleProject(projectRoot);
111
+ const androidProject = findGradleProject(projectRoot, fs);
113
112
  return {
114
113
  targetName: gradleFriendlyName,
115
114
  version: aarVersion,
@@ -124,22 +123,22 @@ function getAndroidPaths(context, packageName, { targetName, version, output })
124
123
  }
125
124
  }
126
125
  function run(command, args, options) {
127
- const { status } = (0, child_process_1.spawnSync)(command, args, options);
126
+ const { status } = (0, node_child_process_1.spawnSync)(command, args, options);
128
127
  if (status !== 0) {
129
128
  process.exit(status || 1);
130
129
  }
131
130
  }
132
- async function assembleAarBundle(context, packageName, { aar }) {
131
+ async function assembleAarBundle(context, packageName, { aar }, fs = nodefs) {
133
132
  if (!aar) {
134
133
  return;
135
134
  }
136
135
  const wrapper = os.platform() === "win32" ? "gradlew.bat" : "gradlew";
137
- const gradlew = (0, path_1.findUp)(wrapper);
136
+ const gradlew = (0, path_1.findUp)(wrapper, undefined, fs);
138
137
  if (!gradlew) {
139
138
  (0, console_1.warn)(`Skipped \`${packageName}\`: cannot find \`${wrapper}\``);
140
139
  return;
141
140
  }
142
- const { targetName, version, androidProject, output } = getAndroidPaths(context, packageName, aar);
141
+ const { targetName, version, androidProject, output } = getAndroidPaths(context, packageName, aar, fs);
143
142
  if (!androidProject || !output) {
144
143
  (0, console_1.warn)(`Skipped \`${packageName}\`: cannot find \`build.gradle\``);
145
144
  return;
@@ -147,7 +146,7 @@ async function assembleAarBundle(context, packageName, { aar }) {
147
146
  const { env: customEnv, dependencies, android } = aar;
148
147
  const env = {
149
148
  NODE_MODULES_PATH: path.join(process.cwd(), "node_modules"),
150
- REACT_NATIVE_VERSION: versionOf("react-native"),
149
+ REACT_NATIVE_VERSION: versionOf("react-native", fs),
151
150
  ...process.env,
152
151
  ...customEnv,
153
152
  };
@@ -160,7 +159,7 @@ async function assembleAarBundle(context, packageName, { aar }) {
160
159
  if (fs.existsSync(settings)) {
161
160
  if (dependencies) {
162
161
  for (const [dependencyName, aar] of Object.entries(dependencies)) {
163
- const { targetName, output, destination } = getAndroidPaths(context, dependencyName, aar);
162
+ const { targetName, output, destination } = getAndroidPaths(context, dependencyName, aar, fs);
164
163
  if (output) {
165
164
  if (!fs.existsSync(output)) {
166
165
  targets.push(`:${targetName}:assembleRelease`);
@@ -232,7 +231,7 @@ async function assembleAarBundle(context, packageName, { aar }) {
232
231
  // Run only one Gradle task at a time
233
232
  run(gradlew, targets, { cwd: buildDir, stdio: "inherit", env });
234
233
  }
235
- await Promise.all(targetsToCopy.map(([src, dest]) => cloneFile(src, dest)));
234
+ await Promise.all(targetsToCopy.map(([src, dest]) => cloneFile(src, dest, fs)));
236
235
  }
237
236
  function copyFiles(files, destination, fs = nodefs) {
238
237
  if (!Array.isArray(files) || files.length === 0) {
@@ -253,7 +252,7 @@ async function copyAssets({ options: { assetsDest, xcassetsDest } }, packageName
253
252
  }
254
253
  await Promise.all(tasks);
255
254
  }
256
- async function gatherConfigs({ projectRoot, manifest, }) {
255
+ async function gatherConfigs({ projectRoot, manifest }, fs = nodefs) {
257
256
  const { dependencies, devDependencies } = manifest;
258
257
  const packages = [...(0, properties_1.keysOf)(dependencies), ...(0, properties_1.keysOf)(devDependencies)];
259
258
  if (packages.length === 0) {
@@ -342,10 +341,10 @@ async function gatherConfigs({ projectRoot, manifest, }) {
342
341
  *
343
342
  * @param options Options dictate what gets copied where
344
343
  */
345
- async function copyProjectAssets(options, { root: projectRoot, reactNativePath }) {
344
+ async function copyProjectAssets(options, { root: projectRoot, reactNativePath }, fs = nodefs) {
346
345
  const manifest = (0, package_1.readPackage)(projectRoot);
347
346
  const context = { projectRoot, manifest, options, reactNativePath };
348
- const assetConfigs = await gatherConfigs(context);
347
+ const assetConfigs = await gatherConfigs(context, fs);
349
348
  if (!assetConfigs) {
350
349
  return;
351
350
  }
@@ -362,22 +361,22 @@ async function copyProjectAssets(options, { root: projectRoot, reactNativePath }
362
361
  const assets = await getAssets(context);
363
362
  if (options.bundleAar && assets.aar) {
364
363
  (0, console_1.info)(`Assembling "${packageName}"`);
365
- await assembleAarBundle(context, packageName, assets);
364
+ await assembleAarBundle(context, packageName, assets, fs);
366
365
  }
367
366
  else {
368
367
  (0, console_1.info)(`Copying assets for "${packageName}"`);
369
- await copyAssets(context, packageName, assets);
368
+ await copyAssets(context, packageName, assets, fs);
370
369
  }
371
370
  }
372
371
  if (options.bundleAar) {
373
372
  const dummyAar = { targetName: "dummy" };
374
373
  const copyTasks = [];
375
374
  for (const dependencyName of ["hermes-engine", "react-native"]) {
376
- const { output, destination } = getAndroidPaths(context, dependencyName, dummyAar);
375
+ const { output, destination } = getAndroidPaths(context, dependencyName, dummyAar, fs);
377
376
  if (output &&
378
377
  (!fs.existsSync(destination) || fs.statSync(destination).isDirectory())) {
379
378
  (0, console_1.info)(`Copying Android Archive of "${dependencyName}"`);
380
- copyTasks.push(cloneFile(output, destination));
379
+ copyTasks.push(cloneFile(output, destination, fs));
381
380
  }
382
381
  }
383
382
  await Promise.all(copyTasks);
@@ -389,7 +388,7 @@ exports.rnxCopyAssetsCommand = {
389
388
  func: (_argv, config, options) => {
390
389
  ensureOption(options, "platform");
391
390
  ensureOption(options, "assetsDest", "assets-dest");
392
- return copyProjectAssets(options, config);
391
+ return copyProjectAssets(options, config, nodefs);
393
392
  },
394
393
  options: [
395
394
  {
@@ -1,3 +1,3 @@
1
- import * as nodefs from "fs";
1
+ import * as nodefs from "node:fs";
2
2
  export declare function ensureDir(p: string, fs?: typeof nodefs): void;
3
3
  //# sourceMappingURL=filesystem.d.ts.map
@@ -24,7 +24,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.ensureDir = ensureDir;
27
- const nodefs = __importStar(require("fs")); // Cannot use `node:fs` because of Jest mocks
27
+ const nodefs = __importStar(require("node:fs"));
28
28
  function ensureDir(p, fs = nodefs) {
29
29
  fs.mkdirSync(p, { recursive: true, mode: 0o755 });
30
30
  }
package/lib/index.js CHANGED
@@ -2,10 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.rnxWriteThirdPartyNoticesCommand = exports.rnxWriteThirdPartyNotices = exports.rnxTestCommand = exports.rnxTest = exports.rnxStartCommand = exports.rnxStart = exports.rnxRunCommand = exports.rnxRun = exports.rnxRamBundleCommand = exports.rnxRamBundle = exports.rnxCopyAssetsCommand = exports.copyProjectAssets = exports.rnxCleanCommand = exports.rnxClean = exports.rnxBundleCommand = exports.rnxBundle = exports.rnxBuildCommand = exports.rnxBuild = exports.rnxAlignDepsCommand = exports.rnxAlignDeps = exports.reactNativeConfig = void 0;
4
4
  const align_deps_1 = require("./align-deps");
5
+ const build_1 = require("./build");
5
6
  const bundle_1 = require("./bundle");
6
7
  const clean_1 = require("./clean");
7
8
  const copy_assets_1 = require("./copy-assets");
8
9
  const ram_bundle_1 = require("./ram-bundle");
10
+ const run_1 = require("./run");
9
11
  const start_1 = require("./start");
10
12
  const test_1 = require("./test");
11
13
  const write_third_party_notices_1 = require("./write-third-party-notices");
@@ -14,6 +16,8 @@ exports.reactNativeConfig = {
14
16
  bundle_1.rnxBundleCommand,
15
17
  ram_bundle_1.rnxRamBundleCommand,
16
18
  start_1.rnxStartCommand,
19
+ build_1.rnxBuildCommand,
20
+ run_1.rnxRunCommand,
17
21
  copy_assets_1.rnxCopyAssetsCommand,
18
22
  align_deps_1.rnxAlignDepsCommand,
19
23
  test_1.rnxTestCommand,
@@ -24,9 +28,9 @@ exports.reactNativeConfig = {
24
28
  var align_deps_2 = require("./align-deps");
25
29
  Object.defineProperty(exports, "rnxAlignDeps", { enumerable: true, get: function () { return align_deps_2.rnxAlignDeps; } });
26
30
  Object.defineProperty(exports, "rnxAlignDepsCommand", { enumerable: true, get: function () { return align_deps_2.rnxAlignDepsCommand; } });
27
- var build_1 = require("./build");
28
- Object.defineProperty(exports, "rnxBuild", { enumerable: true, get: function () { return build_1.rnxBuild; } });
29
- Object.defineProperty(exports, "rnxBuildCommand", { enumerable: true, get: function () { return build_1.rnxBuildCommand; } });
31
+ var build_2 = require("./build");
32
+ Object.defineProperty(exports, "rnxBuild", { enumerable: true, get: function () { return build_2.rnxBuild; } });
33
+ Object.defineProperty(exports, "rnxBuildCommand", { enumerable: true, get: function () { return build_2.rnxBuildCommand; } });
30
34
  var bundle_2 = require("./bundle");
31
35
  Object.defineProperty(exports, "rnxBundle", { enumerable: true, get: function () { return bundle_2.rnxBundle; } });
32
36
  Object.defineProperty(exports, "rnxBundleCommand", { enumerable: true, get: function () { return bundle_2.rnxBundleCommand; } });
@@ -39,9 +43,9 @@ Object.defineProperty(exports, "rnxCopyAssetsCommand", { enumerable: true, get:
39
43
  var ram_bundle_2 = require("./ram-bundle");
40
44
  Object.defineProperty(exports, "rnxRamBundle", { enumerable: true, get: function () { return ram_bundle_2.rnxRamBundle; } });
41
45
  Object.defineProperty(exports, "rnxRamBundleCommand", { enumerable: true, get: function () { return ram_bundle_2.rnxRamBundleCommand; } });
42
- var run_1 = require("./run");
43
- Object.defineProperty(exports, "rnxRun", { enumerable: true, get: function () { return run_1.rnxRun; } });
44
- Object.defineProperty(exports, "rnxRunCommand", { enumerable: true, get: function () { return run_1.rnxRunCommand; } });
46
+ var run_2 = require("./run");
47
+ Object.defineProperty(exports, "rnxRun", { enumerable: true, get: function () { return run_2.rnxRun; } });
48
+ Object.defineProperty(exports, "rnxRunCommand", { enumerable: true, get: function () { return run_2.rnxRunCommand; } });
45
49
  var start_2 = require("./start");
46
50
  Object.defineProperty(exports, "rnxStart", { enumerable: true, get: function () { return start_2.rnxStart; } });
47
51
  Object.defineProperty(exports, "rnxStartCommand", { enumerable: true, get: function () { return start_2.rnxStartCommand; } });
@@ -0,0 +1,4 @@
1
+ import type { Config } from "@react-native-community/cli-types";
2
+ import type { AndroidInputParams } from "../build/types";
3
+ export declare function runAndroid(config: Config, buildParams: AndroidInputParams): Promise<void>;
4
+ //# sourceMappingURL=android.d.ts.map
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.runAndroid = runAndroid;
30
+ const path = __importStar(require("node:path"));
31
+ const ora_1 = __importDefault(require("ora"));
32
+ const android_1 = require("../build/android");
33
+ async function runAndroid(config, buildParams) {
34
+ const logger = (0, ora_1.default)();
35
+ const projectDir = await (0, android_1.buildAndroid)(config, buildParams, logger);
36
+ if (typeof projectDir !== "string") {
37
+ return;
38
+ }
39
+ logger.start("Preparing to launch app");
40
+ const { findOutputFile, getPackageName, install, selectDevice, start } = await import("@rnx-kit/tools-android");
41
+ const { configuration = "Debug" } = buildParams;
42
+ const apks = findOutputFile(projectDir, configuration);
43
+ if (apks.length === 0) {
44
+ logger.fail("Failed to find the APK that was just built");
45
+ process.exitCode = 1;
46
+ return;
47
+ }
48
+ if (apks.length > 1) {
49
+ const currentStatus = logger.text;
50
+ const choices = apks.map((p) => path.basename(p)).join(", ");
51
+ logger.info(`Multiple APKs were found; picking the first one: ${choices}`);
52
+ logger.info("If this is wrong, remove the others and try again");
53
+ logger.start(currentStatus);
54
+ }
55
+ const apk = apks[0];
56
+ const info = getPackageName(apk);
57
+ if (info instanceof Error) {
58
+ logger.fail(info.message);
59
+ process.exitCode = 1;
60
+ return;
61
+ }
62
+ const device = await selectDevice(buildParams.device, logger);
63
+ if (!device) {
64
+ logger.fail("Failed to launch app: Could not find an appropriate device");
65
+ process.exitCode = 1;
66
+ return;
67
+ }
68
+ logger.start(`Installing ${apk}`);
69
+ const { packageName, activityName } = info;
70
+ const error = await install(device, apk, packageName);
71
+ if (error) {
72
+ logger.fail(error.message);
73
+ process.exitCode = 1;
74
+ return;
75
+ }
76
+ logger.text = `Starting ${packageName}`;
77
+ await start(device, packageName, activityName);
78
+ logger.succeed(`Started ${packageName}`);
79
+ }
80
+ //# sourceMappingURL=android.js.map
package/lib/run/ios.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import type { Config } from "@react-native-community/cli-types";
2
- import type { InputParams } from "../build/apple";
2
+ import type { InputParams } from "../build/types";
3
3
  export declare function runIOS(config: Config, buildParams: InputParams): Promise<void>;
4
4
  //# sourceMappingURL=ios.d.ts.map
package/lib/run/ios.js CHANGED
@@ -40,7 +40,7 @@ async function runIOS(config, buildParams) {
40
40
  if (!result || typeof result !== "object") {
41
41
  return;
42
42
  }
43
- logger.start("Preparing to launch app...");
43
+ logger.start("Preparing to launch app");
44
44
  const { getBuildSettings, getDevicePlatformIdentifier, install, launch, selectDevice, } = await import("@rnx-kit/tools-apple");
45
45
  const { destination = "simulator", device: deviceName } = buildParams;
46
46
  const deviceOrPlatformIdentifier = deviceName ?? getDevicePlatformIdentifier(buildParams);
@@ -60,7 +60,7 @@ async function runIOS(config, buildParams) {
60
60
  }
61
61
  const { EXECUTABLE_FOLDER_PATH, FULL_PRODUCT_NAME, TARGET_BUILD_DIR } = settings.buildSettings;
62
62
  const app = path.join(TARGET_BUILD_DIR, EXECUTABLE_FOLDER_PATH);
63
- logger.start(`Installing '${FULL_PRODUCT_NAME}' on ${device.name}...`);
63
+ logger.start(`Installing '${FULL_PRODUCT_NAME}' on ${device.name}`);
64
64
  const installError = await install(device, app);
65
65
  if (installError) {
66
66
  logger.fail(installError.message);
@@ -1,4 +1,4 @@
1
1
  import type { Config } from "@react-native-community/cli-types";
2
- import type { InputParams } from "../build/apple";
3
- export declare function runMacOS(config: Config, buildParams: InputParams): Promise<void>;
2
+ import type { AppleInputParams } from "../build/types";
3
+ export declare function runMacOS(config: Config, buildParams: AppleInputParams): Promise<void>;
4
4
  //# sourceMappingURL=macos.d.ts.map
package/lib/run/macos.js CHANGED
@@ -37,7 +37,7 @@ async function runMacOS(config, buildParams) {
37
37
  return;
38
38
  }
39
39
  const { getBuildSettings, open } = await import("@rnx-kit/tools-apple");
40
- logger.start("Launching app...");
40
+ logger.start("Launching app");
41
41
  const settings = await getBuildSettings(result.xcworkspace, result.args);
42
42
  if (!settings) {
43
43
  logger.fail("Failed to launch app: Could not get build settings");
@@ -46,7 +46,7 @@ async function runMacOS(config, buildParams) {
46
46
  }
47
47
  const { FULL_PRODUCT_NAME, TARGET_BUILD_DIR } = settings.buildSettings;
48
48
  const appPath = path.join(TARGET_BUILD_DIR, FULL_PRODUCT_NAME);
49
- logger.text = `Launching '${FULL_PRODUCT_NAME}'...`;
49
+ logger.text = `Launching '${FULL_PRODUCT_NAME}'`;
50
50
  const { stderr, status } = await open(appPath);
51
51
  if (status !== 0) {
52
52
  logger.fail(`Failed to launch app: ${stderr}`);
package/lib/run.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { Config } from "@react-native-community/cli-types";
2
- import type { InputParams } from "./build/apple";
2
+ import type { InputParams } from "./build/types";
3
3
  export declare function rnxRun(_argv: string[], config: Config, buildParams: InputParams): Promise<void>;
4
4
  export declare const rnxRunCommand: {
5
5
  name: string;
@@ -19,12 +19,12 @@ export declare const rnxRunCommand: {
19
19
  name: string;
20
20
  description: string;
21
21
  default: string;
22
- parse: (configuration: string) => import("./build/apple").BuildConfiguration;
22
+ parse: (configuration: string) => import("./build/types").BuildConfiguration;
23
23
  } | {
24
24
  name: string;
25
25
  description: string;
26
26
  default: string;
27
- parse: (destination: string) => import("./build/apple").DeviceType;
27
+ parse: (destination: string) => import("./build/types").DeviceType;
28
28
  })[];
29
29
  };
30
30
  //# sourceMappingURL=run.d.ts.map
package/lib/run.js CHANGED
@@ -3,10 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.rnxRunCommand = void 0;
4
4
  exports.rnxRun = rnxRun;
5
5
  const build_1 = require("./build");
6
+ const android_1 = require("./run/android");
6
7
  const ios_1 = require("./run/ios");
7
8
  const macos_1 = require("./run/macos");
8
9
  function rnxRun(_argv, config, buildParams) {
9
10
  switch (buildParams.platform) {
11
+ case "android":
12
+ return (0, android_1.runAndroid)(config, buildParams);
10
13
  case "ios":
11
14
  case "visionos":
12
15
  return (0, ios_1.runIOS)(config, buildParams);
@@ -21,7 +24,7 @@ exports.rnxRunCommand = {
21
24
  options: [
22
25
  ...build_1.rnxBuildCommand.options,
23
26
  {
24
- name: "--device <string>",
27
+ name: "-d, --device <string>",
25
28
  description: "The name of the device to launch the app in",
26
29
  },
27
30
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rnx-kit/cli",
3
- "version": "0.17.3",
3
+ "version": "0.17.5",
4
4
  "description": "Command-line interface for working with kit packages in your repo",
5
5
  "homepage": "https://github.com/microsoft/rnx-kit/tree/main/packages/cli#readme",
6
6
  "license": "MIT",
@@ -40,7 +40,7 @@
40
40
  "test": "rnx-kit-scripts test"
41
41
  },
42
42
  "dependencies": {
43
- "@rnx-kit/align-deps": "^2.5.2",
43
+ "@rnx-kit/align-deps": "^2.5.4",
44
44
  "@rnx-kit/config": "^0.6.6",
45
45
  "@rnx-kit/console": "^1.1.0",
46
46
  "@rnx-kit/metro-plugin-cyclic-dependencies-detector": "^1.1.1",
@@ -50,6 +50,7 @@
50
50
  "@rnx-kit/metro-serializer-esbuild": "^0.1.38",
51
51
  "@rnx-kit/metro-service": "^3.1.6",
52
52
  "@rnx-kit/third-party-notices": "^1.3.4",
53
+ "@rnx-kit/tools-android": "^0.1.1",
53
54
  "@rnx-kit/tools-apple": "^0.1.2",
54
55
  "@rnx-kit/tools-language": "^2.0.0",
55
56
  "@rnx-kit/tools-node": "^2.1.1",