From 690d70c1c423405ff80b47671413791daa83ba6b Mon Sep 17 00:00:00 2001 From: "Zihan Chen (MSFT)" <53799235+ZihanChen-MSFT@users.noreply.github.com> Date: Mon, 14 Aug 2023 14:55:06 -0700 Subject: [PATCH] Generate types and spec in two files for turbo module (#11990) * Add `allInOne` to `createNM2Generator` * Add `allInOne` to @rnw/cli and @rnw/codegen * ... * ... * ... * Update sample-apps * Change files * Fix code review comment * Remove `allInOne` option and make it always happen * Update generated files * Update #include * Fix build break * Suppress clang-format on some include order --- ...-f3143569-d5a6-4a78-bfcc-84628b54933e.json | 7 ++ ...-be2112bc-3d94-4028-88d1-e2bfaae94185.json | 7 ++ ...-14398591-3062-462e-a9a5-25ca35480231.json | 7 ++ .../@react-native-windows/cli/src/codegen.ts | 20 ++++- .../@react-native-windows/codegen/src/Cli.ts | 5 ++ .../codegen/src/generators/GenerateNM2.ts | 88 +++++++++++++++---- .../codegen/src/index.ts | 5 ++ .../codegen/NativeMyModuleDataTypes.g.h | 24 +++++ .../codegen/NativeMyModuleSpec.g.h | 8 +- packages/sample-apps/package.json | 4 +- .../windows/SampleLibraryCPP/MyModule.h | 4 + 11 files changed, 155 insertions(+), 24 deletions(-) create mode 100644 change/@react-native-windows-cli-f3143569-d5a6-4a78-bfcc-84628b54933e.json create mode 100644 change/@react-native-windows-codegen-be2112bc-3d94-4028-88d1-e2bfaae94185.json create mode 100644 change/react-native-windows-14398591-3062-462e-a9a5-25ca35480231.json create mode 100644 packages/sample-apps/codegen/NativeMyModuleDataTypes.g.h diff --git a/change/@react-native-windows-cli-f3143569-d5a6-4a78-bfcc-84628b54933e.json b/change/@react-native-windows-cli-f3143569-d5a6-4a78-bfcc-84628b54933e.json new file mode 100644 index 00000000000..9f2ae718711 --- /dev/null +++ b/change/@react-native-windows-cli-f3143569-d5a6-4a78-bfcc-84628b54933e.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Add `separateDataFiles` to @rnw/cli and @rnw/codegen", + "packageName": "@react-native-windows/cli", + "email": "53799235+ZihanChen-MSFT@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/change/@react-native-windows-codegen-be2112bc-3d94-4028-88d1-e2bfaae94185.json b/change/@react-native-windows-codegen-be2112bc-3d94-4028-88d1-e2bfaae94185.json new file mode 100644 index 00000000000..641ae8bc657 --- /dev/null +++ b/change/@react-native-windows-codegen-be2112bc-3d94-4028-88d1-e2bfaae94185.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Add `separateDataFiles` to @rnw/cli and @rnw/codegen", + "packageName": "@react-native-windows/codegen", + "email": "53799235+ZihanChen-MSFT@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/change/react-native-windows-14398591-3062-462e-a9a5-25ca35480231.json b/change/react-native-windows-14398591-3062-462e-a9a5-25ca35480231.json new file mode 100644 index 00000000000..0511d9cf3ca --- /dev/null +++ b/change/react-native-windows-14398591-3062-462e-a9a5-25ca35480231.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Add `separateDataFiles` to @rnw/cli and @rnw/codegen", + "packageName": "react-native-windows", + "email": "53799235+ZihanChen-MSFT@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/@react-native-windows/cli/src/codegen.ts b/packages/@react-native-windows/cli/src/codegen.ts index 98477c41d6b..1fc17db94f4 100644 --- a/packages/@react-native-windows/cli/src/codegen.ts +++ b/packages/@react-native-windows/cli/src/codegen.ts @@ -106,7 +106,24 @@ export class CodeGenWindows { 'InvalidCodegenConfig', `Value of ${chalk.bold( 'codegenConfig.windows.cppStringType', - )} package.json should be either 'std::string' or 'std::wstring'`, + )} in package.json should be either 'std::string' or 'std::wstring'`, + ); + } + } + + let separateDataTypes = true; + if (pkgJson.codegenConfig.windows.separateDataTypes !== undefined) { + switch (pkgJson.codegenConfig.windows.separateDataTypes) { + case true: + case false: + separateDataTypes = pkgJson.codegenConfig.windows.separateDataTypes; + break; + default: + throw new CodedError( + 'InvalidCodegenConfig', + `Value of ${chalk.bold( + 'codegenConfig.windows.separateDataTypes', + )} in package.json should be either true or false`, ); } } @@ -138,6 +155,7 @@ export class CodeGenWindows { }**/*Native*.[jt]s`, ], cppStringType, + separateDataTypes, libraryName: projectName, methodOnly: false, modulesCxx: generators.indexOf('modulesCxx') !== -1, diff --git a/packages/@react-native-windows/codegen/src/Cli.ts b/packages/@react-native-windows/codegen/src/Cli.ts index 1b192a6016f..14e2f4473d9 100644 --- a/packages/@react-native-windows/codegen/src/Cli.ts +++ b/packages/@react-native-windows/codegen/src/Cli.ts @@ -64,6 +64,11 @@ const argv = yargs.options({ 'C++ string type in generated code, should be "std::string" or "std::wstring"', default: 'std::string', }, + separateDataTypes: { + type: 'boolean', + describe: 'generate data types in a separate file', + default: false, + }, }).argv; if ((argv.file && argv.files) || (!argv.file && !argv.files)) { diff --git a/packages/@react-native-windows/codegen/src/generators/GenerateNM2.ts b/packages/@react-native-windows/codegen/src/generators/GenerateNM2.ts index a46fa1c4208..fa1e12f4f94 100644 --- a/packages/@react-native-windows/codegen/src/generators/GenerateNM2.ts +++ b/packages/@react-native-windows/codegen/src/generators/GenerateNM2.ts @@ -17,22 +17,16 @@ export type {CppStringTypes} from './ObjectTypes'; type FilesOutput = Map; -const moduleTemplate = ` -/* +const headerTemplate = `/* * This file is auto-generated from a NativeModule spec file in js. * * This is a C++ Spec class that should be used with MakeTurboModuleProvider to register native modules * in a way that also verifies at compile time that the native module matches the interface required * by the TurboModule JS spec. */ -#pragma once +#pragma once`; -#include -#include - -namespace ::_NAMESPACE_:: { -::_MODULE_CUSTPM_TYPES_:: -::_MODULE_CUSTPM_TYPES_REFLECTION_:: +const specTemplate = `::_MODULE_CUSTPM_TYPES_REFLECTION_:: struct ::_MODULE_NAME_::Spec : winrt::Microsoft::ReactNative::TurboModuleSpec { ::_MODULE_MEMBERS_TUPLES_:: @@ -41,7 +35,44 @@ struct ::_MODULE_NAME_::Spec : winrt::Microsoft::ReactNative::TurboModuleSpec { ::_MODULE_MEMBERS_CHECKS_:: ::_MODULE_MEMBERS_ERRORS_:: - } + }`; + +const typeOnlyTemplate = ` +${headerTemplate} + +#include +#include +#include +#include + +namespace ::_NAMESPACE_:: { +::_MODULE_CUSTPM_TYPES_:: +} // namespace ::_NAMESPACE_:: +`; + +const moduleOnlyTemplate = ` +${headerTemplate} + +::_TYPE_DEFINITION_INCLUDE_:: +#include +#include + +namespace ::_NAMESPACE_:: { +${specTemplate} +}; + +} // namespace ::_NAMESPACE_:: +`; + +const allInOneTemplate = ` +${headerTemplate} + +#include +#include + +namespace ::_NAMESPACE_:: { +::_MODULE_CUSTPM_TYPES_:: +${specTemplate} }; } // namespace ::_NAMESPACE_:: @@ -51,10 +82,12 @@ export function createNM2Generator({ methodOnly, namespace, cppStringType, + separateDataTypes, }: { methodOnly: boolean; namespace: string; cppStringType: CppStringTypes; + separateDataTypes: boolean; }) { return ( _libraryName: string, @@ -110,17 +143,42 @@ ${errors}`; cppStringType, }); - files.set( - `Native${preferredModuleName}Spec.g.h`, - moduleTemplate + const customTypesExist = customTypes !== ''; + + const replaceContent = function (template: string): string { + return template .replace(/::_MODULE_CUSTPM_TYPES_::/g, customTypes) .replace(/::_MODULE_CUSTPM_TYPES_REFLECTION_::/g, customReflection) .replace(/::_MODULE_MEMBERS_TUPLES_::/g, tuples.substring(1)) .replace(/::_MODULE_MEMBERS_CHECKS_::/g, checks.substring(1)) .replace(/::_MODULE_MEMBERS_ERRORS_::/g, errors) .replace(/::_MODULE_NAME_::/g, preferredModuleName) - .replace(/::_NAMESPACE_::/g, namespace), - ); + .replace( + /::_TYPE_DEFINITION_INCLUDE_::/g, + customTypesExist + ? `// #include "Native${preferredModuleName}DataTypes.g.h" before this file to use the generated type definition` + : '', + ) + .replace(/::_NAMESPACE_::/g, namespace); + }; + + if (separateDataTypes) { + if (customTypesExist) { + files.set( + `Native${preferredModuleName}DataTypes.g.h`, + replaceContent(typeOnlyTemplate), + ); + } + files.set( + `Native${preferredModuleName}Spec.g.h`, + replaceContent(moduleOnlyTemplate), + ); + } else { + files.set( + `Native${preferredModuleName}Spec.g.h`, + replaceContent(allInOneTemplate), + ); + } } } diff --git a/packages/@react-native-windows/codegen/src/index.ts b/packages/@react-native-windows/codegen/src/index.ts index 782161ba1a9..75e7712410d 100644 --- a/packages/@react-native-windows/codegen/src/index.ts +++ b/packages/@react-native-windows/codegen/src/index.ts @@ -52,6 +52,7 @@ export interface SharedOptions { namespace: string; outputDirectory: string; cppStringType: CppStringTypes; + separateDataTypes: boolean; } interface Options extends SharedOptions { @@ -216,6 +217,7 @@ export function generate( namespace, outputDirectory, cppStringType, + separateDataTypes, moduleSpecName, schema, }: Options, @@ -240,6 +242,7 @@ export function generate( methodOnly, namespace, cppStringType, + separateDataTypes, }); const generateJsiModuleH = require(path.resolve( @@ -369,6 +372,7 @@ export function runCodeGen(options: CodeGenOptions): boolean { namespace, outputDirectory, cppStringType, + separateDataTypes, } = options; return generate( { @@ -380,6 +384,7 @@ export function runCodeGen(options: CodeGenOptions): boolean { namespace, outputDirectory, cppStringType, + separateDataTypes, moduleSpecName, schema, }, diff --git a/packages/sample-apps/codegen/NativeMyModuleDataTypes.g.h b/packages/sample-apps/codegen/NativeMyModuleDataTypes.g.h new file mode 100644 index 00000000000..b44cd2cfb38 --- /dev/null +++ b/packages/sample-apps/codegen/NativeMyModuleDataTypes.g.h @@ -0,0 +1,24 @@ + +/* + * This file is auto-generated from a NativeModule spec file in js. + * + * This is a C++ Spec class that should be used with MakeTurboModuleProvider to register native modules + * in a way that also verifies at compile time that the native module matches the interface required + * by the TurboModule JS spec. + */ +#pragma once + +#include +#include +#include +#include + +namespace SampleLibraryCodegen { + +struct MyModuleSpec_Constants { + bool const1; + double const2; + std::string const3; +}; + +} // namespace SampleLibraryCodegen diff --git a/packages/sample-apps/codegen/NativeMyModuleSpec.g.h b/packages/sample-apps/codegen/NativeMyModuleSpec.g.h index 4dfd5f7fdcd..5b5861629ab 100644 --- a/packages/sample-apps/codegen/NativeMyModuleSpec.g.h +++ b/packages/sample-apps/codegen/NativeMyModuleSpec.g.h @@ -8,18 +8,12 @@ */ #pragma once +// #include "NativeMyModuleDataTypes.g.h" before this file to use the generated type definition #include #include namespace SampleLibraryCodegen { -struct MyModuleSpec_Constants { - bool const1; - double const2; - std::string const3; -}; - - inline winrt::Microsoft::ReactNative::FieldMap GetStructInfo(MyModuleSpec_Constants*) noexcept { winrt::Microsoft::ReactNative::FieldMap fieldMap { {L"const1", &MyModuleSpec_Constants::const1}, diff --git a/packages/sample-apps/package.json b/packages/sample-apps/package.json index 512e77f2d6c..d4cbc9ee379 100644 --- a/packages/sample-apps/package.json +++ b/packages/sample-apps/package.json @@ -23,6 +23,7 @@ "@babel/eslint-parser": "^7.20.0", "@babel/runtime": "^7.8.4", "@react-native-windows/codegen": "0.0.0-canary.67", + "@react-native-windows/cli": "0.0.0-canary.183", "@rnw-scripts/babel-react-native-config": "0.0.0", "@rnw-scripts/eslint-config": "1.2.2", "@rnw-scripts/just-task": "2.3.15", @@ -39,7 +40,8 @@ "type": "modules", "jsSrcsDir": "src", "windows": { - "namespace": "SampleLibraryCodegen" + "namespace": "SampleLibraryCodegen", + "separateDataFiles": true } }, "engines": { diff --git a/packages/sample-apps/windows/SampleLibraryCPP/MyModule.h b/packages/sample-apps/windows/SampleLibraryCPP/MyModule.h index 6c68752ebdc..a2f99412c75 100644 --- a/packages/sample-apps/windows/SampleLibraryCPP/MyModule.h +++ b/packages/sample-apps/windows/SampleLibraryCPP/MyModule.h @@ -3,6 +3,10 @@ #pragma once +// a demo of setting codegenConfig.windows.separateDataTypes to true in package.json +// it generates data types in a separate file, but one doesn't include another +// including them in a expected order is required +#include "..\..\codegen\NativeMyModuleDataTypes.g.h" #include "..\..\codegen\NativeMyModuleSpec.g.h" #include "DebugHelpers.h"