Compare commits

..
Author SHA1 Message Date
Christian Falch f4f85123a5 codereview: sorted the output from getArchsFromFramework
If there are multiple platforms we now sort them before returning.
2025-08-20 17:42:18 +02:00
Christian FalchandRiccardo Cipolleschi bf7086c850 Update packages/react-native/scripts/ios-prebuild/xcframework.js
Co-authored-by: Riccardo Cipolleschi <cipolleschi@meta.com>
2025-08-20 17:20:22 +02:00
Christian Falch 2efed20e5c [ios][precompile] aligned symbol folders with RNdeps
After fixing an isssue with ReactnativeDependencies and how it built symbols (#53353) this commit will align the output of the Symbols folder for the two frameworks.

Previously we had an output in the Symbols folder that looked like this (from a local build on my machine)

- catalyst
- iphone
- iphonesimulator

After this we now have the more correct arcitecture names on these folders:

- ios-arm64
- ios-arm64_x86_64-simulator
- ios-arm64_x86_64-maccatalyst

This is in line with how the ReactNativeDependencies Symbol folder is set up.
2025-08-19 18:22:28 +02:00
671 changed files with 4335 additions and 7387 deletions
+3 -5
View File
@@ -75,10 +75,8 @@ module.system.haste.module_ref_prefix=m#
react.runtime=automatic
experimental.only_support_flow_fixme_and_expected_error=true
experimental.require_suppression_with_error_code=true
experimental.invariant_subtyping_error_message_improvement=true
experimental.natural_inference.local_object_literals.followup_fix=true
experimental.error_code_migration=new
suppress_type=$FlowFixMe
ban_spread_key_props=true
@@ -103,4 +101,4 @@ untyped-import
untyped-type-import
[version]
^0.280.0
^0.279.0
@@ -71,17 +71,17 @@ runs:
mv build_"$SLICE" "$FINAL_PATH"
# check whether everything is there
if [[ -d "$FINAL_PATH/lib/hermesvm.framework" ]]; then
echo "Successfully built hermesvm.framework for $SLICE in $FLAVOR"
if [[ -d "$FINAL_PATH/API/hermes/hermes.framework" ]]; then
echo "Successfully built hermes.framework for $SLICE in $FLAVOR"
else
echo "Failed to built hermesvm.framework for $SLICE in $FLAVOR"
echo "Failed to built hermes.framework for $SLICE in $FLAVOR"
exit 1
fi
if [[ -d "$FINAL_PATH/lib/hermesvm.framework.dSYM" ]]; then
echo "Successfully built hermesvm.framework.dSYM for $SLICE in $FLAVOR"
if [[ -d "$FINAL_PATH/API/hermes/hermes.framework.dSYM" ]]; then
echo "Successfully built hermes.framework.dSYM for $SLICE in $FLAVOR"
else
echo "Failed to built hermesvm.framework.dSYM for $SLICE in $FLAVOR"
echo "Failed to built hermes.framework.dSYM for $SLICE in $FLAVOR"
echo "Please try again"
exit 1
fi
@@ -186,7 +186,7 @@ runs:
cd ./packages/react-native/sdks/hermes || exit 1
DSYM_FILE_PATH=lib/hermesvm.framework.dSYM
DSYM_FILE_PATH=API/hermes/hermes.framework.dSYM
cp -r build_macosx/$DSYM_FILE_PATH "$WORKING_DIR/macosx/"
cp -r build_catalyst/$DSYM_FILE_PATH "$WORKING_DIR/catalyst/"
cp -r build_iphoneos/$DSYM_FILE_PATH "$WORKING_DIR/iphoneos/"
@@ -197,10 +197,10 @@ runs:
cp -r build_xrsimulator/$DSYM_FILE_PATH "$WORKING_DIR/xrsimulator/"
DEST_DIR="/tmp/hermes/dSYM/$FLAVOR"
tar -C "$WORKING_DIR" -czvf "hermesvm.framework.dSYM" .
tar -C "$WORKING_DIR" -czvf "hermes.framework.dSYM" .
mkdir -p "$DEST_DIR"
mv "hermesvm.framework.dSYM" "$DEST_DIR"
mv "hermes.framework.dSYM" "$DEST_DIR"
- name: Upload hermes dSYM artifacts
uses: actions/upload-artifact@v4.3.4
with:
+2 -2
View File
@@ -99,8 +99,8 @@ runs:
mkdir -p ./packages/react-native/ReactAndroid/external-artifacts/artifacts/
cp ${{ inputs.hermes-ws-dir }}/hermes-runtime-darwin/hermes-ios-Debug.tar.gz ./packages/react-native/ReactAndroid/external-artifacts/artifacts/hermes-ios-debug.tar.gz
cp ${{ inputs.hermes-ws-dir }}/hermes-runtime-darwin/hermes-ios-Release.tar.gz ./packages/react-native/ReactAndroid/external-artifacts/artifacts/hermes-ios-release.tar.gz
cp ${{ inputs.hermes-ws-dir }}/dSYM/Debug/hermesvm.framework.dSYM ./packages/react-native/ReactAndroid/external-artifacts/artifacts/hermes-framework-dSYM-debug.tar.gz
cp ${{ inputs.hermes-ws-dir }}/dSYM/Release/hermesvm.framework.dSYM ./packages/react-native/ReactAndroid/external-artifacts/artifacts/hermes-framework-dSYM-release.tar.gz
cp ${{ inputs.hermes-ws-dir }}/dSYM/Debug/hermes.framework.dSYM ./packages/react-native/ReactAndroid/external-artifacts/artifacts/hermes-framework-dSYM-debug.tar.gz
cp ${{ inputs.hermes-ws-dir }}/dSYM/Release/hermes.framework.dSYM ./packages/react-native/ReactAndroid/external-artifacts/artifacts/hermes-framework-dSYM-release.tar.gz
- name: Download ReactNativeDependencies
uses: actions/download-artifact@v4
with:
@@ -179,9 +179,8 @@ jobs:
- name: Compress and Rename dSYM
if: steps.restore-xcframework.outputs.cache-hit != 'true'
run: |
cd packages/react-native/third-party/Symbols/
tar -cz -f ../ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz .
mv ../ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz ./ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz
tar -cz -f packages/react-native/third-party/Symbols/ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz \
packages/react-native/third-party/Symbols/ReactNativeDependencies.framework.dSYM
- name: Upload XCFramework Artifact
uses: actions/upload-artifact@v4
with:
-5
View File
@@ -246,11 +246,6 @@ jobs:
- name: Print ReactCore folder
shell: bash
run: ls -lR /tmp/ReactCore
- name: Configure git
shell: bash
run: |
git config --global user.email "react-native-bot@meta.com"
git config --global user.name "React Native Bot"
- name: Prepare artifacts
run: |
REACT_NATIVE_PKG=$(find /tmp/react-native-tmp -type f -name "*.tgz")
+12 -28
View File
@@ -26,12 +26,10 @@ fun getListReactAndroidProperty(name: String) = reactAndroidProperties.getProper
apiValidation {
ignoredPackages.addAll(
getListReactAndroidProperty("binaryCompatibilityValidator.ignoredPackages")
)
getListReactAndroidProperty("binaryCompatibilityValidator.ignoredPackages"))
ignoredClasses.addAll(getListReactAndroidProperty("binaryCompatibilityValidator.ignoredClasses"))
nonPublicMarkers.addAll(
getListReactAndroidProperty("binaryCompatibilityValidator.nonPublicMarkers")
)
getListReactAndroidProperty("binaryCompatibilityValidator.nonPublicMarkers"))
validationDisabled =
reactAndroidProperties
.getProperty("binaryCompatibilityValidator.validationDisabled")
@@ -39,9 +37,8 @@ apiValidation {
}
version =
if (
project.hasProperty("isSnapshot") && (project.property("isSnapshot") as? String).toBoolean()
) {
if (project.hasProperty("isSnapshot") &&
(project.property("isSnapshot") as? String).toBoolean()) {
"${reactAndroidProperties.getProperty("VERSION_NAME")}-SNAPSHOT"
} else {
reactAndroidProperties.getProperty("VERSION_NAME")
@@ -69,10 +66,8 @@ tasks.register("clean", Delete::class.java) {
description = "Remove all the build files and intermediate build outputs"
dependsOn(gradle.includedBuild("gradle-plugin").task(":clean"))
subprojects.forEach {
if (
it.project.plugins.hasPlugin("com.android.library") ||
it.project.plugins.hasPlugin("com.android.application")
) {
if (it.project.plugins.hasPlugin("com.android.library") ||
it.project.plugins.hasPlugin("com.android.application")) {
dependsOn(it.tasks.named("clean"))
}
}
@@ -82,13 +77,10 @@ tasks.register("clean", Delete::class.java) {
delete(rootProject.file("./packages/react-native/sdks/download/"))
delete(rootProject.file("./packages/react-native/sdks/hermes/"))
delete(
rootProject.file("./packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/arm64-v8a/")
)
rootProject.file("./packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/arm64-v8a/"))
delete(
rootProject.file(
"./packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/armeabi-v7a/"
)
)
"./packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/armeabi-v7a/"))
delete(rootProject.file("./packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/x86/"))
delete(rootProject.file("./packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/x86_64/"))
delete(rootProject.file("./packages/react-native-codegen/lib"))
@@ -106,8 +98,7 @@ tasks.register("publishAllToMavenTempLocal") {
dependsOn(":packages:react-native:ReactAndroid:publishAllPublicationsToMavenTempLocalRepository")
// We don't publish the external-artifacts to Maven Local as ci is using it via workspace.
dependsOn(
":packages:react-native:ReactAndroid:hermes-engine:publishAllPublicationsToMavenTempLocalRepository"
)
":packages:react-native:ReactAndroid:hermes-engine:publishAllPublicationsToMavenTempLocalRepository")
}
tasks.register("publishAndroidToSonatype") {
@@ -129,8 +120,7 @@ if (project.findProperty("react.internal.useHermesNightly")?.toString()?.toBoole
That's fine for local development, but you should not commit this change.
********************************************************************************
"""
.trimIndent()
)
.trimIndent())
allprojects {
configurations.all {
resolutionStrategy.dependencySubstitution {
@@ -162,12 +152,10 @@ allprojects {
"**/build/**",
"**/hermes-engine/**",
"**/internal/featureflags/**",
"**/systeminfo/ReactNativeVersion.kt",
)
"**/systeminfo/ReactNativeVersion.kt")
listOf(
com.ncorti.ktfmt.gradle.tasks.KtfmtCheckTask::class,
com.ncorti.ktfmt.gradle.tasks.KtfmtFormatTask::class,
)
com.ncorti.ktfmt.gradle.tasks.KtfmtFormatTask::class)
.forEach { tasks.withType(it) { exclude(excludePatterns) } }
// Disable the problematic ktfmt script tasks due to symbolic link issues in subprojects
@@ -177,7 +165,3 @@ allprojects {
}
}
}
// We intentionally disable the `ktfmtCheck` tasks as the formatting is primarly handled inside
// fbsource
allprojects { tasks.withType<com.ncorti.ktfmt.gradle.tasks.KtfmtCheckTask>() { enabled = false } }
+7 -7
View File
@@ -63,7 +63,7 @@
"@typescript-eslint/parser": "^8.36.0",
"ansi-styles": "^4.2.1",
"babel-plugin-minify-dead-code-elimination": "^0.5.2",
"babel-plugin-syntax-hermes-parser": "0.32.0",
"babel-plugin-syntax-hermes-parser": "0.31.2",
"babel-plugin-transform-define": "^2.1.4",
"babel-plugin-transform-flow-enums": "^0.0.2",
"clang-format": "^1.8.0",
@@ -81,17 +81,17 @@
"eslint-plugin-react-native": "^4.0.0",
"eslint-plugin-redundant-undefined": "^0.4.0",
"eslint-plugin-relay": "^1.8.3",
"flow-api-translator": "0.32.0",
"flow-bin": "^0.280.0",
"flow-api-translator": "0.31.2",
"flow-bin": "^0.279.0",
"glob": "^7.1.1",
"hermes-eslint": "0.32.0",
"hermes-transform": "0.32.0",
"hermes-eslint": "0.31.2",
"hermes-transform": "0.31.2",
"ini": "^5.0.0",
"inquirer": "^7.1.0",
"jest": "^29.7.0",
"jest-config": "^29.7.0",
"jest-diff": "^29.7.0",
"jest-junit": "^16.0.0",
"jest-junit": "^10.0.0",
"jest-snapshot": "^29.7.0",
"markdownlint-cli2": "^0.17.2",
"markdownlint-rule-relative-links": "^3.0.0",
@@ -102,7 +102,7 @@
"node-fetch": "^2.2.0",
"nullthrows": "^1.1.1",
"prettier": "3.6.2",
"prettier-plugin-hermes-parser": "0.32.0",
"prettier-plugin-hermes-parser": "0.31.1",
"react": "19.1.1",
"react-test-renderer": "19.1.1",
"rimraf": "^3.0.2",
@@ -81,147 +81,10 @@ export {Commands};
export default (codegenNativeComponent<ModuleProps>('Module'): NativeType);
`;
const COMMANDS_WITH_COVERAGE_INVALID = `
// @flow
const codegenNativeComponent = require('codegenNativeComponent');
import type {NativeComponentType} from 'codegenNativeComponent';
import type {ViewProps} from 'ViewPropTypes';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
type NativeType = NativeComponentType<ModuleProps>;
// Coverage instrumentation of invalid Commands export - should still fail
export const Commands = (cov_1234567890().s[0]++, {
hotspotUpdate: () => {},
scrollTo: () => {},
});
export default (codegenNativeComponent<ModuleProps>('Module'): NativeType);
`;
const COMMANDS_WITH_COVERAGE_WRONG_FUNCTION = `
// @flow
const codegenNativeComponent = require('codegenNativeComponent');
import type {NativeComponentType} from 'codegenNativeComponent';
import type {ViewProps} from 'ViewPropTypes';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
type NativeType = NativeComponentType<ModuleProps>;
// Coverage instrumentation of wrong function call - should fail
export const Commands = (cov_abcdef123().s[0]++, someOtherFunction({
supportedCommands: ['pause', 'play'],
}));
export default (codegenNativeComponent<ModuleProps>('Module'): NativeType);
`;
const COMMANDS_WITH_COMPLEX_COVERAGE_INVALID = `
// @flow
const codegenNativeComponent = require('codegenNativeComponent');
import type {NativeComponentType} from 'codegenNativeComponent';
import type {ViewProps} from 'ViewPropTypes';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
type NativeType = NativeComponentType<ModuleProps>;
// Complex coverage instrumentation with invalid nested structure - should fail
export const Commands = (
cov_xyz789().f[1]++,
cov_xyz789().s[2]++,
{
pause: (ref) => {},
play: (ref) => {},
}
);
export default (codegenNativeComponent<ModuleProps>('Module'): NativeType);
`;
const COMMANDS_WITH_COVERAGE_WRONG_NAME = `
// @flow
const codegenNativeCommands = require('codegenNativeCommands');
const codegenNativeComponent = require('codegenNativeComponent');
import type {NativeComponentType} from 'codegenNativeComponent';
import type {ViewProps} from 'ViewPropTypes';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
type NativeType = NativeComponentType<ModuleProps>;
interface NativeCommands {
+pause: (viewRef: React.ElementRef<NativeType>) => void;
+play: (viewRef: React.ElementRef<NativeType>) => void;
}
// Coverage instrumentation with correct function but wrong export name - should fail
export const WrongName = (cov_wrong123().s[0]++, codegenNativeCommands<NativeCommands>({
supportedCommands: ['pause', 'play'],
}));
export default (codegenNativeComponent<ModuleProps>('Module'): NativeType);
`;
const COMMANDS_WITH_COVERAGE_TYPE_CAST_INVALID = `
// @flow
const codegenNativeComponent = require('codegenNativeComponent');
import type {NativeComponentType} from 'codegenNativeComponent';
import type {ViewProps} from 'ViewPropTypes';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
type NativeType = NativeComponentType<ModuleProps>;
interface NativeCommands {
+pause: (viewRef: React.ElementRef<NativeType>) => void;
+play: (viewRef: React.ElementRef<NativeType>) => void;
}
// Coverage instrumentation with type cast but wrong function - should fail
export const Commands: NativeCommands = (cov_cast123().s[0]++, invalidFunction({
supportedCommands: ['pause', 'play'],
}));
export default (codegenNativeComponent<ModuleProps>('Module'): NativeType);
`;
module.exports = {
'CommandsExportedWithDifferentNameNativeComponent.js':
COMMANDS_EXPORTED_WITH_DIFFERENT_NAME,
'CommandsExportedWithShorthandNativeComponent.js':
COMMANDS_EXPORTED_WITH_SHORTHAND,
'OtherCommandsExportNativeComponent.js': OTHER_COMMANDS_EXPORT,
'CommandsWithCoverageInvalidNativeComponent.js':
COMMANDS_WITH_COVERAGE_INVALID,
'CommandsWithCoverageWrongFunctionNativeComponent.js':
COMMANDS_WITH_COVERAGE_WRONG_FUNCTION,
'CommandsWithComplexCoverageInvalidNativeComponent.js':
COMMANDS_WITH_COMPLEX_COVERAGE_INVALID,
'CommandsWithCoverageWrongNameNativeComponent.js':
COMMANDS_WITH_COVERAGE_WRONG_NAME,
'CommandsWithCoverageTypeCastInvalidNativeComponent.js':
COMMANDS_WITH_COVERAGE_TYPE_CAST_INVALID,
};
@@ -59,92 +59,6 @@ export default codegenNativeComponent<ModuleProps>('Module', {
});
`;
// Coverage instrumentation test cases - should be recognized as valid
const COMMANDS_WITH_SIMPLE_COVERAGE = `
// @flow
const codegenNativeCommands = require('codegenNativeCommands');
const codegenNativeComponent = require('codegenNativeComponent');
import type {ViewProps} from 'ViewPropTypes';
import type {NativeComponentType} from 'codegenNativeComponent';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
type NativeType = NativeComponentType<ModuleProps>;
interface NativeCommands {
+pause: (viewRef: React.ElementRef<NativeType>) => void;
+play: (viewRef: React.ElementRef<NativeType>) => void;
}
export const Commands = (cov_1234567890.s[0]++, codegenNativeCommands<NativeCommands>({
supportedCommands: ['pause', 'play'],
}));
export default codegenNativeComponent<ModuleProps>('Module');
`;
const COMMANDS_WITH_COMPLEX_COVERAGE = `
// @flow
const codegenNativeCommands = require('codegenNativeCommands');
const codegenNativeComponent = require('codegenNativeComponent');
import type {ViewProps} from 'ViewPropTypes';
import type {NativeComponentType} from 'codegenNativeComponent';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
type NativeType = NativeComponentType<ModuleProps>;
interface NativeCommands {
+seek: (viewRef: React.ElementRef<NativeType>, position: number) => void;
+stop: (viewRef: React.ElementRef<NativeType>) => void;
}
export const Commands = (
cov_abcdef123().f[2]++,
cov_abcdef123().s[5]++,
codegenNativeCommands<NativeCommands>({
supportedCommands: ['seek', 'stop'],
})
);
export default codegenNativeComponent<ModuleProps>('Module');
`;
const COMMANDS_WITH_TYPE_CAST_COVERAGE = `
// @flow
const codegenNativeCommands = require('codegenNativeCommands');
const codegenNativeComponent = require('codegenNativeComponent');
import type {ViewProps} from 'ViewPropTypes';
import type {NativeComponentType} from 'codegenNativeComponent';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
type NativeType = NativeComponentType<ModuleProps>;
interface NativeCommands {
+mute: (viewRef: React.ElementRef<NativeType>) => void;
+unmute: (viewRef: React.ElementRef<NativeType>) => void;
}
export const Commands: NativeCommands = (cov_xyz789().s[1]++, codegenNativeCommands<NativeCommands>({
supportedCommands: ['mute', 'unmute'],
}));
export default codegenNativeComponent<ModuleProps>('Module');
`;
const FULL_NATIVE_COMPONENT_WITH_TYPE_EXPORT = `
// @flow
@@ -193,9 +107,4 @@ module.exports = {
'NotANativeComponent.js': NOT_A_NATIVE_COMPONENT,
'FullNativeComponent.js': FULL_NATIVE_COMPONENT,
'FullTypedNativeComponent.js': FULL_NATIVE_COMPONENT_WITH_TYPE_EXPORT,
'CommandsWithSimpleCoverageNativeComponent.js': COMMANDS_WITH_SIMPLE_COVERAGE,
'CommandsWithComplexCoverageNativeComponent.js':
COMMANDS_WITH_COMPLEX_COVERAGE,
'CommandsWithTypeCastCoverageNativeComponent.js':
COMMANDS_WITH_TYPE_CAST_COVERAGE,
};
@@ -1,77 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Babel plugin inline view configs can inline config for CommandsWithComplexCoverageNativeComponent.js 1`] = `
"// @flow
const codegenNativeCommands = require('codegenNativeCommands');
const codegenNativeComponent = require('codegenNativeComponent');
import type { ViewProps } from 'ViewPropTypes';
import type { NativeComponentType } from 'codegenNativeComponent';
type ModuleProps = $ReadOnly<{|
...ViewProps
|}>;
type NativeType = NativeComponentType<ModuleProps>;
interface NativeCommands {
+seek: (viewRef: React.ElementRef<NativeType>, position: number) => void,
+stop: (viewRef: React.ElementRef<NativeType>) => void,
}
const NativeComponentRegistry = require('react-native/Libraries/NativeComponent/NativeComponentRegistry');
let nativeComponentName = 'Module';
export const __INTERNAL_VIEW_CONFIG = {
uiViewClassName: \\"Module\\",
validAttributes: {}
};
export default NativeComponentRegistry.get(nativeComponentName, () => __INTERNAL_VIEW_CONFIG);"
`;
exports[`Babel plugin inline view configs can inline config for CommandsWithSimpleCoverageNativeComponent.js 1`] = `
"// @flow
const codegenNativeCommands = require('codegenNativeCommands');
const codegenNativeComponent = require('codegenNativeComponent');
import type { ViewProps } from 'ViewPropTypes';
import type { NativeComponentType } from 'codegenNativeComponent';
type ModuleProps = $ReadOnly<{|
...ViewProps
|}>;
type NativeType = NativeComponentType<ModuleProps>;
interface NativeCommands {
+pause: (viewRef: React.ElementRef<NativeType>) => void,
+play: (viewRef: React.ElementRef<NativeType>) => void,
}
const NativeComponentRegistry = require('react-native/Libraries/NativeComponent/NativeComponentRegistry');
let nativeComponentName = 'Module';
export const __INTERNAL_VIEW_CONFIG = {
uiViewClassName: \\"Module\\",
validAttributes: {}
};
export default NativeComponentRegistry.get(nativeComponentName, () => __INTERNAL_VIEW_CONFIG);"
`;
exports[`Babel plugin inline view configs can inline config for CommandsWithTypeCastCoverageNativeComponent.js 1`] = `
"// @flow
const codegenNativeCommands = require('codegenNativeCommands');
const codegenNativeComponent = require('codegenNativeComponent');
import type { ViewProps } from 'ViewPropTypes';
import type { NativeComponentType } from 'codegenNativeComponent';
type ModuleProps = $ReadOnly<{|
...ViewProps
|}>;
type NativeType = NativeComponentType<ModuleProps>;
interface NativeCommands {
+mute: (viewRef: React.ElementRef<NativeType>) => void,
+unmute: (viewRef: React.ElementRef<NativeType>) => void,
}
const NativeComponentRegistry = require('react-native/Libraries/NativeComponent/NativeComponentRegistry');
let nativeComponentName = 'Module';
export const __INTERNAL_VIEW_CONFIG = {
uiViewClassName: \\"Module\\",
validAttributes: {}
};
export default NativeComponentRegistry.get(nativeComponentName, () => __INTERNAL_VIEW_CONFIG);"
`;
exports[`Babel plugin inline view configs can inline config for FullNativeComponent.js 1`] = `
"// @flow
@@ -225,61 +153,6 @@ exports[`Babel plugin inline view configs fails on inline config for CommandsExp
24 |"
`;
exports[`Babel plugin inline view configs fails on inline config for CommandsWithComplexCoverageInvalidNativeComponent.js 1`] = `
"/CommandsWithComplexCoverageInvalidNativeComponent.js: 'Commands' is a reserved export and may only be used to export the result of codegenNativeCommands.
14 |
15 | // Complex coverage instrumentation with invalid nested structure - should fail
> 16 | export const Commands = (
| ^
17 | cov_xyz789().f[1]++,
18 | cov_xyz789().s[2]++,
19 | {"
`;
exports[`Babel plugin inline view configs fails on inline config for CommandsWithCoverageInvalidNativeComponent.js 1`] = `
"/CommandsWithCoverageInvalidNativeComponent.js: 'Commands' is a reserved export and may only be used to export the result of codegenNativeCommands.
14 |
15 | // Coverage instrumentation of invalid Commands export - should still fail
> 16 | export const Commands = (cov_1234567890().s[0]++, {
| ^
17 | hotspotUpdate: () => {},
18 | scrollTo: () => {},
19 | });"
`;
exports[`Babel plugin inline view configs fails on inline config for CommandsWithCoverageTypeCastInvalidNativeComponent.js 1`] = `
"/CommandsWithCoverageTypeCastInvalidNativeComponent.js: 'Commands' is a reserved export and may only be used to export the result of codegenNativeCommands.
19 |
20 | // Coverage instrumentation with type cast but wrong function - should fail
> 21 | export const Commands: NativeCommands = (cov_cast123().s[0]++, invalidFunction({
| ^
22 | supportedCommands: ['pause', 'play'],
23 | }));
24 |"
`;
exports[`Babel plugin inline view configs fails on inline config for CommandsWithCoverageWrongFunctionNativeComponent.js 1`] = `
"/CommandsWithCoverageWrongFunctionNativeComponent.js: 'Commands' is a reserved export and may only be used to export the result of codegenNativeCommands.
14 |
15 | // Coverage instrumentation of wrong function call - should fail
> 16 | export const Commands = (cov_abcdef123().s[0]++, someOtherFunction({
| ^
17 | supportedCommands: ['pause', 'play'],
18 | }));
19 |"
`;
exports[`Babel plugin inline view configs fails on inline config for CommandsWithCoverageWrongNameNativeComponent.js 1`] = `
"/CommandsWithCoverageWrongNameNativeComponent.js: Native commands must be exported with the name 'Commands'
20 |
21 | // Coverage instrumentation with correct function but wrong export name - should fail
> 22 | export const WrongName = (cov_wrong123().s[0]++, codegenNativeCommands<NativeCommands>({
| ^
23 | supportedCommands: ['pause', 'play'],
24 | }));
25 |"
`;
exports[`Babel plugin inline view configs fails on inline config for OtherCommandsExportNativeComponent.js 1`] = `
"/OtherCommandsExportNativeComponent.js: 'Commands' is a reserved export and may only be used to export the result of codegenNativeCommands.
17 | }
+6 -58
View File
@@ -102,58 +102,6 @@ function isCodegenDeclaration(declaration) {
return false;
}
function isCodegenNativeCommandsDeclaration(declaration) {
if (!declaration) {
return false;
}
// Handle direct calls: codegenNativeCommands()
if (
declaration.type === 'CallExpression' &&
declaration.callee &&
declaration.callee.type === 'Identifier' &&
declaration.callee.name === 'codegenNativeCommands'
) {
return true;
}
// Handle coverage instrumentation: (cov_xxx().s[0]++, codegenNativeCommands())
if (declaration.type === 'SequenceExpression' && declaration.expressions) {
// Get the last expression in the sequence (the actual function call)
const lastExpression =
declaration.expressions[declaration.expressions.length - 1];
// Recursively check if the last expression is a valid codegenNativeCommands call
return isCodegenNativeCommandsDeclaration(lastExpression);
}
// Handle Flow type casts: (codegenNativeCommands(): NativeCommands)
if (
(declaration.type === 'TypeCastExpression' ||
declaration.type === 'AsExpression') &&
declaration.expression &&
declaration.expression.type === 'CallExpression' &&
declaration.expression.callee &&
declaration.expression.callee.type === 'Identifier' &&
declaration.expression.callee.name === 'codegenNativeCommands'
) {
return true;
}
// Handle TypeScript assertions: codegenNativeCommands() as NativeCommands
if (
declaration.type === 'TSAsExpression' &&
declaration.expression &&
declaration.expression.type === 'CallExpression' &&
declaration.expression.callee &&
declaration.expression.callee.type === 'Identifier' &&
declaration.expression.callee.name === 'codegenNativeCommands'
) {
return true;
}
return false;
}
module.exports = function ({parse, types: t}) {
return {
pre(state) {
@@ -177,12 +125,12 @@ module.exports = function ({parse, types: t}) {
const firstDeclaration = path.node.declaration.declarations[0];
if (firstDeclaration.type === 'VariableDeclarator') {
// Check if this is a valid codegenNativeCommands call, handling type annotations
const isValidCommandsExport = isCodegenNativeCommandsDeclaration(
firstDeclaration.init,
);
if (isValidCommandsExport) {
if (
firstDeclaration.init &&
firstDeclaration.init.type === 'CallExpression' &&
firstDeclaration.init.callee.type === 'Identifier' &&
firstDeclaration.init.callee.name === 'codegenNativeCommands'
) {
if (
firstDeclaration.id.type === 'Identifier' &&
firstDeclaration.id.name !== 'Commands'
@@ -40,9 +40,6 @@
"peerDependenciesMeta": {
"@react-native-community/cli": {
"optional": true
},
"@react-native/metro-config": {
"optional": true
}
},
"engines": {
@@ -31,9 +31,9 @@ type MiddlewareReturn = {
...
};
// $FlowFixMe[incompatible-type]
// $FlowFixMe
const unusedStubWSServer: ws$WebSocketServer = {};
// $FlowFixMe[incompatible-type]
// $FlowFixMe
const unusedMiddlewareStub: Server = {};
const communityMiddlewareFallback = {
@@ -1,33 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`prepareDebuggerShellFromDotSlashFile fails with the expected error message for a missing dotslash file 1`] = `
Object {
"code": "unexpected_error",
"humanReadableMessage": "An unexpected error occured while installing the latest version of React Native DevTools. Using a fallback version instead.",
"verboseInfo": Any<String>,
}
`;
exports[`prepareDebuggerShellFromDotSlashFile fails with the expected error message for missing platforms 1`] = `
Object {
"code": "platform_not_supported",
"humanReadableMessage": "The latest version of React Native DevTools is not supported on this platform. Using a fallback version instead.",
"verboseInfo": Any<String>,
}
`;
exports[`prepareDebuggerShellFromDotSlashFile scenarios requiring a local HTTP server fails with the expected error message for a corrupted tarball 1`] = `
Object {
"code": "possible_corruption",
"humanReadableMessage": "Failed to verify the latest version of React Native DevTools. Using a fallback version instead. ",
"verboseInfo": Any<String>,
}
`;
exports[`prepareDebuggerShellFromDotSlashFile scenarios requiring a local HTTP server fails with the expected error message for a network error 1`] = `
Object {
"code": "likely_offline",
"humanReadableMessage": "Failed to download the latest version of React Native DevTools. Using a fallback version instead. Connect to the internet or check your network settings.",
"verboseInfo": Any<String>,
}
`;
@@ -1,59 +0,0 @@
#!/usr/bin/env dotslash
{
"name": "React Native DevTools",
"platforms": {
"linux-aarch64": {
"size": 113510892,
"hash": "sha256",
"digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"providers": [
{
"type": "http",
"url": "http://$HOST:$PORT/corrupted.tar.gz"
}
],
"format": "tar.gz",
"path": "React Native DevTools-linux-arm64/React Native DevTools"
},
"linux-x86_64": {
"size": 113243910,
"hash": "sha256",
"digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"providers": [
{
"type": "http",
"url": "http://$HOST:$PORT/corrupted.tar.gz"
}
],
"format": "tar.gz",
"path": "React Native DevTools-linux-x64/React Native DevTools"
},
"macos-aarch64": {
"size": 108810433,
"hash": "sha256",
"digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"providers": [
{
"type": "http",
"url": "http://$HOST:$PORT/corrupted.tar.gz"
}
],
"format": "tar.gz",
"path": "React Native DevTools.app/Contents/MacOS/React Native DevTools"
},
"macos-x86_64": {
"size": 113769989,
"hash": "sha256",
"digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"providers": [
{
"type": "http",
"url": "http://$HOST:$PORT/corrupted.tar.gz"
}
],
"format": "tar.gz",
"path": "React Native DevTools.app/Contents/MacOS/React Native DevTools"
}
}
}
@@ -1,59 +0,0 @@
#!/usr/bin/env dotslash
{
"name": "React Native DevTools",
"platforms": {
"linux-aarch64": {
"size": 113510892,
"hash": "sha256",
"digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"providers": [
{
"type": "http",
"url": "https://$HOST:$PORT/does-not-exist"
}
],
"format": "tar.gz",
"path": "React Native DevTools-linux-arm64/React Native DevTools"
},
"linux-x86_64": {
"size": 113243910,
"hash": "sha256",
"digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"providers": [
{
"type": "http",
"url": "https://$HOST:$PORT/does-not-exist"
}
],
"format": "tar.gz",
"path": "React Native DevTools-linux-x64/React Native DevTools"
},
"macos-aarch64": {
"size": 108810433,
"hash": "sha256",
"digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"providers": [
{
"type": "http",
"url": "https://$HOST:$PORT/does-not-exist"
}
],
"format": "tar.gz",
"path": "React Native DevTools.app/Contents/MacOS/React Native DevTools"
},
"macos-x86_64": {
"size": 113769989,
"hash": "sha256",
"digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"providers": [
{
"type": "http",
"url": "https://$HOST:$PORT/does-not-exist"
}
],
"format": "tar.gz",
"path": "React Native DevTools.app/Contents/MacOS/React Native DevTools"
}
}
}
@@ -1,6 +0,0 @@
#!/usr/bin/env dotslash
{
"name": "React Native DevTools",
"platforms": {}
}
@@ -1,139 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
const {
prepareDebuggerShellFromDotSlashFile,
} = require('../src/node/private/LaunchUtils');
const fs = require('fs').promises;
const http = require('http');
const os = require('os');
const path = require('path');
// The implementation of prepareDebuggerShellFromDotSlashFile relies on
// details of DotSlash that are not guaranteed to be stable (support for
// `dotslash -- fetch <file>`, certain strings being printed to stderr).
// This (admittedly elaborate) test suite ensures we'll fail loudly if we
// try to upgrade DotSlash to a version that breaks our assumptions.
describe('prepareDebuggerShellFromDotSlashFile', () => {
test('fails with the expected error message for missing platforms', async () => {
const result = await prepareDebuggerShellFromDotSlashFile(
path.join(__dirname, 'dotslash-file-with-missing-platforms.jsonc'),
);
expect(result).toMatchSnapshot({
verboseInfo: expect.any(String),
});
});
test('fails with the expected error message for a missing dotslash file', async () => {
const result = await prepareDebuggerShellFromDotSlashFile(
path.join(__dirname, 'dotslash-file-that-does-not-exist.jsonc'),
);
expect(result).toMatchSnapshot({
verboseInfo: expect.any(String),
});
});
describe('scenarios requiring a local HTTP server', () => {
let server, scratchDir;
beforeEach(async () => {
scratchDir = await fs.mkdtemp(path.join(os.tmpdir(), 'dotslash-test-'));
server = http.createServer((request, response) => {
if (request.url === '/corrupted.tar.gz') {
response.writeHead(200, {'Content-Type': 'application/gzip'});
response.end(
'Hello, world!\n' + 'This simulated a corrupted tarball.',
);
} else {
response.writeHead(404);
response.end();
}
});
await new Promise((resolve, reject) => {
server.on('error', reject);
server.listen(0, 'localhost', () => {
server.removeListener('error', reject);
resolve();
});
});
});
afterEach(async () => {
await fs.rm(scratchDir, {recursive: true, force: true});
if (server.listening) {
await new Promise((resolve, reject) => {
server.close(error => {
if (error) {
reject(error);
} else {
resolve();
}
});
});
}
});
test('fails with the expected error message for a corrupted tarball', async () => {
const dotslashFileContents = injectHostPort(
await fs.readFile(
path.join(
__dirname,
'dotslash-file-simulating-data-corruption.jsonc',
),
'utf8',
),
server.address(),
);
await fs.writeFile(
path.join(scratchDir, 'dotslash-file.jsonc'),
dotslashFileContents,
);
const result = await prepareDebuggerShellFromDotSlashFile(
path.join(scratchDir, 'dotslash-file.jsonc'),
);
expect(result).toMatchSnapshot({
verboseInfo: expect.any(String),
});
});
test('fails with the expected error message for a network error', async () => {
const dotslashFileContents = injectHostPort(
await fs.readFile(
path.join(__dirname, 'dotslash-file-simulating-network-error.jsonc'),
'utf8',
),
server.address(),
);
await fs.writeFile(
path.join(scratchDir, 'dotslash-file.jsonc'),
dotslashFileContents,
);
const result = await prepareDebuggerShellFromDotSlashFile(
path.join(scratchDir, 'dotslash-file.jsonc'),
);
expect(result).toMatchSnapshot({
verboseInfo: expect.any(String),
});
});
});
});
function injectHostPort(
dotslashFileContents: string,
address: net$Socket$address,
) {
const host =
address.family === 'IPv6' ? `[${address.address}]` : address.address;
return dotslashFileContents
.replaceAll('$HOST', host)
.replaceAll('$PORT', address.port.toString());
}
@@ -22,7 +22,7 @@ describe('Electron dependency', () => {
// $FlowFixMe[untyped-import] - package.json is not typed
const ourPackageJson = require('../package.json');
const declaredElectronVersion = ourPackageJson.devDependencies.electron;
const declaredElectronVersion = ourPackageJson.dependencies.electron;
expect(declaredElectronVersion).toBeTruthy();
// $FlowFixMe[untyped-import] - package.json is not typed
@@ -1,75 +1,62 @@
#!/usr/bin/env dotslash
// @generated SignedSource<<e93d55b5e28943e44271f5d3738083e0>>
// @generated SignedSource<<14de73ea0ed751d80c7c687c6aeb123f>>
{
"name": "React Native DevTools",
"platforms": {
"linux-aarch64": {
"size": 116060647,
"size": 116120331,
"hash": "sha256",
"digest": "4352f1c9848ca919101ec628bd08b87a72a828d1ab55fa43a02098329fa452fa",
"digest": "5a1747bdb50f8140d96e99b31f9a603ceaf52e777e5dd59f65edacd87f8c6348",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQM24LW0nPZRk0ypuIG9prz_72YjBJNcVlGSIEpO4zdlLXgw4dFNodH7MKg9eKNTnx7wrVDDBNACrnEPt_OfXOjZyZsV9Oaqu0-vNFRdlEyis4YqmpqGLtz3LvD-9R6fzcWxJI9zrhdPvOvlXP-3Syt1UNITaxXDVqIwAAYpCaAh0oLpupAFCc2yvYw"
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQMRq1ou56GjpsIRFHpozEYiPfCuVvgWQVwiMMPBbwKyBnebit8HDGKof5XgDHbAKCqAZSgC8L22eJETnqIUM3kEAMYNXcHviIGy41rsXKVDYDgyWlGFB1zP2WzHrjWagfD062Pt4q5GqvCG5RVlhz656BOsutU7B4pDXGFCIdry7FveKn0PXGxvd1E"
}
],
"format": "tar.gz",
"path": "React Native DevTools-linux-arm64/React Native DevTools"
},
"linux-x86_64": {
"size": 115930333,
"size": 116056146,
"hash": "sha256",
"digest": "11c7b07942928a6301b07fbf2bc77ce1229b2a52891f23541cdd9858b5250e64",
"digest": "b48a3e392ac482de8058917879cf07fd5934dcb84aa901d4fe0d29273b503f54",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQNDwm7HZRhtNxHqMr1FfSb0afHFGrn1OHxH0gOiggrLrht9QRUgJ3GG5jj7huhQzMRogE-LCMsnxh1ioOZks-YYX4KRt6Kj1-whdWsGFc7lBhPOpk1ssbYFGN1NNyuyFRmH-3nCY3lBC4AmbCUkbDTUeCi9DidCtJeyc73CZJEu7M62rIzxR2yV"
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQOyyb_LXrME2ubBGSkEi1vDw-2hwuHgHwnR-kAGQyhJK7lnELQDXKX1xW_u0joDwbTOhmiptwenq07G2NFkrY3t_AXefb_xTu2qHzpmrsX2YcwJlewbprgbuX7Uvdhqncb_IRAnJ4ogYKHUg6CZBNmLCQsyDsoqmkXtJ9ikJcQeDu2aiqbb-RWJ"
}
],
"format": "tar.gz",
"path": "React Native DevTools-linux-x64/React Native DevTools"
},
"macos-aarch64": {
"size": 110891041,
"size": 110957864,
"hash": "sha256",
"digest": "3cbe8b1b3d17e433347f1601435bb9a6cb758528a5c176a66fc52d9977223175",
"digest": "7964d83c857f12bb741abf4377771f3f3697b81df6283dd88d75ae43991afb73",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQOmC2cqqSv4OrSJKJroYVg_NE8OE4O73AXqY7wXiYqiWQVkDt0Xnyw3ZeUpQT_Qb0-OoT5F8REKoFrB6eqwat8Ovkyina30peYTTwNUzmwnnGQEg7J0fOHNxLF4dkmU1FagXtsoWgex4dKgsK_VpcMsHj3Vp7diomkYvWBVTf_gPVEseYSN9oKq92qa"
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQM7USVzavWxZkjOO6CasnSfPIfE08jJAkwfVO0qWiYBli136vpzA_HS89ZqsIsAC_GXeT7K-K9BxdON7z5qBoRMUygAay7z4DGT5OZ9YSf9MDCd0JOzah5_6s3ijw2j4eeRu8ZNYzI3aTutDXtPMJAb2KfBHGx2lEiSW5YK9idcB5Y2boAWeDXXX5nb"
}
],
"format": "tar.gz",
"path": "React Native DevTools.app/Contents/MacOS/React Native DevTools"
},
"macos-x86_64": {
"size": 117766158,
"size": 117827315,
"hash": "sha256",
"digest": "6fb79bc2ba3008401b4c9c128248657b95b98581ccde60f8fadb622163779775",
"digest": "bab2fac43def4a82fb88300aac05180eeda24f31cc00402a3ff7ca2e612bd532",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQMMtGn-YGdfLfTVWC8zbQkQx65Asq6iArKt1t__cjZ8UY_s6-sX5XBHr8k1SaexAO21dFZENQVZ1jW_wn_gJ9ENvosQDG1KfWMViKsHli0xRzZ1HVsgPIj_KVXe907QZwwtJf2XhgH0HT8dfH-AQdDcd0_TB5DFUwOsHzhH0nBrHet7YFkbJtPTaA"
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQPYS0ZRQ7RV1S-yy3tut6pRqcKdPcOiKfekrA5AXdd_M-HDaXLwJS57iAFU2K2X-EA_cyg25C3L-5L7O3eyNKPMToZHbV282GiojnNSKFNjsjj9_B737lOwHI_XqbDQEIiNJZ7NjbkZ8_iMKK-LNL-Ydha2ORWWqytuzP4sWQ6sm0XIxsdyQ6bOLw"
}
],
"format": "tar.gz",
"path": "React Native DevTools.app/Contents/MacOS/React Native DevTools"
},
"windows-x86_64": {
"size": 125527537,
"hash": "sha256",
"digest": "579a5b0944c51c3b1b541ad5af66c1ffedf93cae2a891ecdf88cb7219fd9b096",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQOQ3E8lBXqdVHbDPyVb5AOQMrDWjFrFV8fnLLBsygQvLWdpu6ixyG9PgWdwpi5jM-XcDdCHkhBdhaq-5dwT_tgRWKCAMsEBoAIUk0Xg77mGyHG2VF7bNfQ2qFBMuObrsTmrKy1nJ-UFDDm29pJD4GkFQW5NesiBwndJj8t3B8Ur8cczh_XR8rF5"
}
],
"format": "tar.gz",
"path": "React Native DevTools-win32-x64/React Native DevTools.exe"
}
}
}
+4 -10
View File
@@ -26,20 +26,14 @@
},
"license": "MIT",
"engines": {
"node": ">= 20.19.4"
"node": ">= 20.19.4",
"electron": ">=37.2.6"
},
"dependencies": {
"cross-spawn": "^7.0.6",
"fb-dotslash": "0.5.8"
"electron": "37.2.6"
},
"devDependencies": {
"electron": "37.2.6",
"semver": "^7.1.3"
},
"files": [
"!**/__tests__/**",
"bin",
"dist",
"!src/electron"
]
}
}
@@ -1,13 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
export default {
revision: 'dev',
};
@@ -1,19 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* %s
* @flow strict-local
* @format
*/
'use strict';
module.exports = {
default: {
revision: %s,
},
__esModule: true,
};
@@ -36,7 +36,7 @@ function handleLaunchArgs(argv: string[]) {
});
// Find an existing window for this app and launch configuration.
let frontendWindow = BrowserWindow.getAllWindows().find(window => {
const existingWindow = BrowserWindow.getAllWindows().find(window => {
const metadata = windowMetadata.get(window);
if (!metadata) {
return false;
@@ -44,39 +44,41 @@ function handleLaunchArgs(argv: string[]) {
return metadata.windowKey === windowKey;
});
if (frontendWindow) {
if (existingWindow) {
// If the window is already visible, flash it.
if (frontendWindow.isVisible()) {
frontendWindow.flashFrame(true);
if (existingWindow.isVisible()) {
existingWindow.flashFrame(true);
setTimeout(() => {
frontendWindow.flashFrame(false);
existingWindow.flashFrame(false);
}, 1000);
}
} else {
// Create the browser window.
frontendWindow = new BrowserWindow({
width: 1200,
height: 600,
webPreferences: {
partition: 'persist:react-native-devtools',
preload: require.resolve('./preload.js'),
},
// Icon for Linux
icon: path.join(__dirname, 'resources', 'icon.png'),
});
// Auto-hide the Windows/Linux menu bar
frontendWindow.setMenuBarVisibility(false);
if (process.platform === 'darwin') {
app.focus({
steal: true,
});
}
existingWindow.focus();
return;
}
// Create the browser window.
const frontendWindow = new BrowserWindow({
width: 1200,
height: 600,
webPreferences: {
partition: 'persist:react-native-devtools',
preload: require.resolve('./preload.js'),
},
// Icon for Linux
icon: path.join(__dirname, 'resources', 'icon.png'),
});
// Open links in the default browser instead of in new Electron windows.
frontendWindow.webContents.setWindowOpenHandler(({url}) => {
shell.openExternal(url);
return {action: 'deny'};
});
// TODO: If the window contains a live, working frontend instance with a valid connection to the backend,
// we should avoid this reload and instead send the frontend a message to handle the launch arguments
// dynamically (e.g. update the launch ID for telemetry purposes, handle deeplinking to a specific CDT panel, etc).
frontendWindow.loadURL(frontendUrl);
windowMetadata.set(frontendWindow, {
@@ -88,7 +90,6 @@ function handleLaunchArgs(argv: string[]) {
steal: true,
});
}
frontendWindow.focus();
}
app.whenReady().then(() => {
@@ -8,18 +8,9 @@
* @format
*/
import buildInfo from './BuildInfo';
// $FlowFixMe[untyped-import] Flow doesn't infer JSON types
const pkg = require('../../package.json');
const util = require('util');
// $FlowFixMe[unclear-type] We have no Flow types for the Electron API.
const {app} = require('electron') as any;
// Set the app name and version early - these are used in --version as well as
// in the User-Agent string.
app.setName(pkg.name);
app.setVersion(pkg.version + '-' + buildInfo.revision);
const util = require('util');
// Handle global command line arguments which don't require a window
// or the single instance lock to be held.
@@ -1,48 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/
const {unstable_spawnDebuggerShellWithArgs} = require('../../');
describe('debugger-shell Node package', () => {
test('can spawn in detached+prebuilt mode without crashing', async () => {
await expect(
unstable_spawnDebuggerShellWithArgs(['--version'], {
flavor: 'prebuilt',
mode: 'detached',
}),
).resolves.toBeUndefined();
});
// When running in the internal react-native-oss-js job, Electron isn't
// installed correctly (postinstall scripts don't run) but the internal
// `electron` workspace isn't available either. Detecting this dynamically
// weakens the test somewhat in environments where it *should* pass, but this
// is a dev-only feature anyway so this is fine.
if (isElectronInstalled()) {
test('can spawn in detached+dev mode without crashing', async () => {
await expect(
unstable_spawnDebuggerShellWithArgs(['--version'], {
flavor: 'dev',
mode: 'detached',
}),
).resolves.toBeUndefined();
});
}
});
function isElectronInstalled() {
try {
require('electron');
return true;
} catch {
return false;
}
}
+17 -114
View File
@@ -8,54 +8,44 @@
* @format
*/
import {
prepareDebuggerShellFromDotSlashFile,
spawnAndGetStderr,
} from './private/LaunchUtils';
const {spawn} = require('cross-spawn');
const path = require('path');
// The 'prebuilt' flavor will use the prebuilt shell binary (and the JavaScript embedded in it).
// The 'dev' flavor will use a stock Electron binary and run the shell code from the `electron/` directory.
type DebuggerShellFlavor = 'prebuilt' | 'dev';
const DEVTOOLS_BINARY_DOTSLASH_FILE = path.join(
__dirname,
'../../bin/react-native-devtools',
);
async function unstable_spawnDebuggerShellWithArgs(
args: string[],
{
mode = 'detached',
flavor = 'prebuilt',
}: $ReadOnly<{
// In 'syncAndExit' mode, the current process will block until the spawned process exits, and then it will exit
// with the same exit code as the spawned process.
// In 'detached' mode, the spawned process will be detached from the current process and the current process will
// continue to run normally.
mode?: 'syncThenExit' | 'detached',
flavor?: DebuggerShellFlavor,
}> = {},
): Promise<void> {
const [binaryPath, baseArgs] = getShellBinaryAndArgs(flavor);
// NOTE: Internally at Meta, this is aliased to a workspace that is
// API-compatible with the 'electron' package, but contains prebuilt binaries
// that do not need to be downloaded in a postinstall action.
const electronPath = require('electron');
return new Promise((resolve, reject) => {
const child = spawn(binaryPath, [...baseArgs, ...args], {
stdio: 'inherit',
windowsHide: true,
detached: mode === 'detached',
});
const child = spawn(
electronPath,
[require.resolve('../electron'), ...args],
{
stdio: 'inherit',
windowsHide: true,
detached: mode === 'detached',
},
);
if (mode === 'detached') {
child.on('spawn', () => {
resolve();
});
child.on('close', (code: number) => {
child.on('close', (code /*: number */) => {
if (code !== 0) {
reject(
new Error(
`Failed to open debugger shell: exited with code ${code}`,
`Failed to open debugger shell: ${electronPath} exited with code ${code}`,
),
);
}
@@ -64,7 +54,7 @@ async function unstable_spawnDebuggerShellWithArgs(
} else if (mode === 'syncThenExit') {
child.on('close', function (code, signal) {
if (code === null) {
console.error('Debugger shell exited with signal', signal);
console.error(electronPath, 'exited with signal', signal);
process.exit(1);
}
process.exit(code);
@@ -84,91 +74,4 @@ async function unstable_spawnDebuggerShellWithArgs(
});
}
export type DebuggerShellPreparationResult = $ReadOnly<{
code:
| 'success'
| 'not_implemented'
| 'likely_offline'
| 'platform_not_supported'
| 'possible_corruption'
| 'unexpected_error',
humanReadableMessage?: string,
verboseInfo?: string,
}>;
/**
* Attempts to prepare the debugger shell for use and returns a coded result
* that can be used to advise the user on how to proceed in case of failure.
* In particular, this function will attempt to download and extract an
* appropriate binary for the "prebuilt" flavor.
*
* This function should be called early during dev server startup, in parallel
* with other initialization steps, so that the debugger shell is ready to use
* instantly when the user tries to open it (and conversely, the user is
* informed ASAP if it is not ready to use).
*/
async function unstable_prepareDebuggerShell(
flavor: DebuggerShellFlavor,
): Promise<DebuggerShellPreparationResult> {
const [binaryPath, baseArgs] = getShellBinaryAndArgs(flavor);
try {
switch (flavor) {
case 'prebuilt':
const prebuiltResult = await prepareDebuggerShellFromDotSlashFile(
DEVTOOLS_BINARY_DOTSLASH_FILE,
);
if (prebuiltResult.code !== 'success') {
return prebuiltResult;
}
break;
case 'dev':
break;
default:
flavor as empty;
throw new Error(`Unknown flavor: ${flavor}`);
}
const {code, stderr} = await spawnAndGetStderr(binaryPath, [
...baseArgs,
'--version',
]);
if (code !== 0) {
return {
code: 'unexpected_error',
verboseInfo: stderr,
};
}
return {code: 'success'};
} catch (e) {
return {
code: 'unexpected_error',
verboseInfo: e.message,
};
}
}
function getShellBinaryAndArgs(
flavor: DebuggerShellFlavor,
): [string, Array<string>] {
switch (flavor) {
case 'prebuilt':
return [
// $FlowFixMe[cannot-resolve-module] fb-dotslash includes Flow types but Flow does not pick them up
require('fb-dotslash'),
[DEVTOOLS_BINARY_DOTSLASH_FILE],
];
case 'dev':
return [
// NOTE: Internally at Meta, this is aliased to a workspace that is
// API-compatible with the 'electron' package, but contains prebuilt binaries
// that do not need to be downloaded in a postinstall action.
require('electron'),
[require.resolve('../electron')],
];
default:
flavor as empty;
throw new Error(`Unknown flavor: ${flavor}`);
}
}
export {unstable_spawnDebuggerShellWithArgs, unstable_prepareDebuggerShell};
export {unstable_spawnDebuggerShellWithArgs};
@@ -1,98 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type {DebuggerShellPreparationResult} from '../';
const {spawn} = require('cross-spawn');
async function spawnAndGetStderr(
command: string,
args: string[],
): Promise<{
code: number,
stderr: string,
}> {
return new Promise((resolve, reject) => {
const child = spawn(command, args, {
stdio: ['ignore', 'ignore', 'pipe'],
encoding: 'utf8',
windowsHide: true,
});
let stderr = '';
child.stderr.on('data', data => {
stderr += data;
});
child.on('error', error => {
reject(error);
});
child.on('close', (code, signal) => {
resolve({
code,
stderr,
});
});
});
}
async function prepareDebuggerShellFromDotSlashFile(
filePath: string,
): Promise<DebuggerShellPreparationResult> {
const {code, stderr} = await spawnAndGetStderr(
// $FlowFixMe[cannot-resolve-module] fb-dotslash includes Flow types but Flow does not pick them up
require('fb-dotslash'),
['--', 'fetch', filePath],
);
if (code === 0) {
return {code: 'success'};
}
if (
stderr.includes('dotslash error') &&
stderr.includes('no providers succeeded')
) {
if (stderr.includes('failed to verify artifact')) {
return {
code: 'possible_corruption',
humanReadableMessage:
'Failed to verify the latest version of React Native DevTools. ' +
'Using a fallback version instead. ',
verboseInfo: stderr,
};
}
return {
code: 'likely_offline',
humanReadableMessage:
'Failed to download the latest version of React Native DevTools. ' +
'Using a fallback version instead. ' +
'Connect to the internet or check your network settings.',
verboseInfo: stderr,
};
}
if (
stderr.includes('dotslash error') &&
stderr.includes('platform not supported')
) {
return {
code: 'platform_not_supported',
humanReadableMessage:
'The latest version of React Native DevTools is not supported on this platform. ' +
'Using a fallback version instead.',
verboseInfo: stderr,
};
}
return {
code: 'unexpected_error',
humanReadableMessage:
'An unexpected error occured while installing the latest version of React Native DevTools. ' +
'Using a fallback version instead.',
verboseInfo: stderr,
};
}
export {spawnAndGetStderr, prepareDebuggerShellFromDotSlashFile};
-10
View File
@@ -88,16 +88,6 @@ WebSocket handler for registering device connections.
WebSocket handler that proxies CDP messages to/from the corresponding device.
## Experimental features
React Native frameworks may pass an `unstable_experiments` option to `createDevMiddleware` to configure experimental features. Note that these features might not work correctly, and they may change or be removed in the future without notice. Some of the experiment flags available are documented below.
### `unstable_experiments.enableStandaloneFuseboxShell`
When `true`, the debugger frontend will launch in a standalone app shell (provided by the `@react-native/debugger-shell` package) rather than in a browser window. The standalone shell provides an improved experience and will become the default in a future version of React Native.
The shell is powered by a separate binary that is downloaded and cached in the background (immediately after the call to `createDevMiddleware`). If there is a problem downloading or invoking this binary for the first time, the debugger frontend will revert to launching in a browser window until the next time `createDevMiddleware` is called (typically, on the next dev server start).
## Contributing
Changes to this package can be made locally and tested against the `rn-tester` app, per the [Contributing guide](https://reactnative.dev/contributing/overview#contributing-code). During development, this package is automatically run from source with no build step.
-2
View File
@@ -24,7 +24,6 @@
"dependencies": {
"@isaacs/ttlcache": "^1.4.1",
"@react-native/debugger-frontend": "0.82.0-main",
"@react-native/debugger-shell": "0.82.0-main",
"chrome-launcher": "^0.15.2",
"chromium-edge-launcher": "^0.2.0",
"connect": "^3.6.5",
@@ -39,7 +38,6 @@
"node": ">= 20.19.4"
},
"devDependencies": {
"@react-native/debugger-shell": "0.82.0-main",
"selfsigned": "^2.4.1",
"undici": "^5.29.0",
"wait-for-expect": "^3.0.2"
@@ -28,9 +28,6 @@ describe('enableStandaloneFuseboxShell experiment', () => {
unstable_showFuseboxShell: () => {
throw new Error('Not implemented');
},
unstable_prepareFuseboxShell: async () => {
return {code: 'not_implemented'};
},
};
const serverRef = withServerForEachTest({
logger: undefined,
@@ -130,7 +127,5 @@ describe('enableStandaloneFuseboxShell experiment', () => {
device.close();
}
});
// TODO(moti): Add tests around unstable_prepareFuseboxShell
});
});
@@ -92,7 +92,6 @@ export default function createDevMiddleware({
const eventReporter = createWrappedEventReporter(
unstable_eventReporter,
logger,
experiments,
);
const inspectorProxy = new InspectorProxy(
@@ -153,7 +152,6 @@ function getExperiments(config: ExperimentsConfig): Experiments {
function createWrappedEventReporter(
reporter: ?EventReporter,
logger: ?Logger,
experiments: Experiments,
): EventReporter {
return {
logEvent(event: ReportableEvent) {
@@ -168,42 +166,10 @@ function createWrappedEventReporter(
logger?.info(
'\u001B[1m\u001B[7m💡 JavaScript logs have moved!\u001B[22m They can now be ' +
'viewed in React Native DevTools. Tip: Type \u001B[1mj\u001B[22m in ' +
'the terminal to open' +
(experiments.enableStandaloneFuseboxShell
? ''
: ' (requires Google Chrome or Microsoft Edge)') +
'.\u001B[27m',
'the terminal to open (requires Google Chrome or Microsoft Edge).' +
'\u001B[27m',
);
break;
case 'fusebox_shell_preparation_attempt':
switch (event.result.code) {
case 'success':
case 'not_implemented':
break;
case 'unexpected_error': {
let message =
event.result.humanReadableMessage ??
'An unknown error occurred while installing React Native DevTools.';
if (event.result.verboseInfo != null) {
message += ` Details:\n\n${event.result.verboseInfo}`;
} else {
message += '.';
}
logger?.error(message);
break;
}
case 'possible_corruption':
case 'platform_not_supported':
case 'likely_offline':
logger?.warn(
event.result.humanReadableMessage ??
`An error of type ${event.result.code} occurred while installing React Native DevTools.`,
);
break;
default:
(event.result.code: empty);
break;
}
}
reporter?.logEvent(event);
+1 -6
View File
@@ -10,15 +10,10 @@
export {default as createDevMiddleware} from './createDevMiddleware';
export type {
BrowserLauncher,
DebuggerShellPreparationResult,
} from './types/BrowserLauncher';
export type {BrowserLauncher} from './types/BrowserLauncher';
export type {EventReporter, ReportableEvent} from './types/EventReporter';
export type {
CustomMessageHandler,
CustomMessageHandlerConnection,
CreateCustomMessageHandlerFn,
} from './inspector-proxy/CustomMessageHandler';
export {default as unstable_DefaultBrowserLauncher} from './utils/DefaultBrowserLauncher';
@@ -970,10 +970,7 @@ export default class Device {
socket: WS,
): void {
const sendSuccessResponse = (scriptSource: string) => {
const result: {
scriptSource: string,
bytecode?: string,
} = {scriptSource};
const result = {scriptSource};
const response: CDPResponse<'Debugger.getScriptSource'> = {
id: req.id,
result,
@@ -10,10 +10,7 @@
import type {InspectorProxyQueries} from '../inspector-proxy/InspectorProxy';
import type {PageDescription} from '../inspector-proxy/types';
import type {
BrowserLauncher,
DebuggerShellPreparationResult,
} from '../types/BrowserLauncher';
import type {BrowserLauncher} from '../types/BrowserLauncher';
import type {EventReporter} from '../types/EventReporter';
import type {Experiments} from '../types/Experiments';
import type {Logger} from '../types/Logger';
@@ -51,19 +48,6 @@ export default function openDebuggerMiddleware({
experiments,
inspectorProxy,
}: Options): NextHandleFunction {
let shellPreparationPromise: Promise<DebuggerShellPreparationResult>;
if (experiments.enableStandaloneFuseboxShell) {
shellPreparationPromise =
browserLauncher?.unstable_prepareFuseboxShell?.() ??
Promise.resolve({code: 'not_implemented'});
shellPreparationPromise = shellPreparationPromise.then(result => {
eventReporter?.logEvent({
type: 'fusebox_shell_preparation_attempt',
result,
});
return result;
});
}
return async (
req: IncomingMessage,
res: ServerResponse,
@@ -83,7 +67,7 @@ export default function openDebuggerMiddleware({
launchId?: string,
telemetryInfo?: string,
target?: string,
panel?: string,
landingView?: string,
...
} = parsedUrl.query;
@@ -168,28 +152,13 @@ export default function openDebuggerMiddleware({
telemetryInfo: query.telemetryInfo,
appId: target.appId,
useFuseboxEntryPoint,
panel: query.panel,
landingView: query.landingView,
},
);
let shouldUseStandaloneFuseboxShell =
useFuseboxEntryPoint && experiments.enableStandaloneFuseboxShell;
if (shouldUseStandaloneFuseboxShell) {
const shellPreparationResult = await shellPreparationPromise;
switch (shellPreparationResult.code) {
case 'success':
case 'not_implemented':
break;
case 'platform_not_supported':
case 'possible_corruption':
case 'likely_offline':
case 'unexpected_error':
shouldUseStandaloneFuseboxShell = false;
break;
default:
(shellPreparationResult.code: empty);
}
}
if (shouldUseStandaloneFuseboxShell) {
if (
useFuseboxEntryPoint &&
experiments.enableStandaloneFuseboxShell
) {
const windowKey = [
serverBaseUrl,
target.webSocketDebuggerUrl,
@@ -8,10 +8,6 @@
* @format
*/
import type {DebuggerShellPreparationResult} from '@react-native/debugger-shell';
export type {DebuggerShellPreparationResult};
/**
* An interface for integrators to provide a custom implementation for
* opening URLs in a web browser.
@@ -46,21 +42,5 @@ export interface BrowserLauncher {
* the host of dev-middleware. Implementations are responsible for rewriting
* this as necessary where the server is remote.
*/
+unstable_showFuseboxShell?: (
url: string,
windowKey: string,
) => Promise<void>;
/**
* Attempt to prepare the debugger shell for use and returns a coded result
* that can be used to advise the user on how to proceed in case of failure.
*
* This function MAY be called multiple times or not at all. Implementers
* SHOULD use the opportunity to prefetch and cache any expensive resources (e.g
* platform-specific binaries needed in order to show the Fusebox shell). After a
* successful call, subsequent calls SHOULD complete quickly. The implementation
* SHOULD NOT return a rejecting promise in any case, and instead SHOULD report
* errors via the returned result object.
*/
+unstable_prepareFuseboxShell?: () => Promise<DebuggerShellPreparationResult>;
unstable_showFuseboxShell?: (url: string, windowKey: string) => Promise<void>;
}
@@ -8,8 +8,6 @@
* @format
*/
import type {DebuggerShellPreparationResult} from './BrowserLauncher';
type SuccessResult<Props: {...} | void = {}> = {
status: 'success',
...Props,
@@ -134,10 +132,6 @@ export type ReportableEvent =
duration: number,
...ConnectionUptime,
...DebuggerSessionIDs,
}
| {
type: 'fusebox_shell_preparation_attempt',
result: DebuggerShellPreparationResult,
};
/**
@@ -26,7 +26,9 @@ export type Experiments = $ReadOnly<{
/**
* Launch the Fusebox frontend in a standalone shell instead of a browser.
* When this is enabled, we will use the optional unstable_showFuseboxShell
* method on the BrowserLauncher, or throw an error if the method is missing.
* method on the framework-provided BrowserLauncher, or throw an error if the
* method is missing. Note that the default BrowserLauncher does *not*
* implement unstable_showFuseboxShell.
*/
enableStandaloneFuseboxShell: boolean,
}>;
@@ -8,12 +8,6 @@
* @format
*/
import type {DebuggerShellPreparationResult} from '../';
const {
unstable_prepareDebuggerShell,
unstable_spawnDebuggerShellWithArgs,
} = require('@react-native/debugger-shell');
const {spawn} = require('child_process');
const ChromeLauncher = require('chrome-launcher');
const {Launcher: EdgeLauncher} = require('chromium-edge-launcher');
@@ -68,25 +62,6 @@ const DefaultBrowserLauncher = {
});
});
},
async unstable_showFuseboxShell(
url: string,
windowKey: string,
): Promise<void> {
return await unstable_spawnDebuggerShellWithArgs(
['--frontendUrl=' + url, '--windowKey=' + windowKey],
{
mode: 'detached',
flavor: process.env.RNDT_DEV === '1' ? 'dev' : 'prebuilt',
},
);
},
async unstable_prepareFuseboxShell(): Promise<DebuggerShellPreparationResult> {
return await unstable_prepareDebuggerShell(
process.env.RNDT_DEV === '1' ? 'dev' : 'prebuilt',
);
},
};
export default DefaultBrowserLauncher;
@@ -24,7 +24,7 @@ export default function getDevToolsFrontendUrl(
/** Whether to use the modern `rn_fusebox.html` entry point. */
useFuseboxEntryPoint?: boolean,
appId?: string,
panel?: string,
landingView?: string,
}>,
): string {
const wsParam = getWsParam({
@@ -55,8 +55,8 @@ export default function getDevToolsFrontendUrl(
if (options?.telemetryInfo != null && options.telemetryInfo !== '') {
searchParams.append('telemetryInfo', options.telemetryInfo);
}
if (options?.panel != null && options.panel !== '') {
searchParams.append('panel', options.panel);
if (options?.landingView != null && options.landingView !== '') {
searchParams.append('landingView', options.landingView);
}
return appUrl + '?' + searchParams.toString();
@@ -18,8 +18,8 @@
"bugs": "https://github.com/facebook/react-native/issues",
"main": "index.js",
"devDependencies": {
"babel-plugin-syntax-hermes-parser": "0.32.0",
"hermes-eslint": "0.32.0"
"babel-plugin-syntax-hermes-parser": "0.31.2",
"hermes-eslint": "0.31.2"
},
"engines": {
"node": ">= 20.19.4"
+2 -2
View File
@@ -32,8 +32,8 @@
"source-map-support": "0.5.0"
},
"devDependencies": {
"babel-plugin-syntax-hermes-parser": "0.32.0",
"hermes-eslint": "0.32.0"
"babel-plugin-syntax-hermes-parser": "0.31.2",
"hermes-eslint": "0.31.2"
},
"engines": {
"node": ">= 20.19.4"
-4
View File
@@ -45,7 +45,3 @@ tasks.named("ktfmtFormat") {
":shared:ktfmtFormat",
)
}
// We intentionally disable the `ktfmtCheck` tasks as the formatting is primarly handled inside
// fbsource
allprojects { tasks.withType<com.ncorti.ktfmt.gradle.tasks.KtfmtCheckTask>() { enabled = false } }
@@ -68,8 +68,7 @@ tasks.withType<KotlinCompile>().configureEach {
// See comment above on JDK 11 support
jvmTarget.set(JvmTarget.JVM_11)
allWarningsAsErrors.set(
project.properties["enableWarningsAsErrors"]?.toString()?.toBoolean() ?: false
)
project.properties["enableWarningsAsErrors"]?.toString()?.toBoolean() ?: false)
}
}
@@ -208,8 +208,7 @@ abstract class ReactExtension @Inject constructor(val project: Project) {
} else {
buildTypes.forEach { buildType ->
result.add(
(dependencyConfiguration ?: "${buildType}Implementation") to ":$nameCleansed"
)
(dependencyConfiguration ?: "${buildType}Implementation") to ":$nameCleansed")
}
}
}
@@ -112,8 +112,7 @@ class ReactPlugin : Plugin<Project> {
********************************************************************************
"""
.trimIndent()
)
.trimIndent())
exitProcess(1)
}
}
@@ -187,8 +186,7 @@ class ReactPlugin : Plugin<Project> {
// We want to exclude the build directory, to don't pick them up for execution
// avoidance.
tree.exclude("**/build/**/*")
}
)
})
val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(rootExtension.root)
it.onlyIf { (isLibrary || needsCodegenFromPackageJson) && !includesGeneratedCode }
@@ -305,8 +303,7 @@ class ReactPlugin : Plugin<Project> {
project.extensions.getByType(ApplicationAndroidComponentsExtension::class.java).apply {
onVariants(selector().all()) { variant ->
variant.sources.java?.addStaticSourceDirectory(
generatedAutolinkingJavaDir.get().asFile.absolutePath
)
generatedAutolinkingJavaDir.get().asFile.absolutePath)
}
}
}
@@ -59,12 +59,10 @@ class ReactRootProjectPlugin : Plugin<Project> {
}
private fun checkLegacyArchProperty(project: Project) {
if (
(project.hasProperty(PropertyUtils.NEW_ARCH_ENABLED) &&
!project.property(PropertyUtils.NEW_ARCH_ENABLED).toString().toBoolean()) ||
(project.hasProperty(PropertyUtils.SCOPED_NEW_ARCH_ENABLED) &&
!project.property(PropertyUtils.SCOPED_NEW_ARCH_ENABLED).toString().toBoolean())
) {
if ((project.hasProperty(PropertyUtils.NEW_ARCH_ENABLED) &&
!project.property(PropertyUtils.NEW_ARCH_ENABLED).toString().toBoolean()) ||
(project.hasProperty(PropertyUtils.SCOPED_NEW_ARCH_ENABLED) &&
!project.property(PropertyUtils.SCOPED_NEW_ARCH_ENABLED).toString().toBoolean())) {
project.logger.error(
"""
********************************************************************************
@@ -79,8 +77,7 @@ class ReactRootProjectPlugin : Plugin<Project> {
********************************************************************************
"""
.trimIndent()
)
.trimIndent())
}
}
}
@@ -54,11 +54,9 @@ internal fun Project.configureReactTasks(variant: Variant, config: ReactExtensio
configureNewArchPackagingOptions(project, config, variant)
configureJsEnginePackagingOptions(config, variant, isHermesEnabledInThisVariant, useThirdPartyJSC)
if (
!isHermesEnabledInThisVariant &&
!useThirdPartyJSC &&
rootProject.name != "react-native-github"
) {
if (!isHermesEnabledInThisVariant &&
!useThirdPartyJSC &&
rootProject.name != "react-native-github") {
showJSCRemovalMessage(project)
}
@@ -39,15 +39,12 @@ abstract class PrivateReactExtension @Inject constructor(project: Project) {
// - We're inside a user project, so inside the ./android folder. Default should be
// ../
// User can always override this default by setting a `root =` inside the template.
if (
project.rootProject.name == "react-native-github" ||
project.rootProject.name == "react-native-build-from-source"
) {
if (project.rootProject.name == "react-native-github" ||
project.rootProject.name == "react-native-build-from-source") {
project.rootProject.layout.projectDirectory.dir("../../")
} else {
project.rootProject.layout.projectDirectory.dir("../")
}
)
})
val reactNativeDir: DirectoryProperty =
objects.directoryProperty().convention(root.dir("node_modules/react-native"))
@@ -34,15 +34,15 @@ abstract class BundleHermesCTask : DefaultTask() {
@get:InputFiles
val sources: ConfigurableFileTree =
project.fileTree(root) { fileTree ->
fileTree.include("**/*.js")
fileTree.include("**/*.jsx")
fileTree.include("**/*.ts")
fileTree.include("**/*.tsx")
fileTree.exclude("**/android/**/*")
fileTree.exclude("**/ios/**/*")
fileTree.exclude("**/build/**/*")
fileTree.exclude("**/node_modules/**/*")
project.fileTree(root) {
it.include("**/*.js")
it.include("**/*.jsx")
it.include("**/*.ts")
it.include("**/*.tsx")
it.exclude("**/android/**/*")
it.exclude("**/ios/**/*")
it.exclude("**/build/**/*")
it.exclude("**/node_modules/**/*")
}
@get:Input abstract val nodeExecutableAndArgs: ListProperty<String>
@@ -165,88 +165,88 @@ abstract class GenerateAutolinkingNewArchitecturesFileTask : DefaultTask() {
// language=cmake
val CMAKE_TEMPLATE =
"""
# This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin)
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
# We set REACTNATIVE_MERGED_SO so libraries/apps can selectively decide to depend on either libreactnative.so
# or link against a old prefab target (this is needed for React Native 0.76 on).
set(REACTNATIVE_MERGED_SO true)
{{ libraryIncludes }}
set(AUTOLINKED_LIBRARIES
{{ libraryModules }}
)
"""
# This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin)
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
# We set REACTNATIVE_MERGED_SO so libraries/apps can selectively decide to depend on either libreactnative.so
# or link against a old prefab target (this is needed for React Native 0.76 on).
set(REACTNATIVE_MERGED_SO true)
{{ libraryIncludes }}
set(AUTOLINKED_LIBRARIES
{{ libraryModules }}
)
"""
.trimIndent()
// language=cpp
val CPP_TEMPLATE =
"""
/**
* This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
*/
#include "autolinking.h"
{{ autolinkingCppIncludes }}
namespace facebook {
namespace react {
std::shared_ptr<TurboModule> autolinking_ModuleProvider(const std::string moduleName, const JavaTurboModule::InitParams &params) {
{{ autolinkingCppTurboModuleJavaProviders }}
return nullptr;
}
std::shared_ptr<TurboModule> autolinking_cxxModuleProvider(const std::string moduleName, const std::shared_ptr<CallInvoker>& jsInvoker) {
{{ autolinkingCppTurboModuleCxxProviders }}
return nullptr;
}
void autolinking_registerProviders(std::shared_ptr<ComponentDescriptorProviderRegistry const> providerRegistry) {
{{ autolinkingCppComponentDescriptors }}
return;
}
} // namespace react
} // namespace facebook
"""
/**
* This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
*/
#include "autolinking.h"
{{ autolinkingCppIncludes }}
namespace facebook {
namespace react {
std::shared_ptr<TurboModule> autolinking_ModuleProvider(const std::string moduleName, const JavaTurboModule::InitParams &params) {
{{ autolinkingCppTurboModuleJavaProviders }}
return nullptr;
}
std::shared_ptr<TurboModule> autolinking_cxxModuleProvider(const std::string moduleName, const std::shared_ptr<CallInvoker>& jsInvoker) {
{{ autolinkingCppTurboModuleCxxProviders }}
return nullptr;
}
void autolinking_registerProviders(std::shared_ptr<ComponentDescriptorProviderRegistry const> providerRegistry) {
{{ autolinkingCppComponentDescriptors }}
return;
}
} // namespace react
} // namespace facebook
"""
.trimIndent()
// language=cpp
val hTemplate =
"""
/**
* This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
*/
#pragma once
#include <ReactCommon/CallInvoker.h>
#include <ReactCommon/JavaTurboModule.h>
#include <ReactCommon/TurboModule.h>
#include <jsi/jsi.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
namespace facebook {
namespace react {
std::shared_ptr<TurboModule> autolinking_ModuleProvider(const std::string moduleName, const JavaTurboModule::InitParams &params);
std::shared_ptr<TurboModule> autolinking_cxxModuleProvider(const std::string moduleName, const std::shared_ptr<CallInvoker>& jsInvoker);
void autolinking_registerProviders(std::shared_ptr<ComponentDescriptorProviderRegistry const> providerRegistry);
} // namespace react
} // namespace facebook
"""
/**
* This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
*/
#pragma once
#include <ReactCommon/CallInvoker.h>
#include <ReactCommon/JavaTurboModule.h>
#include <ReactCommon/TurboModule.h>
#include <jsi/jsi.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
namespace facebook {
namespace react {
std::shared_ptr<TurboModule> autolinking_ModuleProvider(const std::string moduleName, const JavaTurboModule::InitParams &params);
std::shared_ptr<TurboModule> autolinking_cxxModuleProvider(const std::string moduleName, const std::shared_ptr<CallInvoker>& jsInvoker);
void autolinking_registerProviders(std::shared_ptr<ComponentDescriptorProviderRegistry const> providerRegistry);
} // namespace react
} // namespace facebook
"""
.trimIndent()
}
}
@@ -82,7 +82,6 @@ abstract class GenerateCodegenArtifactsTask : Exec() {
libraryName,
"--javaPackageName",
codegenJavaPackageName,
)
)
))
}
}
@@ -69,7 +69,6 @@ abstract class GenerateCodegenSchemaTask : Exec() {
"NativeSampleTurboModule",
generatedSchemaFile.get().asFile.cliPath(workingDir),
jsRootDir.asFile.get().cliPath(workingDir),
)
)
))
}
}
@@ -32,19 +32,17 @@ abstract class GenerateEntryPointTask : DefaultTask() {
JsonUtils.fromAutolinkingConfigJson(autolinkInputFile.get().asFile)
?: error(
"""
RNGP - Autolinking: Could not parse autolinking config file:
${autolinkInputFile.get().asFile.absolutePath}
The file is either missing or not containing valid JSON so the build won't succeed.
"""
.trimIndent()
)
RNGP - Autolinking: Could not parse autolinking config file:
${autolinkInputFile.get().asFile.absolutePath}
The file is either missing or not containing valid JSON so the build won't succeed.
"""
.trimIndent())
val packageName =
model.project?.android?.packageName
?: error(
"RNGP - Autolinking: Could not find project.android.packageName in react-native config output! Could not autolink packages without this field."
)
"RNGP - Autolinking: Could not find project.android.packageName in react-native config output! Could not autolink packages without this field.")
val generatedFileContents = composeFileContent(packageName)
val outputDir = generatedOutputDirectory.get().asFile
@@ -64,45 +62,45 @@ abstract class GenerateEntryPointTask : DefaultTask() {
// language=java
val generatedFileContentsTemplate =
"""
package com.facebook.react;
import android.app.Application;
import android.content.Context;
import android.content.res.Resources;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger;
import com.facebook.react.views.view.WindowUtilKt;
import com.facebook.react.soloader.OpenSourceMergedSoMapping;
import com.facebook.soloader.SoLoader;
import java.io.IOException;
/**
* This class is the entry point for loading React Native using the configuration
* that the users specifies in their .gradle files.
*
* The `loadReactNative(this)` method invocation should be called inside the
* application onCreate otherwise the app won't load correctly.
*/
public class ReactNativeApplicationEntryPoint {
public static void loadReactNative(Context context) {
try {
SoLoader.init(context, OpenSourceMergedSoMapping.INSTANCE);
} catch (IOException error) {
throw new RuntimeException(error);
}
if ({{packageName}}.BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
DefaultNewArchitectureEntryPoint.load();
}
if ({{packageName}}.BuildConfig.IS_EDGE_TO_EDGE_ENABLED) {
WindowUtilKt.setEdgeToEdgeFeatureFlagOn();
}
package com.facebook.react;
import android.app.Application;
import android.content.Context;
import android.content.res.Resources;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger;
import com.facebook.react.views.view.WindowUtilKt;
import com.facebook.react.soloader.OpenSourceMergedSoMapping;
import com.facebook.soloader.SoLoader;
import java.io.IOException;
/**
* This class is the entry point for loading React Native using the configuration
* that the users specifies in their .gradle files.
*
* The `loadReactNative(this)` method invocation should be called inside the
* application onCreate otherwise the app won't load correctly.
*/
public class ReactNativeApplicationEntryPoint {
public static void loadReactNative(Context context) {
try {
SoLoader.init(context, OpenSourceMergedSoMapping.INSTANCE);
} catch (IOException error) {
throw new RuntimeException(error);
}
if ({{packageName}}.BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
DefaultNewArchitectureEntryPoint.load();
}
if ({{packageName}}.BuildConfig.IS_EDGE_TO_EDGE_ENABLED) {
WindowUtilKt.setEdgeToEdgeFeatureFlagOn();
}
}
"""
}
"""
.trimIndent()
}
}
@@ -34,19 +34,17 @@ abstract class GeneratePackageListTask : DefaultTask() {
JsonUtils.fromAutolinkingConfigJson(autolinkInputFile.get().asFile)
?: error(
"""
RNGP - Autolinking: Could not parse autolinking config file:
${autolinkInputFile.get().asFile.absolutePath}
The file is either missing or not containing valid JSON so the build won't succeed.
"""
.trimIndent()
)
RNGP - Autolinking: Could not parse autolinking config file:
${autolinkInputFile.get().asFile.absolutePath}
The file is either missing or not containing valid JSON so the build won't succeed.
"""
.trimIndent())
val packageName =
model.project?.android?.packageName
?: error(
"RNGP - Autolinking: Could not find project.android.packageName in react-native config output! Could not autolink packages without this field."
)
"RNGP - Autolinking: Could not find project.android.packageName in react-native config output! Could not autolink packages without this field.")
val androidPackages = filterAndroidPackages(model)
val packageImports = composePackageImports(packageName, androidPackages)
@@ -136,69 +134,69 @@ abstract class GeneratePackageListTask : DefaultTask() {
// language=java
val generatedFileContentsTemplate =
"""
package com.facebook.react;
import android.app.Application;
import android.content.Context;
import android.content.res.Resources;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainPackageConfig;
import com.facebook.react.shell.MainReactPackage;
import java.util.Arrays;
import java.util.ArrayList;
{{ packageImports }}
@SuppressWarnings("deprecation")
public class PackageList {
private Application application;
private ReactNativeHost reactNativeHost;
private MainPackageConfig mConfig;
public PackageList(ReactNativeHost reactNativeHost) {
this(reactNativeHost, null);
}
public PackageList(Application application) {
this(application, null);
}
public PackageList(ReactNativeHost reactNativeHost, MainPackageConfig config) {
this.reactNativeHost = reactNativeHost;
mConfig = config;
}
public PackageList(Application application, MainPackageConfig config) {
this.reactNativeHost = null;
this.application = application;
mConfig = config;
}
private ReactNativeHost getReactNativeHost() {
return this.reactNativeHost;
}
private Resources getResources() {
return this.getApplication().getResources();
}
private Application getApplication() {
if (this.reactNativeHost == null) return this.application;
return this.reactNativeHost.getApplication();
}
private Context getApplicationContext() {
return this.getApplication().getApplicationContext();
}
public ArrayList<ReactPackage> getPackages() {
return new ArrayList<>(Arrays.<ReactPackage>asList(
new MainReactPackage(mConfig){{ packageClassInstances }}
));
}
}
"""
package com.facebook.react;
import android.app.Application;
import android.content.Context;
import android.content.res.Resources;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainPackageConfig;
import com.facebook.react.shell.MainReactPackage;
import java.util.Arrays;
import java.util.ArrayList;
{{ packageImports }}
@SuppressWarnings("deprecation")
public class PackageList {
private Application application;
private ReactNativeHost reactNativeHost;
private MainPackageConfig mConfig;
public PackageList(ReactNativeHost reactNativeHost) {
this(reactNativeHost, null);
}
public PackageList(Application application) {
this(application, null);
}
public PackageList(ReactNativeHost reactNativeHost, MainPackageConfig config) {
this.reactNativeHost = reactNativeHost;
mConfig = config;
}
public PackageList(Application application, MainPackageConfig config) {
this.reactNativeHost = null;
this.application = application;
mConfig = config;
}
private ReactNativeHost getReactNativeHost() {
return this.reactNativeHost;
}
private Resources getResources() {
return this.getApplication().getResources();
}
private Application getApplication() {
if (this.reactNativeHost == null) return this.application;
return this.reactNativeHost.getApplication();
}
private Context getApplicationContext() {
return this.getApplication().getApplicationContext();
}
public ArrayList<ReactPackage> getPackages() {
return new ArrayList<>(Arrays.<ReactPackage>asList(
new MainReactPackage(mConfig){{ packageClassInstances }}
));
}
}
"""
.trimIndent()
}
}
@@ -54,8 +54,7 @@ abstract class BuildCodegenCLITask : Exec() {
windowsAwareBashCommandLine(
codegenDir.asFile.get().canonicalPath.unixifyPath().plus(BUILD_SCRIPT_PATH),
bashWindowsHome = bashWindowsHome.orNull,
)
)
))
super.exec()
}
@@ -29,10 +29,8 @@ abstract class CustomExecTask : Exec() {
@get:Input @get:Optional abstract val onlyIfProvidedPathDoesNotExists: Property<String>
override fun exec() {
if (
onlyIfProvidedPathDoesNotExists.isPresent &&
File(onlyIfProvidedPathDoesNotExists.get()).exists()
) {
if (onlyIfProvidedPathDoesNotExists.isPresent &&
File(onlyIfProvidedPathDoesNotExists.get()).exists()) {
return
}
if (standardOutputFile.isPresent) {
@@ -64,8 +64,7 @@ abstract class PrepareGflagsTask : DefaultTask() {
.replace(Regex("@GFLAGS_NAMESPACE@"), "gflags")
.replace(
Regex(
"@(HAVE_STDINT_H|HAVE_SYS_TYPES_H|HAVE_INTTYPES_H|GFLAGS_INTTYPES_FORMAT_C99)@"
),
"@(HAVE_STDINT_H|HAVE_SYS_TYPES_H|HAVE_INTTYPES_H|GFLAGS_INTTYPES_FORMAT_C99)@"),
"1",
)
.replace(Regex("@([A-Z0-9_]+)@"), "1")
@@ -61,8 +61,7 @@ abstract class PrepareGlogTask : DefaultTask() {
"ac_cv___attribute___noreturn" to "__attribute__ ((noreturn))",
"ac_cv___attribute___printf_4_5" to
"__attribute__((__format__ (__printf__, 4, 5)))",
)
),
)),
ReplaceTokens::class.java,
)
matchedFile.path = (matchedFile.name.removeSuffix(".in"))
@@ -42,35 +42,35 @@ abstract class PreparePrefabHeadersTask : DefaultTask() {
input.get().forEach { (libraryName, pathToPrefixCouples) ->
val outputFolder: RegularFile = outputDir.file(libraryName).get()
pathToPrefixCouples.forEach { (headerPath, headerPrefix) ->
fs.copy { copySpec ->
copySpec.from(headerPath)
copySpec.include("**/*.h")
copySpec.exclude("**/*.cpp")
copySpec.exclude("**/*.txt")
fs.copy {
it.from(headerPath)
it.include("**/*.h")
it.exclude("**/*.cpp")
it.exclude("**/*.txt")
// We don't want to copy all the boost headers as they are 250Mb+
copySpec.include("boost/config.hpp")
copySpec.include("boost/config/**/*.hpp")
copySpec.include("boost/core/*.hpp")
copySpec.include("boost/detail/workaround.hpp")
copySpec.include("boost/operators.hpp")
copySpec.include("boost/preprocessor/**/*.hpp")
it.include("boost/config.hpp")
it.include("boost/config/**/*.hpp")
it.include("boost/core/*.hpp")
it.include("boost/detail/workaround.hpp")
it.include("boost/operators.hpp")
it.include("boost/preprocessor/**/*.hpp")
// Headers needed for exposing rrc_text and rrc_textinput
copySpec.include("boost/container_hash/**/*.hpp")
copySpec.include("boost/detail/**/*.hpp")
copySpec.include("boost/intrusive/**/*.hpp")
copySpec.include("boost/iterator/**/*.hpp")
copySpec.include("boost/move/**/*.hpp")
copySpec.include("boost/mpl/**/*.hpp")
copySpec.include("boost/mp11/**/*.hpp")
copySpec.include("boost/describe/**/*.hpp")
copySpec.include("boost/type_traits/**/*.hpp")
copySpec.include("boost/utility/**/*.hpp")
copySpec.include("boost/assert.hpp")
copySpec.include("boost/static_assert.hpp")
copySpec.include("boost/cstdint.hpp")
copySpec.include("boost/utility.hpp")
copySpec.include("boost/version.hpp")
copySpec.into(File(outputFolder.asFile, headerPrefix))
it.include("boost/container_hash/**/*.hpp")
it.include("boost/detail/**/*.hpp")
it.include("boost/intrusive/**/*.hpp")
it.include("boost/iterator/**/*.hpp")
it.include("boost/move/**/*.hpp")
it.include("boost/mpl/**/*.hpp")
it.include("boost/mp11/**/*.hpp")
it.include("boost/describe/**/*.hpp")
it.include("boost/type_traits/**/*.hpp")
it.include("boost/utility/**/*.hpp")
it.include("boost/assert.hpp")
it.include("boost/static_assert.hpp")
it.include("boost/cstdint.hpp")
it.include("boost/utility.hpp")
it.include("boost/version.hpp")
it.into(File(outputFolder.asFile, headerPrefix))
}
}
}
@@ -39,8 +39,7 @@ internal object BackwardCompatUtils {
********************************************************************************
"""
.trimIndent()
)
.trimIndent())
}
}
@@ -56,14 +55,14 @@ internal object BackwardCompatUtils {
val message =
"""
=============== JavaScriptCore is being moved ===============
JavaScriptCore has been extracted from react-native core
and will be removed in a future release. It can now be
installed from `@react-native-community/javascriptcore`
See: https://github.com/react-native-community/javascriptcore
=============================================================
=============== JavaScriptCore is being moved ===============
JavaScriptCore has been extracted from react-native core
and will be removed in a future release. It can now be
installed from `@react-native-community/javascriptcore`
See: https://github.com/react-native-community/javascriptcore
=============================================================
"""
"""
.trimIndent()
project.logger.warn(message)
hasShownJSCRemovalMessage = true
@@ -33,8 +33,7 @@ internal object DependencyUtils {
val exclusiveEnterpriseRepository = project.rootProject.exclusiveEnterpriseRepository()
if (exclusiveEnterpriseRepository != null) {
project.logger.lifecycle(
"Replacing ALL Maven Repositories with: $exclusiveEnterpriseRepository"
)
"Replacing ALL Maven Repositories with: $exclusiveEnterpriseRepository")
}
project.rootProject.allprojects { eachProject ->
@@ -136,30 +135,26 @@ internal object DependencyUtils {
"com.facebook.react:react-native",
"${groupString}:react-android:${versionString}",
"The react-native artifact was deprecated in favor of react-android due to https://github.com/facebook/react-native/issues/35210.",
)
)
))
dependencySubstitution.add(
Triple(
"com.facebook.react:hermes-engine",
"${groupString}:hermes-android:${versionString}",
"The hermes-engine artifact was deprecated in favor of hermes-android due to https://github.com/facebook/react-native/issues/35210.",
)
)
))
if (groupString != DEFAULT_INTERNAL_PUBLISHING_GROUP) {
dependencySubstitution.add(
Triple(
"com.facebook.react:react-android",
"${groupString}:react-android:${versionString}",
"The react-android dependency was modified to use the correct Maven group.",
)
)
))
dependencySubstitution.add(
Triple(
"com.facebook.react:hermes-android",
"${groupString}:hermes-android:${versionString}",
"The hermes-android dependency was modified to use the correct Maven group.",
)
)
))
}
return dependencySubstitution
}
@@ -45,8 +45,7 @@ internal object NdkConfiguratorUtils {
}
if (cmakeArgs.none { it.startsWith("-DREACT_ANDROID_DIR") }) {
cmakeArgs.add(
"-DREACT_ANDROID_DIR=${extension.reactNativeDir.file("ReactAndroid").get().asFile}"
)
"-DREACT_ANDROID_DIR=${extension.reactNativeDir.file("ReactAndroid").get().asFile}")
}
if (cmakeArgs.none { it.startsWith("-DANDROID_STL") }) {
cmakeArgs.add("-DANDROID_STL=c++_shared")
@@ -87,8 +86,7 @@ internal object NdkConfiguratorUtils {
"**/libjsi.so",
// AGP will give priority of libc++_shared coming from App modules.
"**/libc++_shared.so",
)
)
))
}
/**
@@ -120,17 +118,17 @@ internal object NdkConfiguratorUtils {
hermesEnabled -> {
excludes.add("**/libjsc.so")
excludes.add("**/libjsctooling.so")
includes.add("**/libhermesvm.so")
includes.add("**/libhermes.so")
includes.add("**/libhermestooling.so")
}
useThirdPartyJSC -> {
excludes.add("**/libhermesvm.so")
excludes.add("**/libhermes.so")
excludes.add("**/libhermestooling.so")
excludes.add("**/libjsctooling.so")
includes.add("**/libjsc.so")
}
else -> {
excludes.add("**/libhermesvm.so")
excludes.add("**/libhermes.so")
excludes.add("**/libhermestooling.so")
includes.add("**/libjsc.so")
includes.add("**/libjsctooling.so")
@@ -105,14 +105,13 @@ private fun detectCliFile(reactNativeRoot: File, preconfiguredCliFile: File?): F
error(
"""
Couldn't determine CLI location!
Couldn't determine CLI location!
Please set `react { cliFile = file(...) }` inside your
build.gradle to the path of the react-native cli.js file.
This file typically resides in `node_modules/react-native/cli.js`
"""
.trimIndent()
)
Please set `react { cliFile = file(...) }` inside your
build.gradle to the path of the react-native cli.js file.
This file typically resides in `node_modules/react-native/cli.js`
"""
.trimIndent())
}
/**
@@ -161,8 +160,7 @@ internal fun detectOSAwareHermesCommand(projectRoot: File, hermesCommand: String
error(
"Couldn't determine Hermesc location. " +
"Please set `react.hermesCommand` to the path of the hermesc binary file. " +
"node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc"
)
"node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc")
}
/**
@@ -188,8 +186,7 @@ internal fun getHermesOSBin(): String {
if (Os.isLinuxAmd64()) return "linux64-bin"
error(
"OS not recognized. Please set project.react.hermesCommand " +
"to the path of a working Hermes compiler."
)
"to the path of a working Hermes compiler.")
}
internal fun projectPathToLibraryName(projectPath: String): String =
@@ -23,12 +23,11 @@ class ReactExtensionTest {
val validJsonFile =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0"
}
"""
.trimIndent()
)
{
"reactNativeVersion": "1000.0.0"
}
"""
.trimIndent())
val deps = getGradleDependenciesToApply(validJsonFile)
assertThat(deps).isEmpty()
@@ -39,24 +38,23 @@ class ReactExtensionTest {
val validJsonFile =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"android": {
"sourceDir": "src/main/java",
"packageImportPath": "com.facebook.react"
}
}
}
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"android": {
"sourceDir": "src/main/java",
"packageImportPath": "com.facebook.react"
}
}
"""
.trimIndent()
)
}
}
}
"""
.trimIndent())
val deps = getGradleDependenciesToApply(validJsonFile)
assertThat(deps).containsExactly("implementation" to ":react-native_oss-library-example")
@@ -67,25 +65,24 @@ class ReactExtensionTest {
val validJsonFile =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"android": {
"sourceDir": "src/main/java",
"packageImportPath": "com.facebook.react",
"dependencyConfiguration": "compileOnly"
}
}
}
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"android": {
"sourceDir": "src/main/java",
"packageImportPath": "com.facebook.react",
"dependencyConfiguration": "compileOnly"
}
}
"""
.trimIndent()
)
}
}
}
"""
.trimIndent())
val deps = getGradleDependenciesToApply(validJsonFile)
assertThat(deps).containsExactly("compileOnly" to ":react-native_oss-library-example")
@@ -96,25 +93,24 @@ class ReactExtensionTest {
val validJsonFile =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"android": {
"sourceDir": "src/main/java",
"packageImportPath": "com.facebook.react",
"buildTypes": ["debug", "release"]
}
}
}
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"android": {
"sourceDir": "src/main/java",
"packageImportPath": "com.facebook.react",
"buildTypes": ["debug", "release"]
}
}
"""
.trimIndent()
)
}
}
}
"""
.trimIndent())
val deps = getGradleDependenciesToApply(validJsonFile)
assertThat(deps)
@@ -129,34 +125,33 @@ class ReactExtensionTest {
val validJsonFile =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"android": {
"sourceDir": "src/main/java",
"packageImportPath": "com.facebook.react"
}
}
},
"@react-native/another-library-for-testing": {
"root": "./node_modules/@react-native/another-library-for-testing",
"name": "@react-native/another-library-for-testing",
"platforms": {
"android": {
"sourceDir": "src/main/java",
"packageImportPath": "com.facebook.react"
}
}
}
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"android": {
"sourceDir": "src/main/java",
"packageImportPath": "com.facebook.react"
}
}
"""
.trimIndent()
)
},
"@react-native/another-library-for-testing": {
"root": "./node_modules/@react-native/another-library-for-testing",
"name": "@react-native/another-library-for-testing",
"platforms": {
"android": {
"sourceDir": "src/main/java",
"packageImportPath": "com.facebook.react"
}
}
}
}
}
"""
.trimIndent())
val deps = getGradleDependenciesToApply(validJsonFile)
assertThat(deps)
@@ -171,27 +166,26 @@ class ReactExtensionTest {
val validJsonFile =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"ios": {
"podspecPath": "./node_modules/@react-native/oss-library-example/oss-library-example.podspec",
"version": "0.0.0",
"configurations": [],
"scriptPhases": []
},
"android": null
}
}
}
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"ios": {
"podspecPath": "./node_modules/@react-native/oss-library-example/oss-library-example.podspec",
"version": "0.0.0",
"configurations": [],
"scriptPhases": []
},
"android": null
}
"""
.trimIndent()
)
}
}
}
"""
.trimIndent())
val deps = getGradleDependenciesToApply(validJsonFile)
assertThat(deps).isEmpty()
@@ -202,35 +196,34 @@ class ReactExtensionTest {
val validJsonFile =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/android-example",
"name": "@react-native/android-example",
"platforms": {
"android": {
"sourceDir": "src/main/java",
"packageImportPath": "com.facebook.react"
}
}
},
"@react-native/another-library-for-testing": {
"root": "./node_modules/@react-native/cxx-testing",
"name": "@react-native/cxx-testing",
"platforms": {
"android": {
"sourceDir": "src/main/java",
"packageImportPath": "com.facebook.react",
"isPureCxxDependency": true
}
}
}
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/android-example",
"name": "@react-native/android-example",
"platforms": {
"android": {
"sourceDir": "src/main/java",
"packageImportPath": "com.facebook.react"
}
}
"""
.trimIndent()
)
},
"@react-native/another-library-for-testing": {
"root": "./node_modules/@react-native/cxx-testing",
"name": "@react-native/cxx-testing",
"platforms": {
"android": {
"sourceDir": "src/main/java",
"packageImportPath": "com.facebook.react",
"isPureCxxDependency": true
}
}
}
}
}
"""
.trimIndent())
val deps = getGradleDependenciesToApply(validJsonFile)
assertThat(deps).containsExactly("implementation" to ":react-native_android-example")
@@ -41,8 +41,7 @@ class ModelAutolinkingDependenciesJsonTest {
"@this*is~a(more)complicated/example!of~weird)packages",
null,
)
.nameCleansed
)
.nameCleansed)
.isEqualTo("this_is_a_more_complicated_example_of_weird_packages")
}
}
@@ -72,11 +72,9 @@ class GenerateAutolinkingNewArchitecturesFileTaskTest {
name = "a-dependency",
platforms =
ModelAutolinkingDependenciesPlatformJson(android = null),
)
),
)),
project = null,
)
)
))
assertThat(result).isEmpty()
}
@@ -103,11 +101,9 @@ class GenerateAutolinkingNewArchitecturesFileTaskTest {
name = "a-dependency",
platforms =
ModelAutolinkingDependenciesPlatformJson(android = android),
)
),
)),
project = null,
)
)
))
assertThat(result).containsExactly(android)
}
@@ -134,8 +130,7 @@ class GenerateAutolinkingNewArchitecturesFileTaskTest {
)
"""
.trimIndent()
)
.trimIndent())
}
@Test
@@ -165,8 +160,7 @@ class GenerateAutolinkingNewArchitecturesFileTaskTest {
another_cxxModule
)
"""
.trimIndent()
)
.trimIndent())
}
@Test
@@ -210,8 +204,7 @@ class GenerateAutolinkingNewArchitecturesFileTaskTest {
} // namespace react
} // namespace facebook
"""
.trimIndent()
)
.trimIndent())
}
@Test
@@ -267,8 +260,7 @@ class GenerateAutolinkingNewArchitecturesFileTaskTest {
} // namespace react
} // namespace facebook
"""
.trimIndent()
)
.trimIndent())
}
@Test
@@ -148,8 +148,7 @@ class GenerateCodegenArtifactsTaskTest {
}
}
"""
.trimIndent()
)
.trimIndent())
}
val task =
@@ -178,8 +177,7 @@ class GenerateCodegenArtifactsTaskTest {
}
}
"""
.trimIndent()
)
.trimIndent())
}
val task =
@@ -198,10 +196,10 @@ class GenerateCodegenArtifactsTaskTest {
@Test
fun resolveTaskParameters_withMissingPackageJson_usesGradleOne() {
val task =
createTestTask<GenerateCodegenArtifactsTask> { task ->
task.packageJsonFile.set(File(tempFolder.root, "package.json"))
task.codegenJavaPackageName.set("com.example.test")
task.libraryName.set("a-library-name-from-gradle")
createTestTask<GenerateCodegenArtifactsTask> {
it.packageJsonFile.set(File(tempFolder.root, "package.json"))
it.codegenJavaPackageName.set("com.example.test")
it.libraryName.set("a-library-name-from-gradle")
}
val (libraryName, javaPackageName) = task.resolveTaskParameters()
@@ -86,7 +86,6 @@ class GenerateEntryPointTaskTest {
}
}
"""
.trimIndent()
)
.trimIndent())
}
}
@@ -64,8 +64,7 @@ class GeneratePackageListTaskTest {
// @react-native/another-package
import com.facebook.react.anotherPackage;
"""
.trimIndent()
)
.trimIndent())
}
@Test
@@ -89,8 +88,7 @@ class GeneratePackageListTaskTest {
new APackage(),
new AnotherPackage()
"""
.trimIndent()
)
.trimIndent())
}
@Test
@@ -149,11 +147,9 @@ class GeneratePackageListTaskTest {
name = "a-dependency",
platforms =
ModelAutolinkingDependenciesPlatformJson(android = null),
)
),
)),
project = null,
)
)
))
assertThat(result)
.isEqualTo(emptyMap<String, ModelAutolinkingDependenciesPlatformAndroidJson>())
}
@@ -181,11 +177,9 @@ class GeneratePackageListTaskTest {
name = "a-dependency",
platforms =
ModelAutolinkingDependenciesPlatformJson(android = android),
)
),
)),
project = null,
)
)
))
assertThat(result.entries.size).isEqualTo(1)
assertThat(result["a-dependency"]).isEqualTo(android)
}
@@ -214,11 +208,9 @@ class GeneratePackageListTaskTest {
name = "a-pure-cxx-dependency",
platforms =
ModelAutolinkingDependenciesPlatformJson(android = android),
)
),
)),
project = null,
)
)
))
assertThat(result)
.isEqualTo(emptyMap<String, ModelAutolinkingDependenciesPlatformAndroidJson>())
}
@@ -297,8 +289,7 @@ class GeneratePackageListTaskTest {
}
}
"""
.trimIndent()
)
.trimIndent())
}
@Test
@@ -380,8 +371,7 @@ class GeneratePackageListTaskTest {
}
}
"""
.trimIndent()
)
.trimIndent())
}
private val testDependencies =
@@ -26,8 +26,7 @@ class PrepareBoostTaskTest {
assertThatThrownBy { task.taskAction() }
.isInstanceOf(IllegalStateException::class.java)
.hasMessage(
"Cannot query the value of task ':PrepareBoostTask' property 'boostVersion' because it has no value available."
)
"Cannot query the value of task ':PrepareBoostTask' property 'boostVersion' because it has no value available.")
}
@Test
@@ -58,11 +57,11 @@ class PrepareBoostTaskTest {
val boostThirdPartyJniPath = tempFolder.newFolder("boostpath/jni")
val output = tempFolder.newFolder("output")
val task =
createTestTask<PrepareBoostTask> { task ->
task.boostPath.setFrom(boostpath)
task.boostThirdPartyJniPath.set(boostThirdPartyJniPath)
task.boostVersion.set("1.0.0")
task.outputDir.set(output)
createTestTask<PrepareBoostTask> {
it.boostPath.setFrom(boostpath)
it.boostThirdPartyJniPath.set(boostThirdPartyJniPath)
it.boostVersion.set("1.0.0")
it.outputDir.set(output)
}
File(boostpath, "asm/asm.S").apply {
parentFile.mkdirs()
@@ -79,11 +78,11 @@ class PrepareBoostTaskTest {
val boostThirdPartyJniPath = tempFolder.newFolder("boostpath/jni")
val output = tempFolder.newFolder("output")
val task =
createTestTask<PrepareBoostTask> { task ->
task.boostPath.setFrom(boostpath)
task.boostThirdPartyJniPath.set(boostThirdPartyJniPath)
task.boostVersion.set("1.0.0")
task.outputDir.set(output)
createTestTask<PrepareBoostTask> {
it.boostPath.setFrom(boostpath)
it.boostThirdPartyJniPath.set(boostThirdPartyJniPath)
it.boostVersion.set("1.0.0")
it.outputDir.set(output)
}
File(boostpath, "boost_1.0.0/boost/config.hpp").apply {
parentFile.mkdirs()
@@ -100,11 +99,11 @@ class PrepareBoostTaskTest {
val boostThirdPartyJniPath = tempFolder.newFolder("boostpath/jni")
val output = tempFolder.newFolder("output")
val task =
createTestTask<PrepareBoostTask> { task ->
task.boostPath.setFrom(boostpath)
task.boostThirdPartyJniPath.set(boostThirdPartyJniPath)
task.boostVersion.set("1.0.0")
task.outputDir.set(output)
createTestTask<PrepareBoostTask> {
it.boostPath.setFrom(boostpath)
it.boostThirdPartyJniPath.set(boostThirdPartyJniPath)
it.boostVersion.set("1.0.0")
it.outputDir.set(output)
}
File(boostpath, "boost/boost/config.hpp").apply {
parentFile.mkdirs()
@@ -125,8 +125,7 @@ typedef unsigned __int64 uint64;
#endif
} // namespace GFLAGS_NAMESPACE
"""
)
""")
}
File(gflagspath, "gflags-1.0.0/src/config.h.in").apply {
parentFile.mkdirs()
@@ -122,11 +122,11 @@ class PrepareGlogTaskTest {
val glogThirdPartyJniPath = tempFolder.newFolder("glogpath/jni")
val output = tempFolder.newFolder("output")
val task =
createTestTask<PrepareGlogTask> { task ->
task.glogPath.setFrom(glogpath)
task.glogThirdPartyJniPath.set(glogThirdPartyJniPath)
task.glogVersion.set("1.0.0")
task.outputDir.set(output)
createTestTask<PrepareGlogTask> {
it.glogPath.setFrom(glogpath)
it.glogThirdPartyJniPath.set(glogThirdPartyJniPath)
it.glogVersion.set("1.0.0")
it.outputDir.set(output)
}
File(glogpath, "glog-1.0.0/src/logging.h.in").apply {
parentFile.mkdirs()
@@ -55,8 +55,7 @@ class PreparePrefabHeadersTaskTest {
createTestTask<PreparePrefabHeadersTask>(project = project) {
it.outputDir.set(outputDir)
it.input.set(
listOf(PrefabPreprocessingEntry("sample_library", "input/" to expectedPrefix))
)
listOf(PrefabPreprocessingEntry("sample_library", "input/" to expectedPrefix)))
}
task.taskAction()
@@ -77,8 +76,7 @@ class PreparePrefabHeadersTaskTest {
createTestTask<PreparePrefabHeadersTask>(project = project) {
it.outputDir.set(outputDir)
it.input.set(
listOf(PrefabPreprocessingEntry("sample_library", "input/" to expectedPrefix))
)
listOf(PrefabPreprocessingEntry("sample_library", "input/" to expectedPrefix)))
}
task.taskAction()
@@ -104,8 +102,7 @@ class PreparePrefabHeadersTaskTest {
"sample_library",
listOf("input/component1/" to "", "input/component2/" to ""),
),
)
)
))
}
task.taskAction()
@@ -128,8 +125,7 @@ class PreparePrefabHeadersTaskTest {
listOf(
PrefabPreprocessingEntry("libraryone", "input/lib1/" to ""),
PrefabPreprocessingEntry("librarytwo", "input/lib2/" to ""),
)
)
))
}
task.taskAction()
@@ -159,8 +155,7 @@ class PreparePrefabHeadersTaskTest {
"librarytwo",
listOf("input/lib2/" to "", "input/shared/" to "shared/"),
),
)
)
))
}
task.taskAction()
@@ -186,9 +181,9 @@ class PreparePrefabHeadersTaskTest {
val project = createProject(projectDir = tempFolder.root)
val task =
createTestTask<PreparePrefabHeadersTask>(project = project) { task ->
task.outputDir.set(outputDir)
task.input.set(listOf(PrefabPreprocessingEntry("sample_library", "boost/" to "")))
createTestTask<PreparePrefabHeadersTask>(project = project) {
it.outputDir.set(outputDir)
it.input.set(listOf(PrefabPreprocessingEntry("sample_library", "boost/" to "")))
}
task.taskAction()
@@ -59,8 +59,8 @@ internal fun createZip(dest: File, paths: List<String>) {
val uri = URI.create("jar:file:$dest")
FileSystems.newFileSystem(uri, env).use { zipfs ->
paths.forEach { path ->
val zipEntryPath = zipfs.getPath(path)
paths.forEach {
val zipEntryPath = zipfs.getPath(it)
val zipEntryFolder = zipEntryPath.subpath(0, zipEntryPath.nameCount - 1)
Files.createDirectories(zipEntryFolder)
Files.createFile(zipEntryPath)
@@ -37,8 +37,7 @@ class AgpConfiguratorUtilsTest {
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>
"""
.trimIndent()
)
.trimIndent())
}
val actual = getPackageNameFromManifest(manifest)
@@ -56,8 +55,7 @@ class AgpConfiguratorUtilsTest {
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.facebook.react" >
</manifest>
"""
.trimIndent()
)
.trimIndent())
}
val actual = getPackageNameFromManifest(manifest)
@@ -40,8 +40,7 @@ class DependencyUtilsTest {
assertThat(
project.repositories.firstOrNull {
it is MavenArtifactRepository && it.url == localMavenURI
}
)
})
.isNotNull()
}
@@ -55,8 +54,7 @@ class DependencyUtilsTest {
assertThat(
project.repositories.firstOrNull {
it is MavenArtifactRepository && it.url == repositoryURI
}
)
})
.isNotNull()
}
@@ -70,8 +68,7 @@ class DependencyUtilsTest {
assertThat(
project.repositories.firstOrNull {
it is MavenArtifactRepository && it.url == repositoryURI
}
)
})
.isNotNull()
}
@@ -85,8 +82,7 @@ class DependencyUtilsTest {
assertThat(
project.repositories.firstOrNull {
it is MavenArtifactRepository && it.url == repositoryURI
}
)
})
.isNotNull()
}
@@ -100,8 +96,7 @@ class DependencyUtilsTest {
assertThat(
project.repositories.firstOrNull {
it is MavenArtifactRepository && it.url == repositoryURI
}
)
})
.isNotNull()
}
@@ -121,8 +116,7 @@ class DependencyUtilsTest {
assertThat(
project.repositories.firstOrNull {
it is MavenArtifactRepository && it.url == repositoryURI
}
)
})
.isNotNull()
}
@@ -137,8 +131,7 @@ class DependencyUtilsTest {
assertThat(
project.repositories.firstOrNull {
it is MavenArtifactRepository && it.url == repositoryURI
}
)
})
.isNull()
// We test both with scoped and unscoped property
@@ -150,8 +143,7 @@ class DependencyUtilsTest {
assertThat(
project.repositories.firstOrNull {
it is MavenArtifactRepository && it.url == repositoryURI
}
)
})
.isNull()
}
@@ -166,8 +158,7 @@ class DependencyUtilsTest {
assertThat(
project.repositories.firstOrNull {
it is MavenArtifactRepository && it.url == repositoryURI
}
)
})
.isNotNull()
// We test both with scoped and unscoped property
@@ -179,8 +170,7 @@ class DependencyUtilsTest {
assertThat(
project.repositories.firstOrNull {
it is MavenArtifactRepository && it.url == repositoryURI
}
)
})
.isNotNull()
}
@@ -236,14 +226,12 @@ class DependencyUtilsTest {
assertThat(
appProject.repositories.firstOrNull {
it is MavenArtifactRepository && it.url == repositoryURI
}
)
})
.isNotNull()
assertThat(
libProject.repositories.firstOrNull {
it is MavenArtifactRepository && it.url == repositoryURI
}
)
})
.isNotNull()
}
@@ -266,8 +254,7 @@ class DependencyUtilsTest {
assertThat(
libProject.repositories.count {
it is MavenArtifactRepository && it.url == repositoryURI
}
)
})
.isEqualTo(2)
}
@@ -345,15 +332,13 @@ class DependencyUtilsTest {
assertThat("com.facebook.react:react-android:0.42.0")
.isEqualTo(dependencySubstitutions[0].second)
assertThat(
"The react-native artifact was deprecated in favor of react-android due to https://github.com/facebook/react-native/issues/35210."
)
"The react-native artifact was deprecated in favor of react-android due to https://github.com/facebook/react-native/issues/35210.")
.isEqualTo(dependencySubstitutions[0].third)
assertThat("com.facebook.react:hermes-engine").isEqualTo(dependencySubstitutions[1].first)
assertThat("com.facebook.react:hermes-android:0.42.0")
.isEqualTo(dependencySubstitutions[1].second)
assertThat(
"The hermes-engine artifact was deprecated in favor of hermes-android due to https://github.com/facebook/react-native/issues/35210."
)
"The hermes-engine artifact was deprecated in favor of hermes-android due to https://github.com/facebook/react-native/issues/35210.")
.isEqualTo(dependencySubstitutions[1].third)
}
@@ -364,14 +349,12 @@ class DependencyUtilsTest {
assertThat("com.facebook.react:react-native").isEqualTo(dependencySubstitutions[0].first)
assertThat("io.github.test:react-android:0.42.0").isEqualTo(dependencySubstitutions[0].second)
assertThat(
"The react-native artifact was deprecated in favor of react-android due to https://github.com/facebook/react-native/issues/35210."
)
"The react-native artifact was deprecated in favor of react-android due to https://github.com/facebook/react-native/issues/35210.")
.isEqualTo(dependencySubstitutions[0].third)
assertThat("com.facebook.react:hermes-engine").isEqualTo(dependencySubstitutions[1].first)
assertThat("io.github.test:hermes-android:0.42.0").isEqualTo(dependencySubstitutions[1].second)
assertThat(
"The hermes-engine artifact was deprecated in favor of hermes-android due to https://github.com/facebook/react-native/issues/35210."
)
"The hermes-engine artifact was deprecated in favor of hermes-android due to https://github.com/facebook/react-native/issues/35210.")
.isEqualTo(dependencySubstitutions[1].third)
assertThat("com.facebook.react:react-android").isEqualTo(dependencySubstitutions[2].first)
assertThat("io.github.test:react-android:0.42.0").isEqualTo(dependencySubstitutions[2].second)
@@ -392,8 +375,7 @@ class DependencyUtilsTest {
VERSION_NAME=1000.0.0
ANOTHER_PROPERTY=true
"""
.trimIndent()
)
.trimIndent())
}
val versionString = readVersionAndGroupStrings(propertiesFile).first
@@ -410,8 +392,7 @@ class DependencyUtilsTest {
VERSION_NAME=0.0.0-20221101-2019-cfe811ab1
ANOTHER_PROPERTY=true
"""
.trimIndent()
)
.trimIndent())
}
val versionString = readVersionAndGroupStrings(propertiesFile).first
@@ -427,8 +408,7 @@ class DependencyUtilsTest {
"""
ANOTHER_PROPERTY=true
"""
.trimIndent()
)
.trimIndent())
}
val versionString = readVersionAndGroupStrings(propertiesFile).first
@@ -444,8 +424,7 @@ class DependencyUtilsTest {
VERSION_NAME=
ANOTHER_PROPERTY=true
"""
.trimIndent()
)
.trimIndent())
}
val versionString = readVersionAndGroupStrings(propertiesFile).first
@@ -461,8 +440,7 @@ class DependencyUtilsTest {
react.internal.publishingGroup=io.github.test
ANOTHER_PROPERTY=true
"""
.trimIndent()
)
.trimIndent())
}
val groupString = readVersionAndGroupStrings(propertiesFile).second
@@ -478,8 +456,7 @@ class DependencyUtilsTest {
"""
ANOTHER_PROPERTY=true
"""
.trimIndent()
)
.trimIndent())
}
val groupString = readVersionAndGroupStrings(propertiesFile).second
@@ -24,8 +24,8 @@ class NdkConfiguratorUtilsTest {
assertThat(excludes).containsExactly("**/libjsc.so", "**/libjsctooling.so")
assertThat(includes).doesNotContain("**/libjsc.so", "**/libjsctooling.so")
assertThat(includes).containsExactly("**/libhermesvm.so", "**/libhermestooling.so")
assertThat(excludes).doesNotContain("**/libhermesvm.so", "**/libhermestooling.so")
assertThat(includes).containsExactly("**/libhermes.so", "**/libhermestooling.so")
assertThat(excludes).doesNotContain("**/libhermes.so", "**/libhermestooling.so")
}
@Test
@@ -39,8 +39,8 @@ class NdkConfiguratorUtilsTest {
assertThat(excludes).containsExactly("**/libjsc.so", "**/libjsctooling.so")
assertThat(includes).doesNotContain("**/libjsc.so", "**/libjsctooling.so")
assertThat(includes).containsExactly("**/libhermesvm.so", "**/libhermestooling.so")
assertThat(excludes).doesNotContain("**/libhermesvm.so", "**/libhermestooling.so")
assertThat(includes).containsExactly("**/libhermes.so", "**/libhermestooling.so")
assertThat(excludes).doesNotContain("**/libhermes.so", "**/libhermestooling.so")
}
@Test
@@ -51,8 +51,8 @@ class NdkConfiguratorUtilsTest {
useThirdPartyJSC = false,
)
assertThat(excludes).containsExactly("**/libhermesvm.so", "**/libhermestooling.so")
assertThat(includes).doesNotContain("**/libhermesvm.so", "**/libhermestooling.so")
assertThat(excludes).containsExactly("**/libhermes.so", "**/libhermestooling.so")
assertThat(includes).doesNotContain("**/libhermes.so", "**/libhermestooling.so")
assertThat(includes).containsExactly("**/libjsc.so", "**/libjsctooling.so")
assertThat(excludes).doesNotContain("**/libjsc.so", "**/libjsctooling.so")
@@ -68,6 +68,6 @@ class NdkConfiguratorUtilsTest {
assertThat(includes).containsExactly("**/libjsc.so")
assertThat(excludes)
.containsExactly("**/libhermesvm.so", "**/libhermestooling.so", "**/libjsctooling.so")
.containsExactly("**/libhermes.so", "**/libhermestooling.so", "**/libjsctooling.so")
}
}
@@ -147,8 +147,7 @@ class PathUtilsTest {
tempFolder.newFolder("node_modules/react-native/ReactAndroid/hermes-engine/build/hermes/bin/")
val expected =
tempFolder.newFile(
"node_modules/react-native/ReactAndroid/hermes-engine/build/hermes/bin/hermesc"
)
"node_modules/react-native/ReactAndroid/hermes-engine/build/hermes/bin/hermesc")
assertThat(detectOSAwareHermesCommand(tempFolder.root, "")).isEqualTo(expected.toString())
}
@@ -190,8 +189,7 @@ class PathUtilsTest {
tempFolder.newFolder("node_modules/react-native/ReactAndroid/hermes-engine/build/hermes/bin/")
val expected =
tempFolder.newFile(
"node_modules/react-native/ReactAndroid/hermes-engine/build/hermes/bin/hermesc"
)
"node_modules/react-native/ReactAndroid/hermes-engine/build/hermes/bin/hermesc")
tempFolder.newFolder("node_modules/react-native/sdks/hermesc/osx-bin/")
tempFolder.newFile("node_modules/react-native/sdks/hermesc/osx-bin/hermesc")
@@ -205,8 +203,7 @@ class PathUtilsTest {
File(
tempFolder.root,
"node_modules/react-native/ReactAndroid/hermes-engine/build/hermes/bin/hermesc",
)
)
))
}
@Test
@@ -217,8 +214,7 @@ class PathUtilsTest {
File(
tempFolder.root,
"node_modules/react-native/ReactAndroid/hermes-engine/build/hermes/bin/hermesc.exe",
)
)
))
}
@Test
@@ -315,8 +311,7 @@ class PathUtilsTest {
"codegenConfig": {}
}
"""
.trimIndent()
)
.trimIndent())
}
val project = ProjectBuilder.builder().withProjectDir(moduleFolder).build()
project.plugins.apply("com.android.library")
@@ -128,8 +128,7 @@ class ProjectUtilsTest {
"codegenConfig": {}
}
"""
.trimIndent()
)
.trimIndent())
}
extension.root.set(tempFolder.root)
assertThat(project.needsCodegenFromPackageJson(extension.root)).isTrue()
@@ -147,8 +146,7 @@ class ProjectUtilsTest {
"name": "a-library"
}
"""
.trimIndent()
)
.trimIndent())
}
extension.root.set(tempFolder.root)
assertThat(project.needsCodegenFromPackageJson(extension.root)).isFalse()
@@ -58,8 +58,7 @@ tasks.withType<KotlinCompile>().configureEach {
// See comment above on JDK 11 support
jvmTarget.set(JvmTarget.JVM_11)
allWarningsAsErrors.set(
project.properties["enableWarningsAsErrors"]?.toString()?.toBoolean() ?: false
)
project.properties["enableWarningsAsErrors"]?.toString()?.toBoolean() ?: false)
}
}
@@ -158,8 +158,9 @@ abstract class ReactSettingsExtension @Inject constructor(val settings: Settings
logger.error(message)
if (cacheJsonConfig.length() != 0L) {
logger.error(
cacheJsonConfig.readText().substring(0, min(1024, cacheJsonConfig.length().toInt()))
)
cacheJsonConfig
.readText()
.substring(0, min(1024, cacheJsonConfig.length().toInt())))
}
cacheJsonConfig.delete()
throw GradleException(message)
@@ -29,12 +29,11 @@ class ReactSettingsExtensionTest {
val validFile =
createJsonFile(
"""
{
"value": "¯\\_(ツ)_/¯"
}
"""
.trimIndent()
)
{
"value": "¯\\_(ツ)_/¯"
}
"""
.trimIndent())
assertThat(computeSha256(validFile))
.isEqualTo("838aa9a72a16fdd55b0d49b510a82e264a30f59333b5fdd97c7798a29146f6a8")
}
@@ -44,12 +43,11 @@ class ReactSettingsExtensionTest {
val validJsonFile =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0"
}
"""
.trimIndent()
)
{
"reactNativeVersion": "1000.0.0"
}
"""
.trimIndent())
val map = getLibrariesToAutolink(validJsonFile)
assertThat(map.keys).isEmpty()
@@ -60,42 +58,41 @@ class ReactSettingsExtensionTest {
val validJsonFile =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"ios": {
"podspecPath": "./node_modules/@react-native/oss-library-example/OSSLibraryExample.podspec",
"version": "0.0.1",
"configurations": [],
"scriptPhases": []
},
"android": {
"sourceDir": "./node_modules/@react-native/oss-library-example/android",
"packageImportPath": "import com.facebook.react.osslibraryexample.OSSLibraryExamplePackage;",
"packageInstance": "new OSSLibraryExamplePackage()",
"buildTypes": ["staging", "debug", "release"],
"libraryName": "OSSLibraryExampleSpec",
"componentDescriptors": [
"SampleNativeComponentComponentDescriptor"
],
"cmakeListsPath": "./node_modules/@react-native/oss-library-example/android/build/generated/source/codegen/jni/CMakeLists.txt",
"cxxModuleCMakeListsModuleName": null,
"cxxModuleCMakeListsPath": null,
"cxxModuleHeaderName": null,
"dependencyConfiguration": "implementation",
"isPureCxxDependency": false
}
}
}
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"ios": {
"podspecPath": "./node_modules/@react-native/oss-library-example/OSSLibraryExample.podspec",
"version": "0.0.1",
"configurations": [],
"scriptPhases": []
},
"android": {
"sourceDir": "./node_modules/@react-native/oss-library-example/android",
"packageImportPath": "import com.facebook.react.osslibraryexample.OSSLibraryExamplePackage;",
"packageInstance": "new OSSLibraryExamplePackage()",
"buildTypes": ["staging", "debug", "release"],
"libraryName": "OSSLibraryExampleSpec",
"componentDescriptors": [
"SampleNativeComponentComponentDescriptor"
],
"cmakeListsPath": "./node_modules/@react-native/oss-library-example/android/build/generated/source/codegen/jni/CMakeLists.txt",
"cxxModuleCMakeListsModuleName": null,
"cxxModuleCMakeListsPath": null,
"cxxModuleHeaderName": null,
"dependencyConfiguration": "implementation",
"isPureCxxDependency": false
}
}
"""
.trimIndent()
)
}
}
}
"""
.trimIndent())
val map = getLibrariesToAutolink(validJsonFile)
assertThat(map.keys).containsExactly(":react-native_oss-library-example")
@@ -108,26 +105,25 @@ class ReactSettingsExtensionTest {
val validJsonFile =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"ios": {
"podspecPath": "./node_modules/@react-native/oss-library-example/OSSLibraryExample.podspec",
"version": "0.0.1",
"configurations": [],
"scriptPhases": []
}
}
}
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"ios": {
"podspecPath": "./node_modules/@react-native/oss-library-example/OSSLibraryExample.podspec",
"version": "0.0.1",
"configurations": [],
"scriptPhases": []
}
}
"""
.trimIndent()
)
}
}
}
"""
.trimIndent())
val map = getLibrariesToAutolink(validJsonFile)
assertThat(map.keys).isEmpty()
@@ -262,8 +258,7 @@ class ReactSettingsExtensionTest {
}
}
"""
.trimIndent()
)
.trimIndent())
}
tempFolder.newFile("yarn.lock").apply { writeText("I'm a lockfile") }
val lockfileCollection = project.files("yarn.lock")
@@ -316,8 +311,7 @@ class ReactSettingsExtensionTest {
}
}
"""
.trimIndent()
)
.trimIndent())
}
tempFolder.newFile("yarn.lock").apply { writeText("I'm a lockfile") }
val lockfileCollection = project.files("yarn.lock")
@@ -362,10 +356,9 @@ class ReactSettingsExtensionTest {
val invalidConfigFile =
createJsonFile(
"""
{}
"""
.trimIndent()
)
{}
"""
.trimIndent())
assertThat(ReactSettingsExtension.isCacheDirty(invalidConfigFile, buildFolder, lockfiles))
.isTrue()
@@ -384,12 +377,11 @@ class ReactSettingsExtensionTest {
val invalidConfigFile =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0"
}
"""
.trimIndent()
)
{
"reactNativeVersion": "1000.0.0"
}
"""
.trimIndent())
assertThat(ReactSettingsExtension.isCacheDirty(invalidConfigFile, buildFolder, lockfiles))
.isTrue()
@@ -408,13 +400,12 @@ class ReactSettingsExtensionTest {
val invalidConfigFile =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0",
"dependencies": {}
}
"""
.trimIndent()
)
{
"reactNativeVersion": "1000.0.0",
"dependencies": {}
}
"""
.trimIndent())
assertThat(ReactSettingsExtension.isCacheDirty(invalidConfigFile, buildFolder, lockfiles))
.isTrue()
@@ -433,26 +424,25 @@ class ReactSettingsExtensionTest {
val invalidConfigFile =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"ios": {
"podspecPath": "./node_modules/@react-native/oss-library-example/OSSLibraryExample.podspec",
"version": "0.0.1",
"configurations": [],
"scriptPhases": []
}
}
}
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"ios": {
"podspecPath": "./node_modules/@react-native/oss-library-example/OSSLibraryExample.podspec",
"version": "0.0.1",
"configurations": [],
"scriptPhases": []
}
}
"""
.trimIndent()
)
}
}
}
"""
.trimIndent())
assertThat(ReactSettingsExtension.isCacheDirty(invalidConfigFile, buildFolder, lockfiles))
.isTrue()
@@ -31,8 +31,7 @@ tasks.withType<KotlinCompile>().configureEach {
// See comment above on JDK 11 support
jvmTarget.set(JvmTarget.JVM_11)
allWarningsAsErrors.set(
project.properties["enableWarningsAsErrors"]?.toString()?.toBoolean() ?: false
)
project.properties["enableWarningsAsErrors"]?.toString()?.toBoolean() ?: false)
}
}
@@ -37,8 +37,7 @@ tasks.withType<KotlinCompile>().configureEach {
// See comment above on JDK 11 support
jvmTarget.set(JvmTarget.JVM_11)
allWarningsAsErrors.set(
project.properties["enableWarningsAsErrors"]?.toString()?.toBoolean() ?: false
)
project.properties["enableWarningsAsErrors"]?.toString()?.toBoolean() ?: false)
}
}
@@ -39,21 +39,20 @@ class JsonUtilsTest {
val oldJsonConfig =
createJsonFile(
"""
{
"name": "yet another npm package",
"codegenConfig": {
"libraries": [
{
"name": "yet another npm package",
"codegenConfig": {
"libraries": [
{
"name": "an awesome library",
"jsSrcsDir": "../js/",
"android": {}
}
]
}
"name": "an awesome library",
"jsSrcsDir": "../js/",
"android": {}
}
"""
.trimIndent()
)
]
}
}
"""
.trimIndent())
val parsed = JsonUtils.fromPackageJson(oldJsonConfig)!!
@@ -67,22 +66,21 @@ class JsonUtilsTest {
val validJson =
createJsonFile(
"""
{
"name": "yet another npm package",
"codegenConfig": {
"name": "an awesome library",
"jsSrcsDir": "../js/",
"android": {
"javaPackageName": "com.awesome.library"
},
"ios": {
"other ios only keys": "which are ignored during parsing"
}
}
}
"""
.trimIndent()
)
{
"name": "yet another npm package",
"codegenConfig": {
"name": "an awesome library",
"jsSrcsDir": "../js/",
"android": {
"javaPackageName": "com.awesome.library"
},
"ios": {
"other ios only keys": "which are ignored during parsing"
}
}
}
"""
.trimIndent())
val parsed = JsonUtils.fromPackageJson(validJson)!!
@@ -113,12 +111,11 @@ class JsonUtilsTest {
val validJson =
createJsonFile(
"""
{
"version": "1000.0.0"
}
"""
.trimIndent()
)
{
"version": "1000.0.0"
}
"""
.trimIndent())
val parsed = JsonUtils.fromPackageJson(validJson)!!
assertThat("1000.0.0").isEqualTo(parsed.version)
@@ -136,12 +133,11 @@ class JsonUtilsTest {
val validJson =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0"
}
"""
.trimIndent()
)
{
"reactNativeVersion": "1000.0.0"
}
"""
.trimIndent())
val parsed = JsonUtils.fromAutolinkingConfigJson(validJson)!!
assertThat("1000.0.0").isEqualTo(parsed.reactNativeVersion)
@@ -152,33 +148,32 @@ class JsonUtilsTest {
val validJson =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0",
"project": {
"ios": {
"sourceDir": "./packages/rn-tester",
"xcodeProject": {
"name": "RNTesterPods.xcworkspace",
"isWorkspace": true
},
"automaticPodsInstallation": false
},
"android": {
"sourceDir": "./packages/rn-tester",
"appName": "RN-Tester",
"packageName": "com.facebook.react.uiapp",
"applicationId": "com.facebook.react.uiapp",
"mainActivity": ".RNTesterActivity",
"watchModeCommandParams": [
"--mode HermesDebug"
],
"dependencyConfiguration": "implementation"
}
}
}
"""
.trimIndent()
)
{
"reactNativeVersion": "1000.0.0",
"project": {
"ios": {
"sourceDir": "./packages/rn-tester",
"xcodeProject": {
"name": "RNTesterPods.xcworkspace",
"isWorkspace": true
},
"automaticPodsInstallation": false
},
"android": {
"sourceDir": "./packages/rn-tester",
"appName": "RN-Tester",
"packageName": "com.facebook.react.uiapp",
"applicationId": "com.facebook.react.uiapp",
"mainActivity": ".RNTesterActivity",
"watchModeCommandParams": [
"--mode HermesDebug"
],
"dependencyConfiguration": "implementation"
}
}
}
"""
.trimIndent())
val parsed = JsonUtils.fromAutolinkingConfigJson(validJson)!!
assertThat("./packages/rn-tester").isEqualTo(parsed.project!!.android!!.sourceDir)
@@ -197,37 +192,36 @@ class JsonUtilsTest {
val validJson =
createJsonFile(
"""
> AwesomeProject@0.0.1 npx
> rnc-cli config
{
"reactNativeVersion": "1000.0.0",
"project": {
"ios": {
"sourceDir": "./packages/rn-tester",
"xcodeProject": {
"name": "RNTesterPods.xcworkspace",
"isWorkspace": true
},
"automaticPodsInstallation": false
},
"android": {
"sourceDir": "./packages/rn-tester",
"appName": "RN-Tester",
"packageName": "com.facebook.react.uiapp",
"applicationId": "com.facebook.react.uiapp",
"mainActivity": ".RNTesterActivity",
"watchModeCommandParams": [
"--mode HermesDebug"
],
"dependencyConfiguration": "implementation"
}
}
}
"""
.trimIndent()
)
> AwesomeProject@0.0.1 npx
> rnc-cli config
{
"reactNativeVersion": "1000.0.0",
"project": {
"ios": {
"sourceDir": "./packages/rn-tester",
"xcodeProject": {
"name": "RNTesterPods.xcworkspace",
"isWorkspace": true
},
"automaticPodsInstallation": false
},
"android": {
"sourceDir": "./packages/rn-tester",
"appName": "RN-Tester",
"packageName": "com.facebook.react.uiapp",
"applicationId": "com.facebook.react.uiapp",
"mainActivity": ".RNTesterActivity",
"watchModeCommandParams": [
"--mode HermesDebug"
],
"dependencyConfiguration": "implementation"
}
}
}
"""
.trimIndent())
val parsed = JsonUtils.fromAutolinkingConfigJson(validJson)!!
assertThat("./packages/rn-tester").isEqualTo(parsed.project!!.android!!.sourceDir)
@@ -245,42 +239,41 @@ class JsonUtilsTest {
val validJson =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"ios": {
"podspecPath": "./node_modules/@react-native/oss-library-example/OSSLibraryExample.podspec",
"version": "0.0.1",
"configurations": [],
"scriptPhases": []
},
"android": {
"sourceDir": "./node_modules/@react-native/oss-library-example/android",
"packageImportPath": "import com.facebook.react.osslibraryexample.OSSLibraryExamplePackage;",
"packageInstance": "new OSSLibraryExamplePackage()",
"buildTypes": ["staging", "debug", "release"],
"libraryName": "OSSLibraryExampleSpec",
"componentDescriptors": [
"SampleNativeComponentComponentDescriptor"
],
"cmakeListsPath": "./node_modules/@react-native/oss-library-example/android/build/generated/source/codegen/jni/CMakeLists.txt",
"cxxModuleCMakeListsModuleName": null,
"cxxModuleCMakeListsPath": null,
"cxxModuleHeaderName": null,
"dependencyConfiguration": "implementation",
"isPureCxxDependency": false
}
}
}
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"ios": {
"podspecPath": "./node_modules/@react-native/oss-library-example/OSSLibraryExample.podspec",
"version": "0.0.1",
"configurations": [],
"scriptPhases": []
},
"android": {
"sourceDir": "./node_modules/@react-native/oss-library-example/android",
"packageImportPath": "import com.facebook.react.osslibraryexample.OSSLibraryExamplePackage;",
"packageInstance": "new OSSLibraryExamplePackage()",
"buildTypes": ["staging", "debug", "release"],
"libraryName": "OSSLibraryExampleSpec",
"componentDescriptors": [
"SampleNativeComponentComponentDescriptor"
],
"cmakeListsPath": "./node_modules/@react-native/oss-library-example/android/build/generated/source/codegen/jni/CMakeLists.txt",
"cxxModuleCMakeListsModuleName": null,
"cxxModuleCMakeListsPath": null,
"cxxModuleHeaderName": null,
"dependencyConfiguration": "implementation",
"isPureCxxDependency": false
}
}
"""
.trimIndent()
)
}
}
}
"""
.trimIndent())
val parsed = JsonUtils.fromAutolinkingConfigJson(validJson)!!
assertThat("./node_modules/@react-native/oss-library-example")
@@ -294,86 +287,73 @@ class JsonUtilsTest {
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.sourceDir
)
.sourceDir)
assertThat("import com.facebook.react.osslibraryexample.OSSLibraryExamplePackage;")
.isEqualTo(
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.packageImportPath
)
.packageImportPath)
assertThat("new OSSLibraryExamplePackage()")
.isEqualTo(
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.packageInstance
)
.packageInstance)
assertThat(listOf("staging", "debug", "release"))
.isEqualTo(
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.buildTypes
)
.buildTypes)
assertThat("OSSLibraryExampleSpec")
.isEqualTo(
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.libraryName
)
.libraryName)
assertThat(listOf("SampleNativeComponentComponentDescriptor"))
.isEqualTo(
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.componentDescriptors
)
.componentDescriptors)
assertThat(
"./node_modules/@react-native/oss-library-example/android/build/generated/source/codegen/jni/CMakeLists.txt"
)
"./node_modules/@react-native/oss-library-example/android/build/generated/source/codegen/jni/CMakeLists.txt")
.isEqualTo(
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.cmakeListsPath
)
.cmakeListsPath)
assertThat(
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.cxxModuleHeaderName
)
.cxxModuleHeaderName)
.isNull()
assertThat(
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.cxxModuleCMakeListsPath
)
.cxxModuleCMakeListsPath)
.isNull()
assertThat(
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.cxxModuleCMakeListsModuleName
)
.cxxModuleCMakeListsModuleName)
.isNull()
assertThat("implementation")
.isEqualTo(
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.dependencyConfiguration
)
.dependencyConfiguration)
assertThat(
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.isPureCxxDependency!!
)
.isPureCxxDependency!!)
.isFalse()
}
@@ -47,7 +47,7 @@ it('refuses non-spec compliant colors', () => {
expect(normalizeColor('rgb (0, 1, 2)')).toBe(null);
expect(normalizeColor('rgba(0 0 0 0.0)')).toBe(null);
expect(normalizeColor('hsv(0, 1, 2)')).toBe(null);
// $FlowExpectedError[incompatible-type] - Intentionally malformed argument.
// $FlowExpectedError - Intentionally malformed argument.
expect(normalizeColor({r: 10, g: 10, b: 10})).toBe(null);
expect(normalizeColor('hsl(1%, 2, 3)')).toBe(null);
expect(normalizeColor('rgb(1%, 2%, 3%)')).toBe(null);
@@ -67,7 +67,7 @@
"@babel/plugin-transform-unicode-regex": "^7.24.7",
"@babel/template": "^7.25.0",
"@react-native/babel-plugin-codegen": "0.82.0-main",
"babel-plugin-syntax-hermes-parser": "0.32.0",
"babel-plugin-syntax-hermes-parser": "0.31.2",
"babel-plugin-transform-flow-enums": "^0.0.2",
"react-refresh": "^0.14.0"
},
@@ -28,7 +28,7 @@
"dependencies": {
"@babel/core": "^7.25.2",
"@react-native/babel-preset": "0.82.0-main",
"hermes-parser": "0.32.0",
"hermes-parser": "0.31.2",
"nullthrows": "^1.1.1"
},
"peerDependencies": {
+1 -1
View File
@@ -218,7 +218,7 @@ const transform /*: BabelTransformer['transform'] */ = ({
// The result from `transformFromAstSync` can be null (if the file is ignored)
if (!result) {
/* $FlowFixMe[incompatible-type] BabelTransformer specifies that the `ast` can never be null but
/* $FlowFixMe BabelTransformer specifies that the `ast` can never be null but
* the function returns here. Discovered when typing `BabelNode`. */
return {ast: null};
}
+2 -2
View File
@@ -32,7 +32,7 @@
"@babel/core": "^7.25.2",
"@babel/parser": "^7.25.3",
"glob": "^7.1.1",
"hermes-parser": "0.32.0",
"hermes-parser": "0.31.2",
"invariant": "^2.2.4",
"nullthrows": "^1.1.1",
"yargs": "^17.6.2"
@@ -45,7 +45,7 @@
"@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7",
"@babel/plugin-transform-optional-chaining": "^7.24.8",
"@babel/preset-env": "^7.25.3",
"hermes-estree": "0.32.0",
"hermes-estree": "0.31.2",
"micromatch": "^4.0.4",
"prettier": "3.6.2",
"rimraf": "^3.0.2"
@@ -350,8 +350,6 @@ function setDefaultValue(
common.default = ((defaultValue ? defaultValue : 0): number);
break;
case 'FloatTypeAnnotation':
/* $FlowFixMe[invalid-compare] Error discovered during Constant Condition
* roll out. See https://fburl.com/workplace/5whu3i34. */
common.default = ((defaultValue === null
? null
: defaultValue
@@ -359,8 +357,6 @@ function setDefaultValue(
: 0): number | null);
break;
case 'BooleanTypeAnnotation':
/* $FlowFixMe[invalid-compare] Error discovered during Constant Condition
* roll out. See https://fburl.com/workplace/5whu3i34. */
common.default = defaultValue === null ? null : !!defaultValue;
break;
case 'StringTypeAnnotation':
@@ -275,7 +275,7 @@ export function formatNativeSpecErrorStore(
export function formatDiffSet(summary: DiffSummary): FormattedDiffSummary {
const summaryStatus = summary.status;
if (summaryStatus === 'ok' || summaryStatus === 'patchable') {
// $FlowFixMe[incompatible-type] I don't think we can ever get in this branch
// $FlowFixMe I don't think we can ever get in this branch
return summary;
}
const hasteModules = Object.keys(summary.incompatibilityReport);
@@ -77,8 +77,6 @@ const ActionSheetIOS = {
callback: (buttonIndex: number) => void,
) {
invariant(
/* $FlowFixMe[invalid-compare] Error discovered during Constant Condition
* roll out. See https://fburl.com/workplace/5whu3i34. */
typeof options === 'object' && options !== null,
'Options must be a valid object',
);
@@ -164,8 +162,6 @@ const ActionSheetIOS = {
successCallback: Function | ((success: boolean, method: ?string) => void),
) {
invariant(
/* $FlowFixMe[invalid-compare] Error discovered during Constant Condition
* roll out. See https://fburl.com/workplace/5whu3i34. */
typeof options === 'object' && options !== null,
'Options must be a valid object',
);
@@ -54,8 +54,7 @@ const AnimatedScrollView: AnimatedComponentType<
props.style != null
) {
return (
// $FlowFixMe[incompatible-type] - It should return an Animated ScrollView but it returns a ScrollView with Animated props applied.
// $FlowFixMe[incompatible-variance]
// $FlowFixMe - It should return an Animated ScrollView but it returns a ScrollView with Animated props applied.
<AnimatedScrollViewWithInvertedRefreshControl
scrollEventThrottle={0.0001}
{...props}
@@ -14,7 +14,7 @@ import SectionList, {type SectionListProps} from '../../Lists/SectionList';
import createAnimatedComponent from '../createAnimatedComponent';
import * as React from 'react';
// $FlowFixMe[incompatible-type]
// $FlowFixMe
export default (createAnimatedComponent(SectionList): component<
// $FlowExpectedError[unclear-type]
ItemT = any,
@@ -17,7 +17,6 @@ type ValueListenerCallback = (state: {value: number, ...}) => mixed;
export type AnimatedNodeConfig = $ReadOnly<{
debugID?: string,
unstable_disableBatchingForNativeCreate?: boolean,
}>;
let _uniqueId = 1;
@@ -43,8 +42,6 @@ export default class AnimatedNode {
if (__DEV__) {
this.__debugID = config?.debugID;
}
this.__disableBatchingForNativeCreate =
config?.unstable_disableBatchingForNativeCreate;
}
__attach(): void {}
@@ -68,7 +65,6 @@ export default class AnimatedNode {
/* Methods and props used by native Animated impl */
__isNative: boolean = false;
__nativeTag: ?number = undefined;
__disableBatchingForNativeCreate: ?boolean = undefined;
__makeNative(platformConfig: ?PlatformConfig): void {
// Subclasses are expected to set `__isNative` to true before this.
@@ -146,9 +142,6 @@ export default class AnimatedNode {
if (this._platformConfig) {
config.platformConfig = this._platformConfig;
}
if (this.__disableBatchingForNativeCreate) {
config.disableBatchingForNativeCreate = true;
}
NativeAnimatedHelper.API.createAnimatedNode(nativeTag, config);
}
return nativeTag;
@@ -68,8 +68,7 @@ __attribute__((deprecated(
/// The window object, used to render the UViewControllers
@property (nonatomic, strong, nonnull) UIWindow *window;
@property (nonatomic, nullable) RCTBridge *bridge
__attribute__((deprecated("The bridge is deprecated and will be removed when removing the legacy architecture.")));
@property (nonatomic, nullable) RCTBridge *bridge;
@property (nonatomic, strong, nullable) NSString *moduleName;
@property (nonatomic, strong, nullable) NSDictionary *initialProps;
@property (nonatomic, strong) RCTReactNativeFactory *reactNativeFactory;
@@ -77,9 +76,7 @@ __attribute__((deprecated(
/// If `automaticallyLoadReactNativeWindow` is set to `true`, the React Native window will be loaded automatically.
@property (nonatomic, assign) BOOL automaticallyLoadReactNativeWindow;
@property (nonatomic, nullable) RCTSurfacePresenterBridgeAdapter *bridgeAdapter __attribute__((
deprecated("The bridge adapter is deprecated and will be removed when removing the legacy architecture.")));
;
@property (nonatomic, nullable) RCTSurfacePresenterBridgeAdapter *bridgeAdapter;
- (RCTRootViewFactory *)rootViewFactory;
@@ -40,20 +40,17 @@ std::unique_ptr<facebook::react::JSExecutorFactory> RCTAppSetupDefaultJsExecutor
std::unique_ptr<facebook::react::JSExecutorFactory> RCTAppSetupJsExecutorFactoryForOldArch(
RCTBridge *bridge,
const std::shared_ptr<facebook::react::RuntimeScheduler> &runtimeScheduler)
__attribute__((deprecated(
"RCTAppSetupJsExecutorFactoryForOldArch(RCTBridge *, RuntimeScheduler) is deprecated and will be removed when we remove the legacy architecture.")));
;
const std::shared_ptr<facebook::react::RuntimeScheduler> &runtimeScheduler);
#endif // __cplusplus
RCT_EXTERN_C_BEGIN
void RCTAppSetupPrepareApp(UIApplication *application, BOOL turboModuleEnabled) __attribute__((deprecated(
"RCTAppSetupPrepareApp(UIApplication, BOOL) is deprecated and it's signature will change when we remove the legacy arch")));
UIView *
RCTAppSetupDefaultRootView(RCTBridge *bridge, NSString *moduleName, NSDictionary *initialProperties, BOOL fabricEnabled)
__attribute__((deprecated(
"RCTAppSetupDefaultRootView(RCTBridge *, NSString *, NSDictionary *, BOOL) is deprecated and it's signature will change when we remove the legacy arch")));
void RCTAppSetupPrepareApp(UIApplication *application, BOOL turboModuleEnabled);
UIView *RCTAppSetupDefaultRootView(
RCTBridge *bridge,
NSString *moduleName,
NSDictionary *initialProperties,
BOOL fabricEnabled);
RCT_EXTERN_C_END

Some files were not shown because too many files have changed in this diff Show More