Skip to content

Commit 728a26e

Browse files
Copilotanupriya13
andcommitted
Fix Windows permission error and simplify dependency management
Co-authored-by: anupriya13 <[email protected]>
1 parent 4dbc2e5 commit 728a26e

File tree

1 file changed

+57
-99
lines changed

1 file changed

+57
-99
lines changed

packages/@react-native-windows/cli/src/commands/moduleWindowsSetup/moduleWindowsSetup.ts

Lines changed: 57 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ interface MethodSignature {
4242

4343
export 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(/TurboModuleRegistry\.getEnforcing<Spec>\(['"`]([^'"`]+)['"`]\)/);
102+
const exportMatch = content.match(
103+
/TurboModuleRegistry\.getEnforcing<Spec>\(['"`]([^'"`]+)['"`]\)/,
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

Comments
 (0)