expo-router 5.0.0-sdk-52-router-patches → 5.0.1-preview.1-canary-20250407-10a9b42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/build/Route.d.ts +7 -1
  2. package/build/Route.d.ts.map +1 -1
  3. package/build/Route.js.map +1 -1
  4. package/build/exports.d.ts +1 -0
  5. package/build/exports.d.ts.map +1 -1
  6. package/build/exports.js.map +1 -1
  7. package/build/fork/getStateFromPath-forks.d.ts +3 -2
  8. package/build/fork/getStateFromPath-forks.d.ts.map +1 -1
  9. package/build/fork/getStateFromPath-forks.js +24 -27
  10. package/build/fork/getStateFromPath-forks.js.map +1 -1
  11. package/build/fork/getStateFromPath.js +24 -19
  12. package/build/fork/getStateFromPath.js.map +1 -1
  13. package/build/getLinkingConfig.d.ts +3 -1
  14. package/build/getLinkingConfig.d.ts.map +1 -1
  15. package/build/getLinkingConfig.js +11 -7
  16. package/build/getLinkingConfig.js.map +1 -1
  17. package/build/getReactNavigationConfig.d.ts +1 -0
  18. package/build/getReactNavigationConfig.d.ts.map +1 -1
  19. package/build/getReactNavigationConfig.js +2 -1
  20. package/build/getReactNavigationConfig.js.map +1 -1
  21. package/build/getRoutes.d.ts.map +1 -1
  22. package/build/getRoutes.js +9 -1
  23. package/build/getRoutes.js.map +1 -1
  24. package/build/getRoutesCore.d.ts +16 -1
  25. package/build/getRoutesCore.d.ts.map +1 -1
  26. package/build/getRoutesCore.js +134 -11
  27. package/build/getRoutesCore.js.map +1 -1
  28. package/build/getRoutesRedirects.d.ts +12 -0
  29. package/build/getRoutesRedirects.d.ts.map +1 -0
  30. package/build/getRoutesRedirects.js +71 -0
  31. package/build/getRoutesRedirects.js.map +1 -0
  32. package/build/getRoutesSSR.d.ts.map +1 -1
  33. package/build/getRoutesSSR.js +9 -1
  34. package/build/getRoutesSSR.js.map +1 -1
  35. package/build/getServerManifest.d.ts +13 -1
  36. package/build/getServerManifest.d.ts.map +1 -1
  37. package/build/getServerManifest.js +27 -2
  38. package/build/getServerManifest.js.map +1 -1
  39. package/build/global-state/router-store.d.ts +4 -0
  40. package/build/global-state/router-store.d.ts.map +1 -1
  41. package/build/global-state/router-store.js +44 -2
  42. package/build/global-state/router-store.js.map +1 -1
  43. package/build/global-state/routing.d.ts +1 -1
  44. package/build/global-state/routing.d.ts.map +1 -1
  45. package/build/global-state/routing.js +7 -1
  46. package/build/global-state/routing.js.map +1 -1
  47. package/build/link/linking.d.ts +2 -1
  48. package/build/link/linking.d.ts.map +1 -1
  49. package/build/link/linking.js +14 -8
  50. package/build/link/linking.js.map +1 -1
  51. package/build/matchers.d.ts +3 -1
  52. package/build/matchers.d.ts.map +1 -1
  53. package/build/matchers.js +7 -2
  54. package/build/matchers.js.map +1 -1
  55. package/build/routes-manifest.d.ts +6 -2
  56. package/build/routes-manifest.d.ts.map +1 -1
  57. package/build/routes-manifest.js +1 -0
  58. package/build/routes-manifest.js.map +1 -1
  59. package/build/rsc/middleware.d.ts.map +1 -1
  60. package/build/rsc/middleware.js +6 -1
  61. package/build/rsc/middleware.js.map +1 -1
  62. package/build/rsc/router/create-expo-pages.d.ts +20 -0
  63. package/build/rsc/router/create-expo-pages.d.ts.map +1 -0
  64. package/build/rsc/router/create-expo-pages.js +22 -0
  65. package/build/rsc/router/create-expo-pages.js.map +1 -0
  66. package/build/rsc/router/expo-definedRouter.d.ts +1 -5
  67. package/build/rsc/router/expo-definedRouter.d.ts.map +1 -1
  68. package/build/rsc/router/expo-definedRouter.js +3 -2
  69. package/build/rsc/router/expo-definedRouter.js.map +1 -1
  70. package/build/rsc/router/noopRouter.d.ts +1 -5
  71. package/build/rsc/router/noopRouter.d.ts.map +1 -1
  72. package/build/rsc/router/noopRouter.js +2 -2
  73. package/build/rsc/router/noopRouter.js.map +1 -1
  74. package/build/static/getServerManifest.d.ts.map +1 -1
  75. package/build/static/getServerManifest.js +1 -0
  76. package/build/static/getServerManifest.js.map +1 -1
  77. package/build/useScreens.d.ts +4 -1
  78. package/build/useScreens.d.ts.map +1 -1
  79. package/build/useScreens.js +39 -34
  80. package/build/useScreens.js.map +1 -1
  81. package/package.json +7 -8
  82. package/plugin/options.json +33 -0
