forked from molefrog/wouter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmatcher.js
66 lines (51 loc) · 2.02 KB
/
matcher.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// creates a matcher function
export default function makeMatcher(makeRegexpFn = pathToRegexp) {
let cache = {};
// obtains a cached regexp version of the pattern
const getRegexp = pattern =>
(cache[pattern]) || (cache[pattern] = makeRegexpFn(pattern));
return (pattern, path) => {
const { regexp, keys } = getRegexp(pattern || "");
const out = regexp.exec(path);
if (!out) return [false, null];
// formats an object with matched params
const params = keys.reduce((params, key, i) => {
params[key.name] = out[i + 1];
return params;
}, {});
return [true, params];
};
}
// escapes a regexp string (borrowed from path-to-regexp sources)
// https://github.com/pillarjs/path-to-regexp/blob/v3.0.0/index.js#L202
const escapeRx = str => str.replace(/([.+*?=^!:${}()[\]|/\\])/g, "\\$1");
// returns a segment representation in RegExp based on flags
// adapted and simplified version from path-to-regexp sources
const rxForSegment = (repeat, optional, prefix) => {
let capture = repeat ? "((?:[^\\/]+?)(?:\\/(?:[^\\/]+?))*)" : "([^\\/]+?)";
if (optional && prefix) capture = "(?:\\/" + capture + ")";
return capture + (optional ? "?" : "");
};
const pathToRegexp = pattern => {
const groupRx = /:([A-Za-z0-9_]+)([?+*]?)/g;
let match = null,
lastIndex = 0,
keys = [],
result = "";
while ((match = groupRx.exec(pattern)) !== null) {
const [_, segment, mod] = match;
// :foo [1] ( )
// :foo? [0 - 1] ( o)
// :foo+ [1 - ∞] (r )
// :foo* [0 - ∞] (ro)
const repeat = mod === "+" || mod === "*";
const optional = mod === "?" || mod === "*";
const prefix = optional && pattern[match.index - 1] === "/" ? 1 : 0;
const prev = pattern.substring(lastIndex, match.index - prefix);
keys.push({ name: segment });
lastIndex = groupRx.lastIndex;
result += escapeRx(prev) + rxForSegment(repeat, optional, prefix);
}
result += escapeRx(pattern.substring(lastIndex));
return { keys, regexp: new RegExp("^" + result + "(?:\\/)?$", "i") };
};