Skip to content

Commit a004ed5

Browse files
authored
fix: incorrectly resolving root (#276)
* fix: incorrectly resolving root * changeset * rework autolinkingConfig to include whole projectConfig * refactor * make autolinkingConfig more futureproof with project key
1 parent 5e2a0e7 commit a004ed5

File tree

12 files changed

+109
-116
lines changed

12 files changed

+109
-116
lines changed

.changeset/long-mails-do.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@rnef/config': patch
3+
'@rnef/cli': patch
4+
---
5+
6+
fix: incorrectly resolving root

packages/cli/src/config.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,17 @@ export const logConfig = async (
3434
'@react-native-community/cli-config'
3535
);
3636
const config = await loadConfigAsync({
37+
projectRoot: ownConfig.root,
3738
selectedPlatform: args.platform,
3839
});
3940

40-
for (const platform in ownConfig.platforms) {
41-
for (const projectEntry in config.project[platform]) {
42-
if (
43-
ownConfig.platforms[platform].autolinkingConfig &&
44-
projectEntry in ownConfig.platforms[platform].autolinkingConfig
45-
) {
46-
config.project[platform][projectEntry] =
47-
// @ts-expect-error todo: type it better
48-
ownConfig.platforms[platform].autolinkingConfig[projectEntry];
49-
}
50-
}
41+
const platforms =
42+
ownConfig.platforms && args.platform
43+
? { [args.platform]: ownConfig.platforms[args.platform] }
44+
: ownConfig.platforms;
45+
46+
for (const platform in platforms) {
47+
config.project[platform] = platforms[platform].autolinkingConfig;
5148
}
5249

5350
console.log(JSON.stringify(filterConfig(config), null, 2));

packages/cli/src/lib/__tests__/cli.test.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import { expect, it } from 'vitest';
44
import { cli } from '../cli.js';
55

66
it('should throw when config not found', async () => {
7-
await expect(cli({})).rejects.toThrow(
8-
'rnef.config not found in any parent directory of /'
9-
);
7+
await expect(
8+
cli({
9+
cwd: join(__dirname),
10+
argv: ['node', 'rnef', 'test'],
11+
})
12+
).rejects.toThrow('rnef.config not found in any parent directory of /');
1013
});
1114

1215
it('should not throw when config is there', async () => {

packages/cli/src/lib/cli.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
1313
const { version } = require(resolveFilenameUp(__dirname, 'package.json'));
1414

1515
type CliOptions = {
16-
cwd?: string;
17-
argv?: string[];
16+
cwd: string;
17+
argv: string[];
1818
};
1919

20-
export const cli = async ({ cwd, argv }: CliOptions = {}) => {
20+
export const cli = async ({ cwd, argv }: CliOptions) => {
2121
if (argv) {
2222
logger.setVerbose(argv.includes('--verbose'));
2323
checkDeprecatedOptions(argv);

packages/config/src/lib/config.ts

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export type PluginOutput = {
1212
};
1313

1414
export type PlatformOutput = PluginOutput & {
15-
autolinkingConfig: object | undefined;
15+
autolinkingConfig: { project: Record<string, unknown> | undefined };
1616
};
1717

1818
export type PluginApi = {
@@ -76,6 +76,7 @@ export type ConfigType = {
7676
};
7777

7878
export type ConfigOutput = {
79+
root: string;
7980
commands?: Array<CommandType>;
8081
platforms?: Record<string, PlatformOutput>;
8182
} & PluginApi;
@@ -85,7 +86,11 @@ const extensions = ['.js', '.ts', '.mjs'];
8586
const importUp = async (
8687
dir: string,
8788
name: string
88-
): Promise<{ config: ConfigType; filePathWithExt: string }> => {
89+
): Promise<{
90+
config: ConfigType;
91+
filePathWithExt: string;
92+
configDir: string;
93+
}> => {
8994
const filePath = path.join(dir, name);
9095

9196
for (const ext of extensions) {
@@ -100,7 +105,7 @@ const importUp = async (
100105
config = require(filePathWithExt);
101106
}
102107

103-
return { config, filePathWithExt };
108+
return { config, filePathWithExt, configDir: dir };
104109
}
105110
}
106111

@@ -112,11 +117,11 @@ const importUp = async (
112117
return importUp(parentDir, name);
113118
};
114119

115-
export async function getConfig(
116-
dir: string = process.cwd()
117-
): Promise<ConfigOutput> {
118-
// eslint-disable-next-line prefer-const
119-
let { config, filePathWithExt } = await importUp(dir, 'rnef.config');
120+
export async function getConfig(dir: string): Promise<ConfigOutput> {
121+
const { config, filePathWithExt, configDir } = await importUp(
122+
dir,
123+
'rnef.config'
124+
);
120125

121126
const { error, value: validatedConfig } = ConfigTypeSchema.validate(
122127
config
@@ -128,61 +133,63 @@ export async function getConfig(
128133
if (error) {
129134
logger.error(
130135
`Invalid ${color.cyan(
131-
path.relative(process.cwd(), filePathWithExt)
136+
path.relative(configDir, filePathWithExt)
132137
)} file:\n` + formatValidationError(config, error)
133138
);
134139
process.exit(1);
135140
}
136141

137-
config = {
138-
root: dir,
139-
get reactNativePath() {
140-
return resolveReactNativePath(config.root || dir);
141-
},
142-
get reactNativeVersion() {
143-
return getReactNativeVersion(config.root || dir);
144-
},
145-
...validatedConfig,
146-
};
142+
const projectRoot = validatedConfig.root
143+
? path.resolve(configDir, validatedConfig.root)
144+
: configDir;
145+
146+
if (!fs.existsSync(projectRoot)) {
147+
logger.error(
148+
`Project root ${projectRoot} does not exist. Please check your config file.`
149+
);
150+
process.exit(1);
151+
}
147152

148153
const api = {
149154
registerCommand: (command: CommandType) => {
150-
config.commands = [...(config.commands || []), command];
155+
validatedConfig.commands = [...(validatedConfig.commands || []), command];
151156
},
152-
getProjectRoot: () => path.resolve(config.root as string),
153-
getReactNativeVersion: () => config.reactNativeVersion as string,
154-
getReactNativePath: () => config.reactNativePath as string,
155-
getPlatforms: () => config.platforms as { [platform: string]: object },
156-
getRemoteCacheProvider: () => config.remoteCacheProvider,
157+
getProjectRoot: () => projectRoot,
158+
getReactNativeVersion: () => getReactNativeVersion(projectRoot),
159+
getReactNativePath: () => resolveReactNativePath(projectRoot),
160+
getPlatforms: () =>
161+
validatedConfig.platforms as { [platform: string]: object },
162+
getRemoteCacheProvider: () => validatedConfig.remoteCacheProvider,
157163
getFingerprintOptions: () =>
158-
config.fingerprint as {
164+
validatedConfig.fingerprint as {
159165
extraSources: string[];
160166
ignorePaths: string[];
161167
},
162168
};
163169

164-
if (config.plugins) {
170+
if (validatedConfig.plugins) {
165171
// plugins register commands
166-
for (const plugin of config.plugins) {
167-
assignOriginToCommand(plugin, api, config);
172+
for (const plugin of validatedConfig.plugins) {
173+
assignOriginToCommand(plugin, api, validatedConfig);
168174
}
169175
}
170176

171177
const platforms: Record<string, PlatformOutput> = {};
172-
if (config.platforms) {
178+
if (validatedConfig.platforms) {
173179
// platforms register commands and custom platform functionality (TBD)
174-
for (const platform in config.platforms) {
175-
const platformOutput = config.platforms[platform](api);
180+
for (const platform in validatedConfig.platforms) {
181+
const platformOutput = validatedConfig.platforms[platform](api);
176182
platforms[platform] = platformOutput;
177183
}
178184
}
179185

180-
if (config.bundler) {
181-
assignOriginToCommand(config.bundler, api, config);
186+
if (validatedConfig.bundler) {
187+
assignOriginToCommand(validatedConfig.bundler, api, validatedConfig);
182188
}
183189

184190
const outputConfig: ConfigOutput = {
185-
commands: config.commands ?? [],
191+
root: projectRoot,
192+
commands: validatedConfig.commands ?? [],
186193
platforms: platforms ?? {},
187194
...api,
188195
};

packages/platform-android/src/lib/commands/buildAndroid/command.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,17 @@
1-
import { projectConfig } from '@react-native-community/cli-config-android';
21
import type { AndroidProjectConfig } from '@react-native-community/cli-types';
32
import type { PluginApi } from '@rnef/config';
4-
import { RnefError } from '@rnef/tools';
53
import type { BuildFlags } from './buildAndroid.js';
64
import { buildAndroid, options } from './buildAndroid.js';
75

8-
export function registerBuildCommand(api: PluginApi, pluginConfig?: AndroidProjectConfig) {
6+
export function registerBuildCommand(
7+
api: PluginApi,
8+
androidConfig: AndroidProjectConfig
9+
) {
910
api.registerCommand({
1011
name: 'build:android',
1112
description: 'Builds your app for Android platform.',
1213
action: async (args) => {
13-
const projectRoot = api.getProjectRoot();
14-
const androidConfig = projectConfig(projectRoot, pluginConfig);
15-
if (androidConfig) {
16-
await buildAndroid(androidConfig, args as BuildFlags);
17-
} else {
18-
throw new RnefError('Android project not found.');
19-
}
14+
await buildAndroid(androidConfig, args as BuildFlags);
2015
},
2116
options: options,
2217
});

packages/platform-android/src/lib/commands/generateKeystore.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import path from 'node:path';
2-
import { projectConfig } from '@react-native-community/cli-config-android';
32
import type { AndroidProjectConfig } from '@react-native-community/cli-types';
43
import type { PluginApi } from '@rnef/config';
54
import type { SubprocessError } from '@rnef/tools';
@@ -14,18 +13,15 @@ import {
1413
spawn,
1514
} from '@rnef/tools';
1615

17-
export function registerCreateKeystoreCommand(api: PluginApi, pluginConfig?: AndroidProjectConfig) {
16+
export function registerCreateKeystoreCommand(
17+
api: PluginApi,
18+
androidConfig: AndroidProjectConfig
19+
) {
1820
api.registerCommand({
1921
name: 'create-keystore:android',
2022
description: 'Creates a keystore file for signing Android release builds.',
2123
action: async (args) => {
22-
const projectRoot = api.getProjectRoot();
23-
const androidConfig = projectConfig(projectRoot, pluginConfig);
24-
if (androidConfig) {
25-
await generateKeystore(androidConfig, args);
26-
} else {
27-
throw new RnefError('Android project not found.');
28-
}
24+
await generateKeystore(androidConfig, args);
2925
},
3026
options: generateKeystoreOptions,
3127
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { projectConfig } from '@react-native-community/cli-config-android';
2+
import type { AndroidProjectConfig } from '@react-native-community/cli-types';
3+
import { RnefError } from '@rnef/tools';
4+
5+
export function getValidProjectConfig(
6+
projectRoot: string,
7+
pluginConfig?: AndroidProjectConfig
8+
) {
9+
const androidConfig = projectConfig(projectRoot, pluginConfig);
10+
if (!androidConfig) {
11+
throw new RnefError('Android project not found.');
12+
}
13+
return androidConfig;
14+
}

packages/platform-android/src/lib/commands/runAndroid/command.ts

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,25 @@
1-
import { projectConfig } from '@react-native-community/cli-config-android';
21
import type { AndroidProjectConfig } from '@react-native-community/cli-types';
32
import type { PluginApi } from '@rnef/config';
4-
import { RnefError } from '@rnef/tools';
53
import type { Flags } from './runAndroid.js';
64
import { runAndroid, runOptions } from './runAndroid.js';
75

86
export function registerRunCommand(
97
api: PluginApi,
10-
pluginConfig?: AndroidProjectConfig
8+
androidConfig: AndroidProjectConfig
119
) {
1210
api.registerCommand({
1311
name: 'run:android',
1412
description:
1513
'Builds your app and starts it on a connected Android emulator or a device.',
1614
action: async (args) => {
1715
const projectRoot = api.getProjectRoot();
18-
const androidConfig = projectConfig(projectRoot, pluginConfig);
19-
if (androidConfig) {
20-
await runAndroid(
21-
androidConfig,
22-
args as Flags,
23-
projectRoot,
24-
api.getRemoteCacheProvider(),
25-
api.getFingerprintOptions()
26-
);
27-
} else {
28-
throw new RnefError('Android project not found.');
29-
}
16+
await runAndroid(
17+
androidConfig,
18+
args as Flags,
19+
projectRoot,
20+
api.getRemoteCacheProvider(),
21+
api.getFingerprintOptions()
22+
);
3023
},
3124
options: runOptions,
3225
});

packages/platform-android/src/lib/platformAndroid.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import path from 'node:path';
21
import type { AndroidProjectConfig } from '@react-native-community/cli-types';
32
import type { PlatformOutput, PluginApi } from '@rnef/config';
43
import { registerBuildCommand } from './commands/buildAndroid/command.js';
54
import { registerCreateKeystoreCommand } from './commands/generateKeystore.js';
5+
import { getValidProjectConfig } from './commands/getValidProjectConfig.js';
66
import { registerRunCommand } from './commands/runAndroid/command.js';
77
import { registerSignCommand } from './commands/signAndroid/command.js';
88

@@ -11,20 +11,19 @@ type PluginConfig = AndroidProjectConfig;
1111
export const platformAndroid =
1212
(pluginConfig?: PluginConfig) =>
1313
(api: PluginApi): PlatformOutput => {
14-
registerBuildCommand(api, pluginConfig);
15-
registerRunCommand(api, pluginConfig);
16-
registerCreateKeystoreCommand(api, pluginConfig);
14+
const androidConfig = getValidProjectConfig(
15+
api.getProjectRoot(),
16+
pluginConfig
17+
);
18+
registerBuildCommand(api, androidConfig);
19+
registerRunCommand(api, androidConfig);
20+
registerCreateKeystoreCommand(api, androidConfig);
1721
registerSignCommand(api);
1822

1923
return {
2024
name: '@rnef/platform-android',
2125
description: 'RNEF plugin for everything Android.',
22-
autolinkingConfig: {
23-
...pluginConfig,
24-
sourceDir: pluginConfig?.sourceDir
25-
? path.join(api.getProjectRoot(), pluginConfig.sourceDir)
26-
: undefined,
27-
},
26+
autolinkingConfig: { project: { ...androidConfig } },
2827
};
2928
};
3029

0 commit comments

Comments
 (0)