@kubb/core
Version:
Core functionality for Kubb's plugin-based code generation system, providing the foundation for transforming OpenAPI specifications.
109 lines (89 loc) • 3.36 kB
text/typescript
import { join } from 'node:path'
import type { FileMetaBase } from './FileManager.ts'
import type { KubbFile } from './fs/index.ts'
import { getRelativePath } from './fs/index.ts'
import type { Logger } from './logger.ts'
import { TreeNode } from './utils/TreeNode.ts'
type BarrelManagerOptions = {
logger?: Logger
}
export class BarrelManager {
#options: BarrelManagerOptions
constructor(options: BarrelManagerOptions = {}) {
this.#options = options
return this
}
getFiles({ files: generatedFiles, root }: { files: KubbFile.File[]; root?: string; meta?: FileMetaBase | undefined }): Array<KubbFile.File> {
const { logger } = this.#options
const cachedFiles = new Map<KubbFile.Path, KubbFile.File>()
TreeNode.build(generatedFiles, root)?.forEach((treeNode) => {
if (!treeNode || !treeNode.children || !treeNode.parent?.data.path) {
return undefined
}
const barrelFile: KubbFile.File = {
path: join(treeNode.parent?.data.path, 'index.ts') as KubbFile.Path,
baseName: 'index.ts',
exports: [],
sources: [],
}
const previousBarrelFile = cachedFiles.get(barrelFile.path)
const leaves = treeNode.leaves
leaves.forEach((item) => {
if (!item.data.name) {
return undefined
}
const sources = item.data.file?.sources || []
if (!sources.some((source) => source.isIndexable)) {
logger?.emit(
'warning',
`No isIndexable source found(source should have a name and isIndexable):\nFile: ${JSON.stringify(item.data.file, undefined, 2)}`,
)
}
sources.forEach((source) => {
if (!item.data.file?.path || !source.isIndexable || !source.name) {
return undefined
}
const alreadyContainInPreviousBarrelFile = previousBarrelFile?.sources.some(
(item) => item.name === source.name && item.isTypeOnly === source.isTypeOnly,
)
if (alreadyContainInPreviousBarrelFile) {
return undefined
}
if (!barrelFile.exports) {
barrelFile.exports = []
}
// true when we have a subdirectory that also contains barrel files
const isSubExport = !!treeNode.parent?.data.path?.split?.('/')?.length
if (isSubExport) {
barrelFile.exports.push({
name: [source.name],
path: getRelativePath(treeNode.parent?.data.path, item.data.path),
isTypeOnly: source.isTypeOnly,
})
} else {
barrelFile.exports.push({
name: [source.name],
path: `./${item.data.file.baseName}`,
isTypeOnly: source.isTypeOnly,
})
}
barrelFile.sources.push({
name: source.name,
isTypeOnly: source.isTypeOnly,
//TODO use parser to generate import
value: '',
isExportable: false,
isIndexable: false,
})
})
})
if (previousBarrelFile) {
previousBarrelFile.sources.push(...barrelFile.sources)
previousBarrelFile.exports?.push(...(barrelFile.exports || []))
} else {
cachedFiles.set(barrelFile.path, barrelFile)
}
})
return [...cachedFiles.values()]
}
}