@expo/cli 0.10.9 → 0.10.11

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 (25) hide show
  1. package/build/bin/cli +2 -2
  2. package/build/src/export/index.js +3 -1
  3. package/build/src/export/index.js.map +1 -1
  4. package/build/src/export/resolveOptions.js +28 -29
  5. package/build/src/export/resolveOptions.js.map +1 -1
  6. package/build/src/start/server/metro/MetroBundlerDevServer.js +31 -1
  7. package/build/src/start/server/metro/MetroBundlerDevServer.js.map +1 -1
  8. package/build/src/start/server/metro/inspector-proxy/proxy.js +12 -9
  9. package/build/src/start/server/metro/inspector-proxy/proxy.js.map +1 -1
  10. package/build/src/start/server/metro/metroWatchTypeScriptFiles.js +1 -1
  11. package/build/src/start/server/metro/metroWatchTypeScriptFiles.js.map +1 -1
  12. package/build/src/start/server/metro/withMetroResolvers.js +13 -4
  13. package/build/src/start/server/metro/withMetroResolvers.js.map +1 -1
  14. package/build/src/start/server/middleware/ClassicManifestMiddleware.js +1 -1
  15. package/build/src/start/server/type-generation/__typetests__/fixtures/basic.js.map +1 -1
  16. package/build/src/start/server/type-generation/__typetests__/route.test.js +20 -9
  17. package/build/src/start/server/type-generation/__typetests__/route.test.js.map +1 -1
  18. package/build/src/start/server/type-generation/routes.js +118 -51
  19. package/build/src/start/server/type-generation/routes.js.map +1 -1
  20. package/build/src/utils/analytics/metroDebuggerMiddleware.js +9 -4
  21. package/build/src/utils/analytics/metroDebuggerMiddleware.js.map +1 -1
  22. package/build/src/utils/analytics/rudderstackClient.js +2 -2
  23. package/build/src/utils/port.js +2 -0
  24. package/build/src/utils/port.js.map +1 -1
  25. package/package.json +3 -3
