diff --git a/.changeset/long-mails-do.md b/.changeset/long-mails-do.md new file mode 100644 index 000000000..8de89122b --- /dev/null +++ b/.changeset/long-mails-do.md @@ -0,0 +1,6 @@ +--- +'@rnef/config': patch +'@rnef/cli': patch +--- + +fix: incorrectly resolving root diff --git a/packages/cli/src/config.ts b/packages/cli/src/config.ts index 4e9432536..cef26d014 100644 --- a/packages/cli/src/config.ts +++ b/packages/cli/src/config.ts @@ -34,20 +34,17 @@ export const logConfig = async ( '@react-native-community/cli-config' ); const config = await loadConfigAsync({ + projectRoot: ownConfig.root, selectedPlatform: args.platform, }); - for (const platform in ownConfig.platforms) { - for (const projectEntry in config.project[platform]) { - if ( - ownConfig.platforms[platform].autolinkingConfig && - projectEntry in ownConfig.platforms[platform].autolinkingConfig - ) { - config.project[platform][projectEntry] = - // @ts-expect-error todo: type it better - ownConfig.platforms[platform].autolinkingConfig[projectEntry]; - } - } + const platforms = + ownConfig.platforms && args.platform + ? { [args.platform]: ownConfig.platforms[args.platform] } + : ownConfig.platforms; + + for (const platform in platforms) { + config.project[platform] = platforms[platform].autolinkingConfig; } console.log(JSON.stringify(filterConfig(config), null, 2)); diff --git a/packages/cli/src/lib/__tests__/cli.test.ts b/packages/cli/src/lib/__tests__/cli.test.ts index ac3ed0c95..f171041cf 100644 --- a/packages/cli/src/lib/__tests__/cli.test.ts +++ b/packages/cli/src/lib/__tests__/cli.test.ts @@ -4,9 +4,12 @@ import { expect, it } from 'vitest'; import { cli } from '../cli.js'; it('should throw when config not found', async () => { - await expect(cli({})).rejects.toThrow( - 'rnef.config not found in any parent directory of /' - ); + await expect( + cli({ + cwd: join(__dirname), + argv: ['node', 'rnef', 'test'], + }) + ).rejects.toThrow('rnef.config not found in any parent directory of /'); }); it('should not throw when config is there', async () => { diff --git a/packages/cli/src/lib/cli.ts b/packages/cli/src/lib/cli.ts index 80d5431d2..8b7f1bc2f 100644 --- a/packages/cli/src/lib/cli.ts +++ b/packages/cli/src/lib/cli.ts @@ -13,11 +13,11 @@ const __dirname = dirname(fileURLToPath(import.meta.url)); const { version } = require(resolveFilenameUp(__dirname, 'package.json')); type CliOptions = { - cwd?: string; - argv?: string[]; + cwd: string; + argv: string[]; }; -export const cli = async ({ cwd, argv }: CliOptions = {}) => { +export const cli = async ({ cwd, argv }: CliOptions) => { if (argv) { logger.setVerbose(argv.includes('--verbose')); checkDeprecatedOptions(argv); diff --git a/packages/config/src/lib/config.ts b/packages/config/src/lib/config.ts index adda7caca..4a467ecf1 100644 --- a/packages/config/src/lib/config.ts +++ b/packages/config/src/lib/config.ts @@ -12,7 +12,7 @@ export type PluginOutput = { }; export type PlatformOutput = PluginOutput & { - autolinkingConfig: object | undefined; + autolinkingConfig: { project: Record | undefined }; }; export type PluginApi = { @@ -76,6 +76,7 @@ export type ConfigType = { }; export type ConfigOutput = { + root: string; commands?: Array; platforms?: Record; } & PluginApi; @@ -85,7 +86,11 @@ const extensions = ['.js', '.ts', '.mjs']; const importUp = async ( dir: string, name: string -): Promise<{ config: ConfigType; filePathWithExt: string }> => { +): Promise<{ + config: ConfigType; + filePathWithExt: string; + configDir: string; +}> => { const filePath = path.join(dir, name); for (const ext of extensions) { @@ -100,7 +105,7 @@ const importUp = async ( config = require(filePathWithExt); } - return { config, filePathWithExt }; + return { config, filePathWithExt, configDir: dir }; } } @@ -112,11 +117,11 @@ const importUp = async ( return importUp(parentDir, name); }; -export async function getConfig( - dir: string = process.cwd() -): Promise { - // eslint-disable-next-line prefer-const - let { config, filePathWithExt } = await importUp(dir, 'rnef.config'); +export async function getConfig(dir: string): Promise { + const { config, filePathWithExt, configDir } = await importUp( + dir, + 'rnef.config' + ); const { error, value: validatedConfig } = ConfigTypeSchema.validate( config @@ -128,61 +133,63 @@ export async function getConfig( if (error) { logger.error( `Invalid ${color.cyan( - path.relative(process.cwd(), filePathWithExt) + path.relative(configDir, filePathWithExt) )} file:\n` + formatValidationError(config, error) ); process.exit(1); } - config = { - root: dir, - get reactNativePath() { - return resolveReactNativePath(config.root || dir); - }, - get reactNativeVersion() { - return getReactNativeVersion(config.root || dir); - }, - ...validatedConfig, - }; + const projectRoot = validatedConfig.root + ? path.resolve(configDir, validatedConfig.root) + : configDir; + + if (!fs.existsSync(projectRoot)) { + logger.error( + `Project root ${projectRoot} does not exist. Please check your config file.` + ); + process.exit(1); + } const api = { registerCommand: (command: CommandType) => { - config.commands = [...(config.commands || []), command]; + validatedConfig.commands = [...(validatedConfig.commands || []), command]; }, - getProjectRoot: () => path.resolve(config.root as string), - getReactNativeVersion: () => config.reactNativeVersion as string, - getReactNativePath: () => config.reactNativePath as string, - getPlatforms: () => config.platforms as { [platform: string]: object }, - getRemoteCacheProvider: () => config.remoteCacheProvider, + getProjectRoot: () => projectRoot, + getReactNativeVersion: () => getReactNativeVersion(projectRoot), + getReactNativePath: () => resolveReactNativePath(projectRoot), + getPlatforms: () => + validatedConfig.platforms as { [platform: string]: object }, + getRemoteCacheProvider: () => validatedConfig.remoteCacheProvider, getFingerprintOptions: () => - config.fingerprint as { + validatedConfig.fingerprint as { extraSources: string[]; ignorePaths: string[]; }, }; - if (config.plugins) { + if (validatedConfig.plugins) { // plugins register commands - for (const plugin of config.plugins) { - assignOriginToCommand(plugin, api, config); + for (const plugin of validatedConfig.plugins) { + assignOriginToCommand(plugin, api, validatedConfig); } } const platforms: Record = {}; - if (config.platforms) { + if (validatedConfig.platforms) { // platforms register commands and custom platform functionality (TBD) - for (const platform in config.platforms) { - const platformOutput = config.platforms[platform](api); + for (const platform in validatedConfig.platforms) { + const platformOutput = validatedConfig.platforms[platform](api); platforms[platform] = platformOutput; } } - if (config.bundler) { - assignOriginToCommand(config.bundler, api, config); + if (validatedConfig.bundler) { + assignOriginToCommand(validatedConfig.bundler, api, validatedConfig); } const outputConfig: ConfigOutput = { - commands: config.commands ?? [], + root: projectRoot, + commands: validatedConfig.commands ?? [], platforms: platforms ?? {}, ...api, }; diff --git a/packages/platform-android/src/lib/commands/buildAndroid/command.ts b/packages/platform-android/src/lib/commands/buildAndroid/command.ts index a7db715ee..9766b1137 100644 --- a/packages/platform-android/src/lib/commands/buildAndroid/command.ts +++ b/packages/platform-android/src/lib/commands/buildAndroid/command.ts @@ -1,22 +1,17 @@ -import { projectConfig } from '@react-native-community/cli-config-android'; import type { AndroidProjectConfig } from '@react-native-community/cli-types'; import type { PluginApi } from '@rnef/config'; -import { RnefError } from '@rnef/tools'; import type { BuildFlags } from './buildAndroid.js'; import { buildAndroid, options } from './buildAndroid.js'; -export function registerBuildCommand(api: PluginApi, pluginConfig?: AndroidProjectConfig) { +export function registerBuildCommand( + api: PluginApi, + androidConfig: AndroidProjectConfig +) { api.registerCommand({ name: 'build:android', description: 'Builds your app for Android platform.', action: async (args) => { - const projectRoot = api.getProjectRoot(); - const androidConfig = projectConfig(projectRoot, pluginConfig); - if (androidConfig) { - await buildAndroid(androidConfig, args as BuildFlags); - } else { - throw new RnefError('Android project not found.'); - } + await buildAndroid(androidConfig, args as BuildFlags); }, options: options, }); diff --git a/packages/platform-android/src/lib/commands/generateKeystore.ts b/packages/platform-android/src/lib/commands/generateKeystore.ts index aaf5ee7f6..cb3c6a9c3 100644 --- a/packages/platform-android/src/lib/commands/generateKeystore.ts +++ b/packages/platform-android/src/lib/commands/generateKeystore.ts @@ -1,5 +1,4 @@ import path from 'node:path'; -import { projectConfig } from '@react-native-community/cli-config-android'; import type { AndroidProjectConfig } from '@react-native-community/cli-types'; import type { PluginApi } from '@rnef/config'; import type { SubprocessError } from '@rnef/tools'; @@ -14,18 +13,15 @@ import { spawn, } from '@rnef/tools'; -export function registerCreateKeystoreCommand(api: PluginApi, pluginConfig?: AndroidProjectConfig) { +export function registerCreateKeystoreCommand( + api: PluginApi, + androidConfig: AndroidProjectConfig +) { api.registerCommand({ name: 'create-keystore:android', description: 'Creates a keystore file for signing Android release builds.', action: async (args) => { - const projectRoot = api.getProjectRoot(); - const androidConfig = projectConfig(projectRoot, pluginConfig); - if (androidConfig) { - await generateKeystore(androidConfig, args); - } else { - throw new RnefError('Android project not found.'); - } + await generateKeystore(androidConfig, args); }, options: generateKeystoreOptions, }); diff --git a/packages/platform-android/src/lib/commands/getValidProjectConfig.ts b/packages/platform-android/src/lib/commands/getValidProjectConfig.ts new file mode 100644 index 000000000..c2d52f983 --- /dev/null +++ b/packages/platform-android/src/lib/commands/getValidProjectConfig.ts @@ -0,0 +1,14 @@ +import { projectConfig } from '@react-native-community/cli-config-android'; +import type { AndroidProjectConfig } from '@react-native-community/cli-types'; +import { RnefError } from '@rnef/tools'; + +export function getValidProjectConfig( + projectRoot: string, + pluginConfig?: AndroidProjectConfig +) { + const androidConfig = projectConfig(projectRoot, pluginConfig); + if (!androidConfig) { + throw new RnefError('Android project not found.'); + } + return androidConfig; +} diff --git a/packages/platform-android/src/lib/commands/runAndroid/command.ts b/packages/platform-android/src/lib/commands/runAndroid/command.ts index f91402bd5..0cacc2350 100644 --- a/packages/platform-android/src/lib/commands/runAndroid/command.ts +++ b/packages/platform-android/src/lib/commands/runAndroid/command.ts @@ -1,13 +1,11 @@ -import { projectConfig } from '@react-native-community/cli-config-android'; import type { AndroidProjectConfig } from '@react-native-community/cli-types'; import type { PluginApi } from '@rnef/config'; -import { RnefError } from '@rnef/tools'; import type { Flags } from './runAndroid.js'; import { runAndroid, runOptions } from './runAndroid.js'; export function registerRunCommand( api: PluginApi, - pluginConfig?: AndroidProjectConfig + androidConfig: AndroidProjectConfig ) { api.registerCommand({ name: 'run:android', @@ -15,18 +13,13 @@ export function registerRunCommand( 'Builds your app and starts it on a connected Android emulator or a device.', action: async (args) => { const projectRoot = api.getProjectRoot(); - const androidConfig = projectConfig(projectRoot, pluginConfig); - if (androidConfig) { - await runAndroid( - androidConfig, - args as Flags, - projectRoot, - api.getRemoteCacheProvider(), - api.getFingerprintOptions() - ); - } else { - throw new RnefError('Android project not found.'); - } + await runAndroid( + androidConfig, + args as Flags, + projectRoot, + api.getRemoteCacheProvider(), + api.getFingerprintOptions() + ); }, options: runOptions, }); diff --git a/packages/platform-android/src/lib/platformAndroid.ts b/packages/platform-android/src/lib/platformAndroid.ts index 9e0a4bf3c..8926ede7b 100644 --- a/packages/platform-android/src/lib/platformAndroid.ts +++ b/packages/platform-android/src/lib/platformAndroid.ts @@ -1,8 +1,8 @@ -import path from 'node:path'; import type { AndroidProjectConfig } from '@react-native-community/cli-types'; import type { PlatformOutput, PluginApi } from '@rnef/config'; import { registerBuildCommand } from './commands/buildAndroid/command.js'; import { registerCreateKeystoreCommand } from './commands/generateKeystore.js'; +import { getValidProjectConfig } from './commands/getValidProjectConfig.js'; import { registerRunCommand } from './commands/runAndroid/command.js'; import { registerSignCommand } from './commands/signAndroid/command.js'; @@ -11,20 +11,19 @@ type PluginConfig = AndroidProjectConfig; export const platformAndroid = (pluginConfig?: PluginConfig) => (api: PluginApi): PlatformOutput => { - registerBuildCommand(api, pluginConfig); - registerRunCommand(api, pluginConfig); - registerCreateKeystoreCommand(api, pluginConfig); + const androidConfig = getValidProjectConfig( + api.getProjectRoot(), + pluginConfig + ); + registerBuildCommand(api, androidConfig); + registerRunCommand(api, androidConfig); + registerCreateKeystoreCommand(api, androidConfig); registerSignCommand(api); return { name: '@rnef/platform-android', description: 'RNEF plugin for everything Android.', - autolinkingConfig: { - ...pluginConfig, - sourceDir: pluginConfig?.sourceDir - ? path.join(api.getProjectRoot(), pluginConfig.sourceDir) - : undefined, - }, + autolinkingConfig: { project: { ...androidConfig } }, }; }; diff --git a/packages/platform-apple-helpers/src/lib/utils/getValidProjectConfig.ts b/packages/platform-apple-helpers/src/lib/utils/getValidProjectConfig.ts index 5927ca371..7bc401151 100644 --- a/packages/platform-apple-helpers/src/lib/utils/getValidProjectConfig.ts +++ b/packages/platform-apple-helpers/src/lib/utils/getValidProjectConfig.ts @@ -19,7 +19,6 @@ export function getValidProjectConfig( if (!newProjectConfig || newProjectConfig.xcodeProject === null) { throw new RnefError('Failed to get Xcode project information'); } - return { sourceDir: newProjectConfig.sourceDir, xcodeProject: newProjectConfig.xcodeProject, diff --git a/packages/platform-ios/src/lib/platformIOS.ts b/packages/platform-ios/src/lib/platformIOS.ts index aaca4b7eb..eb635e579 100644 --- a/packages/platform-ios/src/lib/platformIOS.ts +++ b/packages/platform-ios/src/lib/platformIOS.ts @@ -1,4 +1,3 @@ -import path from 'node:path'; import type { IOSProjectConfig } from '@react-native-community/cli-types'; import type { PlatformOutput, PluginApi } from '@rnef/config'; import type { BuildFlags, RunFlags } from '@rnef/platform-apple-helpers'; @@ -18,17 +17,13 @@ const runOptions = getRunOptions({ platformName: 'ios' }); export const platformIOS = (pluginConfig?: IOSProjectConfig) => (api: PluginApi): PlatformOutput => { + const projectRoot = api.getProjectRoot(); + const iosConfig = getValidProjectConfig('ios', projectRoot, pluginConfig); api.registerCommand({ name: 'build:ios', description: 'Build iOS app.', action: async (args) => { intro('Building iOS app'); - const projectRoot = api.getProjectRoot(); - const iosConfig = getValidProjectConfig( - 'ios', - projectRoot, - pluginConfig - ); await createBuild('ios', iosConfig, args as BuildFlags, projectRoot); outro('Success 🎉.'); }, @@ -40,12 +35,6 @@ export const platformIOS = description: 'Run iOS app.', action: async (args) => { intro('Running iOS app'); - const projectRoot = api.getProjectRoot(); - const iosConfig = getValidProjectConfig( - 'ios', - projectRoot, - pluginConfig - ); await createRun( 'ios', iosConfig, @@ -65,12 +54,7 @@ export const platformIOS = return { name: '@rnef/platform-ios', description: 'RNEF plugin for everything iOS.', - autolinkingConfig: { - ...pluginConfig, - sourceDir: pluginConfig?.sourceDir - ? path.join(api.getProjectRoot(), pluginConfig.sourceDir) - : undefined, - }, + autolinkingConfig: { project: { ...iosConfig } }, }; };