Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# Spec Codegen uses LF
*Spec.g.h eol=lf
/vnext/codegen/** eol=lf
/vnext/Microsoft.ReactNative.IntegrationTests/codegen/** eol=lf
/packages/sample-apps/codegen/** eol=lf

# Force Visual Studio project files (mostly XML) to CRLF
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Enable ability to codegen JSI C++ TurboModule specs",
"packageName": "@react-native-windows/cli",
"email": "30809111+acoates-ms@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Enable ability to codegen JSI C++ TurboModule specs",
"packageName": "@react-native-windows/codegen",
"email": "30809111+acoates-ms@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Update codegen version",
"packageName": "react-native-windows",
"email": "30809111+acoates-ms@users.noreply.github.com",
"dependentChangeType": "patch"
}
15 changes: 11 additions & 4 deletions packages/@react-native-windows/cli/src/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,18 +103,25 @@ export class CodeGenWindows {
? path.join(this.root, pkgJson.codegenConfig.jsSrcsDir)
: this.root;

const generators = pkgJson.codegenConfig.windows.generators ?? [
'modulesWindows',
];

const jsRootPathRelative = path.relative(process.cwd(), jsRootDir);
const options = {
files: [
`${jsRootPathRelative}${
jsRootPathRelative ? '/' : ''
}**/*Native*.[jt]s`,
],
namespace: projectNamespace,
libraryName: projectName,
outdir: path.join(this.root, 'codegen'),
methodonly: false,
ts: false,
methodOnly: false,
modulesCxx: generators.indexOf('modulesCxx') !== -1,
modulesTypeScriptTypes:
generators.indexOf('modulesTypeScriptTypes') !== -1,
modulesWindows: generators.indexOf('modulesWindows') !== -1,
namespace: projectNamespace,
outputDirectory: path.join(this.root, 'codegen'),
test: !!this.options.check,
};

Expand Down
16 changes: 13 additions & 3 deletions packages/@react-native-windows/codegen/src/Cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,27 @@ const argv = yargs.options({
array: true,
describe: 'glob patterns for files which contains specs',
},
ts: {
modulesTypeScriptTypes: {
type: 'boolean',
describe: 'generate turbo module definition files in TypeScript',
default: false,
},
methodonly: {
modulesCxx: {
type: 'boolean',
describe: 'generate C++ JSI turbo module spec files',
default: false,
},
modulesWindows: {
type: 'boolean',
describe: 'generate turbo module spec files for REACT_MODULE',
default: false,
},
methodOnly: {
type: 'boolean',
describe: 'generate only method metadata in C++ turbo module spec',
default: false,
},
outdir: {
outputDirectory: {
type: 'string',
describe: 'output directory',
default: 'codegen',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ struct ::_MODULE_NAME_::Spec : winrt::Microsoft::ReactNative::TurboModuleSpec {
`;

