UNPKG

@tanstack/solid-router

Version:

Modern and scalable routing for Solid applications

1 lines • 7.59 kB
{"version":3,"file":"observe.cjs","names":[],"sources":["../../src/observe.ts"],"sourcesContent":["import * as Solid from 'solid-js'\nimport type { NavigationRef } from 'solid-js'\nimport type { AnyRouter, ParsedLocation } from '@tanstack/router-core'\n\n/**\n * What the router says about its navigations to Solid's observe tier\n * (`OBSERVE.attribution.withOrigin`; `OBSERVE` is defined on the dev and\n * observe builds, undefined in production). A navigation is named by the\n * route pattern its pathname matches, so occurrences fold together; `to` and\n * `from` are the location's `href` — path, search and hash, as\n * `@solidjs/router` gives them, in the router's own path space (`name`'s,\n * before a basepath or rewrite is applied).\n */\n\n/** When a navigation was requested, and the interaction it was requested in. */\nexport interface NavigationRequest {\n at: number\n /** Required: `undefined` declares that the request was for no interaction. */\n interaction: NavigationRef['interaction']\n}\n\nconst requests = new WeakMap<AnyRouter, NavigationRequest>()\nconst held = new WeakSet<AnyRouter>()\n\n/**\n * Records the navigation being requested now — a `commitLocation`, or a\n * blocker's `proceed` — for the history change it causes to answer. The\n * history may notify after awaiting its blockers, the interaction gone from\n * the stack by then; a later request replaces this one.\n */\nexport function noteRequest(router: AnyRouter): void {\n const observe = Solid.OBSERVE\n if (observe === undefined) return\n held.delete(router)\n requests.set(router, {\n at: performance.now(),\n interaction: observe.attribution.currentOrigin(),\n })\n}\n\n/** A blocker is deciding on the noted request: keep it past the commit. */\nexport function holdRequest(router: AnyRouter): void {\n if (requests.has(router)) held.add(router)\n}\n\n/**\n * The commit that noted the request has returned. Without a blocker\n * holding it, the history has notified by then — or never will: the same\n * location reloads without a history change.\n */\nexport function releaseRequest(router: AnyRouter): void {\n if (!held.has(router)) requests.delete(router)\n}\n\n/** Forgets the noted request: a blocker stopped the navigation it made. */\nexport function dropRequest(router: AnyRouter): void {\n held.delete(router)\n requests.delete(router)\n}\n\n/** The request noted for the history change being notified, if any. */\nexport function takeRequest(router: AnyRouter): NavigationRequest | undefined {\n const request = requests.get(router)\n dropRequest(router)\n return request\n}\n\n/**\n * The route `pathname` matches — its `fullPath` (`/users/$id`) and the raw\n * params it bound — or, when no route matches it (a not-found, by the rule\n * `matchRoutes` applies), the pathname itself and no params.\n */\nfunction describeRoute(\n router: AnyRouter,\n pathname: string,\n): Pick<NavigationRef, 'name' | 'params'> {\n const [, rawParams, route] = router.getMatchedRoutes(pathname)\n if (!route || (route.path !== '/' && rawParams['**']))\n return { name: pathname }\n const { '**': _, ...params } = rawParams\n return Object.keys(params).length\n ? { name: route.fullPath, params }\n : { name: route.fullPath }\n}\n\n/** A destination a pending navigation was sent on from, and when. */\nexport interface NavigationHop {\n location: ParsedLocation\n at: number\n}\n\n/**\n * The navigation a match publish lands: the latest location, from `from`\n * (the location shown, or the arrival while the first page is still\n * loading). Nothing when the publish reloads the location it came from.\n * `request` dates it from the request and joins it to the interaction that\n * asked, both gone by the time the loaders resolve and the publish runs; the\n * key's presence declares the interaction, `undefined` included.\n *\n * One ref per destination, to be opened nested, as `@solidjs/router`\n * declares a navigation sent elsewhere while pending (a redirect, or\n * another navigation): the first names the destination requested, and each\n * `hops` entry is abandoned by a `redirect: n` ref the engine folds onto it,\n * keeping the request's time and interaction and listing the abandoned\n * destinations in `redirects`.\n */\nexport function describeNavigation(\n router: AnyRouter,\n request: NavigationRequest,\n from: ParsedLocation | undefined,\n hops: ReadonlyArray<NavigationHop>,\n): Array<NavigationRef> | undefined {\n const to = router.latestLocation\n if (!from || (from.href === to.href && !hops.length)) return\n const destinations = [...hops.map((hop) => hop.location), to]\n return destinations.map((location, index) => {\n const ref: NavigationRef = {\n kind: 'navigation',\n ...describeRoute(router, location.pathname),\n to: location.href,\n }\n if (index) {\n ref.redirect = index\n ref.at = hops[index - 1]!.at\n } else {\n ref.from = from.href\n ref.at = request.at\n ref.interaction = request.interaction\n }\n return ref\n })\n}\n\n/**\n * The route the document arrived on, declared around the work that\n * establishes the router's initial match, since a fresh document has no\n * publish to wrap. On the client the engine opens it at the time origin and\n * settles it as that work returns (the first `\"navigation\"` record,\n * `initial: true`); on the server the same call names the request's\n * `\"render\"` record (`RenderEvent.route`). The fields are getters of\n * `location`, read at settle: the canonical location the client committed,\n * or the one a server load resolved.\n */\nexport function describeInitial(\n router: AnyRouter,\n location: () => ParsedLocation,\n): NavigationRef {\n return {\n kind: 'navigation',\n initial: true,\n get to() {\n return location().href\n },\n get name() {\n return describeRoute(router, location().pathname).name\n },\n get params() {\n return describeRoute(router, location().pathname).params\n },\n }\n}\n"],"mappings":";;;;AAqBA,IAAM,2BAAW,IAAI,QAAsC;AAC3D,IAAM,uBAAO,IAAI,QAAmB;;;;;;;AAQpC,SAAgB,YAAY,QAAyB;CACnD,MAAM,UAAU,SAAM;CACtB,IAAI,YAAY,KAAA,GAAW;CAC3B,KAAK,OAAO,MAAM;CAClB,SAAS,IAAI,QAAQ;EACnB,IAAI,YAAY,IAAI;EACpB,aAAa,QAAQ,YAAY,cAAc;CACjD,CAAC;AACH;;AAGA,SAAgB,YAAY,QAAyB;CACnD,IAAI,SAAS,IAAI,MAAM,GAAG,KAAK,IAAI,MAAM;AAC3C;;;;;;AAOA,SAAgB,eAAe,QAAyB;CACtD,IAAI,CAAC,KAAK,IAAI,MAAM,GAAG,SAAS,OAAO,MAAM;AAC/C;;AAGA,SAAgB,YAAY,QAAyB;CACnD,KAAK,OAAO,MAAM;CAClB,SAAS,OAAO,MAAM;AACxB;;AAGA,SAAgB,YAAY,QAAkD;CAC5E,MAAM,UAAU,SAAS,IAAI,MAAM;CACnC,YAAY,MAAM;CAClB,OAAO;AACT;;;;;;AAOA,SAAS,cACP,QACA,UACwC;CACxC,MAAM,GAAG,WAAW,SAAS,OAAO,iBAAiB,QAAQ;CAC7D,IAAI,CAAC,SAAU,MAAM,SAAS,OAAO,UAAU,OAC7C,OAAO,EAAE,MAAM,SAAS;CAC1B,MAAM,EAAE,MAAM,GAAG,GAAG,WAAW;CAC/B,OAAO,OAAO,KAAK,MAAM,EAAE,SACvB;EAAE,MAAM,MAAM;EAAU;CAAO,IAC/B,EAAE,MAAM,MAAM,SAAS;AAC7B;;;;;;;;;;;;;;;;AAuBA,SAAgB,mBACd,QACA,SACA,MACA,MACkC;CAClC,MAAM,KAAK,OAAO;CAClB,IAAI,CAAC,QAAS,KAAK,SAAS,GAAG,QAAQ,CAAC,KAAK,QAAS;CAEtD,OAAO,CADe,GAAG,KAAK,KAAK,QAAQ,IAAI,QAAQ,GAAG,EACnD,EAAa,KAAK,UAAU,UAAU;EAC3C,MAAM,MAAqB;GACzB,MAAM;GACN,GAAG,cAAc,QAAQ,SAAS,QAAQ;GAC1C,IAAI,SAAS;EACf;EACA,IAAI,OAAO;GACT,IAAI,WAAW;GACf,IAAI,KAAK,KAAK,QAAQ,GAAI;EAC5B,OAAO;GACL,IAAI,OAAO,KAAK;GAChB,IAAI,KAAK,QAAQ;GACjB,IAAI,cAAc,QAAQ;EAC5B;EACA,OAAO;CACT,CAAC;AACH;;;;;;;;;;;AAYA,SAAgB,gBACd,QACA,UACe;CACf,OAAO;EACL,MAAM;EACN,SAAS;EACT,IAAI,KAAK;GACP,OAAO,SAAS,EAAE;EACpB;EACA,IAAI,OAAO;GACT,OAAO,cAAc,QAAQ,SAAS,EAAE,QAAQ,EAAE;EACpD;EACA,IAAI,SAAS;GACX,OAAO,cAAc,QAAQ,SAAS,EAAE,QAAQ,EAAE;EACpD;CACF;AACF"}