diff --git a/src/core/tree.ts b/src/core/tree.ts index c4aaf5b90..4580722ec 100644 --- a/src/core/tree.ts +++ b/src/core/tree.ts @@ -34,7 +34,11 @@ export class TreeNode { constructor(options: ResolvedOptions, filePath: string, parent?: TreeNode) { this.options = options this.parent = parent - this.value = createTreeNodeValue(filePath, parent?.value) + this.value = createTreeNodeValue( + filePath, + parent?.value, + options.pathParser + ) } /** diff --git a/src/core/treeNodeValue.ts b/src/core/treeNodeValue.ts index 1ecb9a4da..7403a3126 100644 --- a/src/core/treeNodeValue.ts +++ b/src/core/treeNodeValue.ts @@ -184,13 +184,17 @@ export type TreeNodeValue = TreeNodeValueStatic | TreeNodeValueParam export function createTreeNodeValue( segment: string, - parent?: TreeNodeValue + parent?: TreeNodeValue, + parseSegmentOptions?: ParseSegmentOptions ): TreeNodeValue { if (!segment || segment === 'index') { return new TreeNodeValueStatic(segment, parent, '') } - const [pathSegment, params, subSegments] = parseSegment(segment) + const [pathSegment, params, subSegments] = parseSegment( + segment, + parseSegmentOptions + ) if (params.length) { return new TreeNodeValueParam( @@ -212,6 +216,19 @@ const enum ParseSegmentState { modifier, // after the ] } +/** + * Options passed to `parseSegment()`to control how a segment of a file path is parsed. e.g. in `/users/[id]`, `users` + * and `[id]` are segments. + */ +export interface ParseSegmentOptions { + /** + * Should we allow dot nesting in the param name. e.g. `users.[id]` will be parsed as `users/[id]` if this is `true`, + * nesting + * @default true + */ + dotNesting?: boolean +} + /** * Parses a segment into the route path segment and the extracted params. * @@ -219,7 +236,8 @@ const enum ParseSegmentState { * @returns - the pathSegment and the params */ function parseSegment( - segment: string + segment: string, + { dotNesting = true }: ParseSegmentOptions = {} ): [string, TreeRouteParam[], SubSegment[]] { let buffer = '' let state: ParseSegmentState = ParseSegmentState.static @@ -262,8 +280,9 @@ function parseSegment( // check if it's an optional param or not state = ParseSegmentState.paramOptional } else { - // allows for nested paths without nesting the views - buffer += c === '.' ? '/' : c + // append the char to the buffer or if the dotNesting option + // is enabled (by default it is), transform into a slash + buffer += dotNesting && c === '.' ? '/' : c } } else if (state === ParseSegmentState.paramOptional) { if (c === '[') { diff --git a/src/options.ts b/src/options.ts index 669148c31..d808bef84 100644 --- a/src/options.ts +++ b/src/options.ts @@ -3,6 +3,7 @@ import { Awaitable, getFileBasedRouteName, isArray, warn } from './core/utils' import type { TreeNode } from './core/tree' import { resolve } from 'pathe' import { EditableTreeNode } from './core/extendRoutes' +import { ParseSegmentOptions } from './core/treeNodeValue' export interface RoutesFolderOption { /** @@ -124,6 +125,11 @@ export interface ResolvedOptions { * Activates debug logs. */ logs: boolean + + /** + * @inheritDoc ParseSegmentOptions + */ + pathParser: ParseSegmentOptions } /** @@ -152,6 +158,9 @@ export const DEFAULT_OPTIONS: ResolvedOptions = { dts: isPackageExists('typescript'), logs: false, _inspect: false, + pathParser: { + dotNesting: true, + }, } export interface ServerContext {