Skip to content

Commit

Permalink
WIP optional static segments and splat paths
Browse files Browse the repository at this point in the history
  • Loading branch information
infomiho committed Sep 5, 2024
1 parent dce8f8c commit 666f017
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ export function interpolatePath(

function interpolatePathParams(path: string, params: Params) {
function mapPathPart(part: string) {
if (part === '*') {
return params.splat;
}
if (part.startsWith(":")) {
const paramName = extractParamNameFromPathPart(part);
return params[paramName];
Expand Down
41 changes: 40 additions & 1 deletion waspc/data/Generator/templates/sdk/wasp/client/router/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export type Search =

type RouteDefinitionsToRoutesObj<Routes extends RoutesDefinition> = {
[K in keyof Routes]: {
to: Routes[K]['to']
to: GenerateRoute<Routes[K]['to']>
} & ParamsFromBuildFn<Routes[K]['build']>
}

Expand All @@ -39,3 +39,42 @@ type ParamsFromBuildFn<BF extends BuildFn> = Parameters<BF>[0] extends {
}
? { params: Params }
: { params?: never }

// Optional static segments handling


type SplitPath<S extends string> = S extends `${infer T}/${infer U}`
? [T, ...SplitPath<U>]
: [S]

type DropEmptyStrings<T> = T extends [infer Head, ...infer Tail]
? Head extends ''
? [...DropEmptyStrings<Tail>]
: [ExplodeOptionalStatic<Head>, ...DropEmptyStrings<Tail>]
: T

type ExplodeOptionalStatic<T> = T extends `:${infer P}`
? T
: T extends `${infer S}?`
? [S, '']
: T

type Elem = string | [string, string]

type JoinSegments<T extends Elem[]> = T extends []
? []
: T extends [infer First extends Elem, ...infer Rest extends Elem[]]
? First extends string
? [First, ...JoinSegments<Rest>]
: [First[0], ...JoinSegments<Rest>] | JoinSegments<Rest>
: []

type JoinPath<T extends string[]> = T extends [infer Only extends string]
? Only
: T extends [infer First extends string, ...infer Rest extends string[]]
? `${First}/${JoinPath<Rest>}`
: never

type GenerateRoute<S extends string> = S extends '/'
? '/'
: `/${JoinPath<JoinSegments<ExplodeOptionalStatic<DropEmptyStrings<SplitPath<S>>>>>}`
2 changes: 1 addition & 1 deletion waspc/examples/todoApp/main.wasp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ page AboutPage {
component: import About from "@src/pages/About"
}

route ProfileRoute { path: "/profile", to: ProfilePage }
route ProfileRoute { path: "/profile/extra?", to: ProfilePage }
page ProfilePage {
authRequired: true,
component: import { ProfilePage } from "@src/pages/ProfilePage"
Expand Down
6 changes: 5 additions & 1 deletion waspc/examples/todoApp/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ export function App({ children }: any) {
<div className="app border-spacing-2 p-4">
<header className="flex justify-between">
<h1 className="font-bold text-3xl mb-5">
<Link to="/">{appName}</Link>
<Link to="/*" params={{ splat: 'somethingelse' }}>
{appName}
</Link>

{/* <Link to="/task/nesto?/:id" params={{ id: 1 }}>Filip</Link> */}
</h1>
<h2>
Your site was loaded at: {date?.toLocaleString()} {connectionIcon}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ import Wasp.Util.WebRouterPath (Param (Optional, Required), extractPathParams)
genNewClientRouterApi :: AppSpec -> Generator [FileDraft]
genNewClientRouterApi spec =
sequence
[ genRouterTsx spec,
[ genIndexTs spec,
genFileCopy [relfile|client/router/types.ts|],
genFileCopy [relfile|client/router/linkHelpers.ts|],
genFileCopy [relfile|client/router/Link.tsx|]
]
where
genFileCopy = return . C.mkTmplFd

genRouterTsx :: AppSpec -> Generator FileDraft
genRouterTsx spec = return $ C.mkTmplFdWithData [relfile|client/router/index.ts|] tmplData
genIndexTs :: AppSpec -> Generator FileDraft
genIndexTs spec = return $ C.mkTmplFdWithData [relfile|client/router/index.ts|] tmplData
where
tmplData =
object ["routes" .= map createRouteTemplateData (AS.getRoutes spec)]
Expand Down
3 changes: 3 additions & 0 deletions waspc/src/Wasp/Util/WebRouterPath.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import Data.Maybe (mapMaybe)
data Param = Optional String | Required String deriving (Show, Eq)

-- TODO: upgrade to work with React Router v6: https://reactrouter.com/en/main/route/route#splats
-- Maybe explode all optional segments and then compute the routes for the Link component
-- This would mean we have two different lists: routes and links?
extractPathParams :: String -> [Param]
extractPathParams = mapMaybe parseParam . splitOn "/"
where
parseParam :: String -> Maybe Param
parseParam "*" = Just $ Required "splat"
parseParam (':' : xs) =
Just $
if "?" `isSuffixOf` xs
Expand Down

0 comments on commit 666f017

Please sign in to comment.