Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import kleur from 'kleur';
import type { Input } from '../types';
import { patchCodegenAndroidPackage } from '../utils/patchCodegenAndroidPackage';
import type { Input } from '../../types';
import { patchCodegenAndroidPackage } from './patches/patchCodegenAndroidPackage';
import fs from 'fs-extra';
import path from 'path';
import del from 'del';
import { runRNCCli } from '../utils/runRNCCli';
import { runRNCCli } from '../../utils/runRNCCli';
import { removeCodegenAppLevelCode } from './patches/removeCodegenAppLevelCode';

type Options = Input;

Expand Down Expand Up @@ -47,6 +48,7 @@ export default async function build({ root, report }: Options) {
if (codegenType === 'modules' || codegenType === 'all') {
await patchCodegenAndroidPackage(root, packageJson, report);
}
await removeCodegenAppLevelCode(root, packageJson);

report.success('Generated native code with codegen');
} catch (e: unknown) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { expect, it, describe, beforeEach, afterEach } from '@jest/globals';
import fs from 'fs-extra';
import path from 'node:path';
import { patchCodegenAndroidPackage } from '../utils/patchCodegenAndroidPackage';
import { patchCodegenAndroidPackage } from './patchCodegenAndroidPackage';
import mockfs from 'mock-fs';
import type { Report } from '../types';
import type { Report } from '../../../types';

const mockPackageJson = {
codegenConfig: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import fs from 'fs-extra';
import path from 'path';
import type { Report } from '../types';
import type { Report } from '../../../types';

const CODEGEN_DOCS =
'https://github.com/reactwg/react-native-new-architecture/blob/main/docs/enable-libraries-prerequisites.md#configure-codegen';
export const CODEGEN_DOCS =
'https://reactnative.dev/docs/the-new-architecture/using-codegen#configuring-codegen';

/**
* Currently, running react-native codegen generates java files with package name `com.facebook.fbreact.specs`.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { expect, it, describe, beforeEach, afterEach } from '@jest/globals';
import fs from 'fs-extra';
import path from 'node:path';
import { removeCodegenAppLevelCode } from './removeCodegenAppLevelCode';
import mockfs from 'mock-fs';

const mockPackageJson = {
codegenConfig: {
outputDir: {
android: 'android/generated',
ios: 'ios/generated',
},
},
};

const mockProjectPath = path.resolve(__dirname, 'mockProject');

describe('patchCodegenAndroidPackage', () => {
beforeEach(() => {
mockfs({
[mockProjectPath]: {
'package.json': JSON.stringify(mockPackageJson),
'ios': {
generated: {
'RCTAppDependencyProvider.h': '',
'RCTAppDependencyProvider.mm': '',
'RCTModulesConformingToProtocolsProvider.h': '',
'RCTModulesConformingToProtocolsProvider.mm': '',
'RCTThirdPartyComponentsProvider.h': '',
'RCTThirdPartyComponentsProvider.mm': '',
'ReactAppDependencyProvider.podspec': '',
},
},
'android': {
generated: {
'RCTAppDependencyProvider.h': '',
'RCTAppDependencyProvider.mm': '',
'RCTModulesConformingToProtocolsProvider.h': '',
'RCTModulesConformingToProtocolsProvider.mm': '',
'RCTThirdPartyComponentsProvider.h': '',
'RCTThirdPartyComponentsProvider.mm': '',
'ReactAppDependencyProvider.podspec': '',
},
},
},
});
});

afterEach(() => {
mockfs.restore();
});

it('removes the duplicate iOS files', async () => {
await removeCodegenAppLevelCode(mockProjectPath, mockPackageJson);

expect(
(
await fs.promises.readdir(
path.join(mockProjectPath, 'ios', 'generated')
)
).length
).toBe(0);
});

it('removes the unnecessary Android files', async () => {
await removeCodegenAppLevelCode(mockProjectPath, mockPackageJson);

expect(
(
await fs.promises.readdir(
path.join(mockProjectPath, 'android', 'generated')
)
).length
).toBe(0);
});

it("doesn't crash the process when there are no files to remove", async () => {
mockfs({
[mockProjectPath]: {
'package.json': JSON.stringify(mockPackageJson),
'ios': {
generated: {
someRandomFile: '',
},
},
'android': {
generated: {
someRandomFile: '',
},
},
},
});

await expect(
removeCodegenAppLevelCode(mockProjectPath, mockPackageJson)
).resolves.not.toThrow();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import fs from 'fs-extra';
import path from 'path';
import { CODEGEN_DOCS } from './patchCodegenAndroidPackage';

const FILES_TO_REMOVE = [
'RCTAppDependencyProvider.h',
'RCTAppDependencyProvider.mm',
'RCTModulesConformingToProtocolsProvider.h',
'RCTModulesConformingToProtocolsProvider.mm',
'RCTThirdPartyComponentsProvider.h',
'RCTThirdPartyComponentsProvider.mm',
'ReactAppDependencyProvider.podspec',
];

/**
* With React Native 0.77, calling `@react-native-community/cli codegen` generates
* some app level source files such as `RCTAppDependencyProvider.mm`.
* These files are supposed to be only generated for apps
* but the cli misbehaves and generates them for all sorts of projects.
* You can find the relevant PR here: https://github.com/facebook/react-native/pull/47650
* This patch can be removed when this gets fixed in React Native.
*/
export async function removeCodegenAppLevelCode(
projectPath: string,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
packageJson: any
) {
const codegenAndroidPathSetting: string | undefined =
packageJson.codegenConfig?.outputDir?.android;
if (!codegenAndroidPathSetting) {
throw new Error(
`Your package.json doesn't contain codegenConfig.outputDir.android. Please see ${CODEGEN_DOCS}`
);
}
const codegenAndroidPath = path.resolve(
projectPath,
codegenAndroidPathSetting
);

if (!(await fs.pathExists(codegenAndroidPath))) {
throw new Error(
`The codegen android path defined in your package.json: ${codegenAndroidPath} doesnt' exist.`
);
}

const codegenIosPathSetting: string | undefined =
packageJson.codegenConfig?.outputDir?.ios;
if (!codegenIosPathSetting) {
throw new Error(
`Your package.json doesn't contain codegenConfig.outputDir.ios. Please see ${CODEGEN_DOCS}`
);
}
const codegenIosPath = path.resolve(projectPath, codegenIosPathSetting);

if (!(await fs.pathExists(codegenAndroidPath))) {
throw new Error(
`The codegen iOS path defined in your package.json: ${codegenIosPathSetting} doesnt' exist.`
);
}

const androidPromises = FILES_TO_REMOVE.map((fileName) =>
fs.rm(path.join(codegenAndroidPath, fileName))
);

const iosPromises = FILES_TO_REMOVE.map((fileName) =>
fs.rm(path.join(codegenIosPath, fileName))
);

await Promise.allSettled([...androidPromises, ...iosPromises]);
}
Loading