Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor basePath to withBasePath #224

Merged
merged 3 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .changeset/lazy-camels-appear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'renoun': minor
---

Moves the `Directory` `basePath` option to `<Directory>.withBasePath`. This aligns with the recent refactor of other `Directory` options.

### Breaking Changes

Update the `basePath` option to `withBasePath`:

```diff
export const posts = new Directory<{ mdx: PostType }>({
path: 'posts',
-- basePath: 'blog',
})
++ .withBasePath('blog')
```
30 changes: 11 additions & 19 deletions packages/renoun/src/file-system/FileSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@ import {
resolveTypeAtLocation,
} from '../project/client.js'
import type { ProjectOptions } from '../project/types.js'
import { relative } from '../utils/path.js'
import {
join,
relative,
ensureRelativePath,
removeOrderPrefixes,
} from '../utils/path.js'
import type { SymbolFilter } from '../utils/resolve-type.js'
import type { DirectoryEntry } from './types.js'

interface FileSystemOptions {
/** Root path to use when reading files. */
rootPath?: string

/** Base path to prepend to all paths. */
basePath?: string

/** Path to the tsconfig.json file to use when analyzing types and determining if a file is excluded. */
tsConfigPath?: string

Expand All @@ -29,14 +31,12 @@ interface FileSystemOptions {

export abstract class FileSystem {
#rootPath: string
#basePath?: string
#tsConfigPath: string
#tsConfig?: any
#projectOptions: ProjectOptions

constructor(options: FileSystemOptions = {}) {
this.#rootPath = options.rootPath || '.'
this.#basePath = options.basePath
this.#tsConfigPath = options.tsConfigPath || 'tsconfig.json'
this.#projectOptions = {
projectId: options.projectId,
Expand All @@ -57,26 +57,18 @@ export abstract class FileSystem {
abstract isFilePathGitIgnored(filePath: string): boolean

getRootPath() {
return this.#rootPath
}

getBasePath() {
return this.#basePath
return ensureRelativePath(this.#rootPath)
}

getUrlPathRelativeTo(path: string, includeBasePath = true) {
const parsedPath = relative(this.getRootPath(), path)
getPathRelativeTo(path: string, options: { basePath?: string } = {}) {
const rootPath = this.getRootPath()
const relativePath = relative(rootPath, removeOrderPrefixes(path))
// remove leading dot
.replace(/^\.\//, '')
// remove trailing slash
.replace(/\/$/, '')
const basePath = this.getBasePath()

if (includeBasePath && basePath) {
return `/${basePath}/${parsedPath}`
}

return `/${parsedPath}`
return join('/', options.basePath, relativePath)
}

#getTsConfig() {
Expand Down
31 changes: 13 additions & 18 deletions packages/renoun/src/file-system/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ describe('file system', () => {
await expect(
fileExport!.getRuntimeValue()
).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: [renoun] Schema validation failed to parse export "metadata" at file path "./index.ts" errored with: Expected a title]`
`[Error: [renoun] Schema validation failed to parse export "metadata" at file path "index.ts" errored with: Expected a title]`
)
})

Expand Down Expand Up @@ -550,8 +550,7 @@ describe('file system', () => {
test('generates tree navigation', async () => {
const projectDirectory = new Directory({
path: 'fixtures/project',
basePath: 'project',
})
}).withBasePath('project')

async function buildTreeNavigation<Entry extends FileSystemEntry<any>>(
entry: Entry
Expand Down Expand Up @@ -612,28 +611,24 @@ describe('file system', () => {
expect(readmeFile?.getName()).toBe('components')
})

test('adds basePath to file and directory getPath', async () => {
test('adds base path to entry getPath and getPathSegments', async () => {
const projectDirectory = new Directory({
path: 'fixtures/project',
basePath: 'renoun',
})
}).withBasePath('renoun')

expect(projectDirectory.getBasePath()).toBe('renoun')

const file = await projectDirectory.getFileOrThrow('server', 'ts')
const directory = await projectDirectory.getDirectoryOrThrow('rpc')

expect(file.getPath()).toBe('/renoun/server')
expect(directory.getPath()).toBe('/renoun/rpc')
})
expect(file.getPathSegments()).toEqual(['renoun', 'server'])

test('does not add basePath to getPathSegments', async () => {
const projectDirectory = new Directory({
path: 'fixtures/project',
basePath: 'renoun',
})
const segments = (
await projectDirectory.getDirectoryOrThrow('rpc')
).getPathSegments()
const directory = await projectDirectory.getDirectoryOrThrow('rpc')

expect(segments).toEqual(['rpc'])
expect(directory.getPath({ includeBasePath: false })).toBe('/rpc')
expect(directory.getPathSegments({ includeBasePath: false })).toEqual([
'rpc',
])
})

test('uses file name for anonymous default export metadata', async () => {
Expand Down
112 changes: 62 additions & 50 deletions packages/renoun/src/file-system/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
import type { SymbolFilter } from '../utils/resolve-type.js'
import type { FileSystem } from './FileSystem.js'
import { NodeFileSystem } from './NodeFileSystem.js'
import { VirtualFileSystem } from './VirtualFileSystem.js'
import {
isJavaScriptLikeExtension,
type HasJavaScriptLikeExtensions,
Expand Down Expand Up @@ -94,35 +93,33 @@ export class File<
return extensionName(this.#path).slice(1)
}

/** Get a URL-friendly path to the file. */
getPath() {
/** Get the path of the file. */
getPath(options: { includeBasePath?: boolean } = { includeBasePath: true }) {
const fileSystem = this.#directory.getFileSystem()
return fileSystem.getUrlPathRelativeTo(
removeOrderPrefixes(removeExtension(this.#path))
)
}
const basePath = this.#directory.getBasePath()

/** Get the path segments of the file. */
getPathSegments() {
const fileSystem = this.#directory.getFileSystem()
const path = fileSystem.getUrlPathRelativeTo(
removeOrderPrefixes(removeExtension(this.#path)),
false
return removeExtension(
fileSystem.getPathRelativeTo(
this.#path,
options.includeBasePath ? { basePath } : undefined
)
)
return path.split('/').filter(Boolean)
}

/** Get the path of the file relative to another path. */
getPathRelativeTo(path: string) {
return relative(path, this.#path)
/** Get the path segments of the file. */
getPathSegments(
options: { includeBasePath?: boolean } = { includeBasePath: true }
) {
return this.getPath(options).split('/').filter(Boolean)
}

/** Get the relative path to the file. */
/** Get the relative file system path of the file. */
getRelativePath() {
return this.#path
const fileSystem = this.#directory.getFileSystem()
return relative(fileSystem.getRootPath(), this.#path)
}

/** Get the absolute path of the file. */
/** Get the absolute file system path of the file. */
getAbsolutePath() {
const fileSystem = this.#directory.getFileSystem()
return fileSystem.getAbsolutePath(this.#path)
Expand Down Expand Up @@ -330,10 +327,7 @@ export class JavaScriptFileExportWithRuntime<
}

const exportName = this.getBaseName()
const fileSystem = (await this.#file.getDirectory()).getFileSystem()
const fileModule = await this.#getModule(
this.#file.getPathRelativeTo(fileSystem.getRootPath())
)
const fileModule = await this.#getModule(this.#file.getRelativePath())
const fileModuleExport = fileModule[this.getBaseName()]

if (fileModuleExport === undefined) {
Expand Down Expand Up @@ -506,9 +500,6 @@ interface DirectoryOptions<Types extends ExtensionTypes = ExtensionTypes> {
/** The path to the directory in the file system. */
path?: string

/** The base path used for all entry `getPath` methods. */
basePath?: string

/** The file system to use for reading directory entries. */
fileSystem?: FileSystem

Expand Down Expand Up @@ -540,7 +531,6 @@ export class Directory<
? options.path
: join('.', options.path)
: '.'
this.#basePath = options.basePath
this.#fileSystem = options.fileSystem
this.#entryGroup = options.entryGroup
}
Expand All @@ -554,11 +544,11 @@ export class Directory<
>(options?: DirectoryOptions<Types>): Directory<Types, HasModule, Entry> {
const directory = new Directory<Types, HasModule, Entry>({
path: this.#path,
basePath: this.#basePath,
fileSystem: this.#fileSystem,
...options,
})

directory.#basePath = this.#basePath
directory.#schemas = this.#schemas
if (this.#getModule) {
directory.setModuleGetter(this.#getModule)
Expand All @@ -578,13 +568,32 @@ export class Directory<
if (this.#fileSystem) {
return this.#fileSystem
}
this.#fileSystem = new NodeFileSystem({
rootPath: this.#path,
basePath: this.#basePath,
})
this.#fileSystem = new NodeFileSystem({ rootPath: this.#path })
return this.#fileSystem
}

/** Returns a new `Directory` with a base path applied to all descendant entries. */
withBasePath(path: string): Directory<Types, HasModule, Entry> {
const directory = new Directory<Types, HasModule, Entry>({
path: this.#path,
fileSystem: this.#fileSystem,
})

directory.#basePath = path
directory.#schemas = this.#schemas
if (this.#getModule) {
directory.setModuleGetter(this.#getModule)
}
if (this.#filterCallback) {
directory.setFilterCallback(this.#filterCallback)
}
if (this.#sortCallback) {
directory.setSortCallback(this.#sortCallback)
}

return directory
}

/** Set the module getter for JavaScript files in the directory. */
protected setModuleGetter(getModule: (path: string) => Promise<any>) {
this.#getModule = getModule
Expand All @@ -596,12 +605,11 @@ export class Directory<
): Directory<Types, true, Entry> {
const directory = new Directory<Types, true, Entry>({
path: this.#path,
basePath: this.#basePath,
fileSystem: this.#fileSystem,
})

directory.setDirectory(this)
directory.setModuleGetter(getModule)
directory.#basePath = this.#basePath
directory.#schemas = this.#schemas
if (this.#filterCallback) {
directory.setFilterCallback(this.#filterCallback)
Expand Down Expand Up @@ -640,12 +648,11 @@ export class Directory<
): Directory<Types, HasModule, FilteredEntry> {
const directory = new Directory<Types, HasModule, FilteredEntry>({
path: this.#path,
basePath: this.#basePath,
fileSystem: this.#fileSystem,
})

directory.setDirectory(this)
directory.setFilterCallback(filter)
directory.#basePath = this.#basePath
directory.#schemas = this.#schemas
if (this.#getModule) {
directory.setModuleGetter(this.#getModule)
Expand Down Expand Up @@ -673,12 +680,11 @@ export class Directory<
): Directory<Types, HasModule, Entry> {
const directory = new Directory<Types, HasModule, Entry>({
path: this.#path,
basePath: this.#basePath,
fileSystem: this.#fileSystem,
})

directory.setDirectory(this)
directory.setSortCallback(sort)
directory.#basePath = this.#basePath
directory.#schemas = this.#schemas
if (this.#getModule) {
directory.setModuleGetter(this.#getModule)
Expand Down Expand Up @@ -711,12 +717,11 @@ export class Directory<
): Directory<Types, HasModule, Entry> {
const directory = new Directory<Types, HasModule, Entry>({
path: this.#path,
basePath: this.#basePath,
fileSystem: this.#fileSystem,
})

directory.setDirectory(this)
directory.setSchema(extension, schema)
directory.#basePath = this.#basePath
if (this.#getModule) {
directory.setModuleGetter(this.#getModule)
}
Expand Down Expand Up @@ -972,6 +977,7 @@ export class Directory<
entryGroup: this.#entryGroup,
})

directory.#basePath = this.#basePath
directory.#schemas = this.#schemas

if (this.#getModule) {
Expand Down Expand Up @@ -1099,19 +1105,25 @@ export class Directory<
}

/** Get a URL-friendly path of the directory. */
getPath() {
getPath(options: { includeBasePath?: boolean } = { includeBasePath: true }) {
const fileSystem = this.getFileSystem()
return fileSystem.getUrlPathRelativeTo(removeOrderPrefixes(this.#path))

return fileSystem.getPathRelativeTo(
this.#path,
options.includeBasePath ? { basePath: this.#basePath } : undefined
)
}

/** Get the path segments of the directory. */
getPathSegments() {
const fileSystem = this.getFileSystem()
const path = fileSystem.getUrlPathRelativeTo(
removeOrderPrefixes(this.#path),
false
)
return path.split('/').filter(Boolean)
getPathSegments(
options: { includeBasePath?: boolean } = { includeBasePath: true }
) {
return this.getPath(options).split('/').filter(Boolean)
}

/** Get the configured base path of the directory. */
getBasePath() {
return this.#basePath
}

/** Get the relative path of the directory. */
Expand Down
Loading