Skip to content

Commit

Permalink
Rename paramType properties (redwoodjs#3732)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tobbe authored Nov 16, 2021
1 parent 3c27490 commit 8874cf7
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 35 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ use:
## Features

- Opinionated defaults for formatting, file organization, Webpack, Babel, and more
- Simple but powerful routing (all routes defined in one file) with dynamic (typed) parameters, constraints, and named route functions (to generate correct URLs)
- Simple but powerful routing (all routes defined in one file) with dynamic (typed) parameters, custom types, and named route functions (to generate correct URLs)
- Automatic page-based code-splitting
- Boilerplate-less GraphQL API construction
- Cells: a declarative way to fetch data from the backend API
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,33 @@ ${routes.map(
}
}

type ParamType<constraint> = constraint extends 'Int'
type ParamType<match> = match extends 'Int'
? number
: constraint extends 'Boolean'
: match extends 'Boolean'
? boolean
: constraint extends 'Float'
: match extends 'Float'
? number
: string

// Path string parser for Redwood Routes
type ParsedParams<PartialRoute> =
// {a:Int}/[...moar]
${"PartialRoute extends `{${infer Param}:${infer Constraint}}/${infer Rest}`"}
${"PartialRoute extends `{${infer Param}:${infer Match}}/${infer Rest}`"}
? // check for greedy match e.g. {b}/{c:Int}
// Param = b}/{c, Rest2 = {c, Constrait = Int so we reconstruct the old one {c + : + Int + }
// Param = b}/{c, Rest2 = {c, Match = Int so we reconstruct the old one {c + : + Int + }
${"Param extends `${infer Param2}}/${infer Rest2}`"}
? { [ParamName in Param2]: string } &
${"ParsedParams<`${Rest2}:${Constraint}}`> &"}
${"ParsedParams<`${Rest2}:${Match}}`> &"}
${"ParsedParams<`${Rest}`>"}
${": { [Entry in Param]: ParamType<Constraint> } & ParsedParams<`${Rest}`>"}
: // has type, but at the end e.g.{d:Int}
${"PartialRoute extends `{${infer Param}:${infer Constraint}}`"}
${": { [Entry in Param]: ParamType<Match> } & ParsedParams<`${Rest}`>"}
: // has type, but at the end e.g. {d:Int}
${"PartialRoute extends `{${infer Param}:${infer Match}}`"}
? // Greedy match order 2
${"Param extends `${infer Param2}}/${infer Rest2}`"}
? { [ParamName in Param2]: string } &
${"ParsedParams<`${Rest2}:${Constraint}}`>"}
: { [Entry in Param]: ParamType<Constraint> }
: // no type, but has stuff ater it {c}/{d}
${"ParsedParams<`${Rest2}:${Match}}`>"}
: { [Entry in Param]: ParamType<Match> }
: // no type, but has stuff after it, e.g. {c}/{d}
${"PartialRoute extends `{${infer Param}}/${infer Rest}`"}
${"? { [ParamName in Param]: string } & ParsedParams<`${Rest}`>"}
: // last one with no type e.g. {d}
Expand Down
43 changes: 21 additions & 22 deletions packages/router/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,29 +48,29 @@ export const paramsForRoute = (route: string) => {
export type TrailingSlashesTypes = 'never' | 'always' | 'preserve'

export interface ParamType {
constraint?: RegExp
transform?: (value: any) => unknown
match?: RegExp
parse?: (value: any) => unknown
}

/** Definitions of the core param types. */
const coreParamTypes: Record<string, ParamType> = {
String: {
constraint: /[^/]+/,
match: /[^/]+/,
},
Int: {
constraint: /\d+/,
transform: Number,
match: /\d+/,
parse: Number,
},
Float: {
constraint: /[-+]?(?:\d*\.?\d+|\d+\.?\d*)(?:[eE][-+]?\d+)?/,
transform: Number,
match: /[-+]?(?:\d*\.?\d+|\d+\.?\d*)(?:[eE][-+]?\d+)?/,
parse: Number,
},
Boolean: {
constraint: /true|false/,
transform: (boolAsString: string) => boolAsString === 'true',
match: /true|false/,
parse: (boolAsString: string) => boolAsString === 'true',
},
Glob: {
constraint: /.*/,
match: /.*/,
},
}

Expand Down Expand Up @@ -103,24 +103,23 @@ const matchPath = (
// Get the names and the transform types for the given route.
const routeParams = paramsForRoute(route)
const allParamTypes = { ...coreParamTypes, ...paramTypes }
let typeConstrainedRoute = route
let typeMatchingRoute = route

// Map all params from the route to their type constraint regex to create a
// "type-constrained route" regex
// Map all params from the route to their type `match` regexp to create a
// "type-matching route" regexp
for (const [_name, type, match] of routeParams) {
// `undefined` constraint if `type` is not supported
const constraint =
allParamTypes[type as SupportedRouterParamTypes]?.constraint
// `undefined` matcher if `type` is not supported
const matcher = allParamTypes[type as SupportedRouterParamTypes]?.match

// Get the regex as a string, or default regex if no constraint
const typeRegex = constraint?.source || '[^/]+'
// Get the regex as a string, or default regexp if `match` is not specified
const typeRegexp = matcher?.source || '[^/]+'

typeConstrainedRoute = typeConstrainedRoute.replace(match, `(${typeRegex})`)
typeMatchingRoute = typeMatchingRoute.replace(match, `(${typeRegexp})`)
}

// Does the `pathname` match the route?
const matches = [
...pathname.matchAll(new RegExp(`^${typeConstrainedRoute}$`, 'g')),
...pathname.matchAll(new RegExp(`^${typeMatchingRoute}$`, 'g')),
]

if (matches.length === 0) {
Expand All @@ -135,8 +134,8 @@ const matchPath = (
const typeInfo = allParamTypes[transformName as SupportedRouterParamTypes]

let transformedValue: string | unknown = value
if (typeof typeInfo?.transform === 'function') {
transformedValue = typeInfo.transform(value)
if (typeof typeInfo?.parse === 'function') {
transformedValue = typeInfo.parse(value)
}

return {
Expand Down

0 comments on commit 8874cf7

Please sign in to comment.