Skip to content

Commit

Permalink
[0.71] Port #11982 and #11990 to 0.71-stable (#12020)
Browse files Browse the repository at this point in the history
* @rnw/codegen generates GetStructInfo instead of REACT_STRUCT (#11982)

* #include <NativeModules.h>

* Separate custom types and reflection in template

* Generate GetStructInfo function instead of REACT_STRUCT

* ...

* Update generated files

* Change files

* ...

* 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

* ...

* Change files

* Update packages.lock.json
  • Loading branch information
ZihanChen-MSFT authored Aug 15, 2023
1 parent 8ec53f4 commit 4b58157
Show file tree
Hide file tree
Showing 75 changed files with 977 additions and 394 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"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": "patch",
"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": "patch",
"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
58 changes: 45 additions & 13 deletions packages/@react-native-windows/codegen/src/generators/AliasGen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import type {
import {AliasMap, getAliasCppName} from './AliasManaging';
import {CppCodegenOptions, translateField} from './ObjectTypes';

function translateObjectBody(
function translateObjectMembersDefinition(
type: NativeModuleObjectTypeAnnotation,
aliases: AliasMap,
baseAliasName: string,
Expand All @@ -28,14 +28,24 @@ function translateObjectBody(
if (prop.optional && propType.type !== 'NullableTypeAnnotation') {
propType = {type: 'NullableTypeAnnotation', typeAnnotation: propType};
}
const first = `${prefix}REACT_FIELD(${prop.name})`;
const second = `${prefix}${translateField(
return `${prefix}${translateField(
propType,
aliases,
`${baseAliasName}_${prop.name}`,
options,
)} ${prop.name};`;
return `${first}\n${second}`;
})
.join('\n');
}

function translateObjectMembersReflection(
type: NativeModuleObjectTypeAnnotation,
aliasCppName: string,
prefix: string,
) {
return type.properties
.map((prop: NamedShape<Nullable<NativeModuleBaseTypeAnnotation>>) => {
return `${prefix}{L"${prop.name}", &${aliasCppName}::${prop.name}},`;
})
.join('\n');
}
Expand All @@ -50,8 +60,13 @@ export function createAliasMap(nativeModuleAliases: {
return aliases;
}

interface AliasCode {
definition: string;
reflection: string;
}

interface AliasCodeMap {
[name: string]: string;
[name: string]: AliasCode;
}

function generateSingleAlias(
Expand All @@ -60,13 +75,28 @@ function generateSingleAlias(
aliasCode: AliasCodeMap,
options: CppCodegenOptions,
): void {
const aliasCppName = getAliasCppName(aliasName);
const aliasType = <NativeModuleObjectTypeAnnotation>aliases.types[aliasName];
aliasCode[aliasName] = `
REACT_STRUCT(${getAliasCppName(aliasName)})
struct ${getAliasCppName(aliasName)} {
${translateObjectBody(aliasType, aliases, aliasName, ' ', options)}
const definition = `
struct ${aliasCppName} {
${translateObjectMembersDefinition(
aliasType,
aliases,
aliasName,
' ',
options,
)}
};
`;
const reflection = `
inline winrt::Microsoft::ReactNative::FieldMap GetStructInfo(${aliasCppName}*) noexcept {
winrt::Microsoft::ReactNative::FieldMap fieldMap {
${translateObjectMembersReflection(aliasType, aliasCppName, ' ')}
};
return fieldMap;
}
`;
aliasCode[aliasName] = {definition, reflection};
}

function generateNestedAliasesInCorrectOrder(
Expand Down Expand Up @@ -103,15 +133,17 @@ function generateNestedAliasesInCorrectOrder(
export function generateAliases(
aliases: AliasMap,
options: CppCodegenOptions,
): string {
): [string, string] {
const aliasCode: AliasCodeMap = {};
const aliasOrder: string[] = [];
generateNestedAliasesInCorrectOrder(aliases, aliasCode, aliasOrder, options);

// aliasOrder now has the correct order of C++ struct code
let traversedAliasedStructs = '';
let customTypes = '';
let customReflection = '';
for (const aliasName of aliasOrder) {
traversedAliasedStructs = `${traversedAliasedStructs}${aliasCode[aliasName]}`;
customTypes = `${customTypes}${aliasCode[aliasName].definition}`;
customReflection = `${customReflection}${aliasCode[aliasName].reflection}`;
}
return traversedAliasedStructs;
return [customTypes, customReflection];
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +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_ALIASED_STRUCTS_::
const specTemplate = `::_MODULE_CUSTPM_TYPES_REFLECTION_::
struct ::_MODULE_NAME_::Spec : winrt::Microsoft::ReactNative::TurboModuleSpec {
::_MODULE_MEMBERS_TUPLES_::
Expand All @@ -40,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 @@ -50,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 @@ -105,20 +139,46 @@ ${errors}`;
}

// generate code for structs
const traversedAliasedStructs = generateAliases(aliases, {
const [customTypes, customReflection] = generateAliases(aliases, {
cppStringType,
});

files.set(
`Native${preferredModuleName}Spec.g.h`,
moduleTemplate
.replace(/::_MODULE_ALIASED_STRUCTS_::/g, traversedAliasedStructs)
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 @@ -43,6 +43,7 @@ export interface SharedOptions {
namespace: string;
outputDirectory: string;
cppStringType: CppStringTypes;
separateDataTypes: boolean;
}

interface Options extends SharedOptions {
Expand Down Expand Up @@ -195,6 +196,7 @@ export function generate(
namespace,
outputDirectory,
cppStringType,
separateDataTypes,
moduleSpecName,
schema,
}: Options,
Expand All @@ -219,6 +221,7 @@ export function generate(
methodOnly,
namespace,
cppStringType,
separateDataTypes,
});

const generateJsiModuleH = require(path.resolve(
Expand Down Expand Up @@ -348,6 +351,7 @@ export function runCodeGen(options: CodeGenOptions): boolean {
namespace,
outputDirectory,
cppStringType,
separateDataTypes,
} = options;
return generate(
{
Expand All @@ -359,6 +363,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
Loading

0 comments on commit 4b58157

Please sign in to comment.