utils.d.ts 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. import type { Location, Path, To } from "./history";
  2. /**
  3. * Map of routeId -> data returned from a loader/action/error
  4. */
  5. export interface RouteData {
  6. [routeId: string]: any;
  7. }
  8. export declare enum ResultType {
  9. data = "data",
  10. deferred = "deferred",
  11. redirect = "redirect",
  12. error = "error"
  13. }
  14. /**
  15. * Successful result from a loader or action
  16. */
  17. export interface SuccessResult {
  18. type: ResultType.data;
  19. data: unknown;
  20. statusCode?: number;
  21. headers?: Headers;
  22. }
  23. /**
  24. * Successful defer() result from a loader or action
  25. */
  26. export interface DeferredResult {
  27. type: ResultType.deferred;
  28. deferredData: DeferredData;
  29. statusCode?: number;
  30. headers?: Headers;
  31. }
  32. /**
  33. * Redirect result from a loader or action
  34. */
  35. export interface RedirectResult {
  36. type: ResultType.redirect;
  37. response: Response;
  38. }
  39. /**
  40. * Unsuccessful result from a loader or action
  41. */
  42. export interface ErrorResult {
  43. type: ResultType.error;
  44. error: unknown;
  45. statusCode?: number;
  46. headers?: Headers;
  47. }
  48. /**
  49. * Result from a loader or action - potentially successful or unsuccessful
  50. */
  51. export type DataResult = SuccessResult | DeferredResult | RedirectResult | ErrorResult;
  52. type LowerCaseFormMethod = "get" | "post" | "put" | "patch" | "delete";
  53. type UpperCaseFormMethod = Uppercase<LowerCaseFormMethod>;
  54. /**
  55. * Users can specify either lowercase or uppercase form methods on `<Form>`,
  56. * useSubmit(), `<fetcher.Form>`, etc.
  57. */
  58. export type HTMLFormMethod = LowerCaseFormMethod | UpperCaseFormMethod;
  59. /**
  60. * Active navigation/fetcher form methods are exposed in lowercase on the
  61. * RouterState
  62. */
  63. export type FormMethod = LowerCaseFormMethod;
  64. export type MutationFormMethod = Exclude<FormMethod, "get">;
  65. /**
  66. * In v7, active navigation/fetcher form methods are exposed in uppercase on the
  67. * RouterState. This is to align with the normalization done via fetch().
  68. */
  69. export type V7_FormMethod = UpperCaseFormMethod;
  70. export type V7_MutationFormMethod = Exclude<V7_FormMethod, "GET">;
  71. export type FormEncType = "application/x-www-form-urlencoded" | "multipart/form-data" | "application/json" | "text/plain";
  72. type JsonObject = {
  73. [Key in string]: JsonValue;
  74. } & {
  75. [Key in string]?: JsonValue | undefined;
  76. };
  77. type JsonArray = JsonValue[] | readonly JsonValue[];
  78. type JsonPrimitive = string | number | boolean | null;
  79. type JsonValue = JsonPrimitive | JsonObject | JsonArray;
  80. /**
  81. * @private
  82. * Internal interface to pass around for action submissions, not intended for
  83. * external consumption
  84. */
  85. export type Submission = {
  86. formMethod: FormMethod | V7_FormMethod;
  87. formAction: string;
  88. formEncType: FormEncType;
  89. formData: FormData;
  90. json: undefined;
  91. text: undefined;
  92. } | {
  93. formMethod: FormMethod | V7_FormMethod;
  94. formAction: string;
  95. formEncType: FormEncType;
  96. formData: undefined;
  97. json: JsonValue;
  98. text: undefined;
  99. } | {
  100. formMethod: FormMethod | V7_FormMethod;
  101. formAction: string;
  102. formEncType: FormEncType;
  103. formData: undefined;
  104. json: undefined;
  105. text: string;
  106. };
  107. /**
  108. * @private
  109. * Arguments passed to route loader/action functions. Same for now but we keep
  110. * this as a private implementation detail in case they diverge in the future.
  111. */
  112. interface DataFunctionArgs<Context> {
  113. request: Request;
  114. params: Params;
  115. context?: Context;
  116. }
  117. /**
  118. * Arguments passed to loader functions
  119. */
  120. export interface LoaderFunctionArgs<Context = any> extends DataFunctionArgs<Context> {
  121. }
  122. /**
  123. * Arguments passed to action functions
  124. */
  125. export interface ActionFunctionArgs<Context = any> extends DataFunctionArgs<Context> {
  126. }
  127. /**
  128. * Loaders and actions can return anything except `undefined` (`null` is a
  129. * valid return value if there is no data to return). Responses are preferred
  130. * and will ease any future migration to Remix
  131. */
  132. type DataFunctionValue = Response | NonNullable<unknown> | null;
  133. type DataFunctionReturnValue = Promise<DataFunctionValue> | DataFunctionValue;
  134. /**
  135. * Route loader function signature
  136. */
  137. export type LoaderFunction<Context = any> = {
  138. (args: LoaderFunctionArgs<Context>, handlerCtx?: unknown): DataFunctionReturnValue;
  139. } & {
  140. hydrate?: boolean;
  141. };
  142. /**
  143. * Route action function signature
  144. */
  145. export interface ActionFunction<Context = any> {
  146. (args: ActionFunctionArgs<Context>, handlerCtx?: unknown): DataFunctionReturnValue;
  147. }
  148. /**
  149. * Arguments passed to shouldRevalidate function
  150. */
  151. export interface ShouldRevalidateFunctionArgs {
  152. currentUrl: URL;
  153. currentParams: AgnosticDataRouteMatch["params"];
  154. nextUrl: URL;
  155. nextParams: AgnosticDataRouteMatch["params"];
  156. formMethod?: Submission["formMethod"];
  157. formAction?: Submission["formAction"];
  158. formEncType?: Submission["formEncType"];
  159. text?: Submission["text"];
  160. formData?: Submission["formData"];
  161. json?: Submission["json"];
  162. actionStatus?: number;
  163. actionResult?: any;
  164. defaultShouldRevalidate: boolean;
  165. }
  166. /**
  167. * Route shouldRevalidate function signature. This runs after any submission
  168. * (navigation or fetcher), so we flatten the navigation/fetcher submission
  169. * onto the arguments. It shouldn't matter whether it came from a navigation
  170. * or a fetcher, what really matters is the URLs and the formData since loaders
  171. * have to re-run based on the data models that were potentially mutated.
  172. */
  173. export interface ShouldRevalidateFunction {
  174. (args: ShouldRevalidateFunctionArgs): boolean;
  175. }
  176. /**
  177. * Function provided by the framework-aware layers to set `hasErrorBoundary`
  178. * from the framework-aware `errorElement` prop
  179. *
  180. * @deprecated Use `mapRouteProperties` instead
  181. */
  182. export interface DetectErrorBoundaryFunction {
  183. (route: AgnosticRouteObject): boolean;
  184. }
  185. export interface DataStrategyMatch extends AgnosticRouteMatch<string, AgnosticDataRouteObject> {
  186. shouldLoad: boolean;
  187. resolve: (handlerOverride?: (handler: (ctx?: unknown) => DataFunctionReturnValue) => DataFunctionReturnValue) => Promise<DataStrategyResult>;
  188. }
  189. export interface DataStrategyFunctionArgs<Context = any> extends DataFunctionArgs<Context> {
  190. matches: DataStrategyMatch[];
  191. fetcherKey: string | null;
  192. }
  193. /**
  194. * Result from a loader or action called via dataStrategy
  195. */
  196. export interface DataStrategyResult {
  197. type: "data" | "error";
  198. result: unknown;
  199. }
  200. export interface DataStrategyFunction {
  201. (args: DataStrategyFunctionArgs): Promise<Record<string, DataStrategyResult>>;
  202. }
  203. export type AgnosticPatchRoutesOnNavigationFunctionArgs<O extends AgnosticRouteObject = AgnosticRouteObject, M extends AgnosticRouteMatch = AgnosticRouteMatch> = {
  204. signal: AbortSignal;
  205. path: string;
  206. matches: M[];
  207. fetcherKey: string | undefined;
  208. patch: (routeId: string | null, children: O[]) => void;
  209. };
  210. export type AgnosticPatchRoutesOnNavigationFunction<O extends AgnosticRouteObject = AgnosticRouteObject, M extends AgnosticRouteMatch = AgnosticRouteMatch> = (opts: AgnosticPatchRoutesOnNavigationFunctionArgs<O, M>) => void | Promise<void>;
  211. /**
  212. * Function provided by the framework-aware layers to set any framework-specific
  213. * properties from framework-agnostic properties
  214. */
  215. export interface MapRoutePropertiesFunction {
  216. (route: AgnosticRouteObject): {
  217. hasErrorBoundary: boolean;
  218. } & Record<string, any>;
  219. }
  220. /**
  221. * Keys we cannot change from within a lazy() function. We spread all other keys
  222. * onto the route. Either they're meaningful to the router, or they'll get
  223. * ignored.
  224. */
  225. export type ImmutableRouteKey = "lazy" | "caseSensitive" | "path" | "id" | "index" | "children";
  226. export declare const immutableRouteKeys: Set<ImmutableRouteKey>;
  227. type RequireOne<T, Key = keyof T> = Exclude<{
  228. [K in keyof T]: K extends Key ? Omit<T, K> & Required<Pick<T, K>> : never;
  229. }[keyof T], undefined>;
  230. /**
  231. * lazy() function to load a route definition, which can add non-matching
  232. * related properties to a route
  233. */
  234. export interface LazyRouteFunction<R extends AgnosticRouteObject> {
  235. (): Promise<RequireOne<Omit<R, ImmutableRouteKey>>>;
  236. }
  237. /**
  238. * Base RouteObject with common props shared by all types of routes
  239. */
  240. type AgnosticBaseRouteObject = {
  241. caseSensitive?: boolean;
  242. path?: string;
  243. id?: string;
  244. loader?: LoaderFunction | boolean;
  245. action?: ActionFunction | boolean;
  246. hasErrorBoundary?: boolean;
  247. shouldRevalidate?: ShouldRevalidateFunction;
  248. handle?: any;
  249. lazy?: LazyRouteFunction<AgnosticBaseRouteObject>;
  250. };
  251. /**
  252. * Index routes must not have children
  253. */
  254. export type AgnosticIndexRouteObject = AgnosticBaseRouteObject & {
  255. children?: undefined;
  256. index: true;
  257. };
  258. /**
  259. * Non-index routes may have children, but cannot have index
  260. */
  261. export type AgnosticNonIndexRouteObject = AgnosticBaseRouteObject & {
  262. children?: AgnosticRouteObject[];
  263. index?: false;
  264. };
  265. /**
  266. * A route object represents a logical route, with (optionally) its child
  267. * routes organized in a tree-like structure.
  268. */
  269. export type AgnosticRouteObject = AgnosticIndexRouteObject | AgnosticNonIndexRouteObject;
  270. export type AgnosticDataIndexRouteObject = AgnosticIndexRouteObject & {
  271. id: string;
  272. };
  273. export type AgnosticDataNonIndexRouteObject = AgnosticNonIndexRouteObject & {
  274. children?: AgnosticDataRouteObject[];
  275. id: string;
  276. };
  277. /**
  278. * A data route object, which is just a RouteObject with a required unique ID
  279. */
  280. export type AgnosticDataRouteObject = AgnosticDataIndexRouteObject | AgnosticDataNonIndexRouteObject;
  281. export type RouteManifest = Record<string, AgnosticDataRouteObject | undefined>;
  282. type _PathParam<Path extends string> = Path extends `${infer L}/${infer R}` ? _PathParam<L> | _PathParam<R> : Path extends `:${infer Param}` ? Param extends `${infer Optional}?` ? Optional : Param : never;
  283. /**
  284. * Examples:
  285. * "/a/b/*" -> "*"
  286. * ":a" -> "a"
  287. * "/a/:b" -> "b"
  288. * "/a/blahblahblah:b" -> "b"
  289. * "/:a/:b" -> "a" | "b"
  290. * "/:a/b/:c/*" -> "a" | "c" | "*"
  291. */
  292. export type PathParam<Path extends string> = Path extends "*" | "/*" ? "*" : Path extends `${infer Rest}/*` ? "*" | _PathParam<Rest> : _PathParam<Path>;
  293. export type ParamParseKey<Segment extends string> = [
  294. PathParam<Segment>
  295. ] extends [never] ? string : PathParam<Segment>;
  296. /**
  297. * The parameters that were parsed from the URL path.
  298. */
  299. export type Params<Key extends string = string> = {
  300. readonly [key in Key]: string | undefined;
  301. };
  302. /**
  303. * A RouteMatch contains info about how a route matched a URL.
  304. */
  305. export interface AgnosticRouteMatch<ParamKey extends string = string, RouteObjectType extends AgnosticRouteObject = AgnosticRouteObject> {
  306. /**
  307. * The names and values of dynamic parameters in the URL.
  308. */
  309. params: Params<ParamKey>;
  310. /**
  311. * The portion of the URL pathname that was matched.
  312. */
  313. pathname: string;
  314. /**
  315. * The portion of the URL pathname that was matched before child routes.
  316. */
  317. pathnameBase: string;
  318. /**
  319. * The route object that was used to match.
  320. */
  321. route: RouteObjectType;
  322. }
  323. export interface AgnosticDataRouteMatch extends AgnosticRouteMatch<string, AgnosticDataRouteObject> {
  324. }
  325. export declare function convertRoutesToDataRoutes(routes: AgnosticRouteObject[], mapRouteProperties: MapRoutePropertiesFunction, parentPath?: string[], manifest?: RouteManifest): AgnosticDataRouteObject[];
  326. /**
  327. * Matches the given routes to a location and returns the match data.
  328. *
  329. * @see https://reactrouter.com/v6/utils/match-routes
  330. */
  331. export declare function matchRoutes<RouteObjectType extends AgnosticRouteObject = AgnosticRouteObject>(routes: RouteObjectType[], locationArg: Partial<Location> | string, basename?: string): AgnosticRouteMatch<string, RouteObjectType>[] | null;
  332. export declare function matchRoutesImpl<RouteObjectType extends AgnosticRouteObject = AgnosticRouteObject>(routes: RouteObjectType[], locationArg: Partial<Location> | string, basename: string, allowPartial: boolean): AgnosticRouteMatch<string, RouteObjectType>[] | null;
  333. export interface UIMatch<Data = unknown, Handle = unknown> {
  334. id: string;
  335. pathname: string;
  336. params: AgnosticRouteMatch["params"];
  337. data: Data;
  338. handle: Handle;
  339. }
  340. export declare function convertRouteMatchToUiMatch(match: AgnosticDataRouteMatch, loaderData: RouteData): UIMatch;
  341. /**
  342. * Returns a path with params interpolated.
  343. *
  344. * @see https://reactrouter.com/v6/utils/generate-path
  345. */
  346. export declare function generatePath<Path extends string>(originalPath: Path, params?: {
  347. [key in PathParam<Path>]: string | null;
  348. }): string;
  349. /**
  350. * A PathPattern is used to match on some portion of a URL pathname.
  351. */
  352. export interface PathPattern<Path extends string = string> {
  353. /**
  354. * A string to match against a URL pathname. May contain `:id`-style segments
  355. * to indicate placeholders for dynamic parameters. May also end with `/*` to
  356. * indicate matching the rest of the URL pathname.
  357. */
  358. path: Path;
  359. /**
  360. * Should be `true` if the static portions of the `path` should be matched in
  361. * the same case.
  362. */
  363. caseSensitive?: boolean;
  364. /**
  365. * Should be `true` if this pattern should match the entire URL pathname.
  366. */
  367. end?: boolean;
  368. }
  369. /**
  370. * A PathMatch contains info about how a PathPattern matched on a URL pathname.
  371. */
  372. export interface PathMatch<ParamKey extends string = string> {
  373. /**
  374. * The names and values of dynamic parameters in the URL.
  375. */
  376. params: Params<ParamKey>;
  377. /**
  378. * The portion of the URL pathname that was matched.
  379. */
  380. pathname: string;
  381. /**
  382. * The portion of the URL pathname that was matched before child routes.
  383. */
  384. pathnameBase: string;
  385. /**
  386. * The pattern that was used to match.
  387. */
  388. pattern: PathPattern;
  389. }
  390. /**
  391. * Performs pattern matching on a URL pathname and returns information about
  392. * the match.
  393. *
  394. * @see https://reactrouter.com/v6/utils/match-path
  395. */
  396. export declare function matchPath<ParamKey extends ParamParseKey<Path>, Path extends string>(pattern: PathPattern<Path> | Path, pathname: string): PathMatch<ParamKey> | null;
  397. export declare function decodePath(value: string): string;
  398. /**
  399. * @private
  400. */
  401. export declare function stripBasename(pathname: string, basename: string): string | null;
  402. /**
  403. * Returns a resolved path object relative to the given pathname.
  404. *
  405. * @see https://reactrouter.com/v6/utils/resolve-path
  406. */
  407. export declare function resolvePath(to: To, fromPathname?: string): Path;
  408. /**
  409. * @private
  410. *
  411. * When processing relative navigation we want to ignore ancestor routes that
  412. * do not contribute to the path, such that index/pathless layout routes don't
  413. * interfere.
  414. *
  415. * For example, when moving a route element into an index route and/or a
  416. * pathless layout route, relative link behavior contained within should stay
  417. * the same. Both of the following examples should link back to the root:
  418. *
  419. * <Route path="/">
  420. * <Route path="accounts" element={<Link to=".."}>
  421. * </Route>
  422. *
  423. * <Route path="/">
  424. * <Route path="accounts">
  425. * <Route element={<AccountsLayout />}> // <-- Does not contribute
  426. * <Route index element={<Link to=".."} /> // <-- Does not contribute
  427. * </Route
  428. * </Route>
  429. * </Route>
  430. */
  431. export declare function getPathContributingMatches<T extends AgnosticRouteMatch = AgnosticRouteMatch>(matches: T[]): T[];
  432. export declare function getResolveToMatches<T extends AgnosticRouteMatch = AgnosticRouteMatch>(matches: T[], v7_relativeSplatPath: boolean): string[];
  433. /**
  434. * @private
  435. */
  436. export declare function resolveTo(toArg: To, routePathnames: string[], locationPathname: string, isPathRelative?: boolean): Path;
  437. /**
  438. * @private
  439. */
  440. export declare function getToPathname(to: To): string | undefined;
  441. /**
  442. * @private
  443. */
  444. export declare const joinPaths: (paths: string[]) => string;
  445. /**
  446. * @private
  447. */
  448. export declare const normalizePathname: (pathname: string) => string;
  449. /**
  450. * @private
  451. */
  452. export declare const normalizeSearch: (search: string) => string;
  453. /**
  454. * @private
  455. */
  456. export declare const normalizeHash: (hash: string) => string;
  457. export type JsonFunction = <Data>(data: Data, init?: number | ResponseInit) => Response;
  458. /**
  459. * This is a shortcut for creating `application/json` responses. Converts `data`
  460. * to JSON and sets the `Content-Type` header.
  461. *
  462. * @deprecated The `json` method is deprecated in favor of returning raw objects.
  463. * This method will be removed in v7.
  464. */
  465. export declare const json: JsonFunction;
  466. export declare class DataWithResponseInit<D> {
  467. type: string;
  468. data: D;
  469. init: ResponseInit | null;
  470. constructor(data: D, init?: ResponseInit);
  471. }
  472. /**
  473. * Create "responses" that contain `status`/`headers` without forcing
  474. * serialization into an actual `Response` - used by Remix single fetch
  475. */
  476. export declare function data<D>(data: D, init?: number | ResponseInit): DataWithResponseInit<D>;
  477. export interface TrackedPromise extends Promise<any> {
  478. _tracked?: boolean;
  479. _data?: any;
  480. _error?: any;
  481. }
  482. export declare class AbortedDeferredError extends Error {
  483. }
  484. export declare class DeferredData {
  485. private pendingKeysSet;
  486. private controller;
  487. private abortPromise;
  488. private unlistenAbortSignal;
  489. private subscribers;
  490. data: Record<string, unknown>;
  491. init?: ResponseInit;
  492. deferredKeys: string[];
  493. constructor(data: Record<string, unknown>, responseInit?: ResponseInit);
  494. private trackPromise;
  495. private onSettle;
  496. private emit;
  497. subscribe(fn: (aborted: boolean, settledKey?: string) => void): () => boolean;
  498. cancel(): void;
  499. resolveData(signal: AbortSignal): Promise<boolean>;
  500. get done(): boolean;
  501. get unwrappedData(): {};
  502. get pendingKeys(): string[];
  503. }
  504. export type DeferFunction = (data: Record<string, unknown>, init?: number | ResponseInit) => DeferredData;
  505. /**
  506. * @deprecated The `defer` method is deprecated in favor of returning raw
  507. * objects. This method will be removed in v7.
  508. */
  509. export declare const defer: DeferFunction;
  510. export type RedirectFunction = (url: string, init?: number | ResponseInit) => Response;
  511. /**
  512. * A redirect response. Sets the status code and the `Location` header.
  513. * Defaults to "302 Found".
  514. */
  515. export declare const redirect: RedirectFunction;
  516. /**
  517. * A redirect response that will force a document reload to the new location.
  518. * Sets the status code and the `Location` header.
  519. * Defaults to "302 Found".
  520. */
  521. export declare const redirectDocument: RedirectFunction;
  522. /**
  523. * A redirect response that will perform a `history.replaceState` instead of a
  524. * `history.pushState` for client-side navigation redirects.
  525. * Sets the status code and the `Location` header.
  526. * Defaults to "302 Found".
  527. */
  528. export declare const replace: RedirectFunction;
  529. export type ErrorResponse = {
  530. status: number;
  531. statusText: string;
  532. data: any;
  533. };
  534. /**
  535. * @private
  536. * Utility class we use to hold auto-unwrapped 4xx/5xx Response bodies
  537. *
  538. * We don't export the class for public use since it's an implementation
  539. * detail, but we export the interface above so folks can build their own
  540. * abstractions around instances via isRouteErrorResponse()
  541. */
  542. export declare class ErrorResponseImpl implements ErrorResponse {
  543. status: number;
  544. statusText: string;
  545. data: any;
  546. private error?;
  547. private internal;
  548. constructor(status: number, statusText: string | undefined, data: any, internal?: boolean);
  549. }
  550. /**
  551. * Check if the given error is an ErrorResponse generated from a 4xx/5xx
  552. * Response thrown from an action/loader
  553. */
  554. export declare function isRouteErrorResponse(error: any): error is ErrorResponse;
  555. export {};