export function createNM2Generator({
methodOnly,
namespace,
methodonly,
}: {
methodOnly: boolean;
namespace: string;
methodonly: boolean;
}) {
return (
_libraryName: string,
Expand Down Expand Up @@ -85,7 +85,7 @@ ${methods[0]}

// prepare constants
const constants = generateValidateConstants(nativeModule, aliases);
if (constants !== undefined && !methodonly) {
if (constants !== undefined && !methodOnly) {
tuples = `
static constexpr auto constants = std::tuple{
${constants[0]}
Expand Down
100 changes: 66 additions & 34 deletions packages/@react-native-windows/codegen/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@ const schemaValidator = require(path.resolve(

interface Options {
libraryName: string;
schema: SchemaType;
outputDirectory: string;
methodOnly: boolean;
modulesCxx: boolean;
moduleSpecName: string;
modulesTypeScriptTypes: boolean;
modulesWindows: boolean;
namespace: string;
methodonly: boolean;
ts: boolean;
outputDirectory: string;
schema: SchemaType;
}

interface Config {
Expand Down Expand Up @@ -179,12 +181,14 @@ export function combineSchemas(files: string[]): SchemaType {
export function generate(
{
libraryName,
schema,
outputDirectory,
methodOnly,
modulesCxx,
moduleSpecName,
modulesTypeScriptTypes,
modulesWindows,
namespace,
methodonly,
ts,
outputDirectory,
schema,
}: Options,
{/*generators,*/ test}: Config,
): boolean {
Expand All @@ -204,10 +208,18 @@ export function generate(
);

const generateNM2 = createNM2Generator({
methodOnly,
namespace,
methodonly,
});

const generateJsiModuleH = require(path.resolve(
rncodegenPath,
'lib/generators/modules/GenerateModuleH',
)).generate;
const generateJsiModuleCpp = require(path.resolve(
rncodegenPath,
'lib/generators/modules/GenerateModuleCpp',
)).generate;
const generatorPropsH = require(path.resolve(
rncodegenPath,
'lib/generators/components/GeneratePropsH',
Expand Down Expand Up @@ -237,33 +249,43 @@ export function generate(
'lib/generators/components/GenerateEventEmitterCpp',
)).generate;

normalizeFileMap(
generateNM2(libraryName, schema, moduleSpecName),
outputDirectory,
generatedFiles,
);
const moduleGenerators = [];

if (ts) {
normalizeFileMap(
generateTypeScript(libraryName, schema, moduleSpecName),
outputDirectory,
generatedFiles,
);
if (modulesWindows) {
moduleGenerators.push(generateNM2);
}

if (modulesCxx) {
moduleGenerators.push(generateJsiModuleH);
moduleGenerators.push(generateJsiModuleCpp);
}

if (modulesTypeScriptTypes) {
moduleGenerators.push(generateTypeScript);
}

moduleGenerators.forEach(generator => {
const generated: Map<string, string> = generator(
libraryName,
schema,
moduleSpecName,
);
normalizeFileMap(generated, outputDirectory, generatedFiles);
});

if (
Object.keys(schema.modules).some(
moduleName => schema.modules[moduleName].type === 'Component',
)
) {
const componentGenerators = [
generatorPropsH,
generatorPropsCPP,
generatorShadowNodeH,
generatorShadowNodeCPP,
generatorComponentDescriptorH,
generatorEventEmitterH,
generatorEventEmitterCPP,
generatorEventEmitterH,
generatorPropsCPP,
generatorPropsH,
generatorShadowNodeCPP,
generatorShadowNodeH,
];

componentGenerators.forEach(generator => {
Expand All @@ -287,10 +309,12 @@ export type CodeGenOptions = {
file?: string;
files?: string[];
libraryName: string;
outdir: string;
methodOnly: boolean;
modulesCxx: boolean;
modulesTypeScriptTypes: boolean;
modulesWindows: boolean;
namespace: string;
methodonly: boolean;
ts: boolean;
outputDirectory: string;
test: boolean;
};

Expand All @@ -304,17 +328,25 @@ export function runCodeGen(options: CodeGenOptions): boolean {

const libraryName = options.libraryName;
const moduleSpecName = 'moduleSpecName';
const outputDirectory = options.outdir;
const {namespace, methodonly, ts} = options;
const {
methodOnly,
modulesCxx,
modulesTypeScriptTypes,
modulesWindows,
namespace,
outputDirectory,
} = options;
return generate(
{
libraryName,
schema,
outputDirectory,
methodOnly,
modulesCxx,
moduleSpecName,
modulesTypeScriptTypes,
modulesWindows,
namespace,
methodonly,
ts,
outputDirectory,
schema,
},
{generators: [], test: options.test},
);
Expand Down
2 changes: 1 addition & 1 deletion packages/sample-apps/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@
"engines": {
"node": ">= 14"
}
}
}
4 changes: 3 additions & 1 deletion packages/sample-apps/windows/SampleAppCPP/App.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@ App::App() noexcept {
InstanceSettings().UseFastRefresh(false);
#else
JavaScriptBundleFile(L"index");
InstanceSettings().UseWebDebugger(true);
InstanceSettings().UseWebDebugger(false);
InstanceSettings().UseFastRefresh(true);
#endif

#if _DEBUG
InstanceSettings().UseDeveloperSupport(true);
InstanceSettings().UseDirectDebugger(true);
#else
InstanceSettings().UseDirectDebugger(false);
InstanceSettings().UseDeveloperSupport(false);
#endif

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,53 +11,26 @@
#include "TestEventService.h"
#include "TestReactNativeHostHolder.h"

#pragma pack(push)
#pragma warning(disable : 4100 4127 4324)
#include "codegen/msrnIntegrationTestsJSI-generated.cpp"
#include "codegen/msrnIntegrationTestsJSI.h"
#pragma pack(pop)

using namespace facebook;
using namespace winrt;
using namespace Microsoft::ReactNative;

namespace ReactNativeIntegrationTests {

// Use anonymous namespace to avoid any linking conflicts
namespace {

// In this test we put spec definition that normally must be generated.
// >>>> Start generated

// The spec from .h file
struct MyTrivialTurboModuleSpec : react::TurboModule {
virtual void startFromJS(jsi::Runtime &rt) = 0;

protected:
MyTrivialTurboModuleSpec(std::shared_ptr<react::CallInvoker> jsInvoker);
};

// The spec from .cpp file

static jsi::Value MyTrivialTurboModuleSpec_startFromJS(
jsi::Runtime &rt,
react::TurboModule &turboModule,
[[maybe_unused]] const jsi::Value *args,
[[maybe_unused]] size_t count) {
assert(count >= 0);
static_cast<MyTrivialTurboModuleSpec *>(&turboModule)->startFromJS(rt);
return jsi::Value::undefined();
}

MyTrivialTurboModuleSpec::MyTrivialTurboModuleSpec(std::shared_ptr<react::CallInvoker> jsInvoker)
: react::TurboModule("MyTrivialTurboModuleSpec", std::move(jsInvoker)) {
methodMap_.try_emplace("startFromJS", MethodMetadata{0, MyTrivialTurboModuleSpec_startFromJS});
}

// <<<< End generated

struct MyTrivialTurboModule : MyTrivialTurboModuleSpec {
struct MyTrivialTurboModule : react::NativeMyTrivialTurboModuleCxxSpecJSI {
MyTrivialTurboModule(std::shared_ptr<react::CallInvoker> jsInvoker);

void startFromJS(jsi::Runtime &rt) override;
};

MyTrivialTurboModule::MyTrivialTurboModule(std::shared_ptr<react::CallInvoker> jsInvoker)
: MyTrivialTurboModuleSpec(std::move(jsInvoker)) {}
: NativeMyTrivialTurboModuleCxxSpecJSI(std::move(jsInvoker)) {}

void MyTrivialTurboModule::startFromJS(jsi::Runtime & /*rt*/) {
TestEventService::LogEvent("startFromJS called", nullptr);
Expand All @@ -70,8 +43,6 @@ struct MyTrivialTurboModulePackageProvider
}
};

} // namespace

TEST_CLASS (JsiSimpleTurboModuleTests) {
TEST_METHOD(TestInstanceReload) {
TestEventService::Initialize();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { TurboModuleRegistry } from 'react-native';
const myTrivialTurboModule = TurboModuleRegistry.getEnforcing('MyTrivialTurboModule');
/**
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*
* @flow
* @format
*/

import {default as myTrivialTurboModule} from './NativeMyTrivialTurboModule';

myTrivialTurboModule.startFromJS();
Loading