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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "forking GenerateModuleCpp",
"packageName": "@react-native-windows/codegen",
"email": "66076509+vineethkuttan@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "forking GenerateModuleCpp",
"packageName": "react-native-windows",
"email": "66076509+vineethkuttan@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/

'use strict';

const path = require('path');

// Load dependencies from @react-native/codegen
const rnPath = path.dirname(require.resolve('react-native/package.json'));
const rncodegenPath = path.dirname(
require.resolve('@react-native/codegen/package.json', {paths: [rnPath]}),
);

const {unwrapNullable} = require(
path.resolve(rncodegenPath, 'lib/parsers/parsers-commons'),
);
const {createAliasResolver, getModules} = require(
path.resolve(rncodegenPath, 'lib/generators/modules/Utils'),
);
const HostFunctionTemplate = ({
hasteModuleName,
methodName,
returnTypeAnnotation,
args,
}) => {
const isNullable = returnTypeAnnotation.type === 'NullableTypeAnnotation';
const isVoid = returnTypeAnnotation.type === 'VoidTypeAnnotation';
const methodCallArgs = [' rt', ...args].join(',\n ');
const methodCall = `static_cast<${hasteModuleName}CxxSpecJSI *>(&turboModule)->${methodName}(\n${methodCallArgs}\n )`;
return `static jsi::Value __hostFunction_${hasteModuleName}CxxSpecJSI_${methodName}(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {${isVoid ? `\n ${methodCall};` : isNullable ? `\n auto result = ${methodCall};` : ''}
return ${isVoid ? 'jsi::Value::undefined()' : isNullable ? 'result ? jsi::Value(std::move(*result)) : jsi::Value::null()' : methodCall};
}`;
};
const ModuleTemplate = ({
hasteModuleName,
hostFunctions,
moduleName,
methods,
}) => {
return `${hostFunctions.join('\n')}

${hasteModuleName}CxxSpecJSI::${hasteModuleName}CxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker)
: TurboModule("${moduleName}", jsInvoker) {
${methods
.map(({methodName, paramCount}) => {
return ` methodMap_["${methodName}"] = MethodMetadata {${paramCount}, __hostFunction_${hasteModuleName}CxxSpecJSI_${methodName}};`;
})
.join('\n')}
}`;
};
const FileTemplate = ({libraryName, modules}) => {
return `/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* ${'@'}generated by codegen project: GenerateModuleCpp.js
*/

#include "${libraryName}JSI.h"

namespace facebook::react {

${modules}


} // namespace facebook::react
`;
};
function serializeArg(moduleName, arg, index, resolveAlias, enumMap) {
const {typeAnnotation: nullableTypeAnnotation, optional} = arg;
const [typeAnnotation, nullable] = unwrapNullable(nullableTypeAnnotation);
let realTypeAnnotation = typeAnnotation;
if (realTypeAnnotation.type === 'TypeAliasTypeAnnotation') {
realTypeAnnotation = resolveAlias(realTypeAnnotation.name);
}
function wrap(callback) {
const val = `args[${index}]`;
const expression = callback(val);

// param?: T
if (optional && !nullable) {
// throw new Error('are we hitting this case? ' + moduleName);
return `count <= ${index} || ${val}.isUndefined() ? std::nullopt : std::make_optional(${expression})`;
}

// param: ?T
// param?: ?T
if (nullable || optional) {
return `count <= ${index} || ${val}.isNull() || ${val}.isUndefined() ? std::nullopt : std::make_optional(${expression})`;
}

// param: T
//return `count <= ${index} ? throw jsi::JSError(rt, "Expected argument in position ${index} to be passed") : ${expression}`;
//Windows #15545
return `(count > ${index} || (throw jsi::JSError(rt, "Expected argument in position ${index} to be passed"), false), ${expression})`;
Copy link
Contributor

@iamAbhi-916 iamAbhi-916 Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to me!

//Windows
}
switch (realTypeAnnotation.type) {
case 'ReservedTypeAnnotation':
switch (realTypeAnnotation.name) {
case 'RootTag':
return wrap(val => `${val}.asNumber()`);
default:
realTypeAnnotation.name;
throw new Error(
`Unknown prop type for "${arg.name}, found: ${realTypeAnnotation.name}"`,
);
}
case 'StringTypeAnnotation':
return wrap(val => `${val}.asString(rt)`);
case 'StringLiteralTypeAnnotation':
return wrap(val => `${val}.asString(rt)`);
case 'StringLiteralUnionTypeAnnotation':
return wrap(val => `${val}.asString(rt)`);
case 'BooleanTypeAnnotation':
return wrap(val => `${val}.asBool()`);
case 'EnumDeclaration':
switch (realTypeAnnotation.memberType) {
case 'NumberTypeAnnotation':
return wrap(val => `${val}.asNumber()`);
case 'StringTypeAnnotation':
return wrap(val => `${val}.asString(rt)`);
default:
throw new Error(
`Unknown enum type for "${arg.name}, found: ${realTypeAnnotation.type}"`,
);
}
case 'NumberTypeAnnotation':
return wrap(val => `${val}.asNumber()`);
case 'FloatTypeAnnotation':
return wrap(val => `${val}.asNumber()`);
case 'DoubleTypeAnnotation':
return wrap(val => `${val}.asNumber()`);
case 'Int32TypeAnnotation':
return wrap(val => `${val}.asNumber()`);
case 'NumberLiteralTypeAnnotation':
return wrap(val => `${val}.asNumber()`);
case 'ArrayTypeAnnotation':
return wrap(val => `${val}.asObject(rt).asArray(rt)`);
case 'FunctionTypeAnnotation':
return wrap(val => `${val}.asObject(rt).asFunction(rt)`);
case 'GenericObjectTypeAnnotation':
return wrap(val => `${val}.asObject(rt)`);
case 'UnionTypeAnnotation':
switch (typeAnnotation.memberType) {
case 'NumberTypeAnnotation':
return wrap(val => `${val}.asNumber()`);
case 'ObjectTypeAnnotation':
return wrap(val => `${val}.asObject(rt)`);
case 'StringTypeAnnotation':
return wrap(val => `${val}.asString(rt)`);
default:
throw new Error(
`Unsupported union member type for param "${arg.name}, found: ${realTypeAnnotation.memberType}"`,
);
}
case 'ObjectTypeAnnotation':
return wrap(val => `${val}.asObject(rt)`);
case 'MixedTypeAnnotation':
return wrap(val => `jsi::Value(rt, ${val})`);
default:
realTypeAnnotation.type;
throw new Error(
`Unknown prop type for "${arg.name}, found: ${realTypeAnnotation.type}"`,
);
}
}
function serializePropertyIntoHostFunction(
moduleName,
hasteModuleName,
property,
resolveAlias,
enumMap,
) {
const [propertyTypeAnnotation] = unwrapNullable(property.typeAnnotation);
return HostFunctionTemplate({
hasteModuleName,
methodName: property.name,
returnTypeAnnotation: propertyTypeAnnotation.returnTypeAnnotation,
args: propertyTypeAnnotation.params.map((p, i) =>
serializeArg(moduleName, p, i, resolveAlias, enumMap),
),
});
}
module.exports = {
generate(
libraryName,
schema,
packageName,
assumeNonnull = false,
headerPrefix,
) {
const nativeModules = getModules(schema);
const modules = Object.keys(nativeModules)
.map(hasteModuleName => {
const nativeModule = nativeModules[hasteModuleName];
const {
aliasMap,
enumMap,
spec: {methods},
moduleName,
} = nativeModule;
const resolveAlias = createAliasResolver(aliasMap);
const hostFunctions = methods.map(property =>
serializePropertyIntoHostFunction(
moduleName,
hasteModuleName,
property,
resolveAlias,
enumMap,
),
);
return ModuleTemplate({
hasteModuleName,
hostFunctions,
moduleName,
methods: methods.map(
({name: propertyName, typeAnnotation: nullableTypeAnnotation}) => {
const [{params}] = unwrapNullable(nullableTypeAnnotation);
return {
methodName: propertyName,
paramCount: params.length,
};
},
),
});
})
.join('\n');
const fileName = `${libraryName}JSI-generated.cpp`;
const replacedTemplate = FileTemplate({
modules,
libraryName,
});
return new Map([[fileName, replacedTemplate]]);
},
};
8 changes: 4 additions & 4 deletions packages/@react-native-windows/codegen/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,10 +254,10 @@ export function generate(
rncodegenPath,
'lib/generators/modules/GenerateModuleH',
)).generate;
const generateJsiModuleCpp = require(path.resolve(
rncodegenPath,
'lib/generators/modules/GenerateModuleCpp',
)).generate;
// Use local fixed version instead of upstream to fix x86 union padding issue
// with MixedTypeAnnotation. See GenerateModuleCpp.js for details.
const generateJsiModuleCpp =
require('./generators/GenerateModuleCpp').generate;
const generatorPropsH = require(path.resolve(
rncodegenPath,
'lib/generators/components/GeneratePropsH',
Expand Down
13 changes: 10 additions & 3 deletions packages/@react-native-windows/codegen/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
{
"extends": "@rnw-scripts/ts-config",
"include": ["src"],
"exclude": ["node_modules"]
}
"compilerOptions": {
"allowJs": true
},
"include": [
"src"
],
"exclude": [
"node_modules"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ static jsi::Value __hostFunction_NativeMySimpleTurboModuleCxxCxxSpecJSI_getConst
static jsi::Value __hostFunction_NativeMySimpleTurboModuleCxxCxxSpecJSI_logAction(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
static_cast<NativeMySimpleTurboModuleCxxCxxSpecJSI *>(&turboModule)->logAction(
rt,
count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt),
count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : jsi::Value(rt, args[1])
(count > 0 || (throw jsi::JSError(rt, "Expected argument in position 0 to be passed"), false), args[0].asString(rt)),
(count > 1 || (throw jsi::JSError(rt, "Expected argument in position 1 to be passed"), false), jsi::Value(rt, args[1]))
);
return jsi::Value::undefined();
}
Expand All @@ -33,52 +33,52 @@ static jsi::Value __hostFunction_NativeMySimpleTurboModuleCxxCxxSpecJSI_voidFunc
static jsi::Value __hostFunction_NativeMySimpleTurboModuleCxxCxxSpecJSI_getBool(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<NativeMySimpleTurboModuleCxxCxxSpecJSI *>(&turboModule)->getBool(
rt,
count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asBool()
(count > 0 || (throw jsi::JSError(rt, "Expected argument in position 0 to be passed"), false), args[0].asBool())
);
}
static jsi::Value __hostFunction_NativeMySimpleTurboModuleCxxCxxSpecJSI_getNumber(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<NativeMySimpleTurboModuleCxxCxxSpecJSI *>(&turboModule)->getNumber(
rt,
count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber()
(count > 0 || (throw jsi::JSError(rt, "Expected argument in position 0 to be passed"), false), args[0].asNumber())
);
}
static jsi::Value __hostFunction_NativeMySimpleTurboModuleCxxCxxSpecJSI_getString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<NativeMySimpleTurboModuleCxxCxxSpecJSI *>(&turboModule)->getString(
rt,
count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt)
(count > 0 || (throw jsi::JSError(rt, "Expected argument in position 0 to be passed"), false), args[0].asString(rt))
);
}
static jsi::Value __hostFunction_NativeMySimpleTurboModuleCxxCxxSpecJSI_getArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<NativeMySimpleTurboModuleCxxCxxSpecJSI *>(&turboModule)->getArray(
rt,
count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asObject(rt).asArray(rt)
(count > 0 || (throw jsi::JSError(rt, "Expected argument in position 0 to be passed"), false), args[0].asObject(rt).asArray(rt))
);
}
static jsi::Value __hostFunction_NativeMySimpleTurboModuleCxxCxxSpecJSI_getObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<NativeMySimpleTurboModuleCxxCxxSpecJSI *>(&turboModule)->getObject(
rt,
count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asObject(rt)
(count > 0 || (throw jsi::JSError(rt, "Expected argument in position 0 to be passed"), false), args[0].asObject(rt))
);
}
static jsi::Value __hostFunction_NativeMySimpleTurboModuleCxxCxxSpecJSI_getValue(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<NativeMySimpleTurboModuleCxxCxxSpecJSI *>(&turboModule)->getValue(
rt,
count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber(),
count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt),
count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asObject(rt)
(count > 0 || (throw jsi::JSError(rt, "Expected argument in position 0 to be passed"), false), args[0].asNumber()),
(count > 1 || (throw jsi::JSError(rt, "Expected argument in position 1 to be passed"), false), args[1].asString(rt)),
(count > 2 || (throw jsi::JSError(rt, "Expected argument in position 2 to be passed"), false), args[2].asObject(rt))
);
}
static jsi::Value __hostFunction_NativeMySimpleTurboModuleCxxCxxSpecJSI_getValueWithCallback(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
static_cast<NativeMySimpleTurboModuleCxxCxxSpecJSI *>(&turboModule)->getValueWithCallback(
rt,
count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asObject(rt).asFunction(rt)
(count > 0 || (throw jsi::JSError(rt, "Expected argument in position 0 to be passed"), false), args[0].asObject(rt).asFunction(rt))
);
return jsi::Value::undefined();
}
static jsi::Value __hostFunction_NativeMySimpleTurboModuleCxxCxxSpecJSI_getValueWithPromise(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<NativeMySimpleTurboModuleCxxCxxSpecJSI *>(&turboModule)->getValueWithPromise(
rt,
count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asBool()
(count > 0 || (throw jsi::JSError(rt, "Expected argument in position 0 to be passed"), false), args[0].asBool())
);
}

Expand Down
Loading