git.fiddlerwoaroof.com
Browse code

Refactor, fix edge case in previous commit

Ed Langley authored on 16/06/2017 00:33:18
Showing 1 changed files
... ...
@@ -40,25 +40,17 @@ function matchRoute(loc, matchers) {
40 40
 
41 41
   const buildMatch = (extractedParams, route) => Object.assign({extractedParams}, route);
42 42
 
43
-  let match = null;
44
-  for (const path in matchers) {
45
-    const {type: matcherType, route} = matchers[path];
43
+  return R.toPairs(matchers).reduce((match, [path,{type: matcherType, route}]) => {
46 44
     const pathMatcher = route.routeMatcher;
47
-
48 45
     const matchedParams = pathMatcher(inputPath);
49 46
 
50
-    if (pathMatcher(inputPath)) {
51
-      if (matcherType === 'exact') {
52
-        match = buildMatch(matchedParams, route);
53
-        break;
54
-      } else {
55
-        match = mostSpecificRouteMatch(match, buildMatch(matchedParams, route));
56
-      }
47
+    if (matchedParams) {
48
+      return (matcherType === 'exact')? buildMatch(matchedParams, route) : mostSpecificRouteMatch(match, buildMatch(matchedParams, route));
49
+    } else {
50
+      return match;
57 51
     }
58
-  }
59
-
60
-  return match;
61 52
 
53
+  }, null);
62 54
 }
63 55
 
64 56
 function mostSpecificActionMatch(match1, match2) {
... ...
@@ -67,9 +59,8 @@ function mostSpecificActionMatch(match1, match2) {
67 59
     return match2;
68 60
   }
69 61
 
70
-  const {extraParams: match1params} = match1;
71
-  const {extraParams: match2params} = match2;
72
-  return Object.keys(match1params).length >= Object.keys(match2params).length ? match1 : match2;
62
+  let countExtraParams = ({extraParams: obj}) => Object.keys(obj).length;
63
+  return countExtraParams(match1) >= countExtraParams(match2) ? match1 : match2;
73 64
 }
74 65
 
75 66
 // matchers is {action : [routeMatcher]} structure
... ...
@@ -77,8 +68,8 @@ function matchAction(action, matchers) {
77 68
   // match on params in action vs possible actions if more than 1
78 69
   let match = null;
79 70
 
80
-  const {type, ...args} = action;
81
-  const routes = matchers[type];
71
+  const {type: actionType, ...args} = action;
72
+  const routes = matchers[actionType];
82 73
 
83 74
   // Specificity:
84 75
   // 1. wildcard(s) / no extra param   /route/:id  || /route/me
... ...
@@ -96,8 +87,9 @@ function matchAction(action, matchers) {
96 87
       const unallocatedArgKeys = R.difference(Object.keys(args), Object.keys(route.extraParams));
97 88
       // if all keys ^ are equal to all keys in route
98 89
       const intersectCount = R.intersection(unallocatedArgKeys, route.routeParams).length;
90
+      const unionCount = R.union(unallocatedArgKeys, route.routeParams).length;
99 91
 
100
-      if (intersectCount === route.routeParams.length && intersectCount === unallocatedArgKeys.length) {
92
+      if (intersectCount === unionCount) {
101 93
         const extractedParams = R.pick(unallocatedArgKeys, args);
102 94
         match = mostSpecificActionMatch(match, Object.assign({extractedParams}, route));
103 95
       }
... ...
@@ -111,20 +103,21 @@ function matchesAction(action, matchers) {
111 103
   return !!matchers[action.type];
112 104
 }
113 105
 
106
+function isWildcard(segment) {
107
+  return segment && segment[0] === ":";
108
+}
114 109
 function extractParams(path) {
115 110
   const pathParts = path.split("/");
116 111
   let params = [];
117 112
 
118
-  for (const part of pathParts) {
119
-    if (part[0] === ":") {
120
-      const name = part.slice(1);
121
-
122
-      if (params.indexOf(name) !== -1) {
123
-        throw new Error("duplicate param");
124
-      }
113
+  for (const part of pathParts.filter(isWildcard)) {
114
+    const name = part.slice(1);
125 115
 
126
-      params.push(name);
116
+    if (params.indexOf(name) !== -1) {
117
+      throw new Error("duplicate param");
127 118
     }
119
+
120
+    params.push(name);
128 121
   }
129 122
 
130 123
   return params;
... ...
@@ -136,7 +129,6 @@ function normalizePathParts(path) {
136 129
   return normalizedPathParts;
137 130
 }
138 131
 
139
-
140 132
 function makeRoute(path, action, extraParams) {
141 133
 
142 134
   let type = "exact";
... ...
@@ -146,36 +138,43 @@ function makeRoute(path, action, extraParams) {
146 138
 
147 139
   const normalizedPathParts = normalizePathParts(path);
148 140
 
141
+  const updateWildcard = (wildcards, match, input) => {
142
+    const wildcardName = match.replace(':', '');
143
+    return Object.assign(wildcards, {[wildcardName]: input});
144
+  }
145
+
149 146
   const routeMatcher = function (inputPath) {
147
+    let result = null;
150 148
     const normMatchPath = normalizedPathParts;
151 149
     const normInputPath = normalizePathParts(inputPath);
152 150
 
151
+    // exact match
153 152
     if (R.equals(normalizedPathParts, normInputPath)) {
154 153
       return {};
155 154
     }
156 155
 
156
+    //wildcard match
157 157
     const inputLength = normInputPath.length;
158 158
     const matchLength = normMatchPath.length;
159 159
 
160
-    if (inputLength !== matchLength) {
161
-      return false;
160
+    if (inputLength === matchLength) {
161
+      const f = (acc, [match, input]) => {
162
+        if (acc === null) {
163
+          return null;
164
+        }
165
+
166
+        if(match === input) {
167
+          return acc
168
+        } else if (match[0] === ":") {
169
+          return updateWildcard(acc, match, input);
170
+        } else {
171
+          return null;
172
+        }
173
+      };
174
+      result = R.zip(normMatchPath, normInputPath).reduce(f, {})
162 175
     }
163 176
 
164
-    const f = (acc, [match, input]) => {
165
-      if (acc === null) {
166
-        return null;
167
-      }
168
-      if (R.head(match) === ":") {
169
-        acc[match.replace(':', '')] = input;
170
-        return acc;
171
-      } else if (match === input) {
172
-        return acc;
173
-      } else {
174
-        return null;
175
-      }
176
-    };
177
-
178
-    return R.reduce(f, {}, R.zip(normMatchPath, normInputPath))
177
+    return result;
179 178
   };
180 179
 
181 180