Browse code
Refactoring
Showing 3 changed files
... | ... |
@@ -11,8 +11,9 @@ function mostSpecificRouteMatch(match1, match2) { |
11 | 11 |
|
12 | 12 |
const paramLength1 = match1.routeParams.length; |
13 | 13 |
const paramLength2 = match2.routeParams.length; |
14 |
+ |
|
14 | 15 |
let findWildcard = R.compose( |
15 |
- R.findIndex.bind(R, isWildcard), |
|
16 |
+ R.findIndex(isWildcard), |
|
16 | 17 |
pathSplit |
17 | 18 |
); |
18 | 19 |
|
... | ... |
@@ -39,8 +40,7 @@ function mostSpecificRouteMatch(match1, match2) { |
39 | 40 |
function matchRoute(loc, matchers) { |
40 | 41 |
const inputPath = loc.pathname; |
41 | 42 |
|
42 |
- const buildMatch = (extractedParams, route) => |
|
43 |
- Object.assign({ extractedParams }, route); |
|
43 |
+ const buildMatch = (extractedParams, route) => ({ extractedParams, ...route }); |
|
44 | 44 |
|
45 | 45 |
return R.toPairs(matchers).reduce( |
46 | 46 |
(match, [_, { type: matcherType, route }]) => { |
... | ... |
@@ -69,7 +69,7 @@ function mostSpecificActionMatch(match1, match2) { |
69 | 69 |
return match2; |
70 | 70 |
} |
71 | 71 |
|
72 |
- let countExtraParams = ({ extraParams: obj }) => Object.keys(obj).length; |
|
72 |
+ let countExtraParams = ({ extraParams: obj }) => R.keys(obj).length; |
|
73 | 73 |
return countExtraParams(match1) >= countExtraParams(match2) ? match1 : match2; |
74 | 74 |
} |
75 | 75 |
|
... | ... |
@@ -88,15 +88,15 @@ function matchAction(action, matchers) { |
88 | 88 |
|
89 | 89 |
for (const { type: matcherType, route } of routes) { |
90 | 90 |
if (matcherType === "exact" && R.equals(route.extraParams, args)) { |
91 |
- match = Object.assign({ extractedParams: {} }, route); |
|
91 |
+ match = { extractedParams: {}, ...route}; |
|
92 | 92 |
// case 3 |
93 | 93 |
break; // most specific |
94 | 94 |
} else if (matcherType === "wildcard") { |
95 | 95 |
// case 1+2 |
96 | 96 |
|
97 | 97 |
const unallocatedArgKeys = R.difference( |
98 |
- Object.keys(args), |
|
99 |
- Object.keys(route.extraParams) |
|
98 |
+ R.keys(args), |
|
99 |
+ R.keys(route.extraParams) |
|
100 | 100 |
); |
101 | 101 |
// if all keys ^ are equal to all keys in route |
102 | 102 |
const intersectCount = R.intersection( |
... | ... |
@@ -109,7 +109,7 @@ function matchAction(action, matchers) { |
109 | 109 |
const extractedParams = R.pick(unallocatedArgKeys, args); |
110 | 110 |
match = mostSpecificActionMatch( |
111 | 111 |
match, |
112 |
- Object.assign({ extractedParams }, route) |
|
112 |
+ { extractedParams, ...route } |
|
113 | 113 |
); |
114 | 114 |
} |
115 | 115 |
} |
... | ... |
@@ -143,26 +143,27 @@ function extractParams(path) { |
143 | 143 |
} |
144 | 144 |
|
145 | 145 |
function normalizePathParts(path) { |
146 |
- const rawPathParts = R.split("/", path); |
|
147 |
- const normalizedPathParts = R.filter(p => p !== "", rawPathParts); |
|
148 |
- return normalizedPathParts; |
|
146 |
+ const splitAndFilterEmpty = R.pipe( |
|
147 |
+ R.split('/'), |
|
148 |
+ R.filter(p => p !== "") |
|
149 |
+ ); |
|
150 |
+ |
|
151 |
+ return splitAndFilterEmpty(path); |
|
149 | 152 |
} |
150 | 153 |
|
151 | 154 |
function makeRoute(path, action, extraParams) { |
152 |
- let type = "exact"; |
|
153 |
- if (path.indexOf(":") !== -1) { |
|
154 |
- type = "wildcard"; |
|
155 |
- } |
|
155 |
+ const type = (R.includes(':', path) ? 'wildcard': 'exact'); |
|
156 | 156 |
|
157 | 157 |
const normalizedPathParts = normalizePathParts(path); |
158 | 158 |
|
159 | 159 |
const updateWildcard = (wildcards, match, input) => { |
160 | 160 |
const wildcardName = match.replace(":", ""); |
161 |
- return Object.assign(wildcards, { [wildcardName]: input }); |
|
161 |
+ return {...wildcards, [wildcardName]: input}; |
|
162 | 162 |
}; |
163 | 163 |
|
164 | 164 |
const routeMatcher = function(inputPath) { |
165 | 165 |
let result = null; |
166 |
+ |
|
166 | 167 |
const normMatchPath = normalizedPathParts; |
167 | 168 |
const normInputPath = normalizePathParts(inputPath); |
168 | 169 |
|
... | ... |
@@ -230,7 +231,7 @@ function routeAlreadyExists(compiledRouteMatchers, path) { |
230 | 231 |
); |
231 | 232 |
const pathParts = normalizingSplit(path); |
232 | 233 |
|
233 |
- for (const otherPath of Object.keys(compiledRouteMatchers)) { |
|
234 |
+ for (const otherPath of R.keys(compiledRouteMatchers)) { |
|
234 | 235 |
const otherPathParts = normalizingSplit(otherPath); |
235 | 236 |
if (R.equals(pathParts, otherPathParts)) { |
236 | 237 |
throw new Error( |
... | ... |
@@ -244,8 +245,8 @@ function routeAlreadyExists(compiledRouteMatchers, path) { |
244 | 245 |
} |
245 | 246 |
|
246 | 247 |
function compileRoutes(routesConfig) { |
247 |
- let compiledActionMatchers = {}; |
|
248 |
- let compiledRouteMatchers = {}; |
|
248 |
+ const compiledActionMatchers = {}; |
|
249 |
+ const compiledRouteMatchers = {}; |
|
249 | 250 |
|
250 | 251 |
for (let [path, action, extraParams] of routesConfig) { |
251 | 252 |
if (typeof path !== "string" || typeof action !== "string") { |
... | ... |
@@ -305,26 +306,37 @@ function createActionDispatcher(routesConfig, window) { |
305 | 306 |
return match ? constructPath(match) : null; |
306 | 307 |
} |
307 | 308 |
|
309 |
+ function actionForLocation(location) { |
|
310 |
+ const match = matchRoute(location, compiledRouteMatchers); |
|
311 |
+ return match ? constructAction(match) : null; |
|
312 |
+ } |
|
313 |
+ |
|
308 | 314 |
let actionDispatcher = { |
309 | 315 |
currentLocation: null, |
310 |
- |
|
311 | 316 |
store: null, |
317 |
+ |
|
312 | 318 |
activateDispatcher(store) { |
313 | 319 |
window.addEventListener("urlchanged", this); |
314 | 320 |
this.store = store; |
315 | 321 |
}, |
322 |
+ |
|
316 | 323 |
enhanceStore(nextStoreCreator) { |
317 | 324 |
let middleware = buildMiddleware(this); |
325 |
+ |
|
318 | 326 |
return (reducer, finalInitialState, enhancer) => { |
319 | 327 |
let theStore = nextStoreCreator(reducer, finalInitialState, enhancer); |
328 |
+ |
|
320 | 329 |
this.activateDispatcher(theStore); |
330 |
+ |
|
321 | 331 |
theStore.pathForAction = pathForAction; |
332 |
+ |
|
322 | 333 |
theStore.dispatch = middleware(theStore)( |
323 | 334 |
theStore.dispatch.bind(theStore) |
324 | 335 |
); |
325 | 336 |
return theStore; |
326 | 337 |
}; |
327 | 338 |
}, |
339 |
+ |
|
328 | 340 |
handleEvent(ev) { |
329 | 341 |
if (!this.store) { |
330 | 342 |
throw new Error( |
... | ... |
@@ -337,31 +349,27 @@ function createActionDispatcher(routesConfig, window) { |
337 | 349 |
}, |
338 | 350 |
|
339 | 351 |
onLocationChanged(newLoc, cb) { |
340 |
- let result = undefined; |
|
341 |
- |
|
342 | 352 |
if (this.currentLocation !== newLoc) { |
343 | 353 |
this.currentLocation = newLoc; |
344 |
- result = cb(); |
|
354 |
+ cb(); |
|
345 | 355 |
} |
346 |
- |
|
347 |
- return result; |
|
348 | 356 |
}, |
349 | 357 |
|
350 | 358 |
receiveLocation(location) { |
351 | 359 |
this.onLocationChanged(location.pathname, () => { |
352 |
- const match = matchRoute(location, compiledRouteMatchers); |
|
353 |
- if (match) { |
|
354 |
- const action = constructAction(match); |
|
355 | 360 |
|
361 |
+ const action = actionForLocation(location); |
|
362 |
+ |
|
363 |
+ if (action) { |
|
356 | 364 |
this.store.dispatch(action); |
357 | 365 |
} |
358 | 366 |
}); |
359 | 367 |
}, |
360 | 368 |
|
361 | 369 |
receiveAction(action) { |
362 |
- let matcher = matchAction(action, compiledActionMatchers); |
|
363 |
- if (matcher) { |
|
364 |
- let path = constructPath(matcher); |
|
370 |
+ const path = pathForAction(action); |
|
371 |
+ |
|
372 |
+ if (path) { |
|
365 | 373 |
this.onLocationChanged(path, () => { |
366 | 374 |
window.history.pushState({}, "", path); |
367 | 375 |
}); |
... | ... |
@@ -4,7 +4,7 @@ export function wrapEvent(target, name, obj) { |
4 | 4 |
target.addEventListener(name, obj); |
5 | 5 |
} |
6 | 6 |
|
7 |
-function debounce(object, flag, cb) { |
|
7 |
+function runOnceFor(object, flag, cb) { |
|
8 | 8 |
if (!object[flag]) { |
9 | 9 |
object[flag] = true; |
10 | 10 |
cb(); |
... | ... |
@@ -13,7 +13,7 @@ function debounce(object, flag, cb) { |
13 | 13 |
|
14 | 14 |
let MISSING_CHANGE_URL = Symbol("missing_change_url"); |
15 | 15 |
export default function addChangeUrlEvent(window) { |
16 |
- debounce(window, MISSING_CHANGE_URL, () => { |
|
16 |
+ runOnceFor(window, MISSING_CHANGE_URL, () => { |
|
17 | 17 |
const changeUrlEventCreator = { |
18 | 18 |
lastLocation: null, |
19 | 19 |
handleEvent(_) { |
... | ... |
@@ -18,7 +18,7 @@ function polyfillCustomEvent() { |
18 | 18 |
window.CustomEvent = CustomEvent; |
19 | 19 |
} |
20 | 20 |
|
21 |
-function debounce(object, flag, cb) { |
|
21 |
+function runOnceFor(object, flag, cb) { |
|
22 | 22 |
if (!object[flag]) { |
23 | 23 |
object[flag] = true; |
24 | 24 |
cb(); |
... | ... |
@@ -27,7 +27,7 @@ function debounce(object, flag, cb) { |
27 | 27 |
|
28 | 28 |
let MISSING_HISTORY = Symbol("missing_history"); |
29 | 29 |
export default function addMissingHistoryEvents(window, history) { |
30 |
- debounce(history, MISSING_HISTORY, () => { |
|
30 |
+ runOnceFor(history, MISSING_HISTORY, () => { |
|
31 | 31 |
const pushState = history.pushState.bind(history); |
32 | 32 |
const replaceState = history.replaceState.bind(history); |
33 | 33 |
|