@@ -2,7 +2,6 @@ import { getConfig } from '@expo/config';
22import { getPbxproj } from '@expo/config-plugins/build/ios/utils/Xcodeproj' ;
33import Server from '@expo/metro/metro/Server' ;
44import type MetroServer from '@expo/metro/metro/Server' ;
5- import { assert as consoleAssert } from 'console' ;
65import fs from 'fs' ;
76import path from 'path' ;
87
@@ -26,7 +25,7 @@ function findUpTSConfig(cwd: string): string | null {
2625 return findUpTSConfig ( parent ) ;
2726}
2827
29- function findUpTSProjectRootOrAssert ( dir : string ) : string {
28+ function findUpTSProjectRootOrThrow ( dir : string ) : string {
3029 const tsProjectRoot = findUpTSConfig ( dir ) ;
3130 if ( ! tsProjectRoot ) {
3231 throw new Error ( 'Local modules watched dir needs to be inside a TS project with tsconfig.json' ) ;
@@ -71,7 +70,7 @@ function getMirrorDirectories(projectRoot: string): {
7170 } ;
7271}
7372
74- function createFreshMirrorDirectories ( projectRoot : string ) {
73+ function createFreshMirrorDirectories ( projectRoot : string ) : void {
7574 const { localModulesModulesPath, localModulesTypesPath } = getMirrorDirectories ( projectRoot ) ;
7675
7776 if ( fs . existsSync ( localModulesModulesPath ) ) {
@@ -84,26 +83,26 @@ function createFreshMirrorDirectories(projectRoot: string) {
8483 fs . mkdirSync ( localModulesTypesPath , { recursive : true } ) ;
8584}
8685
87- function trimExtension ( fileName : string ) {
86+ function trimExtension ( fileName : string ) : string {
8887 return fileName . substring ( 0 , fileName . lastIndexOf ( '.' ) ) ;
8988}
9089
9190function typesAndLocalModulePathsForFile (
9291 projectRoot : string ,
93- watchedDirRoot : string ,
92+ watchedDirRootAbolutePath : string ,
9493 absoluteFilePath : string
95- ) {
96- consoleAssert ( ! ! absoluteFilePath ) ;
97- consoleAssert ( path . isAbsolute ( absoluteFilePath ) ) ;
94+ ) : {
95+ moduleTypesFilePath : string ;
96+ viewTypesFilePath : string ;
97+ viewExportPath : string ;
98+ moduleExportPath : string ;
99+ moduleName : string ;
100+ } {
98101 const { localModulesModulesPath, localModulesTypesPath } = getMirrorDirectories ( projectRoot ) ;
99- const splitPath = absoluteFilePath . split ( '/' ) ;
100- const fileName = splitPath . at ( - 1 ) ;
101- if ( ! fileName ) {
102- throw new Error ( 'Invalid absoluteFilePath provided.' ) ;
103- }
102+ const fileName = path . basename ( absoluteFilePath ) ;
104103 const moduleName = trimExtension ( fileName ) ;
105104
106- const watchedDirTSProjectRoot = findUpTSProjectRootOrAssert ( watchedDirRoot ) ;
105+ const watchedDirTSProjectRoot = findUpTSProjectRootOrThrow ( watchedDirRootAbolutePath ) ;
107106 const filePathRelativeToTSProjectRoot = path . relative ( watchedDirTSProjectRoot , absoluteFilePath ) ;
108107 const filePathRelativeToTSProjectRootWithoutExtension = trimExtension (
109108 filePathRelativeToTSProjectRoot
@@ -117,14 +116,14 @@ function typesAndLocalModulePathsForFile(
117116 localModulesTypesPath ,
118117 filePathRelativeToTSProjectRootWithoutExtension + '.view.d.ts'
119118 ) ;
120- const viewExportPath = path . resolve (
121- localModulesModulesPath ,
122- filePathRelativeToTSProjectRootWithoutExtension + '.view.js'
123- ) ;
124119 const moduleExportPath = path . resolve (
125120 localModulesModulesPath ,
126121 filePathRelativeToTSProjectRootWithoutExtension + '.module.js'
127122 ) ;
123+ const viewExportPath = path . resolve (
124+ localModulesModulesPath ,
125+ filePathRelativeToTSProjectRootWithoutExtension + '.view.js'
126+ ) ;
128127 return {
129128 moduleTypesFilePath,
130129 viewTypesFilePath,
@@ -148,7 +147,7 @@ function fileWatchedWithAnyNativeExtension(
148147 return false ;
149148}
150149
151- export function updateXCodeProject ( projectRoot : string ) {
150+ export function updateXCodeProject ( projectRoot : string ) : void {
152151 const pbxProject = getPbxproj ( projectRoot ) ;
153152 const mainGroupUUID = pbxProject . getFirstProject ( ) . firstProject . mainGroup ;
154153 const mainTargetUUID = pbxProject . getFirstProject ( ) . firstProject . targets [ 0 ] . value ;
@@ -212,9 +211,12 @@ export function updateXCodeProject(projectRoot: string) {
212211 fs . writeFileSync ( pbxProject . filepath , pbxProject . writeSync ( ) ) ;
213212}
214213
215- function fileWatchedDirAncestor ( projectRoot : string , filePathAbsolute : string ) : string | null {
214+ function getWatchedDirAncestorAbsolutePath (
215+ projectRoot : string ,
216+ filePathAbsolute : string
217+ ) : string | null {
216218 const watchedDirs = getConfig ( projectRoot ) . exp . localModules ?. watchedDirs ?? [ ] ;
217- const realRoot = fs . realpathSync ( projectRoot ) ;
219+ const realRoot = path . resolve ( projectRoot ) ;
218220 for ( const dir of watchedDirs ) {
219221 const dirPathAbsolute = path . resolve ( realRoot , dir ) ;
220222 if ( filePathAbsolute . startsWith ( dirPathAbsolute ) ) {
@@ -226,12 +228,12 @@ function fileWatchedDirAncestor(projectRoot: string, filePathAbsolute: string):
226228
227229function onSourceFileCreated (
228230 projectRoot : string ,
229- watchedDirRoot : string ,
231+ watchedDirRootAbolutePath : string ,
230232 absoluteFilePath : string ,
231233 filesWatched ?: Set < string >
232- ) {
234+ ) : void {
233235 const { moduleTypesFilePath, viewTypesFilePath, viewExportPath, moduleExportPath, moduleName } =
234- typesAndLocalModulePathsForFile ( projectRoot , watchedDirRoot , absoluteFilePath ) ;
236+ typesAndLocalModulePathsForFile ( projectRoot , watchedDirRootAbolutePath , absoluteFilePath ) ;
235237
236238 if ( filesWatched && fileWatchedWithAnyNativeExtension ( absoluteFilePath , filesWatched ) ) {
237239 filesWatched . add ( absoluteFilePath ) ;
@@ -265,12 +267,15 @@ export default _default`
265267 fs . writeFileSync ( moduleTypesFilePath , 'const _default: any\nexport default _default' ) ;
266268}
267269
268- async function generateMirrorDirectories ( projectRoot : string , filesWatched ?: Set < string > ) {
270+ async function generateMirrorDirectories (
271+ projectRoot : string ,
272+ filesWatched ?: Set < string >
273+ ) : Promise < void > {
269274 createFreshMirrorDirectories ( projectRoot ) ;
270275
271276 const generateExportsAndTypesForDirectory = async (
272277 absoluteDirPath : string ,
273- watchedDirRoot : string
278+ watchedDirRootAbolutePath : string
274279 ) => {
275280 for ( const glob of excludePathsGlobs ( projectRoot ) ) {
276281 if ( path . matchesGlob ( absoluteDirPath , glob ) ) {
@@ -284,11 +289,16 @@ async function generateMirrorDirectories(projectRoot: string, filesWatched?: Set
284289 if (
285290 dirent . isFile ( ) &&
286291 isValidLocalModuleFileName ( dirent . name ) &&
287- absoluteDirentPath . startsWith ( watchedDirRoot )
292+ absoluteDirentPath . startsWith ( watchedDirRootAbolutePath )
288293 ) {
289- onSourceFileCreated ( projectRoot , watchedDirRoot , absoluteDirentPath , filesWatched ) ;
294+ onSourceFileCreated (
295+ projectRoot ,
296+ watchedDirRootAbolutePath ,
297+ absoluteDirentPath ,
298+ filesWatched
299+ ) ;
290300 } else if ( dirent . isDirectory ( ) ) {
291- await generateExportsAndTypesForDirectory ( absoluteDirentPath , watchedDirRoot ) ;
301+ await generateExportsAndTypesForDirectory ( absoluteDirentPath , watchedDirRootAbolutePath ) ;
292302 }
293303 }
294304 } ;
@@ -305,32 +315,25 @@ async function generateMirrorDirectories(projectRoot: string, filesWatched?: Set
305315function excludePathsGlobs ( projectRoot : string ) : string [ ] {
306316 return [
307317 path . resolve ( projectRoot , '.expo' ) ,
308- path . resolve ( projectRoot , '.expo' , './**' ) ,
309318 path . resolve ( projectRoot , '.expo' , './**/*' ) ,
310319 path . resolve ( projectRoot , 'node_modules' ) ,
311- path . resolve ( projectRoot , 'node_modules' , './**' ) ,
312320 path . resolve ( projectRoot , 'node_modules' , './**/*' ) ,
313321 path . resolve ( projectRoot , 'localModules' ) ,
314- path . resolve ( projectRoot , 'localModules' , './**' ) ,
315322 path . resolve ( projectRoot , 'localModules' , './**/*' ) ,
316323 path . resolve ( projectRoot , 'android' ) ,
317- path . resolve ( projectRoot , 'android' , './**' ) ,
318324 path . resolve ( projectRoot , 'android' , './**/*' ) ,
319325 path . resolve ( projectRoot , 'ios' ) ,
320- path . resolve ( projectRoot , 'ios' , './**' ) ,
321326 path . resolve ( projectRoot , 'ios' , './**/*' ) ,
322327 path . resolve ( projectRoot , 'modules' ) ,
323- path . resolve ( projectRoot , 'modules' , './**' ) ,
324328 path . resolve ( projectRoot , 'modules' , './**/*' ) ,
325329 ] ;
326330}
327331
328332export async function startModuleGenerationAsync ( {
329333 projectRoot,
330334 metro,
331- } : ModuleGenerationArguments ) {
335+ } : ModuleGenerationArguments ) : Promise < void > {
332336 const dotExpoDir = ensureDotExpoProjectDirectoryInitialized ( projectRoot ) ;
333- const { exp } = getConfig ( projectRoot ) ;
334337 const filesWatched = new Set < string > ( ) ;
335338
336339 const isFileExcluded = ( absolutePath : string ) => {
@@ -345,21 +348,17 @@ export async function startModuleGenerationAsync({
345348 createFreshMirrorDirectories ( projectRoot ) ;
346349
347350 const removeFileAndEmptyDirectories = ( absoluteFilePath : string ) => {
348- if ( fs . lstatSync ( absoluteFilePath ) . isSymbolicLink ( ) ) {
349- fs . unlinkSync ( absoluteFilePath ) ;
350- } else {
351- fs . rmSync ( absoluteFilePath ) ;
352- }
351+ fs . rmSync ( absoluteFilePath ) ;
353352 let dirNow : string = path . dirname ( absoluteFilePath ) ;
354353 while ( fs . readdirSync ( dirNow ) . length === 0 && dirNow !== dotExpoDir ) {
355354 fs . rmdirSync ( dirNow ) ;
356355 dirNow = path . dirname ( dirNow ) ;
357356 }
358357 } ;
359358
360- const onSourceFileRemoved = ( absoluteFilePath : string , watchedDirRoot : string ) => {
359+ const onSourceFileRemoved = ( absoluteFilePath : string , watchedDirRootAbolutePath : string ) => {
361360 const { moduleTypesFilePath, moduleExportPath, viewExportPath, viewTypesFilePath } =
362- typesAndLocalModulePathsForFile ( projectRoot , watchedDirRoot , absoluteFilePath ) ;
361+ typesAndLocalModulePathsForFile ( projectRoot , watchedDirRootAbolutePath , absoluteFilePath ) ;
363362
364363 filesWatched . delete ( absoluteFilePath ) ;
365364 if ( ! fileWatchedWithAnyNativeExtension ( absoluteFilePath , filesWatched ) ) {
@@ -370,55 +369,40 @@ export async function startModuleGenerationAsync({
370369 }
371370 } ;
372371
373- const metroWatchKotlinAndSwiftFiles = async ( {
374- projectRoot,
375- metro,
376- eventTypes = [ 'add' , 'delete' ] ,
377- } : {
378- metro : MetroServer | null ;
379- projectRoot : string ;
380- eventTypes ?: string [ ] ;
381- } ) => {
382- const watcher = metro ?. getBundler ( ) . getBundler ( ) . getWatcher ( ) ;
383-
384- const isWatchedFileEvent = ( event : Event , watchedDirAncestor : string | null ) : boolean => {
385- return (
386- event . metadata ?. type !== 'd' &&
387- isValidLocalModuleFileName ( path . basename ( event . filePath ) ) &&
388- ! isFileExcluded ( event . filePath ) &&
389- ! ! watchedDirAncestor
390- ) ;
391- } ;
372+ const watcher = metro ?. getBundler ( ) . getBundler ( ) . getWatcher ( ) ;
373+ const eventTypes = [ 'add' , 'delete' , 'change' ] ;
392374
393- const listener = async ( { eventsQueue } : { eventsQueue : EventsQueue } ) => {
394- for ( const event of eventsQueue ) {
395- const watchedDirAncestor = fileWatchedDirAncestor (
396- projectRoot ,
397- fs . realpathSync ( event . filePath )
398- ) ;
399- if (
400- eventTypes . includes ( event . type ) &&
401- isWatchedFileEvent ( event , watchedDirAncestor ) &&
402- ! ! watchedDirAncestor
403- ) {
404- const { filePath } = event ;
405- if ( event . type === 'add' ) {
406- onSourceFileCreated ( projectRoot , filePath , watchedDirAncestor , filesWatched ) ;
407- } else if ( event . type === 'delete' ) {
408- onSourceFileRemoved ( filePath , watchedDirAncestor ) ;
409- }
375+ const isWatchedFileEvent = ( event : Event , watchedDirAncestor : string | null ) : boolean => {
376+ return (
377+ event . metadata ?. type !== 'd' &&
378+ isValidLocalModuleFileName ( path . basename ( event . filePath ) ) &&
379+ ! isFileExcluded ( event . filePath ) &&
380+ ! ! watchedDirAncestor
381+ ) ;
382+ } ;
383+
384+ const listener = async ( { eventsQueue } : { eventsQueue : EventsQueue } ) => {
385+ for ( const event of eventsQueue ) {
386+ const watchedDirAncestor = getWatchedDirAncestorAbsolutePath (
387+ projectRoot ,
388+ path . resolve ( event . filePath )
389+ ) ;
390+ if (
391+ eventTypes . includes ( event . type ) &&
392+ isWatchedFileEvent ( event , watchedDirAncestor ) &&
393+ ! ! watchedDirAncestor
394+ ) {
395+ const { filePath } = event ;
396+ if ( event . type === 'add' ) {
397+ onSourceFileCreated ( projectRoot , watchedDirAncestor , filePath , filesWatched ) ;
398+ } else if ( event . type === 'delete' ) {
399+ onSourceFileRemoved ( filePath , watchedDirAncestor ) ;
410400 }
411401 }
412- } ;
413-
414- watcher ?. addListener ( 'change' , listener ) ;
415-
416- await generateMirrorDirectories ( projectRoot , filesWatched ) ;
402+ }
417403 } ;
418404
419- metroWatchKotlinAndSwiftFiles ( {
420- projectRoot,
421- metro,
422- eventTypes : [ 'add' , 'delete' , 'change' ] ,
423- } ) ;
405+ watcher ?. addListener ( 'change' , listener ) ;
406+
407+ await generateMirrorDirectories ( projectRoot , filesWatched ) ;
424408}
0 commit comments