space-router 0.9.5 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +1 -0
  2. package/dist/history.d.ts +12 -0
  3. package/dist/history.js +98 -0
  4. package/dist/index.d.ts +6 -0
  5. package/dist/index.js +3 -0
  6. package/dist/match.d.ts +16 -0
  7. package/dist/match.js +68 -0
  8. package/dist/qs.d.ts +5 -0
  9. package/dist/qs.js +27 -0
  10. package/dist/router.d.ts +42 -0
  11. package/dist/router.js +131 -0
  12. package/package.json +29 -22
  13. package/src/history.ts +116 -0
  14. package/src/index.ts +7 -0
  15. package/src/match.ts +88 -0
  16. package/src/qs.ts +33 -0
  17. package/src/router.ts +197 -0
  18. package/.prettierignore +0 -5
  19. package/.prettierrc +0 -6
  20. package/.swc-cjs +0 -11
  21. package/.swc-esm +0 -1
  22. package/CHANGELOG.md +0 -68
  23. package/dist/cjs/history.js +0 -100
  24. package/dist/cjs/index.js +0 -27
  25. package/dist/cjs/match.js +0 -94
  26. package/dist/cjs/qs.js +0 -27
  27. package/dist/cjs/router.js +0 -279
  28. package/dist/esm/history.js +0 -90
  29. package/dist/esm/index.js +0 -3
  30. package/dist/esm/match.js +0 -76
  31. package/dist/esm/qs.js +0 -17
  32. package/dist/esm/router.js +0 -258
  33. package/docs/archetypes/default.md +0 -7
  34. package/docs/assets/js/bg.js +0 -742
  35. package/docs/assets/styles/base.scss +0 -2816
  36. package/docs/assets/styles/main.scss +0 -1368
  37. package/docs/assets/styles/syntax-m.scss +0 -264
  38. package/docs/assets/styles/syntax.scss +0 -240
  39. package/docs/config.toml +0 -9
  40. package/docs/content/_index.md +0 -189
  41. package/docs/layouts/404.html +0 -0
  42. package/docs/layouts/_default/baseof.html +0 -68
  43. package/docs/layouts/index.html +0 -31
  44. package/docs/layouts/partials/favicon.html +0 -5
  45. package/docs/layouts/partials/header.html +0 -0
  46. package/docs/layouts/partials/meta/name-author.html +0 -6
  47. package/docs/layouts/partials/meta/ogimage.html +0 -8
  48. package/docs/layouts/partials/site-verification.html +0 -12
  49. package/docs/layouts/shortcodes/callout.html +0 -1
  50. package/docs/static/js/highlightjs-9.15.10.min.js +0 -2
  51. package/docs/static/js/master.js +0 -0
  52. package/docs/static/js/tocbot.min.js +0 -18
  53. package/docs/static/space.png +0 -0
  54. package/oxlintrc.json +0 -6
  55. package/src/history.js +0 -97
  56. package/src/index.js +0 -3
  57. package/src/match.js +0 -87
  58. package/src/qs.js +0 -20
  59. package/src/router.js +0 -147
  60. package/tasks/build.js +0 -16
  61. package/test/flatten.test.js +0 -58
  62. package/test/match.test.js +0 -68
  63. package/test/router.test.js +0 -157
