diff --git a/packages/app/android/template.config.mjs b/packages/app/android/template.config.mjs index 8b515a86c..da99108e7 100644 --- a/packages/app/android/template.config.mjs +++ b/packages/app/android/template.config.mjs @@ -1,11 +1,139 @@ // @ts-check import * as nodefs from "node:fs"; import * as path from "node:path"; -import { findFile } from "../scripts/helpers.js"; +import { findFile, toVersionNumber } from "../scripts/helpers.js"; +import { copyFrom } from "../scripts/template.mjs"; import { generateAndroidManifest } from "./android-manifest.js"; import { configureGradleWrapper } from "./gradle-wrapper.js"; -/** @import { ProjectConfig, ProjectParams } from "../scripts/types.js"; */ +/** + * @import { + * Configuration, + * ConfigureParams, + * ProjectConfig, + * ProjectParams, + * } from "../scripts/types.js"; + */ + +/** + * @returns {string} + */ +export function buildGradle() { + return `buildscript { + apply(from: { + def searchDir = rootDir.toPath() + do { + def p = searchDir.resolve("node_modules/react-native-test-app/android/dependencies.gradle") + if (p.toFile().exists()) { + return p.toRealPath().toString() + } + } while (searchDir = searchDir.getParent()) + throw new GradleException("Could not find \`react-native-test-app\`"); + }()) + + repositories { + mavenCentral() + google() + } + + dependencies { + getReactNativeDependencies().each { dependency -> + classpath(dependency) + } + } +} +`; +} + +/** + * @param {number} _targetVersion Target React Native version + * @returns {string} + */ +export function gradleProperties(_targetVersion) { + return `# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the Gradle Daemon. The setting is +# particularly useful for configuring JVM memory settings for build performance. +# This does not affect the JVM settings for the Gradle client VM. +# The default is \`-Xmx512m -XX:MaxMetaspaceSize=256m\`. +org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will fork up to org.gradle.workers.max JVMs to execute +# projects in parallel. To learn more about parallel task execution, see the +# section on Gradle build performance: +# https://docs.gradle.org/current/userguide/performance.html#parallel_execution. +# Default is \`false\`. +#org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +#android.enableJetifier=true +# Jetifier randomly fails on these libraries +#android.jetifier.ignorelist=hermes-android,react-android + +# Use this property to specify which architecture you want to build. +# You can also override it from the CLI using +# ./gradlew -PreactNativeArchitectures=x86_64 +reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 + +# Use this property to enable support to the new architecture. +# This will allow you to use TurboModules and the Fabric render in +# your application. You should enable this flag either if you want +# to write custom TurboModules/Fabric components OR use libraries that +# are providing them. +# Note that this is incompatible with web debugging. +newArchEnabled=true +#bridgelessEnabled=true + +# Uncomment the line below to build React Native from source. +#react.buildFromSource=true + +# Version of Android NDK to build against. +#ANDROID_NDK_VERSION=26.1.10909125 + +# Version of Kotlin to build against. +#KOTLIN_VERSION=1.8.22 +`; +} + +/** + * @param {string} name Root project name + * @returns {string} + */ +export function settingsGradle(name) { + return `pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() + google() + } +} + +rootProject.name = "${name}" + +apply(from: { + def searchDir = rootDir.toPath() + do { + def p = searchDir.resolve("node_modules/react-native-test-app/test-app.gradle") + if (p.toFile().exists()) { + return p.toRealPath().toString() + } + } while (searchDir = searchDir.getParent()) + throw new GradleException("Could not find \`react-native-test-app\`"); +}()) +applyTestAppSettings(settings) +`; +} /** * @returns {string | undefined} @@ -47,3 +175,43 @@ export function configure( packageName: packageName || getAndroidPackageName(), }; } + +/** + * @param {ConfigureParams} params + * @returns {Configuration} + */ +export function getTemplate({ name, testAppPath, targetVersion }) { + const targetVersionNum = toVersionNumber(targetVersion); + return { + files: { + "build.gradle": buildGradle(), + "gradle/wrapper/gradle-wrapper.jar": copyFrom( + testAppPath, + "example", + "android", + "gradle", + "wrapper", + "gradle-wrapper.jar" + ), + "gradle/wrapper/gradle-wrapper.properties": copyFrom( + testAppPath, + "example", + "android", + "gradle", + "wrapper", + "gradle-wrapper.properties" + ), + "gradle.properties": gradleProperties(targetVersionNum), + gradlew: copyFrom(testAppPath, "example", "android", "gradlew"), + "gradlew.bat": copyFrom(testAppPath, "example", "android", "gradlew.bat"), + "settings.gradle": settingsGradle(name), + }, + oldFiles: [], + scripts: { + android: "react-native run-android", + "build:android": + "react-native bundle --entry-file index.js --platform android --dev true --bundle-output dist/main.android.jsbundle --assets-dest dist/res", + }, + dependencies: {}, + }; +} diff --git a/packages/app/ios/template.config.mjs b/packages/app/ios/template.config.mjs index 86b1c046c..969658b09 100644 --- a/packages/app/ios/template.config.mjs +++ b/packages/app/ios/template.config.mjs @@ -1,7 +1,42 @@ // @ts-check import * as nodefs from "node:fs"; +import { toVersionNumber, v } from "../scripts/helpers.js"; -/** @import { ProjectConfig, ProjectParams } from "../scripts/types.js"; */ +/** + * @import { + * Configuration, + * ConfigureParams, + * ProjectConfig, + * ProjectParams, + * } from "../scripts/types.js"; + */ + +/** + * @param {string} name Root project name + * @param {"" | "macos/" | "visionos/"} prefix Platform prefix + * @param {number} targetVersion Target React Native version + * @returns {string} + */ +export function podfile(name, prefix, targetVersion) { + // https://reactnative.dev/blog/2024/10/23/the-new-architecture-is-here + /** @type {Record} */ + const newArchMatrix = { + "": v(0, 76, 0), + "macos/": v(1000, 0, 0), + "visionos/": v(0, 76, 0), + }; + const newArchEnabled = targetVersion >= newArchMatrix[prefix]; + return `ws_dir = Pathname.new(__dir__) +ws_dir = ws_dir.parent until + File.exist?("#{ws_dir}/node_modules/react-native-test-app/${prefix}test_app.rb") || + ws_dir.expand_path.to_s == '/' +require "#{ws_dir}/node_modules/react-native-test-app/${prefix}test_app.rb" + +workspace '${name}.xcworkspace' + +use_test_app! :hermes_enabled => true, :fabric_enabled => ${newArchEnabled} +`; +} /** * @param {string} _projectRoot @@ -11,3 +46,28 @@ import * as nodefs from "node:fs"; export function configure(_projectRoot, config, _fs = nodefs) { return config; } + +/** + * @param {ConfigureParams} params + * @returns {Configuration} + */ +export function getTemplate({ name, targetVersion }) { + const targetVersionNum = toVersionNumber(targetVersion); + return { + files: { + Podfile: podfile(name, "", targetVersionNum), + }, + oldFiles: [ + "Podfile.lock", + "Pods", + `${name}.xcodeproj`, + `${name}.xcworkspace`, + ], + scripts: { + "build:ios": + "react-native bundle --entry-file index.js --platform ios --dev true --bundle-output dist/main.ios.jsbundle --assets-dest dist", + ios: "react-native run-ios", + }, + dependencies: {}, + }; +} diff --git a/packages/app/macos/template.config.mjs b/packages/app/macos/template.config.mjs new file mode 100644 index 000000000..090e8f6bb --- /dev/null +++ b/packages/app/macos/template.config.mjs @@ -0,0 +1,40 @@ +// @ts-check +import * as nodefs from "node:fs"; +import { podfile } from "../ios/template.config.mjs"; +import { toVersionNumber } from "../scripts/helpers.js"; + +/** @import { Configuration, ConfigureParams } from "../scripts/types.js"; */ + +/** + * @param {string} _projectRoot + * @param {unknown} _config + * @returns {undefined} + */ +export function configure(_projectRoot, _config, _fs = nodefs) { + return undefined; +} + +/** + * @param {ConfigureParams} params + * @returns {Configuration} + */ +export function getTemplate({ name, targetVersion }) { + const targetVersionNum = toVersionNumber(targetVersion); + return { + files: { + Podfile: podfile(name, "macos/", targetVersionNum), + }, + oldFiles: [ + "Podfile.lock", + "Pods", + `${name}.xcodeproj`, + `${name}.xcworkspace`, + ], + scripts: { + "build:macos": + "react-native bundle --entry-file index.js --platform macos --dev true --bundle-output dist/main.macos.jsbundle --assets-dest dist", + macos: `react-native run-macos --scheme ${name}`, + }, + dependencies: {}, + }; +} diff --git a/packages/app/scripts/configure.mjs b/packages/app/scripts/configure.mjs index ee1f5ef41..18133e430 100755 --- a/packages/app/scripts/configure.mjs +++ b/packages/app/scripts/configure.mjs @@ -17,35 +17,29 @@ import * as path from "node:path"; import { URL, fileURLToPath } from "node:url"; import semverCoerce from "semver/functions/coerce.js"; import semverSatisfies from "semver/functions/satisfies.js"; +import { getTemplate as getAndroidTemplate } from "../android/template.config.mjs"; +import { getTemplate as getIOSTemplate } from "../ios/template.config.mjs"; +import { getTemplate as getMacOSTemplate } from "../macos/template.config.mjs"; +import { getTemplate as getVisionOSTemplate } from "../visionos/template.config.mjs"; +import { getTemplate as getWindowsTemplate } from "../windows/template.config.mjs"; import { getPackageVersion, isMain, memo, readJSONFile, readTextFile, - toVersionNumber, } from "./helpers.js"; import { appManifest, - buildGradle, bundleConfig, - gradleProperties, - podfile, + copyFrom, + findGitIgnore, serialize, - settingsGradle, } from "./template.mjs"; import * as colors from "./utils/colors.mjs"; import { downloadPackage } from "./utils/npm.mjs"; import { parseArgs } from "./utils/parseargs.mjs"; -/** - * @param {...string} paths - * @returns {{ source: string; }} - */ -function copyFrom(...paths) { - return { source: path.join(...paths) }; -} - /** * Merges two objects. * @param {unknown} lhs @@ -255,15 +249,7 @@ export const getConfig = (() => { fs = nodefs ) => { if (disableCache || typeof configuration === "undefined") { - const { name, templatePath, testAppPath, targetVersion, init } = params; - - // `.gitignore` files are only renamed when published. - const gitignore = ["_gitignore", ".gitignore"].find((filename) => { - return fs.existsSync(path.join(testAppPath, "example", filename)); - }); - if (!gitignore) { - throw new Error("Failed to find `.gitignore`"); - } + const { name, templatePath, testAppPath, init } = params; const require = createRequire(import.meta.url); const templateDir = @@ -273,12 +259,10 @@ export const getConfig = (() => { path.dirname(require.resolve("react-native/template/package.json")) ); - const targetVersionNum = toVersionNumber(targetVersion); - configuration = { common: { files: { - ".gitignore": copyFrom(testAppPath, "example", gitignore), + ".gitignore": findGitIgnore(path.join(testAppPath, "example"), fs), ".watchmanconfig": copyFrom(templateDir, "_watchmanconfig"), "babel.config.js": copyFrom(templateDir, "babel.config.js"), "metro.config.js": copyFrom( @@ -308,115 +292,11 @@ export const getConfig = (() => { }, dependencies: {}, }, - android: { - files: { - "build.gradle": buildGradle(), - "gradle/wrapper/gradle-wrapper.jar": copyFrom( - testAppPath, - "example", - "android", - "gradle", - "wrapper", - "gradle-wrapper.jar" - ), - "gradle/wrapper/gradle-wrapper.properties": copyFrom( - testAppPath, - "example", - "android", - "gradle", - "wrapper", - "gradle-wrapper.properties" - ), - "gradle.properties": gradleProperties(targetVersionNum), - gradlew: copyFrom(testAppPath, "example", "android", "gradlew"), - "gradlew.bat": copyFrom( - testAppPath, - "example", - "android", - "gradlew.bat" - ), - "settings.gradle": settingsGradle(name), - }, - oldFiles: [], - scripts: { - android: "react-native run-android", - "build:android": - "react-native bundle --entry-file index.js --platform android --dev true --bundle-output dist/main.android.jsbundle --assets-dest dist/res", - }, - dependencies: {}, - }, - ios: { - files: { - Podfile: podfile(name, "", targetVersionNum), - }, - oldFiles: [ - "Podfile.lock", - "Pods", - `${name}.xcodeproj`, - `${name}.xcworkspace`, - ], - scripts: { - "build:ios": - "react-native bundle --entry-file index.js --platform ios --dev true --bundle-output dist/main.ios.jsbundle --assets-dest dist", - ios: "react-native run-ios", - }, - dependencies: {}, - }, - macos: { - files: { - Podfile: podfile(name, "macos/", targetVersionNum), - }, - oldFiles: [ - "Podfile.lock", - "Pods", - `${name}.xcodeproj`, - `${name}.xcworkspace`, - ], - scripts: { - "build:macos": - "react-native bundle --entry-file index.js --platform macos --dev true --bundle-output dist/main.macos.jsbundle --assets-dest dist", - macos: `react-native run-macos --scheme ${name}`, - }, - dependencies: {}, - }, - visionos: { - files: { - Podfile: podfile(name, "visionos/", targetVersionNum), - }, - oldFiles: [ - "Podfile.lock", - "Pods", - `${name}.xcodeproj`, - `${name}.xcworkspace`, - ], - scripts: { - "build:visionos": - "react-native bundle --entry-file index.js --platform ios --dev true --bundle-output dist/main.visionos.jsbundle --assets-dest dist", - visionos: "react-native run-visionos", - }, - dependencies: {}, - }, - windows: { - files: { - ".gitignore": copyFrom( - testAppPath, - "example", - "windows", - gitignore - ), - }, - oldFiles: [ - `${name}.sln`, - `${name}.vcxproj`, - path.join(name, `${name}.vcxproj`), - ], - scripts: { - "build:windows": - "react-native bundle --entry-file index.js --platform windows --dev true --bundle-output dist/main.windows.bundle --assets-dest dist", - windows: "react-native run-windows", - }, - dependencies: {}, - }, + android: getAndroidTemplate(params), + ios: getIOSTemplate(params), + macos: getMacOSTemplate(params), + visionos: getVisionOSTemplate(params), + windows: getWindowsTemplate(params, fs), }; } return configuration[platform]; diff --git a/packages/app/scripts/template.mjs b/packages/app/scripts/template.mjs index c088bc5d3..c1afca183 100644 --- a/packages/app/scripts/template.mjs +++ b/packages/app/scripts/template.mjs @@ -1,13 +1,29 @@ // @ts-check -import { v } from "./helpers.js"; +import * as nodefs from "node:fs"; +import * as path from "node:path"; /** - * Joins all specified lines into a single string. - * @param {...string} lines - * @returns {string} + * @param {...string} paths + * @returns {{ source: string; }} */ -export function join(...lines) { - return lines.join("\n"); +export function copyFrom(...paths) { + return { source: path.join(...paths) }; +} + +/** + * @param {string} dir + * @returns {import("./types.ts").Configuration["files"][string]} + */ +export function findGitIgnore(dir, fs = nodefs) { + // `.gitignore` files are only renamed when published. + for (const filename of ["_gitignore", ".gitignore"]) { + const gitignore = path.join(dir, filename); + if (fs.existsSync(gitignore)) { + return { source: gitignore }; + } + } + + return ""; } /** @@ -43,38 +59,6 @@ export function appManifest(name) { }); } -/** - * @returns {string} - */ -export function buildGradle() { - return join( - "buildscript {", - " apply(from: {", - " def searchDir = rootDir.toPath()", - " do {", - ' def p = searchDir.resolve("node_modules/react-native-test-app/android/dependencies.gradle")', - " if (p.toFile().exists()) {", - " return p.toRealPath().toString()", - " }", - " } while (searchDir = searchDir.getParent())", - ' throw new GradleException("Could not find `react-native-test-app`");', - " }())", - "", - " repositories {", - " mavenCentral()", - " google()", - " }", - "", - " dependencies {", - " getReactNativeDependencies().each { dependency ->", - " classpath(dependency)", - " }", - " }", - "}", - "" - ); -} - /** * Returns `.bundle/config`. * @@ -84,127 +68,7 @@ export function buildGradle() { * @returns {string} */ export function bundleConfig() { - return join('BUNDLE_PATH: ".bundle"', "BUNDLE_FORCE_RUBY_PLATFORM: 1"); -} - -/** - * @param {number} _targetVersion Target React Native version - * @returns {string} - */ -export function gradleProperties(_targetVersion) { - return join( - "# Project-wide Gradle settings.", - "", - "# IDE (e.g. Android Studio) users:", - "# Gradle settings configured through the IDE *will override*", - "# any settings specified in this file.", - "", - "# For more details on how to configure your build environment visit", - "# http://www.gradle.org/docs/current/userguide/build_environment.html", - "", - "# Specifies the JVM arguments used for the Gradle Daemon. The setting is", - "# particularly useful for configuring JVM memory settings for build performance.", - "# This does not affect the JVM settings for the Gradle client VM.", - "# The default is `-Xmx512m -XX:MaxMetaspaceSize=256m`.", - "org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8", - "", - "# When configured, Gradle will fork up to org.gradle.workers.max JVMs to execute", - "# projects in parallel. To learn more about parallel task execution, see the", - "# section on Gradle build performance:", - "# https://docs.gradle.org/current/userguide/performance.html#parallel_execution.", - "# Default is `false`.", - "#org.gradle.parallel=true", - "", - "# AndroidX package structure to make it clearer which packages are bundled with the", - "# Android operating system, and which are packaged with your app's APK", - "# https://developer.android.com/topic/libraries/support-library/androidx-rn", - "android.useAndroidX=true", - "# Automatically convert third-party libraries to use AndroidX", - `#android.enableJetifier=true`, - "# Jetifier randomly fails on these libraries", - `#android.jetifier.ignorelist=hermes-android,react-android`, - "", - "# Use this property to specify which architecture you want to build.", - "# You can also override it from the CLI using", - "# ./gradlew -PreactNativeArchitectures=x86_64", - "reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64", - "", - "# Use this property to enable support to the new architecture.", - "# This will allow you to use TurboModules and the Fabric render in", - "# your application. You should enable this flag either if you want", - "# to write custom TurboModules/Fabric components OR use libraries that", - "# are providing them.", - "# Note that this is incompatible with web debugging.", - `newArchEnabled=true`, - "#bridgelessEnabled=true", - "", - "# Uncomment the line below to build React Native from source.", - "#react.buildFromSource=true", - "", - "# Version of Android NDK to build against.", - "#ANDROID_NDK_VERSION=26.1.10909125", - "", - "# Version of Kotlin to build against.", - "#KOTLIN_VERSION=1.8.22" - ); -} - -/** - * @param {string} name Root project name - * @param {"" | "macos/" | "visionos/"} prefix Platform prefix - * @param {number} targetVersion Target React Native version - * @returns {string} - */ -export function podfile(name, prefix, targetVersion) { - // https://reactnative.dev/blog/2024/10/23/the-new-architecture-is-here - /** @type {Record} */ - const newArchMatrix = { - "": v(0, 76, 0), - "macos/": v(1000, 0, 0), - "visionos/": v(0, 76, 0), - }; - const newArchEnabled = targetVersion >= newArchMatrix[prefix]; - return join( - "ws_dir = Pathname.new(__dir__)", - "ws_dir = ws_dir.parent until", - ` File.exist?("#{ws_dir}/node_modules/react-native-test-app/${prefix}test_app.rb") ||`, - " ws_dir.expand_path.to_s == '/'", - `require "#{ws_dir}/node_modules/react-native-test-app/${prefix}test_app.rb"`, - "", - `workspace '${name}.xcworkspace'`, - "", - `use_test_app! :hermes_enabled => true, :fabric_enabled => ${newArchEnabled}`, - "" - ); -} - -/** - * @param {string} name Root project name - * @returns {string} - */ -export function settingsGradle(name) { - return join( - "pluginManagement {", - " repositories {", - " gradlePluginPortal()", - " mavenCentral()", - " google()", - " }", - "}", - "", - `rootProject.name = "${name}"`, - "", - "apply(from: {", - " def searchDir = rootDir.toPath()", - " do {", - ' def p = searchDir.resolve("node_modules/react-native-test-app/test-app.gradle")', - " if (p.toFile().exists()) {", - " return p.toRealPath().toString()", - " }", - " } while (searchDir = searchDir.getParent())", - ' throw new GradleException("Could not find `react-native-test-app`");', - "}())", - "applyTestAppSettings(settings)", - "" - ); + return `BUNDLE_PATH: ".bundle" +BUNDLE_FORCE_RUBY_PLATFORM: 1 +`; } diff --git a/packages/app/test/configure/gatherConfig.test.mts b/packages/app/test/configure/gatherConfig.test.mts index ef90825b7..1b76e139a 100644 --- a/packages/app/test/configure/gatherConfig.test.mts +++ b/packages/app/test/configure/gatherConfig.test.mts @@ -1,16 +1,10 @@ -import { deepEqual } from "node:assert/strict"; import { describe, it } from "node:test"; import { gatherConfig as gatherConfigActual } from "../../scripts/configure.mjs"; -import { join } from "../../scripts/template.mjs"; import type { Configuration, ConfigureParams } from "../../scripts/types.ts"; import { templatePath } from "../template.mts"; import { mockParams } from "./mockParams.mts"; describe("gatherConfig()", () => { - const templateDir = templatePath.substring( - templatePath.lastIndexOf("node_modules") - ); - /** * Like `gatherConfig()`, but with normalized newlines and paths. * @@ -34,575 +28,18 @@ describe("gatherConfig()", () => { return config; } - it("returns configuration for all platforms", () => { - deepEqual(gatherConfig(mockParams()), { - dependencies: { - "react-native-macos": "^0.76.0", - "react-native-windows": "^0.76.0", - }, - files: { - ".gitignore": { - source: "example/.gitignore", - }, - ".watchmanconfig": { - source: `${templateDir}/_watchmanconfig`, - }, - "android/build.gradle": join( - "buildscript {", - " apply(from: {", - " def searchDir = rootDir.toPath()", - " do {", - ' def p = searchDir.resolve("node_modules/react-native-test-app/android/dependencies.gradle")', - " if (p.toFile().exists()) {", - " return p.toRealPath().toString()", - " }", - " } while (searchDir = searchDir.getParent())", - ' throw new GradleException("Could not find `react-native-test-app`");', - " }())", - "", - " repositories {", - " mavenCentral()", - " google()", - " }", - "", - " dependencies {", - " getReactNativeDependencies().each { dependency ->", - " classpath(dependency)", - " }", - " }", - "}", - "" - ), - "android/gradle.properties": join( - "# Project-wide Gradle settings.", - "", - "# IDE (e.g. Android Studio) users:", - "# Gradle settings configured through the IDE *will override*", - "# any settings specified in this file.", - "", - "# For more details on how to configure your build environment visit", - "# http://www.gradle.org/docs/current/userguide/build_environment.html", - "", - "# Specifies the JVM arguments used for the Gradle Daemon. The setting is", - "# particularly useful for configuring JVM memory settings for build performance.", - "# This does not affect the JVM settings for the Gradle client VM.", - "# The default is `-Xmx512m -XX:MaxMetaspaceSize=256m`.", - "org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8", - "", - "# When configured, Gradle will fork up to org.gradle.workers.max JVMs to execute", - "# projects in parallel. To learn more about parallel task execution, see the", - "# section on Gradle build performance:", - "# https://docs.gradle.org/current/userguide/performance.html#parallel_execution.", - "# Default is `false`.", - "#org.gradle.parallel=true", - "", - "# AndroidX package structure to make it clearer which packages are bundled with the", - "# Android operating system, and which are packaged with your app's APK", - "# https://developer.android.com/topic/libraries/support-library/androidx-rn", - "android.useAndroidX=true", - "# Automatically convert third-party libraries to use AndroidX", - "#android.enableJetifier=true", - "# Jetifier randomly fails on these libraries", - "#android.jetifier.ignorelist=hermes-android,react-android", - "", - "# Use this property to specify which architecture you want to build.", - "# You can also override it from the CLI using", - "# ./gradlew -PreactNativeArchitectures=x86_64", - "reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64", - "", - "# Use this property to enable support to the new architecture.", - "# This will allow you to use TurboModules and the Fabric render in", - "# your application. You should enable this flag either if you want", - "# to write custom TurboModules/Fabric components OR use libraries that", - "# are providing them.", - "# Note that this is incompatible with web debugging.", - "newArchEnabled=true", - "#bridgelessEnabled=true", - "", - "# Uncomment the line below to build React Native from source.", - "#react.buildFromSource=true", - "", - "# Version of Android NDK to build against.", - "#ANDROID_NDK_VERSION=26.1.10909125", - "", - "# Version of Kotlin to build against.", - "#KOTLIN_VERSION=1.8.22" - ), - "android/gradle/wrapper/gradle-wrapper.jar": { - source: "example/android/gradle/wrapper/gradle-wrapper.jar", - }, - "android/gradle/wrapper/gradle-wrapper.properties": { - source: "example/android/gradle/wrapper/gradle-wrapper.properties", - }, - "android/gradlew": { - source: "example/android/gradlew", - }, - "android/gradlew.bat": { - source: "example/android/gradlew.bat", - }, - "android/settings.gradle": join( - "pluginManagement {", - " repositories {", - " gradlePluginPortal()", - " mavenCentral()", - " google()", - " }", - "}", - "", - 'rootProject.name = "Test"', - "", - "apply(from: {", - " def searchDir = rootDir.toPath()", - " do {", - ' def p = searchDir.resolve("node_modules/react-native-test-app/test-app.gradle")', - " if (p.toFile().exists()) {", - " return p.toRealPath().toString()", - " }", - " } while (searchDir = searchDir.getParent())", - ' throw new GradleException("Could not find `react-native-test-app`");', - "}())", - "applyTestAppSettings(settings)", - "" - ), - "babel.config.js": { - source: `${templateDir}/babel.config.js`, - }, - "ios/Podfile": join( - "ws_dir = Pathname.new(__dir__)", - "ws_dir = ws_dir.parent until", - ` File.exist?("#{ws_dir}/node_modules/react-native-test-app/test_app.rb") ||`, - " ws_dir.expand_path.to_s == '/'", - `require "#{ws_dir}/node_modules/react-native-test-app/test_app.rb"`, - "", - "workspace 'Test.xcworkspace'", - "", - "use_test_app! :hermes_enabled => true, :fabric_enabled => true", - "" - ), - "macos/Podfile": join( - "ws_dir = Pathname.new(__dir__)", - "ws_dir = ws_dir.parent until", - ` File.exist?("#{ws_dir}/node_modules/react-native-test-app/macos/test_app.rb") ||`, - " ws_dir.expand_path.to_s == '/'", - `require "#{ws_dir}/node_modules/react-native-test-app/macos/test_app.rb"`, - "", - "workspace 'Test.xcworkspace'", - "", - "use_test_app! :hermes_enabled => true, :fabric_enabled => false", - "" - ), - "metro.config.js": { - source: "example/metro.config.js", - }, - "react-native.config.js": join( - "const project = (() => {", - " try {", - ' const { configureProjects } = require("react-native-test-app");', - " return configureProjects({", - " android: {", - ' sourceDir: "android",', - " },", - " ios: {", - ' sourceDir: "ios",', - " },", - " windows: {", - ' sourceDir: "windows",', - ' solutionFile: "windows/Test.sln",', - " },", - " });", - " } catch (_) {", - " return undefined;", - " }", - "})();", - "", - "module.exports = {", - " ...(project ? { project } : undefined),", - "};", - "" - ), - "windows/.gitignore": { - source: "example/windows/.gitignore", - }, - }, - oldFiles: [ - "ios/Podfile.lock", - "ios/Pods", - "ios/Test.xcodeproj", - "ios/Test.xcworkspace", - "macos/Podfile.lock", - "macos/Pods", - "macos/Test.xcodeproj", - "macos/Test.xcworkspace", - "windows/Test.sln", - "windows/Test.vcxproj", - "windows/Test/Test.vcxproj", - ], - scripts: { - android: "react-native run-android", - "build:android": - "react-native bundle --entry-file index.js --platform android --dev true --bundle-output dist/main.android.jsbundle --assets-dest dist/res", - "build:ios": - "react-native bundle --entry-file index.js --platform ios --dev true --bundle-output dist/main.ios.jsbundle --assets-dest dist", - "build:macos": - "react-native bundle --entry-file index.js --platform macos --dev true --bundle-output dist/main.macos.jsbundle --assets-dest dist", - "build:windows": - "react-native bundle --entry-file index.js --platform windows --dev true --bundle-output dist/main.windows.bundle --assets-dest dist", - ios: "react-native run-ios", - macos: "react-native run-macos --scheme Test", - start: "react-native start", - windows: "react-native run-windows", - }, - }); - }); - - it("returns common configuration", () => { - const params = mockParams({ platforms: ["common"] }); - deepEqual(gatherConfig(params), { - dependencies: {}, - files: { - ".gitignore": { - source: "example/.gitignore", - }, - ".watchmanconfig": { - source: `${templateDir}/_watchmanconfig`, - }, - "babel.config.js": { - source: `${templateDir}/babel.config.js`, - }, - "common/.gitignore": { - source: "example/.gitignore", - }, - "common/.watchmanconfig": { - source: `${templateDir}/_watchmanconfig`, - }, - "common/babel.config.js": { - source: `${templateDir}/babel.config.js`, - }, - "common/metro.config.js": { - source: "example/metro.config.js", - }, - "common/react-native.config.js": join( - "const project = (() => {", - " try {", - ' const { configureProjects } = require("react-native-test-app");', - " return configureProjects({", - " android: {", - ' sourceDir: "android",', - " },", - " ios: {", - ' sourceDir: "ios",', - " },", - " windows: {", - ' sourceDir: "windows",', - ' solutionFile: "windows/Test.sln",', - " },", - " });", - " } catch (_) {", - " return undefined;", - " }", - "})();", - "", - "module.exports = {", - " ...(project ? { project } : undefined),", - "};", - "" - ), - "metro.config.js": { - source: "example/metro.config.js", - }, - "react-native.config.js": join( - "const project = (() => {", - " try {", - ' const { configureProjects } = require("react-native-test-app");', - " return configureProjects({", - " android: {", - ' sourceDir: "android",', - " },", - " ios: {", - ' sourceDir: "ios",', - " },", - " windows: {", - ' sourceDir: "windows",', - ' solutionFile: "windows/Test.sln",', - " },", - " });", - " } catch (_) {", - " return undefined;", - " }", - "})();", - "", - "module.exports = {", - " ...(project ? { project } : undefined),", - "};", - "" - ), - }, - oldFiles: [], - scripts: { - start: "react-native start", - }, - }); - }); - - it("returns configuration for a single platform", () => { - const params = mockParams({ platforms: ["ios"] }); - deepEqual(gatherConfig(params), { - dependencies: {}, - files: { - ".gitignore": { - source: "example/.gitignore", - }, - ".watchmanconfig": { - source: `${templateDir}/_watchmanconfig`, - }, - "babel.config.js": { - source: `${templateDir}/babel.config.js`, - }, - "ios/Podfile": join( - "ws_dir = Pathname.new(__dir__)", - "ws_dir = ws_dir.parent until", - ` File.exist?("#{ws_dir}/node_modules/react-native-test-app/test_app.rb") ||`, - " ws_dir.expand_path.to_s == '/'", - `require "#{ws_dir}/node_modules/react-native-test-app/test_app.rb"`, - "", - "workspace 'Test.xcworkspace'", - "", - "use_test_app! :hermes_enabled => true, :fabric_enabled => true", - "" - ), - "metro.config.js": { - source: "example/metro.config.js", - }, - "react-native.config.js": join( - "const project = (() => {", - " try {", - ' const { configureProjects } = require("react-native-test-app");', - " return configureProjects({", - " android: {", - ' sourceDir: "android",', - " },", - " ios: {", - ' sourceDir: "ios",', - " },", - " windows: {", - ' sourceDir: "windows",', - ' solutionFile: "windows/Test.sln",', - " },", - " });", - " } catch (_) {", - " return undefined;", - " }", - "})();", - "", - "module.exports = {", - " ...(project ? { project } : undefined),", - "};", - "" - ), - }, - oldFiles: [ - "ios/Podfile.lock", - "ios/Pods", - "ios/Test.xcodeproj", - "ios/Test.xcworkspace", - ], - scripts: { - "build:ios": - "react-native bundle --entry-file index.js --platform ios --dev true --bundle-output dist/main.ios.jsbundle --assets-dest dist", - ios: "react-native run-ios", - start: "react-native start", - }, - }); - }); - - it("returns configuration for arbitrary platforms", () => { - const params = mockParams({ platforms: ["android", "ios"] }); - deepEqual(gatherConfig(params), { - dependencies: {}, - files: { - ".gitignore": { - source: "example/.gitignore", - }, - ".watchmanconfig": { - source: `${templateDir}/_watchmanconfig`, - }, - "android/build.gradle": join( - "buildscript {", - " apply(from: {", - " def searchDir = rootDir.toPath()", - " do {", - ' def p = searchDir.resolve("node_modules/react-native-test-app/android/dependencies.gradle")', - " if (p.toFile().exists()) {", - " return p.toRealPath().toString()", - " }", - " } while (searchDir = searchDir.getParent())", - ' throw new GradleException("Could not find `react-native-test-app`");', - " }())", - "", - " repositories {", - " mavenCentral()", - " google()", - " }", - "", - " dependencies {", - " getReactNativeDependencies().each { dependency ->", - " classpath(dependency)", - " }", - " }", - "}", - "" - ), - "android/gradle.properties": join( - "# Project-wide Gradle settings.", - "", - "# IDE (e.g. Android Studio) users:", - "# Gradle settings configured through the IDE *will override*", - "# any settings specified in this file.", - "", - "# For more details on how to configure your build environment visit", - "# http://www.gradle.org/docs/current/userguide/build_environment.html", - "", - "# Specifies the JVM arguments used for the Gradle Daemon. The setting is", - "# particularly useful for configuring JVM memory settings for build performance.", - "# This does not affect the JVM settings for the Gradle client VM.", - "# The default is `-Xmx512m -XX:MaxMetaspaceSize=256m`.", - "org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8", - "", - "# When configured, Gradle will fork up to org.gradle.workers.max JVMs to execute", - "# projects in parallel. To learn more about parallel task execution, see the", - "# section on Gradle build performance:", - "# https://docs.gradle.org/current/userguide/performance.html#parallel_execution.", - "# Default is `false`.", - "#org.gradle.parallel=true", - "", - "# AndroidX package structure to make it clearer which packages are bundled with the", - "# Android operating system, and which are packaged with your app's APK", - "# https://developer.android.com/topic/libraries/support-library/androidx-rn", - "android.useAndroidX=true", - "# Automatically convert third-party libraries to use AndroidX", - "#android.enableJetifier=true", - "# Jetifier randomly fails on these libraries", - "#android.jetifier.ignorelist=hermes-android,react-android", - "", - "# Use this property to specify which architecture you want to build.", - "# You can also override it from the CLI using", - "# ./gradlew -PreactNativeArchitectures=x86_64", - "reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64", - "", - "# Use this property to enable support to the new architecture.", - "# This will allow you to use TurboModules and the Fabric render in", - "# your application. You should enable this flag either if you want", - "# to write custom TurboModules/Fabric components OR use libraries that", - "# are providing them.", - "# Note that this is incompatible with web debugging.", - "newArchEnabled=true", - "#bridgelessEnabled=true", - "", - "# Uncomment the line below to build React Native from source.", - "#react.buildFromSource=true", - "", - "# Version of Android NDK to build against.", - "#ANDROID_NDK_VERSION=26.1.10909125", - "", - "# Version of Kotlin to build against.", - "#KOTLIN_VERSION=1.8.22" - ), - "android/gradle/wrapper/gradle-wrapper.jar": { - source: "example/android/gradle/wrapper/gradle-wrapper.jar", - }, - "android/gradle/wrapper/gradle-wrapper.properties": { - source: "example/android/gradle/wrapper/gradle-wrapper.properties", - }, - "android/gradlew": { - source: "example/android/gradlew", - }, - "android/gradlew.bat": { - source: "example/android/gradlew.bat", - }, - "android/settings.gradle": join( - "pluginManagement {", - " repositories {", - " gradlePluginPortal()", - " mavenCentral()", - " google()", - " }", - "}", - "", - 'rootProject.name = "Test"', - "", - "apply(from: {", - " def searchDir = rootDir.toPath()", - " do {", - ' def p = searchDir.resolve("node_modules/react-native-test-app/test-app.gradle")', - " if (p.toFile().exists()) {", - " return p.toRealPath().toString()", - " }", - " } while (searchDir = searchDir.getParent())", - ' throw new GradleException("Could not find `react-native-test-app`");', - "}())", - "applyTestAppSettings(settings)", - "" - ), - "babel.config.js": { - source: `${templateDir}/babel.config.js`, - }, - "ios/Podfile": join( - "ws_dir = Pathname.new(__dir__)", - "ws_dir = ws_dir.parent until", - ` File.exist?("#{ws_dir}/node_modules/react-native-test-app/test_app.rb") ||`, - " ws_dir.expand_path.to_s == '/'", - `require "#{ws_dir}/node_modules/react-native-test-app/test_app.rb"`, - "", - "workspace 'Test.xcworkspace'", - "", - "use_test_app! :hermes_enabled => true, :fabric_enabled => true", - "" - ), - "metro.config.js": { - source: "example/metro.config.js", - }, - "react-native.config.js": join( - "const project = (() => {", - " try {", - ' const { configureProjects } = require("react-native-test-app");', - " return configureProjects({", - " android: {", - ' sourceDir: "android",', - " },", - " ios: {", - ' sourceDir: "ios",', - " },", - " windows: {", - ' sourceDir: "windows",', - ' solutionFile: "windows/Test.sln",', - " },", - " });", - " } catch (_) {", - " return undefined;", - " }", - "})();", - "", - "module.exports = {", - " ...(project ? { project } : undefined),", - "};", - "" - ), - }, - oldFiles: [ - "ios/Podfile.lock", - "ios/Pods", - "ios/Test.xcodeproj", - "ios/Test.xcworkspace", - ], - scripts: { - android: "react-native run-android", - "build:android": - "react-native bundle --entry-file index.js --platform android --dev true --bundle-output dist/main.android.jsbundle --assets-dest dist/res", - "build:ios": - "react-native bundle --entry-file index.js --platform ios --dev true --bundle-output dist/main.ios.jsbundle --assets-dest dist", - ios: "react-native run-ios", - start: "react-native start", - }, + const configurations: [string, Partial][] = [ + ["returns configuration for all platforms", {}], + ["returns common configuration", { platforms: ["common"] }], + ["returns configuration for a single platform", { platforms: ["ios"] }], + [ + "returns configuration for arbitrary platforms", + { platforms: ["android", "ios"] }, + ], + ]; + for (const [name, overrides] of configurations) { + it(name, (t) => { + t.assert.snapshot(gatherConfig(mockParams(overrides))); }); - }); + } }); diff --git a/packages/app/test/configure/gatherConfig.test.mts.snapshot b/packages/app/test/configure/gatherConfig.test.mts.snapshot new file mode 100644 index 000000000..c3e6a44a7 --- /dev/null +++ b/packages/app/test/configure/gatherConfig.test.mts.snapshot @@ -0,0 +1,188 @@ +exports[`gatherConfig() > returns common configuration 1`] = ` +{ + "files": { + ".gitignore": { + "source": "example/.gitignore" + }, + ".watchmanconfig": { + "source": "node_modules/@react-native-community/template/template/_watchmanconfig" + }, + "babel.config.js": { + "source": "node_modules/@react-native-community/template/template/babel.config.js" + }, + "metro.config.js": { + "source": "example/metro.config.js" + }, + "react-native.config.js": "const project = (() => {\\n try {\\n const { configureProjects } = require(\\"react-native-test-app\\");\\n return configureProjects({\\n android: {\\n sourceDir: \\"android\\",\\n },\\n ios: {\\n sourceDir: \\"ios\\",\\n },\\n windows: {\\n sourceDir: \\"windows\\",\\n solutionFile: \\"windows/Test.sln\\",\\n },\\n });\\n } catch (_) {\\n return undefined;\\n }\\n})();\\n\\nmodule.exports = {\\n ...(project ? { project } : undefined),\\n};\\n", + "common/.gitignore": { + "source": "example/.gitignore" + }, + "common/.watchmanconfig": { + "source": "node_modules/@react-native-community/template/template/_watchmanconfig" + }, + "common/babel.config.js": { + "source": "node_modules/@react-native-community/template/template/babel.config.js" + }, + "common/metro.config.js": { + "source": "example/metro.config.js" + }, + "common/react-native.config.js": "const project = (() => {\\n try {\\n const { configureProjects } = require(\\"react-native-test-app\\");\\n return configureProjects({\\n android: {\\n sourceDir: \\"android\\",\\n },\\n ios: {\\n sourceDir: \\"ios\\",\\n },\\n windows: {\\n sourceDir: \\"windows\\",\\n solutionFile: \\"windows/Test.sln\\",\\n },\\n });\\n } catch (_) {\\n return undefined;\\n }\\n})();\\n\\nmodule.exports = {\\n ...(project ? { project } : undefined),\\n};\\n" + }, + "oldFiles": [], + "scripts": { + "start": "react-native start" + }, + "dependencies": {} +} +`; + +exports[`gatherConfig() > returns configuration for a single platform 1`] = ` +{ + "files": { + ".gitignore": { + "source": "example/.gitignore" + }, + ".watchmanconfig": { + "source": "node_modules/@react-native-community/template/template/_watchmanconfig" + }, + "babel.config.js": { + "source": "node_modules/@react-native-community/template/template/babel.config.js" + }, + "metro.config.js": { + "source": "example/metro.config.js" + }, + "react-native.config.js": "const project = (() => {\\n try {\\n const { configureProjects } = require(\\"react-native-test-app\\");\\n return configureProjects({\\n android: {\\n sourceDir: \\"android\\",\\n },\\n ios: {\\n sourceDir: \\"ios\\",\\n },\\n windows: {\\n sourceDir: \\"windows\\",\\n solutionFile: \\"windows/Test.sln\\",\\n },\\n });\\n } catch (_) {\\n return undefined;\\n }\\n})();\\n\\nmodule.exports = {\\n ...(project ? { project } : undefined),\\n};\\n", + "ios/Podfile": "ws_dir = Pathname.new(__dir__)\\nws_dir = ws_dir.parent until\\n File.exist?(\\"#{ws_dir}/node_modules/react-native-test-app/test_app.rb\\") ||\\n ws_dir.expand_path.to_s == '/'\\nrequire \\"#{ws_dir}/node_modules/react-native-test-app/test_app.rb\\"\\n\\nworkspace 'Test.xcworkspace'\\n\\nuse_test_app! :hermes_enabled => true, :fabric_enabled => true\\n" + }, + "oldFiles": [ + "ios/Podfile.lock", + "ios/Pods", + "ios/Test.xcodeproj", + "ios/Test.xcworkspace" + ], + "scripts": { + "start": "react-native start", + "build:ios": "react-native bundle --entry-file index.js --platform ios --dev true --bundle-output dist/main.ios.jsbundle --assets-dest dist", + "ios": "react-native run-ios" + }, + "dependencies": {} +} +`; + +exports[`gatherConfig() > returns configuration for all platforms 1`] = ` +{ + "files": { + ".gitignore": { + "source": "example/.gitignore" + }, + ".watchmanconfig": { + "source": "node_modules/@react-native-community/template/template/_watchmanconfig" + }, + "babel.config.js": { + "source": "node_modules/@react-native-community/template/template/babel.config.js" + }, + "metro.config.js": { + "source": "example/metro.config.js" + }, + "react-native.config.js": "const project = (() => {\\n try {\\n const { configureProjects } = require(\\"react-native-test-app\\");\\n return configureProjects({\\n android: {\\n sourceDir: \\"android\\",\\n },\\n ios: {\\n sourceDir: \\"ios\\",\\n },\\n windows: {\\n sourceDir: \\"windows\\",\\n solutionFile: \\"windows/Test.sln\\",\\n },\\n });\\n } catch (_) {\\n return undefined;\\n }\\n})();\\n\\nmodule.exports = {\\n ...(project ? { project } : undefined),\\n};\\n", + "android/build.gradle": "buildscript {\\n apply(from: {\\n def searchDir = rootDir.toPath()\\n do {\\n def p = searchDir.resolve(\\"node_modules/react-native-test-app/android/dependencies.gradle\\")\\n if (p.toFile().exists()) {\\n return p.toRealPath().toString()\\n }\\n } while (searchDir = searchDir.getParent())\\n throw new GradleException(\\"Could not find \`react-native-test-app\`\\");\\n }())\\n\\n repositories {\\n mavenCentral()\\n google()\\n }\\n\\n dependencies {\\n getReactNativeDependencies().each { dependency ->\\n classpath(dependency)\\n }\\n }\\n}\\n", + "android/gradle/wrapper/gradle-wrapper.jar": { + "source": "example/android/gradle/wrapper/gradle-wrapper.jar" + }, + "android/gradle/wrapper/gradle-wrapper.properties": { + "source": "example/android/gradle/wrapper/gradle-wrapper.properties" + }, + "android/gradle.properties": "# Project-wide Gradle settings.\\n\\n# IDE (e.g. Android Studio) users:\\n# Gradle settings configured through the IDE *will override*\\n# any settings specified in this file.\\n\\n# For more details on how to configure your build environment visit\\n# http://www.gradle.org/docs/current/userguide/build_environment.html\\n\\n# Specifies the JVM arguments used for the Gradle Daemon. The setting is\\n# particularly useful for configuring JVM memory settings for build performance.\\n# This does not affect the JVM settings for the Gradle client VM.\\n# The default is \`-Xmx512m -XX:MaxMetaspaceSize=256m\`.\\norg.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\\n\\n# When configured, Gradle will fork up to org.gradle.workers.max JVMs to execute\\n# projects in parallel. To learn more about parallel task execution, see the\\n# section on Gradle build performance:\\n# https://docs.gradle.org/current/userguide/performance.html#parallel_execution.\\n# Default is \`false\`.\\n#org.gradle.parallel=true\\n\\n# AndroidX package structure to make it clearer which packages are bundled with the\\n# Android operating system, and which are packaged with your app's APK\\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\\nandroid.useAndroidX=true\\n# Automatically convert third-party libraries to use AndroidX\\n#android.enableJetifier=true\\n# Jetifier randomly fails on these libraries\\n#android.jetifier.ignorelist=hermes-android,react-android\\n\\n# Use this property to specify which architecture you want to build.\\n# You can also override it from the CLI using\\n# ./gradlew -PreactNativeArchitectures=x86_64\\nreactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64\\n\\n# Use this property to enable support to the new architecture.\\n# This will allow you to use TurboModules and the Fabric render in\\n# your application. You should enable this flag either if you want\\n# to write custom TurboModules/Fabric components OR use libraries that\\n# are providing them.\\n# Note that this is incompatible with web debugging.\\nnewArchEnabled=true\\n#bridgelessEnabled=true\\n\\n# Uncomment the line below to build React Native from source.\\n#react.buildFromSource=true\\n\\n# Version of Android NDK to build against.\\n#ANDROID_NDK_VERSION=26.1.10909125\\n\\n# Version of Kotlin to build against.\\n#KOTLIN_VERSION=1.8.22\\n", + "android/gradlew": { + "source": "example/android/gradlew" + }, + "android/gradlew.bat": { + "source": "example/android/gradlew.bat" + }, + "android/settings.gradle": "pluginManagement {\\n repositories {\\n gradlePluginPortal()\\n mavenCentral()\\n google()\\n }\\n}\\n\\nrootProject.name = \\"Test\\"\\n\\napply(from: {\\n def searchDir = rootDir.toPath()\\n do {\\n def p = searchDir.resolve(\\"node_modules/react-native-test-app/test-app.gradle\\")\\n if (p.toFile().exists()) {\\n return p.toRealPath().toString()\\n }\\n } while (searchDir = searchDir.getParent())\\n throw new GradleException(\\"Could not find \`react-native-test-app\`\\");\\n}())\\napplyTestAppSettings(settings)\\n", + "ios/Podfile": "ws_dir = Pathname.new(__dir__)\\nws_dir = ws_dir.parent until\\n File.exist?(\\"#{ws_dir}/node_modules/react-native-test-app/test_app.rb\\") ||\\n ws_dir.expand_path.to_s == '/'\\nrequire \\"#{ws_dir}/node_modules/react-native-test-app/test_app.rb\\"\\n\\nworkspace 'Test.xcworkspace'\\n\\nuse_test_app! :hermes_enabled => true, :fabric_enabled => true\\n", + "macos/Podfile": "ws_dir = Pathname.new(__dir__)\\nws_dir = ws_dir.parent until\\n File.exist?(\\"#{ws_dir}/node_modules/react-native-test-app/macos/test_app.rb\\") ||\\n ws_dir.expand_path.to_s == '/'\\nrequire \\"#{ws_dir}/node_modules/react-native-test-app/macos/test_app.rb\\"\\n\\nworkspace 'Test.xcworkspace'\\n\\nuse_test_app! :hermes_enabled => true, :fabric_enabled => false\\n", + "windows/.gitignore": { + "source": "example/windows/.gitignore" + } + }, + "oldFiles": [ + "ios/Podfile.lock", + "ios/Pods", + "ios/Test.xcodeproj", + "ios/Test.xcworkspace", + "macos/Podfile.lock", + "macos/Pods", + "macos/Test.xcodeproj", + "macos/Test.xcworkspace", + "windows/Test.sln", + "windows/Test.vcxproj", + "windows/Test/Test.vcxproj" + ], + "scripts": { + "start": "react-native start", + "android": "react-native run-android", + "build:android": "react-native bundle --entry-file index.js --platform android --dev true --bundle-output dist/main.android.jsbundle --assets-dest dist/res", + "build:ios": "react-native bundle --entry-file index.js --platform ios --dev true --bundle-output dist/main.ios.jsbundle --assets-dest dist", + "ios": "react-native run-ios", + "build:macos": "react-native bundle --entry-file index.js --platform macos --dev true --bundle-output dist/main.macos.jsbundle --assets-dest dist", + "macos": "react-native run-macos --scheme Test", + "build:windows": "react-native bundle --entry-file index.js --platform windows --dev true --bundle-output dist/main.windows.bundle --assets-dest dist", + "windows": "react-native run-windows" + }, + "dependencies": { + "react-native-macos": "^0.76.0", + "react-native-windows": "^0.76.0" + } +} +`; + +exports[`gatherConfig() > returns configuration for arbitrary platforms 1`] = ` +{ + "files": { + ".gitignore": { + "source": "example/.gitignore" + }, + ".watchmanconfig": { + "source": "node_modules/@react-native-community/template/template/_watchmanconfig" + }, + "babel.config.js": { + "source": "node_modules/@react-native-community/template/template/babel.config.js" + }, + "metro.config.js": { + "source": "example/metro.config.js" + }, + "react-native.config.js": "const project = (() => {\\n try {\\n const { configureProjects } = require(\\"react-native-test-app\\");\\n return configureProjects({\\n android: {\\n sourceDir: \\"android\\",\\n },\\n ios: {\\n sourceDir: \\"ios\\",\\n },\\n windows: {\\n sourceDir: \\"windows\\",\\n solutionFile: \\"windows/Test.sln\\",\\n },\\n });\\n } catch (_) {\\n return undefined;\\n }\\n})();\\n\\nmodule.exports = {\\n ...(project ? { project } : undefined),\\n};\\n", + "android/build.gradle": "buildscript {\\n apply(from: {\\n def searchDir = rootDir.toPath()\\n do {\\n def p = searchDir.resolve(\\"node_modules/react-native-test-app/android/dependencies.gradle\\")\\n if (p.toFile().exists()) {\\n return p.toRealPath().toString()\\n }\\n } while (searchDir = searchDir.getParent())\\n throw new GradleException(\\"Could not find \`react-native-test-app\`\\");\\n }())\\n\\n repositories {\\n mavenCentral()\\n google()\\n }\\n\\n dependencies {\\n getReactNativeDependencies().each { dependency ->\\n classpath(dependency)\\n }\\n }\\n}\\n", + "android/gradle/wrapper/gradle-wrapper.jar": { + "source": "example/android/gradle/wrapper/gradle-wrapper.jar" + }, + "android/gradle/wrapper/gradle-wrapper.properties": { + "source": "example/android/gradle/wrapper/gradle-wrapper.properties" + }, + "android/gradle.properties": "# Project-wide Gradle settings.\\n\\n# IDE (e.g. Android Studio) users:\\n# Gradle settings configured through the IDE *will override*\\n# any settings specified in this file.\\n\\n# For more details on how to configure your build environment visit\\n# http://www.gradle.org/docs/current/userguide/build_environment.html\\n\\n# Specifies the JVM arguments used for the Gradle Daemon. The setting is\\n# particularly useful for configuring JVM memory settings for build performance.\\n# This does not affect the JVM settings for the Gradle client VM.\\n# The default is \`-Xmx512m -XX:MaxMetaspaceSize=256m\`.\\norg.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\\n\\n# When configured, Gradle will fork up to org.gradle.workers.max JVMs to execute\\n# projects in parallel. To learn more about parallel task execution, see the\\n# section on Gradle build performance:\\n# https://docs.gradle.org/current/userguide/performance.html#parallel_execution.\\n# Default is \`false\`.\\n#org.gradle.parallel=true\\n\\n# AndroidX package structure to make it clearer which packages are bundled with the\\n# Android operating system, and which are packaged with your app's APK\\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\\nandroid.useAndroidX=true\\n# Automatically convert third-party libraries to use AndroidX\\n#android.enableJetifier=true\\n# Jetifier randomly fails on these libraries\\n#android.jetifier.ignorelist=hermes-android,react-android\\n\\n# Use this property to specify which architecture you want to build.\\n# You can also override it from the CLI using\\n# ./gradlew -PreactNativeArchitectures=x86_64\\nreactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64\\n\\n# Use this property to enable support to the new architecture.\\n# This will allow you to use TurboModules and the Fabric render in\\n# your application. You should enable this flag either if you want\\n# to write custom TurboModules/Fabric components OR use libraries that\\n# are providing them.\\n# Note that this is incompatible with web debugging.\\nnewArchEnabled=true\\n#bridgelessEnabled=true\\n\\n# Uncomment the line below to build React Native from source.\\n#react.buildFromSource=true\\n\\n# Version of Android NDK to build against.\\n#ANDROID_NDK_VERSION=26.1.10909125\\n\\n# Version of Kotlin to build against.\\n#KOTLIN_VERSION=1.8.22\\n", + "android/gradlew": { + "source": "example/android/gradlew" + }, + "android/gradlew.bat": { + "source": "example/android/gradlew.bat" + }, + "android/settings.gradle": "pluginManagement {\\n repositories {\\n gradlePluginPortal()\\n mavenCentral()\\n google()\\n }\\n}\\n\\nrootProject.name = \\"Test\\"\\n\\napply(from: {\\n def searchDir = rootDir.toPath()\\n do {\\n def p = searchDir.resolve(\\"node_modules/react-native-test-app/test-app.gradle\\")\\n if (p.toFile().exists()) {\\n return p.toRealPath().toString()\\n }\\n } while (searchDir = searchDir.getParent())\\n throw new GradleException(\\"Could not find \`react-native-test-app\`\\");\\n}())\\napplyTestAppSettings(settings)\\n", + "ios/Podfile": "ws_dir = Pathname.new(__dir__)\\nws_dir = ws_dir.parent until\\n File.exist?(\\"#{ws_dir}/node_modules/react-native-test-app/test_app.rb\\") ||\\n ws_dir.expand_path.to_s == '/'\\nrequire \\"#{ws_dir}/node_modules/react-native-test-app/test_app.rb\\"\\n\\nworkspace 'Test.xcworkspace'\\n\\nuse_test_app! :hermes_enabled => true, :fabric_enabled => true\\n" + }, + "oldFiles": [ + "ios/Podfile.lock", + "ios/Pods", + "ios/Test.xcodeproj", + "ios/Test.xcworkspace" + ], + "scripts": { + "start": "react-native start", + "android": "react-native run-android", + "build:android": "react-native bundle --entry-file index.js --platform android --dev true --bundle-output dist/main.android.jsbundle --assets-dest dist/res", + "build:ios": "react-native bundle --entry-file index.js --platform ios --dev true --bundle-output dist/main.ios.jsbundle --assets-dest dist", + "ios": "react-native run-ios" + }, + "dependencies": {} +} +`; diff --git a/packages/app/test/configure/join.test.mts b/packages/app/test/configure/join.test.mts deleted file mode 100644 index abb65a295..000000000 --- a/packages/app/test/configure/join.test.mts +++ /dev/null @@ -1,12 +0,0 @@ -import { equal } from "node:assert/strict"; -import { describe, it } from "node:test"; -import { join } from "../../scripts/template.mjs"; - -describe("join()", () => { - it("joins lines", () => { - equal(join(""), ""); - equal(join("a", "b"), "a\nb"); - equal(join("a", "", "b"), "a\n\nb"); - equal(join("a", "", "b", ""), "a\n\nb\n"); - }); -}); diff --git a/packages/app/test/pack.test.mts b/packages/app/test/pack.test.mts index c015eb579..77ff7b5d9 100644 --- a/packages/app/test/pack.test.mts +++ b/packages/app/test/pack.test.mts @@ -173,6 +173,7 @@ describe("npm pack", () => { "macos/ReactTestAppTests/ReactTestAppTests.swift", "macos/ReactTestAppUITests/Info.plist", "macos/ReactTestAppUITests/ReactTestAppUITests.swift", + "macos/template.config.mjs", "macos/test_app.rb", "package.json", "plugins/index.js", @@ -230,6 +231,7 @@ describe("npm pack", () => { "visionos/ReactTestAppTests/ReactTestAppTests.swift", "visionos/ReactTestAppUITests/Info.plist", "visionos/ReactTestAppUITests/ReactTestAppUITests.swift", + "visionos/template.config.mjs", "visionos/test_app.rb", "windows/ExperimentalFeatures.props", "windows/Shared/EmbedManifest.targets", diff --git a/packages/app/visionos/template.config.mjs b/packages/app/visionos/template.config.mjs new file mode 100644 index 000000000..cb30ce7d8 --- /dev/null +++ b/packages/app/visionos/template.config.mjs @@ -0,0 +1,40 @@ +// @ts-check +import * as nodefs from "node:fs"; +import { podfile } from "../ios/template.config.mjs"; +import { toVersionNumber } from "../scripts/helpers.js"; + +/** @import { Configuration, ConfigureParams } from "../scripts/types.js"; */ + +/** + * @param {string} _projectRoot + * @param {unknown} _config + * @returns {undefined} + */ +export function configure(_projectRoot, _config, _fs = nodefs) { + return undefined; +} + +/** + * @param {ConfigureParams} params + * @returns {Configuration} + */ +export function getTemplate({ name, targetVersion }) { + const targetVersionNum = toVersionNumber(targetVersion); + return { + files: { + Podfile: podfile(name, "visionos/", targetVersionNum), + }, + oldFiles: [ + "Podfile.lock", + "Pods", + `${name}.xcodeproj`, + `${name}.xcworkspace`, + ], + scripts: { + "build:visionos": + "react-native bundle --entry-file index.js --platform ios --dev true --bundle-output dist/main.visionos.jsbundle --assets-dest dist", + visionos: "react-native run-visionos", + }, + dependencies: {}, + }; +} diff --git a/packages/app/windows/template.config.mjs b/packages/app/windows/template.config.mjs index 1591ca96c..72013d0f7 100644 --- a/packages/app/windows/template.config.mjs +++ b/packages/app/windows/template.config.mjs @@ -2,8 +2,16 @@ import * as nodefs from "node:fs"; import * as path from "node:path"; import { readTextFile } from "../scripts/helpers.js"; +import { findGitIgnore } from "../scripts/template.mjs"; -/** @import { ProjectConfig, ProjectParams } from "../scripts/types.js"; */ +/** + * @import { + * Configuration, + * ConfigureParams, + * ProjectConfig, + * ProjectParams, + * } from "../scripts/types.js"; + */ /** * @param {string} solutionFile @@ -35,3 +43,27 @@ export function configure( } : undefined; } + +/** + * @param {ConfigureParams} params + * @returns {Configuration} + */ +export function getTemplate({ name, testAppPath }, fs = nodefs) { + const windowsDir = path.join(testAppPath, "example", "windows"); + return { + files: { + ".gitignore": findGitIgnore(windowsDir, fs), + }, + oldFiles: [ + `${name}.sln`, + `${name}.vcxproj`, + path.join(name, `${name}.vcxproj`), + ], + scripts: { + "build:windows": + "react-native bundle --entry-file index.js --platform windows --dev true --bundle-output dist/main.windows.bundle --assets-dest dist", + windows: "react-native run-windows", + }, + dependencies: {}, + }; +}