Skip to content

Commit

Permalink
Generate types and spec in two files for turbo module (#11990)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
ZihanChen-MSFT committed Aug 14, 2023
1 parent 8fc4cf7 commit 690d70c
Show file tree
Hide file tree
Showing 11 changed files with 155 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -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"
}
Original file line number Diff line number Diff line change
@@ -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"
}
Original file line number Diff line number Diff line change
@@ -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"
}
20 changes: 19 additions & 1 deletion packages/@react-native-windows/cli/src/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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`,
);
}
}
Expand Down Expand Up @@ -138,6 +155,7 @@ export class CodeGenWindows {
}**/*Native*.[jt]s`,
],
cppStringType,
separateDataTypes,
libraryName: projectName,
methodOnly: false,
modulesCxx: generators.indexOf('modulesCxx') !== -1,
Expand Down
5 changes: 5 additions & 0 deletions packages/@react-native-windows/codegen/src/Cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,16 @@ export type {CppStringTypes} from './ObjectTypes';

type FilesOutput = Map<string, string>;

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 <NativeModules.h>
#include <tuple>
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_::
Expand All @@ -41,7 +35,44 @@ struct ::_MODULE_NAME_::Spec : winrt::Microsoft::ReactNative::TurboModuleSpec {
::_MODULE_MEMBERS_CHECKS_::
::_MODULE_MEMBERS_ERRORS_::
}
}`;

const typeOnlyTemplate = `
${headerTemplate}
#include <string>
#include <optional>
#include <functional>
#include <vector>
namespace ::_NAMESPACE_:: {
::_MODULE_CUSTPM_TYPES_::
} // namespace ::_NAMESPACE_::
`;

const moduleOnlyTemplate = `
${headerTemplate}
::_TYPE_DEFINITION_INCLUDE_::
#include <NativeModules.h>
#include <tuple>
namespace ::_NAMESPACE_:: {
${specTemplate}
};
} // namespace ::_NAMESPACE_::
`;

const allInOneTemplate = `
${headerTemplate}
#include <NativeModules.h>
#include <tuple>
namespace ::_NAMESPACE_:: {
::_MODULE_CUSTPM_TYPES_::
${specTemplate}
};
} // namespace ::_NAMESPACE_::
Expand All @@ -51,10 +82,12 @@ export function createNM2Generator({
methodOnly,
namespace,
cppStringType,
separateDataTypes,
}: {
methodOnly: boolean;
namespace: string;
cppStringType: CppStringTypes;
separateDataTypes: boolean;
}) {
return (
_libraryName: string,
Expand Down Expand Up @@ -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),
);
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions packages/@react-native-windows/codegen/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export interface SharedOptions {
namespace: string;
outputDirectory: string;
cppStringType: CppStringTypes;
separateDataTypes: boolean;
}

interface Options extends SharedOptions {
Expand Down Expand Up @@ -216,6 +217,7 @@ export function generate(
namespace,
outputDirectory,
cppStringType,
separateDataTypes,
moduleSpecName,
schema,
}: Options,
Expand All @@ -240,6 +242,7 @@ export function generate(
methodOnly,
namespace,
cppStringType,
separateDataTypes,
});

const generateJsiModuleH = require(path.resolve(
Expand Down Expand Up @@ -369,6 +372,7 @@ export function runCodeGen(options: CodeGenOptions): boolean {
namespace,
outputDirectory,
cppStringType,
separateDataTypes,
} = options;
return generate(
{
Expand All @@ -380,6 +384,7 @@ export function runCodeGen(options: CodeGenOptions): boolean {
namespace,
outputDirectory,
cppStringType,
separateDataTypes,
moduleSpecName,
schema,
},
Expand Down
24 changes: 24 additions & 0 deletions packages/sample-apps/codegen/NativeMyModuleDataTypes.g.h
Original file line number Diff line number Diff line change
@@ -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 <string>
#include <optional>
#include <functional>
#include <vector>

namespace SampleLibraryCodegen {

struct MyModuleSpec_Constants {
bool const1;
double const2;
std::string const3;
};

} // namespace SampleLibraryCodegen
8 changes: 1 addition & 7 deletions packages/sample-apps/codegen/NativeMyModuleSpec.g.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,12 @@
*/
#pragma once

// #include "NativeMyModuleDataTypes.g.h" before this file to use the generated type definition
#include <NativeModules.h>
#include <tuple>

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},
Expand Down
4 changes: 3 additions & 1 deletion packages/sample-apps/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -39,7 +40,8 @@
"type": "modules",
"jsSrcsDir": "src",
"windows": {
"namespace": "SampleLibraryCodegen"
"namespace": "SampleLibraryCodegen",
"separateDataFiles": true
}
},
"engines": {
Expand Down
4 changes: 4 additions & 0 deletions packages/sample-apps/windows/SampleLibraryCPP/MyModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down

0 comments on commit 690d70c

Please sign in to comment.