Skip to content
Merged
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
5 changes: 5 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,12 @@ export {
expandPlatformExtensions,
getAvailablePlatforms,
getAvailablePlatformsUncached,
getModuleSuffixes,
getPlatformPackageName,
getPlatformsForPackage,
parsePlatform,
parsePlatformValue,
platformExtensions,
platformValues,
} from "./platform";
export type { AllPlatforms } from "./platform";
83 changes: 73 additions & 10 deletions packages/tools-react-native/src/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ import { readReactNativeConfig } from "./context";
*/
export type AllPlatforms = "android" | "ios" | "macos" | "win32" | "windows";

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

/**
* Returns a list of extensions that should be tried for the target platform in
* prioritized order.
Expand All @@ -30,6 +39,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 +162,57 @@ 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 parsePlatformValue(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 = parsePlatformValue(val);
if (!platform) {
throw new Error(`Invalid platform '${val}'`);
}
return platform;
}

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

// Map of platform to npm package name
const platformToPackage: Record<AllPlatforms, string> = {
android: "react-native",
ios: "react-native",
macos: "react-native-macos",
win32: "@office-iss/react-native-win32",
windows: "react-native-windows",
};

/**
* @returns The react-native package name for the given platform
*/
export function getPlatformPackageName(platform: AllPlatforms): string {
return platformToPackage[platform];
}

/**
* @returns The list of packages supported by the given react-native package name
*/
export function getPlatformsForPackage(packageName: string): AllPlatforms[] {
return Object.entries(platformToPackage)
.filter(([, pkg]) => pkg === packageName)
.map(([platform]) => platform as AllPlatforms);
}
Loading