@@ -4,6 +4,7 @@ import { describe, test } from 'node:test';
44import rehypeStaticToDynamic , {
55 type RehypeStaticToDynamicElement as Element ,
66 type RehypeStaticToDynamicElementChild as ElementChild ,
7+ type RehypeStaticToDynamicMdxEsm as MdxEsm ,
78 type RehypeStaticToDynamicRoot as Root ,
89 type RehypeStaticToDynamicText as Text ,
910 type RehypeStaticToDynamicTreeChild as TreeChild ,
@@ -12,10 +13,11 @@ import rehypeStaticToDynamic, {
1213/**
1314 * Helper function to create a test tree structure
1415 */
15- function createTestTree ( code : string ) : Root {
16+ function createTestTree ( code : string , extraChildren : MdxEsm [ ] = [ ] ) : Root {
1617 const tree : Root = {
1718 type : 'root' ,
1819 children : [
20+ ...extraChildren ,
1921 {
2022 type : 'element' ,
2123 tagName : 'pre' ,
@@ -35,7 +37,7 @@ function createTestTree(code: string): Root {
3537 } ,
3638 ] ,
3739 } ,
38- ] ,
40+ ] as Root [ 'children' ] ,
3941 } ;
4042
4143 return tree ;
@@ -46,7 +48,9 @@ function createTestTree(code: string): Root {
4648 */
4749function extractTransformedCode ( tree : Root ) : string {
4850 // After transformation, the tree should have TabItem elements
49- const tabsElement = tree . children [ 0 ] ;
51+ const tabsElement = tree . children . find (
52+ ( child ) : child is Element => isElement ( child ) && child . tagName === 'Tabs'
53+ ) ;
5054
5155 if ( ! isElement ( tabsElement ) || tabsElement . tagName !== 'Tabs' ) {
5256 throw new Error ( 'Expected Tabs element not found' ) ;
@@ -92,6 +96,10 @@ function isElement(
9296 return Boolean ( node && node . type === 'element' ) ;
9397}
9498
99+ function isMdxEsmNode ( node : TreeChild | undefined ) : node is MdxEsm {
100+ return Boolean ( node && node . type === 'mdxjsEsm' ) ;
101+ }
102+
95103function isTextNode ( node : ElementChild ) : node is Text {
96104 return node . type === 'text' ;
97105}
@@ -149,6 +157,77 @@ describe('rehype-static-to-dynamic', () => {
149157 assert . strictEqual ( output , expected ) ;
150158 } ) ;
151159
160+ test ( 'adds Tabs imports when transforming static2dynamic code' , async ( ) => {
161+ const input = dedent /* javascript */ `
162+ import { createNativeStackNavigator } from '@react-navigation/native-stack';
163+ import { createStaticNavigation } from '@react-navigation/native';
164+
165+ const RootStack = createNativeStackNavigator({
166+ screens: {
167+ Home: HomeScreen,
168+ },
169+ });
170+
171+ const Navigation = createStaticNavigation(RootStack);
172+
173+ export default function App() {
174+ return <Navigation />;
175+ }
176+ ` ;
177+
178+ const tree = createTestTree ( input ) ;
179+ const plugin = rehypeStaticToDynamic ( ) ;
180+ await plugin ( tree ) ;
181+
182+ const importNode = tree . children . find ( isMdxEsmNode ) ;
183+
184+ if ( ! importNode || ! ( 'value' in importNode ) ) {
185+ throw new Error ( 'Expected MDX import node not found' ) ;
186+ }
187+
188+ assert . strictEqual (
189+ importNode . value ,
190+ "import Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'"
191+ ) ;
192+ } ) ;
193+
194+ test ( 'does not duplicate existing Tabs imports' , async ( ) => {
195+ const input = dedent /* javascript */ `
196+ import { createNativeStackNavigator } from '@react-navigation/native-stack';
197+ import { createStaticNavigation } from '@react-navigation/native';
198+
199+ const RootStack = createNativeStackNavigator({
200+ screens: {
201+ Home: HomeScreen,
202+ },
203+ });
204+
205+ const Navigation = createStaticNavigation(RootStack);
206+
207+ export default function App() {
208+ return <Navigation />;
209+ }
210+ ` ;
211+
212+ const tree = createTestTree ( input , [
213+ {
214+ type : 'mdxjsEsm' ,
215+ value :
216+ "import Tabs from '@theme/Tabs'\nimport TabItem from '@theme/TabItem'" ,
217+ } ,
218+ ] ) ;
219+ const plugin = rehypeStaticToDynamic ( ) ;
220+ await plugin ( tree ) ;
221+
222+ const tabImportNodes = tree . children . filter (
223+ ( child ) =>
224+ isMdxEsmNode ( child ) &&
225+ child . value . includes ( "import Tabs from '@theme/Tabs'" )
226+ ) ;
227+
228+ assert . strictEqual ( tabImportNodes . length , 1 ) ;
229+ } ) ;
230+
152231 test ( 'screen with options' , async ( ) => {
153232 const input = dedent /* javascript */ `
154233 import { createNativeStackNavigator, createNativeStackScreen } from '@react-navigation/native-stack';
@@ -912,14 +991,14 @@ describe('rehype-static-to-dynamic', () => {
912991 import { createDrawerNavigator } from '@react-navigation/drawer';
913992 import { createStaticNavigation } from '@react-navigation/native';
914993
915- const Drawer = createDrawerNavigator({
994+ const RootDrawer = createDrawerNavigator({
916995 screens: {
917996 Home: HomeScreen,
918997 Profile: ProfileScreen,
919998 },
920999 });
9211000
922- const Navigation = createStaticNavigation(Drawer );
1001+ const Navigation = createStaticNavigation(RootDrawer );
9231002
9241003 export default function App() {
9251004 return <Navigation />;
@@ -938,7 +1017,7 @@ describe('rehype-static-to-dynamic', () => {
9381017
9391018 const Drawer = createDrawerNavigator();
9401019
941- function Drawer () {
1020+ function RootDrawer () {
9421021 return (
9431022 <Drawer.Navigator>
9441023 <Drawer.Screen name="Home" component={HomeScreen} />
@@ -950,7 +1029,7 @@ describe('rehype-static-to-dynamic', () => {
9501029 export default function App() {
9511030 return (
9521031 <NavigationContainer>
953- <Drawer />
1032+ <RootDrawer />
9541033 </NavigationContainer>
9551034 );
9561035 }
@@ -959,6 +1038,33 @@ describe('rehype-static-to-dynamic', () => {
9591038 assert . strictEqual ( output , expected ) ;
9601039 } ) ;
9611040
1041+ test ( 'throws on colliding navigator component names' , async ( ) => {
1042+ const input = dedent /* javascript */ `
1043+ import { createNativeStackNavigator } from '@react-navigation/native-stack';
1044+ import { createStaticNavigation } from '@react-navigation/native';
1045+
1046+ const Stack = createNativeStackNavigator({
1047+ screens: {
1048+ Home: HomeScreen,
1049+ },
1050+ });
1051+
1052+ const Navigation = createStaticNavigation(Stack);
1053+
1054+ export default function App() {
1055+ return <Navigation />;
1056+ }
1057+ ` ;
1058+
1059+ const tree = createTestTree ( input ) ;
1060+ const plugin = rehypeStaticToDynamic ( ) ;
1061+
1062+ await assert . rejects (
1063+ plugin ( tree ) ,
1064+ / R e n a m e t h e s t a t i c n a v i g a t o r t o a v o i d c o l l i d i n g w i t h t h e g e n e r a t e d d y n a m i c c o d e \. /
1065+ ) ;
1066+ } ) ;
1067+
9621068 test ( 'nested navigator with highlight on screen property' , async ( ) => {
9631069 const input = dedent /* javascript */ `
9641070 import { createNativeStackNavigator } from '@react-navigation/native-stack';
0 commit comments