@@ -862,34 +862,67 @@ export default TurboModuleRegistry.getEnforcing<Spec>('${moduleName}');
862862 }
863863 }
864864
865- if ( specFiles . length === 0 ) {
866- this . verboseMessage (
867- `No spec file found for ${ moduleName } , using default methods` ,
868- ) ;
869- return [ ] ;
865+ if ( specFiles . length > 0 ) {
866+ // Use the first valid spec file
867+ const specPath = path . join ( this . root , specFiles [ 0 ] ) ;
868+ this . verboseMessage ( `Reading spec file: ${ specPath } ` ) ;
869+ const specContent = await fs . readFile ( specPath , 'utf8' ) ;
870+
871+ // Parse method signatures from the Spec interface
872+ const methods = this . extractMethodsFromSpecInterface ( specContent ) ;
873+ if ( methods . length > 0 ) {
874+ this . verboseMessage (
875+ `Extracted ${ methods . length } methods from spec file: ${ methods
876+ . map ( m => m . name )
877+ . join ( ', ' ) } `,
878+ ) ;
879+ return methods ;
880+ }
870881 }
871882
872- // Use the first valid spec file
873- const specPath = path . join ( this . root , specFiles [ 0 ] ) ;
874- this . verboseMessage ( `Reading spec file: ${ specPath } ` ) ;
875- const specContent = await fs . readFile ( specPath , 'utf8' ) ;
876-
877- // Parse method signatures from the Spec interface
878- const methods = this . extractMethodsFromSpecInterface ( specContent ) ;
883+ // If no methods found from any source, provide default WebView-like methods
879884 this . verboseMessage (
880- `Extracted ${ methods . length } methods from spec file: ${ methods
881- . map ( m => m . name )
882- . join ( ', ' ) } `,
885+ `No spec file found for ${ moduleName } , using default WebView-like methods` ,
883886 ) ;
884- return methods ;
887+ return this . getDefaultWebViewMethods ( ) ;
885888 } catch ( error ) {
886889 this . verboseMessage (
887890 `Could not parse spec file for ${ moduleName } : ${ error } ` ,
888891 ) ;
889- return [ ] ;
892+ return this . getDefaultWebViewMethods ( ) ;
890893 }
891894 }
892895
896+ private getDefaultWebViewMethods ( ) : MethodSignature [ ] {
897+ return [
898+ {
899+ name : 'MessagingEnabled' ,
900+ returnType : 'void' ,
901+ parameters : [ { name : 'enabled' , type : 'boolean' } ] ,
902+ } ,
903+ {
904+ name : 'MessagingEnabled' ,
905+ returnType : 'boolean' ,
906+ parameters : [ ] ,
907+ } ,
908+ {
909+ name : 'SetInjectedJavascript' ,
910+ returnType : 'void' ,
911+ parameters : [ { name : 'payload' , type : 'string' } ] ,
912+ } ,
913+ {
914+ name : 'RequestFocus' ,
915+ returnType : 'void' ,
916+ parameters : [ ] ,
917+ } ,
918+ {
919+ name : 'PostMessage' ,
920+ returnType : 'void' ,
921+ parameters : [ { name : 'message' , type : 'string' } ] ,
922+ } ,
923+ ] ;
924+ }
925+
893926 private async parseCodegenHeaderFiles (
894927 codegenDir : string ,
895928 moduleName : string
@@ -957,6 +990,78 @@ export default TurboModuleRegistry.getEnforcing<Spec>('${moduleName}');
957990 }
958991 }
959992
993+ // Try parsing directly from C++ method declarations in the header
994+ if ( methods . length === 0 ) {
995+ this . verboseMessage ( 'Trying to parse C++ method declarations directly...' ) ;
996+
997+ // Look for virtual method declarations like:
998+ // virtual void MethodName(parameters) = 0;
999+ const virtualMethodPattern = / v i r t u a l \s + ( \w + (?: \s * \* ) ? ) \s + ( \w + ) \s * \( ( [ ^ ) ] * ) \) \s * (?: c o n s t \s * ) ? = \s * 0 \s * ; / g;
1000+
1001+ while ( ( match = virtualMethodPattern . exec ( content ) ) !== null ) {
1002+ const returnType = match [ 1 ] . trim ( ) ;
1003+ const methodName = match [ 2 ] ;
1004+ const paramString = match [ 3 ] ;
1005+ const parameters = this . parseCodegenParameters ( paramString ) ;
1006+
1007+ methods . push ( {
1008+ name : methodName ,
1009+ returnType : returnType === 'void' ? 'void' : returnType ,
1010+ parameters : parameters ,
1011+ } ) ;
1012+ }
1013+ }
1014+
1015+ // Try parsing from JSI method declarations
1016+ if ( methods . length === 0 ) {
1017+ this . verboseMessage ( 'Trying to parse JSI method declarations...' ) ;
1018+
1019+ // Look for JSI-style method declarations
1020+ const jsiMethodPattern = / s t a t i c \s + j s i : : V a l u e \s + _ _ h o s t F u n c t i o n _ ( \w + ) \s * \( [ ^ ) ] * \) \s * { / g;
1021+
1022+ while ( ( match = jsiMethodPattern . exec ( content ) ) !== null ) {
1023+ const methodName = match [ 1 ] ;
1024+
1025+ methods . push ( {
1026+ name : methodName ,
1027+ returnType : 'void' ,
1028+ parameters : [ ] , // JSI methods will be parsed separately for parameters
1029+ } ) ;
1030+ }
1031+ }
1032+
1033+ // Try parsing from struct member methods
1034+ if ( methods . length === 0 ) {
1035+ this . verboseMessage ( 'Trying to parse struct member methods...' ) ;
1036+
1037+ // Look for struct methods like:
1038+ // bool MessagingEnabled() const;
1039+ // void MessagingEnabled(bool enabled);
1040+ const structMethodPattern = / ^ \s * (?: v i r t u a l \s + ) ? ( \w + (?: \s * & ) ? ) \s + ( \w + ) \s * \( ( [ ^ ) ] * ) \) \s * (?: c o n s t \s * ) ? (?: n o e x c e p t \s * ) ? (?: = \s * 0 \s * ) ? ; / gm;
1041+
1042+ while ( ( match = structMethodPattern . exec ( content ) ) !== null ) {
1043+ const returnType = match [ 1 ] . trim ( ) ;
1044+ const methodName = match [ 2 ] ;
1045+ const paramString = match [ 3 ] ;
1046+ const parameters = this . parseCodegenParameters ( paramString ) ;
1047+
1048+ // Skip common non-API methods
1049+ if ( ! methodName . startsWith ( '~' ) &&
1050+ ! methodName . includes ( 'Destructor' ) &&
1051+ ! methodName . includes ( 'Constructor' ) &&
1052+ methodName !== 'getContext' &&
1053+ methodName !== 'invalidate' ) {
1054+
1055+ methods . push ( {
1056+ name : methodName ,
1057+ returnType : returnType === 'void' ? 'void' : returnType ,
1058+ parameters : parameters ,
1059+ } ) ;
1060+ }
1061+ }
1062+ }
1063+
1064+ this . verboseMessage ( `Extracted ${ methods . length } methods from codegen header using multiple parsing strategies` ) ;
9601065 return methods ;
9611066 }
9621067
@@ -1019,20 +1124,27 @@ export default TurboModuleRegistry.getEnforcing<Spec>('${moduleName}');
10191124
10201125 // Extract parameter name from the end
10211126 const parts = param . split ( / \s + / ) ;
1022- const name = parts [ parts . length - 1 ] . replace ( / [ & * ] / g, '' ) ; // Remove references/pointers
1127+ let name = parts [ parts . length - 1 ] . replace ( / [ & * ] / g, '' ) ; // Remove references/pointers
1128+
1129+ // Handle winrt types and const references
1130+ if ( name . includes ( 'const' ) ) {
1131+ name = parts [ parts . length - 2 ] || 'param' ;
1132+ }
10231133
10241134 // Map common codegen types
10251135 let type = 'any' ;
1026- if ( param . includes ( 'std::string' ) ) {
1136+ if ( param . includes ( 'std::string' ) || param . includes ( 'winrt::hstring' ) ) {
10271137 type = 'string' ;
1028- } else if ( param . includes ( 'double' ) ) {
1138+ } else if ( param . includes ( 'double' ) || param . includes ( 'float' ) ) {
10291139 type = 'number' ;
10301140 } else if ( param . includes ( 'bool' ) ) {
10311141 type = 'boolean' ;
1032- } else if ( param . includes ( 'int32_t' ) || param . includes ( 'int' ) ) {
1142+ } else if ( param . includes ( 'int32_t' ) || param . includes ( 'int64_t' ) || param . includes ( ' int') ) {
10331143 type = 'number' ;
10341144 } else if ( param . includes ( 'JSValue' ) ) {
10351145 type = 'any' ;
1146+ } else if ( param . includes ( 'winrt::' ) ) {
1147+ type = 'string' ; // Most winrt types are strings or can be treated as such
10361148 }
10371149
10381150 return { name : name || 'param' , type } ;
@@ -1153,13 +1265,23 @@ export default TurboModuleRegistry.getEnforcing<Spec>('${moduleName}');
11531265 return `std::function<void()> const & ${ p . name } ` ;
11541266 }
11551267 } else {
1156- return `${ this . mapTSToCppType ( p . type ) } ${ p . name } ` ;
1268+ let cppType = this . mapTSToCppType ( p . type ) ;
1269+ // Use winrt::hstring for string parameters to match Windows conventions
1270+ if ( p . type === 'string' ) {
1271+ cppType = 'winrt::hstring const&' ;
1272+ }
1273+ return `${ cppType } ${ p . name } ` ;
11571274 }
11581275 } )
11591276 . join ( ', ' ) ;
11601277
1278+ // Determine if this is a getter method (no parameters and non-void return type)
1279+ const isGetter = method . parameters . length === 0 && method . returnType !== 'void' ;
1280+ const returnType = isGetter ? this . mapTSToCppType ( method . returnType ) : 'void' ;
1281+ const constModifier = isGetter ? ' const' : '' ;
1282+
11611283 return ` REACT_METHOD(${ method . name } )
1162- void ${ method . name } (${ cppParams } ) noexcept;` ;
1284+ ${ returnType } ${ method . name } (${ cppParams } ) noexcept${ constModifier } ;` ;
11631285 } )
11641286 . join ( '\n\n' ) ;
11651287
@@ -1224,26 +1346,40 @@ private:
12241346 return `std::function<void()> const & ${ p . name } ` ;
12251347 }
12261348 } else {
1227- return `${ this . mapTSToCppType ( p . type ) } ${ p . name } ` ;
1349+ let cppType = this . mapTSToCppType ( p . type ) ;
1350+ // Use winrt::hstring for string parameters to match Windows conventions
1351+ if ( p . type === 'string' ) {
1352+ cppType = 'winrt::hstring const&' ;
1353+ }
1354+ return `${ cppType } ${ p . name } ` ;
12281355 }
12291356 } )
12301357 . join ( ', ' ) ;
12311358
1232- // Generate implementation based on callback pattern
1359+ // Determine if this is a getter method (no parameters and non-void return type)
1360+ const isGetter = method . parameters . length === 0 && method . returnType !== 'void' ;
1361+ const returnType = isGetter ? this . mapTSToCppType ( method . returnType ) : 'void' ;
1362+ const constModifier = isGetter ? ' const' : '' ;
1363+
1364+ // Generate implementation based on method type
12331365 const hasCallback = method . parameters . some ( p => p . type === 'function' && ( p . name . includes ( 'onSuccess' ) || p . name === 'callback' ) ) ;
12341366 const hasErrorCallback = method . parameters . some ( p => p . type === 'function' && p . name . includes ( 'onError' ) ) ;
12351367
12361368 let implementation = ` // TODO: Implement ${ method . name } ` ;
12371369
1238- if ( hasCallback && hasErrorCallback ) {
1370+ if ( isGetter ) {
1371+ // Getter method - return default value
1372+ const defaultValue = this . generateDefaultValue ( method . returnType ) ;
1373+ implementation += `\n return ${ defaultValue } ;` ;
1374+ } else if ( hasCallback && hasErrorCallback ) {
12391375 // Method with success and error callbacks
12401376 implementation += `\n // Example: callback(); // Call on success\n // Example: onError(React::JSValue{"Error message"}); // Call on error` ;
12411377 } else if ( hasCallback ) {
12421378 // Method with just callback
12431379 implementation += `\n // Example: callback(); // Call when complete` ;
12441380 }
12451381
1246- return `void ${ moduleName } ::${ method . name } (${ cppParams } ) noexcept {
1382+ return `${ returnType } ${ moduleName } ::${ method . name } (${ cppParams } ) noexcept${ constModifier } {
12471383${ implementation }
12481384}` ;
12491385 } )
0 commit comments