feat(kit): handle virtual files in resolvePath and findPath (#26465)

This commit is contained in:
Inesh Bose 2024-04-19 10:43:28 +01:00 committed by GitHub
parent d5e2080cd1
commit 3e610df4dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 74 additions and 2 deletions

View File

@ -0,0 +1,31 @@
import { describe, expect, it } from 'vitest'
import { resolve } from 'pathe'
import { loadNuxt } from './loader/nuxt'
import { findPath, resolvePath } from './resolve'
import { defineNuxtModule } from './module/define'
import { addTemplate } from './template'
const nuxt = await loadNuxt({
overrides: {
modules: [
defineNuxtModule(() => {
addTemplate({
filename: 'my-template.mjs',
getContents: () => 'export const myUtil = () => \'hello\'',
})
}),
],
},
})
describe('resolvePath', () => {
it('should resolve paths correctly', async () => {
expect(await resolvePath('.nuxt/app.config')).toBe(resolve(nuxt.options.buildDir, 'app.config'))
})
})
describe('findPath', () => {
it('should find paths correctly', async () => {
expect(await findPath(resolve(nuxt.options.buildDir, 'my-template'), { virtual: true })).toBe(resolve(nuxt.options.buildDir, 'my-template.mjs'))
})
})

View File

@ -17,6 +17,12 @@ export interface ResolvePathOptions {
/** The file extensions to try. Default is Nuxt configured extensions. */ /** The file extensions to try. Default is Nuxt configured extensions. */
extensions?: string[] extensions?: string[]
/**
* Whether to resolve files that exist in the Nuxt VFS (for example, as a Nuxt template).
* @default false
*/
virtual?: boolean
} }
/** /**
@ -30,9 +36,14 @@ export async function resolvePath (path: string, opts: ResolvePathOptions = {}):
path = normalize(path) path = normalize(path)
// Fast return if the path exists // Fast return if the path exists
if (isAbsolute(path) && existsSync(path) && !(await isDirectory(path))) { if (isAbsolute(path)) {
if (opts?.virtual && existsInVFS(path)) {
return path return path
} }
if (existsSync(path) && !(await isDirectory(path))) {
return path
}
}
// Use current nuxt options // Use current nuxt options
const nuxt = tryUseNuxt() const nuxt = tryUseNuxt()
@ -49,6 +60,10 @@ export async function resolvePath (path: string, opts: ResolvePathOptions = {}):
} }
// Check if resolvedPath is a file // Check if resolvedPath is a file
if (opts?.virtual && existsInVFS(path, nuxt)) {
return path
}
let _isDir = false let _isDir = false
if (existsSync(path)) { if (existsSync(path)) {
_isDir = await isDirectory(path) _isDir = await isDirectory(path)
@ -61,11 +76,17 @@ export async function resolvePath (path: string, opts: ResolvePathOptions = {}):
for (const ext of extensions) { for (const ext of extensions) {
// path.[ext] // path.[ext]
const pathWithExt = path + ext const pathWithExt = path + ext
if (opts?.virtual && existsInVFS(pathWithExt, nuxt)) {
return pathWithExt
}
if (existsSync(pathWithExt)) { if (existsSync(pathWithExt)) {
return pathWithExt return pathWithExt
} }
// path/index.[ext] // path/index.[ext]
const pathWithIndex = join(path, 'index' + ext) const pathWithIndex = join(path, 'index' + ext)
if (opts?.virtual && existsInVFS(pathWithIndex, nuxt)) {
return pathWithIndex
}
if (_isDir && existsSync(pathWithIndex)) { if (_isDir && existsSync(pathWithIndex)) {
return pathWithIndex return pathWithIndex
} }
@ -85,8 +106,17 @@ export async function resolvePath (path: string, opts: ResolvePathOptions = {}):
* Try to resolve first existing file in paths * Try to resolve first existing file in paths
*/ */
export async function findPath (paths: string | string[], opts?: ResolvePathOptions, pathType: 'file' | 'dir' = 'file'): Promise<string | null> { export async function findPath (paths: string | string[], opts?: ResolvePathOptions, pathType: 'file' | 'dir' = 'file'): Promise<string | null> {
const nuxt = opts?.virtual ? tryUseNuxt() : undefined
for (const path of toArray(paths)) { for (const path of toArray(paths)) {
const rPath = await resolvePath(path, opts) const rPath = await resolvePath(path, opts)
// Check VFS
if (opts?.virtual && existsInVFS(rPath, nuxt)) {
return rPath
}
// Check file system
if (await existsSensitive(rPath)) { if (await existsSensitive(rPath)) {
const _isDir = await isDirectory(rPath) const _isDir = await isDirectory(rPath)
if (!pathType || (pathType === 'file' && !_isDir) || (pathType === 'dir' && _isDir)) { if (!pathType || (pathType === 'file' && !_isDir) || (pathType === 'dir' && _isDir)) {
@ -160,6 +190,17 @@ async function isDirectory (path: string) {
return (await fsp.lstat(path)).isDirectory() return (await fsp.lstat(path)).isDirectory()
} }
function existsInVFS (path: string, nuxt = tryUseNuxt()) {
if (!nuxt) { return false }
if (path in nuxt.vfs) {
return true
}
const templates = nuxt.apps.default?.templates ?? nuxt.options.build.templates
return templates.some(template => template.dst === path)
}
export async function resolveFiles (path: string, pattern: string | string[], opts: { followSymbolicLinks?: boolean } = {}) { export async function resolveFiles (path: string, pattern: string | string[], opts: { followSymbolicLinks?: boolean } = {}) {
const files = await globby(pattern, { cwd: path, followSymbolicLinks: opts.followSymbolicLinks ?? true }) const files = await globby(pattern, { cwd: path, followSymbolicLinks: opts.followSymbolicLinks ?? true })
return files.map(p => resolve(path, p)).filter(p => !isIgnored(p)).sort() return files.map(p => resolve(path, p)).filter(p => !isIgnored(p)).sort()