@kubb/middleware-barrel 5.0.0-beta.5 → 5.0.0-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,98 @@
1
+ <div align="center">
2
+ <h1>@kubb/middleware-barrel</h1>
3
+ <a href="https://kubb.dev" target="_blank" rel="noopener noreferrer">
4
+ <img width="180" src="https://raw.githubusercontent.com/kubb-labs/kubb/main/assets/logo.png" alt="Kubb logo">
5
+ </a>
6
+
7
+ [![npm version][npm-version-src]][npm-version-href]
8
+ [![npm downloads][npm-downloads-src]][npm-downloads-href]
9
+ [![Coverage][coverage-src]][coverage-href]
10
+ [![License][license-src]][license-href]
11
+ [![Sponsors][sponsors-src]][sponsors-href]
12
+
13
+ <h4>
14
+ <a href="https://kubb.dev/" target="_blank">Documentation</a>
15
+ <span> · </span>
16
+ <a href="https://github.com/kubb-labs/kubb/issues/" target="_blank">Report Bug</a>
17
+ <span> · </span>
18
+ <a href="https://github.com/kubb-labs/kubb/issues/" target="_blank">Request Feature</a>
19
+ </h4>
20
+ </div>
21
+
22
+ Barrel-file middleware for Kubb. Automatically generates `index.ts` re-export files for each plugin output directory and an optional root barrel after all plugins have run.
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ bun add @kubb/middleware-barrel
28
+ # or
29
+ pnpm add @kubb/middleware-barrel
30
+ # or
31
+ npm install @kubb/middleware-barrel
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ Add `middlewareBarrel` to the `middleware` array in your `kubb.config.ts`:
37
+
38
+ ```typescript
39
+ import { defineConfig } from 'kubb'
40
+ import { middlewareBarrel } from '@kubb/middleware-barrel'
41
+
42
+ export default defineConfig({
43
+ input: {
44
+ path: './openapi.yaml',
45
+ },
46
+ output: {
47
+ path: './src/gen',
48
+ },
49
+ middleware: [
50
+ middlewareBarrel({
51
+ type: 'named',
52
+ }),
53
+ ],
54
+ })
55
+ ```
56
+
57
+ ## Options
58
+
59
+ | Option | Type | Default | Description |
60
+ | ------ | --------------------------------- | --------- | ------------------------------------------- |
61
+ | `type` | `'all' \| 'named' \| 'propagate'` | `'named'` | Export style for the generated barrel files |
62
+
63
+ ### Export types
64
+
65
+ | Value | Output |
66
+ | ------------- | ------------------------------------------------------------------------------- |
67
+ | `'all'` | `export * from './...'` — wildcard re-exports |
68
+ | `'named'` | `export { ... } from './...'` — named re-exports, tree-shaking friendly |
69
+ | `'propagate'` | `export * from './...'` on index files only, propagating up through directories |
70
+
71
+ ## How it works
72
+
73
+ After every plugin finishes generating files, `@kubb/middleware-barrel` walks the output tree and creates an `index.ts` in each directory, re-exporting everything inside. It then creates a root `index.ts` at the top of the output path that re-exports from all plugin directories.
74
+
75
+ ## Supporting Kubb
76
+
77
+ Kubb is an open source project with its ongoing development made possible entirely by the support of Sponsors. If you would like to become a sponsor, please consider:
78
+
79
+ - [Become a Sponsor on GitHub](https://github.com/sponsors/stijnvanhulle)
80
+
81
+ <p align="center">
82
+ <a href="https://github.com/sponsors/stijnvanhulle">
83
+ <img src="https://raw.githubusercontent.com/stijnvanhulle/sponsors/main/sponsors.svg" alt="My sponsors" />
84
+ </a>
85
+ </p>
86
+
87
+ <!-- Badges -->
88
+
89
+ [npm-version-src]: https://img.shields.io/npm/v/@kubb/middleware-barrel?flat&colorA=18181B&colorB=f58517
90
+ [npm-version-href]: https://npmjs.com/package/@kubb/middleware-barrel
91
+ [npm-downloads-src]: https://img.shields.io/npm/dm/@kubb/middleware-barrel?flat&colorA=18181B&colorB=f58517
92
+ [npm-downloads-href]: https://npmjs.com/package/@kubb/middleware-barrel
93
+ [license-src]: https://img.shields.io/github/license/kubb-labs/kubb.svg?flat&colorA=18181B&colorB=f58517
94
+ [license-href]: https://github.com/kubb-labs/kubb/blob/main/LICENSE
95
+ [coverage-src]: https://img.shields.io/codecov/c/github/kubb-labs/kubb?style=flat&colorA=18181B&colorB=f58517
96
+ [coverage-href]: https://www.npmjs.com/package/@kubb/middleware-barrel
97
+ [sponsors-src]: https://img.shields.io/github/sponsors/stijnvanhulle?style=flat&colorA=18181B&colorB=f58517
98
+ [sponsors-href]: https://github.com/sponsors/stijnvanhulle/
package/dist/index.cjs CHANGED
@@ -109,32 +109,13 @@ function compareByPath(a, b) {
109
109
  return a.path < b.path ? -1 : a.path > b.path ? 1 : 0;
110
110
  }
111
111
  //#endregion
112
- //#region src/utils/excludedPaths.ts
113
- /**
114
- * Builds a POSIX-normalized prefix for a plugin's output directory, with a trailing `/`.
115
- *
116
- * Used to detect (and later exclude) files generated by plugins that opted out of the root barrel.
117
- */
118
- function getPluginOutputPrefix(plugin, config) {
119
- return `${toPosixPath((0, node_path.resolve)(config.root, config.output.path, plugin.options.output.path))}/`;
120
- }
121
- /**
122
- * Returns `true` when `filePath` lives under any of the given excluded directory prefixes.
123
- *
124
- * Both sides are POSIX-normalized so Windows backslash paths match correctly.
125
- */
126
- function isExcludedPath(filePath, prefixes) {
127
- const normalized = toPosixPath(filePath);
128
- return prefixes.values().some((prefix) => normalized.startsWith(prefix));
129
- }
130
- //#endregion
131
112
  //#region src/constants.ts
132
113
  /**
133
114
  * Full file name for barrel files (with extension).
134
115
  */
135
116
  const BARREL_FILENAME = "index.ts";
136
117
  //#endregion
137
- //#region src/utils/getBarrelFiles.ts
118
+ //#region src/utils.ts
138
119
  const SOURCE_EXTENSIONS = new Set([
139
120
  ".ts",
140
121
  ".tsx",
@@ -276,6 +257,23 @@ function getBarrelFiles({ outputPath, files, barrelType, nested = false, recursi
276
257
  }, true, result);
277
258
  return result;
278
259
  }
260
+ /**
261
+ * Builds a POSIX-normalized prefix for a plugin's output directory, with a trailing `/`.
262
+ *
263
+ * Used to detect (and later exclude) files generated by plugins that opted out of the root barrel.
264
+ */
265
+ function getPluginOutputPrefix(plugin, config) {
266
+ return `${toPosixPath((0, node_path.resolve)(config.root, config.output.path, plugin.options.output.path))}/`;
267
+ }
268
+ /**
269
+ * Returns `true` when `filePath` lives under any of the given excluded directory prefixes.
270
+ *
271
+ * Both sides are POSIX-normalized so Windows backslash paths match correctly.
272
+ */
273
+ function isExcludedPath(filePath, prefixes) {
274
+ const normalized = toPosixPath(filePath);
275
+ return prefixes.values().some((prefix) => normalized.startsWith(prefix));
276
+ }
279
277
  //#endregion
280
278
  //#region src/middleware.ts
281
279
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["path"],"sources":["../../../internals/utils/src/path.ts","../../../internals/utils/src/buildTree.ts","../src/utils/excludedPaths.ts","../src/constants.ts","../src/utils/getBarrelFiles.ts","../src/middleware.ts"],"sourcesContent":["/**\n * Converts a filesystem path to use POSIX (`/`) separators.\n *\n * Most of the codebase compares and composes paths as strings (prefix matching, joining for\n * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated\n * paths, but on Windows it returns `\\`-separated paths, which breaks every such comparison.\n *\n * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the\n * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is\n * exercisable from POSIX CI.\n *\n * @example\n * toPosixPath('C:\\\\repo\\\\src\\\\pet.ts') // 'C:/repo/src/pet.ts'\n */\nexport function toPosixPath(filePath: string): string {\n return filePath.replaceAll('\\\\', '/')\n}\n","import { toPosixPath } from './path.ts'\n\n/**\n * A node in the directory tree used to compute barrel file exports.\n * Either represents a directory (with `children`) or a file (`isFile: true`, empty `children`).\n */\nexport type BuildTree = {\n /**\n * Absolute filesystem path of this directory or file. Always normalized to POSIX (`/`) separators.\n */\n path: string\n /**\n * Sub-directories and files contained within this directory.\n * Always empty for file nodes.\n */\n children: Array<BuildTree>\n /**\n * `true` when this node represents a file (leaf), `false` for directory nodes.\n */\n isFile: boolean\n}\n\n/**\n * Builds a directory tree rooted at `rootPath` from a list of absolute file paths.\n * Paths outside `rootPath` are silently ignored. Children are sorted alphabetically\n * by path so consumers (barrel exports, propagated indexes) emit a deterministic order.\n *\n * Both POSIX (`/`) and Windows (`\\`) separators are accepted in input paths; emitted node\n * paths are always POSIX-normalized so downstream prefix/lookup operations behave the same\n * across platforms.\n *\n * @example\n * ```ts\n * buildTree('/src/gen/types', [\n * '/src/gen/types/pet.ts',\n * '/src/gen/types/pets/listPets.ts',\n * ])\n * ```\n */\nexport function buildTree(rootPath: string, filePaths: ReadonlyArray<string>): BuildTree {\n const normalizedRoot = toPosixPath(rootPath)\n const root: BuildTree = { path: normalizedRoot, children: [], isFile: false }\n // Per-directory child lookup avoids the O(N) `Array.find` scan during insertion.\n const childIndex = new Map<BuildTree, Map<string, BuildTree>>()\n childIndex.set(root, new Map())\n\n const rootPrefix = `${normalizedRoot}/`\n\n for (const filePath of filePaths) {\n const normalized = toPosixPath(filePath)\n if (!normalized.startsWith(rootPrefix)) continue\n\n const parts = normalized.slice(rootPrefix.length).split('/')\n if (parts.length === 0) continue\n\n let current = root\n const lastIndex = parts.length - 1\n for (const [i, part] of parts.entries()) {\n if (!part) continue\n\n const isLast = i === lastIndex\n const siblings = childIndex.get(current)!\n let child = siblings.get(part)\n if (!child) {\n child = { path: `${current.path}/${part}`, children: [], isFile: isLast }\n current.children.push(child)\n siblings.set(part, child)\n if (!isLast) childIndex.set(child, new Map())\n }\n current = child\n }\n }\n\n sortTree(root)\n\n return root\n}\n\nfunction sortTree(node: BuildTree): void {\n if (node.children.length === 0) return\n node.children.sort(compareByPath)\n for (const child of node.children) {\n if (!child.isFile) sortTree(child)\n }\n}\n\nfunction compareByPath(a: BuildTree, b: BuildTree): number {\n return a.path < b.path ? -1 : a.path > b.path ? 1 : 0\n}\n","import { resolve } from 'node:path'\nimport type { Config, NormalizedPlugin } from '@kubb/core'\nimport { toPosixPath } from '@internals/utils'\n\n/**\n * Builds a POSIX-normalized prefix for a plugin's output directory, with a trailing `/`.\n *\n * Used to detect (and later exclude) files generated by plugins that opted out of the root barrel.\n */\nexport function getPluginOutputPrefix(plugin: NormalizedPlugin, config: Config): string {\n return `${toPosixPath(resolve(config.root, config.output.path, plugin.options.output.path))}/`\n}\n\n/**\n * Returns `true` when `filePath` lives under any of the given excluded directory prefixes.\n *\n * Both sides are POSIX-normalized so Windows backslash paths match correctly.\n */\nexport function isExcludedPath(filePath: string, prefixes: ReadonlySet<string>): boolean {\n const normalized = toPosixPath(filePath)\n return prefixes.values().some((prefix) => normalized.startsWith(prefix))\n}\n","/**\n * Full file name for barrel files (with extension).\n */\nexport const BARREL_FILENAME = 'index.ts' as const\n","import { extname } from 'node:path'\nimport { createExport, createFile } from '@kubb/ast'\nimport type { ExportNode, FileNode, SourceNode } from '@kubb/ast'\nimport { BARREL_FILENAME } from '../constants.ts'\nimport type { BarrelType } from '../types.ts'\nimport { type BuildTree, buildTree, toPosixPath } from '@internals/utils'\n\nconst SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx'])\nconst BARREL_SUFFIX = `/${BARREL_FILENAME}`\n\nfunction toRelativeModulePath(fromDir: string, filePath: string): string {\n return `./${filePath.slice(fromDir.length + 1)}`\n}\n\nfunction isBarrelPath(path: string): boolean {\n return path.endsWith(BARREL_SUFFIX)\n}\n\nfunction makeBarrel(dirPath: string, exports: Array<ExportNode>): FileNode {\n return createFile({\n baseName: BARREL_FILENAME,\n path: `${dirPath}${BARREL_SUFFIX}`,\n exports,\n sources: [],\n imports: [],\n // Barrel files must never carry a banner or footer: they only re-export\n // symbols and adding a directive like \"use server\" would break consumers.\n banner: undefined,\n footer: undefined,\n })\n}\n\ntype LeafContext = {\n dirPath: string\n leafPath: string\n sourceFile: FileNode | undefined\n}\n\ntype LeafStrategy = (ctx: LeafContext) => Array<ExportNode>\n\nfunction hasOnlyNonIndexableSources(sources: ReadonlyArray<SourceNode>): boolean {\n if (sources.length === 0) return false\n for (const source of sources) {\n if (source.isIndexable) return false\n }\n return true\n}\n\nfunction partitionIndexableNames(sources: ReadonlyArray<SourceNode>): Map<boolean, Set<string>> {\n const byTypeOnly = new Map<boolean, Set<string>>([\n [false, new Set()],\n [true, new Set()],\n ])\n for (const source of sources) {\n if (!source.isIndexable || !source.name) continue\n byTypeOnly.get(Boolean(source.isTypeOnly))!.add(source.name)\n }\n return byTypeOnly\n}\n\nconst allStrategy: LeafStrategy = ({ dirPath, leafPath, sourceFile }) => {\n if (sourceFile && hasOnlyNonIndexableSources(sourceFile.sources)) return []\n return [createExport({ path: toRelativeModulePath(dirPath, leafPath) })]\n}\n\nconst namedStrategy: LeafStrategy = ({ dirPath, leafPath, sourceFile }) => {\n const modulePath = toRelativeModulePath(dirPath, leafPath)\n\n if (!sourceFile) return [createExport({ path: modulePath })]\n\n const namesByTypeOnly = partitionIndexableNames(sourceFile.sources)\n const valueNames = namesByTypeOnly.get(false)!\n const typeNames = namesByTypeOnly.get(true)!\n\n if (valueNames.size === 0 && typeNames.size === 0) {\n if (sourceFile.sources.length > 0) return []\n return [createExport({ path: modulePath })]\n }\n\n const exports: Array<ExportNode> = []\n if (valueNames.size > 0) {\n exports.push(createExport({ name: [...valueNames].sort(), path: modulePath }))\n }\n if (typeNames.size > 0) {\n exports.push(createExport({ name: [...typeNames].sort(), path: modulePath, isTypeOnly: true }))\n }\n return exports\n}\n\nconst LEAF_STRATEGIES: ReadonlyMap<BarrelType, LeafStrategy> = new Map([\n ['all', allStrategy],\n ['named', namedStrategy],\n])\n\ntype LeafWalkParams = {\n sourceFiles: ReadonlyMap<string, FileNode>\n strategy: LeafStrategy\n recursive: boolean\n}\n\n/**\n * Post-order walk that emits a barrel per visited directory.\n */\nfunction walkAllOrNamed(node: BuildTree, params: LeafWalkParams, isRoot: boolean, out: Array<FileNode>): Array<string> {\n const subtreeLeaves: Array<string> = []\n\n for (const child of node.children) {\n if (child.isFile) {\n if (!isBarrelPath(child.path)) subtreeLeaves.push(child.path)\n continue\n }\n\n const childLeaves = walkAllOrNamed(child, params, false, out)\n for (const leaf of childLeaves) subtreeLeaves.push(leaf)\n }\n\n if (!isRoot && !params.recursive) return subtreeLeaves\n\n const exports = subtreeLeaves.flatMap((leafPath) => params.strategy({ dirPath: node.path, leafPath, sourceFile: params.sourceFiles.get(leafPath) }))\n\n if (exports.length > 0) {\n out.push(makeBarrel(node.path, exports))\n }\n\n return subtreeLeaves\n}\n\n/**\n * Recursive walk that emits one barrel per directory, re-exporting files and sub-barrels.\n * Used when nested: true.\n */\nfunction walkNested(node: BuildTree, out: Array<FileNode>): void {\n const exports: Array<ExportNode> = []\n\n for (const child of node.children) {\n if (child.isFile) {\n if (isBarrelPath(child.path)) continue\n exports.push(createExport({ path: toRelativeModulePath(node.path, child.path) }))\n continue\n }\n\n walkNested(child, out)\n exports.push(createExport({ path: toRelativeModulePath(node.path, `${child.path}${BARREL_SUFFIX}`) }))\n }\n\n if (exports.length > 0) {\n out.push(makeBarrel(node.path, exports))\n }\n}\n\ntype IndexedFiles = {\n sourceFiles: ReadonlyMap<string, FileNode>\n paths: ReadonlyArray<string>\n}\n\nfunction indexRelevantFiles(files: ReadonlyArray<FileNode>, outputPath: string): IndexedFiles {\n const outputPrefix = `${toPosixPath(outputPath)}/`\n const sourceFiles = new Map<string, FileNode>()\n const paths: Array<string> = []\n\n for (const file of files) {\n const normalized = toPosixPath(file.path)\n if (!normalized.startsWith(outputPrefix)) continue\n if (isBarrelPath(normalized)) continue\n if (!SOURCE_EXTENSIONS.has(extname(normalized))) continue\n\n sourceFiles.set(normalized, file)\n paths.push(normalized)\n }\n\n return { sourceFiles, paths }\n}\n\ntype GetBarrelFilesParams = {\n /**\n * Absolute directory the barrel(s) should be rooted at.\n * Only files living under this path are considered.\n */\n outputPath: string\n /**\n * Pool of generated files to scan for indexable sources.\n */\n files: ReadonlyArray<FileNode>\n /**\n * Export strategy used when emitting each barrel.\n * - `'all'` re-exports the whole module (`export * from './x'`)\n * - `'named'` re-exports only the indexable named symbols\n */\n barrelType: BarrelType\n /**\n * Generate an `index.ts` in every sub-directory, each re-exporting only what's directly inside it (hierarchical).\n * When false, uses flat generation strategy with optional recursive subdirectory barrels.\n *\n * @default false\n */\n nested?: boolean\n /**\n * Also generate a barrel for each sub-directory when nested is false.\n * No effect when nested is true (always generates hierarchical structure).\n *\n * @default false\n */\n recursive?: boolean\n}\n\n/**\n * Generates barrel `FileNode`s for the directory rooted at `outputPath`.\n */\nexport function getBarrelFiles({ outputPath, files, barrelType, nested = false, recursive = false }: GetBarrelFilesParams): Array<FileNode> {\n const { sourceFiles, paths } = indexRelevantFiles(files, outputPath)\n if (paths.length === 0) return []\n\n const tree = buildTree(outputPath, paths)\n const result: Array<FileNode> = []\n\n // Use nested walk for hierarchical barrel structure\n if (nested) {\n walkNested(tree, result)\n return result\n }\n\n const strategy = LEAF_STRATEGIES.get(barrelType)\n if (!strategy) return result\n\n walkAllOrNamed(tree, { sourceFiles, strategy, recursive }, true, result)\n return result\n}\n","import path from 'node:path'\nimport { resolve } from 'node:path'\nimport { defineMiddleware } from '@kubb/core'\nimport type { Middleware } from '@kubb/core'\nimport type { BarrelConfig, PluginBarrelConfig } from './types.ts'\nimport { getPluginOutputPrefix, isExcludedPath } from './utils/excludedPaths.ts'\nimport { getBarrelFiles } from './utils/getBarrelFiles.ts'\n\ndeclare global {\n namespace Kubb {\n interface PluginOptionsRegistry {\n output: {\n /**\n * Barrel configuration for this plugin's output.\n * Set to `false` to disable barrel generation for this plugin entirely; doing so also\n * excludes the plugin's files from the root barrel.\n *\n * Falls back to `config.output.barrel` when omitted.\n *\n * @default { type: 'named' }\n */\n barrel?: PluginBarrelConfig | false\n }\n }\n interface ConfigOptionsRegistry {\n output: {\n /**\n * Barrel configuration for the root barrel file at `config.output.path/index.ts`.\n * Set to `false` to disable root barrel generation. Individual plugins can override\n * this via their own `output.barrel`.\n *\n * @default { type: 'named' }\n */\n barrel?: BarrelConfig | false\n }\n }\n }\n}\n\n/**\n * Generates `index.ts` barrel files for each plugin and a root barrel at `config.output.path/index.ts`.\n *\n * Each plugin inherits `output.barrel` from `config.output.barrel` (defaults to `{ type: 'named' }`).\n * Set `barrel: false` on a plugin to disable its barrel and exclude it from the root barrel.\n *\n * @example\n * ```ts\n * import { defineConfig } from '@kubb/core'\n * import { middlewareBarrel } from '@kubb/middleware-barrel'\n *\n * export default defineConfig({\n * output: { path: 'src/gen', barrel: { type: 'named' } },\n * plugins: [\n * pluginTs({ output: { path: 'types', barrel: { type: 'all' } } }),\n * pluginZod({ output: { path: 'schemas' } }),\n * ],\n * middleware: [middlewareBarrel()],\n * })\n * ```\n */\n\n/**\n * Stable string identifier for the barrel middleware.\n */\nexport const middlewareBarrelName = 'middleware-barrel' satisfies Middleware['name']\n\nexport const middlewareBarrel = defineMiddleware(() => {\n const excludedPrefixes = new Set<string>()\n\n return {\n name: middlewareBarrelName,\n hooks: {\n 'kubb:plugin:end'({ plugin, config, files, upsertFile }) {\n const pluginBarrel = plugin.options.output?.barrel\n const configBarrel = config.output.barrel\n const defaultBarrel = { type: 'named' } as const\n\n let barrelConfig: PluginBarrelConfig | false\n if (pluginBarrel !== undefined) {\n barrelConfig = pluginBarrel\n } else if (configBarrel !== undefined) {\n // Root config barrel doesn't have nested, so we add it\n barrelConfig = configBarrel === false ? false : { ...configBarrel, nested: false }\n } else {\n barrelConfig = defaultBarrel\n }\n\n if (barrelConfig === false) {\n excludedPrefixes.add(getPluginOutputPrefix(plugin, config))\n return\n }\n\n const barrelType = barrelConfig.type\n const nested = barrelConfig.nested ?? false\n\n const base = resolve(config.root, config.output.path)\n const target = resolve(base, plugin.options.output.path)\n const relative = path.relative(base, target)\n if (relative.startsWith('..') || path.isAbsolute(relative)) {\n throw new Error('Invalid output path')\n }\n const barrelFiles = getBarrelFiles({\n outputPath: target,\n files,\n barrelType,\n nested,\n recursive: true,\n })\n\n if (barrelFiles.length > 0) {\n upsertFile(...barrelFiles)\n }\n },\n 'kubb:plugins:end'({ files, config, upsertFile }) {\n const barrelConfig = config.output.barrel ?? { type: 'named' }\n\n const filteredFiles = excludedPrefixes.size === 0 ? files : files.filter((f) => !isExcludedPath(f.path, excludedPrefixes))\n excludedPrefixes.clear()\n\n if (barrelConfig === false) return\n\n const barrelType = barrelConfig.type\n\n const rootBarrelFiles = getBarrelFiles({\n outputPath: resolve(config.root, config.output.path),\n files: filteredFiles,\n barrelType,\n })\n\n if (rootBarrelFiles.length > 0) {\n upsertFile(...rootBarrelFiles)\n }\n },\n },\n }\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["path"],"sources":["../../../internals/utils/src/path.ts","../../../internals/utils/src/buildTree.ts","../src/constants.ts","../src/utils.ts","../src/middleware.ts"],"sourcesContent":["/**\n * Converts a filesystem path to use POSIX (`/`) separators.\n *\n * Most of the codebase compares and composes paths as strings (prefix matching, joining for\n * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated\n * paths, but on Windows it returns `\\`-separated paths, which breaks every such comparison.\n *\n * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the\n * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is\n * exercisable from POSIX CI.\n *\n * @example\n * toPosixPath('C:\\\\repo\\\\src\\\\pet.ts') // 'C:/repo/src/pet.ts'\n */\nexport function toPosixPath(filePath: string): string {\n return filePath.replaceAll('\\\\', '/')\n}\n","import { toPosixPath } from './path.ts'\n\n/**\n * A node in the directory tree used to compute barrel file exports.\n * Either represents a directory (with `children`) or a file (`isFile: true`, empty `children`).\n */\nexport type BuildTree = {\n /**\n * Absolute filesystem path of this directory or file. Always normalized to POSIX (`/`) separators.\n */\n path: string\n /**\n * Sub-directories and files contained within this directory.\n * Always empty for file nodes.\n */\n children: Array<BuildTree>\n /**\n * `true` when this node represents a file (leaf), `false` for directory nodes.\n */\n isFile: boolean\n}\n\n/**\n * Builds a directory tree rooted at `rootPath` from a list of absolute file paths.\n * Paths outside `rootPath` are silently ignored. Children are sorted alphabetically\n * by path so consumers (barrel exports, propagated indexes) emit a deterministic order.\n *\n * Both POSIX (`/`) and Windows (`\\`) separators are accepted in input paths; emitted node\n * paths are always POSIX-normalized so downstream prefix/lookup operations behave the same\n * across platforms.\n *\n * @example\n * ```ts\n * buildTree('/src/gen/types', [\n * '/src/gen/types/pet.ts',\n * '/src/gen/types/pets/listPets.ts',\n * ])\n * ```\n */\nexport function buildTree(rootPath: string, filePaths: ReadonlyArray<string>): BuildTree {\n const normalizedRoot = toPosixPath(rootPath)\n const root: BuildTree = { path: normalizedRoot, children: [], isFile: false }\n // Per-directory child lookup avoids the O(N) `Array.find` scan during insertion.\n const childIndex = new Map<BuildTree, Map<string, BuildTree>>()\n childIndex.set(root, new Map())\n\n const rootPrefix = `${normalizedRoot}/`\n\n for (const filePath of filePaths) {\n const normalized = toPosixPath(filePath)\n if (!normalized.startsWith(rootPrefix)) continue\n\n const parts = normalized.slice(rootPrefix.length).split('/')\n if (parts.length === 0) continue\n\n let current = root\n const lastIndex = parts.length - 1\n for (const [i, part] of parts.entries()) {\n if (!part) continue\n\n const isLast = i === lastIndex\n const siblings = childIndex.get(current)!\n let child = siblings.get(part)\n if (!child) {\n child = { path: `${current.path}/${part}`, children: [], isFile: isLast }\n current.children.push(child)\n siblings.set(part, child)\n if (!isLast) childIndex.set(child, new Map())\n }\n current = child\n }\n }\n\n sortTree(root)\n\n return root\n}\n\nfunction sortTree(node: BuildTree): void {\n if (node.children.length === 0) return\n node.children.sort(compareByPath)\n for (const child of node.children) {\n if (!child.isFile) sortTree(child)\n }\n}\n\nfunction compareByPath(a: BuildTree, b: BuildTree): number {\n return a.path < b.path ? -1 : a.path > b.path ? 1 : 0\n}\n","/**\n * Full file name for barrel files (with extension).\n */\nexport const BARREL_FILENAME = 'index.ts' as const\n","import { extname, resolve } from 'node:path'\nimport { createExport, createFile } from '@kubb/ast'\nimport type { ExportNode, FileNode, SourceNode } from '@kubb/ast'\nimport type { Config, NormalizedPlugin } from '@kubb/core'\nimport { type BuildTree, buildTree, toPosixPath } from '@internals/utils'\nimport { BARREL_FILENAME } from './constants.ts'\nimport type { BarrelType } from './types.ts'\n\nconst SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx'])\nconst BARREL_SUFFIX = `/${BARREL_FILENAME}`\n\nfunction toRelativeModulePath(fromDir: string, filePath: string): string {\n return `./${filePath.slice(fromDir.length + 1)}`\n}\n\nfunction isBarrelPath(path: string): boolean {\n return path.endsWith(BARREL_SUFFIX)\n}\n\nfunction makeBarrel(dirPath: string, exports: Array<ExportNode>): FileNode {\n return createFile({\n baseName: BARREL_FILENAME,\n path: `${dirPath}${BARREL_SUFFIX}`,\n exports,\n sources: [],\n imports: [],\n // Barrel files must never carry a banner or footer: they only re-export\n // symbols and adding a directive like \"use server\" would break consumers.\n banner: undefined,\n footer: undefined,\n })\n}\n\ntype LeafContext = {\n dirPath: string\n leafPath: string\n sourceFile: FileNode | undefined\n}\n\ntype LeafStrategy = (ctx: LeafContext) => Array<ExportNode>\n\nfunction hasOnlyNonIndexableSources(sources: ReadonlyArray<SourceNode>): boolean {\n if (sources.length === 0) return false\n for (const source of sources) {\n if (source.isIndexable) return false\n }\n return true\n}\n\nfunction partitionIndexableNames(sources: ReadonlyArray<SourceNode>): Map<boolean, Set<string>> {\n const byTypeOnly = new Map<boolean, Set<string>>([\n [false, new Set()],\n [true, new Set()],\n ])\n for (const source of sources) {\n if (!source.isIndexable || !source.name) continue\n byTypeOnly.get(Boolean(source.isTypeOnly))!.add(source.name)\n }\n return byTypeOnly\n}\n\nconst allStrategy: LeafStrategy = ({ dirPath, leafPath, sourceFile }) => {\n if (sourceFile && hasOnlyNonIndexableSources(sourceFile.sources)) return []\n return [createExport({ path: toRelativeModulePath(dirPath, leafPath) })]\n}\n\nconst namedStrategy: LeafStrategy = ({ dirPath, leafPath, sourceFile }) => {\n const modulePath = toRelativeModulePath(dirPath, leafPath)\n\n if (!sourceFile) return [createExport({ path: modulePath })]\n\n const namesByTypeOnly = partitionIndexableNames(sourceFile.sources)\n const valueNames = namesByTypeOnly.get(false)!\n const typeNames = namesByTypeOnly.get(true)!\n\n if (valueNames.size === 0 && typeNames.size === 0) {\n if (sourceFile.sources.length > 0) return []\n return [createExport({ path: modulePath })]\n }\n\n const exports: Array<ExportNode> = []\n if (valueNames.size > 0) {\n exports.push(createExport({ name: [...valueNames].sort(), path: modulePath }))\n }\n if (typeNames.size > 0) {\n exports.push(createExport({ name: [...typeNames].sort(), path: modulePath, isTypeOnly: true }))\n }\n return exports\n}\n\nconst LEAF_STRATEGIES: ReadonlyMap<BarrelType, LeafStrategy> = new Map([\n ['all', allStrategy],\n ['named', namedStrategy],\n])\n\ntype LeafWalkParams = {\n sourceFiles: ReadonlyMap<string, FileNode>\n strategy: LeafStrategy\n recursive: boolean\n}\n\n/**\n * Post-order walk that emits a barrel per visited directory.\n */\nfunction walkAllOrNamed(node: BuildTree, params: LeafWalkParams, isRoot: boolean, out: Array<FileNode>): Array<string> {\n const subtreeLeaves: Array<string> = []\n\n for (const child of node.children) {\n if (child.isFile) {\n if (!isBarrelPath(child.path)) subtreeLeaves.push(child.path)\n continue\n }\n\n const childLeaves = walkAllOrNamed(child, params, false, out)\n for (const leaf of childLeaves) subtreeLeaves.push(leaf)\n }\n\n if (!isRoot && !params.recursive) return subtreeLeaves\n\n const exports = subtreeLeaves.flatMap((leafPath) => params.strategy({ dirPath: node.path, leafPath, sourceFile: params.sourceFiles.get(leafPath) }))\n\n if (exports.length > 0) {\n out.push(makeBarrel(node.path, exports))\n }\n\n return subtreeLeaves\n}\n\n/**\n * Recursive walk that emits one barrel per directory, re-exporting files and sub-barrels.\n * Used when nested: true.\n */\nfunction walkNested(node: BuildTree, out: Array<FileNode>): void {\n const exports: Array<ExportNode> = []\n\n for (const child of node.children) {\n if (child.isFile) {\n if (isBarrelPath(child.path)) continue\n exports.push(createExport({ path: toRelativeModulePath(node.path, child.path) }))\n continue\n }\n\n walkNested(child, out)\n exports.push(createExport({ path: toRelativeModulePath(node.path, `${child.path}${BARREL_SUFFIX}`) }))\n }\n\n if (exports.length > 0) {\n out.push(makeBarrel(node.path, exports))\n }\n}\n\ntype IndexedFiles = {\n sourceFiles: ReadonlyMap<string, FileNode>\n paths: ReadonlyArray<string>\n}\n\nfunction indexRelevantFiles(files: ReadonlyArray<FileNode>, outputPath: string): IndexedFiles {\n const outputPrefix = `${toPosixPath(outputPath)}/`\n const sourceFiles = new Map<string, FileNode>()\n const paths: Array<string> = []\n\n for (const file of files) {\n const normalized = toPosixPath(file.path)\n if (!normalized.startsWith(outputPrefix)) continue\n if (isBarrelPath(normalized)) continue\n if (!SOURCE_EXTENSIONS.has(extname(normalized))) continue\n\n sourceFiles.set(normalized, file)\n paths.push(normalized)\n }\n\n return { sourceFiles, paths }\n}\n\ntype GetBarrelFilesParams = {\n /**\n * Absolute directory the barrel(s) should be rooted at.\n * Only files living under this path are considered.\n */\n outputPath: string\n /**\n * Pool of generated files to scan for indexable sources.\n */\n files: ReadonlyArray<FileNode>\n /**\n * Export strategy used when emitting each barrel.\n * - `'all'` re-exports the whole module (`export * from './x'`)\n * - `'named'` re-exports only the indexable named symbols\n */\n barrelType: BarrelType\n /**\n * Generate an `index.ts` in every sub-directory, each re-exporting only what's directly inside it (hierarchical).\n * When false, uses flat generation strategy with optional recursive subdirectory barrels.\n *\n * @default false\n */\n nested?: boolean\n /**\n * Also generate a barrel for each sub-directory when nested is false.\n * No effect when nested is true (always generates hierarchical structure).\n *\n * @default false\n */\n recursive?: boolean\n}\n\n/**\n * Generates barrel `FileNode`s for the directory rooted at `outputPath`.\n */\nexport function getBarrelFiles({ outputPath, files, barrelType, nested = false, recursive = false }: GetBarrelFilesParams): Array<FileNode> {\n const { sourceFiles, paths } = indexRelevantFiles(files, outputPath)\n if (paths.length === 0) return []\n\n const tree = buildTree(outputPath, paths)\n const result: Array<FileNode> = []\n\n // Use nested walk for hierarchical barrel structure\n if (nested) {\n walkNested(tree, result)\n return result\n }\n\n const strategy = LEAF_STRATEGIES.get(barrelType)\n if (!strategy) return result\n\n walkAllOrNamed(tree, { sourceFiles, strategy, recursive }, true, result)\n return result\n}\n\n/**\n * Builds a POSIX-normalized prefix for a plugin's output directory, with a trailing `/`.\n *\n * Used to detect (and later exclude) files generated by plugins that opted out of the root barrel.\n */\nexport function getPluginOutputPrefix(plugin: NormalizedPlugin, config: Config): string {\n return `${toPosixPath(resolve(config.root, config.output.path, plugin.options.output.path))}/`\n}\n\n/**\n * Returns `true` when `filePath` lives under any of the given excluded directory prefixes.\n *\n * Both sides are POSIX-normalized so Windows backslash paths match correctly.\n */\nexport function isExcludedPath(filePath: string, prefixes: ReadonlySet<string>): boolean {\n const normalized = toPosixPath(filePath)\n return prefixes.values().some((prefix) => normalized.startsWith(prefix))\n}\n","import path from 'node:path'\nimport { resolve } from 'node:path'\nimport { defineMiddleware } from '@kubb/core'\nimport type { Middleware } from '@kubb/core'\nimport type { BarrelConfig, PluginBarrelConfig } from './types.ts'\nimport { getBarrelFiles, getPluginOutputPrefix, isExcludedPath } from './utils.ts'\n\ndeclare global {\n namespace Kubb {\n interface PluginOptionsRegistry {\n output: {\n /**\n * Barrel configuration for this plugin's output.\n * Set to `false` to disable barrel generation for this plugin entirely; doing so also\n * excludes the plugin's files from the root barrel.\n *\n * Falls back to `config.output.barrel` when omitted.\n *\n * @default { type: 'named' }\n */\n barrel?: PluginBarrelConfig | false\n }\n }\n interface ConfigOptionsRegistry {\n output: {\n /**\n * Barrel configuration for the root barrel file at `config.output.path/index.ts`.\n * Set to `false` to disable root barrel generation. Individual plugins can override\n * this via their own `output.barrel`.\n *\n * @default { type: 'named' }\n */\n barrel?: BarrelConfig | false\n }\n }\n }\n}\n\n/**\n * Generates `index.ts` barrel files for each plugin and a root barrel at `config.output.path/index.ts`.\n *\n * Each plugin inherits `output.barrel` from `config.output.barrel` (defaults to `{ type: 'named' }`).\n * Set `barrel: false` on a plugin to disable its barrel and exclude it from the root barrel.\n *\n * @example\n * ```ts\n * import { defineConfig } from '@kubb/core'\n * import { middlewareBarrel } from '@kubb/middleware-barrel'\n *\n * export default defineConfig({\n * output: { path: 'src/gen', barrel: { type: 'named' } },\n * plugins: [\n * pluginTs({ output: { path: 'types', barrel: { type: 'all' } } }),\n * pluginZod({ output: { path: 'schemas' } }),\n * ],\n * middleware: [middlewareBarrel()],\n * })\n * ```\n */\n\n/**\n * Stable string identifier for the barrel middleware.\n */\nexport const middlewareBarrelName = 'middleware-barrel' satisfies Middleware['name']\n\nexport const middlewareBarrel = defineMiddleware(() => {\n const excludedPrefixes = new Set<string>()\n\n return {\n name: middlewareBarrelName,\n hooks: {\n 'kubb:plugin:end'({ plugin, config, files, upsertFile }) {\n const pluginBarrel = plugin.options.output?.barrel\n const configBarrel = config.output.barrel\n const defaultBarrel = { type: 'named' } as const\n\n let barrelConfig: PluginBarrelConfig | false\n if (pluginBarrel !== undefined) {\n barrelConfig = pluginBarrel\n } else if (configBarrel !== undefined) {\n // Root config barrel doesn't have nested, so we add it\n barrelConfig = configBarrel === false ? false : { ...configBarrel, nested: false }\n } else {\n barrelConfig = defaultBarrel\n }\n\n if (barrelConfig === false) {\n excludedPrefixes.add(getPluginOutputPrefix(plugin, config))\n return\n }\n\n const barrelType = barrelConfig.type\n const nested = barrelConfig.nested ?? false\n\n const base = resolve(config.root, config.output.path)\n const target = resolve(base, plugin.options.output.path)\n const relative = path.relative(base, target)\n if (relative.startsWith('..') || path.isAbsolute(relative)) {\n throw new Error('Invalid output path')\n }\n const barrelFiles = getBarrelFiles({\n outputPath: target,\n files,\n barrelType,\n nested,\n recursive: true,\n })\n\n if (barrelFiles.length > 0) {\n upsertFile(...barrelFiles)\n }\n },\n 'kubb:plugins:end'({ files, config, upsertFile }) {\n const barrelConfig = config.output.barrel ?? { type: 'named' }\n\n const filteredFiles = excludedPrefixes.size === 0 ? files : files.filter((f) => !isExcludedPath(f.path, excludedPrefixes))\n excludedPrefixes.clear()\n\n if (barrelConfig === false) return\n\n const barrelType = barrelConfig.type\n\n const rootBarrelFiles = getBarrelFiles({\n outputPath: resolve(config.root, config.output.path),\n files: filteredFiles,\n barrelType,\n })\n\n if (rootBarrelFiles.length > 0) {\n upsertFile(...rootBarrelFiles)\n }\n },\n },\n }\n})\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -86,32 +86,13 @@ function compareByPath(a, b) {
86
86
  return a.path < b.path ? -1 : a.path > b.path ? 1 : 0;
87
87
  }
88
88
  //#endregion
89
- //#region src/utils/excludedPaths.ts
90
- /**
91
- * Builds a POSIX-normalized prefix for a plugin's output directory, with a trailing `/`.
92
- *
93
- * Used to detect (and later exclude) files generated by plugins that opted out of the root barrel.
94
- */
95
- function getPluginOutputPrefix(plugin, config) {
96
- return `${toPosixPath(resolve(config.root, config.output.path, plugin.options.output.path))}/`;
97
- }
98
- /**
99
- * Returns `true` when `filePath` lives under any of the given excluded directory prefixes.
100
- *
101
- * Both sides are POSIX-normalized so Windows backslash paths match correctly.
102
- */
103
- function isExcludedPath(filePath, prefixes) {
104
- const normalized = toPosixPath(filePath);
105
- return prefixes.values().some((prefix) => normalized.startsWith(prefix));
106
- }
107
- //#endregion
108
89
  //#region src/constants.ts
109
90
  /**
110
91
  * Full file name for barrel files (with extension).
111
92
  */
112
93
  const BARREL_FILENAME = "index.ts";
113
94
  //#endregion
114
- //#region src/utils/getBarrelFiles.ts
95
+ //#region src/utils.ts
115
96
  const SOURCE_EXTENSIONS = new Set([
116
97
  ".ts",
117
98
  ".tsx",
@@ -253,6 +234,23 @@ function getBarrelFiles({ outputPath, files, barrelType, nested = false, recursi
253
234
  }, true, result);
254
235
  return result;
255
236
  }
237
+ /**
238
+ * Builds a POSIX-normalized prefix for a plugin's output directory, with a trailing `/`.
239
+ *
240
+ * Used to detect (and later exclude) files generated by plugins that opted out of the root barrel.
241
+ */
242
+ function getPluginOutputPrefix(plugin, config) {
243
+ return `${toPosixPath(resolve(config.root, config.output.path, plugin.options.output.path))}/`;
244
+ }
245
+ /**
246
+ * Returns `true` when `filePath` lives under any of the given excluded directory prefixes.
247
+ *
248
+ * Both sides are POSIX-normalized so Windows backslash paths match correctly.
249
+ */
250
+ function isExcludedPath(filePath, prefixes) {
251
+ const normalized = toPosixPath(filePath);
252
+ return prefixes.values().some((prefix) => normalized.startsWith(prefix));
253
+ }
256
254
  //#endregion
257
255
  //#region src/middleware.ts
258
256
  /**
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../internals/utils/src/path.ts","../../../internals/utils/src/buildTree.ts","../src/utils/excludedPaths.ts","../src/constants.ts","../src/utils/getBarrelFiles.ts","../src/middleware.ts"],"sourcesContent":["/**\n * Converts a filesystem path to use POSIX (`/`) separators.\n *\n * Most of the codebase compares and composes paths as strings (prefix matching, joining for\n * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated\n * paths, but on Windows it returns `\\`-separated paths, which breaks every such comparison.\n *\n * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the\n * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is\n * exercisable from POSIX CI.\n *\n * @example\n * toPosixPath('C:\\\\repo\\\\src\\\\pet.ts') // 'C:/repo/src/pet.ts'\n */\nexport function toPosixPath(filePath: string): string {\n return filePath.replaceAll('\\\\', '/')\n}\n","import { toPosixPath } from './path.ts'\n\n/**\n * A node in the directory tree used to compute barrel file exports.\n * Either represents a directory (with `children`) or a file (`isFile: true`, empty `children`).\n */\nexport type BuildTree = {\n /**\n * Absolute filesystem path of this directory or file. Always normalized to POSIX (`/`) separators.\n */\n path: string\n /**\n * Sub-directories and files contained within this directory.\n * Always empty for file nodes.\n */\n children: Array<BuildTree>\n /**\n * `true` when this node represents a file (leaf), `false` for directory nodes.\n */\n isFile: boolean\n}\n\n/**\n * Builds a directory tree rooted at `rootPath` from a list of absolute file paths.\n * Paths outside `rootPath` are silently ignored. Children are sorted alphabetically\n * by path so consumers (barrel exports, propagated indexes) emit a deterministic order.\n *\n * Both POSIX (`/`) and Windows (`\\`) separators are accepted in input paths; emitted node\n * paths are always POSIX-normalized so downstream prefix/lookup operations behave the same\n * across platforms.\n *\n * @example\n * ```ts\n * buildTree('/src/gen/types', [\n * '/src/gen/types/pet.ts',\n * '/src/gen/types/pets/listPets.ts',\n * ])\n * ```\n */\nexport function buildTree(rootPath: string, filePaths: ReadonlyArray<string>): BuildTree {\n const normalizedRoot = toPosixPath(rootPath)\n const root: BuildTree = { path: normalizedRoot, children: [], isFile: false }\n // Per-directory child lookup avoids the O(N) `Array.find` scan during insertion.\n const childIndex = new Map<BuildTree, Map<string, BuildTree>>()\n childIndex.set(root, new Map())\n\n const rootPrefix = `${normalizedRoot}/`\n\n for (const filePath of filePaths) {\n const normalized = toPosixPath(filePath)\n if (!normalized.startsWith(rootPrefix)) continue\n\n const parts = normalized.slice(rootPrefix.length).split('/')\n if (parts.length === 0) continue\n\n let current = root\n const lastIndex = parts.length - 1\n for (const [i, part] of parts.entries()) {\n if (!part) continue\n\n const isLast = i === lastIndex\n const siblings = childIndex.get(current)!\n let child = siblings.get(part)\n if (!child) {\n child = { path: `${current.path}/${part}`, children: [], isFile: isLast }\n current.children.push(child)\n siblings.set(part, child)\n if (!isLast) childIndex.set(child, new Map())\n }\n current = child\n }\n }\n\n sortTree(root)\n\n return root\n}\n\nfunction sortTree(node: BuildTree): void {\n if (node.children.length === 0) return\n node.children.sort(compareByPath)\n for (const child of node.children) {\n if (!child.isFile) sortTree(child)\n }\n}\n\nfunction compareByPath(a: BuildTree, b: BuildTree): number {\n return a.path < b.path ? -1 : a.path > b.path ? 1 : 0\n}\n","import { resolve } from 'node:path'\nimport type { Config, NormalizedPlugin } from '@kubb/core'\nimport { toPosixPath } from '@internals/utils'\n\n/**\n * Builds a POSIX-normalized prefix for a plugin's output directory, with a trailing `/`.\n *\n * Used to detect (and later exclude) files generated by plugins that opted out of the root barrel.\n */\nexport function getPluginOutputPrefix(plugin: NormalizedPlugin, config: Config): string {\n return `${toPosixPath(resolve(config.root, config.output.path, plugin.options.output.path))}/`\n}\n\n/**\n * Returns `true` when `filePath` lives under any of the given excluded directory prefixes.\n *\n * Both sides are POSIX-normalized so Windows backslash paths match correctly.\n */\nexport function isExcludedPath(filePath: string, prefixes: ReadonlySet<string>): boolean {\n const normalized = toPosixPath(filePath)\n return prefixes.values().some((prefix) => normalized.startsWith(prefix))\n}\n","/**\n * Full file name for barrel files (with extension).\n */\nexport const BARREL_FILENAME = 'index.ts' as const\n","import { extname } from 'node:path'\nimport { createExport, createFile } from '@kubb/ast'\nimport type { ExportNode, FileNode, SourceNode } from '@kubb/ast'\nimport { BARREL_FILENAME } from '../constants.ts'\nimport type { BarrelType } from '../types.ts'\nimport { type BuildTree, buildTree, toPosixPath } from '@internals/utils'\n\nconst SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx'])\nconst BARREL_SUFFIX = `/${BARREL_FILENAME}`\n\nfunction toRelativeModulePath(fromDir: string, filePath: string): string {\n return `./${filePath.slice(fromDir.length + 1)}`\n}\n\nfunction isBarrelPath(path: string): boolean {\n return path.endsWith(BARREL_SUFFIX)\n}\n\nfunction makeBarrel(dirPath: string, exports: Array<ExportNode>): FileNode {\n return createFile({\n baseName: BARREL_FILENAME,\n path: `${dirPath}${BARREL_SUFFIX}`,\n exports,\n sources: [],\n imports: [],\n // Barrel files must never carry a banner or footer: they only re-export\n // symbols and adding a directive like \"use server\" would break consumers.\n banner: undefined,\n footer: undefined,\n })\n}\n\ntype LeafContext = {\n dirPath: string\n leafPath: string\n sourceFile: FileNode | undefined\n}\n\ntype LeafStrategy = (ctx: LeafContext) => Array<ExportNode>\n\nfunction hasOnlyNonIndexableSources(sources: ReadonlyArray<SourceNode>): boolean {\n if (sources.length === 0) return false\n for (const source of sources) {\n if (source.isIndexable) return false\n }\n return true\n}\n\nfunction partitionIndexableNames(sources: ReadonlyArray<SourceNode>): Map<boolean, Set<string>> {\n const byTypeOnly = new Map<boolean, Set<string>>([\n [false, new Set()],\n [true, new Set()],\n ])\n for (const source of sources) {\n if (!source.isIndexable || !source.name) continue\n byTypeOnly.get(Boolean(source.isTypeOnly))!.add(source.name)\n }\n return byTypeOnly\n}\n\nconst allStrategy: LeafStrategy = ({ dirPath, leafPath, sourceFile }) => {\n if (sourceFile && hasOnlyNonIndexableSources(sourceFile.sources)) return []\n return [createExport({ path: toRelativeModulePath(dirPath, leafPath) })]\n}\n\nconst namedStrategy: LeafStrategy = ({ dirPath, leafPath, sourceFile }) => {\n const modulePath = toRelativeModulePath(dirPath, leafPath)\n\n if (!sourceFile) return [createExport({ path: modulePath })]\n\n const namesByTypeOnly = partitionIndexableNames(sourceFile.sources)\n const valueNames = namesByTypeOnly.get(false)!\n const typeNames = namesByTypeOnly.get(true)!\n\n if (valueNames.size === 0 && typeNames.size === 0) {\n if (sourceFile.sources.length > 0) return []\n return [createExport({ path: modulePath })]\n }\n\n const exports: Array<ExportNode> = []\n if (valueNames.size > 0) {\n exports.push(createExport({ name: [...valueNames].sort(), path: modulePath }))\n }\n if (typeNames.size > 0) {\n exports.push(createExport({ name: [...typeNames].sort(), path: modulePath, isTypeOnly: true }))\n }\n return exports\n}\n\nconst LEAF_STRATEGIES: ReadonlyMap<BarrelType, LeafStrategy> = new Map([\n ['all', allStrategy],\n ['named', namedStrategy],\n])\n\ntype LeafWalkParams = {\n sourceFiles: ReadonlyMap<string, FileNode>\n strategy: LeafStrategy\n recursive: boolean\n}\n\n/**\n * Post-order walk that emits a barrel per visited directory.\n */\nfunction walkAllOrNamed(node: BuildTree, params: LeafWalkParams, isRoot: boolean, out: Array<FileNode>): Array<string> {\n const subtreeLeaves: Array<string> = []\n\n for (const child of node.children) {\n if (child.isFile) {\n if (!isBarrelPath(child.path)) subtreeLeaves.push(child.path)\n continue\n }\n\n const childLeaves = walkAllOrNamed(child, params, false, out)\n for (const leaf of childLeaves) subtreeLeaves.push(leaf)\n }\n\n if (!isRoot && !params.recursive) return subtreeLeaves\n\n const exports = subtreeLeaves.flatMap((leafPath) => params.strategy({ dirPath: node.path, leafPath, sourceFile: params.sourceFiles.get(leafPath) }))\n\n if (exports.length > 0) {\n out.push(makeBarrel(node.path, exports))\n }\n\n return subtreeLeaves\n}\n\n/**\n * Recursive walk that emits one barrel per directory, re-exporting files and sub-barrels.\n * Used when nested: true.\n */\nfunction walkNested(node: BuildTree, out: Array<FileNode>): void {\n const exports: Array<ExportNode> = []\n\n for (const child of node.children) {\n if (child.isFile) {\n if (isBarrelPath(child.path)) continue\n exports.push(createExport({ path: toRelativeModulePath(node.path, child.path) }))\n continue\n }\n\n walkNested(child, out)\n exports.push(createExport({ path: toRelativeModulePath(node.path, `${child.path}${BARREL_SUFFIX}`) }))\n }\n\n if (exports.length > 0) {\n out.push(makeBarrel(node.path, exports))\n }\n}\n\ntype IndexedFiles = {\n sourceFiles: ReadonlyMap<string, FileNode>\n paths: ReadonlyArray<string>\n}\n\nfunction indexRelevantFiles(files: ReadonlyArray<FileNode>, outputPath: string): IndexedFiles {\n const outputPrefix = `${toPosixPath(outputPath)}/`\n const sourceFiles = new Map<string, FileNode>()\n const paths: Array<string> = []\n\n for (const file of files) {\n const normalized = toPosixPath(file.path)\n if (!normalized.startsWith(outputPrefix)) continue\n if (isBarrelPath(normalized)) continue\n if (!SOURCE_EXTENSIONS.has(extname(normalized))) continue\n\n sourceFiles.set(normalized, file)\n paths.push(normalized)\n }\n\n return { sourceFiles, paths }\n}\n\ntype GetBarrelFilesParams = {\n /**\n * Absolute directory the barrel(s) should be rooted at.\n * Only files living under this path are considered.\n */\n outputPath: string\n /**\n * Pool of generated files to scan for indexable sources.\n */\n files: ReadonlyArray<FileNode>\n /**\n * Export strategy used when emitting each barrel.\n * - `'all'` re-exports the whole module (`export * from './x'`)\n * - `'named'` re-exports only the indexable named symbols\n */\n barrelType: BarrelType\n /**\n * Generate an `index.ts` in every sub-directory, each re-exporting only what's directly inside it (hierarchical).\n * When false, uses flat generation strategy with optional recursive subdirectory barrels.\n *\n * @default false\n */\n nested?: boolean\n /**\n * Also generate a barrel for each sub-directory when nested is false.\n * No effect when nested is true (always generates hierarchical structure).\n *\n * @default false\n */\n recursive?: boolean\n}\n\n/**\n * Generates barrel `FileNode`s for the directory rooted at `outputPath`.\n */\nexport function getBarrelFiles({ outputPath, files, barrelType, nested = false, recursive = false }: GetBarrelFilesParams): Array<FileNode> {\n const { sourceFiles, paths } = indexRelevantFiles(files, outputPath)\n if (paths.length === 0) return []\n\n const tree = buildTree(outputPath, paths)\n const result: Array<FileNode> = []\n\n // Use nested walk for hierarchical barrel structure\n if (nested) {\n walkNested(tree, result)\n return result\n }\n\n const strategy = LEAF_STRATEGIES.get(barrelType)\n if (!strategy) return result\n\n walkAllOrNamed(tree, { sourceFiles, strategy, recursive }, true, result)\n return result\n}\n","import path from 'node:path'\nimport { resolve } from 'node:path'\nimport { defineMiddleware } from '@kubb/core'\nimport type { Middleware } from '@kubb/core'\nimport type { BarrelConfig, PluginBarrelConfig } from './types.ts'\nimport { getPluginOutputPrefix, isExcludedPath } from './utils/excludedPaths.ts'\nimport { getBarrelFiles } from './utils/getBarrelFiles.ts'\n\ndeclare global {\n namespace Kubb {\n interface PluginOptionsRegistry {\n output: {\n /**\n * Barrel configuration for this plugin's output.\n * Set to `false` to disable barrel generation for this plugin entirely; doing so also\n * excludes the plugin's files from the root barrel.\n *\n * Falls back to `config.output.barrel` when omitted.\n *\n * @default { type: 'named' }\n */\n barrel?: PluginBarrelConfig | false\n }\n }\n interface ConfigOptionsRegistry {\n output: {\n /**\n * Barrel configuration for the root barrel file at `config.output.path/index.ts`.\n * Set to `false` to disable root barrel generation. Individual plugins can override\n * this via their own `output.barrel`.\n *\n * @default { type: 'named' }\n */\n barrel?: BarrelConfig | false\n }\n }\n }\n}\n\n/**\n * Generates `index.ts` barrel files for each plugin and a root barrel at `config.output.path/index.ts`.\n *\n * Each plugin inherits `output.barrel` from `config.output.barrel` (defaults to `{ type: 'named' }`).\n * Set `barrel: false` on a plugin to disable its barrel and exclude it from the root barrel.\n *\n * @example\n * ```ts\n * import { defineConfig } from '@kubb/core'\n * import { middlewareBarrel } from '@kubb/middleware-barrel'\n *\n * export default defineConfig({\n * output: { path: 'src/gen', barrel: { type: 'named' } },\n * plugins: [\n * pluginTs({ output: { path: 'types', barrel: { type: 'all' } } }),\n * pluginZod({ output: { path: 'schemas' } }),\n * ],\n * middleware: [middlewareBarrel()],\n * })\n * ```\n */\n\n/**\n * Stable string identifier for the barrel middleware.\n */\nexport const middlewareBarrelName = 'middleware-barrel' satisfies Middleware['name']\n\nexport const middlewareBarrel = defineMiddleware(() => {\n const excludedPrefixes = new Set<string>()\n\n return {\n name: middlewareBarrelName,\n hooks: {\n 'kubb:plugin:end'({ plugin, config, files, upsertFile }) {\n const pluginBarrel = plugin.options.output?.barrel\n const configBarrel = config.output.barrel\n const defaultBarrel = { type: 'named' } as const\n\n let barrelConfig: PluginBarrelConfig | false\n if (pluginBarrel !== undefined) {\n barrelConfig = pluginBarrel\n } else if (configBarrel !== undefined) {\n // Root config barrel doesn't have nested, so we add it\n barrelConfig = configBarrel === false ? false : { ...configBarrel, nested: false }\n } else {\n barrelConfig = defaultBarrel\n }\n\n if (barrelConfig === false) {\n excludedPrefixes.add(getPluginOutputPrefix(plugin, config))\n return\n }\n\n const barrelType = barrelConfig.type\n const nested = barrelConfig.nested ?? false\n\n const base = resolve(config.root, config.output.path)\n const target = resolve(base, plugin.options.output.path)\n const relative = path.relative(base, target)\n if (relative.startsWith('..') || path.isAbsolute(relative)) {\n throw new Error('Invalid output path')\n }\n const barrelFiles = getBarrelFiles({\n outputPath: target,\n files,\n barrelType,\n nested,\n recursive: true,\n })\n\n if (barrelFiles.length > 0) {\n upsertFile(...barrelFiles)\n }\n },\n 'kubb:plugins:end'({ files, config, upsertFile }) {\n const barrelConfig = config.output.barrel ?? { type: 'named' }\n\n const filteredFiles = excludedPrefixes.size === 0 ? files : files.filter((f) => !isExcludedPath(f.path, excludedPrefixes))\n excludedPrefixes.clear()\n\n if (barrelConfig === false) return\n\n const barrelType = barrelConfig.type\n\n const rootBarrelFiles = getBarrelFiles({\n outputPath: resolve(config.root, config.output.path),\n files: filteredFiles,\n barrelType,\n })\n\n if (rootBarrelFiles.length > 0) {\n upsertFile(...rootBarrelFiles)\n }\n },\n },\n }\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../internals/utils/src/path.ts","../../../internals/utils/src/buildTree.ts","../src/constants.ts","../src/utils.ts","../src/middleware.ts"],"sourcesContent":["/**\n * Converts a filesystem path to use POSIX (`/`) separators.\n *\n * Most of the codebase compares and composes paths as strings (prefix matching, joining for\n * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated\n * paths, but on Windows it returns `\\`-separated paths, which breaks every such comparison.\n *\n * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the\n * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is\n * exercisable from POSIX CI.\n *\n * @example\n * toPosixPath('C:\\\\repo\\\\src\\\\pet.ts') // 'C:/repo/src/pet.ts'\n */\nexport function toPosixPath(filePath: string): string {\n return filePath.replaceAll('\\\\', '/')\n}\n","import { toPosixPath } from './path.ts'\n\n/**\n * A node in the directory tree used to compute barrel file exports.\n * Either represents a directory (with `children`) or a file (`isFile: true`, empty `children`).\n */\nexport type BuildTree = {\n /**\n * Absolute filesystem path of this directory or file. Always normalized to POSIX (`/`) separators.\n */\n path: string\n /**\n * Sub-directories and files contained within this directory.\n * Always empty for file nodes.\n */\n children: Array<BuildTree>\n /**\n * `true` when this node represents a file (leaf), `false` for directory nodes.\n */\n isFile: boolean\n}\n\n/**\n * Builds a directory tree rooted at `rootPath` from a list of absolute file paths.\n * Paths outside `rootPath` are silently ignored. Children are sorted alphabetically\n * by path so consumers (barrel exports, propagated indexes) emit a deterministic order.\n *\n * Both POSIX (`/`) and Windows (`\\`) separators are accepted in input paths; emitted node\n * paths are always POSIX-normalized so downstream prefix/lookup operations behave the same\n * across platforms.\n *\n * @example\n * ```ts\n * buildTree('/src/gen/types', [\n * '/src/gen/types/pet.ts',\n * '/src/gen/types/pets/listPets.ts',\n * ])\n * ```\n */\nexport function buildTree(rootPath: string, filePaths: ReadonlyArray<string>): BuildTree {\n const normalizedRoot = toPosixPath(rootPath)\n const root: BuildTree = { path: normalizedRoot, children: [], isFile: false }\n // Per-directory child lookup avoids the O(N) `Array.find` scan during insertion.\n const childIndex = new Map<BuildTree, Map<string, BuildTree>>()\n childIndex.set(root, new Map())\n\n const rootPrefix = `${normalizedRoot}/`\n\n for (const filePath of filePaths) {\n const normalized = toPosixPath(filePath)\n if (!normalized.startsWith(rootPrefix)) continue\n\n const parts = normalized.slice(rootPrefix.length).split('/')\n if (parts.length === 0) continue\n\n let current = root\n const lastIndex = parts.length - 1\n for (const [i, part] of parts.entries()) {\n if (!part) continue\n\n const isLast = i === lastIndex\n const siblings = childIndex.get(current)!\n let child = siblings.get(part)\n if (!child) {\n child = { path: `${current.path}/${part}`, children: [], isFile: isLast }\n current.children.push(child)\n siblings.set(part, child)\n if (!isLast) childIndex.set(child, new Map())\n }\n current = child\n }\n }\n\n sortTree(root)\n\n return root\n}\n\nfunction sortTree(node: BuildTree): void {\n if (node.children.length === 0) return\n node.children.sort(compareByPath)\n for (const child of node.children) {\n if (!child.isFile) sortTree(child)\n }\n}\n\nfunction compareByPath(a: BuildTree, b: BuildTree): number {\n return a.path < b.path ? -1 : a.path > b.path ? 1 : 0\n}\n","/**\n * Full file name for barrel files (with extension).\n */\nexport const BARREL_FILENAME = 'index.ts' as const\n","import { extname, resolve } from 'node:path'\nimport { createExport, createFile } from '@kubb/ast'\nimport type { ExportNode, FileNode, SourceNode } from '@kubb/ast'\nimport type { Config, NormalizedPlugin } from '@kubb/core'\nimport { type BuildTree, buildTree, toPosixPath } from '@internals/utils'\nimport { BARREL_FILENAME } from './constants.ts'\nimport type { BarrelType } from './types.ts'\n\nconst SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx'])\nconst BARREL_SUFFIX = `/${BARREL_FILENAME}`\n\nfunction toRelativeModulePath(fromDir: string, filePath: string): string {\n return `./${filePath.slice(fromDir.length + 1)}`\n}\n\nfunction isBarrelPath(path: string): boolean {\n return path.endsWith(BARREL_SUFFIX)\n}\n\nfunction makeBarrel(dirPath: string, exports: Array<ExportNode>): FileNode {\n return createFile({\n baseName: BARREL_FILENAME,\n path: `${dirPath}${BARREL_SUFFIX}`,\n exports,\n sources: [],\n imports: [],\n // Barrel files must never carry a banner or footer: they only re-export\n // symbols and adding a directive like \"use server\" would break consumers.\n banner: undefined,\n footer: undefined,\n })\n}\n\ntype LeafContext = {\n dirPath: string\n leafPath: string\n sourceFile: FileNode | undefined\n}\n\ntype LeafStrategy = (ctx: LeafContext) => Array<ExportNode>\n\nfunction hasOnlyNonIndexableSources(sources: ReadonlyArray<SourceNode>): boolean {\n if (sources.length === 0) return false\n for (const source of sources) {\n if (source.isIndexable) return false\n }\n return true\n}\n\nfunction partitionIndexableNames(sources: ReadonlyArray<SourceNode>): Map<boolean, Set<string>> {\n const byTypeOnly = new Map<boolean, Set<string>>([\n [false, new Set()],\n [true, new Set()],\n ])\n for (const source of sources) {\n if (!source.isIndexable || !source.name) continue\n byTypeOnly.get(Boolean(source.isTypeOnly))!.add(source.name)\n }\n return byTypeOnly\n}\n\nconst allStrategy: LeafStrategy = ({ dirPath, leafPath, sourceFile }) => {\n if (sourceFile && hasOnlyNonIndexableSources(sourceFile.sources)) return []\n return [createExport({ path: toRelativeModulePath(dirPath, leafPath) })]\n}\n\nconst namedStrategy: LeafStrategy = ({ dirPath, leafPath, sourceFile }) => {\n const modulePath = toRelativeModulePath(dirPath, leafPath)\n\n if (!sourceFile) return [createExport({ path: modulePath })]\n\n const namesByTypeOnly = partitionIndexableNames(sourceFile.sources)\n const valueNames = namesByTypeOnly.get(false)!\n const typeNames = namesByTypeOnly.get(true)!\n\n if (valueNames.size === 0 && typeNames.size === 0) {\n if (sourceFile.sources.length > 0) return []\n return [createExport({ path: modulePath })]\n }\n\n const exports: Array<ExportNode> = []\n if (valueNames.size > 0) {\n exports.push(createExport({ name: [...valueNames].sort(), path: modulePath }))\n }\n if (typeNames.size > 0) {\n exports.push(createExport({ name: [...typeNames].sort(), path: modulePath, isTypeOnly: true }))\n }\n return exports\n}\n\nconst LEAF_STRATEGIES: ReadonlyMap<BarrelType, LeafStrategy> = new Map([\n ['all', allStrategy],\n ['named', namedStrategy],\n])\n\ntype LeafWalkParams = {\n sourceFiles: ReadonlyMap<string, FileNode>\n strategy: LeafStrategy\n recursive: boolean\n}\n\n/**\n * Post-order walk that emits a barrel per visited directory.\n */\nfunction walkAllOrNamed(node: BuildTree, params: LeafWalkParams, isRoot: boolean, out: Array<FileNode>): Array<string> {\n const subtreeLeaves: Array<string> = []\n\n for (const child of node.children) {\n if (child.isFile) {\n if (!isBarrelPath(child.path)) subtreeLeaves.push(child.path)\n continue\n }\n\n const childLeaves = walkAllOrNamed(child, params, false, out)\n for (const leaf of childLeaves) subtreeLeaves.push(leaf)\n }\n\n if (!isRoot && !params.recursive) return subtreeLeaves\n\n const exports = subtreeLeaves.flatMap((leafPath) => params.strategy({ dirPath: node.path, leafPath, sourceFile: params.sourceFiles.get(leafPath) }))\n\n if (exports.length > 0) {\n out.push(makeBarrel(node.path, exports))\n }\n\n return subtreeLeaves\n}\n\n/**\n * Recursive walk that emits one barrel per directory, re-exporting files and sub-barrels.\n * Used when nested: true.\n */\nfunction walkNested(node: BuildTree, out: Array<FileNode>): void {\n const exports: Array<ExportNode> = []\n\n for (const child of node.children) {\n if (child.isFile) {\n if (isBarrelPath(child.path)) continue\n exports.push(createExport({ path: toRelativeModulePath(node.path, child.path) }))\n continue\n }\n\n walkNested(child, out)\n exports.push(createExport({ path: toRelativeModulePath(node.path, `${child.path}${BARREL_SUFFIX}`) }))\n }\n\n if (exports.length > 0) {\n out.push(makeBarrel(node.path, exports))\n }\n}\n\ntype IndexedFiles = {\n sourceFiles: ReadonlyMap<string, FileNode>\n paths: ReadonlyArray<string>\n}\n\nfunction indexRelevantFiles(files: ReadonlyArray<FileNode>, outputPath: string): IndexedFiles {\n const outputPrefix = `${toPosixPath(outputPath)}/`\n const sourceFiles = new Map<string, FileNode>()\n const paths: Array<string> = []\n\n for (const file of files) {\n const normalized = toPosixPath(file.path)\n if (!normalized.startsWith(outputPrefix)) continue\n if (isBarrelPath(normalized)) continue\n if (!SOURCE_EXTENSIONS.has(extname(normalized))) continue\n\n sourceFiles.set(normalized, file)\n paths.push(normalized)\n }\n\n return { sourceFiles, paths }\n}\n\ntype GetBarrelFilesParams = {\n /**\n * Absolute directory the barrel(s) should be rooted at.\n * Only files living under this path are considered.\n */\n outputPath: string\n /**\n * Pool of generated files to scan for indexable sources.\n */\n files: ReadonlyArray<FileNode>\n /**\n * Export strategy used when emitting each barrel.\n * - `'all'` re-exports the whole module (`export * from './x'`)\n * - `'named'` re-exports only the indexable named symbols\n */\n barrelType: BarrelType\n /**\n * Generate an `index.ts` in every sub-directory, each re-exporting only what's directly inside it (hierarchical).\n * When false, uses flat generation strategy with optional recursive subdirectory barrels.\n *\n * @default false\n */\n nested?: boolean\n /**\n * Also generate a barrel for each sub-directory when nested is false.\n * No effect when nested is true (always generates hierarchical structure).\n *\n * @default false\n */\n recursive?: boolean\n}\n\n/**\n * Generates barrel `FileNode`s for the directory rooted at `outputPath`.\n */\nexport function getBarrelFiles({ outputPath, files, barrelType, nested = false, recursive = false }: GetBarrelFilesParams): Array<FileNode> {\n const { sourceFiles, paths } = indexRelevantFiles(files, outputPath)\n if (paths.length === 0) return []\n\n const tree = buildTree(outputPath, paths)\n const result: Array<FileNode> = []\n\n // Use nested walk for hierarchical barrel structure\n if (nested) {\n walkNested(tree, result)\n return result\n }\n\n const strategy = LEAF_STRATEGIES.get(barrelType)\n if (!strategy) return result\n\n walkAllOrNamed(tree, { sourceFiles, strategy, recursive }, true, result)\n return result\n}\n\n/**\n * Builds a POSIX-normalized prefix for a plugin's output directory, with a trailing `/`.\n *\n * Used to detect (and later exclude) files generated by plugins that opted out of the root barrel.\n */\nexport function getPluginOutputPrefix(plugin: NormalizedPlugin, config: Config): string {\n return `${toPosixPath(resolve(config.root, config.output.path, plugin.options.output.path))}/`\n}\n\n/**\n * Returns `true` when `filePath` lives under any of the given excluded directory prefixes.\n *\n * Both sides are POSIX-normalized so Windows backslash paths match correctly.\n */\nexport function isExcludedPath(filePath: string, prefixes: ReadonlySet<string>): boolean {\n const normalized = toPosixPath(filePath)\n return prefixes.values().some((prefix) => normalized.startsWith(prefix))\n}\n","import path from 'node:path'\nimport { resolve } from 'node:path'\nimport { defineMiddleware } from '@kubb/core'\nimport type { Middleware } from '@kubb/core'\nimport type { BarrelConfig, PluginBarrelConfig } from './types.ts'\nimport { getBarrelFiles, getPluginOutputPrefix, isExcludedPath } from './utils.ts'\n\ndeclare global {\n namespace Kubb {\n interface PluginOptionsRegistry {\n output: {\n /**\n * Barrel configuration for this plugin's output.\n * Set to `false` to disable barrel generation for this plugin entirely; doing so also\n * excludes the plugin's files from the root barrel.\n *\n * Falls back to `config.output.barrel` when omitted.\n *\n * @default { type: 'named' }\n */\n barrel?: PluginBarrelConfig | false\n }\n }\n interface ConfigOptionsRegistry {\n output: {\n /**\n * Barrel configuration for the root barrel file at `config.output.path/index.ts`.\n * Set to `false` to disable root barrel generation. Individual plugins can override\n * this via their own `output.barrel`.\n *\n * @default { type: 'named' }\n */\n barrel?: BarrelConfig | false\n }\n }\n }\n}\n\n/**\n * Generates `index.ts` barrel files for each plugin and a root barrel at `config.output.path/index.ts`.\n *\n * Each plugin inherits `output.barrel` from `config.output.barrel` (defaults to `{ type: 'named' }`).\n * Set `barrel: false` on a plugin to disable its barrel and exclude it from the root barrel.\n *\n * @example\n * ```ts\n * import { defineConfig } from '@kubb/core'\n * import { middlewareBarrel } from '@kubb/middleware-barrel'\n *\n * export default defineConfig({\n * output: { path: 'src/gen', barrel: { type: 'named' } },\n * plugins: [\n * pluginTs({ output: { path: 'types', barrel: { type: 'all' } } }),\n * pluginZod({ output: { path: 'schemas' } }),\n * ],\n * middleware: [middlewareBarrel()],\n * })\n * ```\n */\n\n/**\n * Stable string identifier for the barrel middleware.\n */\nexport const middlewareBarrelName = 'middleware-barrel' satisfies Middleware['name']\n\nexport const middlewareBarrel = defineMiddleware(() => {\n const excludedPrefixes = new Set<string>()\n\n return {\n name: middlewareBarrelName,\n hooks: {\n 'kubb:plugin:end'({ plugin, config, files, upsertFile }) {\n const pluginBarrel = plugin.options.output?.barrel\n const configBarrel = config.output.barrel\n const defaultBarrel = { type: 'named' } as const\n\n let barrelConfig: PluginBarrelConfig | false\n if (pluginBarrel !== undefined) {\n barrelConfig = pluginBarrel\n } else if (configBarrel !== undefined) {\n // Root config barrel doesn't have nested, so we add it\n barrelConfig = configBarrel === false ? false : { ...configBarrel, nested: false }\n } else {\n barrelConfig = defaultBarrel\n }\n\n if (barrelConfig === false) {\n excludedPrefixes.add(getPluginOutputPrefix(plugin, config))\n return\n }\n\n const barrelType = barrelConfig.type\n const nested = barrelConfig.nested ?? false\n\n const base = resolve(config.root, config.output.path)\n const target = resolve(base, plugin.options.output.path)\n const relative = path.relative(base, target)\n if (relative.startsWith('..') || path.isAbsolute(relative)) {\n throw new Error('Invalid output path')\n }\n const barrelFiles = getBarrelFiles({\n outputPath: target,\n files,\n barrelType,\n nested,\n recursive: true,\n })\n\n if (barrelFiles.length > 0) {\n upsertFile(...barrelFiles)\n }\n },\n 'kubb:plugins:end'({ files, config, upsertFile }) {\n const barrelConfig = config.output.barrel ?? { type: 'named' }\n\n const filteredFiles = excludedPrefixes.size === 0 ? files : files.filter((f) => !isExcludedPath(f.path, excludedPrefixes))\n excludedPrefixes.clear()\n\n if (barrelConfig === false) return\n\n const barrelType = barrelConfig.type\n\n const rootBarrelFiles = getBarrelFiles({\n outputPath: resolve(config.root, config.output.path),\n files: filteredFiles,\n barrelType,\n })\n\n if (rootBarrelFiles.length > 0) {\n upsertFile(...rootBarrelFiles)\n }\n },\n },\n }\n})\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,14 +1,12 @@
1
1
  {
2
2
  "name": "@kubb/middleware-barrel",
3
- "version": "5.0.0-beta.5",
4
- "description": "Barrel-file generation middleware for Kubb. Generates index.ts barrel files for each plugin's output directory and a root index.ts after all plugins have run.",
3
+ "version": "5.0.0-beta.7",
4
+ "description": "Barrel-file middleware for Kubb. Automatically generates index.ts re-export files per plugin output directory and an optional root barrel after all plugins complete.",
5
5
  "keywords": [
6
6
  "barrel",
7
- "code-generator",
8
7
  "codegen",
9
8
  "kubb",
10
9
  "middleware",
11
- "openapi",
12
10
  "typescript"
13
11
  ],
14
12
  "license": "MIT",
@@ -44,11 +42,14 @@
44
42
  "access": "public",
45
43
  "registry": "https://registry.npmjs.org/"
46
44
  },
45
+ "dependencies": {
46
+ "@kubb/ast": "5.0.0-beta.7"
47
+ },
47
48
  "devDependencies": {
48
49
  "@internals/utils": "0.0.0"
49
50
  },
50
51
  "peerDependencies": {
51
- "@kubb/core": "5.0.0-beta.5"
52
+ "@kubb/core": "5.0.0-beta.7"
52
53
  },
53
54
  "engines": {
54
55
  "node": ">=22"
package/src/middleware.ts CHANGED
@@ -3,8 +3,7 @@ import { resolve } from 'node:path'
3
3
  import { defineMiddleware } from '@kubb/core'
4
4
  import type { Middleware } from '@kubb/core'
5
5
  import type { BarrelConfig, PluginBarrelConfig } from './types.ts'
6
- import { getPluginOutputPrefix, isExcludedPath } from './utils/excludedPaths.ts'
7
- import { getBarrelFiles } from './utils/getBarrelFiles.ts'
6
+ import { getBarrelFiles, getPluginOutputPrefix, isExcludedPath } from './utils.ts'
8
7
 
9
8
  declare global {
10
9
  namespace Kubb {
@@ -1,9 +1,10 @@
1
- import { extname } from 'node:path'
1
+ import { extname, resolve } from 'node:path'
2
2
  import { createExport, createFile } from '@kubb/ast'
3
3
  import type { ExportNode, FileNode, SourceNode } from '@kubb/ast'
4
- import { BARREL_FILENAME } from '../constants.ts'
5
- import type { BarrelType } from '../types.ts'
4
+ import type { Config, NormalizedPlugin } from '@kubb/core'
6
5
  import { type BuildTree, buildTree, toPosixPath } from '@internals/utils'
6
+ import { BARREL_FILENAME } from './constants.ts'
7
+ import type { BarrelType } from './types.ts'
7
8
 
8
9
  const SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx'])
9
10
  const BARREL_SUFFIX = `/${BARREL_FILENAME}`
@@ -225,3 +226,22 @@ export function getBarrelFiles({ outputPath, files, barrelType, nested = false,
225
226
  walkAllOrNamed(tree, { sourceFiles, strategy, recursive }, true, result)
226
227
  return result
227
228
  }
229
+
230
+ /**
231
+ * Builds a POSIX-normalized prefix for a plugin's output directory, with a trailing `/`.
232
+ *
233
+ * Used to detect (and later exclude) files generated by plugins that opted out of the root barrel.
234
+ */
235
+ export function getPluginOutputPrefix(plugin: NormalizedPlugin, config: Config): string {
236
+ return `${toPosixPath(resolve(config.root, config.output.path, plugin.options.output.path))}/`
237
+ }
238
+
239
+ /**
240
+ * Returns `true` when `filePath` lives under any of the given excluded directory prefixes.
241
+ *
242
+ * Both sides are POSIX-normalized so Windows backslash paths match correctly.
243
+ */
244
+ export function isExcludedPath(filePath: string, prefixes: ReadonlySet<string>): boolean {
245
+ const normalized = toPosixPath(filePath)
246
+ return prefixes.values().some((prefix) => normalized.startsWith(prefix))
247
+ }
@@ -1,22 +0,0 @@
1
- import { resolve } from 'node:path'
2
- import type { Config, NormalizedPlugin } from '@kubb/core'
3
- import { toPosixPath } from '@internals/utils'
4
-
5
- /**
6
- * Builds a POSIX-normalized prefix for a plugin's output directory, with a trailing `/`.
7
- *
8
- * Used to detect (and later exclude) files generated by plugins that opted out of the root barrel.
9
- */
10
- export function getPluginOutputPrefix(plugin: NormalizedPlugin, config: Config): string {
11
- return `${toPosixPath(resolve(config.root, config.output.path, plugin.options.output.path))}/`
12
- }
13
-
14
- /**
15
- * Returns `true` when `filePath` lives under any of the given excluded directory prefixes.
16
- *
17
- * Both sides are POSIX-normalized so Windows backslash paths match correctly.
18
- */
19
- export function isExcludedPath(filePath: string, prefixes: ReadonlySet<string>): boolean {
20
- const normalized = toPosixPath(filePath)
21
- return prefixes.values().some((prefix) => normalized.startsWith(prefix))
22
- }