diff --git a/packages/react-native-codegen/src/generators/RNCodegen.js b/packages/react-native-codegen/src/generators/RNCodegen.js index 0de0f2ec1d1..ce6221db60e 100644 --- a/packages/react-native-codegen/src/generators/RNCodegen.js +++ b/packages/react-native-codegen/src/generators/RNCodegen.js @@ -26,6 +26,7 @@ const generatePropsH = require('./components/GeneratePropsH.js'); const generateModuleH = require('./modules/GenerateModuleH.js'); const generateModuleCpp = require('./modules/GenerateModuleCpp.js'); const generateModuleHObjCpp = require('./modules/GenerateModuleHObjCpp.js'); +const generateModuleJavaSpec = require('./modules/GenerateModuleJavaSpec.js'); const generateModuleMm = require('./modules/GenerateModuleMm.js'); const generatePropsJavaInterface = require('./components/GeneratePropsJavaInterface.js'); const generatePropsJavaDelegate = require('./components/GeneratePropsJavaDelegate.js'); @@ -60,12 +61,7 @@ type Config = $ReadOnly<{| const GENERATORS = { descriptors: [generateComponentDescriptorH.generate], - events: [ - generateEventEmitterCpp.generate, - generateEventEmitterH.generate, - generateModuleHObjCpp.generate, - generateModuleMm.generate, - ], + events: [generateEventEmitterCpp.generate, generateEventEmitterH.generate], props: [ generateComponentHObjCpp.generate, generatePropsCpp.generate, @@ -73,7 +69,14 @@ const GENERATORS = { generatePropsJavaInterface.generate, generatePropsJavaDelegate.generate, ], - modules: [generateModuleCpp.generate, generateModuleH.generate], + modules: [ + generateModuleCpp.generate, + generateModuleH.generate, + generateModuleHObjCpp.generate, + generateModuleMm.generate, + // TODO: Java output and the C++ output need to be separated. + generateModuleJavaSpec.generate, + ], tests: [generateTests.generate], 'shadow-nodes': [ generateShadowNodeCpp.generate, diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js new file mode 100644 index 00000000000..d26211f8c12 --- /dev/null +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js @@ -0,0 +1,101 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict + * @format + */ + +'use strict'; + +import type { + FunctionTypeAnnotationParamTypeAnnotation, + FunctionTypeAnnotationReturn, + NativeModuleShape, + TypeAliasTypeAnnotation, + ObjectTypeAliasTypeShape, + SchemaType, +} from '../../CodegenSchema'; + +type FilesOutput = Map; + +const moduleTemplate = `/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the LICENSE file in the root + * directory of this source tree. + * + * ${'@'}generated by codegen project: GenerateModuleJavaSpec.js + * + * @nolint + */ + +package ::_PACKAGENAME_::; + +::_IMPORTS_:: + +public abstract class ::_CLASSNAME_:: extends ReactContextBaseJavaModule implements ReactModuleWithSpec, TurboModule { + public ::_CLASSNAME_::(ReactApplicationContext reactContext) { + super(reactContext); + } + +::_METHODS_:: +} +`; + +function getImportList(nativeModule: NativeModuleShape): Set { + const imports: Set = new Set(); + + // Always required. + imports.add('com.facebook.react.bridge.ReactApplicationContext'); + imports.add('com.facebook.react.bridge.ReactContextBaseJavaModule'); + imports.add('com.facebook.react.bridge.ReactMethod'); + imports.add('com.facebook.react.bridge.ReactModuleWithSpec'); + imports.add('com.facebook.react.turbomodule.core.interfaces.TurboModule'); + + return imports; +} + +// TODO: complete this implementation +module.exports = { + generate( + libraryName: string, + schema: SchemaType, + moduleSpecName: string, + ): FilesOutput { + const files = new Map(); + // TODO: Allow package configuration. + const packageName = 'com.facebook.fbreact.specs'; + const nativeModules = Object.keys(schema.modules) + .map(moduleName => { + const modules = schema.modules[moduleName].nativeModules; + if (modules == null) { + return null; + } + + return modules; + }) + .filter(Boolean) + .reduce((acc, components) => Object.assign(acc, components), {}); + + Object.keys(nativeModules).forEach(name => { + const {aliases, properties} = nativeModules[name]; + const className = `Native${name}Spec`; + + const methods = properties.map(method => { + const traversedArgs = method.typeAnnotation.params.map(param => {}); + }); + + files.set( + `${className}.java`, + moduleTemplate + .replace(/::_PACKAGENAME_::/g, packageName) + .replace(/::_CLASSNAME_::/g, className), + ); + }); + + return files; + }, +}; diff --git a/scripts/generate-native-modules-specs-cli.js b/scripts/generate-native-modules-specs-cli.js index 2b72610e21b..fe0871bb368 100644 --- a/scripts/generate-native-modules-specs-cli.js +++ b/scripts/generate-native-modules-specs-cli.js @@ -15,7 +15,7 @@ const mkdirp = require('mkdirp'); const os = require('os'); const path = require('path'); -function generateSpec(schemaPath, outputDirectory) { +function generateSpec(platform, schemaPath, outputDirectory) { const libraryName = 'FBReactNativeSpec'; const moduleSpecName = 'FBReactNativeSpec'; const schemaText = fs.readFileSync(schemaPath, 'utf-8'); @@ -38,14 +38,7 @@ function generateSpec(schemaPath, outputDirectory) { RNCodegen.generate( {libraryName, schema, outputDirectory: tempOutputDirectory, moduleSpecName}, { - generators: [ - 'descriptors', - 'events', - 'props', - 'tests', - 'shadow-nodes', - 'modules', - ], + generators: ['modules'], }, ); @@ -60,19 +53,35 @@ function generateSpec(schemaPath, outputDirectory) { } mkdirp.sync(outputDirectory); - const fileNames = [`${moduleSpecName}.h`, `${moduleSpecName}-generated.mm`]; - fileNames.forEach(fileName => { - const newOutput = `${tempOutputDirectory}/${fileName}`; - const prevOutput = `${outputDirectory}/${fileName}`; - fs.copyFileSync(newOutput, prevOutput); - }); + if (platform === 'ios') { + const fileNames = [`${moduleSpecName}.h`, `${moduleSpecName}-generated.mm`]; + fileNames.forEach(fileName => { + const newOutput = `${tempOutputDirectory}/${fileName}`; + const prevOutput = `${outputDirectory}/${fileName}`; + fs.copyFileSync(newOutput, prevOutput); + }); + } else if (platform === 'android') { + // Copy all .java files for now. + // TODO: Build sufficient support for producing Java package directories based + // on preferred package name. + const files = fs.readdirSync(tempOutputDirectory); + files + .filter(f => f.endsWith('.java')) + .forEach(f => { + fs.copyFileSync( + `${tempOutputDirectory}/${f}`, + `${outputDirectory}/${f}`, + ); + }); + } } function main() { const args = process.argv.slice(2); - const schemaPath = args[0]; - const outputDir = args[1]; - generateSpec(schemaPath, outputDir); + const platform = args[0]; + const schemaPath = args[1]; + const outputDir = args[2]; + generateSpec(platform, schemaPath, outputDir); } main(); diff --git a/scripts/generate-native-modules-specs.sh b/scripts/generate-native-modules-specs.sh index fc567f9f388..c65f85aa819 100755 --- a/scripts/generate-native-modules-specs.sh +++ b/scripts/generate-native-modules-specs.sh @@ -47,8 +47,8 @@ step_gen_schema () { } step_gen_specs () { - describe "Generating native code from schema" - "$YARN_BINARY" --silent node scripts/generate-native-modules-specs-cli.js "$SCHEMA_FILE" "$OUTPUT_DIR" + describe "Generating native code from schema (iOS)" + "$YARN_BINARY" --silent node scripts/generate-native-modules-specs-cli.js ios "$SCHEMA_FILE" "$OUTPUT_DIR" } step_build_codegen