devtools-BLCumUwL.mjs 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218
  1. /*!
  2. * vue-router v4.6.3
  3. * (c) 2025 Eduardo San Martin Morote
  4. * @license MIT
  5. */
  6. import { getCurrentInstance, inject, onActivated, onDeactivated, onUnmounted, watch } from "vue";
  7. import { setupDevtoolsPlugin } from "@vue/devtools-api";
  8. //#region src/utils/env.ts
  9. const isBrowser = typeof document !== "undefined";
  10. //#endregion
  11. //#region src/utils/index.ts
  12. /**
  13. * Identity function that returns the value as is.
  14. *
  15. * @param v - the value to return
  16. *
  17. * @internal
  18. */
  19. const identityFn = (v) => v;
  20. /**
  21. * Allows differentiating lazy components from functional components and vue-class-component
  22. * @internal
  23. *
  24. * @param component
  25. */
  26. function isRouteComponent(component) {
  27. return typeof component === "object" || "displayName" in component || "props" in component || "__vccOpts" in component;
  28. }
  29. function isESModule(obj) {
  30. return obj.__esModule || obj[Symbol.toStringTag] === "Module" || obj.default && isRouteComponent(obj.default);
  31. }
  32. const assign = Object.assign;
  33. function applyToParams(fn, params) {
  34. const newParams = {};
  35. for (const key in params) {
  36. const value = params[key];
  37. newParams[key] = isArray(value) ? value.map(fn) : fn(value);
  38. }
  39. return newParams;
  40. }
  41. const noop = () => {};
  42. /**
  43. * Typesafe alternative to Array.isArray
  44. * https://github.com/microsoft/TypeScript/pull/48228
  45. */
  46. const isArray = Array.isArray;
  47. function mergeOptions(defaults, partialOptions) {
  48. const options = {};
  49. for (const key in defaults) options[key] = key in partialOptions ? partialOptions[key] : defaults[key];
  50. return options;
  51. }
  52. //#endregion
  53. //#region src/warning.ts
  54. function warn$1(msg) {
  55. const args = Array.from(arguments).slice(1);
  56. console.warn.apply(console, ["[Vue Router warn]: " + msg].concat(args));
  57. }
  58. //#endregion
  59. //#region src/encoding.ts
  60. /**
  61. * Encoding Rules (␣ = Space)
  62. * - Path: ␣ " < > # ? { }
  63. * - Query: ␣ " < > # & =
  64. * - Hash: ␣ " < > `
  65. *
  66. * On top of that, the RFC3986 (https://tools.ietf.org/html/rfc3986#section-2.2)
  67. * defines some extra characters to be encoded. Most browsers do not encode them
  68. * in encodeURI https://github.com/whatwg/url/issues/369, so it may be safer to
  69. * also encode `!'()*`. Leaving un-encoded only ASCII alphanumeric(`a-zA-Z0-9`)
  70. * plus `-._~`. This extra safety should be applied to query by patching the
  71. * string returned by encodeURIComponent encodeURI also encodes `[\]^`. `\`
  72. * should be encoded to avoid ambiguity. Browsers (IE, FF, C) transform a `\`
  73. * into a `/` if directly typed in. The _backtick_ (`````) should also be
  74. * encoded everywhere because some browsers like FF encode it when directly
  75. * written while others don't. Safari and IE don't encode ``"<>{}``` in hash.
  76. */
  77. const HASH_RE = /#/g;
  78. const AMPERSAND_RE = /&/g;
  79. const SLASH_RE = /\//g;
  80. const EQUAL_RE = /=/g;
  81. const IM_RE = /\?/g;
  82. const PLUS_RE = /\+/g;
  83. /**
  84. * NOTE: It's not clear to me if we should encode the + symbol in queries, it
  85. * seems to be less flexible than not doing so and I can't find out the legacy
  86. * systems requiring this for regular requests like text/html. In the standard,
  87. * the encoding of the plus character is only mentioned for
  88. * application/x-www-form-urlencoded
  89. * (https://url.spec.whatwg.org/#urlencoded-parsing) and most browsers seems lo
  90. * leave the plus character as is in queries. To be more flexible, we allow the
  91. * plus character on the query, but it can also be manually encoded by the user.
  92. *
  93. * Resources:
  94. * - https://url.spec.whatwg.org/#urlencoded-parsing
  95. * - https://stackoverflow.com/questions/1634271/url-encoding-the-space-character-or-20
  96. */
  97. const ENC_BRACKET_OPEN_RE = /%5B/g;
  98. const ENC_BRACKET_CLOSE_RE = /%5D/g;
  99. const ENC_CARET_RE = /%5E/g;
  100. const ENC_BACKTICK_RE = /%60/g;
  101. const ENC_CURLY_OPEN_RE = /%7B/g;
  102. const ENC_PIPE_RE = /%7C/g;
  103. const ENC_CURLY_CLOSE_RE = /%7D/g;
  104. const ENC_SPACE_RE = /%20/g;
  105. /**
  106. * Encode characters that need to be encoded on the path, search and hash
  107. * sections of the URL.
  108. *
  109. * @internal
  110. * @param text - string to encode
  111. * @returns encoded string
  112. */
  113. function commonEncode(text) {
  114. return text == null ? "" : encodeURI("" + text).replace(ENC_PIPE_RE, "|").replace(ENC_BRACKET_OPEN_RE, "[").replace(ENC_BRACKET_CLOSE_RE, "]");
  115. }
  116. /**
  117. * Encode characters that need to be encoded on the hash section of the URL.
  118. *
  119. * @param text - string to encode
  120. * @returns encoded string
  121. */
  122. function encodeHash(text) {
  123. return commonEncode(text).replace(ENC_CURLY_OPEN_RE, "{").replace(ENC_CURLY_CLOSE_RE, "}").replace(ENC_CARET_RE, "^");
  124. }
  125. /**
  126. * Encode characters that need to be encoded query values on the query
  127. * section of the URL.
  128. *
  129. * @param text - string to encode
  130. * @returns encoded string
  131. */
  132. function encodeQueryValue(text) {
  133. return commonEncode(text).replace(PLUS_RE, "%2B").replace(ENC_SPACE_RE, "+").replace(HASH_RE, "%23").replace(AMPERSAND_RE, "%26").replace(ENC_BACKTICK_RE, "`").replace(ENC_CURLY_OPEN_RE, "{").replace(ENC_CURLY_CLOSE_RE, "}").replace(ENC_CARET_RE, "^");
  134. }
  135. /**
  136. * Like `encodeQueryValue` but also encodes the `=` character.
  137. *
  138. * @param text - string to encode
  139. */
  140. function encodeQueryKey(text) {
  141. return encodeQueryValue(text).replace(EQUAL_RE, "%3D");
  142. }
  143. /**
  144. * Encode characters that need to be encoded on the path section of the URL.
  145. *
  146. * @param text - string to encode
  147. * @returns encoded string
  148. */
  149. function encodePath(text) {
  150. return commonEncode(text).replace(HASH_RE, "%23").replace(IM_RE, "%3F");
  151. }
  152. /**
  153. * Encode characters that need to be encoded on the path section of the URL as a
  154. * param. This function encodes everything {@link encodePath} does plus the
  155. * slash (`/`) character. If `text` is `null` or `undefined`, returns an empty
  156. * string instead.
  157. *
  158. * @param text - string to encode
  159. * @returns encoded string
  160. */
  161. function encodeParam(text) {
  162. return encodePath(text).replace(SLASH_RE, "%2F");
  163. }
  164. function decode(text) {
  165. if (text == null) return null;
  166. try {
  167. return decodeURIComponent("" + text);
  168. } catch (err) {
  169. process.env.NODE_ENV !== "production" && warn$1(`Error decoding "${text}". Using original value`);
  170. }
  171. return "" + text;
  172. }
  173. //#endregion
  174. //#region src/location.ts
  175. const TRAILING_SLASH_RE = /\/$/;
  176. const removeTrailingSlash = (path) => path.replace(TRAILING_SLASH_RE, "");
  177. /**
  178. * Transforms a URI into a normalized history location
  179. *
  180. * @param parseQuery
  181. * @param location - URI to normalize
  182. * @param currentLocation - current absolute location. Allows resolving relative
  183. * paths. Must start with `/`. Defaults to `/`
  184. * @returns a normalized history location
  185. */
  186. function parseURL(parseQuery$1, location, currentLocation = "/") {
  187. let path, query = {}, searchString = "", hash = "";
  188. const hashPos = location.indexOf("#");
  189. let searchPos = location.indexOf("?");
  190. searchPos = hashPos >= 0 && searchPos > hashPos ? -1 : searchPos;
  191. if (searchPos >= 0) {
  192. path = location.slice(0, searchPos);
  193. searchString = location.slice(searchPos, hashPos > 0 ? hashPos : location.length);
  194. query = parseQuery$1(searchString.slice(1));
  195. }
  196. if (hashPos >= 0) {
  197. path = path || location.slice(0, hashPos);
  198. hash = location.slice(hashPos, location.length);
  199. }
  200. path = resolveRelativePath(path != null ? path : location, currentLocation);
  201. return {
  202. fullPath: path + searchString + hash,
  203. path,
  204. query,
  205. hash: decode(hash)
  206. };
  207. }
  208. function NEW_stringifyURL(stringifyQuery$1, path, query, hash = "") {
  209. const searchText = stringifyQuery$1(query);
  210. return path + (searchText && "?") + searchText + encodeHash(hash);
  211. }
  212. /**
  213. * Stringifies a URL object
  214. *
  215. * @param stringifyQuery
  216. * @param location
  217. */
  218. function stringifyURL(stringifyQuery$1, location) {
  219. const query = location.query ? stringifyQuery$1(location.query) : "";
  220. return location.path + (query && "?") + query + (location.hash || "");
  221. }
  222. /**
  223. * Strips off the base from the beginning of a location.pathname in a non-case-sensitive way.
  224. *
  225. * @param pathname - location.pathname
  226. * @param base - base to strip off
  227. */
  228. function stripBase(pathname, base) {
  229. if (!base || !pathname.toLowerCase().startsWith(base.toLowerCase())) return pathname;
  230. return pathname.slice(base.length) || "/";
  231. }
  232. /**
  233. * Checks if two RouteLocation are equal. This means that both locations are
  234. * pointing towards the same {@link RouteRecord} and that all `params`, `query`
  235. * parameters and `hash` are the same
  236. *
  237. * @param stringifyQuery - A function that takes a query object of type LocationQueryRaw and returns a string representation of it.
  238. * @param a - first {@link RouteLocation}
  239. * @param b - second {@link RouteLocation}
  240. */
  241. function isSameRouteLocation(stringifyQuery$1, a, b) {
  242. const aLastIndex = a.matched.length - 1;
  243. const bLastIndex = b.matched.length - 1;
  244. return aLastIndex > -1 && aLastIndex === bLastIndex && isSameRouteRecord(a.matched[aLastIndex], b.matched[bLastIndex]) && isSameRouteLocationParams(a.params, b.params) && stringifyQuery$1(a.query) === stringifyQuery$1(b.query) && a.hash === b.hash;
  245. }
  246. /**
  247. * Check if two `RouteRecords` are equal. Takes into account aliases: they are
  248. * considered equal to the `RouteRecord` they are aliasing.
  249. *
  250. * @param a - first {@link RouteRecord}
  251. * @param b - second {@link RouteRecord}
  252. */
  253. function isSameRouteRecord(a, b) {
  254. return (a.aliasOf || a) === (b.aliasOf || b);
  255. }
  256. function isSameRouteLocationParams(a, b) {
  257. if (Object.keys(a).length !== Object.keys(b).length) return false;
  258. for (const key in a) if (!isSameRouteLocationParamsValue(a[key], b[key])) return false;
  259. return true;
  260. }
  261. function isSameRouteLocationParamsValue(a, b) {
  262. return isArray(a) ? isEquivalentArray(a, b) : isArray(b) ? isEquivalentArray(b, a) : a === b;
  263. }
  264. /**
  265. * Check if two arrays are the same or if an array with one single entry is the
  266. * same as another primitive value. Used to check query and parameters
  267. *
  268. * @param a - array of values
  269. * @param b - array of values or a single value
  270. */
  271. function isEquivalentArray(a, b) {
  272. return isArray(b) ? a.length === b.length && a.every((value, i) => value === b[i]) : a.length === 1 && a[0] === b;
  273. }
  274. /**
  275. * Resolves a relative path that starts with `.`.
  276. *
  277. * @param to - path location we are resolving
  278. * @param from - currentLocation.path, should start with `/`
  279. */
  280. function resolveRelativePath(to, from) {
  281. if (to.startsWith("/")) return to;
  282. if (process.env.NODE_ENV !== "production" && !from.startsWith("/")) {
  283. warn$1(`Cannot resolve a relative location without an absolute path. Trying to resolve "${to}" from "${from}". It should look like "/${from}".`);
  284. return to;
  285. }
  286. if (!to) return from;
  287. const fromSegments = from.split("/");
  288. const toSegments = to.split("/");
  289. const lastToSegment = toSegments[toSegments.length - 1];
  290. if (lastToSegment === ".." || lastToSegment === ".") toSegments.push("");
  291. let position = fromSegments.length - 1;
  292. let toPosition;
  293. let segment;
  294. for (toPosition = 0; toPosition < toSegments.length; toPosition++) {
  295. segment = toSegments[toPosition];
  296. if (segment === ".") continue;
  297. if (segment === "..") {
  298. if (position > 1) position--;
  299. } else break;
  300. }
  301. return fromSegments.slice(0, position).join("/") + "/" + toSegments.slice(toPosition).join("/");
  302. }
  303. /**
  304. * Initial route location where the router is. Can be used in navigation guards
  305. * to differentiate the initial navigation.
  306. *
  307. * @example
  308. * ```js
  309. * import { START_LOCATION } from 'vue-router'
  310. *
  311. * router.beforeEach((to, from) => {
  312. * if (from === START_LOCATION) {
  313. * // initial navigation
  314. * }
  315. * })
  316. * ```
  317. */
  318. const START_LOCATION_NORMALIZED = {
  319. path: "/",
  320. name: void 0,
  321. params: {},
  322. query: {},
  323. hash: "",
  324. fullPath: "/",
  325. matched: [],
  326. meta: {},
  327. redirectedFrom: void 0
  328. };
  329. //#endregion
  330. //#region src/history/common.ts
  331. let NavigationType = /* @__PURE__ */ function(NavigationType$1) {
  332. NavigationType$1["pop"] = "pop";
  333. NavigationType$1["push"] = "push";
  334. return NavigationType$1;
  335. }({});
  336. let NavigationDirection = /* @__PURE__ */ function(NavigationDirection$1) {
  337. NavigationDirection$1["back"] = "back";
  338. NavigationDirection$1["forward"] = "forward";
  339. NavigationDirection$1["unknown"] = "";
  340. return NavigationDirection$1;
  341. }({});
  342. /**
  343. * Starting location for Histories
  344. */
  345. const START = "";
  346. /**
  347. * Normalizes a base by removing any trailing slash and reading the base tag if
  348. * present.
  349. *
  350. * @param base - base to normalize
  351. */
  352. function normalizeBase(base) {
  353. if (!base) if (isBrowser) {
  354. const baseEl = document.querySelector("base");
  355. base = baseEl && baseEl.getAttribute("href") || "/";
  356. base = base.replace(/^\w+:\/\/[^\/]+/, "");
  357. } else base = "/";
  358. if (base[0] !== "/" && base[0] !== "#") base = "/" + base;
  359. return removeTrailingSlash(base);
  360. }
  361. const BEFORE_HASH_RE = /^[^#]+#/;
  362. function createHref(base, location) {
  363. return base.replace(BEFORE_HASH_RE, "#") + location;
  364. }
  365. //#endregion
  366. //#region src/scrollBehavior.ts
  367. function getElementPosition(el, offset) {
  368. const docRect = document.documentElement.getBoundingClientRect();
  369. const elRect = el.getBoundingClientRect();
  370. return {
  371. behavior: offset.behavior,
  372. left: elRect.left - docRect.left - (offset.left || 0),
  373. top: elRect.top - docRect.top - (offset.top || 0)
  374. };
  375. }
  376. const computeScrollPosition = () => ({
  377. left: window.scrollX,
  378. top: window.scrollY
  379. });
  380. function scrollToPosition(position) {
  381. let scrollToOptions;
  382. if ("el" in position) {
  383. const positionEl = position.el;
  384. const isIdSelector = typeof positionEl === "string" && positionEl.startsWith("#");
  385. /**
  386. * `id`s can accept pretty much any characters, including CSS combinators
  387. * like `>` or `~`. It's still possible to retrieve elements using
  388. * `document.getElementById('~')` but it needs to be escaped when using
  389. * `document.querySelector('#\\~')` for it to be valid. The only
  390. * requirements for `id`s are them to be unique on the page and to not be
  391. * empty (`id=""`). Because of that, when passing an id selector, it should
  392. * be properly escaped for it to work with `querySelector`. We could check
  393. * for the id selector to be simple (no CSS combinators `+ >~`) but that
  394. * would make things inconsistent since they are valid characters for an
  395. * `id` but would need to be escaped when using `querySelector`, breaking
  396. * their usage and ending up in no selector returned. Selectors need to be
  397. * escaped:
  398. *
  399. * - `#1-thing` becomes `#\31 -thing`
  400. * - `#with~symbols` becomes `#with\\~symbols`
  401. *
  402. * - More information about the topic can be found at
  403. * https://mathiasbynens.be/notes/html5-id-class.
  404. * - Practical example: https://mathiasbynens.be/demo/html5-id
  405. */
  406. if (process.env.NODE_ENV !== "production" && typeof position.el === "string") {
  407. if (!isIdSelector || !document.getElementById(position.el.slice(1))) try {
  408. const foundEl = document.querySelector(position.el);
  409. if (isIdSelector && foundEl) {
  410. warn$1(`The selector "${position.el}" should be passed as "el: document.querySelector('${position.el}')" because it starts with "#".`);
  411. return;
  412. }
  413. } catch (err) {
  414. warn$1(`The selector "${position.el}" is invalid. If you are using an id selector, make sure to escape it. You can find more information about escaping characters in selectors at https://mathiasbynens.be/notes/css-escapes or use CSS.escape (https://developer.mozilla.org/en-US/docs/Web/API/CSS/escape).`);
  415. return;
  416. }
  417. }
  418. const el = typeof positionEl === "string" ? isIdSelector ? document.getElementById(positionEl.slice(1)) : document.querySelector(positionEl) : positionEl;
  419. if (!el) {
  420. process.env.NODE_ENV !== "production" && warn$1(`Couldn't find element using selector "${position.el}" returned by scrollBehavior.`);
  421. return;
  422. }
  423. scrollToOptions = getElementPosition(el, position);
  424. } else scrollToOptions = position;
  425. if ("scrollBehavior" in document.documentElement.style) window.scrollTo(scrollToOptions);
  426. else window.scrollTo(scrollToOptions.left != null ? scrollToOptions.left : window.scrollX, scrollToOptions.top != null ? scrollToOptions.top : window.scrollY);
  427. }
  428. function getScrollKey(path, delta) {
  429. return (history.state ? history.state.position - delta : -1) + path;
  430. }
  431. const scrollPositions = /* @__PURE__ */ new Map();
  432. function saveScrollPosition(key, scrollPosition) {
  433. scrollPositions.set(key, scrollPosition);
  434. }
  435. function getSavedScrollPosition(key) {
  436. const scroll = scrollPositions.get(key);
  437. scrollPositions.delete(key);
  438. return scroll;
  439. }
  440. /**
  441. * ScrollBehavior instance used by the router to compute and restore the scroll
  442. * position when navigating.
  443. */
  444. //#endregion
  445. //#region src/types/typeGuards.ts
  446. function isRouteLocation(route) {
  447. return typeof route === "string" || route && typeof route === "object";
  448. }
  449. function isRouteName(name) {
  450. return typeof name === "string" || typeof name === "symbol";
  451. }
  452. //#endregion
  453. //#region src/errors.ts
  454. /**
  455. * Flags so we can combine them when checking for multiple errors. This is the internal version of
  456. * {@link NavigationFailureType}.
  457. *
  458. * @internal
  459. */
  460. let ErrorTypes = /* @__PURE__ */ function(ErrorTypes$1) {
  461. ErrorTypes$1[ErrorTypes$1["MATCHER_NOT_FOUND"] = 1] = "MATCHER_NOT_FOUND";
  462. ErrorTypes$1[ErrorTypes$1["NAVIGATION_GUARD_REDIRECT"] = 2] = "NAVIGATION_GUARD_REDIRECT";
  463. ErrorTypes$1[ErrorTypes$1["NAVIGATION_ABORTED"] = 4] = "NAVIGATION_ABORTED";
  464. ErrorTypes$1[ErrorTypes$1["NAVIGATION_CANCELLED"] = 8] = "NAVIGATION_CANCELLED";
  465. ErrorTypes$1[ErrorTypes$1["NAVIGATION_DUPLICATED"] = 16] = "NAVIGATION_DUPLICATED";
  466. return ErrorTypes$1;
  467. }({});
  468. const NavigationFailureSymbol = Symbol(process.env.NODE_ENV !== "production" ? "navigation failure" : "");
  469. /**
  470. * Enumeration with all possible types for navigation failures. Can be passed to
  471. * {@link isNavigationFailure} to check for specific failures.
  472. */
  473. let NavigationFailureType = /* @__PURE__ */ function(NavigationFailureType$1) {
  474. /**
  475. * An aborted navigation is a navigation that failed because a navigation
  476. * guard returned `false` or called `next(false)`
  477. */
  478. NavigationFailureType$1[NavigationFailureType$1["aborted"] = 4] = "aborted";
  479. /**
  480. * A cancelled navigation is a navigation that failed because a more recent
  481. * navigation finished started (not necessarily finished).
  482. */
  483. NavigationFailureType$1[NavigationFailureType$1["cancelled"] = 8] = "cancelled";
  484. /**
  485. * A duplicated navigation is a navigation that failed because it was
  486. * initiated while already being at the exact same location.
  487. */
  488. NavigationFailureType$1[NavigationFailureType$1["duplicated"] = 16] = "duplicated";
  489. return NavigationFailureType$1;
  490. }({});
  491. const ErrorTypeMessages = {
  492. [ErrorTypes.MATCHER_NOT_FOUND]({ location, currentLocation }) {
  493. return `No match for\n ${JSON.stringify(location)}${currentLocation ? "\nwhile being at\n" + JSON.stringify(currentLocation) : ""}`;
  494. },
  495. [ErrorTypes.NAVIGATION_GUARD_REDIRECT]({ from, to }) {
  496. return `Redirected from "${from.fullPath}" to "${stringifyRoute(to)}" via a navigation guard.`;
  497. },
  498. [ErrorTypes.NAVIGATION_ABORTED]({ from, to }) {
  499. return `Navigation aborted from "${from.fullPath}" to "${to.fullPath}" via a navigation guard.`;
  500. },
  501. [ErrorTypes.NAVIGATION_CANCELLED]({ from, to }) {
  502. return `Navigation cancelled from "${from.fullPath}" to "${to.fullPath}" with a new navigation.`;
  503. },
  504. [ErrorTypes.NAVIGATION_DUPLICATED]({ from, to }) {
  505. return `Avoided redundant navigation to current location: "${from.fullPath}".`;
  506. }
  507. };
  508. /**
  509. * Creates a typed NavigationFailure object.
  510. * @internal
  511. * @param type - NavigationFailureType
  512. * @param params - { from, to }
  513. */
  514. function createRouterError(type, params) {
  515. if (process.env.NODE_ENV !== "production" || false) return assign(new Error(ErrorTypeMessages[type](params)), {
  516. type,
  517. [NavigationFailureSymbol]: true
  518. }, params);
  519. else return assign(/* @__PURE__ */ new Error(), {
  520. type,
  521. [NavigationFailureSymbol]: true
  522. }, params);
  523. }
  524. function isNavigationFailure(error, type) {
  525. return error instanceof Error && NavigationFailureSymbol in error && (type == null || !!(error.type & type));
  526. }
  527. const propertiesToLog = [
  528. "params",
  529. "query",
  530. "hash"
  531. ];
  532. function stringifyRoute(to) {
  533. if (typeof to === "string") return to;
  534. if (to.path != null) return to.path;
  535. const location = {};
  536. for (const key of propertiesToLog) if (key in to) location[key] = to[key];
  537. return JSON.stringify(location, null, 2);
  538. }
  539. //#endregion
  540. //#region src/query.ts
  541. /**
  542. * Transforms a queryString into a {@link LocationQuery} object. Accept both, a
  543. * version with the leading `?` and without Should work as URLSearchParams
  544. * @internal
  545. *
  546. * @param search - search string to parse
  547. * @returns a query object
  548. */
  549. function parseQuery(search) {
  550. const query = {};
  551. if (search === "" || search === "?") return query;
  552. const searchParams = (search[0] === "?" ? search.slice(1) : search).split("&");
  553. for (let i = 0; i < searchParams.length; ++i) {
  554. const searchParam = searchParams[i].replace(PLUS_RE, " ");
  555. const eqPos = searchParam.indexOf("=");
  556. const key = decode(eqPos < 0 ? searchParam : searchParam.slice(0, eqPos));
  557. const value = eqPos < 0 ? null : decode(searchParam.slice(eqPos + 1));
  558. if (key in query) {
  559. let currentValue = query[key];
  560. if (!isArray(currentValue)) currentValue = query[key] = [currentValue];
  561. currentValue.push(value);
  562. } else query[key] = value;
  563. }
  564. return query;
  565. }
  566. /**
  567. * Stringifies a {@link LocationQueryRaw} object. Like `URLSearchParams`, it
  568. * doesn't prepend a `?`
  569. *
  570. * @internal
  571. *
  572. * @param query - query object to stringify
  573. * @returns string version of the query without the leading `?`
  574. */
  575. function stringifyQuery(query) {
  576. let search = "";
  577. for (let key in query) {
  578. const value = query[key];
  579. key = encodeQueryKey(key);
  580. if (value == null) {
  581. if (value !== void 0) search += (search.length ? "&" : "") + key;
  582. continue;
  583. }
  584. (isArray(value) ? value.map((v) => v && encodeQueryValue(v)) : [value && encodeQueryValue(value)]).forEach((value$1) => {
  585. if (value$1 !== void 0) {
  586. search += (search.length ? "&" : "") + key;
  587. if (value$1 != null) search += "=" + value$1;
  588. }
  589. });
  590. }
  591. return search;
  592. }
  593. /**
  594. * Transforms a {@link LocationQueryRaw} into a {@link LocationQuery} by casting
  595. * numbers into strings, removing keys with an undefined value and replacing
  596. * undefined with null in arrays
  597. *
  598. * @param query - query object to normalize
  599. * @returns a normalized query object
  600. */
  601. function normalizeQuery(query) {
  602. const normalizedQuery = {};
  603. for (const key in query) {
  604. const value = query[key];
  605. if (value !== void 0) normalizedQuery[key] = isArray(value) ? value.map((v) => v == null ? null : "" + v) : value == null ? value : "" + value;
  606. }
  607. return normalizedQuery;
  608. }
  609. //#endregion
  610. //#region src/injectionSymbols.ts
  611. /**
  612. * RouteRecord being rendered by the closest ancestor Router View. Used for
  613. * `onBeforeRouteUpdate` and `onBeforeRouteLeave`. rvlm stands for Router View
  614. * Location Matched
  615. *
  616. * @internal
  617. */
  618. const matchedRouteKey = Symbol(process.env.NODE_ENV !== "production" ? "router view location matched" : "");
  619. /**
  620. * Allows overriding the router view depth to control which component in
  621. * `matched` is rendered. rvd stands for Router View Depth
  622. *
  623. * @internal
  624. */
  625. const viewDepthKey = Symbol(process.env.NODE_ENV !== "production" ? "router view depth" : "");
  626. /**
  627. * Allows overriding the router instance returned by `useRouter` in tests. r
  628. * stands for router
  629. *
  630. * @internal
  631. */
  632. const routerKey = Symbol(process.env.NODE_ENV !== "production" ? "router" : "");
  633. /**
  634. * Allows overriding the current route returned by `useRoute` in tests. rl
  635. * stands for route location
  636. *
  637. * @internal
  638. */
  639. const routeLocationKey = Symbol(process.env.NODE_ENV !== "production" ? "route location" : "");
  640. /**
  641. * Allows overriding the current route used by router-view. Internally this is
  642. * used when the `route` prop is passed.
  643. *
  644. * @internal
  645. */
  646. const routerViewLocationKey = Symbol(process.env.NODE_ENV !== "production" ? "router view location" : "");
  647. //#endregion
  648. //#region src/utils/callbacks.ts
  649. /**
  650. * Create a list of callbacks that can be reset. Used to create before and after navigation guards list
  651. */
  652. function useCallbacks() {
  653. let handlers = [];
  654. function add(handler) {
  655. handlers.push(handler);
  656. return () => {
  657. const i = handlers.indexOf(handler);
  658. if (i > -1) handlers.splice(i, 1);
  659. };
  660. }
  661. function reset() {
  662. handlers = [];
  663. }
  664. return {
  665. add,
  666. list: () => handlers.slice(),
  667. reset
  668. };
  669. }
  670. //#endregion
  671. //#region src/navigationGuards.ts
  672. function registerGuard(record, name, guard) {
  673. const removeFromList = () => {
  674. record[name].delete(guard);
  675. };
  676. onUnmounted(removeFromList);
  677. onDeactivated(removeFromList);
  678. onActivated(() => {
  679. record[name].add(guard);
  680. });
  681. record[name].add(guard);
  682. }
  683. /**
  684. * Add a navigation guard that triggers whenever the component for the current
  685. * location is about to be left. Similar to {@link beforeRouteLeave} but can be
  686. * used in any component. The guard is removed when the component is unmounted.
  687. *
  688. * @param leaveGuard - {@link NavigationGuard}
  689. */
  690. function onBeforeRouteLeave(leaveGuard) {
  691. if (process.env.NODE_ENV !== "production" && !getCurrentInstance()) {
  692. warn$1("getCurrentInstance() returned null. onBeforeRouteLeave() must be called at the top of a setup function");
  693. return;
  694. }
  695. const activeRecord = inject(matchedRouteKey, {}).value;
  696. if (!activeRecord) {
  697. process.env.NODE_ENV !== "production" && warn$1("No active route record was found when calling `onBeforeRouteLeave()`. Make sure you call this function inside a component child of <router-view>. Maybe you called it inside of App.vue?");
  698. return;
  699. }
  700. registerGuard(activeRecord, "leaveGuards", leaveGuard);
  701. }
  702. /**
  703. * Add a navigation guard that triggers whenever the current location is about
  704. * to be updated. Similar to {@link beforeRouteUpdate} but can be used in any
  705. * component. The guard is removed when the component is unmounted.
  706. *
  707. * @param updateGuard - {@link NavigationGuard}
  708. */
  709. function onBeforeRouteUpdate(updateGuard) {
  710. if (process.env.NODE_ENV !== "production" && !getCurrentInstance()) {
  711. warn$1("getCurrentInstance() returned null. onBeforeRouteUpdate() must be called at the top of a setup function");
  712. return;
  713. }
  714. const activeRecord = inject(matchedRouteKey, {}).value;
  715. if (!activeRecord) {
  716. process.env.NODE_ENV !== "production" && warn$1("No active route record was found when calling `onBeforeRouteUpdate()`. Make sure you call this function inside a component child of <router-view>. Maybe you called it inside of App.vue?");
  717. return;
  718. }
  719. registerGuard(activeRecord, "updateGuards", updateGuard);
  720. }
  721. function guardToPromiseFn(guard, to, from, record, name, runWithContext = (fn) => fn()) {
  722. const enterCallbackArray = record && (record.enterCallbacks[name] = record.enterCallbacks[name] || []);
  723. return () => new Promise((resolve, reject) => {
  724. const next = (valid) => {
  725. if (valid === false) reject(createRouterError(ErrorTypes.NAVIGATION_ABORTED, {
  726. from,
  727. to
  728. }));
  729. else if (valid instanceof Error) reject(valid);
  730. else if (isRouteLocation(valid)) reject(createRouterError(ErrorTypes.NAVIGATION_GUARD_REDIRECT, {
  731. from: to,
  732. to: valid
  733. }));
  734. else {
  735. if (enterCallbackArray && record.enterCallbacks[name] === enterCallbackArray && typeof valid === "function") enterCallbackArray.push(valid);
  736. resolve();
  737. }
  738. };
  739. const guardReturn = runWithContext(() => guard.call(record && record.instances[name], to, from, process.env.NODE_ENV !== "production" ? canOnlyBeCalledOnce(next, to, from) : next));
  740. let guardCall = Promise.resolve(guardReturn);
  741. if (guard.length < 3) guardCall = guardCall.then(next);
  742. if (process.env.NODE_ENV !== "production" && guard.length > 2) {
  743. const message = `The "next" callback was never called inside of ${guard.name ? "\"" + guard.name + "\"" : ""}:\n${guard.toString()}\n. If you are returning a value instead of calling "next", make sure to remove the "next" parameter from your function.`;
  744. if (typeof guardReturn === "object" && "then" in guardReturn) guardCall = guardCall.then((resolvedValue) => {
  745. if (!next._called) {
  746. warn$1(message);
  747. return Promise.reject(/* @__PURE__ */ new Error("Invalid navigation guard"));
  748. }
  749. return resolvedValue;
  750. });
  751. else if (guardReturn !== void 0) {
  752. if (!next._called) {
  753. warn$1(message);
  754. reject(/* @__PURE__ */ new Error("Invalid navigation guard"));
  755. return;
  756. }
  757. }
  758. }
  759. guardCall.catch((err) => reject(err));
  760. });
  761. }
  762. function canOnlyBeCalledOnce(next, to, from) {
  763. let called = 0;
  764. return function() {
  765. if (called++ === 1) warn$1(`The "next" callback was called more than once in one navigation guard when going from "${from.fullPath}" to "${to.fullPath}". It should be called exactly one time in each navigation guard. This will fail in production.`);
  766. next._called = true;
  767. if (called === 1) next.apply(null, arguments);
  768. };
  769. }
  770. function extractComponentsGuards(matched, guardType, to, from, runWithContext = (fn) => fn()) {
  771. const guards = [];
  772. for (const record of matched) {
  773. if (process.env.NODE_ENV !== "production" && !record.components && record.children && !record.children.length) warn$1(`Record with path "${record.path}" is either missing a "component(s)" or "children" property.`);
  774. for (const name in record.components) {
  775. let rawComponent = record.components[name];
  776. if (process.env.NODE_ENV !== "production") {
  777. if (!rawComponent || typeof rawComponent !== "object" && typeof rawComponent !== "function") {
  778. warn$1(`Component "${name}" in record with path "${record.path}" is not a valid component. Received "${String(rawComponent)}".`);
  779. throw new Error("Invalid route component");
  780. } else if ("then" in rawComponent) {
  781. warn$1(`Component "${name}" in record with path "${record.path}" is a Promise instead of a function that returns a Promise. Did you write "import('./MyPage.vue')" instead of "() => import('./MyPage.vue')" ? This will break in production if not fixed.`);
  782. const promise = rawComponent;
  783. rawComponent = () => promise;
  784. } else if (rawComponent.__asyncLoader && !rawComponent.__warnedDefineAsync) {
  785. rawComponent.__warnedDefineAsync = true;
  786. warn$1(`Component "${name}" in record with path "${record.path}" is defined using "defineAsyncComponent()". Write "() => import('./MyPage.vue')" instead of "defineAsyncComponent(() => import('./MyPage.vue'))".`);
  787. }
  788. }
  789. if (guardType !== "beforeRouteEnter" && !record.instances[name]) continue;
  790. if (isRouteComponent(rawComponent)) {
  791. const guard = (rawComponent.__vccOpts || rawComponent)[guardType];
  792. guard && guards.push(guardToPromiseFn(guard, to, from, record, name, runWithContext));
  793. } else {
  794. let componentPromise = rawComponent();
  795. if (process.env.NODE_ENV !== "production" && !("catch" in componentPromise)) {
  796. warn$1(`Component "${name}" in record with path "${record.path}" is a function that does not return a Promise. If you were passing a functional component, make sure to add a "displayName" to the component. This will break in production if not fixed.`);
  797. componentPromise = Promise.resolve(componentPromise);
  798. }
  799. guards.push(() => componentPromise.then((resolved) => {
  800. if (!resolved) throw new Error(`Couldn't resolve component "${name}" at "${record.path}"`);
  801. const resolvedComponent = isESModule(resolved) ? resolved.default : resolved;
  802. record.mods[name] = resolved;
  803. record.components[name] = resolvedComponent;
  804. const guard = (resolvedComponent.__vccOpts || resolvedComponent)[guardType];
  805. return guard && guardToPromiseFn(guard, to, from, record, name, runWithContext)();
  806. }));
  807. }
  808. }
  809. }
  810. return guards;
  811. }
  812. /**
  813. * Ensures a route is loaded, so it can be passed as o prop to `<RouterView>`.
  814. *
  815. * @param route - resolved route to load
  816. */
  817. function loadRouteLocation(route) {
  818. return route.matched.every((record) => record.redirect) ? Promise.reject(/* @__PURE__ */ new Error("Cannot load a route that redirects.")) : Promise.all(route.matched.map((record) => record.components && Promise.all(Object.keys(record.components).reduce((promises, name) => {
  819. const rawComponent = record.components[name];
  820. if (typeof rawComponent === "function" && !("displayName" in rawComponent)) promises.push(rawComponent().then((resolved) => {
  821. if (!resolved) return Promise.reject(/* @__PURE__ */ new Error(`Couldn't resolve component "${name}" at "${record.path}". Ensure you passed a function that returns a promise.`));
  822. const resolvedComponent = isESModule(resolved) ? resolved.default : resolved;
  823. record.mods[name] = resolved;
  824. record.components[name] = resolvedComponent;
  825. }));
  826. return promises;
  827. }, [])))).then(() => route);
  828. }
  829. /**
  830. * Split the leaving, updating, and entering records.
  831. * @internal
  832. *
  833. * @param to - Location we are navigating to
  834. * @param from - Location we are navigating from
  835. */
  836. function extractChangingRecords(to, from) {
  837. const leavingRecords = [];
  838. const updatingRecords = [];
  839. const enteringRecords = [];
  840. const len = Math.max(from.matched.length, to.matched.length);
  841. for (let i = 0; i < len; i++) {
  842. const recordFrom = from.matched[i];
  843. if (recordFrom) if (to.matched.find((record) => isSameRouteRecord(record, recordFrom))) updatingRecords.push(recordFrom);
  844. else leavingRecords.push(recordFrom);
  845. const recordTo = to.matched[i];
  846. if (recordTo) {
  847. if (!from.matched.find((record) => isSameRouteRecord(record, recordTo))) enteringRecords.push(recordTo);
  848. }
  849. }
  850. return [
  851. leavingRecords,
  852. updatingRecords,
  853. enteringRecords
  854. ];
  855. }
  856. //#endregion
  857. //#region src/devtools.ts
  858. /**
  859. * Copies a route location and removes any problematic properties that cannot be shown in devtools (e.g. Vue instances).
  860. *
  861. * @param routeLocation - routeLocation to format
  862. * @param tooltip - optional tooltip
  863. * @returns a copy of the routeLocation
  864. */
  865. function formatRouteLocation(routeLocation, tooltip) {
  866. const copy = assign({}, routeLocation, { matched: routeLocation.matched.map((matched) => omit(matched, [
  867. "instances",
  868. "children",
  869. "aliasOf"
  870. ])) });
  871. return { _custom: {
  872. type: null,
  873. readOnly: true,
  874. display: routeLocation.fullPath,
  875. tooltip,
  876. value: copy
  877. } };
  878. }
  879. function formatDisplay(display) {
  880. return { _custom: { display } };
  881. }
  882. let routerId = 0;
  883. function addDevtools(app, router, matcher) {
  884. if (router.__hasDevtools) return;
  885. router.__hasDevtools = true;
  886. const id = routerId++;
  887. setupDevtoolsPlugin({
  888. id: "org.vuejs.router" + (id ? "." + id : ""),
  889. label: "Vue Router",
  890. packageName: "vue-router",
  891. homepage: "https://router.vuejs.org",
  892. logo: "https://router.vuejs.org/logo.png",
  893. componentStateTypes: ["Routing"],
  894. app
  895. }, (api) => {
  896. if (typeof api.now !== "function") warn$1("[Vue Router]: You seem to be using an outdated version of Vue Devtools. Are you still using the Beta release instead of the stable one? You can find the links at https://devtools.vuejs.org/guide/installation.html.");
  897. api.on.inspectComponent((payload, ctx) => {
  898. if (payload.instanceData) payload.instanceData.state.push({
  899. type: "Routing",
  900. key: "$route",
  901. editable: false,
  902. value: formatRouteLocation(router.currentRoute.value, "Current Route")
  903. });
  904. });
  905. api.on.visitComponentTree(({ treeNode: node, componentInstance }) => {
  906. if (componentInstance.__vrv_devtools) {
  907. const info = componentInstance.__vrv_devtools;
  908. node.tags.push({
  909. label: (info.name ? `${info.name.toString()}: ` : "") + info.path,
  910. textColor: 0,
  911. tooltip: "This component is rendered by &lt;router-view&gt;",
  912. backgroundColor: PINK_500
  913. });
  914. }
  915. if (isArray(componentInstance.__vrl_devtools)) {
  916. componentInstance.__devtoolsApi = api;
  917. componentInstance.__vrl_devtools.forEach((devtoolsData) => {
  918. let label = devtoolsData.route.path;
  919. let backgroundColor = ORANGE_400;
  920. let tooltip = "";
  921. let textColor = 0;
  922. if (devtoolsData.error) {
  923. label = devtoolsData.error;
  924. backgroundColor = RED_100;
  925. textColor = RED_700;
  926. } else if (devtoolsData.isExactActive) {
  927. backgroundColor = LIME_500;
  928. tooltip = "This is exactly active";
  929. } else if (devtoolsData.isActive) {
  930. backgroundColor = BLUE_600;
  931. tooltip = "This link is active";
  932. }
  933. node.tags.push({
  934. label,
  935. textColor,
  936. tooltip,
  937. backgroundColor
  938. });
  939. });
  940. }
  941. });
  942. watch(router.currentRoute, () => {
  943. refreshRoutesView();
  944. api.notifyComponentUpdate();
  945. api.sendInspectorTree(routerInspectorId);
  946. api.sendInspectorState(routerInspectorId);
  947. });
  948. const navigationsLayerId = "router:navigations:" + id;
  949. api.addTimelineLayer({
  950. id: navigationsLayerId,
  951. label: `Router${id ? " " + id : ""} Navigations`,
  952. color: 4237508
  953. });
  954. router.onError((error, to) => {
  955. api.addTimelineEvent({
  956. layerId: navigationsLayerId,
  957. event: {
  958. title: "Error during Navigation",
  959. subtitle: to.fullPath,
  960. logType: "error",
  961. time: api.now(),
  962. data: { error },
  963. groupId: to.meta.__navigationId
  964. }
  965. });
  966. });
  967. let navigationId = 0;
  968. router.beforeEach((to, from) => {
  969. const data = {
  970. guard: formatDisplay("beforeEach"),
  971. from: formatRouteLocation(from, "Current Location during this navigation"),
  972. to: formatRouteLocation(to, "Target location")
  973. };
  974. Object.defineProperty(to.meta, "__navigationId", { value: navigationId++ });
  975. api.addTimelineEvent({
  976. layerId: navigationsLayerId,
  977. event: {
  978. time: api.now(),
  979. title: "Start of navigation",
  980. subtitle: to.fullPath,
  981. data,
  982. groupId: to.meta.__navigationId
  983. }
  984. });
  985. });
  986. router.afterEach((to, from, failure) => {
  987. const data = { guard: formatDisplay("afterEach") };
  988. if (failure) {
  989. data.failure = { _custom: {
  990. type: Error,
  991. readOnly: true,
  992. display: failure ? failure.message : "",
  993. tooltip: "Navigation Failure",
  994. value: failure
  995. } };
  996. data.status = formatDisplay("❌");
  997. } else data.status = formatDisplay("✅");
  998. data.from = formatRouteLocation(from, "Current Location during this navigation");
  999. data.to = formatRouteLocation(to, "Target location");
  1000. api.addTimelineEvent({
  1001. layerId: navigationsLayerId,
  1002. event: {
  1003. title: "End of navigation",
  1004. subtitle: to.fullPath,
  1005. time: api.now(),
  1006. data,
  1007. logType: failure ? "warning" : "default",
  1008. groupId: to.meta.__navigationId
  1009. }
  1010. });
  1011. });
  1012. /**
  1013. * Inspector of Existing routes
  1014. */
  1015. const routerInspectorId = "router-inspector:" + id;
  1016. api.addInspector({
  1017. id: routerInspectorId,
  1018. label: "Routes" + (id ? " " + id : ""),
  1019. icon: "book",
  1020. treeFilterPlaceholder: "Search routes"
  1021. });
  1022. function refreshRoutesView() {
  1023. if (!activeRoutesPayload) return;
  1024. const payload = activeRoutesPayload;
  1025. let routes = matcher.getRoutes().filter((route) => !route.parent || !route.parent.record.components);
  1026. routes.forEach(resetMatchStateOnRouteRecord);
  1027. if (payload.filter) routes = routes.filter((route) => isRouteMatching(route, payload.filter.toLowerCase()));
  1028. routes.forEach((route) => markRouteRecordActive(route, router.currentRoute.value));
  1029. payload.rootNodes = routes.map(formatRouteRecordForInspector);
  1030. }
  1031. let activeRoutesPayload;
  1032. api.on.getInspectorTree((payload) => {
  1033. activeRoutesPayload = payload;
  1034. if (payload.app === app && payload.inspectorId === routerInspectorId) refreshRoutesView();
  1035. });
  1036. /**
  1037. * Display information about the currently selected route record
  1038. */
  1039. api.on.getInspectorState((payload) => {
  1040. if (payload.app === app && payload.inspectorId === routerInspectorId) {
  1041. const route = matcher.getRoutes().find((route$1) => route$1.record.__vd_id === payload.nodeId);
  1042. if (route) payload.state = { options: formatRouteRecordMatcherForStateInspector(route) };
  1043. }
  1044. });
  1045. api.sendInspectorTree(routerInspectorId);
  1046. api.sendInspectorState(routerInspectorId);
  1047. });
  1048. }
  1049. function modifierForKey(key) {
  1050. if (key.optional) return key.repeatable ? "*" : "?";
  1051. else return key.repeatable ? "+" : "";
  1052. }
  1053. function formatRouteRecordMatcherForStateInspector(route) {
  1054. const { record } = route;
  1055. const fields = [{
  1056. editable: false,
  1057. key: "path",
  1058. value: record.path
  1059. }];
  1060. if (record.name != null) fields.push({
  1061. editable: false,
  1062. key: "name",
  1063. value: record.name
  1064. });
  1065. fields.push({
  1066. editable: false,
  1067. key: "regexp",
  1068. value: route.re
  1069. });
  1070. if (route.keys.length) fields.push({
  1071. editable: false,
  1072. key: "keys",
  1073. value: { _custom: {
  1074. type: null,
  1075. readOnly: true,
  1076. display: route.keys.map((key) => `${key.name}${modifierForKey(key)}`).join(" "),
  1077. tooltip: "Param keys",
  1078. value: route.keys
  1079. } }
  1080. });
  1081. if (record.redirect != null) fields.push({
  1082. editable: false,
  1083. key: "redirect",
  1084. value: record.redirect
  1085. });
  1086. if (route.alias.length) fields.push({
  1087. editable: false,
  1088. key: "aliases",
  1089. value: route.alias.map((alias) => alias.record.path)
  1090. });
  1091. if (Object.keys(route.record.meta).length) fields.push({
  1092. editable: false,
  1093. key: "meta",
  1094. value: route.record.meta
  1095. });
  1096. fields.push({
  1097. key: "score",
  1098. editable: false,
  1099. value: { _custom: {
  1100. type: null,
  1101. readOnly: true,
  1102. display: route.score.map((score) => score.join(", ")).join(" | "),
  1103. tooltip: "Score used to sort routes",
  1104. value: route.score
  1105. } }
  1106. });
  1107. return fields;
  1108. }
  1109. /**
  1110. * Extracted from tailwind palette
  1111. */
  1112. const PINK_500 = 15485081;
  1113. const BLUE_600 = 2450411;
  1114. const LIME_500 = 8702998;
  1115. const CYAN_400 = 2282478;
  1116. const ORANGE_400 = 16486972;
  1117. const DARK = 6710886;
  1118. const RED_100 = 16704226;
  1119. const RED_700 = 12131356;
  1120. function formatRouteRecordForInspector(route) {
  1121. const tags = [];
  1122. const { record } = route;
  1123. if (record.name != null) tags.push({
  1124. label: String(record.name),
  1125. textColor: 0,
  1126. backgroundColor: CYAN_400
  1127. });
  1128. if (record.aliasOf) tags.push({
  1129. label: "alias",
  1130. textColor: 0,
  1131. backgroundColor: ORANGE_400
  1132. });
  1133. if (route.__vd_match) tags.push({
  1134. label: "matches",
  1135. textColor: 0,
  1136. backgroundColor: PINK_500
  1137. });
  1138. if (route.__vd_exactActive) tags.push({
  1139. label: "exact",
  1140. textColor: 0,
  1141. backgroundColor: LIME_500
  1142. });
  1143. if (route.__vd_active) tags.push({
  1144. label: "active",
  1145. textColor: 0,
  1146. backgroundColor: BLUE_600
  1147. });
  1148. if (record.redirect) tags.push({
  1149. label: typeof record.redirect === "string" ? `redirect: ${record.redirect}` : "redirects",
  1150. textColor: 16777215,
  1151. backgroundColor: DARK
  1152. });
  1153. let id = record.__vd_id;
  1154. if (id == null) {
  1155. id = String(routeRecordId++);
  1156. record.__vd_id = id;
  1157. }
  1158. return {
  1159. id,
  1160. label: record.path,
  1161. tags,
  1162. children: route.children.map(formatRouteRecordForInspector)
  1163. };
  1164. }
  1165. let routeRecordId = 0;
  1166. const EXTRACT_REGEXP_RE = /^\/(.*)\/([a-z]*)$/;
  1167. function markRouteRecordActive(route, currentRoute) {
  1168. const isExactActive = currentRoute.matched.length && isSameRouteRecord(currentRoute.matched[currentRoute.matched.length - 1], route.record);
  1169. route.__vd_exactActive = route.__vd_active = isExactActive;
  1170. if (!isExactActive) route.__vd_active = currentRoute.matched.some((match) => isSameRouteRecord(match, route.record));
  1171. route.children.forEach((childRoute) => markRouteRecordActive(childRoute, currentRoute));
  1172. }
  1173. function resetMatchStateOnRouteRecord(route) {
  1174. route.__vd_match = false;
  1175. route.children.forEach(resetMatchStateOnRouteRecord);
  1176. }
  1177. function isRouteMatching(route, filter) {
  1178. const found = String(route.re).match(EXTRACT_REGEXP_RE);
  1179. route.__vd_match = false;
  1180. if (!found || found.length < 3) return false;
  1181. if (new RegExp(found[1].replace(/\$$/, ""), found[2]).test(filter)) {
  1182. route.children.forEach((child) => isRouteMatching(child, filter));
  1183. if (route.record.path !== "/" || filter === "/") {
  1184. route.__vd_match = route.re.test(filter);
  1185. return true;
  1186. }
  1187. return false;
  1188. }
  1189. const path = route.record.path.toLowerCase();
  1190. const decodedPath = decode(path);
  1191. if (!filter.startsWith("/") && (decodedPath.includes(filter) || path.includes(filter))) return true;
  1192. if (decodedPath.startsWith(filter) || path.startsWith(filter)) return true;
  1193. if (route.record.name && String(route.record.name).includes(filter)) return true;
  1194. return route.children.some((child) => isRouteMatching(child, filter));
  1195. }
  1196. function omit(obj, keys) {
  1197. const ret = {};
  1198. for (const key in obj) if (!keys.includes(key)) ret[key] = obj[key];
  1199. return ret;
  1200. }
  1201. //#endregion
  1202. export { ErrorTypes, NEW_stringifyURL, NavigationDirection, NavigationFailureType, NavigationType, START, START_LOCATION_NORMALIZED, addDevtools, applyToParams, assign, computeScrollPosition, createHref, createRouterError, decode, encodeHash, encodeParam, encodePath, extractChangingRecords, extractComponentsGuards, getSavedScrollPosition, getScrollKey, guardToPromiseFn, identityFn, isArray, isBrowser, isNavigationFailure, isRouteLocation, isRouteName, isSameRouteLocation, isSameRouteLocationParams, isSameRouteRecord, loadRouteLocation, matchedRouteKey, mergeOptions, noop, normalizeBase, normalizeQuery, onBeforeRouteLeave, onBeforeRouteUpdate, parseQuery, parseURL, resolveRelativePath, routeLocationKey, routerKey, routerViewLocationKey, saveScrollPosition, scrollToPosition, stringifyQuery, stringifyURL, stripBase, useCallbacks, viewDepthKey, warn$1 as warn };