UNPKG

4 kBJavaScriptView Raw
1import './chunk/constants.js';
2import './chunk/utils.js';
3import { useState, useEffect } from './core.js';
4
5/**
6 * @return {string} pathname
7 */
8function getPathname() {
9 return location.pathname;
10}
11/**
12 * Dispatch history a new pathname
13 * @type {Redirect}
14 */
15function redirect(pathname) {
16 if (pathname == getPathname()) return;
17 history.pushState({}, "history", pathname);
18 window.dispatchEvent(new PopStateEvent("popstate"));
19}
20
21function subscribe(handler) {
22 window.addEventListener("popstate", handler);
23 return () => window.removeEventListener("popstate", handler);
24}
25
26const FOLDERS = /([^\/]+)/g;
27const FOLDER = "[^\\/]";
28const SPLIT = "(?:\\/){0,1}";
29const PARAM = /^(:)(\w+)(\?|(\.){3}){0,1}/;
30const PARAMS_EMPTY = {};
31const MEMO = {};
32
33function format(path) {
34 return path.replace(/(\/){2,}/g, "/").replace(/([^\/]+)\/$/, "$1");
35}
36
37function parse(string) {
38 let folders = string.match(FOLDERS) || [""];
39 let params = [];
40 let regexp = new RegExp(
41 "^" +
42 folders
43 .map(folder => {
44 let [string, param, field, type] =
45 folder.match(PARAM) || [];
46 if (param) {
47 params.push(field);
48 if (type === "...") {
49 return `(.*)`;
50 } else if (type === "?") {
51 return `${SPLIT}(${FOLDER}*)`;
52 } else {
53 return `\\/(${FOLDER}+)`;
54 }
55 } else {
56 return `\\/(?:${folder
57 .replace(/(\.|\-)/g, "\\$1")
58 .replace(/\*/g, FOLDER + "+")
59 .replace(/\((?!\?\:)/g, "(?:")})`;
60 }
61 })
62 .join("") +
63 "$",
64 "i"
65 );
66
67 return { regexp, params, logs: {} };
68}
69/**
70 * permite comparar un patron de captura vs un ruta de entrada
71 * @param {string} path - ruta de patron de captura
72 * @param {string} value - ruta de comparacion a patron
73 * @return {array} - [ inRoute:boolean, params:object ];
74 */
75function match(path, value) {
76 path = format(path);
77 value = format(value);
78 if (!MEMO[path]) {
79 MEMO[path] = parse(path);
80 }
81 let { regexp, params, logs } = MEMO[path];
82 if (logs[value]) {
83 return logs[value];
84 }
85 let vs = value.match(regexp);
86 return (logs[value] = [
87 vs ? true : false,
88 vs
89 ? vs.slice(1).reduce((next, value, index) => {
90 next[params[index] || index] = value;
91 return next;
92 }, {})
93 : PARAMS_EMPTY
94 ]);
95}
96
97let cachePathCallback = {};
98
99function useHistory() {
100 let pathname = getPathname();
101 let [state, setState] = useState({ pathname });
102
103 useEffect(() => {
104 function handler() {
105 let pathname = getPathname();
106 setState(state =>
107 state.pathname != pathname ? { pathname } : state
108 );
109 }
110 return subscribe(handler);
111 }, []);
112 return [pathname, redirect];
113}
114
115function useMatchRoute(path) {
116 return match(path, getPathname());
117}
118
119function useRoute(path) {
120 useHistory();
121 return useMatchRoute(path);
122}
123
124function useRedirect(path) {
125 return (cachePathCallback[path] =
126 cachePathCallback[path] || (() => redirect(path)));
127}
128
129function useRouter(cases) {
130 let def = "default";
131 let [pathname] = useHistory();
132 for (let key in cases) {
133 if (key != def) {
134 let [status, params] = match(key, pathname);
135 if (status) return cases[key](params);
136 }
137 }
138 return cases[def]();
139}
140
141export { useHistory, useMatchRoute, useRedirect, useRoute, useRouter };
142//# sourceMappingURL=use-router.js.map