@@ -1 +1 @@
1
- {"version":3,"file":"getLinkingConfig.d.ts","sourceRoot":"","sources":["../src/getLinkingConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG9E,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGpC,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAEL,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAgB,cAAc,EAAE,MAAM,SAAS,CAAC;AAEvD,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAE3C,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,GAAE,OAAc;;;;;;;;EAS9E;AAED,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,cAAc,CAAC,CAAC,CAAC,GAAG;IAC/F,gBAAgB,CAAC,EAAE,OAAO,gBAAgB,CAAC;IAC3C,gBAAgB,CAAC,EAAE,OAAO,gBAAgB,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,aAAa,CAAC;CACtC,CAAC;AAEF,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,cAAc,EACvB,EAAE,QAAe,EAAE,SAAS,EAAE,GAAE,oBAAyB,GACxD,kBAAkB,CA6DpB"}
1
+ {"version":3,"file":"getLinkingConfig.d.ts","sourceRoot":"","sources":["../src/getLinkingConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG9E,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGpC,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAEL,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAgB,cAAc,EAAE,MAAM,SAAS,CAAC;AAEvD,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAE3C,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,GAAE,OAAc;;;;;;;;EAS9E;AAED,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,cAAc,CAAC,CAAC,CAAC,GAAG;IAC/F,gBAAgB,CAAC,EAAE,OAAO,gBAAgB,CAAC;IAC3C,gBAAgB,CAAC,EAAE,OAAO,gBAAgB,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,aAAa,CAAC;IACrC,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;CAC9B,CAAC;AAEF,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,cAAc,EACvB,EAAE,QAAe,EAAE,SAAS,EAAE,SAAS,EAAE,GAAE,oBAAyB,GACnE,kBAAkB,CAkEpB"}
@@ -17,7 +17,7 @@ function getNavigationConfig(routes, metaOnly = true) {
17
17
  };
18
18
  }
19
19
  exports.getNavigationConfig = getNavigationConfig;
20
- function getLinkingConfig(store, routes, context, { metaOnly = true, serverUrl } = {}) {
20
+ function getLinkingConfig(store, routes, context, { metaOnly = true, serverUrl, redirects } = {}) {
21
21
  // Returning `undefined` / `null from `getInitialURL` are valid values, so we need to track if it's been called.
22
22
  let hasCachedInitialUrl = false;
23
23
  let initialUrl;
@@ -27,9 +27,11 @@ function getLinkingConfig(store, routes, context, { metaOnly = true, serverUrl }
27
27
  const nativeLinking = nativeLinkingKey
28
28
  ? context(nativeLinkingKey)
29
29
  : undefined;
30
+ const config = getNavigationConfig(routes, metaOnly);
31
+ const boundGetStateFromPath = linking_1.getStateFromPath.bind(store);
30
32
  return {
31
33
  prefixes: [],
32
- config: getNavigationConfig(routes, metaOnly),
34
+ config,
33
35
  // A custom getInitialURL is used on native to ensure the app always starts at
34
36
  // the root path if it's launched from something other than a deep link.
35
37
  // This helps keep the native functionality working like the web functionality.
@@ -45,12 +47,14 @@ function getLinkingConfig(store, routes, context, { metaOnly = true, serverUrl }
45
47
  else {
46
48
  initialUrl = serverUrl ?? (0, linking_1.getInitialURL)();
47
49
  if (typeof initialUrl === 'string') {
48
- if (typeof nativeLinking?.redirectSystemPath === 'function') {
50
+ initialUrl = store.applyRedirects(initialUrl);
51
+ if (initialUrl && typeof nativeLinking?.redirectSystemPath === 'function') {
49
52
  initialUrl = nativeLinking.redirectSystemPath({ path: initialUrl, initial: true });
50
53
  }
51
54
  }
52
55
  else if (initialUrl) {
53
56
  initialUrl = initialUrl.then((url) => {
57
+ url = store.applyRedirects(url);
54
58
  if (url && typeof nativeLinking?.redirectSystemPath === 'function') {
55
59
  return nativeLinking.redirectSystemPath({ path: url, initial: true });
56
60
  }
@@ -62,13 +66,13 @@ function getLinkingConfig(store, routes, context, { metaOnly = true, serverUrl }
62
66
  }
63
67
  return initialUrl;
64
68
  },
65
- subscribe: (0, linking_1.addEventListener)(nativeLinking),
66
- getStateFromPath: linking_1.getStateFromPath.bind(store),
69
+ subscribe: (0, linking_1.addEventListener)(nativeLinking, store),
70
+ getStateFromPath: boundGetStateFromPath,
67
71
  getPathFromState(state, options) {
68
72
  return ((0, linking_1.getPathFromState)(state, {
69
- screens: {},
70
- ...this.config,
73
+ ...config,
71
74
  ...options,
75
+ screens: config.screens ?? options?.screens ?? {},
72
76
  }) ?? '/');
73
77
  },
74
78
  // Add all functions to ensure the types never need to fallback.
@@ -1 +1 @@
1
- {"version":3,"file":"getLinkingConfig.js","sourceRoot":"","sources":["../src/getLinkingConfig.ts"],"names":[],"mappings":";;;AAAA,qDAA8E;AAC9E,yDAA6C;AAI7C,yEAAsE;AAEtE,4CAKwB;AAGX,QAAA,kBAAkB,GAAG,QAAQ,CAAC;AAE3C,SAAgB,mBAAmB,CAAC,MAAiB,EAAE,WAAoB,IAAI;IAC7E,OAAO;QACL,OAAO,EAAE;YACP,CAAC,0BAAkB,CAAC,EAAE;gBACpB,IAAI,EAAE,EAAE;gBACR,GAAG,IAAA,mDAAwB,EAAC,MAAM,EAAE,QAAQ,CAAC;aAC9C;SACF;KACF,CAAC;AACJ,CAAC;AATD,kDASC;AAaD,SAAgB,gBAAgB,CAC9B,KAAkB,EAClB,MAAiB,EACjB,OAAuB,EACvB,EAAE,QAAQ,GAAG,IAAI,EAAE,SAAS,KAA2B,EAAE;IAEzD,gHAAgH;IAChH,IAAI,mBAAmB,GAAG,KAAK,CAAC;IAChC,IAAI,UAAwD,CAAC;IAE7D,MAAM,gBAAgB,GAAG,OAAO;SAC7B,IAAI,EAAE;SACN,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC,CAAC;IAC9D,MAAM,aAAa,GAA6B,gBAAgB;QAC9D,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC;QAC3B,CAAC,CAAC,SAAS,CAAC;IAEd,OAAO;QACL,QAAQ,EAAE,EAAE;QACZ,MAAM,EAAE,mBAAmB,CAAC,MAAM,EAAE,QAAQ,CAAC;QAC7C,8EAA8E;QAC9E,wEAAwE;QACxE,+EAA+E;QAC/E,8GAA8G;QAC9G,8EAA8E;QAC9E,aAAa;YACX,gHAAgH;YAChH,kCAAkC;YAClC,IAAI,CAAC,mBAAmB,EAAE;gBACxB,IAAI,4BAAQ,CAAC,EAAE,KAAK,KAAK,EAAE;oBACzB,UAAU,GAAG,SAAS,IAAI,IAAA,uBAAa,GAAE,CAAC;iBAC3C;qBAAM;oBACL,UAAU,GAAG,SAAS,IAAI,IAAA,uBAAa,GAAE,CAAC;oBAE1C,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE;wBAClC,IAAI,OAAO,aAAa,EAAE,kBAAkB,KAAK,UAAU,EAAE;4BAC3D,UAAU,GAAG,aAAa,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;yBACpF;qBACF;yBAAM,IAAI,UAAU,EAAE;wBACrB,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;4BACnC,IAAI,GAAG,IAAI,OAAO,aAAa,EAAE,kBAAkB,KAAK,UAAU,EAAE;gCAClE,OAAO,aAAa,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;6BACvE;4BACD,OAAO,GAAG,CAAC;wBACb,CAAC,CAAC,CAAC;qBACJ;iBACF;gBACD,mBAAmB,GAAG,IAAI,CAAC;aAC5B;YACD,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,SAAS,EAAE,IAAA,0BAAgB,EAAC,aAAa,CAAC;QAC1C,gBAAgB,EAAE,0BAAgB,CAAC,IAAI,CAAC,KAAK,CAAC;QAC9C,gBAAgB,CAAC,KAAY,EAAE,OAA+C;YAC5E,OAAO,CACL,IAAA,0BAAgB,EAAC,KAAK,EAAE;gBACtB,OAAO,EAAE,EAAE;gBACX,GAAG,IAAI,CAAC,MAAM;gBACd,GAAG,OAAO;aACX,CAAC,IAAI,GAAG,CACV,CAAC;QACJ,CAAC;QACD,gEAAgE;QAChE,kDAAkD;QAClD,kBAAkB,EAAlB,2BAAkB;KACnB,CAAC;AACJ,CAAC;AAlED,4CAkEC","sourcesContent":["import { getActionFromState, LinkingOptions } from '@react-navigation/native';\nimport { Platform } from 'expo-modules-core';\n\nimport { RouteNode } from './Route';\nimport { State } from './fork/getPathFromState';\nimport { getReactNavigationConfig } from './getReactNavigationConfig';\nimport { RouterStore } from './global-state/router-store';\nimport {\n addEventListener,\n getInitialURL,\n getPathFromState,\n getStateFromPath,\n} from './link/linking';\nimport { NativeIntent, RequireContext } from './types';\n\nexport const INTERNAL_SLOT_NAME = '__root';\n\nexport function getNavigationConfig(routes: RouteNode, metaOnly: boolean = true) {\n return {\n screens: {\n [INTERNAL_SLOT_NAME]: {\n path: '',\n ...getReactNavigationConfig(routes, metaOnly),\n },\n },\n };\n}\n\nexport type ExpoLinkingOptions<T extends object = Record<string, unknown>> = LinkingOptions<T> & {\n getPathFromState?: typeof getPathFromState;\n getStateFromPath?: typeof getStateFromPath;\n};\n\nexport type LinkingConfigOptions = {\n metaOnly?: boolean;\n serverUrl?: string;\n getInitialURL?: typeof getInitialURL;\n};\n\nexport function getLinkingConfig(\n store: RouterStore,\n routes: RouteNode,\n context: RequireContext,\n { metaOnly = true, serverUrl }: LinkingConfigOptions = {}\n): ExpoLinkingOptions {\n // Returning `undefined` / `null from `getInitialURL` are valid values, so we need to track if it's been called.\n let hasCachedInitialUrl = false;\n let initialUrl: ReturnType<typeof getInitialURL> | undefined;\n\n const nativeLinkingKey = context\n .keys()\n .find((key) => key.match(/^\\.\\/\\+native-intent\\.[tj]sx?$/));\n const nativeLinking: NativeIntent | undefined = nativeLinkingKey\n ? context(nativeLinkingKey)\n : undefined;\n\n return {\n prefixes: [],\n config: getNavigationConfig(routes, metaOnly),\n // A custom getInitialURL is used on native to ensure the app always starts at\n // the root path if it's launched from something other than a deep link.\n // This helps keep the native functionality working like the web functionality.\n // For example, if you had a root navigator where the first screen was `/settings` and the second was `/index`\n // then `/index` would be used on web and `/settings` would be used on native.\n getInitialURL() {\n // Expo Router calls `getInitialURL` twice, which may confuse the user if they provide a custom `getInitialURL`.\n // Therefor we memoize the result.\n if (!hasCachedInitialUrl) {\n if (Platform.OS === 'web') {\n initialUrl = serverUrl ?? getInitialURL();\n } else {\n initialUrl = serverUrl ?? getInitialURL();\n\n if (typeof initialUrl === 'string') {\n if (typeof nativeLinking?.redirectSystemPath === 'function') {\n initialUrl = nativeLinking.redirectSystemPath({ path: initialUrl, initial: true });\n }\n } else if (initialUrl) {\n initialUrl = initialUrl.then((url) => {\n if (url && typeof nativeLinking?.redirectSystemPath === 'function') {\n return nativeLinking.redirectSystemPath({ path: url, initial: true });\n }\n return url;\n });\n }\n }\n hasCachedInitialUrl = true;\n }\n return initialUrl;\n },\n subscribe: addEventListener(nativeLinking),\n getStateFromPath: getStateFromPath.bind(store),\n getPathFromState(state: State, options: Parameters<typeof getPathFromState>[1]) {\n return (\n getPathFromState(state, {\n screens: {},\n ...this.config,\n ...options,\n }) ?? '/'\n );\n },\n // Add all functions to ensure the types never need to fallback.\n // This is a convenience for usage in the package.\n getActionFromState,\n };\n}\n"]}
1
+ {"version":3,"file":"getLinkingConfig.js","sourceRoot":"","sources":["../src/getLinkingConfig.ts"],"names":[],"mappings":";;;AAAA,qDAA8E;AAC9E,yDAA6C;AAI7C,yEAAsE;AAGtE,4CAKwB;AAGX,QAAA,kBAAkB,GAAG,QAAQ,CAAC;AAE3C,SAAgB,mBAAmB,CAAC,MAAiB,EAAE,WAAoB,IAAI;IAC7E,OAAO;QACL,OAAO,EAAE;YACP,CAAC,0BAAkB,CAAC,EAAE;gBACpB,IAAI,EAAE,EAAE;gBACR,GAAG,IAAA,mDAAwB,EAAC,MAAM,EAAE,QAAQ,CAAC;aAC9C;SACF;KACF,CAAC;AACJ,CAAC;AATD,kDASC;AAcD,SAAgB,gBAAgB,CAC9B,KAAkB,EAClB,MAAiB,EACjB,OAAuB,EACvB,EAAE,QAAQ,GAAG,IAAI,EAAE,SAAS,EAAE,SAAS,KAA2B,EAAE;IAEpE,gHAAgH;IAChH,IAAI,mBAAmB,GAAG,KAAK,CAAC;IAChC,IAAI,UAAwD,CAAC;IAE7D,MAAM,gBAAgB,GAAG,OAAO;SAC7B,IAAI,EAAE;SACN,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC,CAAC;IAC9D,MAAM,aAAa,GAA6B,gBAAgB;QAC9D,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC;QAC3B,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,MAAM,GAAG,mBAAmB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACrD,MAAM,qBAAqB,GAAG,0BAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAE3D,OAAO;QACL,QAAQ,EAAE,EAAE;QACZ,MAAM;QACN,8EAA8E;QAC9E,wEAAwE;QACxE,+EAA+E;QAC/E,8GAA8G;QAC9G,8EAA8E;QAC9E,aAAa;YACX,gHAAgH;YAChH,kCAAkC;YAClC,IAAI,CAAC,mBAAmB,EAAE;gBACxB,IAAI,4BAAQ,CAAC,EAAE,KAAK,KAAK,EAAE;oBACzB,UAAU,GAAG,SAAS,IAAI,IAAA,uBAAa,GAAE,CAAC;iBAC3C;qBAAM;oBACL,UAAU,GAAG,SAAS,IAAI,IAAA,uBAAa,GAAE,CAAC;oBAE1C,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE;wBAClC,UAAU,GAAG,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;wBAC9C,IAAI,UAAU,IAAI,OAAO,aAAa,EAAE,kBAAkB,KAAK,UAAU,EAAE;4BACzE,UAAU,GAAG,aAAa,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;yBACpF;qBACF;yBAAM,IAAI,UAAU,EAAE;wBACrB,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;4BACnC,GAAG,GAAG,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;4BAChC,IAAI,GAAG,IAAI,OAAO,aAAa,EAAE,kBAAkB,KAAK,UAAU,EAAE;gCAClE,OAAO,aAAa,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;6BACvE;4BACD,OAAO,GAAG,CAAC;wBACb,CAAC,CAAC,CAAC;qBACJ;iBACF;gBACD,mBAAmB,GAAG,IAAI,CAAC;aAC5B;YACD,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,SAAS,EAAE,IAAA,0BAAgB,EAAC,aAAa,EAAE,KAAK,CAAC;QACjD,gBAAgB,EAAE,qBAAqB;QACvC,gBAAgB,CAAC,KAAY,EAAE,OAA+C;YAC5E,OAAO,CACL,IAAA,0BAAgB,EAAC,KAAK,EAAE;gBACtB,GAAG,MAAM;gBACT,GAAG,OAAO;gBACV,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,OAAO,EAAE,OAAO,IAAI,EAAE;aAClD,CAAC,IAAI,GAAG,CACV,CAAC;QACJ,CAAC;QACD,gEAAgE;QAChE,kDAAkD;QAClD,kBAAkB,EAAlB,2BAAkB;KACnB,CAAC;AACJ,CAAC;AAvED,4CAuEC","sourcesContent":["import { getActionFromState, LinkingOptions } from '@react-navigation/native';\nimport { Platform } from 'expo-modules-core';\n\nimport { RouteNode } from './Route';\nimport { State } from './fork/getPathFromState';\nimport { getReactNavigationConfig } from './getReactNavigationConfig';\nimport { type RedirectConfig } from './getRoutesCore';\nimport { RouterStore } from './global-state/router-store';\nimport {\n addEventListener,\n getInitialURL,\n getPathFromState,\n getStateFromPath,\n} from './link/linking';\nimport { NativeIntent, RequireContext } from './types';\n\nexport const INTERNAL_SLOT_NAME = '__root';\n\nexport function getNavigationConfig(routes: RouteNode, metaOnly: boolean = true) {\n return {\n screens: {\n [INTERNAL_SLOT_NAME]: {\n path: '',\n ...getReactNavigationConfig(routes, metaOnly),\n },\n },\n };\n}\n\nexport type ExpoLinkingOptions<T extends object = Record<string, unknown>> = LinkingOptions<T> & {\n getPathFromState?: typeof getPathFromState;\n getStateFromPath?: typeof getStateFromPath;\n};\n\nexport type LinkingConfigOptions = {\n metaOnly?: boolean;\n serverUrl?: string;\n getInitialURL?: typeof getInitialURL;\n redirects?: RedirectConfig[];\n};\n\nexport function getLinkingConfig(\n store: RouterStore,\n routes: RouteNode,\n context: RequireContext,\n { metaOnly = true, serverUrl, redirects }: LinkingConfigOptions = {}\n): ExpoLinkingOptions {\n // Returning `undefined` / `null from `getInitialURL` are valid values, so we need to track if it's been called.\n let hasCachedInitialUrl = false;\n let initialUrl: ReturnType<typeof getInitialURL> | undefined;\n\n const nativeLinkingKey = context\n .keys()\n .find((key) => key.match(/^\\.\\/\\+native-intent\\.[tj]sx?$/));\n const nativeLinking: NativeIntent | undefined = nativeLinkingKey\n ? context(nativeLinkingKey)\n : undefined;\n\n const config = getNavigationConfig(routes, metaOnly);\n const boundGetStateFromPath = getStateFromPath.bind(store);\n\n return {\n prefixes: [],\n config,\n // A custom getInitialURL is used on native to ensure the app always starts at\n // the root path if it's launched from something other than a deep link.\n // This helps keep the native functionality working like the web functionality.\n // For example, if you had a root navigator where the first screen was `/settings` and the second was `/index`\n // then `/index` would be used on web and `/settings` would be used on native.\n getInitialURL() {\n // Expo Router calls `getInitialURL` twice, which may confuse the user if they provide a custom `getInitialURL`.\n // Therefor we memoize the result.\n if (!hasCachedInitialUrl) {\n if (Platform.OS === 'web') {\n initialUrl = serverUrl ?? getInitialURL();\n } else {\n initialUrl = serverUrl ?? getInitialURL();\n\n if (typeof initialUrl === 'string') {\n initialUrl = store.applyRedirects(initialUrl);\n if (initialUrl && typeof nativeLinking?.redirectSystemPath === 'function') {\n initialUrl = nativeLinking.redirectSystemPath({ path: initialUrl, initial: true });\n }\n } else if (initialUrl) {\n initialUrl = initialUrl.then((url) => {\n url = store.applyRedirects(url);\n if (url && typeof nativeLinking?.redirectSystemPath === 'function') {\n return nativeLinking.redirectSystemPath({ path: url, initial: true });\n }\n return url;\n });\n }\n }\n hasCachedInitialUrl = true;\n }\n return initialUrl;\n },\n subscribe: addEventListener(nativeLinking, store),\n getStateFromPath: boundGetStateFromPath,\n getPathFromState(state: State, options: Parameters<typeof getPathFromState>[1]) {\n return (\n getPathFromState(state, {\n ...config,\n ...options,\n screens: config.screens ?? options?.screens ?? {},\n }) ?? '/'\n );\n },\n // Add all functions to ensure the types never need to fallback.\n // This is a convenience for usage in the package.\n getActionFromState,\n };\n}\n"]}
@@ -5,6 +5,7 @@ export type Screen = string | {
5
5
  _route?: RouteNode;
6
6
  initialRouteName?: string;
7
7
  };
8
+ export declare function parseRouteSegments(segments: string): string;
8
9
  export declare function getReactNavigationScreensConfig(nodes: RouteNode[], metaOnly: boolean): Record<string, Screen>;
9
10
  export declare function getReactNavigationConfig(routes: RouteNode, metaOnly: boolean): {
10
11
  initialRouteName: undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"getReactNavigationConfig.d.ts","sourceRoot":"","sources":["../src/getReactNavigationConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGzC,MAAM,MAAM,MAAM,GACd,MAAM,GACN;IACE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AA4EN,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,SAAS,EAAE,EAClB,QAAQ,EAAE,OAAO,GAChB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAIxB;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO;;;EAY5E"}
1
+ {"version":3,"file":"getReactNavigationConfig.d.ts","sourceRoot":"","sources":["../src/getReactNavigationConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGzC,MAAM,MAAM,MAAM,GACd,MAAM,GACN;IACE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AA0BN,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAc3D;AAoCD,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,SAAS,EAAE,EAClB,QAAQ,EAAE,OAAO,GAChB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAIxB;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO;;;EAY5E"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getReactNavigationConfig = exports.getReactNavigationScreensConfig = void 0;
3
+ exports.getReactNavigationConfig = exports.getReactNavigationScreensConfig = exports.parseRouteSegments = void 0;
4
4
  const matchers_1 = require("./matchers");
5
5
  // `[page]` -> `:page`
6
6
  // `page` -> `page`
@@ -36,6 +36,7 @@ function parseRouteSegments(segments) {
36
36
  // Join to return as a path.
37
37
  .join('/'));
38
38
  }
39
+ exports.parseRouteSegments = parseRouteSegments;
39
40
  function convertRouteNodeToScreen(node, metaOnly) {
40
41
  const path = parseRouteSegments(node.route);
41
42
  if (!node.children.length) {
@@ -1 +1 @@
1
- {"version":3,"file":"getReactNavigationConfig.js","sourceRoot":"","sources":["../src/getReactNavigationConfig.ts"],"names":[],"mappings":";;;AACA,yCAAyE;AAWzE,sBAAsB;AACtB,mBAAmB;AACnB,SAAS,oCAAoC,CAAC,OAAe;IAC3D,wEAAwE;IACxE,IAAI,OAAO,KAAK,OAAO,EAAE;QACvB,OAAO,EAAE,CAAC;KACX;IACD,IAAI,OAAO,KAAK,YAAY,EAAE;QAC5B,OAAO,YAAY,CAAC;KACrB;IAED,MAAM,IAAI,GAAG,IAAA,oCAAyB,EAAC,OAAO,CAAC,CAAC;IAChD,IAAI,IAAI,IAAI,IAAI,EAAE;QAChB,OAAO,GAAG,GAAG,IAAI,CAAC;KACnB;IACD,MAAM,WAAW,GAAG,IAAA,2BAAgB,EAAC,OAAO,CAAC,CAAC;IAE9C,IAAI,WAAW,IAAI,IAAI,EAAE;QACvB,OAAO,IAAI,WAAW,EAAE,CAAC;KAC1B;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,kBAAkB,CAAC,QAAgB;IAC1C,OAAO;IACL,gEAAgE;IAChE,yDAAyD;IACzD,qEAAqE;IACrE,QAAQ;SACL,KAAK,CAAC,GAAG,CAAC;QACX,qDAAqD;SACpD,GAAG,CAAC,oCAAoC,CAAC;QAC1C,sDAAsD;SACrD,MAAM,CAAC,OAAO,CAAC;QAChB,4BAA4B;SAC3B,IAAI,CAAC,GAAG,CAAC,CACb,CAAC;AACJ,CAAC;AAED,SAAS,wBAAwB,CAAC,IAAe,EAAE,QAAiB;IAClE,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5C,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;QACzB,IAAI,CAAC,QAAQ,EAAE;YACb,OAAO;gBACL,IAAI;gBACJ,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,IAAI;aACb,CAAC;SACH;QACD,OAAO,IAAI,CAAC;KACb;IACD,MAAM,OAAO,GAAG,+BAA+B,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAEzE,MAAM,MAAM,GAAW;QACrB,IAAI;QACJ,OAAO;KACR,CAAC;IAEF,IAAI,IAAI,CAAC,gBAAgB,EAAE;QACzB,mEAAmE;QACnE,kEAAkE;QAClE,6EAA6E;QAC7E,2CAA2C;QAC3C,MAAM,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;KACjD;IAED,IAAI,CAAC,QAAQ,EAAE;QACb,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC;KACtB;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAgB,+BAA+B,CAC7C,KAAkB,EAClB,QAAiB;IAEjB,OAAO,MAAM,CAAC,WAAW,CACvB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,wBAAwB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAU,CAAC,CACrF,CAAC;AACJ,CAAC;AAPD,0EAOC;AAED,SAAgB,wBAAwB,CAAC,MAAiB,EAAE,QAAiB;IAC3E,MAAM,MAAM,GAAG;QACb,gBAAgB,EAAE,SAAS;QAC3B,OAAO,EAAE,+BAA+B,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC;KACpE,CAAC;IAEF,IAAI,MAAM,CAAC,gBAAgB,EAAE;QAC3B,yFAAyF;QACzF,yEAAyE;QACzE,MAAM,CAAC,gBAAgB,GAAG,MAAM,CAAC,gBAAuB,CAAC;KAC1D;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAZD,4DAYC","sourcesContent":["import type { RouteNode } from './Route';\nimport { matchDeepDynamicRouteName, matchDynamicName } from './matchers';\n\nexport type Screen =\n | string\n | {\n path: string;\n screens: Record<string, Screen>;\n _route?: RouteNode;\n initialRouteName?: string;\n };\n\n// `[page]` -> `:page`\n// `page` -> `page`\nfunction convertDynamicRouteToReactNavigation(segment: string): string {\n // NOTE(EvanBacon): To support shared routes we preserve group segments.\n if (segment === 'index') {\n return '';\n }\n if (segment === '+not-found') {\n return '*not-found';\n }\n\n const rest = matchDeepDynamicRouteName(segment);\n if (rest != null) {\n return '*' + rest;\n }\n const dynamicName = matchDynamicName(segment);\n\n if (dynamicName != null) {\n return `:${dynamicName}`;\n }\n\n return segment;\n}\n\nfunction parseRouteSegments(segments: string): string {\n return (\n // NOTE(EvanBacon): When there are nested routes without layouts\n // the node.route will be something like `app/home/index`\n // this needs to be split to ensure each segment is parsed correctly.\n segments\n .split('/')\n // Convert each segment to a React Navigation format.\n .map(convertDynamicRouteToReactNavigation)\n // Remove any empty paths from groups or index routes.\n .filter(Boolean)\n // Join to return as a path.\n .join('/')\n );\n}\n\nfunction convertRouteNodeToScreen(node: RouteNode, metaOnly: boolean): Screen {\n const path = parseRouteSegments(node.route);\n if (!node.children.length) {\n if (!metaOnly) {\n return {\n path,\n screens: {},\n _route: node,\n };\n }\n return path;\n }\n const screens = getReactNavigationScreensConfig(node.children, metaOnly);\n\n const screen: Screen = {\n path,\n screens,\n };\n\n if (node.initialRouteName) {\n // NOTE(EvanBacon): This is bad because it forces all Layout Routes\n // to be loaded into memory. We should move towards a system where\n // the initial route name is either loaded asynchronously in the Layout Route\n // or defined via a file system convention.\n screen.initialRouteName = node.initialRouteName;\n }\n\n if (!metaOnly) {\n screen._route = node;\n }\n\n return screen;\n}\n\nexport function getReactNavigationScreensConfig(\n nodes: RouteNode[],\n metaOnly: boolean\n): Record<string, Screen> {\n return Object.fromEntries(\n nodes.map((node) => [node.route, convertRouteNodeToScreen(node, metaOnly)] as const)\n );\n}\n\nexport function getReactNavigationConfig(routes: RouteNode, metaOnly: boolean) {\n const config = {\n initialRouteName: undefined,\n screens: getReactNavigationScreensConfig(routes.children, metaOnly),\n };\n\n if (routes.initialRouteName) {\n // We're using LinkingOptions the generic type is `object` instead of a proper ParamList.\n // So we need to cast the initialRouteName to `any` to avoid type errors.\n config.initialRouteName = routes.initialRouteName as any;\n }\n return config;\n}\n"]}
1
+ {"version":3,"file":"getReactNavigationConfig.js","sourceRoot":"","sources":["../src/getReactNavigationConfig.ts"],"names":[],"mappings":";;;AACA,yCAAyE;AAWzE,sBAAsB;AACtB,mBAAmB;AACnB,SAAS,oCAAoC,CAAC,OAAe;IAC3D,wEAAwE;IACxE,IAAI,OAAO,KAAK,OAAO,EAAE;QACvB,OAAO,EAAE,CAAC;KACX;IACD,IAAI,OAAO,KAAK,YAAY,EAAE;QAC5B,OAAO,YAAY,CAAC;KACrB;IAED,MAAM,IAAI,GAAG,IAAA,oCAAyB,EAAC,OAAO,CAAC,CAAC;IAChD,IAAI,IAAI,IAAI,IAAI,EAAE;QAChB,OAAO,GAAG,GAAG,IAAI,CAAC;KACnB;IACD,MAAM,WAAW,GAAG,IAAA,2BAAgB,EAAC,OAAO,CAAC,CAAC;IAE9C,IAAI,WAAW,IAAI,IAAI,EAAE;QACvB,OAAO,IAAI,WAAW,EAAE,CAAC;KAC1B;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAgB,kBAAkB,CAAC,QAAgB;IACjD,OAAO;IACL,gEAAgE;IAChE,yDAAyD;IACzD,qEAAqE;IACrE,QAAQ;SACL,KAAK,CAAC,GAAG,CAAC;QACX,qDAAqD;SACpD,GAAG,CAAC,oCAAoC,CAAC;QAC1C,sDAAsD;SACrD,MAAM,CAAC,OAAO,CAAC;QAChB,4BAA4B;SAC3B,IAAI,CAAC,GAAG,CAAC,CACb,CAAC;AACJ,CAAC;AAdD,gDAcC;AAED,SAAS,wBAAwB,CAAC,IAAe,EAAE,QAAiB;IAClE,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5C,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;QACzB,IAAI,CAAC,QAAQ,EAAE;YACb,OAAO;gBACL,IAAI;gBACJ,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,IAAI;aACb,CAAC;SACH;QACD,OAAO,IAAI,CAAC;KACb;IACD,MAAM,OAAO,GAAG,+BAA+B,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAEzE,MAAM,MAAM,GAAW;QACrB,IAAI;QACJ,OAAO;KACR,CAAC;IAEF,IAAI,IAAI,CAAC,gBAAgB,EAAE;QACzB,mEAAmE;QACnE,kEAAkE;QAClE,6EAA6E;QAC7E,2CAA2C;QAC3C,MAAM,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;KACjD;IAED,IAAI,CAAC,QAAQ,EAAE;QACb,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC;KACtB;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAgB,+BAA+B,CAC7C,KAAkB,EAClB,QAAiB;IAEjB,OAAO,MAAM,CAAC,WAAW,CACvB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,wBAAwB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAU,CAAC,CACrF,CAAC;AACJ,CAAC;AAPD,0EAOC;AAED,SAAgB,wBAAwB,CAAC,MAAiB,EAAE,QAAiB;IAC3E,MAAM,MAAM,GAAG;QACb,gBAAgB,EAAE,SAAS;QAC3B,OAAO,EAAE,+BAA+B,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC;KACpE,CAAC;IAEF,IAAI,MAAM,CAAC,gBAAgB,EAAE;QAC3B,yFAAyF;QACzF,yEAAyE;QACzE,MAAM,CAAC,gBAAgB,GAAG,MAAM,CAAC,gBAAuB,CAAC;KAC1D;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAZD,4DAYC","sourcesContent":["import type { RouteNode } from './Route';\nimport { matchDeepDynamicRouteName, matchDynamicName } from './matchers';\n\nexport type Screen =\n | string\n | {\n path: string;\n screens: Record<string, Screen>;\n _route?: RouteNode;\n initialRouteName?: string;\n };\n\n// `[page]` -> `:page`\n// `page` -> `page`\nfunction convertDynamicRouteToReactNavigation(segment: string): string {\n // NOTE(EvanBacon): To support shared routes we preserve group segments.\n if (segment === 'index') {\n return '';\n }\n if (segment === '+not-found') {\n return '*not-found';\n }\n\n const rest = matchDeepDynamicRouteName(segment);\n if (rest != null) {\n return '*' + rest;\n }\n const dynamicName = matchDynamicName(segment);\n\n if (dynamicName != null) {\n return `:${dynamicName}`;\n }\n\n return segment;\n}\n\nexport function parseRouteSegments(segments: string): string {\n return (\n // NOTE(EvanBacon): When there are nested routes without layouts\n // the node.route will be something like `app/home/index`\n // this needs to be split to ensure each segment is parsed correctly.\n segments\n .split('/')\n // Convert each segment to a React Navigation format.\n .map(convertDynamicRouteToReactNavigation)\n // Remove any empty paths from groups or index routes.\n .filter(Boolean)\n // Join to return as a path.\n .join('/')\n );\n}\n\nfunction convertRouteNodeToScreen(node: RouteNode, metaOnly: boolean): Screen {\n const path = parseRouteSegments(node.route);\n if (!node.children.length) {\n if (!metaOnly) {\n return {\n path,\n screens: {},\n _route: node,\n };\n }\n return path;\n }\n const screens = getReactNavigationScreensConfig(node.children, metaOnly);\n\n const screen: Screen = {\n path,\n screens,\n };\n\n if (node.initialRouteName) {\n // NOTE(EvanBacon): This is bad because it forces all Layout Routes\n // to be loaded into memory. We should move towards a system where\n // the initial route name is either loaded asynchronously in the Layout Route\n // or defined via a file system convention.\n screen.initialRouteName = node.initialRouteName;\n }\n\n if (!metaOnly) {\n screen._route = node;\n }\n\n return screen;\n}\n\nexport function getReactNavigationScreensConfig(\n nodes: RouteNode[],\n metaOnly: boolean\n): Record<string, Screen> {\n return Object.fromEntries(\n nodes.map((node) => [node.route, convertRouteNodeToScreen(node, metaOnly)] as const)\n );\n}\n\nexport function getReactNavigationConfig(routes: RouteNode, metaOnly: boolean) {\n const config = {\n initialRouteName: undefined,\n screens: getReactNavigationScreensConfig(routes.children, metaOnly),\n };\n\n if (routes.initialRouteName) {\n // We're using LinkingOptions the generic type is `object` instead of a proper ParamList.\n // So we need to cast the initialRouteName to `any` to avoid type errors.\n config.initialRouteName = routes.initialRouteName as any;\n }\n return config;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"getRoutes.d.ts","sourceRoot":"","sources":["../src/getRoutes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAA8B,KAAK,OAAO,IAAI,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC1F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;AAC1D;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,aAAa,EAAE,cAAc,EAAE,OAAO,GAAE,OAAY,GAAG,SAAS,GAAG,IAAI,CAkDhG;AAED,wBAAgB,cAAc,CAC5B,aAAa,EAAE,cAAc,EAC7B,OAAO,GAAE,OAAY,GACpB,SAAS,GAAG,IAAI,CAKlB;AAED,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"getRoutes.d.ts","sourceRoot":"","sources":["../src/getRoutes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAA8B,KAAK,OAAO,IAAI,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC1F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;AAC1D;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,aAAa,EAAE,cAAc,EAAE,OAAO,GAAE,OAAY,GAAG,SAAS,GAAG,IAAI,CAyDhG;AAED,wBAAgB,cAAc,CAC5B,aAAa,EAAE,cAAc,EAC7B,OAAO,GAAE,OAAY,GACpB,SAAS,GAAG,IAAI,CAKlB;AAED,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
@@ -16,7 +16,7 @@ const getRoutesCore_1 = require("./getRoutesCore");
16
16
  */
17
17
  function getRoutes(contextModule, options = {}) {
18
18
  return (0, getRoutesCore_1.getRoutes)(contextModule, {
19
- getSystemRoute({ route, type }) {
19
+ getSystemRoute({ route, type }, defaults) {
20
20
  if (route === '' && type === 'layout') {
21
21
  // Root layout when no layout is defined.
22
22
  return {
@@ -62,6 +62,14 @@ function getRoutes(contextModule, options = {}) {
62
62
  children: [],
63
63
  };
64
64
  }
65
+ else if ((type === 'redirect' || type === 'rewrite') && defaults) {
66
+ return {
67
+ ...defaults,
68
+ loadRoute() {
69
+ return require('./getRoutesRedirects').getRedirectModule(route);
70
+ },
71
+ };
72
+ }
65
73
  throw new Error(`Unknown system route: ${route} and type: ${type}`);
66
74
  },
67
75
  ...options,
@@ -1 +1 @@
1
- {"version":3,"file":"getRoutes.js","sourceRoot":"","sources":["../src/getRoutes.ts"],"names":[],"mappings":";;;AACA,mDAA0F;AAI1F;;;;;;;;;;;GAWG;AACH,SAAgB,SAAS,CAAC,aAA6B,EAAE,UAAmB,EAAE;IAC5E,OAAO,IAAA,yBAAa,EAAC,aAAa,EAAE;QAClC,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE;YAC5B,IAAI,KAAK,KAAK,EAAE,IAAI,IAAI,KAAK,QAAQ,EAAE;gBACrC,yCAAyC;gBACzC,OAAO;oBACL,IAAI,EAAE,QAAQ;oBACd,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;wBAChB,OAAO,EAAG,OAAO,CAAC,mBAAmB,CAAwC;6BAC1E,gBAAgB;qBACpB,CAAC;oBACF,8CAA8C;oBAC9C,UAAU,EAAE,sCAAsC;oBAClD,KAAK,EAAE,EAAE;oBACT,SAAS,EAAE,IAAI;oBACf,OAAO,EAAE,IAAI;oBACb,QAAQ,EAAE,EAAE;iBACb,CAAC;aACH;iBAAM,IAAI,KAAK,KAAK,UAAU,IAAI,IAAI,KAAK,OAAO,EAAE;gBACnD,OAAO;oBACL,SAAS;wBACP,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;wBAC9D,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC;oBAC7C,CAAC;oBACD,KAAK,EAAE,UAAU;oBACjB,IAAI,EAAE,OAAO;oBACb,UAAU,EAAE,oCAAoC;oBAChD,SAAS,EAAE,IAAI;oBACf,QAAQ,EAAE,IAAI;oBACd,OAAO,EAAE,IAAI;oBACb,QAAQ,EAAE,EAAE;iBACb,CAAC;aACH;iBAAM,IAAI,KAAK,KAAK,YAAY,IAAI,IAAI,KAAK,OAAO,EAAE;gBACrD,OAAO;oBACL,SAAS;wBACP,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC,SAAS,EAAE,CAAC;oBAC7D,CAAC;oBACD,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE,YAAY;oBACnB,UAAU,EAAE,sCAAsC;oBAClD,SAAS,EAAE,IAAI;oBACf,QAAQ,EAAE,IAAI;oBACd,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;oBAC7D,QAAQ,EAAE,EAAE;iBACb,CAAC;aACH;YACD,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,cAAc,IAAI,EAAE,CAAC,CAAC;QACtE,CAAC;QACD,GAAG,OAAO;KACX,CAAC,CAAC;AACL,CAAC;AAlDD,8BAkDC;AAED,SAAgB,cAAc,CAC5B,aAA6B,EAC7B,UAAmB,EAAE;IAErB,OAAO,SAAS,CAAC,aAAa,EAAE;QAC9B,GAAG,OAAO;QACV,aAAa,EAAE,IAAI;KACpB,CAAC,CAAC;AACL,CAAC;AARD,wCAQC;AAED,iDAAoF;AAA3E,gHAAA,eAAe,OAAA;AAAE,kHAAA,iBAAiB,OAAA;AAAE,8GAAA,aAAa,OAAA","sourcesContent":["import type { RouteNode } from './Route';\nimport { getRoutes as getRoutesCore, type Options as OptionsCore } from './getRoutesCore';\nimport type { RequireContext } from './types';\n\nexport type Options = Omit<OptionsCore, 'getSystemRoute'>;\n/**\n * Given a Metro context module, return an array of nested routes.\n *\n * This is a two step process:\n * 1. Convert the RequireContext keys (file paths) into a directory tree.\n * - This should extrapolate array syntax into multiple routes\n * - Routes are given a specificity score\n * 2. Flatten the directory tree into routes\n * - Routes in directories without _layout files are hoisted to the nearest _layout\n * - The name of the route is relative to the nearest _layout\n * - If multiple routes have the same name, the most specific route is used\n */\nexport function getRoutes(contextModule: RequireContext, options: Options = {}): RouteNode | null {\n return getRoutesCore(contextModule, {\n getSystemRoute({ route, type }) {\n if (route === '' && type === 'layout') {\n // Root layout when no layout is defined.\n return {\n type: 'layout',\n loadRoute: () => ({\n default: (require('./views/Navigator') as typeof import('./views/Navigator'))\n .DefaultNavigator,\n }),\n // Generate a fake file name for the directory\n contextKey: 'expo-router/build/views/Navigator.js',\n route: '',\n generated: true,\n dynamic: null,\n children: [],\n };\n } else if (route === '_sitemap' && type === 'route') {\n return {\n loadRoute() {\n const { Sitemap, getNavOptions } = require('./views/Sitemap');\n return { default: Sitemap, getNavOptions };\n },\n route: '_sitemap',\n type: 'route',\n contextKey: 'expo-router/build/views/Sitemap.js',\n generated: true,\n internal: true,\n dynamic: null,\n children: [],\n };\n } else if (route === '+not-found' && type === 'route') {\n return {\n loadRoute() {\n return { default: require('./views/Unmatched').Unmatched };\n },\n type: 'route',\n route: '+not-found',\n contextKey: 'expo-router/build/views/Unmatched.js',\n generated: true,\n internal: true,\n dynamic: [{ name: '+not-found', deep: true, notFound: true }],\n children: [],\n };\n }\n throw new Error(`Unknown system route: ${route} and type: ${type}`);\n },\n ...options,\n });\n}\n\nexport function getExactRoutes(\n contextModule: RequireContext,\n options: Options = {}\n): RouteNode | null {\n return getRoutes(contextModule, {\n ...options,\n skipGenerated: true,\n });\n}\n\nexport { generateDynamic, extrapolateGroups, getIgnoreList } from './getRoutesCore';\n"]}
1
+ {"version":3,"file":"getRoutes.js","sourceRoot":"","sources":["../src/getRoutes.ts"],"names":[],"mappings":";;;AACA,mDAA0F;AAI1F;;;;;;;;;;;GAWG;AACH,SAAgB,SAAS,CAAC,aAA6B,EAAE,UAAmB,EAAE;IAC5E,OAAO,IAAA,yBAAa,EAAC,aAAa,EAAE;QAClC,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ;YACtC,IAAI,KAAK,KAAK,EAAE,IAAI,IAAI,KAAK,QAAQ,EAAE;gBACrC,yCAAyC;gBACzC,OAAO;oBACL,IAAI,EAAE,QAAQ;oBACd,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;wBAChB,OAAO,EAAG,OAAO,CAAC,mBAAmB,CAAwC;6BAC1E,gBAAgB;qBACpB,CAAC;oBACF,8CAA8C;oBAC9C,UAAU,EAAE,sCAAsC;oBAClD,KAAK,EAAE,EAAE;oBACT,SAAS,EAAE,IAAI;oBACf,OAAO,EAAE,IAAI;oBACb,QAAQ,EAAE,EAAE;iBACb,CAAC;aACH;iBAAM,IAAI,KAAK,KAAK,UAAU,IAAI,IAAI,KAAK,OAAO,EAAE;gBACnD,OAAO;oBACL,SAAS;wBACP,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;wBAC9D,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC;oBAC7C,CAAC;oBACD,KAAK,EAAE,UAAU;oBACjB,IAAI,EAAE,OAAO;oBACb,UAAU,EAAE,oCAAoC;oBAChD,SAAS,EAAE,IAAI;oBACf,QAAQ,EAAE,IAAI;oBACd,OAAO,EAAE,IAAI;oBACb,QAAQ,EAAE,EAAE;iBACb,CAAC;aACH;iBAAM,IAAI,KAAK,KAAK,YAAY,IAAI,IAAI,KAAK,OAAO,EAAE;gBACrD,OAAO;oBACL,SAAS;wBACP,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC,SAAS,EAAE,CAAC;oBAC7D,CAAC;oBACD,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE,YAAY;oBACnB,UAAU,EAAE,sCAAsC;oBAClD,SAAS,EAAE,IAAI;oBACf,QAAQ,EAAE,IAAI;oBACd,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;oBAC7D,QAAQ,EAAE,EAAE;iBACb,CAAC;aACH;iBAAM,IAAI,CAAC,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,SAAS,CAAC,IAAI,QAAQ,EAAE;gBAClE,OAAO;oBACL,GAAG,QAAQ;oBACX,SAAS;wBACP,OAAO,OAAO,CAAC,sBAAsB,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;oBAClE,CAAC;iBACF,CAAC;aACH;YACD,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,cAAc,IAAI,EAAE,CAAC,CAAC;QACtE,CAAC;QACD,GAAG,OAAO;KACX,CAAC,CAAC;AACL,CAAC;AAzDD,8BAyDC;AAED,SAAgB,cAAc,CAC5B,aAA6B,EAC7B,UAAmB,EAAE;IAErB,OAAO,SAAS,CAAC,aAAa,EAAE;QAC9B,GAAG,OAAO;QACV,aAAa,EAAE,IAAI;KACpB,CAAC,CAAC;AACL,CAAC;AARD,wCAQC;AAED,iDAAoF;AAA3E,gHAAA,eAAe,OAAA;AAAE,kHAAA,iBAAiB,OAAA;AAAE,8GAAA,aAAa,OAAA","sourcesContent":["import type { RouteNode } from './Route';\nimport { getRoutes as getRoutesCore, type Options as OptionsCore } from './getRoutesCore';\nimport type { RequireContext } from './types';\n\nexport type Options = Omit<OptionsCore, 'getSystemRoute'>;\n/**\n * Given a Metro context module, return an array of nested routes.\n *\n * This is a two step process:\n * 1. Convert the RequireContext keys (file paths) into a directory tree.\n * - This should extrapolate array syntax into multiple routes\n * - Routes are given a specificity score\n * 2. Flatten the directory tree into routes\n * - Routes in directories without _layout files are hoisted to the nearest _layout\n * - The name of the route is relative to the nearest _layout\n * - If multiple routes have the same name, the most specific route is used\n */\nexport function getRoutes(contextModule: RequireContext, options: Options = {}): RouteNode | null {\n return getRoutesCore(contextModule, {\n getSystemRoute({ route, type }, defaults) {\n if (route === '' && type === 'layout') {\n // Root layout when no layout is defined.\n return {\n type: 'layout',\n loadRoute: () => ({\n default: (require('./views/Navigator') as typeof import('./views/Navigator'))\n .DefaultNavigator,\n }),\n // Generate a fake file name for the directory\n contextKey: 'expo-router/build/views/Navigator.js',\n route: '',\n generated: true,\n dynamic: null,\n children: [],\n };\n } else if (route === '_sitemap' && type === 'route') {\n return {\n loadRoute() {\n const { Sitemap, getNavOptions } = require('./views/Sitemap');\n return { default: Sitemap, getNavOptions };\n },\n route: '_sitemap',\n type: 'route',\n contextKey: 'expo-router/build/views/Sitemap.js',\n generated: true,\n internal: true,\n dynamic: null,\n children: [],\n };\n } else if (route === '+not-found' && type === 'route') {\n return {\n loadRoute() {\n return { default: require('./views/Unmatched').Unmatched };\n },\n type: 'route',\n route: '+not-found',\n contextKey: 'expo-router/build/views/Unmatched.js',\n generated: true,\n internal: true,\n dynamic: [{ name: '+not-found', deep: true, notFound: true }],\n children: [],\n };\n } else if ((type === 'redirect' || type === 'rewrite') && defaults) {\n return {\n ...defaults,\n loadRoute() {\n return require('./getRoutesRedirects').getRedirectModule(route);\n },\n };\n }\n throw new Error(`Unknown system route: ${route} and type: ${type}`);\n },\n ...options,\n });\n}\n\nexport function getExactRoutes(\n contextModule: RequireContext,\n options: Options = {}\n): RouteNode | null {\n return getRoutes(contextModule, {\n ...options,\n skipGenerated: true,\n });\n}\n\nexport { generateDynamic, extrapolateGroups, getIgnoreList } from './getRoutesCore';\n"]}
@@ -12,8 +12,23 @@ export type Options = {
12
12
  platformRoutes?: boolean;
13
13
  sitemap?: boolean;
14
14
  platform?: string;
15
+ redirects?: RedirectConfig[];
16
+ rewrites?: RewriteConfig[];
17
+ preserveRedirectAndRewrites?: boolean;
15
18
  /** Get the system route for a location. Useful for shimming React Native imports in SSR environments. */
16
- getSystemRoute: (route: Pick<RouteNode, 'route' | 'type'>) => RouteNode;
19
+ getSystemRoute: (route: Pick<RouteNode, 'route' | 'type'>, defaults?: RouteNode) => RouteNode;
20
+ };
21
+ export type RedirectConfig = {
22
+ source: string;
23
+ destination: string;
24
+ permanent?: boolean;
25
+ methods?: string[];
26
+ external?: boolean;
27
+ };
28
+ export type RewriteConfig = {
29
+ source: string;
30
+ destination: string;
31
+ methods?: string[];
17
32
  };
18
33
  /**
19
34
  * Given a Metro context module, return an array of nested routes.
@@ -1 +1 @@
1
- {"version":3,"file":"getRoutesCore.d.ts","sourceRoot":"","sources":["../src/getRoutesCore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAS5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,MAAM,OAAO,GAAG;IACpB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,yGAAyG;IACzG,cAAc,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,CAAC,KAAK,SAAS,CAAC;CACzE,CAAC;AAUF;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,aAAa,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAe3F;AA0WD,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,OAAO,YAM9C;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,GAAG,CAAC,MAAM,CAAa,GAAG,GAAG,CAAC,MAAM,CAAC,CAwBzF;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,EAAE,GAAG,IAAI,CAqBxE"}
1
+ {"version":3,"file":"getRoutesCore.d.ts","sourceRoot":"","sources":["../src/getRoutesCore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAY5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG9C,MAAM,MAAM,OAAO,GAAG;IACpB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;IAC7B,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;IAE3B,2BAA2B,CAAC,EAAE,OAAO,CAAC;IAEtC,yGAAyG;IACzG,cAAc,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,CAAC,EAAE,QAAQ,CAAC,EAAE,SAAS,KAAK,SAAS,CAAC;CAC/F,CAAC;AAQF,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAIF;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,aAAa,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAe3F;AA2gBD,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,OAAO,YAM9C;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,GAAG,CAAC,MAAM,CAAa,GAAG,GAAG,CAAC,MAAM,CAAC,CAwBzF;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,EAAE,GAAG,IAAI,CAqBxE"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateDynamic = exports.extrapolateGroups = exports.getIgnoreList = exports.getRoutes = void 0;
4
4
  const matchers_1 = require("./matchers");
5
+ const url_1 = require("./utils/url");
5
6
  const validPlatforms = new Set(['android', 'ios', 'native', 'web']);
6
7
  /**
7
8
  * Given a Metro context module, return an array of nested routes.
@@ -38,7 +39,7 @@ function getDirectoryTree(contextModule, options) {
38
39
  ignoreList.push(...options.ignore);
39
40
  }
40
41
  if (!options.preserveApiRoutes) {
41
- ignoreList.push(/\+api\.[tj]sx?$/);
42
+ ignoreList.push(/\+api$/, /\+api\.[tj]sx?$/);
42
43
  }
43
44
  const rootDirectory = {
44
45
  files: new Map(),
@@ -46,12 +47,100 @@ function getDirectoryTree(contextModule, options) {
46
47
  };
47
48
  let hasRoutes = false;
48
49
  let isValid = false;
49
- for (const filePath of contextModule.keys()) {
50
+ const contextKeys = contextModule.keys();
51
+ const redirects = {};
52
+ const rewrites = {};
53
+ let validRedirectDestinations;
54
+ // If we are keeping redirects as valid routes, then we need to add them to the contextKeys
55
+ // This is useful for generating a sitemap with redirects, or static site generation that includes redirects
56
+ if (options.preserveRedirectAndRewrites) {
57
+ if (options.redirects) {
58
+ for (const redirect of options.redirects) {
59
+ // Remove the leading `./` or `/`
60
+ const source = redirect.source.replace(/^\.?\//, '');
61
+ const isExternalRedirect = (0, url_1.shouldLinkExternally)(redirect.destination);
62
+ const targetDestination = isExternalRedirect
63
+ ? redirect.destination
64
+ : (0, matchers_1.stripInvisibleSegmentsFromPath)((0, matchers_1.removeFileSystemDots)((0, matchers_1.removeFileSystemExtensions)(redirect.destination.replace(/^\.?\/?/, ''))));
65
+ const normalizedSource = (0, matchers_1.removeFileSystemDots)((0, matchers_1.removeSupportedExtensions)(source));
66
+ if (ignoreList.some((regex) => regex.test(normalizedSource))) {
67
+ continue;
68
+ }
69
+ // Loop over this once and cache the valid destinations
70
+ validRedirectDestinations ??= contextKeys.map((key) => {
71
+ return [
72
+ (0, matchers_1.stripInvisibleSegmentsFromPath)((0, matchers_1.removeFileSystemDots)((0, matchers_1.removeSupportedExtensions)(key))),
73
+ key,
74
+ ];
75
+ });
76
+ const destination = isExternalRedirect
77
+ ? targetDestination
78
+ : validRedirectDestinations.find((key) => key[0] === targetDestination)?.[1];
79
+ if (!destination) {
80
+ /*
81
+ * Only throw the error when we are preserving the api routes
82
+ * When doing a static export, API routes will not exist so the redirect destination may not exist.
83
+ * The desired behavior for this error is to warn the user when running `expo start`, so its ok if
84
+ * `expo export` swallows this error.
85
+ */
86
+ if (options.preserveApiRoutes) {
87
+ throw new Error(`Redirect destination "${redirect.destination}" does not exist.`);
88
+ }
89
+ continue;
90
+ }
91
+ const fakeContextKey = (0, matchers_1.removeFileSystemDots)((0, matchers_1.removeSupportedExtensions)(source));
92
+ contextKeys.push(fakeContextKey);
93
+ redirects[fakeContextKey] = {
94
+ source,
95
+ destination,
96
+ permanent: Boolean(redirect.permanent),
97
+ external: isExternalRedirect,
98
+ methods: redirect.methods,
99
+ };
100
+ }
101
+ }
102
+ if (options.rewrites) {
103
+ for (const rewrite of options.rewrites) {
104
+ // Remove the leading `./` or `/`
105
+ const source = rewrite.source.replace(/^\.?\//, '');
106
+ const targetDestination = (0, matchers_1.stripInvisibleSegmentsFromPath)((0, matchers_1.removeFileSystemDots)((0, matchers_1.removeSupportedExtensions)(rewrite.destination)));
107
+ const normalizedSource = (0, matchers_1.removeFileSystemDots)((0, matchers_1.removeSupportedExtensions)(source));
108
+ if (ignoreList.some((regex) => regex.test(normalizedSource))) {
109
+ continue;
110
+ }
111
+ // Loop over this once and cache the valid destinations
112
+ validRedirectDestinations ??= contextKeys.map((key) => {
113
+ return [
114
+ (0, matchers_1.stripInvisibleSegmentsFromPath)((0, matchers_1.removeFileSystemDots)((0, matchers_1.removeSupportedExtensions)(key))),
115
+ key,
116
+ ];
117
+ });
118
+ const destination = validRedirectDestinations.find((key) => key[0] === targetDestination)?.[1];
119
+ if (!destination) {
120
+ /*
121
+ * Only throw the error when we are preserving the api routes
122
+ * When doing a static export, API routes will not exist so the redirect destination may not exist.
123
+ * The desired behavior for this error is to warn the user when running `expo start`, so its ok if
124
+ * `expo export` swallows this error.
125
+ */
126
+ if (options.preserveApiRoutes) {
127
+ throw new Error(`Redirect destination "${rewrite.destination}" does not exist.`);
128
+ }
129
+ continue;
130
+ }
131
+ // Add a fake context key
132
+ const fakeContextKey = `./${source}.tsx`;
133
+ contextKeys.push(fakeContextKey);
134
+ rewrites[fakeContextKey] = { source, destination, methods: rewrite.methods };
135
+ }
136
+ }
137
+ }
138
+ for (const filePath of contextKeys) {
50
139
  if (ignoreList.some((regex) => regex.test(filePath))) {
51
140
  continue;
52
141
  }
53
142
  isValid = true;
54
- const meta = getFileMeta(filePath, options);
143
+ const meta = getFileMeta(filePath, options, redirects, rewrites);
55
144
  // This is a file that should be ignored. e.g maybe it has an invalid platform?
56
145
  if (meta.specificity < 0) {
57
146
  continue;
@@ -95,6 +184,35 @@ function getDirectoryTree(contextModule, options) {
95
184
  dynamic: null,
96
185
  children: [], // While we are building the directory tree, we don't know the node's children just yet. This is added during hoisting
97
186
  };
187
+ if (meta.isRedirect) {
188
+ node.destinationContextKey = redirects[filePath].destination;
189
+ node.permanent = redirects[filePath].permanent;
190
+ node.generated = true;
191
+ if (node.type === 'route') {
192
+ node = options.getSystemRoute({
193
+ type: 'redirect',
194
+ route: (0, matchers_1.removeFileSystemDots)((0, matchers_1.removeSupportedExtensions)(node.destinationContextKey)),
195
+ }, node);
196
+ }
197
+ if (redirects[filePath].methods) {
198
+ node.methods = redirects[filePath].methods;
199
+ }
200
+ node.type = 'redirect';
201
+ }
202
+ if (meta.isRewrite) {
203
+ node.destinationContextKey = rewrites[filePath].destination;
204
+ node.generated = true;
205
+ if (node.type === 'route') {
206
+ node = options.getSystemRoute({
207
+ type: 'rewrite',
208
+ route: (0, matchers_1.removeFileSystemDots)((0, matchers_1.removeSupportedExtensions)(node.destinationContextKey)),
209
+ }, node);
210
+ }
211
+ if (redirects[filePath].methods) {
212
+ node.methods = redirects[filePath].methods;
213
+ }
214
+ node.type = 'rewrite';
215
+ }
98
216
  if (process.env.NODE_ENV === 'development') {
99
217
  // If the user has set the `EXPO_ROUTER_IMPORT_MODE` to `sync` then we should
100
218
  // filter the missing routes.
@@ -268,22 +386,22 @@ pathToRemove = '') {
268
386
  }
269
387
  return layout;
270
388
  }
271
- function getFileMeta(key, options) {
389
+ function getFileMeta(originalKey, options, redirects, rewrites) {
272
390
  // Remove the leading `./`
273
- key = key.replace(/^\.\//, '');
274
- const parts = key.split('/');
275
- let route = (0, matchers_1.removeSupportedExtensions)(key);
391
+ const key = (0, matchers_1.removeSupportedExtensions)((0, matchers_1.removeFileSystemDots)(originalKey));
392
+ let route = key;
393
+ const parts = (0, matchers_1.removeFileSystemDots)(originalKey).split('/');
276
394
  const filename = parts[parts.length - 1];
277
395
  const [filenameWithoutExtensions, platformExtension] = (0, matchers_1.removeSupportedExtensions)(filename).split('.');
278
396
  const isLayout = filenameWithoutExtensions === '_layout';
279
- const isApi = filename.match(/\+api\.(\w+\.)?[jt]sx?$/);
397
+ const isApi = originalKey.match(/\+api\.(\w+\.)?[jt]sx?$/);
280
398
  if (filenameWithoutExtensions.startsWith('(') && filenameWithoutExtensions.endsWith(')')) {
281
- throw new Error(`Invalid route ./${key}. Routes cannot end with '(group)' syntax`);
399
+ throw new Error(`Invalid route ${originalKey}. Routes cannot end with '(group)' syntax`);
282
400
  }
283
401
  // Nested routes cannot start with the '+' character, except for the '+not-found' route
284
402
  if (!isApi && filename.startsWith('+') && filenameWithoutExtensions !== '+not-found') {
285
403
  const renamedRoute = [...parts.slice(0, -1), filename.slice(1)].join('/');
286
- throw new Error(`Invalid route ./${key}. Route nodes cannot start with the '+' character. "Please rename to ${renamedRoute}"`);
404
+ throw new Error(`Invalid route ${originalKey}. Route nodes cannot start with the '+' character. "Please rename to ${renamedRoute}"`);
287
405
  }
288
406
  let specificity = 0;
289
407
  const hasPlatformExtension = validPlatforms.has(platformExtension);
@@ -312,7 +430,7 @@ function getFileMeta(key, options) {
312
430
  specificity = -1;
313
431
  }
314
432
  if (isApi && specificity !== 0) {
315
- throw new Error(`Api routes cannot have platform extensions. Please remove '.${platformExtension}' from './${key}'`);
433
+ throw new Error(`Api routes cannot have platform extensions. Please remove '.${platformExtension}' from '${originalKey}'`);
316
434
  }
317
435
  route = route.replace(new RegExp(`.${platformExtension}$`), '');
318
436
  }
@@ -321,6 +439,8 @@ function getFileMeta(key, options) {
321
439
  specificity,
322
440
  isLayout,
323
441
  isApi,
442
+ isRedirect: key in redirects,
443
+ isRewrite: key in rewrites,
324
444
  };
325
445
  }
326
446
  function getIgnoreList(options) {
@@ -441,6 +561,9 @@ function crawlAndAppendInitialRoutesAndEntryFiles(node, options, entryPoints = [
441
561
  if (node.type === 'route') {
442
562
  node.entryPoints = [...new Set([...entryPoints, node.contextKey])];
443
563
  }
564
+ else if (node.type === 'redirect') {
565
+ node.entryPoints = [...new Set([...entryPoints, node.destinationContextKey])];
566
+ }
444
567
  else if (node.type === 'layout') {
445
568
  if (!node.children) {
446
569
  throw new Error(`Layout "${node.contextKey}" does not contain any child routes`);