@@ -251,6 +251,152 @@ fn test_require_with_config_luau() {
251251 test_require_with_config_inner ( "with_config_luau" ) ;
252252}
253253
254+ #[ test]
255+ fn test_alias_override ( ) {
256+ let lua = Lua :: new ( ) ;
257+
258+ struct OverrideRequire ( FsRequirer ) ;
259+
260+ impl Require for OverrideRequire {
261+ fn is_require_allowed ( & self , chunk_name : & str ) -> bool {
262+ self . 0 . is_require_allowed ( chunk_name)
263+ }
264+
265+ fn reset ( & mut self , chunk_name : & str ) -> StdResult < ( ) , NavigateError > {
266+ self . 0 . reset ( chunk_name)
267+ }
268+
269+ fn jump_to_alias ( & mut self , path : & str ) -> StdResult < ( ) , NavigateError > {
270+ self . 0 . jump_to_alias ( path)
271+ }
272+
273+ fn to_alias_override ( & mut self , alias : & str ) -> StdResult < ( ) , NavigateError > {
274+ if alias == "testoverride" {
275+ self . 0 . jump_to_alias ( "./tests/luau/require/without_config" )
276+ } else {
277+ Err ( NavigateError :: NotFound )
278+ }
279+ }
280+
281+ fn to_parent ( & mut self ) -> StdResult < ( ) , NavigateError > {
282+ self . 0 . to_parent ( )
283+ }
284+
285+ fn to_child ( & mut self , name : & str ) -> StdResult < ( ) , NavigateError > {
286+ self . 0 . to_child ( name)
287+ }
288+
289+ fn has_module ( & self ) -> bool {
290+ self . 0 . has_module ( )
291+ }
292+
293+ fn cache_key ( & self ) -> String {
294+ self . 0 . cache_key ( )
295+ }
296+
297+ fn has_config ( & self ) -> bool {
298+ self . 0 . has_config ( )
299+ }
300+
301+ fn config ( & self ) -> IoResult < Vec < u8 > > {
302+ self . 0 . config ( )
303+ }
304+
305+ fn loader ( & self , lua : & Lua ) -> Result < mlua:: Function > {
306+ self . 0 . loader ( lua)
307+ }
308+ }
309+
310+ let require_fn = lua
311+ . create_require_function ( OverrideRequire ( FsRequirer :: new ( ) ) )
312+ . unwrap ( ) ;
313+ lua. globals ( ) . set ( "require" , require_fn) . unwrap ( ) ;
314+
315+ // to_alias_override intercepts before config-file search
316+ let res = run_require ( & lua, "@testoverride/dependency" ) . unwrap ( ) ;
317+ assert_eq ! ( "result from dependency" , get_str( & res, 1 ) ) ;
318+
319+ // Different sub-path through the same alias
320+ let res = run_require ( & lua, "@testoverride/module" ) . unwrap ( ) ;
321+ assert_eq ! ( "required into module" , get_str( & res, 2 ) ) ;
322+
323+ // Aliases not handled by the override still fail normally
324+ let res = run_require ( & lua, "@unknown_alias_xyz/anything" ) ;
325+ assert ! ( res. is_err( ) ) ;
326+ assert ! ( ( res. unwrap_err( ) . to_string( ) ) . contains( "@unknown_alias_xyz is not a valid alias" ) ) ;
327+ }
328+
329+ #[ test]
330+ fn test_alias_fallback ( ) {
331+ let lua = Lua :: new ( ) ;
332+
333+ struct FallbackRequire ( FsRequirer ) ;
334+
335+ impl Require for FallbackRequire {
336+ fn is_require_allowed ( & self , chunk_name : & str ) -> bool {
337+ self . 0 . is_require_allowed ( chunk_name)
338+ }
339+
340+ fn reset ( & mut self , chunk_name : & str ) -> StdResult < ( ) , NavigateError > {
341+ self . 0 . reset ( chunk_name)
342+ }
343+
344+ fn jump_to_alias ( & mut self , path : & str ) -> StdResult < ( ) , NavigateError > {
345+ self . 0 . jump_to_alias ( path)
346+ }
347+
348+ fn to_alias_fallback ( & mut self , alias : & str ) -> StdResult < ( ) , NavigateError > {
349+ if alias == "testfallback" {
350+ self . 0 . jump_to_alias ( "./tests/luau/require/without_config" )
351+ } else {
352+ Err ( NavigateError :: NotFound )
353+ }
354+ }
355+
356+ fn to_parent ( & mut self ) -> StdResult < ( ) , NavigateError > {
357+ self . 0 . to_parent ( )
358+ }
359+
360+ fn to_child ( & mut self , name : & str ) -> StdResult < ( ) , NavigateError > {
361+ self . 0 . to_child ( name)
362+ }
363+
364+ fn has_module ( & self ) -> bool {
365+ self . 0 . has_module ( )
366+ }
367+
368+ fn cache_key ( & self ) -> String {
369+ self . 0 . cache_key ( )
370+ }
371+
372+ fn has_config ( & self ) -> bool {
373+ self . 0 . has_config ( )
374+ }
375+
376+ fn config ( & self ) -> IoResult < Vec < u8 > > {
377+ self . 0 . config ( )
378+ }
379+
380+ fn loader ( & self , lua : & Lua ) -> Result < mlua:: Function > {
381+ self . 0 . loader ( lua)
382+ }
383+ }
384+
385+ let require_fn = lua
386+ . create_require_function ( FallbackRequire ( FsRequirer :: new ( ) ) )
387+ . unwrap ( ) ;
388+ lua. globals ( ) . set ( "require" , require_fn) . unwrap ( ) ;
389+
390+ // to_alias_fallback catches after config-file search misses
391+ let res = run_require ( & lua, "@testfallback/dependency" ) . unwrap ( ) ;
392+ assert_eq ! ( "result from dependency" , get_str( & res, 1 ) ) ;
393+
394+ // Aliases not handled by the fallback still fail
395+ let res = run_require ( & lua, "@unknown_alias_xyz/anything" ) ;
396+ assert ! ( res. is_err( ) ) ;
397+ assert ! ( ( res. unwrap_err( ) . to_string( ) ) . contains( "@unknown_alias_xyz is not a valid alias" ) ) ;
398+ }
399+
254400#[ cfg( all( feature = "async" , not( windows) ) ) ]
255401#[ tokio:: test]
256402async fn test_async_require ( ) -> Result < ( ) > {
0 commit comments