UNPKG

2.95 kBJavaScriptView Raw
1import withTrailingSlash from './with-trailing-slash'
2
3const DEFAULT_PARSER = /^https?:\/\/([a-zA-Z0-9\-_.]+)()(\/.*)/
4const PROTOCOL = /(https?):\/\//
5const SLICE_END = ')'
6const SLICE_START = '('
7const SLICE_MARKERS = new RegExp(`[${SLICE_START}${SLICE_END}]`, 'g')
8
9// TODO review this, instead of discarding the query string perhaps we can pass it down to
10// the last panel?
11const withoutQueryString = s => (/\?/.test(s) ? s.match(/(.*?)\?/)[1] : s)
12
13const MANY_APPS = /^(https?:\/\/.+?\/)(https?:\/\/.+)/
14
15const appSplit = s => {
16 let currentUri = s
17 let nextUri = false
18
19 const manyAppsMatch = s.match(MANY_APPS)
20 if (manyAppsMatch) {
21 currentUri = manyAppsMatch[1]
22 nextUri = manyAppsMatch[2]
23 }
24
25 return {
26 currentUri,
27 nextUri,
28 }
29}
30
31export default function parse(uri, parsers = []) {
32 const apps = {
33 byName: {},
34 items: [],
35 }
36 const routes = {
37 byContext: {},
38 items: [],
39 }
40
41 // Make sure we always have a trailing slash on the URI
42 const protocol = uri.match(PROTOCOL)[1]
43 let nextUri = withoutQueryString(withTrailingSlash(uri))
44
45 do {
46 const split = appSplit(nextUri)
47 const currentUri = split.currentUri
48 nextUri = split.nextUri
49
50 const parser = parsers.find(p => p.test(currentUri)) || DEFAULT_PARSER
51 let [_0, app, _1, path] = currentUri.match(parser)
52
53 const base = `${protocol}://${app}`
54 const context = routes.items.length > 0
55 ? routes.items[routes.items.length - 1]
56 : ''
57
58 // Get every path 'bit' which is indeed every panel we need to load
59 let pathRoute = []
60 let isVisible = true
61 do {
62 path = path.split('/')
63 const lastBit = path.length > 1 ? path[path.length - 2] : ''
64 path = path.slice(0, path.length - 1).join('/')
65 const hasSliceEndMarkerForRoot = lastBit.indexOf(SLICE_END) === 0
66 const hasSliceEndMarker =
67 !hasSliceEndMarkerForRoot && lastBit.indexOf(SLICE_END) > -1
68 const hasSliceStartMarker = lastBit.indexOf(SLICE_START) > -1
69
70 if (hasSliceEndMarker || hasSliceStartMarker) {
71 isVisible = false
72 }
73
74 const panelPath = path.replace(SLICE_MARKERS, '') || '/'
75
76 const panelId = `${app}${panelPath}`
77
78 pathRoute.push({
79 app,
80 context: `${context}${base}${withTrailingSlash(path)}`,
81 isVisible,
82 panelId,
83 path: panelPath,
84 })
85
86 isVisible = hasSliceEndMarkerForRoot
87 ? false
88 : hasSliceStartMarker ? true : isVisible
89 } while (path.length)
90
91 if (apps.items.indexOf(app) === -1) {
92 apps.items.push(app)
93 apps.byName[app] = {
94 app,
95 panels: [],
96 }
97 }
98
99 pathRoute.reverse().forEach(route => {
100 routes.byContext[route.context] = route
101 routes.items.push(route.context)
102
103 if (apps.byName[app].panels.indexOf(route.path) === -1) {
104 apps.byName[app].panels.push(route.path)
105 }
106 })
107 } while (nextUri)
108
109 return {
110 apps,
111 routes,
112 }
113}