市场夺宝奇兵
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2416 lines
82 KiB

  1. import { callWithAsyncErrorHandling, camelize, capitalize, computed, createRenderer, defineComponent, extend, h, hyphenate, includeBooleanAttr, inject, invokeArrayFns, isArray, isFunction, isModelListener, isOn, isSet, isSpecialBooleanAttr, isString, isSymbol, looseEqual, looseIndexOf, looseToNumber, nextTick, provide, reactive, ref, shallowReactive, shallowRef, unref, watch } from "./runtime-core.esm-bundler-Cyv4obHQ.js";
  2. let policy = void 0;
  3. const tt = typeof window !== "undefined" && window.trustedTypes;
  4. if (tt) try {
  5. policy = /* @__PURE__ */ tt.createPolicy("vue", { createHTML: (val) => val });
  6. } catch (e) {}
  7. const unsafeToTrustedHTML = policy ? (val) => policy.createHTML(val) : (val) => val;
  8. const svgNS = "http://www.w3.org/2000/svg";
  9. const mathmlNS = "http://www.w3.org/1998/Math/MathML";
  10. const doc = typeof document !== "undefined" ? document : null;
  11. const templateContainer = doc && /* @__PURE__ */ doc.createElement("template");
  12. const nodeOps = {
  13. insert: (child, parent, anchor) => {
  14. parent.insertBefore(child, anchor || null);
  15. },
  16. remove: (child) => {
  17. const parent = child.parentNode;
  18. if (parent) parent.removeChild(child);
  19. },
  20. createElement: (tag, namespace, is, props) => {
  21. const el = namespace === "svg" ? doc.createElementNS(svgNS, tag) : namespace === "mathml" ? doc.createElementNS(mathmlNS, tag) : is ? doc.createElement(tag, { is }) : doc.createElement(tag);
  22. if (tag === "select" && props && props.multiple != null) el.setAttribute("multiple", props.multiple);
  23. return el;
  24. },
  25. createText: (text) => doc.createTextNode(text),
  26. createComment: (text) => doc.createComment(text),
  27. setText: (node, text) => {
  28. node.nodeValue = text;
  29. },
  30. setElementText: (el, text) => {
  31. el.textContent = text;
  32. },
  33. parentNode: (node) => node.parentNode,
  34. nextSibling: (node) => node.nextSibling,
  35. querySelector: (selector) => doc.querySelector(selector),
  36. setScopeId(el, id) {
  37. el.setAttribute(id, "");
  38. },
  39. insertStaticContent(content, parent, anchor, namespace, start, end) {
  40. const before = anchor ? anchor.previousSibling : parent.lastChild;
  41. if (start && (start === end || start.nextSibling)) while (true) {
  42. parent.insertBefore(start.cloneNode(true), anchor);
  43. if (start === end || !(start = start.nextSibling)) break;
  44. }
  45. else {
  46. templateContainer.innerHTML = unsafeToTrustedHTML(namespace === "svg" ? `<svg>${content}</svg>` : namespace === "mathml" ? `<math>${content}</math>` : content);
  47. const template = templateContainer.content;
  48. if (namespace === "svg" || namespace === "mathml") {
  49. const wrapper = template.firstChild;
  50. while (wrapper.firstChild) template.appendChild(wrapper.firstChild);
  51. template.removeChild(wrapper);
  52. }
  53. parent.insertBefore(template, anchor);
  54. }
  55. return [before ? before.nextSibling : parent.firstChild, anchor ? anchor.previousSibling : parent.lastChild];
  56. }
  57. };
  58. const vtcKey = Symbol("_vtc");
  59. function patchClass(el, value, isSVG) {
  60. const transitionClasses = el[vtcKey];
  61. if (transitionClasses) value = (value ? [value, ...transitionClasses] : [...transitionClasses]).join(" ");
  62. if (value == null) el.removeAttribute("class");
  63. else if (isSVG) el.setAttribute("class", value);
  64. else el.className = value;
  65. }
  66. const vShowOriginalDisplay = Symbol("_vod");
  67. const vShowHidden = Symbol("_vsh");
  68. const vShow = {
  69. beforeMount(el, { value }, { transition }) {
  70. el[vShowOriginalDisplay] = el.style.display === "none" ? "" : el.style.display;
  71. if (transition && value) transition.beforeEnter(el);
  72. else setDisplay(el, value);
  73. },
  74. mounted(el, { value }, { transition }) {
  75. if (transition && value) transition.enter(el);
  76. },
  77. updated(el, { value, oldValue }, { transition }) {
  78. if (!value === !oldValue) return;
  79. if (transition) if (value) {
  80. transition.beforeEnter(el);
  81. setDisplay(el, true);
  82. transition.enter(el);
  83. } else transition.leave(el, () => {
  84. setDisplay(el, false);
  85. });
  86. else setDisplay(el, value);
  87. },
  88. beforeUnmount(el, { value }) {
  89. setDisplay(el, value);
  90. }
  91. };
  92. function setDisplay(el, value) {
  93. el.style.display = value ? el[vShowOriginalDisplay] : "none";
  94. el[vShowHidden] = !value;
  95. }
  96. const CSS_VAR_TEXT = Symbol("");
  97. const displayRE = /(^|;)\s*display\s*:/;
  98. function patchStyle(el, prev, next) {
  99. const style = el.style;
  100. const isCssString = isString(next);
  101. let hasControlledDisplay = false;
  102. if (next && !isCssString) {
  103. if (prev) if (!isString(prev)) {
  104. for (const key in prev) if (next[key] == null) setStyle(style, key, "");
  105. } else for (const prevStyle of prev.split(";")) {
  106. const key = prevStyle.slice(0, prevStyle.indexOf(":")).trim();
  107. if (next[key] == null) setStyle(style, key, "");
  108. }
  109. for (const key in next) {
  110. if (key === "display") hasControlledDisplay = true;
  111. setStyle(style, key, next[key]);
  112. }
  113. } else if (isCssString) {
  114. if (prev !== next) {
  115. const cssVarText = style[CSS_VAR_TEXT];
  116. if (cssVarText) next += ";" + cssVarText;
  117. style.cssText = next;
  118. hasControlledDisplay = displayRE.test(next);
  119. }
  120. } else if (prev) el.removeAttribute("style");
  121. if (vShowOriginalDisplay in el) {
  122. el[vShowOriginalDisplay] = hasControlledDisplay ? style.display : "";
  123. if (el[vShowHidden]) style.display = "none";
  124. }
  125. }
  126. const importantRE = /\s*!important$/;
  127. function setStyle(style, name, val) {
  128. if (isArray(val)) val.forEach((v) => setStyle(style, name, v));
  129. else {
  130. if (val == null) val = "";
  131. if (name.startsWith("--")) style.setProperty(name, val);
  132. else {
  133. const prefixed = autoPrefix(style, name);
  134. if (importantRE.test(val)) style.setProperty(hyphenate(prefixed), val.replace(importantRE, ""), "important");
  135. else style[prefixed] = val;
  136. }
  137. }
  138. }
  139. const prefixes = [
  140. "Webkit",
  141. "Moz",
  142. "ms"
  143. ];
  144. const prefixCache = {};
  145. function autoPrefix(style, rawName) {
  146. const cached = prefixCache[rawName];
  147. if (cached) return cached;
  148. let name = camelize(rawName);
  149. if (name !== "filter" && name in style) return prefixCache[rawName] = name;
  150. name = capitalize(name);
  151. for (let i = 0; i < prefixes.length; i++) {
  152. const prefixed = prefixes[i] + name;
  153. if (prefixed in style) return prefixCache[rawName] = prefixed;
  154. }
  155. return rawName;
  156. }
  157. const xlinkNS = "http://www.w3.org/1999/xlink";
  158. function patchAttr(el, key, value, isSVG, instance, isBoolean = isSpecialBooleanAttr(key)) {
  159. if (isSVG && key.startsWith("xlink:")) if (value == null) el.removeAttributeNS(xlinkNS, key.slice(6, key.length));
  160. else el.setAttributeNS(xlinkNS, key, value);
  161. else if (value == null || isBoolean && !includeBooleanAttr(value)) el.removeAttribute(key);
  162. else el.setAttribute(key, isBoolean ? "" : isSymbol(value) ? String(value) : value);
  163. }
  164. function patchDOMProp(el, key, value, parentComponent, attrName) {
  165. if (key === "innerHTML" || key === "textContent") {
  166. if (value != null) el[key] = key === "innerHTML" ? unsafeToTrustedHTML(value) : value;
  167. return;
  168. }
  169. const tag = el.tagName;
  170. if (key === "value" && tag !== "PROGRESS" && !tag.includes("-")) {
  171. const oldValue = tag === "OPTION" ? el.getAttribute("value") || "" : el.value;
  172. const newValue = value == null ? el.type === "checkbox" ? "on" : "" : String(value);
  173. if (oldValue !== newValue || !("_value" in el)) el.value = newValue;
  174. if (value == null) el.removeAttribute(key);
  175. el._value = value;
  176. return;
  177. }
  178. let needRemove = false;
  179. if (value === "" || value == null) {
  180. const type = typeof el[key];
  181. if (type === "boolean") value = includeBooleanAttr(value);
  182. else if (value == null && type === "string") {
  183. value = "";
  184. needRemove = true;
  185. } else if (type === "number") {
  186. value = 0;
  187. needRemove = true;
  188. }
  189. }
  190. try {
  191. el[key] = value;
  192. } catch (e) {}
  193. needRemove && el.removeAttribute(attrName || key);
  194. }
  195. function addEventListener(el, event, handler, options) {
  196. el.addEventListener(event, handler, options);
  197. }
  198. function removeEventListener(el, event, handler, options) {
  199. el.removeEventListener(event, handler, options);
  200. }
  201. const veiKey = Symbol("_vei");
  202. function patchEvent(el, rawName, prevValue, nextValue, instance = null) {
  203. const invokers = el[veiKey] || (el[veiKey] = {});
  204. const existingInvoker = invokers[rawName];
  205. if (nextValue && existingInvoker) existingInvoker.value = nextValue;
  206. else {
  207. const [name, options] = parseName(rawName);
  208. if (nextValue) {
  209. const invoker = invokers[rawName] = createInvoker(nextValue, instance);
  210. addEventListener(el, name, invoker, options);
  211. } else if (existingInvoker) {
  212. removeEventListener(el, name, existingInvoker, options);
  213. invokers[rawName] = void 0;
  214. }
  215. }
  216. }
  217. const optionsModifierRE = /(?:Once|Passive|Capture)$/;
  218. function parseName(name) {
  219. let options;
  220. if (optionsModifierRE.test(name)) {
  221. options = {};
  222. let m;
  223. while (m = name.match(optionsModifierRE)) {
  224. name = name.slice(0, name.length - m[0].length);
  225. options[m[0].toLowerCase()] = true;
  226. }
  227. }
  228. const event = name[2] === ":" ? name.slice(3) : hyphenate(name.slice(2));
  229. return [event, options];
  230. }
  231. let cachedNow = 0;
  232. const p = /* @__PURE__ */ Promise.resolve();
  233. const getNow = () => cachedNow || (p.then(() => cachedNow = 0), cachedNow = Date.now());
  234. function createInvoker(initialValue, instance) {
  235. const invoker = (e) => {
  236. if (!e._vts) e._vts = Date.now();
  237. else if (e._vts <= invoker.attached) return;
  238. callWithAsyncErrorHandling(patchStopImmediatePropagation(e, invoker.value), instance, 5, [e]);
  239. };
  240. invoker.value = initialValue;
  241. invoker.attached = getNow();
  242. return invoker;
  243. }
  244. function patchStopImmediatePropagation(e, value) {
  245. if (isArray(value)) {
  246. const originalStop = e.stopImmediatePropagation;
  247. e.stopImmediatePropagation = () => {
  248. originalStop.call(e);
  249. e._stopped = true;
  250. };
  251. return value.map((fn) => (e2) => !e2._stopped && fn && fn(e2));
  252. } else return value;
  253. }
  254. const isNativeOn = (key) => key.charCodeAt(0) === 111 && key.charCodeAt(1) === 110 && key.charCodeAt(2) > 96 && key.charCodeAt(2) < 123;
  255. const patchProp = (el, key, prevValue, nextValue, namespace, parentComponent) => {
  256. const isSVG = namespace === "svg";
  257. if (key === "class") patchClass(el, nextValue, isSVG);
  258. else if (key === "style") patchStyle(el, prevValue, nextValue);
  259. else if (isOn(key)) {
  260. if (!isModelListener(key)) patchEvent(el, key, prevValue, nextValue, parentComponent);
  261. } else if (key[0] === "." ? (key = key.slice(1), true) : key[0] === "^" ? (key = key.slice(1), false) : shouldSetAsProp(el, key, nextValue, isSVG)) {
  262. patchDOMProp(el, key, nextValue);
  263. if (!el.tagName.includes("-") && (key === "value" || key === "checked" || key === "selected")) patchAttr(el, key, nextValue, isSVG, parentComponent, key !== "value");
  264. } else if (el._isVueCE && (/[A-Z]/.test(key) || !isString(nextValue))) patchDOMProp(el, camelize(key), nextValue, parentComponent, key);
  265. else {
  266. if (key === "true-value") el._trueValue = nextValue;
  267. else if (key === "false-value") el._falseValue = nextValue;
  268. patchAttr(el, key, nextValue, isSVG);
  269. }
  270. };
  271. function shouldSetAsProp(el, key, value, isSVG) {
  272. if (isSVG) {
  273. if (key === "innerHTML" || key === "textContent") return true;
  274. if (key in el && isNativeOn(key) && isFunction(value)) return true;
  275. return false;
  276. }
  277. if (key === "spellcheck" || key === "draggable" || key === "translate" || key === "autocorrect") return false;
  278. if (key === "form") return false;
  279. if (key === "list" && el.tagName === "INPUT") return false;
  280. if (key === "type" && el.tagName === "TEXTAREA") return false;
  281. if (key === "width" || key === "height") {
  282. const tag = el.tagName;
  283. if (tag === "IMG" || tag === "VIDEO" || tag === "CANVAS" || tag === "SOURCE") return false;
  284. }
  285. if (isNativeOn(key) && isString(value)) return false;
  286. return key in el;
  287. }
  288. const moveCbKey = Symbol("_moveCb");
  289. const enterCbKey = Symbol("_enterCb");
  290. const getModelAssigner = (vnode) => {
  291. const fn = vnode.props["onUpdate:modelValue"] || false;
  292. return isArray(fn) ? (value) => invokeArrayFns(fn, value) : fn;
  293. };
  294. function onCompositionStart(e) {
  295. e.target.composing = true;
  296. }
  297. function onCompositionEnd(e) {
  298. const target = e.target;
  299. if (target.composing) {
  300. target.composing = false;
  301. target.dispatchEvent(new Event("input"));
  302. }
  303. }
  304. const assignKey = Symbol("_assign");
  305. const vModelText = {
  306. created(el, { modifiers: { lazy, trim, number } }, vnode) {
  307. el[assignKey] = getModelAssigner(vnode);
  308. const castToNumber = number || vnode.props && vnode.props.type === "number";
  309. addEventListener(el, lazy ? "change" : "input", (e) => {
  310. if (e.target.composing) return;
  311. let domValue = el.value;
  312. if (trim) domValue = domValue.trim();
  313. if (castToNumber) domValue = looseToNumber(domValue);
  314. el[assignKey](domValue);
  315. });
  316. if (trim) addEventListener(el, "change", () => {
  317. el.value = el.value.trim();
  318. });
  319. if (!lazy) {
  320. addEventListener(el, "compositionstart", onCompositionStart);
  321. addEventListener(el, "compositionend", onCompositionEnd);
  322. addEventListener(el, "change", onCompositionEnd);
  323. }
  324. },
  325. mounted(el, { value }) {
  326. el.value = value == null ? "" : value;
  327. },
  328. beforeUpdate(el, { value, oldValue, modifiers: { lazy, trim, number } }, vnode) {
  329. el[assignKey] = getModelAssigner(vnode);
  330. if (el.composing) return;
  331. const elValue = (number || el.type === "number") && !/^0\d/.test(el.value) ? looseToNumber(el.value) : el.value;
  332. const newValue = value == null ? "" : value;
  333. if (elValue === newValue) return;
  334. if (document.activeElement === el && el.type !== "range") {
  335. if (lazy && value === oldValue) return;
  336. if (trim && el.value.trim() === newValue) return;
  337. }
  338. el.value = newValue;
  339. }
  340. };
  341. const vModelCheckbox = {
  342. deep: true,
  343. created(el, _, vnode) {
  344. el[assignKey] = getModelAssigner(vnode);
  345. addEventListener(el, "change", () => {
  346. const modelValue = el._modelValue;
  347. const elementValue = getValue(el);
  348. const checked = el.checked;
  349. const assign$1 = el[assignKey];
  350. if (isArray(modelValue)) {
  351. const index = looseIndexOf(modelValue, elementValue);
  352. const found = index !== -1;
  353. if (checked && !found) assign$1(modelValue.concat(elementValue));
  354. else if (!checked && found) {
  355. const filtered = [...modelValue];
  356. filtered.splice(index, 1);
  357. assign$1(filtered);
  358. }
  359. } else if (isSet(modelValue)) {
  360. const cloned = new Set(modelValue);
  361. if (checked) cloned.add(elementValue);
  362. else cloned.delete(elementValue);
  363. assign$1(cloned);
  364. } else assign$1(getCheckboxValue(el, checked));
  365. });
  366. },
  367. mounted: setChecked,
  368. beforeUpdate(el, binding, vnode) {
  369. el[assignKey] = getModelAssigner(vnode);
  370. setChecked(el, binding, vnode);
  371. }
  372. };
  373. function setChecked(el, { value, oldValue }, vnode) {
  374. el._modelValue = value;
  375. let checked;
  376. if (isArray(value)) checked = looseIndexOf(value, vnode.props.value) > -1;
  377. else if (isSet(value)) checked = value.has(vnode.props.value);
  378. else {
  379. if (value === oldValue) return;
  380. checked = looseEqual(value, getCheckboxValue(el, true));
  381. }
  382. if (el.checked !== checked) el.checked = checked;
  383. }
  384. function getValue(el) {
  385. return "_value" in el ? el._value : el.value;
  386. }
  387. function getCheckboxValue(el, checked) {
  388. const key = checked ? "_trueValue" : "_falseValue";
  389. return key in el ? el[key] : checked;
  390. }
  391. const keyNames = {
  392. esc: "escape",
  393. space: " ",
  394. up: "arrow-up",
  395. left: "arrow-left",
  396. right: "arrow-right",
  397. down: "arrow-down",
  398. delete: "backspace"
  399. };
  400. const withKeys = (fn, modifiers) => {
  401. const cache = fn._withKeys || (fn._withKeys = {});
  402. const cacheKey = modifiers.join(".");
  403. return cache[cacheKey] || (cache[cacheKey] = (event) => {
  404. if (!("key" in event)) return;
  405. const eventKey = hyphenate(event.key);
  406. if (modifiers.some((k) => k === eventKey || keyNames[k] === eventKey)) return fn(event);
  407. });
  408. };
  409. const rendererOptions = /* @__PURE__ */ extend({ patchProp }, nodeOps);
  410. let renderer;
  411. function ensureRenderer() {
  412. return renderer || (renderer = createRenderer(rendererOptions));
  413. }
  414. const createApp = (...args) => {
  415. const app = ensureRenderer().createApp(...args);
  416. const { mount } = app;
  417. app.mount = (containerOrSelector) => {
  418. const container = normalizeContainer(containerOrSelector);
  419. if (!container) return;
  420. const component = app._component;
  421. if (!isFunction(component) && !component.render && !component.template) component.template = container.innerHTML;
  422. if (container.nodeType === 1) container.textContent = "";
  423. const proxy = mount(container, false, resolveRootNamespace(container));
  424. if (container instanceof Element) {
  425. container.removeAttribute("v-cloak");
  426. container.setAttribute("data-v-app", "");
  427. }
  428. return proxy;
  429. };
  430. return app;
  431. };
  432. function resolveRootNamespace(container) {
  433. if (container instanceof SVGElement) return "svg";
  434. if (typeof MathMLElement === "function" && container instanceof MathMLElement) return "mathml";
  435. }
  436. function normalizeContainer(container) {
  437. if (isString(container)) {
  438. const res = document.querySelector(container);
  439. return res;
  440. }
  441. return container;
  442. }
  443. const isBrowser = typeof document !== "undefined";
  444. /**
  445. * Allows differentiating lazy components from functional components and vue-class-component
  446. * @internal
  447. *
  448. * @param component
  449. */
  450. function isRouteComponent(component) {
  451. return typeof component === "object" || "displayName" in component || "props" in component || "__vccOpts" in component;
  452. }
  453. function isESModule(obj) {
  454. return obj.__esModule || obj[Symbol.toStringTag] === "Module" || obj.default && isRouteComponent(obj.default);
  455. }
  456. const assign = Object.assign;
  457. function applyToParams(fn, params) {
  458. const newParams = {};
  459. for (const key in params) {
  460. const value = params[key];
  461. newParams[key] = isArray$1(value) ? value.map(fn) : fn(value);
  462. }
  463. return newParams;
  464. }
  465. const noop = () => {};
  466. /**
  467. * Typesafe alternative to Array.isArray
  468. * https://github.com/microsoft/TypeScript/pull/48228
  469. */
  470. const isArray$1 = Array.isArray;
  471. /**
  472. * Encoding Rules ( = Space)
  473. * - Path: " < > # ? { }
  474. * - Query: " < > # & =
  475. * - Hash: " < > `
  476. *
  477. * On top of that, the RFC3986 (https://tools.ietf.org/html/rfc3986#section-2.2)
  478. * defines some extra characters to be encoded. Most browsers do not encode them
  479. * in encodeURI https://github.com/whatwg/url/issues/369, so it may be safer to
  480. * also encode `!'()*`. Leaving un-encoded only ASCII alphanumeric(`a-zA-Z0-9`)
  481. * plus `-._~`. This extra safety should be applied to query by patching the
  482. * string returned by encodeURIComponent encodeURI also encodes `[\]^`. `\`
  483. * should be encoded to avoid ambiguity. Browsers (IE, FF, C) transform a `\`
  484. * into a `/` if directly typed in. The _backtick_ (`````) should also be
  485. * encoded everywhere because some browsers like FF encode it when directly
  486. * written while others don't. Safari and IE don't encode ``"<>{}``` in hash.
  487. */
  488. const HASH_RE = /#/g;
  489. const AMPERSAND_RE = /&/g;
  490. const SLASH_RE = /\//g;
  491. const EQUAL_RE = /=/g;
  492. const IM_RE = /\?/g;
  493. const PLUS_RE = /\+/g;
  494. /**
  495. * NOTE: It's not clear to me if we should encode the + symbol in queries, it
  496. * seems to be less flexible than not doing so and I can't find out the legacy
  497. * systems requiring this for regular requests like text/html. In the standard,
  498. * the encoding of the plus character is only mentioned for
  499. * application/x-www-form-urlencoded
  500. * (https://url.spec.whatwg.org/#urlencoded-parsing) and most browsers seems lo
  501. * leave the plus character as is in queries. To be more flexible, we allow the
  502. * plus character on the query, but it can also be manually encoded by the user.
  503. *
  504. * Resources:
  505. * - https://url.spec.whatwg.org/#urlencoded-parsing
  506. * - https://stackoverflow.com/questions/1634271/url-encoding-the-space-character-or-20
  507. */
  508. const ENC_BRACKET_OPEN_RE = /%5B/g;
  509. const ENC_BRACKET_CLOSE_RE = /%5D/g;
  510. const ENC_CARET_RE = /%5E/g;
  511. const ENC_BACKTICK_RE = /%60/g;
  512. const ENC_CURLY_OPEN_RE = /%7B/g;
  513. const ENC_PIPE_RE = /%7C/g;
  514. const ENC_CURLY_CLOSE_RE = /%7D/g;
  515. const ENC_SPACE_RE = /%20/g;
  516. /**
  517. * Encode characters that need to be encoded on the path, search and hash
  518. * sections of the URL.
  519. *
  520. * @internal
  521. * @param text - string to encode
  522. * @returns encoded string
  523. */
  524. function commonEncode(text) {
  525. return encodeURI("" + text).replace(ENC_PIPE_RE, "|").replace(ENC_BRACKET_OPEN_RE, "[").replace(ENC_BRACKET_CLOSE_RE, "]");
  526. }
  527. /**
  528. * Encode characters that need to be encoded on the hash section of the URL.
  529. *
  530. * @param text - string to encode
  531. * @returns encoded string
  532. */
  533. function encodeHash(text) {
  534. return commonEncode(text).replace(ENC_CURLY_OPEN_RE, "{").replace(ENC_CURLY_CLOSE_RE, "}").replace(ENC_CARET_RE, "^");
  535. }
  536. /**
  537. * Encode characters that need to be encoded query values on the query
  538. * section of the URL.
  539. *
  540. * @param text - string to encode
  541. * @returns encoded string
  542. */
  543. function encodeQueryValue(text) {
  544. 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, "^");
  545. }
  546. /**
  547. * Like `encodeQueryValue` but also encodes the `=` character.
  548. *
  549. * @param text - string to encode
  550. */
  551. function encodeQueryKey(text) {
  552. return encodeQueryValue(text).replace(EQUAL_RE, "%3D");
  553. }
  554. /**
  555. * Encode characters that need to be encoded on the path section of the URL.
  556. *
  557. * @param text - string to encode
  558. * @returns encoded string
  559. */
  560. function encodePath(text) {
  561. return commonEncode(text).replace(HASH_RE, "%23").replace(IM_RE, "%3F");
  562. }
  563. /**
  564. * Encode characters that need to be encoded on the path section of the URL as a
  565. * param. This function encodes everything {@link encodePath} does plus the
  566. * slash (`/`) character. If `text` is `null` or `undefined`, returns an empty
  567. * string instead.
  568. *
  569. * @param text - string to encode
  570. * @returns encoded string
  571. */
  572. function encodeParam(text) {
  573. return text == null ? "" : encodePath(text).replace(SLASH_RE, "%2F");
  574. }
  575. /**
  576. * Decode text using `decodeURIComponent`. Returns the original text if it
  577. * fails.
  578. *
  579. * @param text - string to decode
  580. * @returns decoded string
  581. */
  582. function decode(text) {
  583. try {
  584. return decodeURIComponent("" + text);
  585. } catch (err) {}
  586. return "" + text;
  587. }
  588. const TRAILING_SLASH_RE = /\/$/;
  589. const removeTrailingSlash = (path) => path.replace(TRAILING_SLASH_RE, "");
  590. /**
  591. * Transforms a URI into a normalized history location
  592. *
  593. * @param parseQuery
  594. * @param location - URI to normalize
  595. * @param currentLocation - current absolute location. Allows resolving relative
  596. * paths. Must start with `/`. Defaults to `/`
  597. * @returns a normalized history location
  598. */
  599. function parseURL(parseQuery$1, location$1, currentLocation = "/") {
  600. let path, query = {}, searchString = "", hash = "";
  601. const hashPos = location$1.indexOf("#");
  602. let searchPos = location$1.indexOf("?");
  603. if (hashPos < searchPos && hashPos >= 0) searchPos = -1;
  604. if (searchPos > -1) {
  605. path = location$1.slice(0, searchPos);
  606. searchString = location$1.slice(searchPos + 1, hashPos > -1 ? hashPos : location$1.length);
  607. query = parseQuery$1(searchString);
  608. }
  609. if (hashPos > -1) {
  610. path = path || location$1.slice(0, hashPos);
  611. hash = location$1.slice(hashPos, location$1.length);
  612. }
  613. path = resolveRelativePath(path != null ? path : location$1, currentLocation);
  614. return {
  615. fullPath: path + (searchString && "?") + searchString + hash,
  616. path,
  617. query,
  618. hash: decode(hash)
  619. };
  620. }
  621. /**
  622. * Stringifies a URL object
  623. *
  624. * @param stringifyQuery
  625. * @param location
  626. */
  627. function stringifyURL(stringifyQuery$1, location$1) {
  628. const query = location$1.query ? stringifyQuery$1(location$1.query) : "";
  629. return location$1.path + (query && "?") + query + (location$1.hash || "");
  630. }
  631. /**
  632. * Strips off the base from the beginning of a location.pathname in a non-case-sensitive way.
  633. *
  634. * @param pathname - location.pathname
  635. * @param base - base to strip off
  636. */
  637. function stripBase(pathname, base) {
  638. if (!base || !pathname.toLowerCase().startsWith(base.toLowerCase())) return pathname;
  639. return pathname.slice(base.length) || "/";
  640. }
  641. /**
  642. * Checks if two RouteLocation are equal. This means that both locations are
  643. * pointing towards the same {@link RouteRecord} and that all `params`, `query`
  644. * parameters and `hash` are the same
  645. *
  646. * @param stringifyQuery - A function that takes a query object of type LocationQueryRaw and returns a string representation of it.
  647. * @param a - first {@link RouteLocation}
  648. * @param b - second {@link RouteLocation}
  649. */
  650. function isSameRouteLocation(stringifyQuery$1, a, b) {
  651. const aLastIndex = a.matched.length - 1;
  652. const bLastIndex = b.matched.length - 1;
  653. 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;
  654. }
  655. /**
  656. * Check if two `RouteRecords` are equal. Takes into account aliases: they are
  657. * considered equal to the `RouteRecord` they are aliasing.
  658. *
  659. * @param a - first {@link RouteRecord}
  660. * @param b - second {@link RouteRecord}
  661. */
  662. function isSameRouteRecord(a, b) {
  663. return (a.aliasOf || a) === (b.aliasOf || b);
  664. }
  665. function isSameRouteLocationParams(a, b) {
  666. if (Object.keys(a).length !== Object.keys(b).length) return false;
  667. for (const key in a) if (!isSameRouteLocationParamsValue(a[key], b[key])) return false;
  668. return true;
  669. }
  670. function isSameRouteLocationParamsValue(a, b) {
  671. return isArray$1(a) ? isEquivalentArray(a, b) : isArray$1(b) ? isEquivalentArray(b, a) : a === b;
  672. }
  673. /**
  674. * Check if two arrays are the same or if an array with one single entry is the
  675. * same as another primitive value. Used to check query and parameters
  676. *
  677. * @param a - array of values
  678. * @param b - array of values or a single value
  679. */
  680. function isEquivalentArray(a, b) {
  681. return isArray$1(b) ? a.length === b.length && a.every((value, i) => value === b[i]) : a.length === 1 && a[0] === b;
  682. }
  683. /**
  684. * Resolves a relative path that starts with `.`.
  685. *
  686. * @param to - path location we are resolving
  687. * @param from - currentLocation.path, should start with `/`
  688. */
  689. function resolveRelativePath(to, from) {
  690. if (to.startsWith("/")) return to;
  691. if (!to) return from;
  692. const fromSegments = from.split("/");
  693. const toSegments = to.split("/");
  694. const lastToSegment = toSegments[toSegments.length - 1];
  695. if (lastToSegment === ".." || lastToSegment === ".") toSegments.push("");
  696. let position = fromSegments.length - 1;
  697. let toPosition;
  698. let segment;
  699. for (toPosition = 0; toPosition < toSegments.length; toPosition++) {
  700. segment = toSegments[toPosition];
  701. if (segment === ".") continue;
  702. if (segment === "..") {
  703. if (position > 1) position--;
  704. } else break;
  705. }
  706. return fromSegments.slice(0, position).join("/") + "/" + toSegments.slice(toPosition).join("/");
  707. }
  708. /**
  709. * Initial route location where the router is. Can be used in navigation guards
  710. * to differentiate the initial navigation.
  711. *
  712. * @example
  713. * ```js
  714. * import { START_LOCATION } from 'vue-router'
  715. *
  716. * router.beforeEach((to, from) => {
  717. * if (from === START_LOCATION) {
  718. * // initial navigation
  719. * }
  720. * })
  721. * ```
  722. */
  723. const START_LOCATION_NORMALIZED = {
  724. path: "/",
  725. name: void 0,
  726. params: {},
  727. query: {},
  728. hash: "",
  729. fullPath: "/",
  730. matched: [],
  731. meta: {},
  732. redirectedFrom: void 0
  733. };
  734. var NavigationType;
  735. (function(NavigationType$1) {
  736. NavigationType$1["pop"] = "pop";
  737. NavigationType$1["push"] = "push";
  738. })(NavigationType || (NavigationType = {}));
  739. var NavigationDirection;
  740. (function(NavigationDirection$1) {
  741. NavigationDirection$1["back"] = "back";
  742. NavigationDirection$1["forward"] = "forward";
  743. NavigationDirection$1["unknown"] = "";
  744. })(NavigationDirection || (NavigationDirection = {}));
  745. /**
  746. * Normalizes a base by removing any trailing slash and reading the base tag if
  747. * present.
  748. *
  749. * @param base - base to normalize
  750. */
  751. function normalizeBase(base) {
  752. if (!base) if (isBrowser) {
  753. const baseEl = document.querySelector("base");
  754. base = baseEl && baseEl.getAttribute("href") || "/";
  755. base = base.replace(/^\w+:\/\/[^\/]+/, "");
  756. } else base = "/";
  757. if (base[0] !== "/" && base[0] !== "#") base = "/" + base;
  758. return removeTrailingSlash(base);
  759. }
  760. const BEFORE_HASH_RE = /^[^#]+#/;
  761. function createHref(base, location$1) {
  762. return base.replace(BEFORE_HASH_RE, "#") + location$1;
  763. }
  764. function getElementPosition(el, offset) {
  765. const docRect = document.documentElement.getBoundingClientRect();
  766. const elRect = el.getBoundingClientRect();
  767. return {
  768. behavior: offset.behavior,
  769. left: elRect.left - docRect.left - (offset.left || 0),
  770. top: elRect.top - docRect.top - (offset.top || 0)
  771. };
  772. }
  773. const computeScrollPosition = () => ({
  774. left: window.scrollX,
  775. top: window.scrollY
  776. });
  777. function scrollToPosition(position) {
  778. let scrollToOptions;
  779. if ("el" in position) {
  780. const positionEl = position.el;
  781. const isIdSelector = typeof positionEl === "string" && positionEl.startsWith("#");
  782. const el = typeof positionEl === "string" ? isIdSelector ? document.getElementById(positionEl.slice(1)) : document.querySelector(positionEl) : positionEl;
  783. if (!el) return;
  784. scrollToOptions = getElementPosition(el, position);
  785. } else scrollToOptions = position;
  786. if ("scrollBehavior" in document.documentElement.style) window.scrollTo(scrollToOptions);
  787. else window.scrollTo(scrollToOptions.left != null ? scrollToOptions.left : window.scrollX, scrollToOptions.top != null ? scrollToOptions.top : window.scrollY);
  788. }
  789. function getScrollKey(path, delta) {
  790. const position = history.state ? history.state.position - delta : -1;
  791. return position + path;
  792. }
  793. const scrollPositions = new Map();
  794. function saveScrollPosition(key, scrollPosition) {
  795. scrollPositions.set(key, scrollPosition);
  796. }
  797. function getSavedScrollPosition(key) {
  798. const scroll = scrollPositions.get(key);
  799. scrollPositions.delete(key);
  800. return scroll;
  801. }
  802. /**
  803. * ScrollBehavior instance used by the router to compute and restore the scroll
  804. * position when navigating.
  805. */
  806. let createBaseLocation = () => location.protocol + "//" + location.host;
  807. /**
  808. * Creates a normalized history location from a window.location object
  809. * @param base - The base path
  810. * @param location - The window.location object
  811. */
  812. function createCurrentLocation(base, location$1) {
  813. const { pathname, search, hash } = location$1;
  814. const hashPos = base.indexOf("#");
  815. if (hashPos > -1) {
  816. let slicePos = hash.includes(base.slice(hashPos)) ? base.slice(hashPos).length : 1;
  817. let pathFromHash = hash.slice(slicePos);
  818. if (pathFromHash[0] !== "/") pathFromHash = "/" + pathFromHash;
  819. return stripBase(pathFromHash, "");
  820. }
  821. const path = stripBase(pathname, base);
  822. return path + search + hash;
  823. }
  824. function useHistoryListeners(base, historyState, currentLocation, replace) {
  825. let listeners = [];
  826. let teardowns = [];
  827. let pauseState = null;
  828. const popStateHandler = ({ state }) => {
  829. const to = createCurrentLocation(base, location);
  830. const from = currentLocation.value;
  831. const fromState = historyState.value;
  832. let delta = 0;
  833. if (state) {
  834. currentLocation.value = to;
  835. historyState.value = state;
  836. if (pauseState && pauseState === from) {
  837. pauseState = null;
  838. return;
  839. }
  840. delta = fromState ? state.position - fromState.position : 0;
  841. } else replace(to);
  842. listeners.forEach((listener) => {
  843. listener(currentLocation.value, from, {
  844. delta,
  845. type: NavigationType.pop,
  846. direction: delta ? delta > 0 ? NavigationDirection.forward : NavigationDirection.back : NavigationDirection.unknown
  847. });
  848. });
  849. };
  850. function pauseListeners() {
  851. pauseState = currentLocation.value;
  852. }
  853. function listen(callback) {
  854. listeners.push(callback);
  855. const teardown = () => {
  856. const index = listeners.indexOf(callback);
  857. if (index > -1) listeners.splice(index, 1);
  858. };
  859. teardowns.push(teardown);
  860. return teardown;
  861. }
  862. function beforeUnloadListener() {
  863. const { history: history$1 } = window;
  864. if (!history$1.state) return;
  865. history$1.replaceState(assign({}, history$1.state, { scroll: computeScrollPosition() }), "");
  866. }
  867. function destroy() {
  868. for (const teardown of teardowns) teardown();
  869. teardowns = [];
  870. window.removeEventListener("popstate", popStateHandler);
  871. window.removeEventListener("beforeunload", beforeUnloadListener);
  872. }
  873. window.addEventListener("popstate", popStateHandler);
  874. window.addEventListener("beforeunload", beforeUnloadListener, { passive: true });
  875. return {
  876. pauseListeners,
  877. listen,
  878. destroy
  879. };
  880. }
  881. /**
  882. * Creates a state object
  883. */
  884. function buildState(back, current, forward, replaced = false, computeScroll = false) {
  885. return {
  886. back,
  887. current,
  888. forward,
  889. replaced,
  890. position: window.history.length,
  891. scroll: computeScroll ? computeScrollPosition() : null
  892. };
  893. }
  894. function useHistoryStateNavigation(base) {
  895. const { history: history$1, location: location$1 } = window;
  896. const currentLocation = { value: createCurrentLocation(base, location$1) };
  897. const historyState = { value: history$1.state };
  898. if (!historyState.value) changeLocation(currentLocation.value, {
  899. back: null,
  900. current: currentLocation.value,
  901. forward: null,
  902. position: history$1.length - 1,
  903. replaced: true,
  904. scroll: null
  905. }, true);
  906. function changeLocation(to, state, replace$1) {
  907. /**
  908. * if a base tag is provided, and we are on a normal domain, we have to
  909. * respect the provided `base` attribute because pushState() will use it and
  910. * potentially erase anything before the `#` like at
  911. * https://github.com/vuejs/router/issues/685 where a base of
  912. * `/folder/#` but a base of `/` would erase the `/folder/` section. If
  913. * there is no host, the `<base>` tag makes no sense and if there isn't a
  914. * base tag we can just use everything after the `#`.
  915. */
  916. const hashIndex = base.indexOf("#");
  917. const url = hashIndex > -1 ? (location$1.host && document.querySelector("base") ? base : base.slice(hashIndex)) + to : createBaseLocation() + base + to;
  918. try {
  919. history$1[replace$1 ? "replaceState" : "pushState"](state, "", url);
  920. historyState.value = state;
  921. } catch (err) {
  922. console.error(err);
  923. location$1[replace$1 ? "replace" : "assign"](url);
  924. }
  925. }
  926. function replace(to, data) {
  927. const state = assign({}, history$1.state, buildState(
  928. historyState.value.back,
  929. // keep back and forward entries but override current position
  930. to,
  931. historyState.value.forward,
  932. true
  933. ), data, { position: historyState.value.position });
  934. changeLocation(to, state, true);
  935. currentLocation.value = to;
  936. }
  937. function push(to, data) {
  938. const currentState = assign(
  939. {},
  940. // use current history state to gracefully handle a wrong call to
  941. // history.replaceState
  942. // https://github.com/vuejs/router/issues/366
  943. historyState.value,
  944. history$1.state,
  945. {
  946. forward: to,
  947. scroll: computeScrollPosition()
  948. }
  949. );
  950. changeLocation(currentState.current, currentState, true);
  951. const state = assign({}, buildState(currentLocation.value, to, null), { position: currentState.position + 1 }, data);
  952. changeLocation(to, state, false);
  953. currentLocation.value = to;
  954. }
  955. return {
  956. location: currentLocation,
  957. state: historyState,
  958. push,
  959. replace
  960. };
  961. }
  962. /**
  963. * Creates an HTML5 history. Most common history for single page applications.
  964. *
  965. * @param base -
  966. */
  967. function createWebHistory(base) {
  968. base = normalizeBase(base);
  969. const historyNavigation = useHistoryStateNavigation(base);
  970. const historyListeners = useHistoryListeners(base, historyNavigation.state, historyNavigation.location, historyNavigation.replace);
  971. function go(delta, triggerListeners = true) {
  972. if (!triggerListeners) historyListeners.pauseListeners();
  973. history.go(delta);
  974. }
  975. const routerHistory = assign({
  976. location: "",
  977. base,
  978. go,
  979. createHref: createHref.bind(null, base)
  980. }, historyNavigation, historyListeners);
  981. Object.defineProperty(routerHistory, "location", {
  982. enumerable: true,
  983. get: () => historyNavigation.location.value
  984. });
  985. Object.defineProperty(routerHistory, "state", {
  986. enumerable: true,
  987. get: () => historyNavigation.state.value
  988. });
  989. return routerHistory;
  990. }
  991. /**
  992. * Creates a hash history. Useful for web applications with no host (e.g. `file://`) or when configuring a server to
  993. * handle any URL is not possible.
  994. *
  995. * @param base - optional base to provide. Defaults to `location.pathname + location.search` If there is a `<base>` tag
  996. * in the `head`, its value will be ignored in favor of this parameter **but note it affects all the history.pushState()
  997. * calls**, meaning that if you use a `<base>` tag, it's `href` value **has to match this parameter** (ignoring anything
  998. * after the `#`).
  999. *
  1000. * @example
  1001. * ```js
  1002. * // at https://example.com/folder
  1003. * createWebHashHistory() // gives a url of `https://example.com/folder#`
  1004. * createWebHashHistory('/folder/') // gives a url of `https://example.com/folder/#`
  1005. * // if the `#` is provided in the base, it won't be added by `createWebHashHistory`
  1006. * createWebHashHistory('/folder/#/app/') // gives a url of `https://example.com/folder/#/app/`
  1007. * // you should avoid doing this because it changes the original url and breaks copying urls
  1008. * createWebHashHistory('/other-folder/') // gives a url of `https://example.com/other-folder/#`
  1009. *
  1010. * // at file:///usr/etc/folder/index.html
  1011. * // for locations with no `host`, the base is ignored
  1012. * createWebHashHistory('/iAmIgnored') // gives a url of `file:///usr/etc/folder/index.html#`
  1013. * ```
  1014. */
  1015. function createWebHashHistory(base) {
  1016. base = location.host ? base || location.pathname + location.search : "";
  1017. if (!base.includes("#")) base += "#";
  1018. return createWebHistory(base);
  1019. }
  1020. function isRouteLocation(route) {
  1021. return typeof route === "string" || route && typeof route === "object";
  1022. }
  1023. function isRouteName(name) {
  1024. return typeof name === "string" || typeof name === "symbol";
  1025. }
  1026. const NavigationFailureSymbol = Symbol("");
  1027. /**
  1028. * Enumeration with all possible types for navigation failures. Can be passed to
  1029. * {@link isNavigationFailure} to check for specific failures.
  1030. */
  1031. var NavigationFailureType;
  1032. (function(NavigationFailureType$1) {
  1033. /**
  1034. * An aborted navigation is a navigation that failed because a navigation
  1035. * guard returned `false` or called `next(false)`
  1036. */
  1037. NavigationFailureType$1[NavigationFailureType$1["aborted"] = 4] = "aborted";
  1038. /**
  1039. * A cancelled navigation is a navigation that failed because a more recent
  1040. * navigation finished started (not necessarily finished).
  1041. */
  1042. NavigationFailureType$1[NavigationFailureType$1["cancelled"] = 8] = "cancelled";
  1043. /**
  1044. * A duplicated navigation is a navigation that failed because it was
  1045. * initiated while already being at the exact same location.
  1046. */
  1047. NavigationFailureType$1[NavigationFailureType$1["duplicated"] = 16] = "duplicated";
  1048. })(NavigationFailureType || (NavigationFailureType = {}));
  1049. /**
  1050. * Creates a typed NavigationFailure object.
  1051. * @internal
  1052. * @param type - NavigationFailureType
  1053. * @param params - { from, to }
  1054. */
  1055. function createRouterError(type, params) {
  1056. return assign(new Error(), {
  1057. type,
  1058. [NavigationFailureSymbol]: true
  1059. }, params);
  1060. }
  1061. function isNavigationFailure(error, type) {
  1062. return error instanceof Error && NavigationFailureSymbol in error && (type == null || !!(error.type & type));
  1063. }
  1064. const BASE_PARAM_PATTERN = "[^/]+?";
  1065. const BASE_PATH_PARSER_OPTIONS = {
  1066. sensitive: false,
  1067. strict: false,
  1068. start: true,
  1069. end: true
  1070. };
  1071. const REGEX_CHARS_RE = /[.+*?^${}()[\]/\\]/g;
  1072. /**
  1073. * Creates a path parser from an array of Segments (a segment is an array of Tokens)
  1074. *
  1075. * @param segments - array of segments returned by tokenizePath
  1076. * @param extraOptions - optional options for the regexp
  1077. * @returns a PathParser
  1078. */
  1079. function tokensToParser(segments, extraOptions) {
  1080. const options = assign({}, BASE_PATH_PARSER_OPTIONS, extraOptions);
  1081. const score = [];
  1082. let pattern = options.start ? "^" : "";
  1083. const keys = [];
  1084. for (const segment of segments) {
  1085. const segmentScores = segment.length ? [] : [90];
  1086. if (options.strict && !segment.length) pattern += "/";
  1087. for (let tokenIndex = 0; tokenIndex < segment.length; tokenIndex++) {
  1088. const token = segment[tokenIndex];
  1089. let subSegmentScore = 40 + (options.sensitive ? .25 : 0);
  1090. if (token.type === 0) {
  1091. if (!tokenIndex) pattern += "/";
  1092. pattern += token.value.replace(REGEX_CHARS_RE, "\\$&");
  1093. subSegmentScore += 40;
  1094. } else if (token.type === 1) {
  1095. const { value, repeatable, optional, regexp } = token;
  1096. keys.push({
  1097. name: value,
  1098. repeatable,
  1099. optional
  1100. });
  1101. const re$1 = regexp ? regexp : BASE_PARAM_PATTERN;
  1102. if (re$1 !== BASE_PARAM_PATTERN) {
  1103. subSegmentScore += 10;
  1104. try {
  1105. new RegExp(`(${re$1})`);
  1106. } catch (err) {
  1107. throw new Error(`Invalid custom RegExp for param "${value}" (${re$1}): ` + err.message);
  1108. }
  1109. }
  1110. let subPattern = repeatable ? `((?:${re$1})(?:/(?:${re$1}))*)` : `(${re$1})`;
  1111. if (!tokenIndex) subPattern = optional && segment.length < 2 ? `(?:/${subPattern})` : "/" + subPattern;
  1112. if (optional) subPattern += "?";
  1113. pattern += subPattern;
  1114. subSegmentScore += 20;
  1115. if (optional) subSegmentScore += -8;
  1116. if (repeatable) subSegmentScore += -20;
  1117. if (re$1 === ".*") subSegmentScore += -50;
  1118. }
  1119. segmentScores.push(subSegmentScore);
  1120. }
  1121. score.push(segmentScores);
  1122. }
  1123. if (options.strict && options.end) {
  1124. const i = score.length - 1;
  1125. score[i][score[i].length - 1] += .7000000000000001;
  1126. }
  1127. if (!options.strict) pattern += "/?";
  1128. if (options.end) pattern += "$";
  1129. else if (options.strict && !pattern.endsWith("/")) pattern += "(?:/|$)";
  1130. const re = new RegExp(pattern, options.sensitive ? "" : "i");
  1131. function parse(path) {
  1132. const match = path.match(re);
  1133. const params = {};
  1134. if (!match) return null;
  1135. for (let i = 1; i < match.length; i++) {
  1136. const value = match[i] || "";
  1137. const key = keys[i - 1];
  1138. params[key.name] = value && key.repeatable ? value.split("/") : value;
  1139. }
  1140. return params;
  1141. }
  1142. function stringify(params) {
  1143. let path = "";
  1144. let avoidDuplicatedSlash = false;
  1145. for (const segment of segments) {
  1146. if (!avoidDuplicatedSlash || !path.endsWith("/")) path += "/";
  1147. avoidDuplicatedSlash = false;
  1148. for (const token of segment) if (token.type === 0) path += token.value;
  1149. else if (token.type === 1) {
  1150. const { value, repeatable, optional } = token;
  1151. const param = value in params ? params[value] : "";
  1152. if (isArray$1(param) && !repeatable) throw new Error(`Provided param "${value}" is an array but it is not repeatable (* or + modifiers)`);
  1153. const text = isArray$1(param) ? param.join("/") : param;
  1154. if (!text) if (optional) {
  1155. if (segment.length < 2) if (path.endsWith("/")) path = path.slice(0, -1);
  1156. else avoidDuplicatedSlash = true;
  1157. } else throw new Error(`Missing required param "${value}"`);
  1158. path += text;
  1159. }
  1160. }
  1161. return path || "/";
  1162. }
  1163. return {
  1164. re,
  1165. score,
  1166. keys,
  1167. parse,
  1168. stringify
  1169. };
  1170. }
  1171. /**
  1172. * Compares an array of numbers as used in PathParser.score and returns a
  1173. * number. This function can be used to `sort` an array
  1174. *
  1175. * @param a - first array of numbers
  1176. * @param b - second array of numbers
  1177. * @returns 0 if both are equal, < 0 if a should be sorted first, > 0 if b
  1178. * should be sorted first
  1179. */
  1180. function compareScoreArray(a, b) {
  1181. let i = 0;
  1182. while (i < a.length && i < b.length) {
  1183. const diff = b[i] - a[i];
  1184. if (diff) return diff;
  1185. i++;
  1186. }
  1187. if (a.length < b.length) return a.length === 1 && a[0] === 80 ? -1 : 1;
  1188. else if (a.length > b.length) return b.length === 1 && b[0] === 80 ? 1 : -1;
  1189. return 0;
  1190. }
  1191. /**
  1192. * Compare function that can be used with `sort` to sort an array of PathParser
  1193. *
  1194. * @param a - first PathParser
  1195. * @param b - second PathParser
  1196. * @returns 0 if both are equal, < 0 if a should be sorted first, > 0 if b
  1197. */
  1198. function comparePathParserScore(a, b) {
  1199. let i = 0;
  1200. const aScore = a.score;
  1201. const bScore = b.score;
  1202. while (i < aScore.length && i < bScore.length) {
  1203. const comp = compareScoreArray(aScore[i], bScore[i]);
  1204. if (comp) return comp;
  1205. i++;
  1206. }
  1207. if (Math.abs(bScore.length - aScore.length) === 1) {
  1208. if (isLastScoreNegative(aScore)) return 1;
  1209. if (isLastScoreNegative(bScore)) return -1;
  1210. }
  1211. return bScore.length - aScore.length;
  1212. }
  1213. /**
  1214. * This allows detecting splats at the end of a path: /home/:id(.*)*
  1215. *
  1216. * @param score - score to check
  1217. * @returns true if the last entry is negative
  1218. */
  1219. function isLastScoreNegative(score) {
  1220. const last = score[score.length - 1];
  1221. return score.length > 0 && last[last.length - 1] < 0;
  1222. }
  1223. const ROOT_TOKEN = {
  1224. type: 0,
  1225. value: ""
  1226. };
  1227. const VALID_PARAM_RE = /[a-zA-Z0-9_]/;
  1228. function tokenizePath(path) {
  1229. if (!path) return [[]];
  1230. if (path === "/") return [[ROOT_TOKEN]];
  1231. if (!path.startsWith("/")) throw new Error(`Invalid path "${path}"`);
  1232. function crash(message) {
  1233. throw new Error(`ERR (${state})/"${buffer}": ${message}`);
  1234. }
  1235. let state = 0;
  1236. let previousState = state;
  1237. const tokens = [];
  1238. let segment;
  1239. function finalizeSegment() {
  1240. if (segment) tokens.push(segment);
  1241. segment = [];
  1242. }
  1243. let i = 0;
  1244. let char;
  1245. let buffer = "";
  1246. let customRe = "";
  1247. function consumeBuffer() {
  1248. if (!buffer) return;
  1249. if (state === 0) segment.push({
  1250. type: 0,
  1251. value: buffer
  1252. });
  1253. else if (state === 1 || state === 2 || state === 3) {
  1254. if (segment.length > 1 && (char === "*" || char === "+")) crash(`A repeatable param (${buffer}) must be alone in its segment. eg: '/:ids+.`);
  1255. segment.push({
  1256. type: 1,
  1257. value: buffer,
  1258. regexp: customRe,
  1259. repeatable: char === "*" || char === "+",
  1260. optional: char === "*" || char === "?"
  1261. });
  1262. } else crash("Invalid state to consume buffer");
  1263. buffer = "";
  1264. }
  1265. function addCharToBuffer() {
  1266. buffer += char;
  1267. }
  1268. while (i < path.length) {
  1269. char = path[i++];
  1270. if (char === "\\" && state !== 2) {
  1271. previousState = state;
  1272. state = 4;
  1273. continue;
  1274. }
  1275. switch (state) {
  1276. case 0:
  1277. if (char === "/") {
  1278. if (buffer) consumeBuffer();
  1279. finalizeSegment();
  1280. } else if (char === ":") {
  1281. consumeBuffer();
  1282. state = 1;
  1283. } else addCharToBuffer();
  1284. break;
  1285. case 4:
  1286. addCharToBuffer();
  1287. state = previousState;
  1288. break;
  1289. case 1:
  1290. if (char === "(") state = 2;
  1291. else if (VALID_PARAM_RE.test(char)) addCharToBuffer();
  1292. else {
  1293. consumeBuffer();
  1294. state = 0;
  1295. if (char !== "*" && char !== "?" && char !== "+") i--;
  1296. }
  1297. break;
  1298. case 2:
  1299. if (char === ")") if (customRe[customRe.length - 1] == "\\") customRe = customRe.slice(0, -1) + char;
  1300. else state = 3;
  1301. else customRe += char;
  1302. break;
  1303. case 3:
  1304. consumeBuffer();
  1305. state = 0;
  1306. if (char !== "*" && char !== "?" && char !== "+") i--;
  1307. customRe = "";
  1308. break;
  1309. default:
  1310. crash("Unknown state");
  1311. break;
  1312. }
  1313. }
  1314. if (state === 2) crash(`Unfinished custom RegExp for param "${buffer}"`);
  1315. consumeBuffer();
  1316. finalizeSegment();
  1317. return tokens;
  1318. }
  1319. function createRouteRecordMatcher(record, parent, options) {
  1320. const parser = tokensToParser(tokenizePath(record.path), options);
  1321. const matcher = assign(parser, {
  1322. record,
  1323. parent,
  1324. children: [],
  1325. alias: []
  1326. });
  1327. if (parent) {
  1328. if (!matcher.record.aliasOf === !parent.record.aliasOf) parent.children.push(matcher);
  1329. }
  1330. return matcher;
  1331. }
  1332. /**
  1333. * Creates a Router Matcher.
  1334. *
  1335. * @internal
  1336. * @param routes - array of initial routes
  1337. * @param globalOptions - global route options
  1338. */
  1339. function createRouterMatcher(routes, globalOptions) {
  1340. const matchers = [];
  1341. const matcherMap = new Map();
  1342. globalOptions = mergeOptions({
  1343. strict: false,
  1344. end: true,
  1345. sensitive: false
  1346. }, globalOptions);
  1347. function getRecordMatcher(name) {
  1348. return matcherMap.get(name);
  1349. }
  1350. function addRoute(record, parent, originalRecord) {
  1351. const isRootAdd = !originalRecord;
  1352. const mainNormalizedRecord = normalizeRouteRecord(record);
  1353. mainNormalizedRecord.aliasOf = originalRecord && originalRecord.record;
  1354. const options = mergeOptions(globalOptions, record);
  1355. const normalizedRecords = [mainNormalizedRecord];
  1356. if ("alias" in record) {
  1357. const aliases = typeof record.alias === "string" ? [record.alias] : record.alias;
  1358. for (const alias of aliases) normalizedRecords.push(
  1359. // we need to normalize again to ensure the `mods` property
  1360. // being non enumerable
  1361. normalizeRouteRecord(assign({}, mainNormalizedRecord, {
  1362. components: originalRecord ? originalRecord.record.components : mainNormalizedRecord.components,
  1363. path: alias,
  1364. aliasOf: originalRecord ? originalRecord.record : mainNormalizedRecord
  1365. }))
  1366. );
  1367. }
  1368. let matcher;
  1369. let originalMatcher;
  1370. for (const normalizedRecord of normalizedRecords) {
  1371. const { path } = normalizedRecord;
  1372. if (parent && path[0] !== "/") {
  1373. const parentPath = parent.record.path;
  1374. const connectingSlash = parentPath[parentPath.length - 1] === "/" ? "" : "/";
  1375. normalizedRecord.path = parent.record.path + (path && connectingSlash + path);
  1376. }
  1377. matcher = createRouteRecordMatcher(normalizedRecord, parent, options);
  1378. if (originalRecord) originalRecord.alias.push(matcher);
  1379. else {
  1380. originalMatcher = originalMatcher || matcher;
  1381. if (originalMatcher !== matcher) originalMatcher.alias.push(matcher);
  1382. if (isRootAdd && record.name && !isAliasRecord(matcher)) removeRoute(record.name);
  1383. }
  1384. if (isMatchable(matcher)) insertMatcher(matcher);
  1385. if (mainNormalizedRecord.children) {
  1386. const children = mainNormalizedRecord.children;
  1387. for (let i = 0; i < children.length; i++) addRoute(children[i], matcher, originalRecord && originalRecord.children[i]);
  1388. }
  1389. originalRecord = originalRecord || matcher;
  1390. }
  1391. return originalMatcher ? () => {
  1392. removeRoute(originalMatcher);
  1393. } : noop;
  1394. }
  1395. function removeRoute(matcherRef) {
  1396. if (isRouteName(matcherRef)) {
  1397. const matcher = matcherMap.get(matcherRef);
  1398. if (matcher) {
  1399. matcherMap.delete(matcherRef);
  1400. matchers.splice(matchers.indexOf(matcher), 1);
  1401. matcher.children.forEach(removeRoute);
  1402. matcher.alias.forEach(removeRoute);
  1403. }
  1404. } else {
  1405. const index = matchers.indexOf(matcherRef);
  1406. if (index > -1) {
  1407. matchers.splice(index, 1);
  1408. if (matcherRef.record.name) matcherMap.delete(matcherRef.record.name);
  1409. matcherRef.children.forEach(removeRoute);
  1410. matcherRef.alias.forEach(removeRoute);
  1411. }
  1412. }
  1413. }
  1414. function getRoutes() {
  1415. return matchers;
  1416. }
  1417. function insertMatcher(matcher) {
  1418. const index = findInsertionIndex(matcher, matchers);
  1419. matchers.splice(index, 0, matcher);
  1420. if (matcher.record.name && !isAliasRecord(matcher)) matcherMap.set(matcher.record.name, matcher);
  1421. }
  1422. function resolve(location$1, currentLocation) {
  1423. let matcher;
  1424. let params = {};
  1425. let path;
  1426. let name;
  1427. if ("name" in location$1 && location$1.name) {
  1428. matcher = matcherMap.get(location$1.name);
  1429. if (!matcher) throw createRouterError(1, { location: location$1 });
  1430. name = matcher.record.name;
  1431. params = assign(
  1432. // paramsFromLocation is a new object
  1433. paramsFromLocation(
  1434. currentLocation.params,
  1435. // only keep params that exist in the resolved location
  1436. // only keep optional params coming from a parent record
  1437. matcher.keys.filter((k) => !k.optional).concat(matcher.parent ? matcher.parent.keys.filter((k) => k.optional) : []).map((k) => k.name)
  1438. ),
  1439. // discard any existing params in the current location that do not exist here
  1440. // #1497 this ensures better active/exact matching
  1441. location$1.params && paramsFromLocation(location$1.params, matcher.keys.map((k) => k.name))
  1442. );
  1443. path = matcher.stringify(params);
  1444. } else if (location$1.path != null) {
  1445. path = location$1.path;
  1446. matcher = matchers.find((m) => m.re.test(path));
  1447. if (matcher) {
  1448. params = matcher.parse(path);
  1449. name = matcher.record.name;
  1450. }
  1451. } else {
  1452. matcher = currentLocation.name ? matcherMap.get(currentLocation.name) : matchers.find((m) => m.re.test(currentLocation.path));
  1453. if (!matcher) throw createRouterError(1, {
  1454. location: location$1,
  1455. currentLocation
  1456. });
  1457. name = matcher.record.name;
  1458. params = assign({}, currentLocation.params, location$1.params);
  1459. path = matcher.stringify(params);
  1460. }
  1461. const matched = [];
  1462. let parentMatcher = matcher;
  1463. while (parentMatcher) {
  1464. matched.unshift(parentMatcher.record);
  1465. parentMatcher = parentMatcher.parent;
  1466. }
  1467. return {
  1468. name,
  1469. path,
  1470. params,
  1471. matched,
  1472. meta: mergeMetaFields(matched)
  1473. };
  1474. }
  1475. routes.forEach((route) => addRoute(route));
  1476. function clearRoutes() {
  1477. matchers.length = 0;
  1478. matcherMap.clear();
  1479. }
  1480. return {
  1481. addRoute,
  1482. resolve,
  1483. removeRoute,
  1484. clearRoutes,
  1485. getRoutes,
  1486. getRecordMatcher
  1487. };
  1488. }
  1489. function paramsFromLocation(params, keys) {
  1490. const newParams = {};
  1491. for (const key of keys) if (key in params) newParams[key] = params[key];
  1492. return newParams;
  1493. }
  1494. /**
  1495. * Normalizes a RouteRecordRaw. Creates a copy
  1496. *
  1497. * @param record
  1498. * @returns the normalized version
  1499. */
  1500. function normalizeRouteRecord(record) {
  1501. const normalized = {
  1502. path: record.path,
  1503. redirect: record.redirect,
  1504. name: record.name,
  1505. meta: record.meta || {},
  1506. aliasOf: record.aliasOf,
  1507. beforeEnter: record.beforeEnter,
  1508. props: normalizeRecordProps(record),
  1509. children: record.children || [],
  1510. instances: {},
  1511. leaveGuards: new Set(),
  1512. updateGuards: new Set(),
  1513. enterCallbacks: {},
  1514. components: "components" in record ? record.components || null : record.component && { default: record.component }
  1515. };
  1516. Object.defineProperty(normalized, "mods", { value: {} });
  1517. return normalized;
  1518. }
  1519. /**
  1520. * Normalize the optional `props` in a record to always be an object similar to
  1521. * components. Also accept a boolean for components.
  1522. * @param record
  1523. */
  1524. function normalizeRecordProps(record) {
  1525. const propsObject = {};
  1526. const props = record.props || false;
  1527. if ("component" in record) propsObject.default = props;
  1528. else for (const name in record.components) propsObject[name] = typeof props === "object" ? props[name] : props;
  1529. return propsObject;
  1530. }
  1531. /**
  1532. * Checks if a record or any of its parent is an alias
  1533. * @param record
  1534. */
  1535. function isAliasRecord(record) {
  1536. while (record) {
  1537. if (record.record.aliasOf) return true;
  1538. record = record.parent;
  1539. }
  1540. return false;
  1541. }
  1542. /**
  1543. * Merge meta fields of an array of records
  1544. *
  1545. * @param matched - array of matched records
  1546. */
  1547. function mergeMetaFields(matched) {
  1548. return matched.reduce((meta, record) => assign(meta, record.meta), {});
  1549. }
  1550. function mergeOptions(defaults, partialOptions) {
  1551. const options = {};
  1552. for (const key in defaults) options[key] = key in partialOptions ? partialOptions[key] : defaults[key];
  1553. return options;
  1554. }
  1555. /**
  1556. * Performs a binary search to find the correct insertion index for a new matcher.
  1557. *
  1558. * Matchers are primarily sorted by their score. If scores are tied then we also consider parent/child relationships,
  1559. * with descendants coming before ancestors. If there's still a tie, new routes are inserted after existing routes.
  1560. *
  1561. * @param matcher - new matcher to be inserted
  1562. * @param matchers - existing matchers
  1563. */
  1564. function findInsertionIndex(matcher, matchers) {
  1565. let lower = 0;
  1566. let upper = matchers.length;
  1567. while (lower !== upper) {
  1568. const mid = lower + upper >> 1;
  1569. const sortOrder = comparePathParserScore(matcher, matchers[mid]);
  1570. if (sortOrder < 0) upper = mid;
  1571. else lower = mid + 1;
  1572. }
  1573. const insertionAncestor = getInsertionAncestor(matcher);
  1574. if (insertionAncestor) upper = matchers.lastIndexOf(insertionAncestor, upper - 1);
  1575. return upper;
  1576. }
  1577. function getInsertionAncestor(matcher) {
  1578. let ancestor = matcher;
  1579. while (ancestor = ancestor.parent) if (isMatchable(ancestor) && comparePathParserScore(matcher, ancestor) === 0) return ancestor;
  1580. return;
  1581. }
  1582. /**
  1583. * Checks if a matcher can be reachable. This means if it's possible to reach it as a route. For example, routes without
  1584. * a component, or name, or redirect, are just used to group other routes.
  1585. * @param matcher
  1586. * @param matcher.record record of the matcher
  1587. * @returns
  1588. */
  1589. function isMatchable({ record }) {
  1590. return !!(record.name || record.components && Object.keys(record.components).length || record.redirect);
  1591. }
  1592. /**
  1593. * Transforms a queryString into a {@link LocationQuery} object. Accept both, a
  1594. * version with the leading `?` and without Should work as URLSearchParams
  1595. * @internal
  1596. *
  1597. * @param search - search string to parse
  1598. * @returns a query object
  1599. */
  1600. function parseQuery(search) {
  1601. const query = {};
  1602. if (search === "" || search === "?") return query;
  1603. const hasLeadingIM = search[0] === "?";
  1604. const searchParams = (hasLeadingIM ? search.slice(1) : search).split("&");
  1605. for (let i = 0; i < searchParams.length; ++i) {
  1606. const searchParam = searchParams[i].replace(PLUS_RE, " ");
  1607. const eqPos = searchParam.indexOf("=");
  1608. const key = decode(eqPos < 0 ? searchParam : searchParam.slice(0, eqPos));
  1609. const value = eqPos < 0 ? null : decode(searchParam.slice(eqPos + 1));
  1610. if (key in query) {
  1611. let currentValue = query[key];
  1612. if (!isArray$1(currentValue)) currentValue = query[key] = [currentValue];
  1613. currentValue.push(value);
  1614. } else query[key] = value;
  1615. }
  1616. return query;
  1617. }
  1618. /**
  1619. * Stringifies a {@link LocationQueryRaw} object. Like `URLSearchParams`, it
  1620. * doesn't prepend a `?`
  1621. *
  1622. * @internal
  1623. *
  1624. * @param query - query object to stringify
  1625. * @returns string version of the query without the leading `?`
  1626. */
  1627. function stringifyQuery(query) {
  1628. let search = "";
  1629. for (let key in query) {
  1630. const value = query[key];
  1631. key = encodeQueryKey(key);
  1632. if (value == null) {
  1633. if (value !== void 0) search += (search.length ? "&" : "") + key;
  1634. continue;
  1635. }
  1636. const values = isArray$1(value) ? value.map((v) => v && encodeQueryValue(v)) : [value && encodeQueryValue(value)];
  1637. values.forEach((value$1) => {
  1638. if (value$1 !== void 0) {
  1639. search += (search.length ? "&" : "") + key;
  1640. if (value$1 != null) search += "=" + value$1;
  1641. }
  1642. });
  1643. }
  1644. return search;
  1645. }
  1646. /**
  1647. * Transforms a {@link LocationQueryRaw} into a {@link LocationQuery} by casting
  1648. * numbers into strings, removing keys with an undefined value and replacing
  1649. * undefined with null in arrays
  1650. *
  1651. * @param query - query object to normalize
  1652. * @returns a normalized query object
  1653. */
  1654. function normalizeQuery(query) {
  1655. const normalizedQuery = {};
  1656. for (const key in query) {
  1657. const value = query[key];
  1658. if (value !== void 0) normalizedQuery[key] = isArray$1(value) ? value.map((v) => v == null ? null : "" + v) : value == null ? value : "" + value;
  1659. }
  1660. return normalizedQuery;
  1661. }
  1662. /**
  1663. * RouteRecord being rendered by the closest ancestor Router View. Used for
  1664. * `onBeforeRouteUpdate` and `onBeforeRouteLeave`. rvlm stands for Router View
  1665. * Location Matched
  1666. *
  1667. * @internal
  1668. */
  1669. const matchedRouteKey = Symbol("");
  1670. /**
  1671. * Allows overriding the router view depth to control which component in
  1672. * `matched` is rendered. rvd stands for Router View Depth
  1673. *
  1674. * @internal
  1675. */
  1676. const viewDepthKey = Symbol("");
  1677. /**
  1678. * Allows overriding the router instance returned by `useRouter` in tests. r
  1679. * stands for router
  1680. *
  1681. * @internal
  1682. */
  1683. const routerKey = Symbol("");
  1684. /**
  1685. * Allows overriding the current route returned by `useRoute` in tests. rl
  1686. * stands for route location
  1687. *
  1688. * @internal
  1689. */
  1690. const routeLocationKey = Symbol("");
  1691. /**
  1692. * Allows overriding the current route used by router-view. Internally this is
  1693. * used when the `route` prop is passed.
  1694. *
  1695. * @internal
  1696. */
  1697. const routerViewLocationKey = Symbol("");
  1698. /**
  1699. * Create a list of callbacks that can be reset. Used to create before and after navigation guards list
  1700. */
  1701. function useCallbacks() {
  1702. let handlers = [];
  1703. function add(handler) {
  1704. handlers.push(handler);
  1705. return () => {
  1706. const i = handlers.indexOf(handler);
  1707. if (i > -1) handlers.splice(i, 1);
  1708. };
  1709. }
  1710. function reset() {
  1711. handlers = [];
  1712. }
  1713. return {
  1714. add,
  1715. list: () => handlers.slice(),
  1716. reset
  1717. };
  1718. }
  1719. function guardToPromiseFn(guard, to, from, record, name, runWithContext = (fn) => fn()) {
  1720. const enterCallbackArray = record && (record.enterCallbacks[name] = record.enterCallbacks[name] || []);
  1721. return () => new Promise((resolve, reject) => {
  1722. const next = (valid) => {
  1723. if (valid === false) reject(createRouterError(4, {
  1724. from,
  1725. to
  1726. }));
  1727. else if (valid instanceof Error) reject(valid);
  1728. else if (isRouteLocation(valid)) reject(createRouterError(2, {
  1729. from: to,
  1730. to: valid
  1731. }));
  1732. else {
  1733. if (enterCallbackArray && record.enterCallbacks[name] === enterCallbackArray && typeof valid === "function") enterCallbackArray.push(valid);
  1734. resolve();
  1735. }
  1736. };
  1737. const guardReturn = runWithContext(() => guard.call(record && record.instances[name], to, from, next));
  1738. let guardCall = Promise.resolve(guardReturn);
  1739. if (guard.length < 3) guardCall = guardCall.then(next);
  1740. guardCall.catch((err) => reject(err));
  1741. });
  1742. }
  1743. function extractComponentsGuards(matched, guardType, to, from, runWithContext = (fn) => fn()) {
  1744. const guards = [];
  1745. for (const record of matched) for (const name in record.components) {
  1746. let rawComponent = record.components[name];
  1747. if (guardType !== "beforeRouteEnter" && !record.instances[name]) continue;
  1748. if (isRouteComponent(rawComponent)) {
  1749. const options = rawComponent.__vccOpts || rawComponent;
  1750. const guard = options[guardType];
  1751. guard && guards.push(guardToPromiseFn(guard, to, from, record, name, runWithContext));
  1752. } else {
  1753. let componentPromise = rawComponent();
  1754. guards.push(() => componentPromise.then((resolved) => {
  1755. if (!resolved) throw new Error(`Couldn't resolve component "${name}" at "${record.path}"`);
  1756. const resolvedComponent = isESModule(resolved) ? resolved.default : resolved;
  1757. record.mods[name] = resolved;
  1758. record.components[name] = resolvedComponent;
  1759. const options = resolvedComponent.__vccOpts || resolvedComponent;
  1760. const guard = options[guardType];
  1761. return guard && guardToPromiseFn(guard, to, from, record, name, runWithContext)();
  1762. }));
  1763. }
  1764. }
  1765. return guards;
  1766. }
  1767. /**
  1768. * Returns the internal behavior of a {@link RouterLink} without the rendering part.
  1769. *
  1770. * @param props - a `to` location and an optional `replace` flag
  1771. */
  1772. function useLink(props) {
  1773. const router = inject(routerKey);
  1774. const currentRoute = inject(routeLocationKey);
  1775. let hasPrevious = false;
  1776. let previousTo = null;
  1777. const route = computed(() => {
  1778. const to = unref(props.to);
  1779. return router.resolve(to);
  1780. });
  1781. const activeRecordIndex = computed(() => {
  1782. const { matched } = route.value;
  1783. const { length } = matched;
  1784. const routeMatched = matched[length - 1];
  1785. const currentMatched = currentRoute.matched;
  1786. if (!routeMatched || !currentMatched.length) return -1;
  1787. const index = currentMatched.findIndex(isSameRouteRecord.bind(null, routeMatched));
  1788. if (index > -1) return index;
  1789. const parentRecordPath = getOriginalPath(matched[length - 2]);
  1790. return length > 1 && getOriginalPath(routeMatched) === parentRecordPath && currentMatched[currentMatched.length - 1].path !== parentRecordPath ? currentMatched.findIndex(isSameRouteRecord.bind(null, matched[length - 2])) : index;
  1791. });
  1792. const isActive = computed(() => activeRecordIndex.value > -1 && includesParams(currentRoute.params, route.value.params));
  1793. const isExactActive = computed(() => activeRecordIndex.value > -1 && activeRecordIndex.value === currentRoute.matched.length - 1 && isSameRouteLocationParams(currentRoute.params, route.value.params));
  1794. function navigate(e = {}) {
  1795. if (guardEvent(e)) {
  1796. const p$1 = router[unref(props.replace) ? "replace" : "push"](
  1797. unref(props.to)
  1798. // avoid uncaught errors are they are logged anyway
  1799. ).catch(noop);
  1800. if (props.viewTransition && typeof document !== "undefined" && "startViewTransition" in document) document.startViewTransition(() => p$1);
  1801. return p$1;
  1802. }
  1803. return Promise.resolve();
  1804. }
  1805. /**
  1806. * NOTE: update {@link _RouterLinkI}'s `$slots` type when updating this
  1807. */
  1808. return {
  1809. route,
  1810. href: computed(() => route.value.href),
  1811. isActive,
  1812. isExactActive,
  1813. navigate
  1814. };
  1815. }
  1816. function preferSingleVNode(vnodes) {
  1817. return vnodes.length === 1 ? vnodes[0] : vnodes;
  1818. }
  1819. const RouterLinkImpl = /* @__PURE__ */ defineComponent({
  1820. name: "RouterLink",
  1821. compatConfig: { MODE: 3 },
  1822. props: {
  1823. to: {
  1824. type: [String, Object],
  1825. required: true
  1826. },
  1827. replace: Boolean,
  1828. activeClass: String,
  1829. exactActiveClass: String,
  1830. custom: Boolean,
  1831. ariaCurrentValue: {
  1832. type: String,
  1833. default: "page"
  1834. },
  1835. viewTransition: Boolean
  1836. },
  1837. useLink,
  1838. setup(props, { slots }) {
  1839. const link = reactive(useLink(props));
  1840. const { options } = inject(routerKey);
  1841. const elClass = computed(() => ({
  1842. [getLinkClass(props.activeClass, options.linkActiveClass, "router-link-active")]: link.isActive,
  1843. [getLinkClass(props.exactActiveClass, options.linkExactActiveClass, "router-link-exact-active")]: link.isExactActive
  1844. }));
  1845. return () => {
  1846. const children = slots.default && preferSingleVNode(slots.default(link));
  1847. return props.custom ? children : h("a", {
  1848. "aria-current": link.isExactActive ? props.ariaCurrentValue : null,
  1849. href: link.href,
  1850. onClick: link.navigate,
  1851. class: elClass.value
  1852. }, children);
  1853. };
  1854. }
  1855. });
  1856. /**
  1857. * Component to render a link that triggers a navigation on click.
  1858. */
  1859. const RouterLink = RouterLinkImpl;
  1860. function guardEvent(e) {
  1861. if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return;
  1862. if (e.defaultPrevented) return;
  1863. if (e.button !== void 0 && e.button !== 0) return;
  1864. if (e.currentTarget && e.currentTarget.getAttribute) {
  1865. const target = e.currentTarget.getAttribute("target");
  1866. if (/\b_blank\b/i.test(target)) return;
  1867. }
  1868. if (e.preventDefault) e.preventDefault();
  1869. return true;
  1870. }
  1871. function includesParams(outer, inner) {
  1872. for (const key in inner) {
  1873. const innerValue = inner[key];
  1874. const outerValue = outer[key];
  1875. if (typeof innerValue === "string") {
  1876. if (innerValue !== outerValue) return false;
  1877. } else if (!isArray$1(outerValue) || outerValue.length !== innerValue.length || innerValue.some((value, i) => value !== outerValue[i])) return false;
  1878. }
  1879. return true;
  1880. }
  1881. /**
  1882. * Get the original path value of a record by following its aliasOf
  1883. * @param record
  1884. */
  1885. function getOriginalPath(record) {
  1886. return record ? record.aliasOf ? record.aliasOf.path : record.path : "";
  1887. }
  1888. /**
  1889. * Utility class to get the active class based on defaults.
  1890. * @param propClass
  1891. * @param globalClass
  1892. * @param defaultClass
  1893. */
  1894. const getLinkClass = (propClass, globalClass, defaultClass) => propClass != null ? propClass : globalClass != null ? globalClass : defaultClass;
  1895. const RouterViewImpl = /* @__PURE__ */ defineComponent({
  1896. name: "RouterView",
  1897. inheritAttrs: false,
  1898. props: {
  1899. name: {
  1900. type: String,
  1901. default: "default"
  1902. },
  1903. route: Object
  1904. },
  1905. compatConfig: { MODE: 3 },
  1906. setup(props, { attrs, slots }) {
  1907. const injectedRoute = inject(routerViewLocationKey);
  1908. const routeToDisplay = computed(() => props.route || injectedRoute.value);
  1909. const injectedDepth = inject(viewDepthKey, 0);
  1910. const depth = computed(() => {
  1911. let initialDepth = unref(injectedDepth);
  1912. const { matched } = routeToDisplay.value;
  1913. let matchedRoute;
  1914. while ((matchedRoute = matched[initialDepth]) && !matchedRoute.components) initialDepth++;
  1915. return initialDepth;
  1916. });
  1917. const matchedRouteRef = computed(() => routeToDisplay.value.matched[depth.value]);
  1918. provide(viewDepthKey, computed(() => depth.value + 1));
  1919. provide(matchedRouteKey, matchedRouteRef);
  1920. provide(routerViewLocationKey, routeToDisplay);
  1921. const viewRef = ref();
  1922. watch(() => [
  1923. viewRef.value,
  1924. matchedRouteRef.value,
  1925. props.name
  1926. ], ([instance, to, name], [oldInstance, from, oldName]) => {
  1927. if (to) {
  1928. to.instances[name] = instance;
  1929. if (from && from !== to && instance && instance === oldInstance) {
  1930. if (!to.leaveGuards.size) to.leaveGuards = from.leaveGuards;
  1931. if (!to.updateGuards.size) to.updateGuards = from.updateGuards;
  1932. }
  1933. }
  1934. if (instance && to && (!from || !isSameRouteRecord(to, from) || !oldInstance)) (to.enterCallbacks[name] || []).forEach((callback) => callback(instance));
  1935. }, { flush: "post" });
  1936. return () => {
  1937. const route = routeToDisplay.value;
  1938. const currentName = props.name;
  1939. const matchedRoute = matchedRouteRef.value;
  1940. const ViewComponent = matchedRoute && matchedRoute.components[currentName];
  1941. if (!ViewComponent) return normalizeSlot(slots.default, {
  1942. Component: ViewComponent,
  1943. route
  1944. });
  1945. const routePropsOption = matchedRoute.props[currentName];
  1946. const routeProps = routePropsOption ? routePropsOption === true ? route.params : typeof routePropsOption === "function" ? routePropsOption(route) : routePropsOption : null;
  1947. const onVnodeUnmounted = (vnode) => {
  1948. if (vnode.component.isUnmounted) matchedRoute.instances[currentName] = null;
  1949. };
  1950. const component = h(ViewComponent, assign({}, routeProps, attrs, {
  1951. onVnodeUnmounted,
  1952. ref: viewRef
  1953. }));
  1954. return normalizeSlot(slots.default, {
  1955. Component: component,
  1956. route
  1957. }) || component;
  1958. };
  1959. }
  1960. });
  1961. function normalizeSlot(slot, data) {
  1962. if (!slot) return null;
  1963. const slotContent = slot(data);
  1964. return slotContent.length === 1 ? slotContent[0] : slotContent;
  1965. }
  1966. /**
  1967. * Component to display the current route the user is at.
  1968. */
  1969. const RouterView = RouterViewImpl;
  1970. /**
  1971. * Creates a Router instance that can be used by a Vue app.
  1972. *
  1973. * @param options - {@link RouterOptions}
  1974. */
  1975. function createRouter(options) {
  1976. const matcher = createRouterMatcher(options.routes, options);
  1977. const parseQuery$1 = options.parseQuery || parseQuery;
  1978. const stringifyQuery$1 = options.stringifyQuery || stringifyQuery;
  1979. const routerHistory = options.history;
  1980. const beforeGuards = useCallbacks();
  1981. const beforeResolveGuards = useCallbacks();
  1982. const afterGuards = useCallbacks();
  1983. const currentRoute = shallowRef(START_LOCATION_NORMALIZED);
  1984. let pendingLocation = START_LOCATION_NORMALIZED;
  1985. if (isBrowser && options.scrollBehavior && "scrollRestoration" in history) history.scrollRestoration = "manual";
  1986. const normalizeParams = applyToParams.bind(null, (paramValue) => "" + paramValue);
  1987. const encodeParams = applyToParams.bind(null, encodeParam);
  1988. const decodeParams = applyToParams.bind(null, decode);
  1989. function addRoute(parentOrRoute, route) {
  1990. let parent;
  1991. let record;
  1992. if (isRouteName(parentOrRoute)) {
  1993. parent = matcher.getRecordMatcher(parentOrRoute);
  1994. record = route;
  1995. } else record = parentOrRoute;
  1996. return matcher.addRoute(record, parent);
  1997. }
  1998. function removeRoute(name) {
  1999. const recordMatcher = matcher.getRecordMatcher(name);
  2000. if (recordMatcher) matcher.removeRoute(recordMatcher);
  2001. }
  2002. function getRoutes() {
  2003. return matcher.getRoutes().map((routeMatcher) => routeMatcher.record);
  2004. }
  2005. function hasRoute(name) {
  2006. return !!matcher.getRecordMatcher(name);
  2007. }
  2008. function resolve(rawLocation, currentLocation) {
  2009. currentLocation = assign({}, currentLocation || currentRoute.value);
  2010. if (typeof rawLocation === "string") {
  2011. const locationNormalized = parseURL(parseQuery$1, rawLocation, currentLocation.path);
  2012. const matchedRoute$1 = matcher.resolve({ path: locationNormalized.path }, currentLocation);
  2013. const href$1 = routerHistory.createHref(locationNormalized.fullPath);
  2014. return assign(locationNormalized, matchedRoute$1, {
  2015. params: decodeParams(matchedRoute$1.params),
  2016. hash: decode(locationNormalized.hash),
  2017. redirectedFrom: void 0,
  2018. href: href$1
  2019. });
  2020. }
  2021. let matcherLocation;
  2022. if (rawLocation.path != null) matcherLocation = assign({}, rawLocation, { path: parseURL(parseQuery$1, rawLocation.path, currentLocation.path).path });
  2023. else {
  2024. const targetParams = assign({}, rawLocation.params);
  2025. for (const key in targetParams) if (targetParams[key] == null) delete targetParams[key];
  2026. matcherLocation = assign({}, rawLocation, { params: encodeParams(targetParams) });
  2027. currentLocation.params = encodeParams(currentLocation.params);
  2028. }
  2029. const matchedRoute = matcher.resolve(matcherLocation, currentLocation);
  2030. const hash = rawLocation.hash || "";
  2031. matchedRoute.params = normalizeParams(decodeParams(matchedRoute.params));
  2032. const fullPath = stringifyURL(stringifyQuery$1, assign({}, rawLocation, {
  2033. hash: encodeHash(hash),
  2034. path: matchedRoute.path
  2035. }));
  2036. const href = routerHistory.createHref(fullPath);
  2037. return assign({
  2038. fullPath,
  2039. hash,
  2040. query: stringifyQuery$1 === stringifyQuery ? normalizeQuery(rawLocation.query) : rawLocation.query || {}
  2041. }, matchedRoute, {
  2042. redirectedFrom: void 0,
  2043. href
  2044. });
  2045. }
  2046. function locationAsObject(to) {
  2047. return typeof to === "string" ? parseURL(parseQuery$1, to, currentRoute.value.path) : assign({}, to);
  2048. }
  2049. function checkCanceledNavigation(to, from) {
  2050. if (pendingLocation !== to) return createRouterError(8, {
  2051. from,
  2052. to
  2053. });
  2054. }
  2055. function push(to) {
  2056. return pushWithRedirect(to);
  2057. }
  2058. function replace(to) {
  2059. return push(assign(locationAsObject(to), { replace: true }));
  2060. }
  2061. function handleRedirectRecord(to) {
  2062. const lastMatched = to.matched[to.matched.length - 1];
  2063. if (lastMatched && lastMatched.redirect) {
  2064. const { redirect } = lastMatched;
  2065. let newTargetLocation = typeof redirect === "function" ? redirect(to) : redirect;
  2066. if (typeof newTargetLocation === "string") {
  2067. newTargetLocation = newTargetLocation.includes("?") || newTargetLocation.includes("#") ? newTargetLocation = locationAsObject(newTargetLocation) : { path: newTargetLocation };
  2068. newTargetLocation.params = {};
  2069. }
  2070. return assign({
  2071. query: to.query,
  2072. hash: to.hash,
  2073. params: newTargetLocation.path != null ? {} : to.params
  2074. }, newTargetLocation);
  2075. }
  2076. }
  2077. function pushWithRedirect(to, redirectedFrom) {
  2078. const targetLocation = pendingLocation = resolve(to);
  2079. const from = currentRoute.value;
  2080. const data = to.state;
  2081. const force = to.force;
  2082. const replace$1 = to.replace === true;
  2083. const shouldRedirect = handleRedirectRecord(targetLocation);
  2084. if (shouldRedirect) return pushWithRedirect(
  2085. assign(locationAsObject(shouldRedirect), {
  2086. state: typeof shouldRedirect === "object" ? assign({}, data, shouldRedirect.state) : data,
  2087. force,
  2088. replace: replace$1
  2089. }),
  2090. // keep original redirectedFrom if it exists
  2091. redirectedFrom || targetLocation
  2092. );
  2093. const toLocation = targetLocation;
  2094. toLocation.redirectedFrom = redirectedFrom;
  2095. let failure;
  2096. if (!force && isSameRouteLocation(stringifyQuery$1, from, targetLocation)) {
  2097. failure = createRouterError(16, {
  2098. to: toLocation,
  2099. from
  2100. });
  2101. handleScroll(
  2102. from,
  2103. from,
  2104. // this is a push, the only way for it to be triggered from a
  2105. // history.listen is with a redirect, which makes it become a push
  2106. true,
  2107. // This cannot be the first navigation because the initial location
  2108. // cannot be manually navigated to
  2109. false
  2110. );
  2111. }
  2112. return (failure ? Promise.resolve(failure) : navigate(toLocation, from)).catch((error) => isNavigationFailure(error) ? isNavigationFailure(
  2113. error,
  2114. 2
  2115. /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */
  2116. ) ? error : markAsReady(error) : triggerError(error, toLocation, from)).then((failure$1) => {
  2117. if (failure$1) {
  2118. if (isNavigationFailure(
  2119. failure$1,
  2120. 2
  2121. /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */
  2122. )) return pushWithRedirect(
  2123. // keep options
  2124. assign({ replace: replace$1 }, locationAsObject(failure$1.to), {
  2125. state: typeof failure$1.to === "object" ? assign({}, data, failure$1.to.state) : data,
  2126. force
  2127. }),
  2128. // preserve the original redirectedFrom if any
  2129. redirectedFrom || toLocation
  2130. );
  2131. } else failure$1 = finalizeNavigation(toLocation, from, true, replace$1, data);
  2132. triggerAfterEach(toLocation, from, failure$1);
  2133. return failure$1;
  2134. });
  2135. }
  2136. /**
  2137. * Helper to reject and skip all navigation guards if a new navigation happened
  2138. * @param to
  2139. * @param from
  2140. */
  2141. function checkCanceledNavigationAndReject(to, from) {
  2142. const error = checkCanceledNavigation(to, from);
  2143. return error ? Promise.reject(error) : Promise.resolve();
  2144. }
  2145. function runWithContext(fn) {
  2146. const app = installedApps.values().next().value;
  2147. return app && typeof app.runWithContext === "function" ? app.runWithContext(fn) : fn();
  2148. }
  2149. function navigate(to, from) {
  2150. let guards;
  2151. const [leavingRecords, updatingRecords, enteringRecords] = extractChangingRecords(to, from);
  2152. guards = extractComponentsGuards(leavingRecords.reverse(), "beforeRouteLeave", to, from);
  2153. for (const record of leavingRecords) record.leaveGuards.forEach((guard) => {
  2154. guards.push(guardToPromiseFn(guard, to, from));
  2155. });
  2156. const canceledNavigationCheck = checkCanceledNavigationAndReject.bind(null, to, from);
  2157. guards.push(canceledNavigationCheck);
  2158. return runGuardQueue(guards).then(() => {
  2159. guards = [];
  2160. for (const guard of beforeGuards.list()) guards.push(guardToPromiseFn(guard, to, from));
  2161. guards.push(canceledNavigationCheck);
  2162. return runGuardQueue(guards);
  2163. }).then(() => {
  2164. guards = extractComponentsGuards(updatingRecords, "beforeRouteUpdate", to, from);
  2165. for (const record of updatingRecords) record.updateGuards.forEach((guard) => {
  2166. guards.push(guardToPromiseFn(guard, to, from));
  2167. });
  2168. guards.push(canceledNavigationCheck);
  2169. return runGuardQueue(guards);
  2170. }).then(() => {
  2171. guards = [];
  2172. for (const record of enteringRecords) if (record.beforeEnter) if (isArray$1(record.beforeEnter)) for (const beforeEnter of record.beforeEnter) guards.push(guardToPromiseFn(beforeEnter, to, from));
  2173. else guards.push(guardToPromiseFn(record.beforeEnter, to, from));
  2174. guards.push(canceledNavigationCheck);
  2175. return runGuardQueue(guards);
  2176. }).then(() => {
  2177. to.matched.forEach((record) => record.enterCallbacks = {});
  2178. guards = extractComponentsGuards(enteringRecords, "beforeRouteEnter", to, from, runWithContext);
  2179. guards.push(canceledNavigationCheck);
  2180. return runGuardQueue(guards);
  2181. }).then(() => {
  2182. guards = [];
  2183. for (const guard of beforeResolveGuards.list()) guards.push(guardToPromiseFn(guard, to, from));
  2184. guards.push(canceledNavigationCheck);
  2185. return runGuardQueue(guards);
  2186. }).catch((err) => isNavigationFailure(
  2187. err,
  2188. 8
  2189. /* ErrorTypes.NAVIGATION_CANCELLED */
  2190. ) ? err : Promise.reject(err));
  2191. }
  2192. function triggerAfterEach(to, from, failure) {
  2193. afterGuards.list().forEach((guard) => runWithContext(() => guard(to, from, failure)));
  2194. }
  2195. /**
  2196. * - Cleans up any navigation guards
  2197. * - Changes the url if necessary
  2198. * - Calls the scrollBehavior
  2199. */
  2200. function finalizeNavigation(toLocation, from, isPush, replace$1, data) {
  2201. const error = checkCanceledNavigation(toLocation, from);
  2202. if (error) return error;
  2203. const isFirstNavigation = from === START_LOCATION_NORMALIZED;
  2204. const state = !isBrowser ? {} : history.state;
  2205. if (isPush) if (replace$1 || isFirstNavigation) routerHistory.replace(toLocation.fullPath, assign({ scroll: isFirstNavigation && state && state.scroll }, data));
  2206. else routerHistory.push(toLocation.fullPath, data);
  2207. currentRoute.value = toLocation;
  2208. handleScroll(toLocation, from, isPush, isFirstNavigation);
  2209. markAsReady();
  2210. }
  2211. let removeHistoryListener;
  2212. function setupListeners() {
  2213. if (removeHistoryListener) return;
  2214. removeHistoryListener = routerHistory.listen((to, _from, info) => {
  2215. if (!router.listening) return;
  2216. const toLocation = resolve(to);
  2217. const shouldRedirect = handleRedirectRecord(toLocation);
  2218. if (shouldRedirect) {
  2219. pushWithRedirect(assign(shouldRedirect, {
  2220. replace: true,
  2221. force: true
  2222. }), toLocation).catch(noop);
  2223. return;
  2224. }
  2225. pendingLocation = toLocation;
  2226. const from = currentRoute.value;
  2227. if (isBrowser) saveScrollPosition(getScrollKey(from.fullPath, info.delta), computeScrollPosition());
  2228. navigate(toLocation, from).catch((error) => {
  2229. if (isNavigationFailure(
  2230. error,
  2231. 12
  2232. /* ErrorTypes.NAVIGATION_CANCELLED */
  2233. )) return error;
  2234. if (isNavigationFailure(
  2235. error,
  2236. 2
  2237. /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */
  2238. )) {
  2239. pushWithRedirect(
  2240. assign(locationAsObject(error.to), { force: true }),
  2241. toLocation
  2242. // avoid an uncaught rejection, let push call triggerError
  2243. ).then((failure) => {
  2244. if (isNavigationFailure(
  2245. failure,
  2246. 20
  2247. /* ErrorTypes.NAVIGATION_DUPLICATED */
  2248. ) && !info.delta && info.type === NavigationType.pop) routerHistory.go(-1, false);
  2249. }).catch(noop);
  2250. return Promise.reject();
  2251. }
  2252. if (info.delta) routerHistory.go(-info.delta, false);
  2253. return triggerError(error, toLocation, from);
  2254. }).then((failure) => {
  2255. failure = failure || finalizeNavigation(
  2256. // after navigation, all matched components are resolved
  2257. toLocation,
  2258. from,
  2259. false
  2260. );
  2261. if (failure) {
  2262. if (info.delta && !isNavigationFailure(
  2263. failure,
  2264. 8
  2265. /* ErrorTypes.NAVIGATION_CANCELLED */
  2266. )) routerHistory.go(-info.delta, false);
  2267. else if (info.type === NavigationType.pop && isNavigationFailure(
  2268. failure,
  2269. 20
  2270. /* ErrorTypes.NAVIGATION_DUPLICATED */
  2271. )) routerHistory.go(-1, false);
  2272. }
  2273. triggerAfterEach(toLocation, from, failure);
  2274. }).catch(noop);
  2275. });
  2276. }
  2277. let readyHandlers = useCallbacks();
  2278. let errorListeners = useCallbacks();
  2279. let ready;
  2280. /**
  2281. * Trigger errorListeners added via onError and throws the error as well
  2282. *
  2283. * @param error - error to throw
  2284. * @param to - location we were navigating to when the error happened
  2285. * @param from - location we were navigating from when the error happened
  2286. * @returns the error as a rejected promise
  2287. */
  2288. function triggerError(error, to, from) {
  2289. markAsReady(error);
  2290. const list = errorListeners.list();
  2291. if (list.length) list.forEach((handler) => handler(error, to, from));
  2292. else console.error(error);
  2293. return Promise.reject(error);
  2294. }
  2295. function isReady() {
  2296. if (ready && currentRoute.value !== START_LOCATION_NORMALIZED) return Promise.resolve();
  2297. return new Promise((resolve$1, reject) => {
  2298. readyHandlers.add([resolve$1, reject]);
  2299. });
  2300. }
  2301. function markAsReady(err) {
  2302. if (!ready) {
  2303. ready = !err;
  2304. setupListeners();
  2305. readyHandlers.list().forEach(([resolve$1, reject]) => err ? reject(err) : resolve$1());
  2306. readyHandlers.reset();
  2307. }
  2308. return err;
  2309. }
  2310. function handleScroll(to, from, isPush, isFirstNavigation) {
  2311. const { scrollBehavior } = options;
  2312. if (!isBrowser || !scrollBehavior) return Promise.resolve();
  2313. const scrollPosition = !isPush && getSavedScrollPosition(getScrollKey(to.fullPath, 0)) || (isFirstNavigation || !isPush) && history.state && history.state.scroll || null;
  2314. return nextTick().then(() => scrollBehavior(to, from, scrollPosition)).then((position) => position && scrollToPosition(position)).catch((err) => triggerError(err, to, from));
  2315. }
  2316. const go = (delta) => routerHistory.go(delta);
  2317. let started;
  2318. const installedApps = new Set();
  2319. const router = {
  2320. currentRoute,
  2321. listening: true,
  2322. addRoute,
  2323. removeRoute,
  2324. clearRoutes: matcher.clearRoutes,
  2325. hasRoute,
  2326. getRoutes,
  2327. resolve,
  2328. options,
  2329. push,
  2330. replace,
  2331. go,
  2332. back: () => go(-1),
  2333. forward: () => go(1),
  2334. beforeEach: beforeGuards.add,
  2335. beforeResolve: beforeResolveGuards.add,
  2336. afterEach: afterGuards.add,
  2337. onError: errorListeners.add,
  2338. isReady,
  2339. install(app) {
  2340. const router$1 = this;
  2341. app.component("RouterLink", RouterLink);
  2342. app.component("RouterView", RouterView);
  2343. app.config.globalProperties.$router = router$1;
  2344. Object.defineProperty(app.config.globalProperties, "$route", {
  2345. enumerable: true,
  2346. get: () => unref(currentRoute)
  2347. });
  2348. if (isBrowser && !started && currentRoute.value === START_LOCATION_NORMALIZED) {
  2349. started = true;
  2350. push(routerHistory.location).catch((err) => {});
  2351. }
  2352. const reactiveRoute = {};
  2353. for (const key in START_LOCATION_NORMALIZED) Object.defineProperty(reactiveRoute, key, {
  2354. get: () => currentRoute.value[key],
  2355. enumerable: true
  2356. });
  2357. app.provide(routerKey, router$1);
  2358. app.provide(routeLocationKey, shallowReactive(reactiveRoute));
  2359. app.provide(routerViewLocationKey, currentRoute);
  2360. const unmountApp = app.unmount;
  2361. installedApps.add(app);
  2362. app.unmount = function() {
  2363. installedApps.delete(app);
  2364. if (installedApps.size < 1) {
  2365. pendingLocation = START_LOCATION_NORMALIZED;
  2366. removeHistoryListener && removeHistoryListener();
  2367. removeHistoryListener = null;
  2368. currentRoute.value = START_LOCATION_NORMALIZED;
  2369. started = false;
  2370. ready = false;
  2371. }
  2372. unmountApp();
  2373. };
  2374. }
  2375. };
  2376. function runGuardQueue(guards) {
  2377. return guards.reduce((promise, guard) => promise.then(() => runWithContext(guard)), Promise.resolve());
  2378. }
  2379. return router;
  2380. }
  2381. function extractChangingRecords(to, from) {
  2382. const leavingRecords = [];
  2383. const updatingRecords = [];
  2384. const enteringRecords = [];
  2385. const len = Math.max(from.matched.length, to.matched.length);
  2386. for (let i = 0; i < len; i++) {
  2387. const recordFrom = from.matched[i];
  2388. if (recordFrom) if (to.matched.find((record) => isSameRouteRecord(record, recordFrom))) updatingRecords.push(recordFrom);
  2389. else leavingRecords.push(recordFrom);
  2390. const recordTo = to.matched[i];
  2391. if (recordTo) {
  2392. if (!from.matched.find((record) => isSameRouteRecord(record, recordTo))) enteringRecords.push(recordTo);
  2393. }
  2394. }
  2395. return [
  2396. leavingRecords,
  2397. updatingRecords,
  2398. enteringRecords
  2399. ];
  2400. }
  2401. /**
  2402. * Returns the router instance. Equivalent to using `$router` inside
  2403. * templates.
  2404. */
  2405. function useRouter() {
  2406. return inject(routerKey);
  2407. }
  2408. /**
  2409. * Returns the current route location. Equivalent to using `$route` inside
  2410. * templates.
  2411. */
  2412. function useRoute(_name) {
  2413. return inject(routeLocationKey);
  2414. }
  2415. export { createApp, createRouter, createWebHashHistory, useRoute, useRouter, vModelCheckbox, vModelText, vShow, withKeys };