@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.
- package/build/bin/cli +2 -2
- package/build/src/export/index.js +3 -1
- package/build/src/export/index.js.map +1 -1
- package/build/src/export/resolveOptions.js +28 -29
- package/build/src/export/resolveOptions.js.map +1 -1
- package/build/src/start/server/metro/MetroBundlerDevServer.js +31 -1
- package/build/src/start/server/metro/MetroBundlerDevServer.js.map +1 -1
- package/build/src/start/server/metro/inspector-proxy/proxy.js +12 -9
- package/build/src/start/server/metro/inspector-proxy/proxy.js.map +1 -1
- package/build/src/start/server/metro/metroWatchTypeScriptFiles.js +1 -1
- package/build/src/start/server/metro/metroWatchTypeScriptFiles.js.map +1 -1
- package/build/src/start/server/metro/withMetroResolvers.js +13 -4
- package/build/src/start/server/metro/withMetroResolvers.js.map +1 -1
- package/build/src/start/server/middleware/ClassicManifestMiddleware.js +1 -1
- package/build/src/start/server/type-generation/__typetests__/fixtures/basic.js.map +1 -1
- package/build/src/start/server/type-generation/__typetests__/route.test.js +20 -9
- package/build/src/start/server/type-generation/__typetests__/route.test.js.map +1 -1
- package/build/src/start/server/type-generation/routes.js +118 -51
- package/build/src/start/server/type-generation/routes.js.map +1 -1
- package/build/src/utils/analytics/metroDebuggerMiddleware.js +9 -4
- package/build/src/utils/analytics/metroDebuggerMiddleware.js.map +1 -1
- package/build/src/utils/analytics/rudderstackClient.js +2 -2
- package/build/src/utils/port.js +2 -0
- package/build/src/utils/port.js.map +1 -1
- 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 (
|
|
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(
|
|
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: ${
|
|
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(
|
|
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(
|
|
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.
|
|
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
|
|
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":"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"}
|
|
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
|
|
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
|
|
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
|
|
32
|
-
const { filePathToRoute , staticRoutes , dynamicRoutes , addFilePath } = getTypedRoutesUtils(
|
|
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
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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.
|
|
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(
|
|
127
|
+
return normalizedFilePath(filePath).replace(normalizedAppRoot, "").replace(/index\.[jt]sx?/, "").replace(/\.[jt]sx?$/, "");
|
|
115
128
|
};
|
|
116
|
-
const
|
|
117
|
-
|
|
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, "/")
|
|
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
|
|
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
|
|
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
|
-
?
|
|
353
|
+
? OutputRouteParams<T>
|
|
314
354
|
: T extends StaticRoutes
|
|
315
355
|
? never
|
|
316
|
-
:
|
|
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
|
|
332
|
-
?
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
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>
|
|
391
|
+
export type Href<T> = T extends Record<'pathname', string> ? HrefObject<T> : Route<T>;
|
|
344
392
|
|
|
345
|
-
export type HrefObject<
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
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
|
|
408
|
+
push: <T>(href: Href<T>) => void;
|
|
358
409
|
/** Navigate to route without appending to the history. */
|
|
359
|
-
replace: <T
|
|
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
|
|
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
|
|
372
|
-
href:
|
|
421
|
+
export interface LinkProps<T> extends OriginalLinkProps {
|
|
422
|
+
href: Href<T>;
|
|
373
423
|
}
|
|
374
424
|
|
|
375
425
|
export interface LinkComponent {
|
|
376
|
-
<T
|
|
426
|
+
<T>(props: React.PropsWithChildren<LinkProps<T>>): JSX.Element;
|
|
377
427
|
/** Helper method to resolve an Href object into a string. */
|
|
378
|
-
resolveHref: <T
|
|
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
|
|
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 |
|
|
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 |
|
|
462
|
+
T extends AllRoutes | UnknownOutputParams = UnknownOutputParams
|
|
396
463
|
>(): T extends AllRoutes ? SearchParams<T> : T;
|
|
397
464
|
|
|
398
465
|
export function useSegments<
|