package/src/router.js DELETED
@@ -1,147 +0,0 @@
1
- import { match as findMatch } from './match'
2
- import { createHistory } from './history'
3
- import { qs as defaultQs } from './qs'
4
-
5
- export function createRouter(options = {}) {
6
- let history = null
7
- let routes = []
8
- const mode = options.mode || 'history'
9
- const qs = options.qs || defaultQs
10
- const sync = options.sync || false
11
-
12
- const router = {
13
- listen(routeMap, cb) {
14
- if (history) {
15
- throw new Error('Already listening')
16
- }
17
-
18
- routes = flatten(routeMap)
19
- history = createHistory({ mode, sync })
20
- const dispose = history.listen((url) => transition(router, url, cb))
21
-
22
- return () => {
23
- dispose()
24
- history = null
25
- routes = []
26
- }
27
- },
28
-
29
- navigate(to, curr) {
30
- if (typeof to === 'string') {
31
- to = { url: to }
32
- }
33
- const url = router.href(to, curr)
34
- if (to.replace) {
35
- history.replace(url)
36
- } else {
37
- history.push(url)
38
- }
39
- },
40
-
41
- href(to, curr) {
42
- // already a url
43
- if (typeof to === 'string') {
44
- return to
45
- }
46
-
47
- // align with navigate API
48
- if (to.url) {
49
- return to.url
50
- }
51
-
52
- if (to.merge) {
53
- curr = curr || router.match(router.getUrl())
54
- to = merge(curr, to)
55
- }
56
-
57
- let url = to.pathname || '/'
58
-
59
- if (to.params) {
60
- Object.keys(to.params).forEach((param) => {
61
- url = url.replace(':' + param, to.params[param])
62
- })
63
- }
64
-
65
- if (to.query && Object.keys(to.query).length) {
66
- const query = qs.stringify(to.query)
67
- if (query) {
68
- url = url + '?' + query
69
- }
70
- }
71
-
72
- if (to.hash) {
73
- const prefix = to.hash.startsWith('#') ? '' : '#'
74
- url = url + prefix + to.hash
75
- }
76
-
77
- return url
78
- },
79
-
80
- match(url) {
81
- const route = findMatch(routes, url, qs)
82
- if (route) {
83
- return { ...route, data: data(routes, route) }
84
- }
85
- },
86
-
87
- getUrl() {
88
- return history.getUrl()
89
- },
90
- }
91
-
92
- return router
93
- }
94
-
95
- export function flatten(routeMap) {
96
- const routes = []
97
- const parentData = []
98
- function addLevel(level) {
99
- level.forEach((route) => {
100
- const { path = '', routes: children, ...routeData } = route
101
- routes.push({ pattern: path, data: parentData.concat([routeData]) })
102
- if (children) {
103
- parentData.push(routeData)
104
- addLevel(children)
105
- parentData.pop()
106
- }
107
- })
108
- }
109
- addLevel(routeMap)
110
- return routes
111
- }
112
-
113
- function transition(router, url, onNavigated) {
114
- const route = router.match(url)
115
- if (route) {
116
- for (const r of route.data) {
117
- if (r.redirect) {
118
- const url = redirectUrl(router, r.redirect, route)
119
- return router.navigate({ url, replace: true })
120
- }
121
- }
122
- if (onNavigated) onNavigated(route)
123
- }
124
- }
125
-
126
- function redirectUrl(router, redirect, matchingRoute) {
127
- if (typeof redirect === 'function') {
128
- redirect = redirect(matchingRoute)
129
- }
130
- return router.href(redirect)
131
- }
132
-
133
- function data(routes, matchingRoute) {
134
- for (let i = 0; i < routes.length; i++) {
135
- if (routes[i].pattern === matchingRoute.pattern) {
136
- return routes[i].data
137
- }
138
- }
139
- }
140
-
141
- export function merge(curr = {}, to) {
142
- const pathname = to.pathname || curr.pattern || curr.pathname
143
- const params = Object.assign({}, curr.params, to.params)
144
- const query = to.query === null ? null : Object.assign({}, curr.query, to.query)
145
- const hash = to.hash === null ? null : to.hash || curr.hash || ''
146
- return { pathname, params, query, hash }
147
- }
package/tasks/build.js DELETED
@@ -1,16 +0,0 @@
1
- const fs = require('fs')
2
- const path = require('path')
3
-
4
- ;(async function () {
5
- const { execa } = await import('execa')
6
- const sh = (...args) => execa(...args, { stdio: 'inherit', shell: true })
7
-
8
- await sh('rm -rf dist')
9
- await sh('mkdir -p dist')
10
-
11
- const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json')))
12
-
13
- const swc = './node_modules/.bin/swc'
14
- await sh(`${swc} --no-swcrc src -d ${pkg.main} --strip-leading-paths --config-file=./.swc-cjs`)
15
- await sh(`${swc} --no-swcrc src -d ${pkg.module} --strip-leading-paths --config-file=./.swc-esm`)
16
- })()
@@ -1,58 +0,0 @@
1
- import test from 'ava'
2
- import { flatten } from '../src/router'
3
-
4
- test('converts array of routes to array of internal route descriptors', (t) => {
5
- t.deepEqual(
6
- flatten([
7
- { path: '/foo', a: 'foo' },
8
- { path: '/bar', a: 'bar' },
9
- ]),
10
- [
11
- { pattern: '/foo', data: [{ a: 'foo' }] },
12
- { pattern: '/bar', data: [{ a: 'bar' }] },
13
- ],
14
- )
15
- })
16
-
17
- test('handles nested routes', (t) => {
18
- t.deepEqual(
19
- flatten([
20
- {
21
- component: 'root',
22
- routes: [
23
- {
24
- path: '/foo',
25
- component: 'foo',
26
- routes: [
27
- {
28
- path: '/foo/bar',
29
- component: 'bar',
30
- },
31
- ],
32
- },
33
- ],
34
- },
35
- {
36
- path: '/second',
37
- component: 'second-root',
38
- routes: [
39
- {
40
- path: '/baz/*',
41
- component: 'baz',
42
- },
43
- ],
44
- },
45
- ]),
46
- [
47
- { pattern: '', data: [{ component: 'root' }] },
48
- { pattern: '/foo', data: [{ component: 'root' }, { component: 'foo' }] },
49
- { pattern: '/foo/bar', data: [{ component: 'root' }, { component: 'foo' }, { component: 'bar' }] },
50
- { pattern: '/second', data: [{ component: 'second-root' }] },
51
- { pattern: '/baz/*', data: [{ component: 'second-root' }, { component: 'baz' }] },
52
- ],
53
- )
54
- })
55
-
56
- test('handles empty array', (t) => {
57
- t.deepEqual(flatten([]), [])
58
- })
@@ -1,68 +0,0 @@
1
- import test from 'ava'
2
- import { qs } from '../src'
3
- import { matchOne as match } from '../src/match'
4
-
5
- test('match explicit equality', (t) => {
6
- t.deepEqual(match('/', '/').params, {})
7
- t.deepEqual(match('/a', '/a').params, {})
8
- t.deepEqual(match('/a', '/b'), false)
9
- t.deepEqual(match('/a/b', '/a/b').params, {})
10
- t.deepEqual(match('/a/b', '/a/a'), false)
11
- t.deepEqual(match('/a/b', '/b/b'), false)
12
- })
13
-
14
- test('match param segments', (t) => {
15
- t.deepEqual(match('/:foo', '/'), false)
16
- t.deepEqual(match('/:foo', '/bar').params, { foo: 'bar' })
17
- t.deepEqual(match('/bar/:foo', '/bar/baz').params, { foo: 'baz' })
18
- })
19
-
20
- test('match optional param segments', (t) => {
21
- t.deepEqual(match('/:foo?', '/').params, { foo: '' })
22
- t.deepEqual(match('/:foo?', '/bar').params, { foo: 'bar' })
23
- t.deepEqual(match('/:foo?/:bar?', '/').params, { foo: '', bar: '' })
24
- t.deepEqual(match('/:foo?/:bar?', '/bar').params, { foo: 'bar', bar: '' })
25
- t.deepEqual(match('/:foo?/bar', '/bar'), false)
26
- t.deepEqual(match('/:foo?/bar', '/foo/bar').params, { foo: 'foo' })
27
- })
28
-
29
- test('match splat param segments', (t) => {
30
- t.deepEqual(match('/:foo*', '/').params, { foo: '' })
31
- t.deepEqual(match('/:foo*', '/a').params, { foo: 'a' })
32
- t.deepEqual(match('/:foo*', '/a/b').params, { foo: 'a/b' })
33
- t.deepEqual(match('/:foo*', '/a/b/c').params, { foo: 'a/b/c' })
34
- })
35
-
36
- test('match required splat param segments', (t) => {
37
- t.deepEqual(match('/:foo+', '/'), false)
38
- t.deepEqual(match('/:foo+', '/a').params, { foo: 'a' })
39
- t.deepEqual(match('/:foo+', '/a/b').params, { foo: 'a/b' })
40
- t.deepEqual(match('/:foo+', '/a/b/c').params, { foo: 'a/b/c' })
41
- })
42
-
43
- test('match catch all', (t) => {
44
- t.deepEqual(match('*', '/some/thing?abc=1', qs), {
45
- url: '/some/thing?abc=1',
46
- pathname: '/some/thing',
47
- pattern: '*',
48
- params: {},
49
- query: { abc: '1' },
50
- search: '?abc=1',
51
- hash: '',
52
- })
53
- t.deepEqual(!!match('*', '/a', qs), true)
54
- t.deepEqual(!!match('*', '/a/b', qs), true)
55
- t.deepEqual(!!match('*', '/a/b/c', qs), true)
56
- })
57
-
58
- test('match query params', (t) => {
59
- t.deepEqual(match('/bar/:foo', '/bar/baz?q=s#abc', qs), {
60
- url: '/bar/baz?q=s#abc',
61
- pathname: '/bar/baz',
62
- pattern: '/bar/:foo',
63
- params: { foo: 'baz' },
64
- query: { q: 's' },
65
- search: '?q=s',
66
- hash: '#abc',
67
- })
68
- })
@@ -1,157 +0,0 @@
1
- import test from 'ava'
2
- import { qs, createRouter } from '../src/index'
3
-
4
- test('createRouter, listen, navigate and dispose', (t) => {
5
- const calls = []
6
-
7
- const { router, dispose } = createTestRouter((route) => {
8
- calls.push(route.data[0].render(route.params, route.query, route.hash))
9
- })
10
-
11
- router.navigate({ url: '/foo' })
12
- router.navigate({ url: '/user/5' })
13
- router.navigate({ url: '/user/7/friends' })
14
- router.navigate({ url: '/user/7' })
15
- router.navigate({ url: '/user/8/posts' })
16
- router.navigate('/bar')
17
- router.navigate('/user/1')
18
- router.navigate({ pathname: '/user/:id', params: { id: 2 } })
19
- router.navigate({ pathname: '/user/2', query: { a: 1, b: 2 } })
20
- router.navigate({ query: { a: 11, b: 22 }, merge: true })
21
- router.navigate({ query: { b: undefined, c: 'bla' }, hash: 'test', merge: true })
22
- router.navigate({ params: { id: 3 }, merge: true })
23
- router.navigate({ query: { curr: 'test' }, merge: true }, { pathname: '/user/curr' })
24
-
25
- t.deepEqual(
26
- [
27
- 'foo',
28
- 'user=5',
29
- 'friends=7',
30
- 'user=7',
31
- 'catchall',
32
- 'bar',
33
- 'user=1',
34
- 'user=2',
35
- 'user=2?a=1&b=2',
36
- 'user=2?a=11&b=22',
37
- 'user=2?a=11&c=bla#test',
38
- 'user=3?a=11&c=bla#test',
39
- 'user=curr?curr=test',
40
- ],
41
- calls,
42
- )
43
-
44
- dispose()
45
- })
46
-
47
- test('.href(to)', (t) => {
48
- const { router, dispose } = createTestRouter()
49
-
50
- t.deepEqual('/user/7/friends?a=1&b=2', router.href({ pathname: '/user/7/friends', query: { a: 1, b: 2 } }))
51
-
52
- t.deepEqual(
53
- router.href({ pathname: '/user/:id/friends', params: { id: 7 }, query: { a: 1, b: 2 } }),
54
- '/user/7/friends?a=1&b=2',
55
- )
56
- t.deepEqual(
57
- router.href({ pathname: '/user/:id/friends', params: { id: 7 }, query: { a: 1, b: 2 }, hash: '#bla' }),
58
- '/user/7/friends?a=1&b=2#bla',
59
- )
60
- t.deepEqual(router.href({ pathname: '/user/:id/friends', params: { id: 8 }, hash: '#foo' }), '/user/8/friends#foo')
61
- t.deepEqual(
62
- router.href({ pathname: '/user/:id/friends', params: { id: 8 }, query: {}, hash: '#foo' }),
63
- '/user/8/friends#foo',
64
- )
65
- t.deepEqual(
66
- router.href({ pathname: '/user/:id/friends', params: { id: 8 }, query: { q: null }, hash: '#foo' }),
67
- '/user/8/friends?q=null#foo',
68
- )
69
- t.deepEqual(
70
- router.href({ pathname: '/user/:id/friends', params: { id: 8 }, query: { q: undefined }, hash: '#foo' }),
71
- '/user/8/friends#foo',
72
- )
73
- t.deepEqual(
74
- router.href({ pathname: '/user/:id/friends', params: { id: 8 }, query: { q: undefined }, hash: '#foo' }),
75
- '/user/8/friends#foo',
76
- )
77
- t.deepEqual(router.href({ params: { id: 8 }, query: { q: 1 }, hash: '#foo' }), '/?q=1#foo')
78
-
79
- dispose()
80
- })
81
-
82
- test('.match(url)', (t) => {
83
- const { router, dispose } = createTestRouter()
84
-
85
- const route = {
86
- url: '/user/7/settings?a=1#hello',
87
- pattern: '/user/:id/settings',
88
- pathname: '/user/7/settings',
89
- params: { id: '7' },
90
- query: { a: '1' },
91
- search: '?a=1',
92
- hash: '#hello',
93
- data: [{ datum: 'settings-data' }],
94
- }
95
- t.deepEqual(router.match('/user/7/settings?a=1#hello'), route)
96
-
97
- dispose()
98
- })
99
-
100
- test('.match(url) without catch all', (t) => {
101
- const { router, dispose } = createTestRouter(null, { withoutCatchAll: true })
102
-
103
- const route = router.match('/unknown')
104
- t.is(route, undefined)
105
-
106
- dispose()
107
- })
108
-
109
- test('.getUrl()', (t) => {
110
- const { router } = createTestRouter()
111
-
112
- router.navigate('/user/8')
113
- t.is(router.getUrl(), '/user/8')
114
- })
115
-
116
- test('redirects', (t) => {
117
- const calls = []
118
-
119
- const { router, dispose } = createTestRouter((route) => {
120
- calls.push(route.data[0].render(route.params, route.query))
121
- })
122
-
123
- router.navigate('/redirect-via-obj-1')
124
- router.navigate('/redirect-via-obj-2')
125
- router.navigate('/redirect-via-fn-1/2')
126
- router.navigate('/redirect-via-fn-2/2')
127
-
128
- t.deepEqual(['bar', 'user=1', 'user=2', 'foo'], calls)
129
-
130
- dispose()
131
- })
132
-
133
- function createTestRouter(cb, { withoutCatchAll = false } = {}) {
134
- const router = createRouter({ mode: 'memory', sync: true })
135
- const dispose = router.listen(
136
- [
137
- { path: '/foo', render: () => 'foo' },
138
- { path: '/bar', render: () => 'bar' },
139
- { path: '/redirect-via-obj-1', redirect: 'bar' },
140
- { path: '/redirect-via-obj-2', redirect: { pathname: '/user/:id', params: { id: 1 } } },
141
- { path: '/redirect-via-fn-1/:id', redirect: ({ params }) => ({ pathname: '/user/:id', params }) },
142
- { path: '/redirect-via-fn-2/:id', redirect: () => ({ url: '/foo' }) },
143
- {
144
- path: '/user/:id',
145
- render: (params, query, hash = '') => {
146
- const q = query && Object.keys(query).length ? `?${qs.stringify(query)}` : ''
147
- return 'user=' + params.id + q + hash
148
- },
149
- },
150
- { path: '/user/:id/friends', render: (params) => 'friends=' + params.id },
151
- { path: '/user/:id/settings', datum: 'settings-data' },
152
- !withoutCatchAll && { path: '*', render: () => 'catchall' },
153
- ].filter(Boolean),
154
- cb,
155
- )
156
- return { router, dispose }
157
- }