Skip to content

Commit

Permalink
fix: allow overriding and extending folder options
Browse files Browse the repository at this point in the history
  • Loading branch information
posva committed May 18, 2023
1 parent 086494b commit 1f6e312
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 56 deletions.
74 changes: 56 additions & 18 deletions src/core/RoutesFolderWatcher.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
import chokidar from 'chokidar'
import { normalize } from 'pathe'
import { ResolvedOptions, RoutesFolderOption } from '../options'
import {
ResolvedOptions,
RoutesFolderOption,
RoutesFolderOptionResolved,
_OverridableOption,
} from '../options'
import { asRoutePath } from './utils'

// TODO: export an implementable interface to create a watcher and let users provide a different watcher than chokidar to improve performance on windows

export class RoutesFolderWatcher {
export class RoutesFolderWatcher implements RoutesFolderOptionResolved {
src: string
pathPrefix: string
path: string
extensions: string[]
filePatterns: string[]
exclude: string[]

watcher: chokidar.FSWatcher
options: ResolvedOptions

constructor(routesFolder: RoutesFolderOption, options: ResolvedOptions) {
this.src = routesFolder.src
this.pathPrefix = routesFolder.path || ''
this.options = options
constructor(folderOptions: RoutesFolderOptionResolved) {
this.src = folderOptions.src
this.path = folderOptions.path
this.exclude = folderOptions.exclude
this.extensions = folderOptions.extensions
this.filePatterns = folderOptions.filePatterns

this.watcher = chokidar.watch(this.src, {
ignoreInitial: true,
// disableGlobbing: true,
ignorePermissionErrors: true,
ignored: options.exclude,
ignored: this.exclude,
// useFsEvents: true,
// TODO: allow user options
})
Expand All @@ -35,19 +44,12 @@ export class RoutesFolderWatcher {
// ensure consistent path for Windows and Unix
filePath = normalize(filePath)
// skip other extensions
if (
this.options.extensions.every(
(extension) => !filePath.endsWith(extension)
)
) {
if (this.extensions.every((extension) => !filePath.endsWith(extension))) {
return
}
handler({
filePath,
routePath: asRoutePath(
{ src: this.src, path: this.pathPrefix },
filePath
),
routePath: asRoutePath({ src: this.src, path: this.path }, filePath),
})
})
return this
Expand All @@ -64,3 +66,39 @@ export interface HandlerContext {
// routePath
routePath: string
}

export function resolveFolderOptions(
globalOptions: ResolvedOptions,
folderOptions: RoutesFolderOption
): RoutesFolderOptionResolved {
return {
src: folderOptions.src,
path: folderOptions.path || '',
extensions: overrideOption(
globalOptions.extensions,
folderOptions.extensions
),
exclude: overrideOption(globalOptions.exclude, folderOptions.exclude),
filePatterns: overrideOption(
globalOptions.filePatterns,
folderOptions.filePatterns
),
}
}

function overrideOption(
existing: string[] | string,
newValue: undefined | string[] | string | ((existing: string[]) => string[])
): string[] {
const asArray = typeof existing === 'string' ? [existing] : existing
// allow extending when a function is passed
if (typeof newValue === 'function') {
return newValue(asArray)
}
// override if passed
if (typeof newValue !== 'undefined') {
return typeof newValue === 'string' ? [newValue] : newValue
}
// fallback to existing
return asArray
}
69 changes: 34 additions & 35 deletions src/core/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ import fg from 'fast-glob'
import { resolve } from 'pathe'
import { ServerContext } from '../options'
import { getRouteBlock } from './customBlock'
import { RoutesFolderWatcher, HandlerContext } from './RoutesFolderWatcher'
import {
RoutesFolderWatcher,
HandlerContext,
resolveFolderOptions,
} from './RoutesFolderWatcher'
import { generateDTS as _generateDTS } from '../codegen/generateDTS'
import { generateVueRouterProxy as _generateVueRouterProxy } from '../codegen/vueRouterModule'
import { hasNamedExports } from '../data-fetching/parse'
Expand Down Expand Up @@ -55,45 +59,40 @@ export function createRoutesContext(options: ResolvedOptions) {
return
}

const globalPattern = appendExtensionListToPattern(
options.filePatterns,
options.extensions
)

// get the initial list of pages
await Promise.all(
routesFolder.map((folder) => {
if (startWatchers) {
watchers.push(setupWatcher(new RoutesFolderWatcher(folder, options)))
}

// override the pattern if the folder has a custom pattern
const pattern = folder.filePatterns
? appendExtensionListToPattern(
folder.filePatterns,
// also override the extensions if the folder has a custom extensions
folder.extensions || options.extensions
)
: globalPattern
routesFolder
.map((folder) => resolveFolderOptions(options, folder))
.map((folder) => {
if (startWatchers) {
watchers.push(setupWatcher(new RoutesFolderWatcher(folder)))
}

// override the pattern if the folder has a custom pattern
const pattern = appendExtensionListToPattern(
folder.filePatterns,
// also override the extensions if the folder has a custom extensions
folder.extensions
)

return fg(pattern, {
cwd: folder.src,
// TODO: do they return the symbolic link path or the original file?
// followSymbolicLinks: false,
ignore: folder.exclude || options.exclude,
})
.then((files) => files.map((file) => resolve(folder.src, file)))
.then((files) =>
Promise.all(
files.map((file) =>
addPage({
routePath: asRoutePath(folder, file),
filePath: file,
})
return fg(pattern, {
cwd: folder.src,
// TODO: do they return the symbolic link path or the original file?
// followSymbolicLinks: false,
ignore: folder.exclude,
})
.then((files) => files.map((file) => resolve(folder.src, file)))
.then((files) =>
Promise.all(
files.map((file) =>
addPage({
routePath: asRoutePath(folder, file),
filePath: file,
})
)
)
)
)
})
})
)

for (const route of editableRoutes) {
Expand Down
18 changes: 15 additions & 3 deletions src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,31 @@ export interface RoutesFolderOption {
/**
* Allows to override the global `filePattern` option for this folder.
*/
filePatterns?: string | string[]
filePatterns?: _OverridableOption<string[]> | string

/**
* Allows to override the global `exclude` option for this folder.
*/
exclude?: string[]
exclude?: _OverridableOption<string[]>

/**
* Allows to override the global `extensions` option for this folder.
*/
extensions?: string[]
extensions?: _OverridableOption<string[]>
}

/**
* Normalized options for a routes folder.
*/
export interface RoutesFolderOptionResolved extends RoutesFolderOption {
path: string
filePatterns: string[]
exclude: string[]
extensions: string[]
}

export type _OverridableOption<T> = T | ((existing: T) => T)

export type _RoutesFolder = string | RoutesFolderOption
export type RoutesFolder = _RoutesFolder[] | _RoutesFolder

Expand Down

0 comments on commit 1f6e312

Please sign in to comment.