diff --git a/packages/react-native/scripts/swiftpm/create-symlinks.js b/packages/react-native/scripts/swiftpm/create-links.js similarity index 53% rename from packages/react-native/scripts/swiftpm/create-symlinks.js rename to packages/react-native/scripts/swiftpm/create-links.js index 4b2db4ea539..830f2ac7cf9 100644 --- a/packages/react-native/scripts/swiftpm/create-symlinks.js +++ b/packages/react-native/scripts/swiftpm/create-links.js @@ -54,8 +54,24 @@ function buildHeaderMap(directory) { * @param {string} reactNativePath - Path to the React Native package directory * @returns {Promise<{found: number, notFound: number, errors: number}>} Statistics about the operation */ -async function createSymlinks(reactNativePath) { - console.log(`Creating symlinks for React Native at: ${reactNativePath}`); +async function createLinks(reactNativePath) { + const reactStats = createReactLinks(reactNativePath); + const rctDeprecationStats = createRCTDeprecationLinks(reactNativePath); + const yogaStats = createYogaLinks(reactNativePath); + + // Combine all statistics + const combinedStats = { + found: reactStats.found + rctDeprecationStats.found + yogaStats.found, + notFound: + reactStats.notFound + rctDeprecationStats.notFound + yogaStats.notFound, + errors: reactStats.errors + rctDeprecationStats.errors + yogaStats.errors, + }; + + return combinedStats; +} + +function createReactLinks(reactNativePath) { + console.log(`Creating links for React Native at: ${reactNativePath}`); // Define paths based on the provided reactNativePath const REACT_DIR = path.join(reactNativePath, 'React'); @@ -120,13 +136,10 @@ async function createSymlinks(reactNativePath) { fs.unlinkSync(destPath); } - // Create relative symlink - const relativeSourcePath = path.relative(DESTINATION_DIR, sourcePath); - fs.symlinkSync(relativeSourcePath, destPath); + // Create hard link using absolute source path + console.log(sourcePath, '->', destPath); + fs.linkSync(sourcePath, destPath); - console.log( - `Created symlink: ${targetFilename} -> ${relativeSourcePath}`, - ); found++; } else { console.warn( @@ -172,6 +185,129 @@ async function createSymlinks(reactNativePath) { return {found, notFound, errors}; } +function createRCTDeprecationLinks(reactNativePath) { + console.log('Creating RCTDeprecation links...'); + + // Define paths + const SOURCE_DIR = path.join( + reactNativePath, + 'ReactApple/Libraries/RCTFoundation/RCTDeprecation/Exported', + ); + const DESTINATION_DIR = path.join( + reactNativePath, + 'React/includes/RCTDeprecation', + ); + + // Validate that the source directory exists + if (!fs.existsSync(SOURCE_DIR)) { + console.warn(`RCTDeprecation source directory not found: ${SOURCE_DIR}`); + return {found: 0, notFound: 0, errors: 0}; + } + + // Ensure destination directory exists + if (!fs.existsSync(DESTINATION_DIR)) { + console.log(`Creating directory: ${DESTINATION_DIR}`); + fs.mkdirSync(DESTINATION_DIR, {recursive: true}); + } + + // Read all header files from source directory + const entries = fs.readdirSync(SOURCE_DIR, {withFileTypes: true}); + const headerFiles = entries.filter( + entry => entry.isFile() && entry.name.endsWith('.h'), + ); + + console.log(`Found ${headerFiles.length} RCTDeprecation header files`); + + let found = 0; + let errors = 0; + + // Process each header file + headerFiles.forEach(entry => { + try { + const sourcePath = path.join(SOURCE_DIR, entry.name); + const destPath = path.join(DESTINATION_DIR, entry.name); + + // Remove existing symlink/file if it exists + if (fs.existsSync(destPath)) { + fs.unlinkSync(destPath); + } + + // Create hard link using absolute source path + fs.linkSync(sourcePath, destPath); + + found++; + } catch (error) { + console.error( + `Error processing RCTDeprecation ${entry.name}: ${error.message}`, + ); + errors++; + } + }); + + console.log(`RCTDeprecation links: ${found} created, ${errors} errors`); + return {found, notFound: 0, errors}; +} + +function createYogaLinks(reactNativePath) { + console.log('Creating Yoga links...'); + + // Define paths + const SOURCE_DIR = path.join(reactNativePath, 'ReactCommon/yoga/yoga'); + const DESTINATION_DIR = path.join(reactNativePath, 'React/includes/yoga'); + + // Validate that the source directory exists + if (!fs.existsSync(SOURCE_DIR)) { + console.warn(`Yoga source directory not found: ${SOURCE_DIR}`); + return {found: 0, notFound: 0, errors: 0}; + } + + // Ensure destination directory exists + if (!fs.existsSync(DESTINATION_DIR)) { + console.log(`Creating directory: ${DESTINATION_DIR}`); + fs.mkdirSync(DESTINATION_DIR, {recursive: true}); + } + + // Build header map from source directory (only direct files, no nested folders) + const headerMap = new Map(); + const entries = fs.readdirSync(SOURCE_DIR, {withFileTypes: true}); + + for (const entry of entries) { + if (entry.isFile() && entry.name.endsWith('.h')) { + const fullPath = path.join(SOURCE_DIR, entry.name); + headerMap.set(entry.name, fullPath); + } + // Ignore directories (nested folders) as per the requirement + } + + console.log(`Found ${headerMap.size} Yoga header files`); + + let found = 0; + let errors = 0; + + // Process each header file + headerMap.forEach((sourcePath, filename) => { + try { + const destPath = path.join(DESTINATION_DIR, filename); + + // Remove existing symlink/file if it exists + if (fs.existsSync(destPath)) { + fs.unlinkSync(destPath); + } + + // Create hard link using absolute source path + fs.linkSync(sourcePath, destPath); + + found++; + } catch (error) { + console.error(`Error processing Yoga ${filename}: ${error.message}`); + errors++; + } + }); + + console.log(`Yoga links: ${found} created, ${errors} errors`); + return {found, notFound: 0, errors}; +} + // CLI usage if (require.main === module) { const args = process.argv.slice(2); @@ -185,21 +321,21 @@ if (require.main === module) { reactNativePath = path.resolve(__dirname, '..'); } - console.log('Usage: node create-symlinks.js [reactNativePath]'); + console.log('Usage: node create-links.js [reactNativePath]'); console.log(`Using React Native path: ${reactNativePath}`); - createSymlinks(reactNativePath) - .then((stats) => { - console.log('\n✅ Symlink creation completed successfully!'); + createLinks(reactNativePath) + .then(() => { + console.log('\n✅ Link creation completed successfully!'); process.exit(0); }) - .catch((error) => { - console.error('\n❌ Symlink creation failed:', error.message); + .catch(error => { + console.error('\n❌ Link creation failed:', error.message); process.exit(1); }); } module.exports = { - createSymlinks, - buildHeaderMap + createLinks, + buildHeaderMap, }; diff --git a/packages/react-native/scripts/swiftpm/prepare-app.js b/packages/react-native/scripts/swiftpm/prepare-app.js index 5ec33bc4db1..3b833e9c80c 100644 --- a/packages/react-native/scripts/swiftpm/prepare-app.js +++ b/packages/react-native/scripts/swiftpm/prepare-app.js @@ -21,7 +21,7 @@ const {execSync} = require('child_process'); // Import functions from other scripts const {prepareAppDependenciesHeaders} = require('./prepare-app-dependencies-headers'); -const {createSymlinks: createSymlinksFunction} = require('./create-symlinks'); +const {createLinks: createLinksFunction} = require('./create-links'); const {integrateSwiftPackagesInXcode} = require('./update-xcodeproject'); const codegenExecutor = require('../codegen/generate-artifacts-executor'); @@ -66,9 +66,9 @@ async function prepareApp(appPath = '../../private/helloworld', reactNativePath console.log('\n⚙️ Step 3: Setting BUILD_FROM_SOURCE to true...'); await setBuildFromSource(absoluteReactNativePath); - // Step 4: Create symlinks - console.log('\n🔗 Step 4: Creating symlinks...'); - await createSymlinks(absoluteReactNativePath); + // Step 4: Create links for react-native + console.log('\n🔗 Step 4: Creating links for react-native...'); + await createLinks(absoluteReactNativePath); // Step 5: Generate codegen artifacts console.log('\n🧬 Step 5: Generating codegen artifacts...'); @@ -171,15 +171,15 @@ async function setBuildFromSource(reactNativePath) { } /** - * Create symlinks using the imported function + * Create links using the imported function */ -async function createSymlinks(reactNativePath) { +async function createLinks(reactNativePath) { try { - console.log('Creating symlinks...'); - const stats = await createSymlinksFunction(reactNativePath); - console.log(`✓ Symlinks created: ${stats.found} found, ${stats.notFound} not found, ${stats.errors} errors`); + console.log('Creating links...'); + const stats = await createLinksFunction(reactNativePath); + console.log(`✓ Links created: ${stats.found} found, ${stats.notFound} not found, ${stats.errors} errors`); } catch (error) { - throw new Error(`Symlink creation failed: ${error.message}`); + throw new Error(`Link creation failed: ${error.message}`); } } @@ -376,7 +376,6 @@ module.exports = { runPodDeintegrate, runIosPrebuild, setBuildFromSource, - createSymlinks, generateCodegenArtifacts, prepareHeaders, fixReactNativePath,