@@ -42,6 +42,7 @@ interface MethodSignature {
4242
4343export class ModuleWindowsSetup {
4444 private actualModuleName ?: string ;
45+ private discoveredSpecFiles : string [ ] = [ ] ;
4546 public root : string ;
4647 public options : ModuleWindowsSetupOptions ;
4748
@@ -179,6 +180,8 @@ export class ModuleWindowsSetup {
179180 this . verboseMessage (
180181 `Found valid spec file(s): ${ validSpecFiles . join ( ', ' ) } ` ,
181182 ) ;
183+ // Store the discovered spec files for later use
184+ this . discoveredSpecFiles = validSpecFiles ;
182185 // Extract the actual module name from the existing spec file
183186 await this . extractModuleNameFromExistingSpec ( validSpecFiles [ 0 ] ) ;
184187 }
@@ -702,28 +705,53 @@ export default TurboModuleRegistry.getEnforcing<Spec>('${moduleName}');
702705 const methods = await this . parseSpecFileForMethods ( specName ) ;
703706
704707 // Generate header file with parsed methods
705- const headerContent = this . generateHeaderStub ( specName , methods ) ;
706- if ( ! ( await fs . exists ( headerPath ) ) ) {
707- await fs . writeFile ( headerPath , headerContent ) ;
708- this . verboseMessage ( `Generated header stub: ${ headerPath } ` ) ;
709- }
708+ const headerContent = await this . generateHeaderStub ( specName , methods ) ;
709+ // Always write the header file to ensure it has the correct methods from the spec
710+ await fs . writeFile ( headerPath , headerContent ) ;
711+ this . verboseMessage ( `Generated header stub: ${ headerPath } with ${ methods . length } methods` ) ;
710712
711713 // Generate cpp file with parsed methods
712- const cppContent = this . generateCppStub ( specName , methods ) ;
713- if ( ! ( await fs . exists ( cppPath ) ) ) {
714- await fs . writeFile ( cppPath , cppContent ) ;
715- this . verboseMessage ( `Generated cpp stub: ${ cppPath } ` ) ;
716- }
714+ const cppContent = await this . generateCppStub ( specName , methods ) ;
715+ // Always write the cpp file to ensure it has the correct methods from the spec
716+ await fs . writeFile ( cppPath , cppContent ) ;
717+ this . verboseMessage ( `Generated cpp stub: ${ cppPath } with ${ methods . length } methods` ) ;
717718 }
718719 }
719720
720721 private async parseSpecFileForMethods (
721722 moduleName : string ,
722723 ) : Promise < MethodSignature [ ] > {
723724 try {
724- // Find the spec file
725- const specPattern = `**/Native${ moduleName } .[jt]s` ;
726- const specFiles = glob . sync ( specPattern , { cwd : this . root } ) ;
725+ // First, try to use the previously discovered spec files
726+ let specFiles = this . discoveredSpecFiles ;
727+
728+ // If no discovered spec files, try to find them again with broader patterns
729+ if ( specFiles . length === 0 ) {
730+ this . verboseMessage ( `Searching for spec files for module: ${ moduleName } ` ) ;
731+
732+ // Try multiple patterns to find the spec file
733+ const patterns = [
734+ `**/Native${ moduleName } .[jt]s` ,
735+ `**/Native*${ moduleName } *.[jt]s` ,
736+ `**/Native*.[jt]s` ,
737+ `src/**/Native*.[jt]s` ,
738+ `lib/**/Native*.[jt]s` ,
739+ ] ;
740+
741+ for ( const pattern of patterns ) {
742+ const matches = glob . sync ( pattern , {
743+ cwd : this . root ,
744+ ignore : [ '**/node_modules/**' , '**/build/**' , '**/dist/**' ] ,
745+ } ) ;
746+ if ( matches . length > 0 ) {
747+ specFiles = await this . filterValidSpecFiles ( matches ) ;
748+ if ( specFiles . length > 0 ) {
749+ this . verboseMessage ( `Found spec files with pattern "${ pattern } ": ${ specFiles . join ( ', ' ) } ` ) ;
750+ break ;
751+ }
752+ }
753+ }
754+ }
727755
728756 if ( specFiles . length === 0 ) {
729757 this . verboseMessage (
@@ -732,12 +760,14 @@ export default TurboModuleRegistry.getEnforcing<Spec>('${moduleName}');
732760 return [ ] ;
733761 }
734762
763+ // Use the first valid spec file
735764 const specPath = path . join ( this . root , specFiles [ 0 ] ) ;
765+ this . verboseMessage ( `Reading spec file: ${ specPath } ` ) ;
736766 const specContent = await fs . readFile ( specPath , 'utf8' ) ;
737767
738768 // Parse method signatures from the Spec interface
739769 const methods = this . extractMethodsFromSpecInterface ( specContent ) ;
740- this . verboseMessage ( `Extracted ${ methods . length } methods from spec file` ) ;
770+ this . verboseMessage ( `Extracted ${ methods . length } methods from spec file: ${ methods . map ( m => m . name ) . join ( ', ' ) } ` ) ;
741771 return methods ;
742772 } catch ( error ) {
743773 this . verboseMessage (
@@ -808,10 +838,28 @@ export default TurboModuleRegistry.getEnforcing<Spec>('${moduleName}');
808838 } ) ;
809839 }
810840
811- private generateHeaderStub (
841+ private async getNamespaceInfo ( ) : Promise < { namespace : string , codegenNamespace : string } > {
842+ try {
843+ const packageJsonPath = path . join ( this . root , 'package.json' ) ;
844+ const pkgJson = JSON . parse ( await fs . readFile ( packageJsonPath , 'utf8' ) ) ;
845+ const actualModuleName = this . getActualModuleName ( pkgJson . name || 'SampleModule' ) ;
846+
847+ // Create reasonable namespace from package name
848+ const namespace = this . getModuleName ( pkgJson . name || 'SampleModule' ) ;
849+ const codegenNamespace = `${ namespace } Codegen` ;
850+
851+ return { namespace, codegenNamespace } ;
852+ } catch ( error ) {
853+ // Fallback
854+ return { namespace : 'ReactNativeWebview' , codegenNamespace : 'ReactNativeWebviewCodegen' } ;
855+ }
856+ }
857+
858+ private async generateHeaderStub (
812859 moduleName : string ,
813860 methods : MethodSignature [ ] ,
814- ) : string {
861+ ) : Promise < string > {
862+ const { namespace, codegenNamespace} = await this . getNamespaceInfo ( ) ;
815863 const methodDeclarations = methods
816864 . map ( method => {
817865 const cppParams = method . parameters
@@ -844,29 +892,43 @@ export default TurboModuleRegistry.getEnforcing<Spec>('${moduleName}');
844892
845893 return `#pragma once
846894
847- #include <${ moduleName } Spec.g.h>
848- #include <NativeModules.h>
895+ #include "pch.h"
896+ #include "resource.h"
897+
898+ #if __has_include("codegen/Native${ moduleName } DataTypes.g.h")
899+ #include "codegen/Native${ moduleName } DataTypes.g.h"
900+ #endif
901+ #include "codegen/Native${ moduleName } Spec.g.h"
902+
903+ #include "NativeModules.h"
904+
905+ namespace winrt::${ namespace }
906+ {
849907
850- namespace ${ moduleName } Specs {
908+ // See https://microsoft.github.io/react-native-windows/docs/native-platform for help writing native modules
851909
852910REACT_MODULE(${ moduleName } )
853- struct ${ moduleName } {
854- using ModuleSpec = ${ moduleName } Spec;
855-
911+ struct ${ moduleName }
912+ {
913+ using ModuleSpec = ${ codegenNamespace } ::${ moduleName } Spec;
914+
856915 REACT_INIT(Initialize)
857916 void Initialize(React::ReactContext const &reactContext) noexcept;
858-
917+
859918${ defaultMethods }
919+
920+ private:
921+ React::ReactContext m_context;
860922};
861923
862- } // namespace ${ moduleName } Specs
863- ` ;
924+ } // namespace winrt::${ namespace } ` ;
864925 }
865926
866- private generateCppStub (
927+ private async generateCppStub (
867928 moduleName : string ,
868929 methods : MethodSignature [ ] ,
869- ) : string {
930+ ) : Promise < string > {
931+ const { namespace} = await this . getNamespaceInfo ( ) ;
870932 const methodImplementations = methods
871933 . map ( method => {
872934 const cppParams = method . parameters
@@ -912,15 +974,15 @@ ${defaultMethods}
912974
913975 return `#include "${ moduleName } .h"
914976
915- namespace ${ moduleName } Specs {
977+ namespace winrt:: ${ namespace } {
916978
917979void ${ moduleName } ::Initialize(React::ReactContext const &reactContext) noexcept {
918- // TODO: Initialize your module
980+ m_context = reactContext;
919981}
920982
921983${ defaultImplementations }
922984
923- } // namespace ${ moduleName } Specs
985+ } // namespace winrt:: ${ namespace }
924986` ;
925987 }
926988
@@ -933,6 +995,9 @@ ${defaultImplementations}
933995 any : 'React::JSValue' ,
934996 'any[]' : 'React::JSValueArray' ,
935997 void : 'void' ,
998+ Double : 'double' , // React Native codegen type
999+ Int32 : 'int32_t' , // React Native codegen type
1000+ Float : 'float' , // React Native codegen type
9361001 } ;
9371002
9381003 // Handle array types
0 commit comments