@@ -20,25 +20,34 @@ function withMetroResolvers(config, projectRoot, resolvers) {
20
20
  ...config,
21
21
  resolver: {
22
22
  ...config.resolver,
23
- resolveRequest (...args) {
23
+ resolveRequest (context, moduleName, platform) {
24
+ const universalContext = {
25
+ ...context,
26
+ preferNativePlatform: platform !== "web"
27
+ };
24
28
  for (const resolver of resolvers){
25
29
  try {
26
- const resolution = resolver(...args);
30
+ const resolution = resolver(universalContext, moduleName, platform);
27
31
  if (resolution) {
28
32
  return resolution;
29
33
  }
30
34
  } catch (error) {
35
+ // If no user-defined resolver, use Expo's default behavior.
36
+ // This prevents extraneous resolution attempts on failure.
37
+ if (!config.resolver.resolveRequest) {
38
+ throw error;
39
+ }
31
40
  // If the error is directly related to a resolver not being able to resolve a module, then
32
41
  // we can ignore the error and try the next resolver. Otherwise, we should throw the error.
33
42
  const isResolutionError = (0, _metroErrors).isFailedToResolveNameError(error) || (0, _metroErrors).isFailedToResolvePathError(error);
34
43
  if (!isResolutionError) {
35
44
  throw error;
36
45
  }
37
- debug(`Custom resolver threw: ${error.constructor.name}. (module: ${args[1]}, platform: ${args[2]})`);
46
+ debug(`Custom resolver threw: ${error.constructor.name}. (module: ${moduleName}, platform: ${platform})`);
38
47
  }
39
48
  }
40
49
  // If we haven't returned by now, use the original resolver or upstream resolver.
41
- return originalResolveRequest(...args);
50
+ return originalResolveRequest(universalContext, moduleName, platform);
42
51
  }
43
52
  }
44
53
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/start/server/metro/withMetroResolvers.ts"],"sourcesContent":["/**\n * Copyright © 2022 650 Industries.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\nimport { ConfigT as MetroConfig } from 'metro-config';\nimport { ResolutionContext } from 'metro-resolver';\n\nimport { isFailedToResolveNameError, isFailedToResolvePathError } from './metroErrors';\nimport { importMetroResolverFromProject } from './resolveFromProject';\n\nconst debug = require('debug')('expo:metro:withMetroResolvers') as typeof console.log;\n\nexport type MetroResolver = NonNullable<MetroConfig['resolver']['resolveRequest']>;\n\n/** Expo Metro Resolvers can return `null` to skip without throwing an error. Metro Resolvers will throw either a `FailedToResolveNameError` or `FailedToResolvePathError`. */\nexport type ExpoCustomMetroResolver = (\n ...args: Parameters<MetroResolver>\n) => ReturnType<MetroResolver> | null;\n\n/** @returns `MetroResolver` utilizing the upstream `resolve` method. */\nexport function getDefaultMetroResolver(projectRoot: string): MetroResolver {\n const { resolve } = importMetroResolverFromProject(projectRoot);\n return (context: ResolutionContext, moduleName: string, platform: string | null) => {\n return resolve(context, moduleName, platform);\n };\n}\n\n/**\n * Extend the Metro config `resolver.resolveRequest` method with additional resolvers that can\n * exit early by returning a `Resolution` or skip to the next resolver by returning `null`.\n *\n * @param config Metro config.\n * @param projectRoot path to the project root used to resolve the default Metro resolver.\n * @param resolvers custom MetroResolver to chain.\n * @returns a new `MetroConfig` with the `resolver.resolveRequest` method chained.\n */\nexport function withMetroResolvers(\n config: MetroConfig,\n projectRoot: string,\n resolvers: ExpoCustomMetroResolver[]\n): MetroConfig {\n debug(\n `Appending ${\n resolvers.length\n } custom resolvers to Metro config. (has custom resolver: ${!!config.resolver.resolveRequest})`\n );\n const originalResolveRequest =\n config.resolver.resolveRequest || getDefaultMetroResolver(projectRoot);\n\n return {\n ...config,\n resolver: {\n ...config.resolver,\n resolveRequest(...args: Parameters<MetroResolver>) {\n for (const resolver of resolvers) {\n try {\n const resolution = resolver(...args);\n if (resolution) {\n return resolution;\n }\n } catch (error: any) {\n // If the error is directly related to a resolver not being able to resolve a module, then\n // we can ignore the error and try the next resolver. Otherwise, we should throw the error.\n const isResolutionError =\n isFailedToResolveNameError(error) || isFailedToResolvePathError(error);\n if (!isResolutionError) {\n throw error;\n }\n debug(\n `Custom resolver threw: ${error.constructor.name}. (module: ${args[1]}, platform: ${args[2]})`\n );\n }\n }\n // If we haven't returned by now, use the original resolver or upstream resolver.\n return originalResolveRequest(...args);\n },\n },\n };\n}\n"],"names":["getDefaultMetroResolver","withMetroResolvers","debug","require","projectRoot","resolve","importMetroResolverFromProject","context","moduleName","platform","config","resolvers","length","resolver","resolveRequest","originalResolveRequest","args","resolution","error","isResolutionError","isFailedToResolveNameError","isFailedToResolvePathError","constructor","name"],"mappings":"AAMA;;;;QAgBgBA,uBAAuB,GAAvBA,uBAAuB;QAgBvBC,kBAAkB,GAAlBA,kBAAkB;AA7BqC,IAAA,YAAe,WAAf,eAAe,CAAA;AACvC,IAAA,mBAAsB,WAAtB,sBAAsB,CAAA;AAErE,MAAMC,KAAK,GAAGC,OAAO,CAAC,OAAO,CAAC,CAAC,+BAA+B,CAAC,AAAsB,AAAC;AAU/E,SAASH,uBAAuB,CAACI,WAAmB,EAAiB;IAC1E,MAAM,EAAEC,OAAO,CAAA,EAAE,GAAGC,CAAAA,GAAAA,mBAA8B,AAAa,CAAA,+BAAb,CAACF,WAAW,CAAC,AAAC;IAChE,OAAO,CAACG,OAA0B,EAAEC,UAAkB,EAAEC,QAAuB,GAAK;QAClF,OAAOJ,OAAO,CAACE,OAAO,EAAEC,UAAU,EAAEC,QAAQ,CAAC,CAAC;KAC/C,CAAC;CACH;AAWM,SAASR,kBAAkB,CAChCS,MAAmB,EACnBN,WAAmB,EACnBO,SAAoC,EACvB;IACbT,KAAK,CACH,CAAC,UAAU,EACTS,SAAS,CAACC,MAAM,CACjB,yDAAyD,EAAE,CAAC,CAACF,MAAM,CAACG,QAAQ,CAACC,cAAc,CAAC,CAAC,CAAC,CAChG,CAAC;IACF,MAAMC,sBAAsB,GAC1BL,MAAM,CAACG,QAAQ,CAACC,cAAc,IAAId,uBAAuB,CAACI,WAAW,CAAC,AAAC;IAEzE,OAAO;QACL,GAAGM,MAAM;QACTG,QAAQ,EAAE;YACR,GAAGH,MAAM,CAACG,QAAQ;YAClBC,cAAc,EAAC,GAAGE,IAAI,AAA2B,EAAE;gBACjD,KAAK,MAAMH,QAAQ,IAAIF,SAAS,CAAE;oBAChC,IAAI;wBACF,MAAMM,UAAU,GAAGJ,QAAQ,IAAIG,IAAI,CAAC,AAAC;wBACrC,IAAIC,UAAU,EAAE;4BACd,OAAOA,UAAU,CAAC;yBACnB;qBACF,CAAC,OAAOC,KAAK,EAAO;wBACnB,0FAA0F;wBAC1F,2FAA2F;wBAC3F,MAAMC,iBAAiB,GACrBC,CAAAA,GAAAA,YAA0B,AAAO,CAAA,2BAAP,CAACF,KAAK,CAAC,IAAIG,CAAAA,GAAAA,YAA0B,AAAO,CAAA,2BAAP,CAACH,KAAK,CAAC,AAAC;wBACzE,IAAI,CAACC,iBAAiB,EAAE;4BACtB,MAAMD,KAAK,CAAC;yBACb;wBACDhB,KAAK,CACH,CAAC,uBAAuB,EAAEgB,KAAK,CAACI,WAAW,CAACC,IAAI,CAAC,WAAW,EAAEP,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,EAAEA,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAC/F,CAAC;qBACH;iBACF;gBACD,iFAAiF;gBACjF,OAAOD,sBAAsB,IAAIC,IAAI,CAAC,CAAC;aACxC;SACF;KACF,CAAC;CACH"}
1
+ {"version":3,"sources":["../../../../../src/start/server/metro/withMetroResolvers.ts"],"sourcesContent":["/**\n * Copyright © 2022 650 Industries.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\nimport { ConfigT as MetroConfig } from 'metro-config';\nimport { ResolutionContext } from 'metro-resolver';\n\nimport { isFailedToResolveNameError, isFailedToResolvePathError } from './metroErrors';\nimport { importMetroResolverFromProject } from './resolveFromProject';\n\nconst debug = require('debug')('expo:metro:withMetroResolvers') as typeof console.log;\n\nexport type MetroResolver = NonNullable<MetroConfig['resolver']['resolveRequest']>;\n\n/** Expo Metro Resolvers can return `null` to skip without throwing an error. Metro Resolvers will throw either a `FailedToResolveNameError` or `FailedToResolvePathError`. */\nexport type ExpoCustomMetroResolver = (\n ...args: Parameters<MetroResolver>\n) => ReturnType<MetroResolver> | null;\n\n/** @returns `MetroResolver` utilizing the upstream `resolve` method. */\nexport function getDefaultMetroResolver(projectRoot: string): MetroResolver {\n const { resolve } = importMetroResolverFromProject(projectRoot);\n return (context: ResolutionContext, moduleName: string, platform: string | null) => {\n return resolve(context, moduleName, platform);\n };\n}\n\n/**\n * Extend the Metro config `resolver.resolveRequest` method with additional resolvers that can\n * exit early by returning a `Resolution` or skip to the next resolver by returning `null`.\n *\n * @param config Metro config.\n * @param projectRoot path to the project root used to resolve the default Metro resolver.\n * @param resolvers custom MetroResolver to chain.\n * @returns a new `MetroConfig` with the `resolver.resolveRequest` method chained.\n */\nexport function withMetroResolvers(\n config: MetroConfig,\n projectRoot: string,\n resolvers: ExpoCustomMetroResolver[]\n): MetroConfig {\n debug(\n `Appending ${\n resolvers.length\n } custom resolvers to Metro config. (has custom resolver: ${!!config.resolver.resolveRequest})`\n );\n const originalResolveRequest =\n config.resolver.resolveRequest || getDefaultMetroResolver(projectRoot);\n\n return {\n ...config,\n resolver: {\n ...config.resolver,\n resolveRequest(context, moduleName, platform) {\n const universalContext = {\n ...context,\n preferNativePlatform: platform !== 'web',\n };\n\n for (const resolver of resolvers) {\n try {\n const resolution = resolver(universalContext, moduleName, platform);\n if (resolution) {\n return resolution;\n }\n } catch (error: any) {\n // If no user-defined resolver, use Expo's default behavior.\n // This prevents extraneous resolution attempts on failure.\n if (!config.resolver.resolveRequest) {\n throw error;\n }\n\n // If the error is directly related to a resolver not being able to resolve a module, then\n // we can ignore the error and try the next resolver. Otherwise, we should throw the error.\n const isResolutionError =\n isFailedToResolveNameError(error) || isFailedToResolvePathError(error);\n if (!isResolutionError) {\n throw error;\n }\n debug(\n `Custom resolver threw: ${error.constructor.name}. (module: ${moduleName}, platform: ${platform})`\n );\n }\n }\n // If we haven't returned by now, use the original resolver or upstream resolver.\n return originalResolveRequest(universalContext, moduleName, platform);\n },\n },\n };\n}\n"],"names":["getDefaultMetroResolver","withMetroResolvers","debug","require","projectRoot","resolve","importMetroResolverFromProject","context","moduleName","platform","config","resolvers","length","resolver","resolveRequest","originalResolveRequest","universalContext","preferNativePlatform","resolution","error","isResolutionError","isFailedToResolveNameError","isFailedToResolvePathError","constructor","name"],"mappings":"AAMA;;;;QAgBgBA,uBAAuB,GAAvBA,uBAAuB;QAgBvBC,kBAAkB,GAAlBA,kBAAkB;AA7BqC,IAAA,YAAe,WAAf,eAAe,CAAA;AACvC,IAAA,mBAAsB,WAAtB,sBAAsB,CAAA;AAErE,MAAMC,KAAK,GAAGC,OAAO,CAAC,OAAO,CAAC,CAAC,+BAA+B,CAAC,AAAsB,AAAC;AAU/E,SAASH,uBAAuB,CAACI,WAAmB,EAAiB;IAC1E,MAAM,EAAEC,OAAO,CAAA,EAAE,GAAGC,CAAAA,GAAAA,mBAA8B,AAAa,CAAA,+BAAb,CAACF,WAAW,CAAC,AAAC;IAChE,OAAO,CAACG,OAA0B,EAAEC,UAAkB,EAAEC,QAAuB,GAAK;QAClF,OAAOJ,OAAO,CAACE,OAAO,EAAEC,UAAU,EAAEC,QAAQ,CAAC,CAAC;KAC/C,CAAC;CACH;AAWM,SAASR,kBAAkB,CAChCS,MAAmB,EACnBN,WAAmB,EACnBO,SAAoC,EACvB;IACbT,KAAK,CACH,CAAC,UAAU,EACTS,SAAS,CAACC,MAAM,CACjB,yDAAyD,EAAE,CAAC,CAACF,MAAM,CAACG,QAAQ,CAACC,cAAc,CAAC,CAAC,CAAC,CAChG,CAAC;IACF,MAAMC,sBAAsB,GAC1BL,MAAM,CAACG,QAAQ,CAACC,cAAc,IAAId,uBAAuB,CAACI,WAAW,CAAC,AAAC;IAEzE,OAAO;QACL,GAAGM,MAAM;QACTG,QAAQ,EAAE;YACR,GAAGH,MAAM,CAACG,QAAQ;YAClBC,cAAc,EAACP,OAAO,EAAEC,UAAU,EAAEC,QAAQ,EAAE;gBAC5C,MAAMO,gBAAgB,GAAG;oBACvB,GAAGT,OAAO;oBACVU,oBAAoB,EAAER,QAAQ,KAAK,KAAK;iBACzC,AAAC;gBAEF,KAAK,MAAMI,QAAQ,IAAIF,SAAS,CAAE;oBAChC,IAAI;wBACF,MAAMO,UAAU,GAAGL,QAAQ,CAACG,gBAAgB,EAAER,UAAU,EAAEC,QAAQ,CAAC,AAAC;wBACpE,IAAIS,UAAU,EAAE;4BACd,OAAOA,UAAU,CAAC;yBACnB;qBACF,CAAC,OAAOC,KAAK,EAAO;wBACnB,4DAA4D;wBAC5D,2DAA2D;wBAC3D,IAAI,CAACT,MAAM,CAACG,QAAQ,CAACC,cAAc,EAAE;4BACnC,MAAMK,KAAK,CAAC;yBACb;wBAED,0FAA0F;wBAC1F,2FAA2F;wBAC3F,MAAMC,iBAAiB,GACrBC,CAAAA,GAAAA,YAA0B,AAAO,CAAA,2BAAP,CAACF,KAAK,CAAC,IAAIG,CAAAA,GAAAA,YAA0B,AAAO,CAAA,2BAAP,CAACH,KAAK,CAAC,AAAC;wBACzE,IAAI,CAACC,iBAAiB,EAAE;4BACtB,MAAMD,KAAK,CAAC;yBACb;wBACDjB,KAAK,CACH,CAAC,uBAAuB,EAAEiB,KAAK,CAACI,WAAW,CAACC,IAAI,CAAC,WAAW,EAAEhB,UAAU,CAAC,YAAY,EAAEC,QAAQ,CAAC,CAAC,CAAC,CACnG,CAAC;qBACH;iBACF;gBACD,iFAAiF;gBACjF,OAAOM,sBAAsB,CAACC,gBAAgB,EAAER,UAAU,EAAEC,QAAQ,CAAC,CAAC;aACvE;SACF;KACF,CAAC;CACH"}
@@ -138,7 +138,7 @@ async function createHostInfoAsync() {
138
138
  host: await _userSettings.default.getAnonymousIdentifierAsync(),
139
139
  server: "expo",
140
140
  // Defined in the build step
141
- serverVersion: "0.10.9",
141
+ serverVersion: "0.10.11",
142
142
  serverDriver: _manifestMiddleware.DEVELOPER_TOOL,
143
143
  serverOS: _os.default.platform(),
144
144
  serverOSVersion: _os.default.release()
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../src/start/server/type-generation/__typetests__/fixtures/basic.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable import/export */\n/* eslint-disable @typescript-eslint/ban-types */\n\nimport type { LinkProps as OriginalLinkProps } from 'expo-router/build/link/Link';\nexport * from 'expo-router/build';\n\n// prettier-ignore\ntype StaticRoutes = `/apple` | `/banana`;\n// prettier-ignore\ntype DynamicRoutes<T extends string> = `/colors/${SingleRoutePart<T>}` | `/animals/${CatchAllRoutePart<T>}` | `/mix/${SingleRoutePart<T>}/${SingleRoutePart<T>}/${CatchAllRoutePart<T>}`;\n// prettier-ignore\ntype DynamicRouteTemplate = `/colors/[color]` | `/animals/[...animal]` | `/mix/[fruit]/[color]/[...animals]`;\n\ntype RelativePathString = `./${string}` | `../${string}` | '..';\ntype AbsoluteRoute = DynamicRouteTemplate | StaticRoutes;\ntype ExternalPathString = `http${string}`;\ntype ExpoRouterRoutes = DynamicRouteTemplate | StaticRoutes | RelativePathString;\ntype AllRoutes = ExpoRouterRoutes | ExternalPathString;\n\n/****************\n * Route Utils *\n ****************/\n\ntype SearchOrHash = `?${string}` | `#${string}`;\n\n/**\n * Return only the RoutePart of a string. If the string has multiple parts return never\n *\n * string | type\n * ---------|------\n * 123 | 123\n * /123/abc | never\n * 123?abc | never\n * ./123 | never\n * /123 | never\n * 123/../ | never\n */\ntype SingleRoutePart<S extends string> = S extends `${string}/${string}`\n ? never\n : S extends `${string}${SearchOrHash}`\n ? never\n : S extends ''\n ? never\n : S;\n\n/**\n * Return only the CatchAll router part. If the string has search parameters or a hash return never\n */\ntype CatchAllRoutePart<S extends string> = S extends `${string}${SearchOrHash}`\n ? never\n : S extends ''\n ? never\n : S;\n\n// type OptionalCatchAllRoutePart<S extends string> = S extends `${string}${SearchOrHash}` ? never : S\n\n/**\n * Return the name of a route parameter\n * '[test]' -> 'test'\n * 'test' -> never\n * '[...test]' -> '...test'\n */\ntype IsParameter<Part> = Part extends `[${infer ParamName}]` ? ParamName : never;\n\n/**\n * Return a union of all parameter names. If there are no names return never\n *\n * /[test] -> 'test'\n * /[abc]/[...def] -> 'abc'|'...def'\n */\ntype ParameterNames<Path> = Path extends `${infer PartA}/${infer PartB}`\n ? IsParameter<PartA> | ParameterNames<PartB>\n : IsParameter<Path>;\n\n/**\n * Returns all segements of a route.\n *\n * /(group)/123/abc/[id]/[...rest] -> ['(group)', '123', 'abc', '[id]', '[...rest]'\n */\ntype RouteSegments<Path> = Path extends `${infer PartA}/${infer PartB}`\n ? PartA extends '' | '.'\n ? [...RouteSegments<PartB>]\n : [PartA, ...RouteSegments<PartB>]\n : Path extends ''\n ? []\n : [Path];\n\n/**\n * Returns a Record of the routes parameters as strings and CatchAll parameters as string[]\n *\n * /[id]/[...rest] -> { id: string, rest: string[] }\n * /no-params -> {}\n */\ntype RouteParams<Path> = {\n [Key in ParameterNames<Path> as Key extends `...${infer Name}`\n ? Name\n : Key]: Key extends `...${string}` ? string[] : string;\n};\n\n/**\n * Returns the search parameters for a route\n */\nexport type SearchParams<T extends AllRoutes> = T extends DynamicRouteTemplate\n ? RouteParams<T>\n : T extends StaticRoutes\n ? never\n : Record<string, string>;\n\n/**\n * Route is mostly used as part of Href to ensure that a valid route is provided\n *\n * Given a dynamic route, this will return never. This is helpful for conditional logic\n *\n * /test -> /test, /test2, etc\n * /test/[abc] -> never\n * /test/resolve -> /test, /test2, etc\n *\n * Note that if we provide a value for [abc] then the route is allowed\n *\n * This is named Route to prevent confusion, as users they will often see it in tooltips\n */\nexport type Route<T> = T extends DynamicRouteTemplate\n ? never\n :\n | StaticRoutes\n | RelativePathString\n | ExternalPathString\n | (T extends DynamicRoutes<infer _> ? T : never);\n\n/*********\n * Href *\n *********/\n\nexport type Href<T extends string> = Route<T> | HrefObject<T>;\n\nexport type HrefObject<T = AllRoutes> = T extends DynamicRouteTemplate\n ? { pathname: T; params: RouteParams<T> }\n : T extends Route<T>\n ? { pathname: Route<T>; params?: never }\n : never;\n\n/***********************\n * Expo Router Exports *\n ***********************/\n\nexport type Router = {\n /** Navigate to the provided href. */\n push: <T extends string>(href: Href<T>) => void;\n /** Navigate to route without appending to the history. */\n replace: <T extends string>(href: Href<T>) => void;\n /** Go back in the history. */\n back: () => void;\n /** Update the current route query params. */\n setParams: <T extends string = ''>(\n params?: T extends '' ? Record<string, string> : RouteParams<T>\n ) => void;\n};\n\n/************\n * <Link /> *\n ************/\nexport interface LinkProps<T extends string> extends OriginalLinkProps {\n href: T extends DynamicRouteTemplate ? HrefObject<T> : Href<T>;\n}\n\nexport interface LinkComponent {\n <T extends string>(props: React.PropsWithChildren<LinkProps<T>>): JSX.Element;\n /** Helper method to resolve an Href object into a string. */\n resolveHref: <T extends string>(href: Href<T>) => string;\n}\n\nexport declare const Link: LinkComponent;\n\n/************\n * Hooks *\n ************/\nexport declare function useRouter(): Router;\nexport declare function useLocalSearchParams<\n T extends DynamicRouteTemplate | StaticRoutes | RelativePathString\n>(): SearchParams<T>;\nexport declare function useSearchParams<\n T extends AllRoutes | SearchParams<DynamicRouteTemplate>\n>(): T extends AllRoutes ? SearchParams<T> : T;\n\nexport declare function useGlobalSearchParams<\n T extends AllRoutes | SearchParams<DynamicRouteTemplate>\n>(): T extends AllRoutes ? SearchParams<T> : T;\n\nexport declare function useSegments<\n T extends AbsoluteRoute | RouteSegments<AbsoluteRoute> | RelativePathString\n>(): T extends AbsoluteRoute ? RouteSegments<T> : T extends string ? string[] : T;\n"],"names":[],"mappings":"AAIA;;;;6CACc,mBAAmB;AAAjC,YAAA,MAAkC;;2CAAlC,MAAkC;;;;mBAAlC,MAAkC;;;EAAA"}
1
+ {"version":3,"sources":["../../../../../../../src/start/server/type-generation/__typetests__/fixtures/basic.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable import/export */\n/* eslint-disable @typescript-eslint/ban-types */\n\nimport type { LinkProps as OriginalLinkProps } from 'expo-router/build/link/Link';\nimport type { Router as OriginalRouter } from 'expo-router/src/types';\nexport * from 'expo-router/build';\n\n// prettier-ignore\ntype StaticRoutes = `/apple` | `/banana`;\n// prettier-ignore\ntype DynamicRoutes<T extends string> = `/colors/${SingleRoutePart<T>}` | `/animals/${CatchAllRoutePart<T>}` | `/mix/${SingleRoutePart<T>}/${SingleRoutePart<T>}/${CatchAllRoutePart<T>}`;\n// prettier-ignore\ntype DynamicRouteTemplate = `/colors/[color]` | `/animals/[...animal]` | `/mix/[fruit]/[color]/[...animals]`;\n\ntype RelativePathString = `./${string}` | `../${string}` | '..';\ntype AbsoluteRoute = DynamicRouteTemplate | StaticRoutes;\ntype ExternalPathString = `http${string}`;\ntype ExpoRouterRoutes = DynamicRouteTemplate | StaticRoutes | RelativePathString;\ntype AllRoutes = ExpoRouterRoutes | ExternalPathString;\n\n/****************\n * Route Utils *\n ****************/\n\ntype SearchOrHash = `?${string}` | `#${string}`;\ntype UnknownInputParams = Record<string, string | number | (string | number)[]>;\ntype UnknownOutputParams = Record<string, string | string[]>;\n\n/**\n * Return only the RoutePart of a string. If the string has multiple parts return never\n *\n * string | type\n * ---------|------\n * 123 | 123\n * /123/abc | never\n * 123?abc | never\n * ./123 | never\n * /123 | never\n * 123/../ | never\n */\ntype SingleRoutePart<S extends string> = S extends `${string}/${string}`\n ? never\n : S extends `${string}${SearchOrHash}`\n ? never\n : S extends ''\n ? never\n : S extends `(${string})`\n ? never\n : S extends `[${string}]`\n ? never\n : S;\n\n/**\n * Return only the CatchAll router part. If the string has search parameters or a hash return never\n */\ntype CatchAllRoutePart<S extends string> = S extends `${string}${SearchOrHash}`\n ? never\n : S extends ''\n ? never\n : S extends `${string}(${string})${string}`\n ? never\n : S extends `${string}[${string}]${string}`\n ? never\n : S;\n\n// type OptionalCatchAllRoutePart<S extends string> = S extends `${string}${SearchOrHash}` ? never : S\n\n/**\n * Return the name of a route parameter\n * '[test]' -> 'test'\n * 'test' -> never\n * '[...test]' -> '...test'\n */\ntype IsParameter<Part> = Part extends `[${infer ParamName}]` ? ParamName : never;\n\n/**\n * Return a union of all parameter names. If there are no names return never\n *\n * /[test] -> 'test'\n * /[abc]/[...def] -> 'abc'|'...def'\n */\ntype ParameterNames<Path> = Path extends `${infer PartA}/${infer PartB}`\n ? IsParameter<PartA> | ParameterNames<PartB>\n : IsParameter<Path>;\n\n/**\n * Returns all segements of a route.\n *\n * /(group)/123/abc/[id]/[...rest] -> ['(group)', '123', 'abc', '[id]', '[...rest]'\n */\ntype RouteSegments<Path> = Path extends `${infer PartA}/${infer PartB}`\n ? PartA extends '' | '.'\n ? [...RouteSegments<PartB>]\n : [PartA, ...RouteSegments<PartB>]\n : Path extends ''\n ? []\n : [Path];\n\n/**\n * Returns a Record of the routes parameters as strings and CatchAll parameters\n *\n * There are two versions, input and output, as you can input 'string | number' but\n * the output will always be 'string'\n *\n * /[id]/[...rest] -> { id: string, rest: string[] }\n * /no-params -> {}\n */\ntype InputRouteParams<Path> = {\n [Key in ParameterNames<Path> as Key extends `...${infer Name}`\n ? Name\n : Key]: Key extends `...${string}` ? (string | number)[] : string | number;\n} & UnknownInputParams;\n\ntype OutputRouteParams<Path> = {\n [Key in ParameterNames<Path> as Key extends `...${infer Name}`\n ? Name\n : Key]: Key extends `...${string}` ? string[] : string;\n} & UnknownOutputParams;\n\n/**\n * Returns the search parameters for a route.\n */\nexport type SearchParams<T extends AllRoutes> = T extends DynamicRouteTemplate\n ? OutputRouteParams<T>\n : T extends StaticRoutes\n ? never\n : UnknownOutputParams;\n\n/**\n * Route is mostly used as part of Href to ensure that a valid route is provided\n *\n * Given a dynamic route, this will return never. This is helpful for conditional logic\n *\n * /test -> /test, /test2, etc\n * /test/[abc] -> never\n * /test/resolve -> /test, /test2, etc\n *\n * Note that if we provide a value for [abc] then the route is allowed\n *\n * This is named Route to prevent confusion, as users they will often see it in tooltips\n */\nexport type Route<T> = T extends string\n ? T extends DynamicRouteTemplate\n ? never\n :\n | StaticRoutes\n | RelativePathString\n | ExternalPathString\n | (T extends `${infer P}${SearchOrHash}`\n ? P extends DynamicRoutes<infer _>\n ? T\n : never\n : T extends DynamicRoutes<infer _>\n ? T\n : never)\n : never;\n\n/*********\n * Href *\n *********/\n\nexport type Href<T> = T extends Record<'pathname', string> ? HrefObject<T> : Route<T>;\n\nexport type HrefObject<\n R extends Record<'pathname', string>,\n P = R['pathname']\n> = P extends DynamicRouteTemplate\n ? { pathname: P; params: InputRouteParams<P> }\n : P extends Route<P>\n ? { pathname: Route<P> | DynamicRouteTemplate; params?: never | InputRouteParams<never> }\n : never;\n\n/***********************\n * Expo Router Exports *\n ***********************/\n\nexport type Router = Omit<OriginalRouter, 'push' | 'replace' | 'setParams'> & {\n /** Navigate to the provided href. */\n push: <T>(href: Href<T>) => void;\n /** Navigate to route without appending to the history. */\n replace: <T>(href: Href<T>) => void;\n /** Update the current route query params. */\n setParams: <T = ''>(params?: T extends '' ? Record<string, string> : InputRouteParams<T>) => void;\n};\n\n/** The imperative router. */\nexport declare const router: Router;\n\n/************\n * <Link /> *\n ************/\nexport interface LinkProps<T> extends OriginalLinkProps {\n href: Href<T>;\n}\n\nexport interface LinkComponent {\n <T>(props: React.PropsWithChildren<LinkProps<T>>): JSX.Element;\n /** Helper method to resolve an Href object into a string. */\n resolveHref: <T>(href: Href<T>) => string;\n}\n\n/**\n * Component to render link to another route using a path.\n * Uses an anchor tag on the web.\n *\n * @param props.href Absolute path to route (e.g. `/feeds/hot`).\n * @param props.replace Should replace the current route without adding to the history.\n * @param props.asChild Forward props to child component. Useful for custom buttons.\n * @param props.children Child elements to render the content.\n */\nexport declare const Link: LinkComponent;\n\n/** Redirects to the href as soon as the component is mounted. */\nexport declare const Redirect: <T>(\n props: React.PropsWithChildren<{ href: Href<T> }>\n) => JSX.Element;\n\n/************\n * Hooks *\n ************/\nexport declare function useRouter(): Router;\n\nexport declare function useLocalSearchParams<\n T extends AllRoutes | UnknownOutputParams = UnknownOutputParams\n>(): T extends AllRoutes ? SearchParams<T> : T;\n\n/** @deprecated renamed to `useGlobalSearchParams` */\nexport declare function useSearchParams<\n T extends AllRoutes | UnknownOutputParams = UnknownOutputParams\n>(): T extends AllRoutes ? SearchParams<T> : T;\n\nexport declare function useGlobalSearchParams<\n T extends AllRoutes | UnknownOutputParams = UnknownOutputParams\n>(): T extends AllRoutes ? SearchParams<T> : T;\n\nexport declare function useSegments<\n T extends AbsoluteRoute | RouteSegments<AbsoluteRoute> | RelativePathString\n>(): T extends AbsoluteRoute ? RouteSegments<T> : T extends string ? string[] : T;\n"],"names":[],"mappings":"AAIA;;;;6CAEc,mBAAmB;AAAjC,YAAA,MAAkC;;2CAAlC,MAAkC;;;;mBAAlC,MAAkC;;;EAAA"}
@@ -39,11 +39,6 @@ describe("router.push()", ()=>{
39
39
  it("can accept any external url", ()=>{
40
40
  (0, _tsdLite).expectType(router.push("http://expo.dev"));
41
41
  });
42
- it("throws if using inline search params", ()=>{
43
- // While this is allowed in Expo Router, the Typed Routes version throws as we cannot type it
44
- (0, _tsdLite).expectError(router.push("/colors?color=blue"));
45
- (0, _tsdLite).expectError(router.push("/animals/bear?color=blue"));
46
- });
47
42
  });
48
43
  describe("HrefObject", ()=>{
49
44
  it("will error on non-urls", ()=>{
@@ -100,6 +95,19 @@ describe("router.push()", ()=>{
100
95
  }
101
96
  }));
102
97
  });
98
+ it("allows numeric inputs", ()=>{
99
+ (0, _tsdLite).expectType(router.push({
100
+ pathname: "/mix/[fruit]/[color]/[...animals]",
101
+ params: {
102
+ color: 1,
103
+ fruit: "apple",
104
+ animals: [
105
+ 2,
106
+ "cat"
107
+ ]
108
+ }
109
+ }));
110
+ });
103
111
  it("requires an array for catch all routes", ()=>{
104
112
  (0, _tsdLite).expectError(router.push({
105
113
  pathname: "/animals/[...animal]",
@@ -114,10 +122,7 @@ describe("router.push()", ()=>{
114
122
  params: {
115
123
  color: "red",
116
124
  fruit: "apple",
117
- animals: [
118
- "cat",
119
- "dog"
120
- ]
125
+ animals: []
121
126
  }
122
127
  }));
123
128
  });
@@ -141,6 +146,12 @@ describe("useSearchParams", ()=>{
141
146
  (0, _tsdLite).expectError((0, _basic).useSearchParams());
142
147
  (0, _tsdLite).expectError((0, _basic).useSearchParams());
143
148
  });
149
+ describe("useLocalSearchParams", ()=>{
150
+ (0, _tsdLite).expectType((0, _basic).useLocalSearchParams());
151
+ (0, _tsdLite).expectType((0, _basic).useLocalSearchParams());
152
+ (0, _tsdLite).expectError((0, _basic).useSearchParams());
153
+ (0, _tsdLite).expectError((0, _basic).useSearchParams());
154
+ });
144
155
  describe("useGlobalSearchParams", ()=>{
145
156
  (0, _tsdLite).expectType((0, _basic).useGlobalSearchParams());
146
157
  (0, _tsdLite).expectType((0, _basic).useGlobalSearchParams());
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../src/start/server/type-generation/__typetests__/route.test.ts"],"sourcesContent":["import { expectType, expectError } from 'tsd-lite';\n\nimport { useGlobalSearchParams, useSegments, useRouter, useSearchParams } from './fixtures/basic';\n\n// eslint-disable-next-line react-hooks/rules-of-hooks\nconst router = useRouter();\n\ndescribe('router.push()', () => {\n // router.push will return void when the type matches, otherwise it should error\n\n describe('href', () => {\n it('will error on non-urls', () => {\n expectError(router.push('should-error'));\n });\n\n it('can accept an absolute url', () => {\n expectType<void>(router.push('/apple'));\n expectType<void>(router.push('/banana'));\n });\n\n it('can accept a ANY relative url', () => {\n // We only type-check absolute urls\n expectType<void>(router.push('./this/work/but/is/not/valid'));\n });\n\n it('works for dynamic urls', () => {\n expectType<void>(router.push('/colors/blue'));\n });\n\n it('works for CatchAll routes', () => {\n expectType<void>(router.push('/animals/bear'));\n expectType<void>(router.push('/animals/bear/cat/dog'));\n expectType<void>(router.push('/mix/apple/blue/cat/dog'));\n });\n\n it.skip('works for optional CatchAll routes', () => {\n // CatchAll routes are not currently optional\n // expectType<void>(router.push('/animals/'));\n });\n\n it('will error when providing extra parameters', () => {\n expectError(router.push('/colors/blue/test'));\n });\n\n it('will error when providing too few parameters', () => {\n expectError(router.push('/mix/apple'));\n expectError(router.push('/mix/apple/cat'));\n });\n\n it('can accept any external url', () => {\n expectType<void>(router.push('http://expo.dev'));\n });\n\n it('throws if using inline search params', () => {\n // While this is allowed in Expo Router, the Typed Routes version throws as we cannot type it\n expectError(router.push('/colors?color=blue'));\n expectError(router.push('/animals/bear?color=blue'));\n });\n });\n\n describe('HrefObject', () => {\n it('will error on non-urls', () => {\n expectError(router.push({ pathname: 'should-error' }));\n });\n\n it('can accept an absolute url', () => {\n expectType<void>(router.push({ pathname: '/apple' }));\n expectType<void>(router.push({ pathname: '/banana' }));\n });\n\n it('can accept a ANY relative url', () => {\n // We only type-check absolute urls\n expectType<void>(router.push({ pathname: './this/work/but/is/not/valid' }));\n });\n\n it('works for dynamic urls', () => {\n expectType<void>(\n router.push({\n pathname: '/colors/[color]',\n params: { color: 'blue' },\n })\n );\n });\n\n it('requires a valid pathname', () => {\n expectError(\n router.push({\n pathname: '/colors/[invalid]',\n params: { color: 'blue' },\n })\n );\n });\n\n it('requires a valid param', () => {\n expectError(\n router.push({\n pathname: '/colors/[color]',\n params: { invalid: 'blue' },\n })\n );\n });\n\n it('works for catch all routes', () => {\n expectType<void>(\n router.push({\n pathname: '/animals/[...animal]',\n params: { animal: ['cat', 'dog'] },\n })\n );\n });\n\n it('requires an array for catch all routes', () => {\n expectError(\n router.push({\n pathname: '/animals/[...animal]',\n params: { animal: 'cat' },\n })\n );\n });\n\n it('works for mixed routes', () => {\n expectType<void>(\n router.push({\n pathname: '/mix/[fruit]/[color]/[...animals]',\n params: { color: 'red', fruit: 'apple', animals: ['cat', 'dog'] },\n })\n );\n });\n\n it('requires all params in mixed routes', () => {\n expectError(\n router.push({\n pathname: '/mix/[fruit]/[color]/[...animals]',\n params: { color: 'red', animals: ['cat', 'dog'] },\n })\n );\n });\n });\n});\n\ndescribe('useSearchParams', () => {\n expectType<Record<'color', string>>(useSearchParams<'/colors/[color]'>());\n expectType<Record<'color', string>>(useSearchParams<Record<'color', string>>());\n expectError(useSearchParams<'/invalid'>());\n expectError(useSearchParams<Record<'custom', string>>());\n});\n\ndescribe('useGlobalSearchParams', () => {\n expectType<Record<'color', string>>(useGlobalSearchParams<'/colors/[color]'>());\n expectType<Record<'color', string>>(useGlobalSearchParams<Record<'color', string>>());\n expectError(useGlobalSearchParams<'/invalid'>());\n expectError(useGlobalSearchParams<Record<'custom', string>>());\n});\n\ndescribe('useSegments', () => {\n it('can accept an absolute url', () => {\n expectType<['apple']>(useSegments<'/apple'>());\n });\n\n it('only accepts valid possible urls', () => {\n expectError(useSegments<'/invalid'>());\n });\n\n it('can accept an array of segments', () => {\n expectType<['apple']>(useSegments<['apple']>());\n });\n\n it('only accepts valid possible segments', () => {\n expectError(useSegments<['invalid segment']>());\n });\n});\n"],"names":["router","useRouter","describe","it","expectError","push","expectType","skip","pathname","params","color","invalid","animal","fruit","animals","useSearchParams","useGlobalSearchParams","useSegments"],"mappings":"AAAA;AAAwC,IAAA,QAAU,WAAV,UAAU,CAAA;AAE6B,IAAA,MAAkB,WAAlB,kBAAkB,CAAA;AAEjG,sDAAsD;AACtD,MAAMA,MAAM,GAAGC,CAAAA,GAAAA,MAAS,AAAE,CAAA,UAAF,EAAE,AAAC;AAE3BC,QAAQ,CAAC,eAAe,EAAE,IAAM;IAC9B,gFAAgF;IAEhFA,QAAQ,CAAC,MAAM,EAAE,IAAM;QACrBC,EAAE,CAAC,wBAAwB,EAAE,IAAM;YACjCC,CAAAA,GAAAA,QAAW,AAA6B,CAAA,YAA7B,CAACJ,MAAM,CAACK,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;SAC1C,CAAC,CAAC;QAEHF,EAAE,CAAC,4BAA4B,EAAE,IAAM;YACrCG,CAAAA,GAAAA,QAAU,AAA6B,CAAA,WAA7B,CAAON,MAAM,CAACK,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YACxCC,CAAAA,GAAAA,QAAU,AAA8B,CAAA,WAA9B,CAAON,MAAM,CAACK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;SAC1C,CAAC,CAAC;QAEHF,EAAE,CAAC,+BAA+B,EAAE,IAAM;YACxC,mCAAmC;YACnCG,CAAAA,GAAAA,QAAU,AAAmD,CAAA,WAAnD,CAAON,MAAM,CAACK,IAAI,CAAC,8BAA8B,CAAC,CAAC,CAAC;SAC/D,CAAC,CAAC;QAEHF,EAAE,CAAC,wBAAwB,EAAE,IAAM;YACjCG,CAAAA,GAAAA,QAAU,AAAmC,CAAA,WAAnC,CAAON,MAAM,CAACK,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;SAC/C,CAAC,CAAC;QAEHF,EAAE,CAAC,2BAA2B,EAAE,IAAM;YACpCG,CAAAA,GAAAA,QAAU,AAAoC,CAAA,WAApC,CAAON,MAAM,CAACK,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;YAC/CC,CAAAA,GAAAA,QAAU,AAA4C,CAAA,WAA5C,CAAON,MAAM,CAACK,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC;YACvDC,CAAAA,GAAAA,QAAU,AAA8C,CAAA,WAA9C,CAAON,MAAM,CAACK,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC;SAC1D,CAAC,CAAC;QAEHF,EAAE,CAACI,IAAI,CAAC,oCAAoC,EAAE,IAAM;QAClD,6CAA6C;QAC7C,8CAA8C;SAC/C,CAAC,CAAC;QAEHJ,EAAE,CAAC,4CAA4C,EAAE,IAAM;YACrDC,CAAAA,GAAAA,QAAW,AAAkC,CAAA,YAAlC,CAACJ,MAAM,CAACK,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;SAC/C,CAAC,CAAC;QAEHF,EAAE,CAAC,8CAA8C,EAAE,IAAM;YACvDC,CAAAA,GAAAA,QAAW,AAA2B,CAAA,YAA3B,CAACJ,MAAM,CAACK,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;YACvCD,CAAAA,GAAAA,QAAW,AAA+B,CAAA,YAA/B,CAACJ,MAAM,CAACK,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;SAC5C,CAAC,CAAC;QAEHF,EAAE,CAAC,6BAA6B,EAAE,IAAM;YACtCG,CAAAA,GAAAA,QAAU,AAAsC,CAAA,WAAtC,CAAON,MAAM,CAACK,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;SAClD,CAAC,CAAC;QAEHF,EAAE,CAAC,sCAAsC,EAAE,IAAM;YAC/C,6FAA6F;YAC7FC,CAAAA,GAAAA,QAAW,AAAmC,CAAA,YAAnC,CAACJ,MAAM,CAACK,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC;YAC/CD,CAAAA,GAAAA,QAAW,AAAyC,CAAA,YAAzC,CAACJ,MAAM,CAACK,IAAI,CAAC,0BAA0B,CAAC,CAAC,CAAC;SACtD,CAAC,CAAC;KACJ,CAAC,CAAC;IAEHH,QAAQ,CAAC,YAAY,EAAE,IAAM;QAC3BC,EAAE,CAAC,wBAAwB,EAAE,IAAM;YACjCC,CAAAA,GAAAA,QAAW,AAA2C,CAAA,YAA3C,CAACJ,MAAM,CAACK,IAAI,CAAC;gBAAEG,QAAQ,EAAE,cAAc;aAAE,CAAC,CAAC,CAAC;SACxD,CAAC,CAAC;QAEHL,EAAE,CAAC,4BAA4B,EAAE,IAAM;YACrCG,CAAAA,GAAAA,QAAU,AAA2C,CAAA,WAA3C,CAAON,MAAM,CAACK,IAAI,CAAC;gBAAEG,QAAQ,EAAE,QAAQ;aAAE,CAAC,CAAC,CAAC;YACtDF,CAAAA,GAAAA,QAAU,AAA4C,CAAA,WAA5C,CAAON,MAAM,CAACK,IAAI,CAAC;gBAAEG,QAAQ,EAAE,SAAS;aAAE,CAAC,CAAC,CAAC;SACxD,CAAC,CAAC;QAEHL,EAAE,CAAC,+BAA+B,EAAE,IAAM;YACxC,mCAAmC;YACnCG,CAAAA,GAAAA,QAAU,AAAiE,CAAA,WAAjE,CAAON,MAAM,CAACK,IAAI,CAAC;gBAAEG,QAAQ,EAAE,8BAA8B;aAAE,CAAC,CAAC,CAAC;SAC7E,CAAC,CAAC;QAEHL,EAAE,CAAC,wBAAwB,EAAE,IAAM;YACjCG,CAAAA,GAAAA,QAAU,AAKT,CAAA,WALS,CACRN,MAAM,CAACK,IAAI,CAAC;gBACVG,QAAQ,EAAE,iBAAiB;gBAC3BC,MAAM,EAAE;oBAAEC,KAAK,EAAE,MAAM;iBAAE;aAC1B,CAAC,CACH,CAAC;SACH,CAAC,CAAC;QAEHP,EAAE,CAAC,2BAA2B,EAAE,IAAM;YACpCC,CAAAA,GAAAA,QAAW,AAKV,CAAA,YALU,CACTJ,MAAM,CAACK,IAAI,CAAC;gBACVG,QAAQ,EAAE,mBAAmB;gBAC7BC,MAAM,EAAE;oBAAEC,KAAK,EAAE,MAAM;iBAAE;aAC1B,CAAC,CACH,CAAC;SACH,CAAC,CAAC;QAEHP,EAAE,CAAC,wBAAwB,EAAE,IAAM;YACjCC,CAAAA,GAAAA,QAAW,AAKV,CAAA,YALU,CACTJ,MAAM,CAACK,IAAI,CAAC;gBACVG,QAAQ,EAAE,iBAAiB;gBAC3BC,MAAM,EAAE;oBAAEE,OAAO,EAAE,MAAM;iBAAE;aAC5B,CAAC,CACH,CAAC;SACH,CAAC,CAAC;QAEHR,EAAE,CAAC,4BAA4B,EAAE,IAAM;YACrCG,CAAAA,GAAAA,QAAU,AAKT,CAAA,WALS,CACRN,MAAM,CAACK,IAAI,CAAC;gBACVG,QAAQ,EAAE,sBAAsB;gBAChCC,MAAM,EAAE;oBAAEG,MAAM,EAAE;wBAAC,KAAK;wBAAE,KAAK;qBAAC;iBAAE;aACnC,CAAC,CACH,CAAC;SACH,CAAC,CAAC;QAEHT,EAAE,CAAC,wCAAwC,EAAE,IAAM;YACjDC,CAAAA,GAAAA,QAAW,AAKV,CAAA,YALU,CACTJ,MAAM,CAACK,IAAI,CAAC;gBACVG,QAAQ,EAAE,sBAAsB;gBAChCC,MAAM,EAAE;oBAAEG,MAAM,EAAE,KAAK;iBAAE;aAC1B,CAAC,CACH,CAAC;SACH,CAAC,CAAC;QAEHT,EAAE,CAAC,wBAAwB,EAAE,IAAM;YACjCG,CAAAA,GAAAA,QAAU,AAKT,CAAA,WALS,CACRN,MAAM,CAACK,IAAI,CAAC;gBACVG,QAAQ,EAAE,mCAAmC;gBAC7CC,MAAM,EAAE;oBAAEC,KAAK,EAAE,KAAK;oBAAEG,KAAK,EAAE,OAAO;oBAAEC,OAAO,EAAE;wBAAC,KAAK;wBAAE,KAAK;qBAAC;iBAAE;aAClE,CAAC,CACH,CAAC;SACH,CAAC,CAAC;QAEHX,EAAE,CAAC,qCAAqC,EAAE,IAAM;YAC9CC,CAAAA,GAAAA,QAAW,AAKV,CAAA,YALU,CACTJ,MAAM,CAACK,IAAI,CAAC;gBACVG,QAAQ,EAAE,mCAAmC;gBAC7CC,MAAM,EAAE;oBAAEC,KAAK,EAAE,KAAK;oBAAEI,OAAO,EAAE;wBAAC,KAAK;wBAAE,KAAK;qBAAC;iBAAE;aAClD,CAAC,CACH,CAAC;SACH,CAAC,CAAC;KACJ,CAAC,CAAC;CACJ,CAAC,CAAC;AAEHZ,QAAQ,CAAC,iBAAiB,EAAE,IAAM;IAChCI,CAAAA,GAAAA,QAAU,AAA+D,CAAA,WAA/D,CAA0BS,CAAAA,GAAAA,MAAe,AAAqB,CAAA,gBAArB,EAAqB,CAAC,CAAC;IAC1ET,CAAAA,GAAAA,QAAU,AAAqE,CAAA,WAArE,CAA0BS,CAAAA,GAAAA,MAAe,AAA2B,CAAA,gBAA3B,EAA2B,CAAC,CAAC;IAChFX,CAAAA,GAAAA,QAAW,AAA+B,CAAA,YAA/B,CAACW,CAAAA,GAAAA,MAAe,AAAc,CAAA,gBAAd,EAAc,CAAC,CAAC;IAC3CX,CAAAA,GAAAA,QAAW,AAA6C,CAAA,YAA7C,CAACW,CAAAA,GAAAA,MAAe,AAA4B,CAAA,gBAA5B,EAA4B,CAAC,CAAC;CAC1D,CAAC,CAAC;AAEHb,QAAQ,CAAC,uBAAuB,EAAE,IAAM;IACtCI,CAAAA,GAAAA,QAAU,AAAqE,CAAA,WAArE,CAA0BU,CAAAA,GAAAA,MAAqB,AAAqB,CAAA,sBAArB,EAAqB,CAAC,CAAC;IAChFV,CAAAA,GAAAA,QAAU,AAA2E,CAAA,WAA3E,CAA0BU,CAAAA,GAAAA,MAAqB,AAA2B,CAAA,sBAA3B,EAA2B,CAAC,CAAC;IACtFZ,CAAAA,GAAAA,QAAW,AAAqC,CAAA,YAArC,CAACY,CAAAA,GAAAA,MAAqB,AAAc,CAAA,sBAAd,EAAc,CAAC,CAAC;IACjDZ,CAAAA,GAAAA,QAAW,AAAmD,CAAA,YAAnD,CAACY,CAAAA,GAAAA,MAAqB,AAA4B,CAAA,sBAA5B,EAA4B,CAAC,CAAC;CAChE,CAAC,CAAC;AAEHd,QAAQ,CAAC,aAAa,EAAE,IAAM;IAC5BC,EAAE,CAAC,4BAA4B,EAAE,IAAM;QACrCG,CAAAA,GAAAA,QAAU,AAAoC,CAAA,WAApC,CAAYW,CAAAA,GAAAA,MAAW,AAAY,CAAA,YAAZ,EAAY,CAAC,CAAC;KAChD,CAAC,CAAC;IAEHd,EAAE,CAAC,kCAAkC,EAAE,IAAM;QAC3CC,CAAAA,GAAAA,QAAW,AAA2B,CAAA,YAA3B,CAACa,CAAAA,GAAAA,MAAW,AAAc,CAAA,YAAd,EAAc,CAAC,CAAC;KACxC,CAAC,CAAC;IAEHd,EAAE,CAAC,iCAAiC,EAAE,IAAM;QAC1CG,CAAAA,GAAAA,QAAU,AAAqC,CAAA,WAArC,CAAYW,CAAAA,GAAAA,MAAW,AAAa,CAAA,YAAb,EAAa,CAAC,CAAC;KACjD,CAAC,CAAC;IAEHd,EAAE,CAAC,sCAAsC,EAAE,IAAM;QAC/CC,CAAAA,GAAAA,QAAW,AAAoC,CAAA,YAApC,CAACa,CAAAA,GAAAA,MAAW,AAAuB,CAAA,YAAvB,EAAuB,CAAC,CAAC;KACjD,CAAC,CAAC;CACJ,CAAC,CAAC"}
1
+ {"version":3,"sources":["../../../../../../src/start/server/type-generation/__typetests__/route.test.ts"],"sourcesContent":["import { expectType, expectError } from 'tsd-lite';\n\nimport {\n useGlobalSearchParams,\n useSegments,\n useRouter,\n useSearchParams,\n useLocalSearchParams,\n} from './fixtures/basic';\n\n// eslint-disable-next-line react-hooks/rules-of-hooks\nconst router = useRouter();\n\ndescribe('router.push()', () => {\n // router.push will return void when the type matches, otherwise it should error\n\n describe('href', () => {\n it('will error on non-urls', () => {\n expectError(router.push('should-error'));\n });\n\n it('can accept an absolute url', () => {\n expectType<void>(router.push('/apple'));\n expectType<void>(router.push('/banana'));\n });\n\n it('can accept a ANY relative url', () => {\n // We only type-check absolute urls\n expectType<void>(router.push('./this/work/but/is/not/valid'));\n });\n\n it('works for dynamic urls', () => {\n expectType<void>(router.push('/colors/blue'));\n });\n\n it('works for CatchAll routes', () => {\n expectType<void>(router.push('/animals/bear'));\n expectType<void>(router.push('/animals/bear/cat/dog'));\n expectType<void>(router.push('/mix/apple/blue/cat/dog'));\n });\n\n it.skip('works for optional CatchAll routes', () => {\n // CatchAll routes are not currently optional\n // expectType<void>(router.push('/animals/'));\n });\n\n it('will error when providing extra parameters', () => {\n expectError(router.push('/colors/blue/test'));\n });\n\n it('will error when providing too few parameters', () => {\n expectError(router.push('/mix/apple'));\n expectError(router.push('/mix/apple/cat'));\n });\n\n it('can accept any external url', () => {\n expectType<void>(router.push('http://expo.dev'));\n });\n });\n\n describe('HrefObject', () => {\n it('will error on non-urls', () => {\n expectError(router.push({ pathname: 'should-error' }));\n });\n\n it('can accept an absolute url', () => {\n expectType<void>(router.push({ pathname: '/apple' }));\n expectType<void>(router.push({ pathname: '/banana' }));\n });\n\n it('can accept a ANY relative url', () => {\n // We only type-check absolute urls\n expectType<void>(router.push({ pathname: './this/work/but/is/not/valid' }));\n });\n\n it('works for dynamic urls', () => {\n expectType<void>(\n router.push({\n pathname: '/colors/[color]',\n params: { color: 'blue' },\n })\n );\n });\n\n it('requires a valid pathname', () => {\n expectError(\n router.push({\n pathname: '/colors/[invalid]',\n params: { color: 'blue' },\n })\n );\n });\n\n it('requires a valid param', () => {\n expectError(\n router.push({\n pathname: '/colors/[color]',\n params: { invalid: 'blue' },\n })\n );\n });\n\n it('works for catch all routes', () => {\n expectType<void>(\n router.push({\n pathname: '/animals/[...animal]',\n params: { animal: ['cat', 'dog'] },\n })\n );\n });\n\n it('allows numeric inputs', () => {\n expectType<void>(\n router.push({\n pathname: '/mix/[fruit]/[color]/[...animals]',\n params: { color: 1, fruit: 'apple', animals: [2, 'cat'] },\n })\n );\n });\n\n it('requires an array for catch all routes', () => {\n expectError(\n router.push({\n pathname: '/animals/[...animal]',\n params: { animal: 'cat' },\n })\n );\n });\n\n it('works for mixed routes', () => {\n expectType<void>(\n router.push({\n pathname: '/mix/[fruit]/[color]/[...animals]',\n params: { color: 'red', fruit: 'apple', animals: [] },\n })\n );\n });\n\n it('requires all params in mixed routes', () => {\n expectError(\n router.push({\n pathname: '/mix/[fruit]/[color]/[...animals]',\n params: { color: 'red', animals: ['cat', 'dog'] },\n })\n );\n });\n });\n});\n\ndescribe('useSearchParams', () => {\n expectType<Record<'color', string>>(useSearchParams<Record<'color', string>>());\n expectType<Record<'color', string> & Record<string, string | string[]>>(\n useSearchParams<'/colors/[color]'>()\n );\n\n expectError(useSearchParams<'/invalid'>());\n expectError(useSearchParams<Record<'custom', Function>>());\n});\n\ndescribe('useLocalSearchParams', () => {\n expectType<Record<'color', string>>(useLocalSearchParams<Record<'color', string>>());\n expectType<Record<'color', string> & Record<string, string | string[]>>(\n useLocalSearchParams<'/colors/[color]'>()\n );\n\n expectError(useSearchParams<'/invalid'>());\n expectError(useSearchParams<Record<'custom', Function>>());\n});\n\ndescribe('useGlobalSearchParams', () => {\n expectType<Record<'color', string>>(useGlobalSearchParams<Record<'color', string>>());\n expectType<Record<'color', string> & Record<string, string | string[]>>(\n useGlobalSearchParams<'/colors/[color]'>()\n );\n\n expectError(useGlobalSearchParams<'/invalid'>());\n expectError(useGlobalSearchParams<Record<'custom', Function>>());\n});\n\ndescribe('useSegments', () => {\n it('can accept an absolute url', () => {\n expectType<['apple']>(useSegments<'/apple'>());\n });\n\n it('only accepts valid possible urls', () => {\n expectError(useSegments<'/invalid'>());\n });\n\n it('can accept an array of segments', () => {\n expectType<['apple']>(useSegments<['apple']>());\n });\n\n it('only accepts valid possible segments', () => {\n expectError(useSegments<['invalid segment']>());\n });\n});\n"],"names":["router","useRouter","describe","it","expectError","push","expectType","skip","pathname","params","color","invalid","animal","fruit","animals","useSearchParams","useLocalSearchParams","useGlobalSearchParams","useSegments"],"mappings":"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"}
@@ -10,6 +10,7 @@ exports.setToUnionType = exports.CAPTURE_GROUP_REGEX = exports.ARRAY_GROUP_REGEX
10
10
  var _promises = _interopRequireDefault(require("fs/promises"));
11
11
  var _lodash = require("lodash");
12
12
  var _path = _interopRequireDefault(require("path"));
13
+ var _dir = require("../../../utils/dir");
13
14
  var _template = require("../../../utils/template");
14
15
  var _metroWatchTypeScriptFiles = require("../metro/metroWatchTypeScriptFiles");
15
16
  function _interopRequireDefault(obj) {
@@ -23,17 +24,17 @@ const CATCH_ALL = /\[\.\.\..+?\]/g;
23
24
  exports.CATCH_ALL = CATCH_ALL;
24
25
  const SLUG = /\[.+?\]/g;
25
26
  exports.SLUG = SLUG;
26
- const ARRAY_GROUP_REGEX = /\(\w+?,.*?\)/g;
27
+ const ARRAY_GROUP_REGEX = /\(\s*\w[\w\s]*?,.*?\)/g;
27
28
  exports.ARRAY_GROUP_REGEX = ARRAY_GROUP_REGEX;
28
- const CAPTURE_GROUP_REGEX = /[\\(,](\w+?)(?=[,\\)])/g;
29
+ const CAPTURE_GROUP_REGEX = /[\\(,]\s*(\w[\w\s]*?)\s*(?=[,\\)])/g;
29
30
  exports.CAPTURE_GROUP_REGEX = CAPTURE_GROUP_REGEX;
30
31
  async function setupTypedRoutes({ server , metro , typesDirectory , projectRoot , routerDirectory }) {
31
- const appRoot = _path.default.join(projectRoot, routerDirectory);
32
- const { filePathToRoute , staticRoutes , dynamicRoutes , addFilePath } = getTypedRoutesUtils(appRoot);
32
+ const absoluteRouterDirectory = _path.default.join(projectRoot, routerDirectory);
33
+ const { filePathToRoute , staticRoutes , dynamicRoutes , addFilePath , isRouteFile } = getTypedRoutesUtils(absoluteRouterDirectory);
33
34
  if (metro) {
34
35
  // Setup out watcher first
35
36
  (0, _metroWatchTypeScriptFiles).metroWatchTypeScriptFiles({
36
- projectRoot: appRoot,
37
+ projectRoot,
37
38
  server,
38
39
  metro,
39
40
  eventTypes: [
@@ -42,6 +43,9 @@ async function setupTypedRoutes({ server , metro , typesDirectory , projectRoot
42
43
  "change"
43
44
  ],
44
45
  async callback ({ filePath , type }) {
46
+ if (!isRouteFile(filePath)) {
47
+ return;
48
+ }
45
49
  let shouldRegenerate = false;
46
50
  if (type === "delete") {
47
51
  const route = filePathToRoute(filePath);
@@ -63,9 +67,11 @@ async function setupTypedRoutes({ server , metro , typesDirectory , projectRoot
63
67
  }
64
68
  });
65
69
  }
66
- // Do we need to walk the entire tree on startup?
67
- // Idea: Store the list of files in the last write, then simply check Git for what files have changed
68
- await walk(appRoot, addFilePath);
70
+ if (await (0, _dir).directoryExistsAsync(absoluteRouterDirectory)) {
71
+ // Do we need to walk the entire tree on startup?
72
+ // Idea: Store the list of files in the last write, then simply check Git for what files have changed
73
+ await walk(absoluteRouterDirectory, addFilePath);
74
+ }
69
75
  regenerateRouterDotTS(typesDirectory, new Set([
70
76
  ...staticRoutes.values()
71
77
  ].flatMap((v)=>Array.from(v)
@@ -77,8 +83,11 @@ async function setupTypedRoutes({ server , metro , typesDirectory , projectRoot
77
83
  /**
78
84
  * Generate a router.d.ts file that contains all of the routes in the project.
79
85
  * Should be debounced as its very common for developers to make changes to multiple files at once (eg Save All)
80
- */ const regenerateRouterDotTS = (0, _lodash).debounce((typesDir, staticRoutes, dynamicRoutes, dynamicRouteTemplates)=>{
81
- _promises.default.writeFile(_path.default.resolve(typesDir, "./router.d.ts"), getTemplateString(staticRoutes, dynamicRoutes, dynamicRouteTemplates));
86
+ */ const regenerateRouterDotTS = (0, _lodash).debounce(async (typesDir, staticRoutes, dynamicRoutes, dynamicRouteTemplates)=>{
87
+ await _promises.default.mkdir(typesDir, {
88
+ recursive: true
89
+ });
90
+ await _promises.default.writeFile(_path.default.resolve(typesDir, "./router.d.ts"), getTemplateString(staticRoutes, dynamicRoutes, dynamicRouteTemplates));
82
91
  }, 100);
83
92
  function getTemplateString(staticRoutes, dynamicRoutes, dynamicRouteTemplates) {
84
93
  return routerDotTSTemplate({
@@ -87,7 +96,7 @@ function getTemplateString(staticRoutes, dynamicRoutes, dynamicRouteTemplates) {
87
96
  dynamicRouteParams: setToUnionType(dynamicRouteTemplates)
88
97
  });
89
98
  }
90
- function getTypedRoutesUtils(appRoot) {
99
+ function getTypedRoutesUtils(appRoot, filePathSeperator = _path.default.sep) {
91
100
  /*
92
101
  * staticRoutes are a map where the key if the route without groups and the value
93
102
  * is another set of all group versions of the route. e.g,
@@ -110,13 +119,23 @@ function getTypedRoutesUtils(appRoot) {
110
119
  * The keys of this map are also important, as they can be used as "static" types
111
120
  * <Link href={{ pathname: "/[...fruits]",params: { fruits: ["apple"] } }} />
112
121
  */ const dynamicRoutes = new Map();
122
+ function normalizedFilePath(filePath) {
123
+ return filePath.replaceAll(filePathSeperator, "/");
124
+ }
125
+ const normalizedAppRoot = normalizedFilePath(appRoot);
113
126
  const filePathToRoute = (filePath)=>{
114
- return filePath.replace(appRoot, "").replace(/index.[jt]sx?/, "").replace(/\.[jt]sx?$/, "");
127
+ return normalizedFilePath(filePath).replace(normalizedAppRoot, "").replace(/index\.[jt]sx?/, "").replace(/\.[jt]sx?$/, "");
115
128
  };
116
- const addFilePath = (filePath)=>{
117
- if (filePath.match(/_layout\.[tj]sx?$/)) {
129
+ const isRouteFile = (filePath)=>{
130
+ // Layout and filenames starting with `+` are not routes
131
+ if (filePath.match(/_layout\.[tj]sx?$/) || filePath.match(/\/\+/)) {
118
132
  return false;
119
133
  }
134
+ // Route files must be nested with in the appRoot
135
+ const relative = _path.default.relative(appRoot, filePath);
136
+ return relative && !relative.startsWith("..") && !_path.default.isAbsolute(relative);
137
+ };
138
+ const addFilePath = (filePath)=>{
120
139
  const route1 = filePathToRoute(filePath);
121
140
  // We have already processed this file
122
141
  if (staticRoutes.has(route1) || dynamicRoutes.has(route1)) {
@@ -163,7 +182,8 @@ function getTypedRoutesUtils(appRoot) {
163
182
  staticRoutes,
164
183
  dynamicRoutes,
165
184
  filePathToRoute,
166
- addFilePath
185
+ addFilePath,
186
+ isRouteFile
167
187
  };
168
188
  }
169
189
  const setToUnionType = (set)=>{
@@ -183,7 +203,7 @@ exports.setToUnionType = setToUnionType;
183
203
  await walk(p, callback);
184
204
  } else {
185
205
  // Normalise the paths so they are easier to convert to URLs
186
- const normalizedPath = p.replaceAll(_path.default.sep, "/").replaceAll(" ", "_");
206
+ const normalizedPath = p.replaceAll(_path.default.sep, "/");
187
207
  callback(normalizedPath);
188
208
  }
189
209
  }
@@ -198,7 +218,7 @@ function extrapolateGroupRoutes(route, routes = new Set()) {
198
218
  }
199
219
  const groupsMatch = match[0];
200
220
  for (const group of groupsMatch.matchAll(CAPTURE_GROUP_REGEX)){
201
- extrapolateGroupRoutes(route.replace(groupsMatch, `(${group[1]})`), routes);
221
+ extrapolateGroupRoutes(route.replace(groupsMatch, `(${group[1].trim()})`), routes);
202
222
  }
203
223
  return routes;
204
224
  }
@@ -211,6 +231,7 @@ function extrapolateGroupRoutes(route, routes = new Set()) {
211
231
  /* eslint-disable @typescript-eslint/ban-types */
212
232
  declare module "expo-router" {
213
233
  import type { LinkProps as OriginalLinkProps } from 'expo-router/build/link/Link';
234
+ import type { Router as OriginalRouter } from 'expo-router/src/types';
214
235
  export * from 'expo-router/build';
215
236
 
216
237
  // prettier-ignore
@@ -231,6 +252,8 @@ declare module "expo-router" {
231
252
  ****************/
232
253
 
233
254
  type SearchOrHash = \`?\${string}\` | \`#\${string}\`;
255
+ type UnknownInputParams = Record<string, string | number | (string | number)[]>;
256
+ type UnknownOutputParams = Record<string, string | string[]>;
234
257
 
235
258
  /**
236
259
  * Return only the RoutePart of a string. If the string has multiple parts return never
@@ -250,6 +273,10 @@ declare module "expo-router" {
250
273
  ? never
251
274
  : S extends ''
252
275
  ? never
276
+ : S extends \`(\${string})\`
277
+ ? never
278
+ : S extends \`[\${string}]\`
279
+ ? never
253
280
  : S;
254
281
 
255
282
  /**
@@ -259,6 +286,10 @@ declare module "expo-router" {
259
286
  ? never
260
287
  : S extends ''
261
288
  ? never
289
+ : S extends \`\${string}(\${string})\${string}\`
290
+ ? never
291
+ : S extends \`\${string}[\${string}]\${string}\`
292
+ ? never
262
293
  : S;
263
294
 
264
295
  // type OptionalCatchAllRoutePart<S extends string> = S extends \`\${string}\${SearchOrHash}\` ? never : S
@@ -295,25 +326,34 @@ declare module "expo-router" {
295
326
  : [Path];
296
327
 
297
328
  /**
298
- * Returns a Record of the routes parameters as strings and CatchAll parameters as string[]
329
+ * Returns a Record of the routes parameters as strings and CatchAll parameters
330
+ *
331
+ * There are two versions, input and output, as you can input 'string | number' but
332
+ * the output will always be 'string'
299
333
  *
300
334
  * /[id]/[...rest] -> { id: string, rest: string[] }
301
335
  * /no-params -> {}
302
336
  */
303
- type RouteParams<Path> = {
337
+ type InputRouteParams<Path> = {
338
+ [Key in ParameterNames<Path> as Key extends \`...\${infer Name}\`
339
+ ? Name
340
+ : Key]: Key extends \`...\${string}\` ? (string | number)[] : string | number;
341
+ } & UnknownInputParams;
342
+
343
+ type OutputRouteParams<Path> = {
304
344
  [Key in ParameterNames<Path> as Key extends \`...\${infer Name}\`
305
345
  ? Name
306
346
  : Key]: Key extends \`...\${string}\` ? string[] : string;
307
- };
347
+ } & UnknownOutputParams;
308
348
 
309
349
  /**
310
- * Returns the search parameters for a route
350
+ * Returns the search parameters for a route.
311
351
  */
312
352
  export type SearchParams<T extends AllRoutes> = T extends DynamicRouteTemplate
313
- ? RouteParams<T>
353
+ ? OutputRouteParams<T>
314
354
  : T extends StaticRoutes
315
355
  ? never
316
- : Record<string, string>;
356
+ : UnknownOutputParams;
317
357
 
318
358
  /**
319
359
  * Route is mostly used as part of Href to ensure that a valid route is provided
@@ -328,71 +368,98 @@ declare module "expo-router" {
328
368
  *
329
369
  * This is named Route to prevent confusion, as users they will often see it in tooltips
330
370
  */
331
- export type Route<T> = T extends DynamicRouteTemplate
332
- ? never
333
- :
334
- | StaticRoutes
335
- | RelativePathString
336
- | ExternalPathString
337
- | (T extends DynamicRoutes<infer _> ? T : never);
371
+ export type Route<T> = T extends string
372
+ ? T extends DynamicRouteTemplate
373
+ ? never
374
+ :
375
+ | StaticRoutes
376
+ | RelativePathString
377
+ | ExternalPathString
378
+ | (T extends \`\${infer P}\${SearchOrHash}\`
379
+ ? P extends DynamicRoutes<infer _>
380
+ ? T
381
+ : never
382
+ : T extends DynamicRoutes<infer _>
383
+ ? T
384
+ : never)
385
+ : never;
338
386
 
339
387
  /*********
340
388
  * Href *
341
389
  *********/
342
390
 
343
- export type Href<T extends string> = Route<T> | HrefObject<T>;
391
+ export type Href<T> = T extends Record<'pathname', string> ? HrefObject<T> : Route<T>;
344
392
 
345
- export type HrefObject<T = AllRoutes> = T extends DynamicRouteTemplate
346
- ? { pathname: T; params: RouteParams<T> }
347
- : T extends Route<T>
348
- ? { pathname: Route<T>; params?: never }
393
+ export type HrefObject<
394
+ R extends Record<'pathname', string>,
395
+ P = R['pathname']
396
+ > = P extends DynamicRouteTemplate
397
+ ? { pathname: P; params: InputRouteParams<P> }
398
+ : P extends Route<P>
399
+ ? { pathname: Route<P> | DynamicRouteTemplate; params?: never | InputRouteParams<never> }
349
400
  : never;
350
401
 
351
402
  /***********************
352
403
  * Expo Router Exports *
353
404
  ***********************/
354
405
 
355
- export type Router = {
406
+ export type Router = Omit<OriginalRouter, 'push' | 'replace' | 'setParams'> & {
356
407
  /** Navigate to the provided href. */
357
- push: <T extends string>(href: Href<T>) => void;
408
+ push: <T>(href: Href<T>) => void;
358
409
  /** Navigate to route without appending to the history. */
359
- replace: <T extends string>(href: Href<T>) => void;
360
- /** Go back in the history. */
361
- back: () => void;
410
+ replace: <T>(href: Href<T>) => void;
362
411
  /** Update the current route query params. */
363
- setParams: <T extends string = ''>(
364
- params?: T extends '' ? Record<string, string> : RouteParams<T>
365
- ) => void;
412
+ setParams: <T = ''>(params?: T extends '' ? Record<string, string> : InputRouteParams<T>) => void;
366
413
  };
367
414
 
415
+ /** The imperative router. */
416
+ export const router: Router;
417
+
368
418
  /************
369
419
  * <Link /> *
370
420
  ************/
371
- export interface LinkProps<T extends string> extends OriginalLinkProps {
372
- href: T extends DynamicRouteTemplate ? HrefObject<T> : Href<T>;
421
+ export interface LinkProps<T> extends OriginalLinkProps {
422
+ href: Href<T>;
373
423
  }
374
424
 
375
425
  export interface LinkComponent {
376
- <T extends string>(props: React.PropsWithChildren<LinkProps<T>>): JSX.Element;
426
+ <T>(props: React.PropsWithChildren<LinkProps<T>>): JSX.Element;
377
427
  /** Helper method to resolve an Href object into a string. */
378
- resolveHref: <T extends string>(href: Href<T>) => string;
428
+ resolveHref: <T>(href: Href<T>) => string;
379
429
  }
380
430
 
431
+ /**
432
+ * Component to render link to another route using a path.
433
+ * Uses an anchor tag on the web.
434
+ *
435
+ * @param props.href Absolute path to route (e.g. \`/feeds/hot\`).
436
+ * @param props.replace Should replace the current route without adding to the history.
437
+ * @param props.asChild Forward props to child component. Useful for custom buttons.
438
+ * @param props.children Child elements to render the content.
439
+ */
381
440
  export const Link: LinkComponent;
441
+
442
+ /** Redirects to the href as soon as the component is mounted. */
443
+ export const Redirect: <T>(
444
+ props: React.PropsWithChildren<{ href: Href<T> }>
445
+ ) => JSX.Element;
382
446
 
383
447
  /************
384
448
  * Hooks *
385
449
  ************/
386
450
  export function useRouter(): Router;
451
+
387
452
  export function useLocalSearchParams<
388
- T extends DynamicRouteTemplate | StaticRoutes | RelativePathString
389
- >(): SearchParams<T>;
453
+ T extends AllRoutes | UnknownOutputParams = UnknownOutputParams
454
+ >(): T extends AllRoutes ? SearchParams<T> : T;
455
+
456
+ /** @deprecated renamed to \`useGlobalSearchParams\` */
390
457
  export function useSearchParams<
391
- T extends AllRoutes | SearchParams<DynamicRouteTemplate>
458
+ T extends AllRoutes | UnknownOutputParams = UnknownOutputParams
392
459
  >(): T extends AllRoutes ? SearchParams<T> : T;
393
460
 
394
461
  export function useGlobalSearchParams<
395
- T extends AllRoutes | SearchParams<DynamicRouteTemplate>
462
+ T extends AllRoutes | UnknownOutputParams = UnknownOutputParams
396
463
  >(): T extends AllRoutes ? SearchParams<T> : T;
397
464
 
398
465
  export function useSegments<