Skip to content

Commit

Permalink
Big change on createUrl -> internalize logic
Browse files Browse the repository at this point in the history
  • Loading branch information
willybrauner committed Nov 9, 2023
1 parent 0136a13 commit 8915a0a
Show file tree
Hide file tree
Showing 12 changed files with 514 additions and 509 deletions.
272 changes: 151 additions & 121 deletions src/core/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { compile, match } from "path-to-regexp"
import { TRoute } from "../components/Router"
import LangService from "./LangService"
import { joinPaths, removeLastCharFromString } from "./helpers"
import { al, ar } from "vitest/dist/reporters-5f784f42"

const componentName: string = "core"
const log = debug(`router:${componentName}`)
Expand All @@ -24,13 +25,13 @@ export type TOpenRouteParams = {
* createUrl URL for setLocation
* (Get URL to push in history)
*
* @param args can be string or TOpenRouteParams object
* @param openRouteParams can be string or TOpenRouteParams object
* @param base
* @param allRoutes
* @param langService
*/
export function createUrl(
args: string | TOpenRouteParams,
openRouteParams: string | TOpenRouteParams,
base: string = Routers.base,
allRoutes: TRoute[] = Routers.routes,
langService = Routers.langService,
Expand All @@ -39,8 +40,8 @@ export function createUrl(
let urlToPush: string

// STRING param
if (typeof args === "string") {
urlToPush = args as string
if (typeof openRouteParams === "string") {
urlToPush = openRouteParams as string
if (!!langService) {
urlToPush = addLangToUrl(urlToPush)
}
Expand All @@ -49,33 +50,62 @@ export function createUrl(
}

// OBJECT param, add lang to params if no exist
else if (typeof args === "object" && args?.name) {
if (langService && !args.params?.lang) {
args.params = {
...args.params,
else if (typeof openRouteParams === "object" && openRouteParams?.name) {
if (langService && !openRouteParams.params?.lang) {
openRouteParams.params = {
...openRouteParams.params,
lang: langService.currentLang.key,
}
}

// add params to URL if exist
let queryParams = ""
if (args?.queryParams) {
if (openRouteParams?.queryParams) {
queryParams = "?"
queryParams += Object.keys(args.queryParams)
.map((key) => `${key}=${args?.queryParams[key]}`)
queryParams += Object.keys(openRouteParams.queryParams)
.map((key) => `${key}=${openRouteParams?.queryParams[key]}`)
.join("&")
}
// add hash to URL if exist
let hash = ""
if (args?.hash) {
hash = "#" + args.hash
if (openRouteParams?.hash) {
hash = "#" + openRouteParams.hash
}

return getUrlByRouteName(allRoutes, args, base) + queryParams + hash
function getUrlByRouteName(
allRoutes: TRoute[],
args: TOpenRouteParams,
base = Routers.base || "/",
langService = Routers.langService,
): string {
const next = (routes, args, curBase): string => {
for (let route of routes) {
const lang = args.params?.lang || langService?.currentLang.key
const langPath = route._langPath?.[lang]
const routePath = route.path
// console.log("---------",{ lang, langPath, routePath })
if (route?.name === args.name || route.component?.displayName === args.name) {
// prettier-ignore
return (curBase + compile(langPath || routePath)(args.params)).replace(/(\/)+/g, "/")
} else if (route.children?.length > 0) {
const match = next(
route.children,
args,
curBase + compile(langPath || routePath)(args.params),
)
if (match) return match
}
}
}
return next(allRoutes, args, base)
}

// in other case return.
const url = getUrlByRouteName(allRoutes, openRouteParams, base)
if (url) return url + queryParams + hash

// in other case return
} else {
console.warn("createUrl param isn't valid. to use createUrl return.", args)
console.warn("createUrl param isn't valid. to use createUrl return.", openRouteParams)
return
}
}
Expand Down Expand Up @@ -488,111 +518,111 @@ export function compileUrl(path: string, params?: TParams): string {
return compile(path)(params)
}

/**
* Get full path by path
* if path "/foo" is a children of path "/bar", his full url is "/bar/foo"
* With the second URL part "/foo", this function will returns "/bar/foo"
* @returns string
*/
export function getFullPathByPath(
routes: TRoute[],
path: string | { [x: string]: string },
routeName: string,
lang: string = Routers.langService?.currentLang.key || undefined,
basePath: string = null,
): string {
let localPath: string[] = [basePath]

for (let route of routes) {
const langPath = route._langPath?.[lang]
const routePath = route.path as string

const pathMatch =
(langPath === path || routePath === path) && route.name === routeName

// if path match on first level, keep path in local array and return it, stop here.
if (pathMatch) {
localPath.push(langPath || routePath)
return joinPaths(localPath)
}

// if not matching but as children, return it
else if (route?.children?.length > 0) {
// no match, recall recursively on children
const matchChildrenPath = getFullPathByPath(
route.children,
path,
routeName,
lang,
joinPaths(localPath),
)
// return recursive Fn only if match, else continue to next iteration
if (matchChildrenPath) {
// keep path in local array
localPath.push(langPath || routePath)
// Return the function after localPath push
return getFullPathByPath(
route.children,
path,
routeName,
lang,
joinPaths(localPath),
)
}
}
}
}

/**
* Get "full" URL by route name and params
* @returns string
*/
export function getUrlByRouteName(
pRoutes: TRoute[],
pParams: TOpenRouteParams,
base?: string,
): string {
// need to wrap the function to be able to access the preserved "pRoutes" param
// in local scope after recursion
const next = (routes: TRoute[], params: TOpenRouteParams): string => {
for (let route of routes) {
const match =
route?.name === params.name || route.component?.displayName === params.name
if (match) {
if (!route?.path) {
log("getUrlByRouteName > There is no route with this name, exit", params.name)
return
}

let path =
typeof route.path === "object"
? route.path[Object.keys(route.path)[0]]
: route.path

// get full path
const _fullPath = getFullPathByPath(
pRoutes,
path,
route.name,
pParams?.params?.lang,
base,
)
// build URL
// console.log("_fullPath", _fullPath, params);
return compileUrl(_fullPath, params.params)
}

// if route has children
else if (route.children?.length > 0) {
// getUrlByRouteName > no match, recall recursively on children
const match = next(route.children, params)
// return recursive Fn only if match, else, continue to next iteration
if (match) return match
}
}
}
return next(pRoutes, pParams)
}
// /**
// * Get full path by path
// * if path "/foo" is a children of path "/bar", his full url is "/bar/foo"
// * With the second URL part "/foo", this function will returns "/bar/foo"
// * @returns string
// */
// export function getFullPathByPath(
// routes: TRoute[],
// path: string | { [x: string]: string },
// routeName: string,
// lang: string = Routers.langService?.currentLang.key || undefined,
// basePath: string = null,
// ): string {
// let localPath: string[] = [basePath]
//
// for (let route of routes) {
// const langPath = route._langPath?.[lang]
// const routePath = route.path as string
//
// const pathMatch =
// (langPath === path || routePath === path) && route.name === routeName
//
// // if path match on first level, keep path in local array and return it, stop here.
// if (pathMatch) {
// localPath.push(langPath || routePath)
// return joinPaths(localPath)
// }
//
// // if not matching but as children, return it
// else if (route?.children?.length > 0) {
// // no match, recall recursively on children
// const matchChildrenPath = getFullPathByPath(
// route.children,
// path,
// routeName,
// lang,
// joinPaths(localPath),
// )
// // return recursive Fn only if match, else continue to next iteration
// if (matchChildrenPath) {
// // keep path in local array
// localPath.push(langPath || routePath)
// // Return the function after localPath push
// return getFullPathByPath(
// route.children,
// path,
// routeName,
// lang,
// joinPaths(localPath),
// )
// }
// }
// }
// }
//
// /**
// * Get "full" URL by route name and params
// * @returns string
// */
// export function getUrlByRouteNameOld(
// pRoutes: TRoute[],
// pParams: TOpenRouteParams,
// base?: string,
// ): string {
// // need to wrap the function to be able to access the preserved "pRoutes" param
// // in local scope after recursion
// const next = (routes: TRoute[], params: TOpenRouteParams): string => {
// for (let route of routes) {
// const match =
// route?.name === params.name || route.component?.displayName === params.name
// if (match) {
// if (!route?.path) {
// log("getUrlByRouteName > There is no route with this name, exit", params.name)
// return
// }
//
// let path =
// typeof route.path === "object"
// ? route.path[Object.keys(route.path)[0]]
// : route.path
//
// // get full path
// const _fullPath = getFullPathByPath(
// pRoutes,
// path,
// route.name,
// pParams?.params?.lang,
// base,
// )
// // build URL
// // console.log("_fullPath", _fullPath, params);
// return compileUrl(_fullPath, params.params)
// }
//
// // if route has children
// else if (route.children?.length > 0) {
// // getUrlByRouteName > no match, recall recursively on children
// const match = next(route.children, params)
// // return recursive Fn only if match, else, continue to next iteration
// if (match) return match
// }
// }
// }
// return next(pRoutes, pParams)
// }

/**
* returns lang path
Expand Down
13 changes: 13 additions & 0 deletions src/tests/core.addLangToUrl.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* @vitest-environment jsdom
*/
import { describe, expect, it } from "vitest"
import { addLangToUrl } from "../core/core"

describe("addLangToUrl", () => {
it("should add lang to Url", () => {
const url = "/foo/en/bar"
expect(addLangToUrl(url, "en", true)).toBe(`/en${url}`)
expect(addLangToUrl(url, "en", false)).toBe(`${url}`)
})
})
17 changes: 17 additions & 0 deletions src/tests/core.applyMiddlewaresToRoutes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* @vitest-environment jsdom
*/

import { describe, expect, it } from "vitest"
import { applyMiddlewaresToRoutes } from "../core/core"

describe("applyMiddlewaresToRoutes", () => {
it("should apply middleware to routes", () => {
// TODO
const transformFn = (r) => r.forEach((e) => (e.path = `-${e.path}`))
const routes = [{ path: "/" }, { path: "/foo" }]
const afterMiddlewareRoutes = [{ path: "-/" }, { path: "-/foo" }]
const transformRoutes = applyMiddlewaresToRoutes(routes, [transformFn])
expect(transformRoutes).toEqual(afterMiddlewareRoutes)
})
})
Loading

0 comments on commit 8915a0a

Please sign in to comment.