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