Skip to content

Commit af54dc6

Browse files
committed
feat: added getNextPath
1 parent c58d5ee commit af54dc6

12 files changed

+127
-16
lines changed

CHANGES.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## 0.2.0 (2024-01-05)
4+
5+
- Feat: added `getNextPath`
6+
- Refactor: refactored internals
7+
- Chore: bumped deps.
8+
39
## 0.1.2 (2023-07-17)
410

511
- CI: create tags and releases on publish.

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,17 @@
55
General utilities for Web development
66

77
## Features
8+
89
### Browser
910

1011
- `copyToClipboard(content: string): boolean`
1112
- `getCookie(name: string): string | null`
1213
- `storageAvailable(type: 'localStorage' | 'sessionStorage'): boolean`
1314

15+
### Vue
16+
17+
- `getNextPath(): string` - returns the value of `?next` query param or `/`
18+
1419
## Installation
1520

1621
`pnpm add @slipmatio/toolbelt`

index.html

+14-11
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
<!DOCTYPE html>
22
<html lang="en">
3-
<head>
4-
<meta charset="UTF-8" />
5-
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7-
<title>Slipmat Toolbelt DEV</title>
8-
</head>
9-
<body class="bg-slate-950">
10-
<div id="app"></div>
11-
<script type="module" src="/src/dev.ts"></script>
12-
</body>
13-
</html>
3+
4+
<head>
5+
<meta charset="UTF-8" />
6+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
8+
<title>Slipmat Toolbelt DEV</title>
9+
</head>
10+
11+
<body class="bg-slate-950">
12+
<div id="app"></div>
13+
<script type="module" src="/src/main.ts"></script>
14+
</body>
15+
16+
</html>

src/App.vue

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<template>
2+
<router-view></router-view>
3+
</template>

src/dev.ts

-4
This file was deleted.

src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export { storageAvailable, getCookie, copyToClipboard } from './browser'
2+
export { getNextPath } from './routes'

src/main.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { createApp } from 'vue'
2+
import App from './App.vue'
3+
import { createRouter, createWebHistory } from 'vue-router'
4+
5+
import BrowserPage from './pages/BrowserPage.vue'
6+
import VuePage from './pages/VuePage.vue'
7+
8+
const routes = [
9+
{ path: '/', component: BrowserPage },
10+
{ path: '/vue/', component: VuePage },
11+
]
12+
13+
const router = createRouter({
14+
history: createWebHistory(),
15+
routes,
16+
})
17+
18+
const app = createApp(App)
19+
app.use(router)
20+
app.mount('#app')

src/Dev.vue src/pages/BrowserPage.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import { copyToClipboard, getCookie, storageAvailable } from './browser'
2+
import { copyToClipboard, getCookie, storageAvailable } from '../browser'
33
44
const clipboardText = 'clipboard works'
55

src/pages/VuePage.vue

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script setup lang="ts">
2+
import { getNextPath } from '../routes'
3+
4+
const nextPath = getNextPath()
5+
console.log(`nextPath: ${nextPath}`)
6+
</script>
7+
<template></template>

src/routes.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { useRoute } from 'vue-router'
2+
import { isString } from './type-helpers'
3+
4+
/**
5+
* Helper for figuring our ?next= query param in a safe way.
6+
*/
7+
export function getNextPath(): string {
8+
const route = useRoute()
9+
10+
let next = '/'
11+
if (
12+
route.query &&
13+
route.query.next &&
14+
isString(route.query.next) &&
15+
route.query.next.startsWith('/')
16+
) {
17+
next = route.query.next as string
18+
}
19+
return next
20+
}

src/type-helpers.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import type { LocationQueryValue } from 'vue-router'
2+
3+
export function isString(value: string | LocationQueryValue[]): value is string {
4+
return typeof value === 'string'
5+
}

tests/e2e/vue.spec.ts

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { test, expect } from '@playwright/test'
2+
3+
test('getNextPath with no querypath should return "/"', async ({ page }) => {
4+
page.on('console', (msg) => {
5+
const text = msg.text()
6+
if (!text.startsWith('[vite]')) {
7+
expect(text).toBe('nextPath: /')
8+
}
9+
})
10+
11+
await page.goto('/vue/')
12+
})
13+
14+
test('getNextPath with next=foo should return "/"', async ({ page }) => {
15+
page.on('console', (msg) => {
16+
const text = msg.text()
17+
if (!text.startsWith('[vite]')) {
18+
expect(text).toBe('nextPath: /')
19+
}
20+
})
21+
22+
await page.goto('/vue/?next=foo')
23+
})
24+
25+
test('getNextPath with next=http://foo.bar should return "/"', async ({ page }) => {
26+
page.on('console', (msg) => {
27+
const text = msg.text()
28+
if (!text.startsWith('[vite]')) {
29+
expect(text).toBe('nextPath: /')
30+
}
31+
})
32+
33+
await page.goto('/vue/?next=http://foo.bar')
34+
})
35+
36+
test('getNextPath with next=/next-url/ should return "/next-url/"', async ({ page }) => {
37+
page.on('console', (msg) => {
38+
const text = msg.text()
39+
if (!text.startsWith('[vite]')) {
40+
expect(text).toBe('nextPath: /next-url/')
41+
}
42+
})
43+
44+
await page.goto('/vue/?next=/next-url/')
45+
})

0 commit comments

Comments
 (0)