Skip to content

Commit

Permalink
fix: correctly trim extensions from routesFolder
Browse files Browse the repository at this point in the history
fix #274
  • Loading branch information
posva committed May 20, 2024
1 parent c67179c commit b8a9473
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 8 deletions.
26 changes: 26 additions & 0 deletions src/codegen/generateRouteMap.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { describe, expect, it } from 'vitest'
import { generateRouteNamedMap } from './generateRouteMap'
import { PrefixTree } from '../core/tree'
import { resolveOptions } from '../options'
import { resolve } from 'node:path'

const DEFAULT_OPTIONS = resolveOptions({})

Expand Down Expand Up @@ -156,6 +157,31 @@ describe('generateRouteNamedMap', () => {
}"
`)
})

// https://github.com/posva/unplugin-vue-router/issues/274
it('removes routeFolders.extensions from the path', () => {
const tree = new PrefixTree(
resolveOptions({
extensions: ['.pagina.vue'],
routesFolder: [
{ src: 'src/pages', extensions: ['.page.vue'] },
{ src: 'src/paginas' },
],
})
)

tree.insert('other.pagina.vue', resolve('src/paginas/other.pagina.vue'))
tree.insert('index.page.vue', resolve('src/pages/index.page.vue'))
tree.insert('about.page.vue', resolve('src/pages/about.page.vue'))

expect(formatExports(generateRouteNamedMap(tree))).toMatchInlineSnapshot(`

Check failure on line 177 in src/codegen/generateRouteMap.spec.ts

View workflow job for this annotation

GitHub Actions / test (18.x, windows-latest)

src/codegen/generateRouteMap.spec.ts > generateRouteNamedMap > removes routeFolders.extensions from the path

Error: Snapshot `generateRouteNamedMap > removes routeFolders.extensions from the path 1` mismatched - Expected + Received "export interface RouteNamedMap { - '/': RouteRecordInfo<'/', '/', Record<never, never>, Record<never, never>>, - '/about': RouteRecordInfo<'/about', '/about', Record<never, never>, Record<never, never>>, '/other': RouteRecordInfo<'/other', '/other', Record<never, never>, Record<never, never>>, }" ❯ src/codegen/generateRouteMap.spec.ts:177:56

Check failure on line 177 in src/codegen/generateRouteMap.spec.ts

View workflow job for this annotation

GitHub Actions / test (lts/*, windows-latest)

src/codegen/generateRouteMap.spec.ts > generateRouteNamedMap > removes routeFolders.extensions from the path

Error: Snapshot `generateRouteNamedMap > removes routeFolders.extensions from the path 1` mismatched - Expected + Received "export interface RouteNamedMap { - '/': RouteRecordInfo<'/', '/', Record<never, never>, Record<never, never>>, - '/about': RouteRecordInfo<'/about', '/about', Record<never, never>, Record<never, never>>, '/other': RouteRecordInfo<'/other', '/other', Record<never, never>, Record<never, never>>, }" ❯ src/codegen/generateRouteMap.spec.ts:177:56
"export interface RouteNamedMap {
'/': RouteRecordInfo<'/', '/', Record<never, never>, Record<never, never>>,
'/about': RouteRecordInfo<'/about', '/about', Record<never, never>, Record<never, never>>,
'/other': RouteRecordInfo<'/other', '/other', Record<never, never>, Record<never, never>>,
}"
`)
})
})

/**
Expand Down
2 changes: 1 addition & 1 deletion src/core/context.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ResolvedOptions } from '../options'
import { ResolvedOptions, RoutesFolderOption } from '../options'

Check failure on line 1 in src/core/context.ts

View workflow job for this annotation

GitHub Actions / lint

'RoutesFolderOption' is declared but its value is never read.
import { TreeNode, PrefixTree } from './tree'
import { promises as fs } from 'fs'
import { asRoutePath, ImportsMap, logTree, throttle } from './utils'
Expand Down
37 changes: 31 additions & 6 deletions src/core/tree.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { ResolvedOptions } from '../options'
import type { ResolvedOptions, RoutesFolderOption } from '../options'
import {
createTreeNodeValue,
TreeNodeValueOptions,
TreeRouteParam,
} from './treeNodeValue'
import type { TreeNodeValue } from './treeNodeValue'
import { trimExtension } from './utils'
import { resolveOverridableOption, trimExtension } from './utils'
import { CustomRouteBlock } from './customBlock'
import { RouteMeta } from 'vue-router'

Expand Down Expand Up @@ -69,9 +69,16 @@ export class TreeNode {
* @param filePath - file path, defaults to path for convenience and testing
*/
insert(path: string, filePath: string = path): TreeNode {
// find the `routesFolder` resolved option that matches the filepath
const folderOptions = findFolderOptions(this.options.routesFolder, filePath)

const { tail, segment, viewName, isComponent } = splitFilePath(
path,
this.options
// use the correct extensions for the folder
resolveOverridableOption(
this.options.extensions,
folderOptions?.extensions
)
)

if (!this.children.has(segment)) {
Expand Down Expand Up @@ -161,10 +168,14 @@ export class TreeNode {
* @param path - path segment of the file
*/
remove(path: string) {
const folderOptions = findFolderOptions(this.options.routesFolder, path)
// TODO: rename remove to removeChild
const { tail, segment, viewName, isComponent } = splitFilePath(
path,
this.options
resolveOverridableOption(
this.options.extensions,
folderOptions?.extensions
)
)

const child = this.children.get(segment)
Expand Down Expand Up @@ -319,15 +330,15 @@ export class PrefixTree extends TreeNode {
*
* @param filePath - filePath to split
*/
function splitFilePath(filePath: string, options: ResolvedOptions) {
function splitFilePath(filePath: string, extensions: string[]) {
const slashPos = filePath.indexOf('/')
let head = slashPos < 0 ? filePath : filePath.slice(0, slashPos)
const tail = slashPos < 0 ? '' : filePath.slice(slashPos + 1)

let segment = head
// only the last segment can be a filename with an extension
if (!tail) {
segment = trimExtension(head, options.extensions)
segment = trimExtension(head, extensions)
}
let viewName = 'default'

Expand All @@ -348,3 +359,17 @@ function splitFilePath(filePath: string, options: ResolvedOptions) {
isComponent,
}
}

/**
* Find the folder options that match the file path.
*
* @param folderOptions `options.routesFolder` option
* @param filePath resolved file path
* @returns
*/
function findFolderOptions(
folderOptions: RoutesFolderOption[],
filePath: string
): RoutesFolderOption | undefined {
return folderOptions.find((folder) => filePath.includes(folder.src))
}
22 changes: 21 additions & 1 deletion src/core/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { TreeNode } from './tree'
import type { RouteRecordOverride, TreeRouteParam } from './treeNodeValue'
import { pascalCase } from 'scule'
import { ResolvedOptions, RoutesFolderOption } from '../options'
import {
ResolvedOptions,
RoutesFolderOption,
_OverridableOption,
} from '../options'

export function warn(
msg: string,
Expand Down Expand Up @@ -77,6 +81,22 @@ export function trimExtension(
return path
}

/**
* Resolves an overridable option by calling the function with the existing value if it's a function, otherwise
* returning the passed `value`. If `value` is undefined, it returns the `defaultValue` instead.
*
* @param defaultValue default value for the option
* @param value and overridable option
*/
export function resolveOverridableOption<T>(
defaultValue: T,
value?: _OverridableOption<T>
): T {
return typeof value === 'function'
? (value as (existing: T) => T)(defaultValue)
: value ?? defaultValue
}

export function throttle(fn: () => void, wait: number, initialWait: number) {
let pendingExecutionTimeout: ReturnType<typeof setTimeout> | null = null
let pendingExecution = false
Expand Down

0 comments on commit b8a9473

Please sign in to comment.