1/** 2 * Copyright (c) Meta Platforms, Inc. and affiliates. 3 * 4 * This source code is licensed under the MIT license found in the 5 * LICENSE file in the root directory of this source tree. 6 * 7 * @format 8 */ 9 10'use strict'; 11 12const fs = require('fs'); 13const mkdirp = require('mkdirp'); 14const path = require('path'); 15const utils = require('./codegen-utils'); 16const RNCodegen = utils.getCodegen(); 17 18const GENERATORS = { 19 all: { 20 android: ['componentsAndroid', 'modulesAndroid', 'modulesCxx'], 21 ios: ['componentsIOS', 'modulesIOS', 'modulesCxx'], 22 }, 23 components: { 24 android: ['componentsAndroid'], 25 ios: ['componentsIOS'], 26 }, 27 modules: { 28 android: ['modulesAndroid', 'modulesCxx'], 29 ios: ['modulesIOS', 'modulesCxx'], 30 }, 31}; 32 33function createOutputDirectoryIfNeeded(outputDirectory, libraryName) { 34 if (!outputDirectory) { 35 outputDirectory = path.resolve(__dirname, '..', 'Libraries', libraryName); 36 } 37 mkdirp.sync(outputDirectory); 38} 39 40function createFolderIfDefined(folder) { 41 if (folder) { 42 mkdirp.sync(folder); 43 } 44} 45 46/** 47 * This function read a JSON schema from a path and parses it. 48 * It throws if the schema don't exists or it can't be parsed. 49 * 50 * @parameter schemaPath: the path to the schema 51 * @return a valid schema 52 * @throw an Error if the schema doesn't exists in a given path or if it can't be parsed. 53 */ 54function readAndParseSchema(schemaPath) { 55 const schemaText = fs.readFileSync(schemaPath, 'utf-8'); 56 57 if (schemaText == null) { 58 throw new Error(`Can't find schema at ${schemaPath}`); 59 } 60 61 try { 62 return JSON.parse(schemaText); 63 } catch (err) { 64 throw new Error(`Can't parse schema to JSON. ${schemaPath}`); 65 } 66} 67 68function validateLibraryType(libraryType) { 69 if (GENERATORS[libraryType] == null) { 70 throw new Error(`Invalid library type. ${libraryType}`); 71 } 72} 73 74function generateSpec( 75 platform, 76 schemaPath, 77 outputDirectory, 78 libraryName, 79 packageName, 80 libraryType, 81) { 82 validateLibraryType(libraryType); 83 84 let schema = readAndParseSchema(schemaPath); 85 86 createOutputDirectoryIfNeeded(outputDirectory, libraryName); 87 function composePath(intermediate) { 88 return path.join(outputDirectory, intermediate, libraryName); 89 } 90 91 // These are hardcoded and should not be changed. 92 // The codegen creates some C++ code with #include directive 93 // which uses these paths. Those directive are not customizable yet. 94 createFolderIfDefined(composePath('react/renderer/components/')); 95 createFolderIfDefined(composePath('./')); 96 97 RNCodegen.generate( 98 { 99 libraryName, 100 schema, 101 outputDirectory, 102 packageName, 103 }, 104 { 105 generators: GENERATORS[libraryType][platform], 106 }, 107 ); 108 109 if (platform === 'android') { 110 // Move all components C++ files to a structured jni folder for now. 111 // Note: this should've been done by RNCodegen's generators, but: 112 // * the generators don't support platform option yet 113 // * this subdir structure is Android-only, not applicable to iOS 114 const files = fs.readdirSync(outputDirectory); 115 const jniOutputDirectory = `${outputDirectory}/jni/react/renderer/components/${libraryName}`; 116 mkdirp.sync(jniOutputDirectory); 117 files 118 .filter(f => f.endsWith('.h') || f.endsWith('.cpp')) 119 .forEach(f => { 120 fs.renameSync(`${outputDirectory}/${f}`, `${jniOutputDirectory}/${f}`); 121 }); 122 } 123} 124 125module.exports = { 126 execute: generateSpec, 127}; 128