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