From 305a0548652a405d9f638fb2c054781951dfc996 Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Wed, 4 May 2022 04:04:10 -0700 Subject: [PATCH] Refactor generate-artifacts to improve testability. Summary: This Diff splits the `generate-artifacts.js` script into: * `generate-artifacts-executor.js`: which contains the logic to generate the code for iOS. * `generate-artifacts.js`: which contains the argument parsing logic and invokes the executor. Finally, it introduces some tests. ## Changelog [iOS][Changed] - Refactor part of the codegen scripts and add tests. Reviewed By: cortinico, dmitryrykun Differential Revision: D35846674 fbshipit-source-id: 14873c3fe762606e9004a29e4a6b986bf6a8f055 --- .../generate-artifacts-executor-test.js | 99 +++++ .../codegen/generate-artifacts-executor.js | 415 ++++++++++++++++++ scripts/generate-artifacts.js | 294 +------------ 3 files changed, 525 insertions(+), 283 deletions(-) create mode 100644 scripts/codegen/__tests__/generate-artifacts-executor-test.js create mode 100644 scripts/codegen/generate-artifacts-executor.js diff --git a/scripts/codegen/__tests__/generate-artifacts-executor-test.js b/scripts/codegen/__tests__/generate-artifacts-executor-test.js new file mode 100644 index 00000000000000..6b7addd60288dd --- /dev/null +++ b/scripts/codegen/__tests__/generate-artifacts-executor-test.js @@ -0,0 +1,99 @@ +/** + * 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. + * + * @emails oncall+react_native + * @format + */ + +'use strict'; + +const underTest = require('../generate-artifacts-executor'); +const path = require('path'); + +describe('generateCode', () => { + it('executeNodes with the right arguents', () => { + // Define variables and expected values + const iosOutputDir = 'app/ios/build/generated/ios'; + const library = {config: {name: 'library', type: 'all'}}; + const tmpDir = 'tmp'; + const node = 'usr/bin/node'; + const pathToSchema = 'app/build/schema.json'; + const rnRoot = path.join(__dirname, '../..'); + const libraryType = 'all'; + + const tmpComponentOutDirs = path.join(tmpDir, 'out', 'components'); + const tmpNativeModulesOutDir = path.join(tmpDir, 'out', 'nativeModules'); + const iOSComponentOutDirs = path.join( + iosOutputDir, + 'react/renderer/components', + library.config.name, + ); + const iOSNativeModulesOutDir = path.join( + iosOutputDir, + './', + library.config.name, + ); + + // mock used functions + let mkdirSyncInvocationCount = 0; + jest.mock('fs', () => ({ + readdirSync: dirpath => { + return ['test/dir']; //we only require to return something, so that the folder is not empty. + }, + mkdirSync: (location, config) => { + if (mkdirSyncInvocationCount === 0) { + expect(location).toEqual(tmpComponentOutDirs); + } + if (mkdirSyncInvocationCount === 1) { + expect(location).toEqual(tmpNativeModulesOutDir); + } + if (mkdirSyncInvocationCount === 2) { + expect(location).toEqual(iOSComponentOutDirs); + } + if (mkdirSyncInvocationCount === 3) { + expect(location).toEqual(iOSNativeModulesOutDir); + } + mkdirSyncInvocationCount += 1; + }, + })); + + let execSyncInvocationCount = 0; + jest.mock('child_process', () => ({ + execSync: command => { + if (execSyncInvocationCount === 0) { + const expectedCommand = `${node} ${path.join( + rnRoot, + 'generate-specs-cli.js', + )} \ + --platform ios \ + --schemaPath ${pathToSchema} \ + --outputDir ${tmpNativeModulesOutDir} \ + --componentsOutputDir ${tmpComponentOutDirs} \ + --modulesOutputDirs ${tmpNativeModulesOutDir} \ + --libraryName ${library.config.name} \ + --libraryType ${libraryType}`; + expect(command).toEqual(expectedCommand); + } + + if (execSyncInvocationCount === 1) { + expect(command).toEqual( + `cp -R ${tmpComponentOutDirs}/* ${iOSComponentOutDirs}`, + ); + } + if (execSyncInvocationCount === 2) { + expect(command).toEqual( + `cp -R ${tmpNativeModulesOutDir}/* ${iOSNativeModulesOutDir}`, + ); + } + + execSyncInvocationCount += 1; + }, + })); + + underTest._generateCode(iosOutputDir, library, tmpDir, node, pathToSchema); + expect(mkdirSyncInvocationCount).toBe(4); + }); +}); diff --git a/scripts/codegen/generate-artifacts-executor.js b/scripts/codegen/generate-artifacts-executor.js new file mode 100644 index 00000000000000..281ed411f3844b --- /dev/null +++ b/scripts/codegen/generate-artifacts-executor.js @@ -0,0 +1,415 @@ +/** + * 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. + * + * @format + */ + +'use strict'; + +/** + * This script crawls through a React Native application's dependencies and invokes the codegen + * for any libraries that require it. + * To enable codegen support, the library should include a config in the codegenConfigKey key + * in a codegenConfigFilename file. + */ + +const {execSync} = require('child_process'); +const fs = require('fs'); +const os = require('os'); +const path = require('path'); + +const RN_ROOT = path.join(__dirname, '../..'); + +const CODEGEN_REPO_PATH = `${RN_ROOT}/packages/react-native-codegen`; +const CODEGEN_NPM_PATH = `${RN_ROOT}/../react-native-codegen`; +const CORE_LIBRARIES = new Set(['rncore', 'FBReactNativeSpec']); +const REACT_NATIVE_DEPENDENCY_NAME = 'react-native'; + +// HELPERS + +function isReactNativeCoreLibrary(libraryName) { + return CORE_LIBRARIES.has(libraryName); +} + +function executeNodeScript(node, script) { + execSync(`${node} ${script}`); +} + +function isDirEmpty(dirPath) { + return fs.readdirSync(dirPath).length === 0; +} + +function isAppRootValid(appRootDir) { + if (appRootDir == null) { + console.error('Missing path to React Native application'); + process.exitCode = 1; + return false; + } + return true; +} + +function readPackageJSON(appRootDir) { + return JSON.parse(fs.readFileSync(path.join(appRootDir, 'package.json'))); +} + +// Reading Libraries + +function handleReactNativeCodeLibraries( + libraries, + codegenConfigFilename, + codegenConfigKey, +) { + // Handle react-native core libraries. + // This is required when react-native is outside of node_modules. + console.log('[Codegen] Processing react-native core libraries'); + const reactNativePkgJson = path.join(RN_ROOT, codegenConfigFilename); + if (!fs.existsSync(reactNativePkgJson)) { + throw '[Codegen] Error: Could not find config file for react-native.'; + } + const reactNativeConfigFile = JSON.parse(fs.readFileSync(reactNativePkgJson)); + if ( + reactNativeConfigFile[codegenConfigKey] == null || + reactNativeConfigFile[codegenConfigKey].libraries == null + ) { + throw '[Codegen] Error: Could not find codegen config for react-native.'; + } + console.log('[Codegen] Found react-native'); + reactNativeConfigFile[codegenConfigKey].libraries.forEach(config => { + const libraryConfig = { + library: REACT_NATIVE_DEPENDENCY_NAME, + config, + libraryPath: RN_ROOT, + }; + libraries.push(libraryConfig); + }); +} + +function handleThirdPartyLibraries( + libraries, + baseCodegenConfigFileDir, + dependencies, + codegenConfigFilename, + codegenConfigKey, +) { + // Determine which of these are codegen-enabled libraries + const configDir = baseCodegenConfigFileDir || path.join(RN_ROOT, '..'); + console.log( + `\n\n[Codegen] >>>>> Searching for codegen-enabled libraries in ${configDir}`, + ); + + // Handle third-party libraries + Object.keys(dependencies).forEach(dependency => { + if (dependency === REACT_NATIVE_DEPENDENCY_NAME) { + // react-native should already be added. + return; + } + const codegenConfigFileDir = path.join(configDir, dependency); + const configFilePath = path.join( + codegenConfigFileDir, + codegenConfigFilename, + ); + if (fs.existsSync(configFilePath)) { + const configFile = JSON.parse(fs.readFileSync(configFilePath)); + if ( + configFile[codegenConfigKey] != null && + configFile[codegenConfigKey].libraries != null + ) { + console.log(`[Codegen] Found ${dependency}`); + configFile[codegenConfigKey].libraries.forEach(config => { + const libraryConfig = { + library: dependency, + config, + libraryPath: codegenConfigFileDir, + }; + libraries.push(libraryConfig); + }); + } + } + }); +} + +function handleInAppLibraries( + libraries, + pkgJson, + codegenConfigKey, + appRootDir, +) { + console.log( + '\n\n[Codegen] >>>>> Searching for codegen-enabled libraries in the app', + ); + + // Handle in-app libraries + if ( + pkgJson[codegenConfigKey] != null && + pkgJson[codegenConfigKey].libraries != null + ) { + console.log(`[Codegen] Found ${pkgJson.name}`); + pkgJson[codegenConfigKey].libraries.forEach(config => { + const libraryConfig = { + library: pkgJson.name, + config, + libraryPath: appRootDir, + }; + libraries.push(libraryConfig); + }); + } +} + +// CodeGen + +function getCodeGenCliPath() { + let codegenCliPath; + if (fs.existsSync(CODEGEN_REPO_PATH)) { + codegenCliPath = CODEGEN_REPO_PATH; + + if (!fs.existsSync(path.join(CODEGEN_REPO_PATH, 'lib'))) { + console.log('\n\n[Codegen] >>>>> Building react-native-codegen package'); + execSync('yarn install', { + cwd: codegenCliPath, + stdio: 'inherit', + }); + execSync('yarn build', { + cwd: codegenCliPath, + stdio: 'inherit', + }); + } + } else if (fs.existsSync(CODEGEN_NPM_PATH)) { + codegenCliPath = CODEGEN_NPM_PATH; + } else { + throw "error: Could not determine react-native-codegen location. Try running 'yarn install' or 'npm install' in your project root."; + } + return codegenCliPath; +} + +function computeIOSOutputDir(outputPath, appRootDir) { + return path.join(outputPath ? outputPath : appRootDir, 'build/generated/ios'); +} + +function generateSchema(tmpDir, library, node, codegenCliPath) { + const pathToSchema = path.join(tmpDir, 'schema.json'); + const pathToJavaScriptSources = path.join( + library.libraryPath, + library.config.jsSrcsDir, + ); + + console.log(`\n\n[Codegen] >>>>> Processing ${library.config.name}`); + // Generate one schema for the entire library... + executeNodeScript( + node, + `${path.join( + codegenCliPath, + 'lib', + 'cli', + 'combine', + 'combine-js-to-schema-cli.js', + )} ${pathToSchema} ${pathToJavaScriptSources}`, + ); + console.log(`[Codegen] Generated schema: ${pathToSchema}`); + return pathToSchema; +} + +function generateCode(iosOutputDir, library, tmpDir, node, pathToSchema) { + function composePath(intermediate) { + return path.join(iosOutputDir, intermediate, library.config.name); + } + + const outputDirsIOS = { + components: composePath('react/renderer/components'), + nativeModules: composePath('./'), + }; + + const tempOutputDirs = { + components: path.join(tmpDir, 'out', 'components'), + nativeModules: path.join(tmpDir, 'out', 'nativeModules'), + }; + + // ...then generate native code artifacts. + const libraryTypeArg = library.config.type + ? `--libraryType ${library.config.type}` + : ''; + + Object.entries(tempOutputDirs).forEach(([type, dirPath]) => { + fs.mkdirSync(dirPath, {recursive: true}); + }); + + const deprecated_outputDir = + library.config.type === 'components' + ? tempOutputDirs.components + : tempOutputDirs.nativeModules; + + executeNodeScript( + node, + `${path.join(RN_ROOT, 'scripts', 'generate-specs-cli.js')} \ + --platform ios \ + --schemaPath ${pathToSchema} \ + --outputDir ${deprecated_outputDir} \ + --componentsOutputDir ${tempOutputDirs.components} \ + --modulesOutputDirs ${tempOutputDirs.nativeModules} \ + --libraryName ${library.config.name} \ + ${libraryTypeArg}`, + ); + + // Finally, copy artifacts to the final output directory. + Object.entries(outputDirsIOS).forEach(([type, dirPath]) => { + const outDir = tempOutputDirs[type]; + if (isDirEmpty(outDir)) { + return; // cp fails if we try to copy something empty. + } + + fs.mkdirSync(dirPath, {recursive: true}); + execSync(`cp -R ${outDir}/* ${dirPath}`); + console.log(`[Codegen] Generated artifacts: ${dirPath}`); + }); +} + +function generateNativeCodegenFiles( + libraries, + fabricEnabled, + iosOutputDir, + node, + codegenCliPath, + schemaPaths, +) { + let fabricEnabledTypes = ['components', 'all']; + libraries.forEach(library => { + if ( + !fabricEnabled && + fabricEnabledTypes.indexOf(library.config.type) >= 0 + ) { + console.log( + `[Codegen] ${library.config.name} skipped because fabric is not enabled.`, + ); + return; + } + const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), library.config.name)); + const pathToSchema = generateSchema(tmpDir, library, node, codegenCliPath); + generateCode(iosOutputDir, library, tmpDir, node, pathToSchema); + + // Filter the react native core library out. + // In the future, core library and third party library should + // use the same way to generate/register the fabric components. + if (!isReactNativeCoreLibrary(library.config.name)) { + schemaPaths[library.config.name] = pathToSchema; + } + }); +} + +function createComponentProvider( + fabricEnabled, + schemaPaths, + node, + iosOutputDir, +) { + if (fabricEnabled) { + console.log('\n\n>>>>> Creating component provider'); + // Save the list of spec paths to a temp file. + const schemaListTmpPath = `${os.tmpdir()}/rn-tmp-schema-list.json`; + const fd = fs.openSync(schemaListTmpPath, 'w'); + fs.writeSync(fd, JSON.stringify(schemaPaths)); + fs.closeSync(fd); + console.log(`Generated schema list: ${schemaListTmpPath}`); + + // Generate FabricComponentProvider. + // Only for iOS at this moment. + executeNodeScript( + node, + `${path.join( + RN_ROOT, + 'scripts', + 'generate-provider-cli.js', + )} --platform ios --schemaListPath "${schemaListTmpPath}" --outputDir ${iosOutputDir}`, + ); + console.log(`Generated provider in: ${iosOutputDir}`); + } +} + +// Execute + +/** + * This function is the entry point for the codegen. It: + * - reads the package json + * - extracts the libraries + * - setups the CLI to generate the code + * - generate the code + * + * @parameter appRootDir: the directory with the app source code, where the `codegenConfigFilename` lives. + * @parameter outputPath: the base output path for the CodeGen. + * @parameter node: the path to the node executable, used to run the codegen scripts. + * @parameter codegenConfigFilename: the file that contains the codeGen configuration. The default is `package.json`. + * @parameter codegenConfigKey: the key in the codegenConfigFile that controls the codegen. + * @parameter baseCodegenConfigFileDir: the directory of the codeGenConfigFile. + * @parameter fabricEnabled: whether fabric is enabled or not. + * @throws If it can't find a config file for react-native. + * @throws If it can't find a CodeGen configuration in the file. + * @throws If it can't find a cli for the CodeGen. + */ +function execute( + appRootDir, + outputPath, + node, + codegenConfigFilename, + codegenConfigKey, + baseCodegenConfigFileDir, + fabricEnabled, +) { + if (!isAppRootValid(appRootDir)) { + return; + } + + try { + const pkgJson = readPackageJSON(appRootDir); + const dependencies = {...pkgJson.dependencies, ...pkgJson.devDependencies}; + const libraries = []; + + handleReactNativeCodeLibraries( + libraries, + codegenConfigFilename, + codegenConfigKey, + ); + handleThirdPartyLibraries( + libraries, + baseCodegenConfigFileDir, + dependencies, + codegenConfigFilename, + codegenConfigKey, + ); + handleInAppLibraries(libraries, pkgJson, codegenConfigKey, appRootDir); + + if (libraries.length === 0) { + console.log('[Codegen] No codegen-enabled libraries found.'); + return; + } + + const codegenCliPath = getCodeGenCliPath(); + + const schemaPaths = {}; + + const iosOutputDir = computeIOSOutputDir(outputPath, appRootDir); + + generateNativeCodegenFiles( + libraries, + fabricEnabled, + iosOutputDir, + node, + codegenCliPath, + schemaPaths, + ); + + createComponentProvider(fabricEnabled, schemaPaths, node, iosOutputDir); + } catch (err) { + console.error(err); + process.exitCode = 1; + } + + console.log('\n\n[Codegen] Done.'); + return; +} + +module.exports = { + execute: execute, + _executeNodeScript: executeNodeScript, // exported for testing purposes only + _generateCode: generateCode, // exported for testing purposes only +}; diff --git a/scripts/generate-artifacts.js b/scripts/generate-artifacts.js index 2feb2d9e2bcf40..bde850b940de2c 100644 --- a/scripts/generate-artifacts.js +++ b/scripts/generate-artifacts.js @@ -9,17 +9,7 @@ 'use strict'; -/** - * This script crawls through a React Native application's dependencies and invokes the codegen - * for any libraries that require it. - * To enable codegen support, the library should include a config in the CODEGEN_CONFIG_KEY key - * in a CODEGEN_CONFIG_FILENAME file. - */ - -const {execSync} = require('child_process'); -const fs = require('fs'); -const os = require('os'); -const path = require('path'); +const executor = require('./codegen/generate-artifacts-executor.js'); const yargs = require('yargs'); const argv = yargs @@ -62,283 +52,21 @@ const argv = yargs .usage('Usage: $0 -p [path to app]') .demandOption(['p']).argv; -const RN_ROOT = path.join(__dirname, '..'); const CODEGEN_CONFIG_FILENAME = argv.f; const CODEGEN_CONFIG_FILE_DIR = argv.c; const CODEGEN_CONFIG_KEY = argv.k; const CODEGEN_FABRIC_ENABLED = argv.e; const NODE = argv.n; -const CODEGEN_REPO_PATH = `${RN_ROOT}/packages/react-native-codegen`; -const CODEGEN_NPM_PATH = `${RN_ROOT}/../react-native-codegen`; -const CORE_LIBRARIES = new Set(['rncore', 'FBReactNativeSpec']); -const REACT_NATIVE_DEPENDENCY_NAME = 'react-native'; - -function isReactNativeCoreLibrary(libraryName) { - return CORE_LIBRARIES.has(libraryName); -} - -function executeNodeScript(script) { - execSync(`${NODE} ${script}`); -} - -function isDirEmpty(dirPath) { - return fs.readdirSync(dirPath).length === 0; -} - -function main(appRootDir, outputPath) { - if (appRootDir == null) { - console.error('Missing path to React Native application'); - process.exitCode = 1; - return; - } - - try { - // Get app package.json - const pkgJson = JSON.parse( - fs.readFileSync(path.join(appRootDir, 'package.json')), - ); - - // Get dependencies for the app - const dependencies = {...pkgJson.dependencies, ...pkgJson.devDependencies}; - - const libraries = []; - - // Handle react-native core libraries. - // This is required when react-native is outside of node_modules. - console.log('[Codegen] Processing react-native core libraries'); - const reactNativePkgJson = path.join(RN_ROOT, CODEGEN_CONFIG_FILENAME); - if (!fs.existsSync(reactNativePkgJson)) { - throw '[Codegen] Error: Could not find config file for react-native.'; - } - const reactNativeConfigFile = JSON.parse( - fs.readFileSync(reactNativePkgJson), - ); - if ( - reactNativeConfigFile[CODEGEN_CONFIG_KEY] == null || - reactNativeConfigFile[CODEGEN_CONFIG_KEY].libraries == null - ) { - throw '[Codegen] Error: Could not find codegen config for react-native.'; - } - console.log('[Codegen] Found react-native'); - reactNativeConfigFile[CODEGEN_CONFIG_KEY].libraries.forEach(config => { - const libraryConfig = { - library: REACT_NATIVE_DEPENDENCY_NAME, - config, - libraryPath: RN_ROOT, - }; - libraries.push(libraryConfig); - }); - - // Determine which of these are codegen-enabled libraries - const confifDir = CODEGEN_CONFIG_FILE_DIR || path.join(RN_ROOT, '..'); - console.log( - `\n\n[Codegen] >>>>> Searching for codegen-enabled libraries in ${confifDir}`, - ); - - // Handle third-party libraries - Object.keys(dependencies).forEach(dependency => { - if (dependency === REACT_NATIVE_DEPENDENCY_NAME) { - // react-native should already be added. - return; - } - const codegenConfigFileDir = path.join(confifDir, dependency); - const configFilePath = path.join( - codegenConfigFileDir, - CODEGEN_CONFIG_FILENAME, - ); - if (fs.existsSync(configFilePath)) { - const configFile = JSON.parse(fs.readFileSync(configFilePath)); - if ( - configFile[CODEGEN_CONFIG_KEY] != null && - configFile[CODEGEN_CONFIG_KEY].libraries != null - ) { - console.log(`[Codegen] Found ${dependency}`); - configFile[CODEGEN_CONFIG_KEY].libraries.forEach(config => { - const libraryConfig = { - library: dependency, - config, - libraryPath: codegenConfigFileDir, - }; - libraries.push(libraryConfig); - }); - } - } - }); - - console.log( - '\n\n[Codegen] >>>>> Searching for codegen-enabled libraries in the app', - ); - - // Handle in-app libraries - if ( - pkgJson[CODEGEN_CONFIG_KEY] != null && - pkgJson[CODEGEN_CONFIG_KEY].libraries != null - ) { - console.log(`[Codegen] Found ${pkgJson.name}`); - pkgJson[CODEGEN_CONFIG_KEY].libraries.forEach(config => { - const libraryConfig = { - library: pkgJson.name, - config, - libraryPath: appRootDir, - }; - libraries.push(libraryConfig); - }); - } - - if (libraries.length === 0) { - console.log('[Codegen] No codegen-enabled libraries found.'); - return; - } - - // 4. Locate codegen package - let codegenCliPath; - if (fs.existsSync(CODEGEN_REPO_PATH)) { - codegenCliPath = CODEGEN_REPO_PATH; - - if (!fs.existsSync(path.join(CODEGEN_REPO_PATH, 'lib'))) { - console.log( - '\n\n[Codegen] >>>>> Building react-native-codegen package', - ); - execSync('yarn install', { - cwd: codegenCliPath, - stdio: 'inherit', - }); - execSync('yarn build', { - cwd: codegenCliPath, - stdio: 'inherit', - }); - } - } else if (fs.existsSync(CODEGEN_NPM_PATH)) { - codegenCliPath = CODEGEN_NPM_PATH; - } else { - throw "error: Could not determine react-native-codegen location. Try running 'yarn install' or 'npm install' in your project root."; - } - - const schemaPaths = {}; - - const iosOutputDir = path.join( - outputPath ? outputPath : appRootDir, - 'build/generated/ios', - ); - - // 5. For each codegen-enabled library, generate the native code spec files - libraries.forEach(library => { - if (!CODEGEN_FABRIC_ENABLED && library.config.type === 'components') { - console.log( - `[Codegen] ${library.config.name} skipped because fabric is not enabled.`, - ); - return; - } - const tmpDir = fs.mkdtempSync( - path.join(os.tmpdir(), library.config.name), - ); - const pathToSchema = path.join(tmpDir, 'schema.json'); - const pathToJavaScriptSources = path.join( - library.libraryPath, - library.config.jsSrcsDir, - ); - function composePath(intermediate) { - return path.join(iosOutputDir, intermediate, library.config.name); - } - - const outputDirsIOS = { - components: composePath('react/renderer/components'), - nativeModules: composePath('./'), - }; - - const tempOutputDirs = { - components: path.join(tmpDir, 'out', 'components'), - nativeModules: path.join(tmpDir, 'out', 'nativeModules'), - }; - - console.log(`\n\n[Codegen] >>>>> Processing ${library.config.name}`); - // Generate one schema for the entire library... - executeNodeScript( - `${path.join( - codegenCliPath, - 'lib', - 'cli', - 'combine', - 'combine-js-to-schema-cli.js', - )} ${pathToSchema} ${pathToJavaScriptSources}`, - ); - console.log(`[Codegen] Generated schema: ${pathToSchema}`); - - // ...then generate native code artifacts. - const libraryTypeArg = library.config.type - ? `--libraryType ${library.config.type}` - : ''; - - Object.entries(tempOutputDirs).forEach(([type, dirPath]) => { - fs.mkdirSync(dirPath, {recursive: true}); - }); - - const deprecated_outputDir = - library.config.type === 'components' - ? tempOutputDirs.components - : tempOutputDirs.nativeModules; - - executeNodeScript( - `${path.join(RN_ROOT, 'scripts', 'generate-specs-cli.js')} \ - --platform ios \ - --schemaPath ${pathToSchema} \ - --outputDir ${deprecated_outputDir} \ - --componentsOutputDir ${tempOutputDirs.components} \ - --modulesOutputDirs ${tempOutputDirs.nativeModules} \ - --libraryName ${library.config.name} \ - ${libraryTypeArg}`, - ); - - // Finally, copy artifacts to the final output directory. - Object.entries(outputDirsIOS).forEach(([type, dirPath]) => { - const outDir = tempOutputDirs[type]; - if (isDirEmpty(outDir)) { - return; // cp fails if we try to copy something empty. - } - - fs.mkdirSync(dirPath, {recursive: true}); - execSync(`cp -R ${outDir}/* ${dirPath}`); - console.log(`[Codegen] Generated artifacts: ${dirPath}`); - }); - - // Filter the react native core library out. - // In the future, core library and third party library should - // use the same way to generate/register the fabric components. - if (!isReactNativeCoreLibrary(library.config.name)) { - schemaPaths[library.config.name] = pathToSchema; - } - }); - - if (CODEGEN_FABRIC_ENABLED) { - console.log('\n\n>>>>> Creating component provider'); - // Save the list of spec paths to a temp file. - const schemaListTmpPath = `${os.tmpdir()}/rn-tmp-schema-list.json`; - const fd = fs.openSync(schemaListTmpPath, 'w'); - fs.writeSync(fd, JSON.stringify(schemaPaths)); - fs.closeSync(fd); - console.log(`Generated schema list: ${schemaListTmpPath}`); - - // Generate FabricComponentProvider. - // Only for iOS at this moment. - executeNodeScript( - `${path.join( - RN_ROOT, - 'scripts', - 'generate-provider-cli.js', - )} --platform ios --schemaListPath "${schemaListTmpPath}" --outputDir ${iosOutputDir}`, - ); - console.log(`Generated provider in: ${iosOutputDir}`); - } - } catch (err) { - console.error(err); - process.exitCode = 1; - } - - // 5. Done! - console.log('\n\n[Codegen] Done.'); - return; -} const appRoot = argv.path; const outputPath = argv.outputPath; -main(appRoot, outputPath); + +executor.execute( + appRoot, + outputPath, + NODE, + CODEGEN_CONFIG_FILENAME, + CODEGEN_CONFIG_KEY, + CODEGEN_CONFIG_FILE_DIR, + CODEGEN_FABRIC_ENABLED, +);