@@ -15,60 +15,29 @@ const path = require('node:path');
1515const COMMANDS_DIR = path . join ( __dirname , '..' ) ;
1616const REPO_ROOT = path . resolve ( __dirname , '../../../../..' ) ;
1717
18- /**
19- * The command wrappers reach into the `react-native` package with
20- * `require.resolve('react-native/...')`. Those specifiers go through
21- * react-native's `exports` map, which — unlike legacy CJS resolution — neither
22- * appends extensions nor falls back to a directory's `index.js`. A specifier
23- * missing either therefore throws, but only at runtime when the command is
24- * invoked.
25- *
26- * Resolution must be checked in a real `node` process: Jest's `moduleNameMapper`
27- * remaps `react-native` to the source tree and bypasses the `exports` map
28- * entirely, so resolving in-band here would pass even when production fails.
29- */
30- function collectReactNativeSpecifiers ( ) : Array < { file: string , spec : string } > {
31- const found = [ ] ;
32- for ( const name of fs . readdirSync ( COMMANDS_DIR ) ) {
33- if ( ! name . endsWith ( '.js' ) ) {
34- continue ;
35- }
36- const filePath = path . join ( COMMANDS_DIR , name ) ;
37- if ( ! fs . statSync ( filePath ) . isFile ( ) ) {
38- continue ;
39- }
40- const source = fs . readFileSync ( filePath , 'utf8' ) ;
41- for ( const match of source . matchAll ( / ' ( r e a c t - n a t i v e \/ [ ^ ' ] + ) ' / g) ) {
42- found . push ( { file : name , spec : match [ 1 ] } ) ;
43- }
44- }
45- return found ;
46- }
47-
48- function resolvesInNode ( spec : string ) : boolean {
49- try {
50- execFileSync (
51- process . execPath ,
52- [ '-e' , `require.resolve(${ JSON . stringify ( spec ) } )` ] ,
53- { cwd : REPO_ROOT , stdio : 'ignore' } ,
54- ) ;
55- return true ;
56- } catch {
57- return false ;
58- }
59- }
60-
61- describe ( 'react-native subpath specifiers used by the command wrappers' , ( ) => {
62- const specifiers = collectReactNativeSpecifiers ( ) ;
18+ // The wrappers load scripts as `react-native/<subpath>`, resolved through
19+ // react-native's `exports` map: no extension guessing, no index.js fallback.
20+ // Must run in a real node process — Jest's moduleNameMapper bypasses `exports`
21+ // and would pass either way.
22+ const specifiers = fs
23+ . readdirSync ( COMMANDS_DIR )
24+ . filter ( name => name . endsWith ( '.js' ) )
25+ . flatMap ( name =>
26+ [
27+ ...fs
28+ . readFileSync ( path . join ( COMMANDS_DIR , name ) , 'utf8' )
29+ . matchAll ( / ' ( r e a c t - n a t i v e \/ [ ^ ' ] + ) ' / g) ,
30+ ] . map ( match => ( { file : name , spec : match [ 1 ] } ) ) ,
31+ ) ;
6332
64- test ( 'at least one specifier is covered by this test ' , ( ) => {
65- expect ( specifiers . length ) . toBeGreaterThan ( 0 ) ;
66- } ) ;
33+ test ( 'found specifiers to check ' , ( ) => {
34+ expect ( specifiers . length ) . toBeGreaterThan ( 0 ) ;
35+ } ) ;
6736
68- test . each ( specifiers ) (
69- "$file resolves $spec through react-native's exports map" ,
70- ( { spec } ) => {
71- expect ( resolvesInNode ( spec ) ) . toBe ( true ) ;
72- } ,
37+ test . each ( specifiers ) ( '$file resolves $spec' , ( { spec } ) => {
38+ execFileSync (
39+ process . execPath ,
40+ [ '-e' , `require.resolve( ${ JSON . stringify ( spec ) } )` ] ,
41+ { cwd : REPO_ROOT , stdio : 'ignore' } ,
7342 ) ;
7443} ) ;
0 commit comments