1+ import  assert  from  "node:assert/strict" ; 
12import  fs  from  "node:fs" ; 
23import  path  from  "node:path" ; 
34
45import  {  Command  }  from  "@commander-js/extra-typings" ; 
56import  {  spawn ,  SpawnFailure  }  from  "bufout" ; 
67import  {  oraPromise  }  from  "ora" ; 
7- import  {  prettyPath  }  from  "../path-utils " ; 
8+ import  {  packageDirectorySync  }  from  "pkg-dir " ; 
89
9- const  HERMES_PATH  =  path . resolve ( __dirname ,  "../../../hermes" ) ; 
10+ import  {  getLatestMtime ,  prettyPath  }  from  "../path-utils" ; 
11+ 
12+ const  HOST_PACKAGE_ROOT  =  path . resolve ( __dirname ,  "../../.." ) ; 
13+ // FIXME: make this configurable with reasonable fallback before public release 
1014const  HERMES_GIT_URL  =  "https://github.com/kraenhansen/hermes.git" ; 
1115const  HERMES_GIT_TAG  =  "node-api-for-react-native-0.79.0" ; 
12- const  REACT_NATIVE_DIR  =  path . dirname ( 
13-   require . resolve ( "react-native/package.json" ) 
14- ) ; 
1516
1617export  const  command  =  new  Command ( "vendor-hermes" ) 
18+   . argument ( "[from]" ,  "Path to a file inside the app package" ,  process . cwd ( ) ) 
1719  . option ( "--silent" ,  "Don't print anything except the final path" ,  false ) 
1820  . option ( 
1921    "--force" , 
2022    "Don't check timestamps of input files to skip unnecessary rebuilds" , 
2123    false 
2224  ) 
23-   . action ( async  ( {  force,  silent } )  =>  { 
25+   . action ( async  ( from ,   {  force,  silent } )  =>  { 
2426    try  { 
25-       if  ( force )  { 
26-         fs . rmSync ( HERMES_PATH ,  {  recursive : true ,  force : true  } ) ; 
27+       const  appPackageRoot  =  packageDirectorySync ( {  cwd : from  } ) ; 
28+       assert ( appPackageRoot ,  "Failed to find package root" ) ; 
29+       const  hermesPath  =  path . join ( HOST_PACKAGE_ROOT ,  "hermes" ) ; 
30+       if  ( force  &&  fs . existsSync ( hermesPath ) )  { 
31+         await  oraPromise ( 
32+           fs . promises . rm ( hermesPath ,  {  recursive : true ,  force : true  } ) , 
33+           { 
34+             text : "Removing existing Hermes clone" , 
35+             successText : "Removed existing Hermes clone" , 
36+             failText : ( error )  => 
37+               `Failed to remove existing Hermes clone: ${ error . message }  , 
38+             isEnabled : ! silent , 
39+           } 
40+         ) ; 
2741      } 
28-       if  ( ! fs . existsSync ( HERMES_PATH ) )  { 
42+       if  ( ! fs . existsSync ( hermesPath ) )  { 
2943        await  oraPromise ( 
3044          spawn ( 
3145            "git" , 
@@ -37,27 +51,41 @@ export const command = new Command("vendor-hermes")
3751              "--branch" , 
3852              HERMES_GIT_TAG , 
3953              HERMES_GIT_URL , 
40-               HERMES_PATH , 
54+               hermesPath , 
4155            ] , 
4256            { 
4357              outputMode : "buffered" , 
4458            } 
4559          ) , 
4660          { 
47-             text : `Cloning custom Hermes into ${ prettyPath ( HERMES_PATH ) }  , 
61+             text : `Cloning custom Hermes into ${ prettyPath ( hermesPath ) }  , 
4862            successText : "Cloned custom Hermes" , 
4963            failText : ( err )  =>  `Failed to clone custom Hermes: ${ err . message }  , 
5064            isEnabled : ! silent , 
5165          } 
5266        ) ; 
67+       } 
68+       const  hermesJsiPath  =  path . join ( hermesPath ,  "API/jsi/jsi" ) ; 
69+       const  reactNativePath  =  path . dirname ( 
70+         require . resolve ( "react-native/package.json" ,  { 
71+           // Ensures we'll be patching the React Native package actually used by the app 
72+           paths : [ appPackageRoot ] , 
73+         } ) 
74+       ) ; 
75+       const  reactNativeJsiPath  =  path . join ( 
76+         reactNativePath , 
77+         "ReactCommon/jsi/jsi/" 
78+       ) ; 
79+ 
80+       if  ( 
81+         fs . existsSync ( reactNativeJsiPath )  && 
82+         ( force  || 
83+           getLatestMtime ( hermesJsiPath )  >  getLatestMtime ( reactNativeJsiPath ) ) 
84+       )  { 
5385        await  oraPromise ( 
54-           fs . promises . cp ( 
55-             path . join ( HERMES_PATH ,  "API/jsi/jsi" ) , 
56-             path . join ( REACT_NATIVE_DIR ,  "ReactCommon/jsi/jsi/" ) , 
57-             { 
58-               recursive : true , 
59-             } 
60-           ) , 
86+           fs . promises . cp ( hermesJsiPath ,  reactNativeJsiPath ,  { 
87+             recursive : true , 
88+           } ) , 
6189          { 
6290            text : `Copying JSI from Hermes to React Native` , 
6391            successText : "Copied JSI from Hermes to React Native" , 
@@ -67,7 +95,7 @@ export const command = new Command("vendor-hermes")
6795          } 
6896        ) ; 
6997      } 
70-       console . log ( HERMES_PATH ) ; 
98+       console . log ( hermesPath ) ; 
7199    }  catch  ( error )  { 
72100      if  ( error  instanceof  SpawnFailure )  { 
73101        error . flushOutput ( "both" ) ; 
0 commit comments