Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tools-react-native): add additional platform helpers #3490

Merged
merged 8 commits into from
Jan 25, 2025
6 changes: 6 additions & 0 deletions .changeset/short-singers-doubt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@rnx-kit/tools-react-native": patch
---

Add additional platform helpers for react-native related to platform names and
suffixes
29 changes: 16 additions & 13 deletions packages/tools-react-native/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,21 @@ import * as platformTools from "@rnx-kit/tools-react-native/platform";
| -------- | ------------ | ----------------------------------------- |
| platform | AllPlatforms | List of supported react-native platforms. |

| Category | Function | Description |
| -------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| context | `loadContext(projectRoot)` | Equivalent to calling `loadConfig()` from `@react-native-community/cli`, but the result is cached for faster subsequent accesses. |
| context | `loadContextAsync(projectRoot)` | Equivalent to calling `loadConfigAsync()` (with fallback to `loadConfig()`) from `@react-native-community/cli`, but the result is cached for faster subsequent accesses. |
| context | `resolveCommunityCLI(root, reactNativePath)` | Finds path to `@react-native-community/cli`. |
| metro | `findMetroPath(projectRoot)` | Finds the installation path of Metro. |
| metro | `getMetroVersion(projectRoot)` | Returns Metro version number. |
| metro | `requireModuleFromMetro(moduleName, fromDir)` | Imports specified module starting from the installation directory of the currently used `metro` version. |
| platform | `expandPlatformExtensions(platform, extensions)` | Returns a list of extensions that should be tried for the target platform in prioritized order. |
| platform | `getAvailablePlatforms(startDir)` | Returns a map of available React Native platforms. The result is cached. |
| platform | `getAvailablePlatformsUncached(startDir, platformMap)` | Returns a map of available React Native platforms. The result is NOT cached. |
| platform | `parsePlatform(val)` | Parse a string to ensure it maps to a valid react-native platform. |
| platform | `platformExtensions(platform)` | Returns file extensions that can be mapped to the target platform. |
| Category | Function | Description |
| -------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| context | `loadContext(projectRoot)` | Equivalent to calling `loadConfig()` from `@react-native-community/cli`, but the result is cached for faster subsequent accesses. |
| context | `loadContextAsync(projectRoot)` | Equivalent to calling `loadConfigAsync()` (with fallback to `loadConfig()`) from `@react-native-community/cli`, but the result is cached for faster subsequent accesses. |
| context | `resolveCommunityCLI(root, reactNativePath)` | Finds path to `@react-native-community/cli`. |
| metro | `findMetroPath(projectRoot)` | Finds the installation path of Metro. |
| metro | `getMetroVersion(projectRoot)` | Returns Metro version number. |
| metro | `requireModuleFromMetro(moduleName, fromDir)` | Imports specified module starting from the installation directory of the currently used `metro` version. |
| platform | `expandPlatformExtensions(platform, extensions)` | Returns a list of extensions that should be tried for the target platform in prioritized order. |
| platform | `getAvailablePlatforms(startDir)` | Returns a map of available React Native platforms. The result is cached. |
| platform | `getAvailablePlatformsUncached(startDir, platformMap)` | Returns a map of available React Native platforms. The result is NOT cached. |
| platform | `getModuleSuffixes(platform, appendEmpty)` | Get the module suffixes array for a given platform, suitable for use with TypeScript's moduleSuffixes setting in the form of ['.ios', '.native', ''] or ['.windows', '.win', '.native', ''] or similar |
| platform | `parsePlatform(val)` | Parse a string to ensure it maps to a valid react-native platform. |
| platform | `platformExtensions(platform)` | Returns file extensions that can be mapped to the target platform. |
| platform | `platformValues()` | |
| platform | `tryParsePlatform(val)` | |

<!-- @rnx-kit/api end -->
3 changes: 3 additions & 0 deletions packages/tools-react-native/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ export {
expandPlatformExtensions,
getAvailablePlatforms,
getAvailablePlatformsUncached,
getModuleSuffixes,
parsePlatform,
platformExtensions,
platformValues,
tryParsePlatform,
} from "./platform";
export type { AllPlatforms } from "./platform";
67 changes: 56 additions & 11 deletions packages/tools-react-native/src/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,23 @@ import { readReactNativeConfig } from "./context";
/**
* List of supported react-native platforms.
*/
export type AllPlatforms = "android" | "ios" | "macos" | "win32" | "windows";
export type AllPlatforms =
| "android"
| "ios"
| "macos"
| "win32"
| "windows"
| "visionos";

// Possible values for AllPlatforms
const allValues: AllPlatforms[] = [
"android",
"ios",
"macos",
"win32",
"windows",
"visionos",
];

/**
* Returns a list of extensions that should be tried for the target platform in
Expand All @@ -30,6 +46,25 @@ export function expandPlatformExtensions(
return expanded;
}

/**
* Get the module suffixes array for a given platform, suitable for use with TypeScript's moduleSuffixes setting
* in the form of ['.ios', '.native', ''] or ['.windows', '.win', '.native', ''] or similar
*
* @param platform platform to get module suffixes for
* @param appendEmpty finish the suffixes with an empty entry, required for typescript usage
* @returns an array of suffixes to try to match a module to in order of priority
*/
export function getModuleSuffixes(
platform: AllPlatforms,
appendEmpty = true
): string[] {
const extensions = platformExtensions(platform).map((ext) => `.${ext}`);
if (appendEmpty) {
extensions.push("");
}
return extensions;
}

/**
* Returns a map of available React Native platforms. The result is NOT cached.
* @param startDir The directory to look for react-native platforms from
Expand Down Expand Up @@ -134,22 +169,32 @@ export function platformExtensions(platform: string): string[] {
}
}

/**
* @returns the given string as a platform value or undefined if it is not a valid platform.
*/
export function tryParsePlatform(val: string): AllPlatforms | undefined {
return allValues.includes(val as AllPlatforms)
? (val as AllPlatforms)
: undefined;
}

/**
* Parse a string to ensure it maps to a valid react-native platform.
*
* @param val Input string
* @returns React-native platform name. Throws `Error` on failure.
*/
export function parsePlatform(val: string): AllPlatforms {
switch (val) {
case "android":
case "ios":
case "macos":
case "win32":
case "windows":
return val;

default:
throw new Error("Invalid platform '" + val + "'");
const platform = tryParsePlatform(val);
if (!platform) {
throw new Error(`Unknown platform '${val}'`);
}
return platform;
}

/**
* @returns List of all supported react-native platforms.
*/
export function platformValues(): readonly AllPlatforms[] {
return allValues;
}
Loading