@@ -42,6 +42,13 @@ interface MethodSignature {
4242
4343export class ModuleWindowsSetup {
4444 private actualModuleName ?: string ;
45+ private root : string ;
46+ private options : ModuleWindowsSetupOptions ;
47+
48+ constructor ( root : string , options : ModuleWindowsSetupOptions ) {
49+ this . root = root ;
50+ this . options = options ;
51+ }
4552
4653 private async validateEnvironment ( ) : Promise < void > {
4754 this . verboseMessage ( 'Validating environment...' ) ;
@@ -69,10 +76,7 @@ export class ModuleWindowsSetup {
6976 if ( error . code === 'NoProjectName' ) {
7077 throw error ;
7178 }
72- throw new CodedError (
73- 'NoPackageJson' ,
74- 'package.json is not valid JSON.' ,
75- ) ;
79+ throw new CodedError ( 'NoPackageJson' , 'package.json is not valid JSON.' ) ;
7680 }
7781
7882 // Check if yarn is available
@@ -87,18 +91,26 @@ export class ModuleWindowsSetup {
8791 }
8892 }
8993
90- private async extractModuleNameFromExistingSpec ( specFilePath : string ) : Promise < void > {
94+ private async extractModuleNameFromExistingSpec (
95+ specFilePath : string ,
96+ ) : Promise < void > {
9197 try {
9298 const fullPath = path . join ( this . root , specFilePath ) ;
9399 const content = await fs . readFile ( fullPath , 'utf8' ) ;
94-
100+
95101 // Extract the module name from TurboModuleRegistry.getEnforcing<Spec>('ModuleName')
96- const exportMatch = content . match ( / T u r b o M o d u l e R e g i s t r y \. g e t E n f o r c i n g < S p e c > \( [ ' " ` ] ( [ ^ ' " ` ] + ) [ ' " ` ] \) / ) ;
102+ const exportMatch = content . match (
103+ / T u r b o M o d u l e R e g i s t r y \. g e t E n f o r c i n g < S p e c > \( [ ' " ` ] ( [ ^ ' " ` ] + ) [ ' " ` ] \) / ,
104+ ) ;
97105 if ( exportMatch ) {
98106 this . actualModuleName = exportMatch [ 1 ] ;
99- this . verboseMessage ( `Extracted actual module name: ${ this . actualModuleName } ` ) ;
107+ this . verboseMessage (
108+ `Extracted actual module name: ${ this . actualModuleName } ` ,
109+ ) ;
100110 } else {
101- this . verboseMessage ( 'Could not extract module name from spec file, using package name conversion' ) ;
111+ this . verboseMessage (
112+ 'Could not extract module name from spec file, using package name conversion' ,
113+ ) ;
102114 }
103115 } catch ( error ) {
104116 this . verboseMessage ( `Error reading spec file: ${ error } ` ) ;
@@ -110,55 +122,11 @@ export class ModuleWindowsSetup {
110122 if ( this . actualModuleName ) {
111123 return this . actualModuleName ;
112124 }
113-
125+
114126 // Otherwise, fall back to the package name conversion
115127 return this . getModuleName ( packageName ) ;
116128 }
117129
118- private async validateEnvironment ( ) : Promise < void > {
119- this . verboseMessage ( 'Validating environment...' ) ;
120-
121- // Check if package.json exists
122- const packageJsonPath = path . join ( this . root , 'package.json' ) ;
123- if ( ! ( await fs . exists ( packageJsonPath ) ) ) {
124- throw new CodedError (
125- 'NoPackageJson' ,
126- 'No package.json found. Make sure you are in a React Native project directory.' ,
127- ) ;
128- }
129-
130- // Check if it's a valid npm package
131- try {
132- const pkgJson = JSON . parse ( await fs . readFile ( packageJsonPath , 'utf8' ) ) ;
133- if ( ! pkgJson . name ) {
134- throw new CodedError (
135- 'NoProjectName' ,
136- 'package.json must have a "name" field.' ,
137- ) ;
138- }
139- this . verboseMessage ( `Project name: ${ pkgJson . name } ` ) ;
140- } catch ( error : any ) {
141- if ( error . code === 'NoProjectName' ) {
142- throw error ;
143- }
144- throw new CodedError (
145- 'NoPackageJson' ,
146- 'package.json is not valid JSON.' ,
147- ) ;
148- }
149-
150- // Check if yarn is available
151- try {
152- execSync ( 'yarn --version' , { stdio : 'ignore' } ) ;
153- this . verboseMessage ( 'Yarn found' ) ;
154- } catch {
155- throw new CodedError (
156- 'Unknown' ,
157- 'Yarn is required but not found. Please install Yarn first.' ,
158- ) ;
159- }
160- }
161-
162130 private verboseMessage ( message : any ) {
163131 if ( this . options . logging ) {
164132 console . log ( `[ModuleWindowsSetup] ${ message } ` ) ;
@@ -183,17 +151,17 @@ export class ModuleWindowsSetup {
183151 // Look for spec files in common locations, excluding node_modules
184152 const specPatterns = [
185153 'Native*.[jt]s' ,
186- 'src/**/Native*.[jt]s' ,
154+ 'src/**/Native*.[jt]s' ,
187155 'lib/**/Native*.[jt]s' ,
188156 'js/**/Native*.[jt]s' ,
189- 'ts/**/Native*.[jt]s'
157+ 'ts/**/Native*.[jt]s' ,
190158 ] ;
191-
159+
192160 const specFiles : string [ ] = [ ] ;
193161 for ( const pattern of specPatterns ) {
194162 const matches = glob . sync ( pattern , {
195163 cwd : this . root ,
196- ignore : [ '**/node_modules/**' , '**/build/**' , '**/dist/**' ]
164+ ignore : [ '**/node_modules/**' , '**/build/**' , '**/dist/**' ] ,
197165 } ) ;
198166 specFiles . push ( ...matches ) ;
199167 }
@@ -203,24 +171,28 @@ export class ModuleWindowsSetup {
203171 const validSpecFiles = await this . filterValidSpecFiles ( uniqueSpecFiles ) ;
204172
205173 if ( validSpecFiles . length === 0 ) {
206- this . verboseMessage ( 'No valid TurboModule spec file found, analyzing existing APIs...' ) ;
174+ this . verboseMessage (
175+ 'No valid TurboModule spec file found, analyzing existing APIs...' ,
176+ ) ;
207177 await this . analyzeAndCreateSpecFile ( ) ;
208178 } else {
209- this . verboseMessage ( `Found valid spec file(s): ${ validSpecFiles . join ( ', ' ) } ` ) ;
179+ this . verboseMessage (
180+ `Found valid spec file(s): ${ validSpecFiles . join ( ', ' ) } ` ,
181+ ) ;
210182 // Extract the actual module name from the existing spec file
211183 await this . extractModuleNameFromExistingSpec ( validSpecFiles [ 0 ] ) ;
212184 }
213185 }
214186
215187 private async filterValidSpecFiles ( specFiles : string [ ] ) : Promise < string [ ] > {
216188 const validFiles : string [ ] = [ ] ;
217-
189+
218190 for ( const file of specFiles ) {
219191 try {
220192 const filePath = path . join ( this . root , file ) ;
221193 if ( await fs . exists ( filePath ) ) {
222194 const content = await fs . readFile ( filePath , 'utf8' ) ;
223-
195+
224196 // Check if it's a valid TurboModule spec file
225197 if ( this . isValidTurboModuleSpec ( content ) ) {
226198 validFiles . push ( file ) ;
@@ -230,17 +202,17 @@ export class ModuleWindowsSetup {
230202 this . verboseMessage ( `Could not read spec file ${ file } : ${ error } ` ) ;
231203 }
232204 }
233-
205+
234206 return validFiles ;
235207 }
236208
237209 private isValidTurboModuleSpec ( content : string ) : boolean {
238210 // Check for TurboModule indicators
239211 return (
240- content . includes ( 'TurboModule' ) &&
241- ( content . includes ( 'export interface Spec' ) ||
242- content . includes ( 'extends TurboModule' ) ||
243- content . includes ( 'TurboModuleRegistry' ) )
212+ content . includes ( 'TurboModule' ) &&
213+ ( content . includes ( 'export interface Spec' ) ||
214+ content . includes ( 'extends TurboModule' ) ||
215+ content . includes ( 'TurboModuleRegistry' ) )
244216 ) ;
245217 }
246218
@@ -571,7 +543,9 @@ export default TurboModuleRegistry.getEnforcing<Spec>('${moduleName}');
571543 const pkgJson = JSON . parse ( await fs . readFile ( packageJsonPath , 'utf8' ) ) ;
572544
573545 if ( ! pkgJson . codegenConfig ) {
574- const moduleName = this . getActualModuleName ( pkgJson . name || 'SampleModule' ) ;
546+ const moduleName = this . getActualModuleName (
547+ pkgJson . name || 'SampleModule' ,
548+ ) ;
575549
576550 pkgJson . codegenConfig = {
577551 name : moduleName ,
@@ -585,28 +559,14 @@ export default TurboModuleRegistry.getEnforcing<Spec>('${moduleName}');
585559 } ;
586560
587561 await fs . writeFile ( packageJsonPath , JSON . stringify ( pkgJson , null , 2 ) ) ;
588- this . verboseMessage ( `Added codegenConfig to package.json with module name: ${ moduleName } ` ) ;
562+ this . verboseMessage (
563+ `Added codegenConfig to package.json with module name: ${ moduleName } ` ,
564+ ) ;
589565 } else {
590566 this . verboseMessage ( 'codegenConfig already exists in package.json' ) ;
591567 }
592568 }
593569
594-
595- private async removeDirectoryRecursive ( dirPath : string ) : Promise < void > {
596- const entries = await fs . readdir ( dirPath , { withFileTypes : true } ) ;
597-
598- for ( const entry of entries ) {
599- const fullPath = path . join ( dirPath , entry . name ) ;
600- if ( entry . isDirectory ( ) ) {
601- await this . removeDirectoryRecursive ( fullPath ) ;
602- } else {
603- await fs . unlink ( fullPath ) ;
604- }
605- }
606-
607- await fs . rmdir ( dirPath ) ;
608- }
609-
610570 private async upgradeDependencies ( ) : Promise < void > {
611571 if ( this . options . skipDeps ) {
612572 this . verboseMessage ( 'Skipping dependency upgrades' ) ;
@@ -1056,18 +1016,19 @@ ${defaultImplementations}
10561016 }
10571017
10581018 private async cleanAndInstallDeps ( ) : Promise < void > {
1059- this . verboseMessage (
1060- 'Cleaning node_modules and reinstalling dependencies...' ,
1061- ) ;
1019+ this . verboseMessage ( 'Installing dependencies...' ) ;
10621020
1063- const nodeModulesPath = path . join ( this . root , 'node_modules' ) ;
1064- if ( await fs . exists ( nodeModulesPath ) ) {
1065- await this . removeDirectoryRecursive ( nodeModulesPath ) ;
1066- this . verboseMessage ( 'Removed node_modules' ) ;
1021+ // Skip node_modules cleaning as it can cause permission issues on Windows
1022+ // and yarn install will handle dependency updates anyway
1023+ try {
1024+ execSync ( 'yarn install' , { cwd : this . root , stdio : 'inherit' } ) ;
1025+ this . verboseMessage ( 'Dependencies installed' ) ;
1026+ } catch ( error : any ) {
1027+ throw new CodedError (
1028+ 'Unknown' ,
1029+ `Failed to install dependencies: ${ error . message } ` ,
1030+ ) ;
10671031 }
1068-
1069- execSync ( 'yarn install' , { cwd : this . root , stdio : 'inherit' } ) ;
1070- this . verboseMessage ( 'Dependencies installed' ) ;
10711032 }
10721033
10731034 public async run ( spinner : Ora , config : Config ) : Promise < void > {
@@ -1078,15 +1039,12 @@ ${defaultImplementations}
10781039 spinner . text = 'Updating package.json...' ;
10791040
10801041 await this . updatePackageJsonCodegen ( ) ;
1081- spinner . text = 'Cleaning and installing dependencies...' ;
1042+ spinner . text = 'Installing dependencies...' ;
10821043
10831044 await this . cleanAndInstallDeps ( ) ;
10841045 spinner . text = 'Upgrading dependencies...' ;
10851046
10861047 await this . upgradeDependencies ( ) ;
1087- spinner . text = 'Running yarn install...' ;
1088-
1089- execSync ( 'yarn install' , { cwd : this . root , stdio : 'inherit' } ) ;
10901048 spinner . text = 'Setting up Windows library...' ;
10911049
10921050 await this . runInitWindows ( config ) ;
0 commit comments