From 9384f5399da39e53855beb8e7f8ded1aa56bf72e Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 27 Dec 2022 14:36:33 +0900 Subject: rename: client -> frontend --- packages/client/src/nirax.ts | 275 ------------------------------------------- 1 file changed, 275 deletions(-) delete mode 100644 packages/client/src/nirax.ts (limited to 'packages/client/src/nirax.ts') diff --git a/packages/client/src/nirax.ts b/packages/client/src/nirax.ts deleted file mode 100644 index 53e73a8d48..0000000000 --- a/packages/client/src/nirax.ts +++ /dev/null @@ -1,275 +0,0 @@ -// NIRAX --- A lightweight router - -import { EventEmitter } from 'eventemitter3'; -import { Ref, Component, ref, shallowRef, ShallowRef } from 'vue'; -import { pleaseLogin } from '@/scripts/please-login'; -import { safeURIDecode } from '@/scripts/safe-uri-decode'; - -type RouteDef = { - path: string; - component: Component; - query?: Record; - loginRequired?: boolean; - name?: string; - hash?: string; - globalCacheKey?: string; - children?: RouteDef[]; -}; - -type ParsedPath = (string | { - name: string; - startsWith?: string; - wildcard?: boolean; - optional?: boolean; -})[]; - -export type Resolved = { route: RouteDef; props: Map; child?: Resolved; }; - -function parsePath(path: string): ParsedPath { - const res = [] as ParsedPath; - - path = path.substring(1); - - for (const part of path.split('/')) { - if (part.includes(':')) { - const prefix = part.substring(0, part.indexOf(':')); - const placeholder = part.substring(part.indexOf(':') + 1); - const wildcard = placeholder.includes('(*)'); - const optional = placeholder.endsWith('?'); - res.push({ - name: placeholder.replace('(*)', '').replace('?', ''), - startsWith: prefix !== '' ? prefix : undefined, - wildcard, - optional, - }); - } else if (part.length !== 0) { - res.push(part); - } - } - - return res; -} - -export class Router extends EventEmitter<{ - change: (ctx: { - beforePath: string; - path: string; - resolved: Resolved; - key: string; - }) => void; - replace: (ctx: { - path: string; - key: string; - }) => void; - push: (ctx: { - beforePath: string; - path: string; - route: RouteDef | null; - props: Map | null; - key: string; - }) => void; - same: () => void; -}> { - private routes: RouteDef[]; - public current: Resolved; - public currentRef: ShallowRef = shallowRef(); - public currentRoute: ShallowRef = shallowRef(); - private currentPath: string; - private currentKey = Date.now().toString(); - - public navHook: ((path: string, flag?: any) => boolean) | null = null; - - constructor(routes: Router['routes'], currentPath: Router['currentPath']) { - super(); - - this.routes = routes; - this.currentPath = currentPath; - this.navigate(currentPath, null, false); - } - - public resolve(path: string): Resolved | null { - let queryString: string | null = null; - let hash: string | null = null; - if (path[0] === '/') path = path.substring(1); - if (path.includes('#')) { - hash = path.substring(path.indexOf('#') + 1); - path = path.substring(0, path.indexOf('#')); - } - if (path.includes('?')) { - queryString = path.substring(path.indexOf('?') + 1); - path = path.substring(0, path.indexOf('?')); - } - - if (_DEV_) console.log('Routing: ', path, queryString); - - function check(routes: RouteDef[], _parts: string[]): Resolved | null { - forEachRouteLoop: - for (const route of routes) { - let parts = [..._parts]; - const props = new Map(); - - pathMatchLoop: - for (const p of parsePath(route.path)) { - if (typeof p === 'string') { - if (p === parts[0]) { - parts.shift(); - } else { - continue forEachRouteLoop; - } - } else { - if (parts[0] == null && !p.optional) { - continue forEachRouteLoop; - } - if (p.wildcard) { - if (parts.length !== 0) { - props.set(p.name, safeURIDecode(parts.join('/'))); - parts = []; - } - break pathMatchLoop; - } else { - if (p.startsWith) { - if (parts[0] == null || !parts[0].startsWith(p.startsWith)) continue forEachRouteLoop; - - props.set(p.name, safeURIDecode(parts[0].substring(p.startsWith.length))); - parts.shift(); - } else { - if (parts[0]) { - props.set(p.name, safeURIDecode(parts[0])); - } - parts.shift(); - } - } - } - } - - if (parts.length === 0) { - if (route.children) { - const child = check(route.children, []); - if (child) { - return { - route, - props, - child, - }; - } else { - continue forEachRouteLoop; - } - } - - if (route.hash != null && hash != null) { - props.set(route.hash, safeURIDecode(hash)); - } - - if (route.query != null && queryString != null) { - const queryObject = [...new URLSearchParams(queryString).entries()] - .reduce((obj, entry) => ({ ...obj, [entry[0]]: entry[1] }), {}); - - for (const q in route.query) { - const as = route.query[q]; - if (queryObject[q]) { - props.set(as, safeURIDecode(queryObject[q])); - } - } - } - - return { - route, - props, - }; - } else { - if (route.children) { - const child = check(route.children, parts); - if (child) { - return { - route, - props, - child, - }; - } else { - continue forEachRouteLoop; - } - } else { - continue forEachRouteLoop; - } - } - } - - return null; - } - - const _parts = path.split('/').filter(part => part.length !== 0); - - return check(this.routes, _parts); - } - - private navigate(path: string, key: string | null | undefined, emitChange = true) { - const beforePath = this.currentPath; - this.currentPath = path; - - const res = this.resolve(this.currentPath); - - if (res == null) { - throw new Error('no route found for: ' + path); - } - - if (res.route.loginRequired) { - pleaseLogin('/'); - } - - const isSamePath = beforePath === path; - if (isSamePath && key == null) key = this.currentKey; - this.current = res; - this.currentRef.value = res; - this.currentRoute.value = res.route; - this.currentKey = res.route.globalCacheKey ?? key ?? path; - - if (emitChange) { - this.emit('change', { - beforePath, - path, - resolved: res, - key: this.currentKey, - }); - } - - return res; - } - - public getCurrentPath() { - return this.currentPath; - } - - public getCurrentKey() { - return this.currentKey; - } - - public push(path: string, flag?: any) { - const beforePath = this.currentPath; - if (path === beforePath) { - this.emit('same'); - return; - } - if (this.navHook) { - const cancel = this.navHook(path, flag); - if (cancel) return; - } - const res = this.navigate(path, null); - this.emit('push', { - beforePath, - path, - route: res.route, - props: res.props, - key: this.currentKey, - }); - } - - public replace(path: string, key?: string | null, emitEvent = true) { - this.navigate(path, key); - if (emitEvent) { - this.emit('replace', { - path, - key: this.currentKey, - }); - } - } -} -- cgit v1.2.3-freya