@kubb/plugin-barrel 5.0.0-beta.51

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.
@@ -0,0 +1,127 @@
1
+ import { t as __name } from "./chunk-C0LytTxp.js";
2
+ import { Plugin } from "@kubb/core";
3
+
4
+ //#region src/types.d.ts
5
+ /**
6
+ * Barrel export strategy.
7
+ *
8
+ * - `'all'` generates `export * from '...'` for every file
9
+ * - `'named'` generates `export { name1, name2 } from '...'` using each file's named exports
10
+ */
11
+ type BarrelType = 'all' | 'named';
12
+ /**
13
+ * Barrel configuration at the root config level.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * barrel: { type: 'named' } // default
18
+ * barrel: { type: 'all' }
19
+ * barrel: false // disable barrel generation
20
+ * ```
21
+ */
22
+ type BarrelConfig = {
23
+ /**
24
+ * Export strategy for the root barrel file.
25
+ * - `'all'` wildcard exports: `export * from './file'`
26
+ * - `'named'` explicit exports: `export { x, y } from './file'`
27
+ */
28
+ type: BarrelType;
29
+ };
30
+ /**
31
+ * Barrel configuration at the plugin level.
32
+ * Supports nested barrel generation in subdirectories.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * barrel: { type: 'named' } // single barrel with named exports
37
+ * barrel: { type: 'all', nested: true } // hierarchical barrels with wildcard exports
38
+ * barrel: { type: 'named', nested: true } // hierarchical barrels with named exports
39
+ * barrel: false // disable barrel generation
40
+ * ```
41
+ */
42
+ type PluginBarrelConfig = {
43
+ /**
44
+ * Export strategy for the plugin's barrel files.
45
+ * - `'all'` wildcard exports: `export * from './file'`
46
+ * - `'named'` explicit exports: `export { x, y } from './file'`
47
+ */
48
+ type: BarrelType;
49
+ /**
50
+ * Generate an `index.ts` in every sub-directory, each re-exporting only what's directly inside it.
51
+ * Creates a hierarchical barrel structure instead of flat exports from the root.
52
+ *
53
+ * @default false
54
+ */
55
+ nested?: boolean;
56
+ };
57
+ //#endregion
58
+ //#region src/plugin.d.ts
59
+ declare global {
60
+ namespace Kubb {
61
+ interface PluginOptionsRegistry {
62
+ output: {
63
+ /**
64
+ * Barrel configuration for this plugin's output.
65
+ * Set to `false` to disable barrel generation for this plugin entirely. Doing so also
66
+ * excludes the plugin's files from the root barrel.
67
+ *
68
+ * Falls back to `config.output.barrel` when omitted.
69
+ *
70
+ * @default { type: 'named' }
71
+ */
72
+ barrel?: PluginBarrelConfig | false;
73
+ };
74
+ }
75
+ interface ConfigOptionsRegistry {
76
+ output: {
77
+ /**
78
+ * Barrel configuration for the root barrel file at `config.output.path/index.ts`.
79
+ * Set to `false` to disable root barrel generation. Individual plugins can override
80
+ * this via their own `output.barrel`.
81
+ *
82
+ * @default { type: 'named' }
83
+ */
84
+ barrel?: BarrelConfig | false;
85
+ };
86
+ }
87
+ }
88
+ }
89
+ /**
90
+ * Canonical plugin name for `@kubb/plugin-barrel`. Used for driver lookups
91
+ * and to guard the `kubb:plugin:end` handler against reacting to its own lifecycle event.
92
+ */
93
+ declare const pluginBarrelName = "plugin-barrel";
94
+ /**
95
+ * Generates an `index.ts` for every plugin output directory and one root
96
+ * barrel at `config.output.path/index.ts` after the build completes. Ships
97
+ * with Kubb and is registered by default in `defineConfig`.
98
+ *
99
+ * Each plugin inherits `output.barrel` from `config.output.barrel` (which
100
+ * defaults to `{ type: 'named' }`). Set `barrel: false` on a plugin to skip
101
+ * its barrel and also exclude its files from the root barrel.
102
+ *
103
+ * A plugin with `output.mode: 'file'` gets no per-plugin barrel, since its output
104
+ * is a single file. The root barrel re-exports that file directly.
105
+ *
106
+ * @example
107
+ * ```ts
108
+ * import { defineConfig } from '@kubb/core'
109
+ * import { pluginBarrel } from '@kubb/plugin-barrel'
110
+ * import { pluginTs } from '@kubb/plugin-ts'
111
+ * import { pluginZod } from '@kubb/plugin-zod'
112
+ *
113
+ * export default defineConfig({
114
+ * input: { path: './petStore.yaml' },
115
+ * output: { path: 'src/gen', barrel: { type: 'named' } },
116
+ * plugins: [
117
+ * pluginTs({ output: { path: 'types', barrel: { type: 'all' } } }),
118
+ * pluginZod({ output: { path: 'schemas' } }),
119
+ * pluginBarrel(),
120
+ * ],
121
+ * })
122
+ * ```
123
+ */
124
+ declare const pluginBarrel: (options?: object | undefined) => Plugin<import("@kubb/core").PluginFactoryOptions<string, object, object, import("@kubb/core").Resolver>>;
125
+ //#endregion
126
+ export { type BarrelConfig, type BarrelType, type PluginBarrelConfig, pluginBarrel, pluginBarrelName };
127
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,386 @@
1
+ import "./chunk-C0LytTxp.js";
2
+ import path, { extname, resolve } from "node:path";
3
+ import { definePlugin } from "@kubb/core";
4
+ import { createExport, createFile } from "@kubb/ast";
5
+ //#region ../../internals/utils/src/path.ts
6
+ /**
7
+ * Converts a filesystem path to use POSIX (`/`) separators.
8
+ *
9
+ * Most of the codebase compares and composes paths as strings (prefix matching, joining for
10
+ * import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated
11
+ * paths, but on Windows it returns `\`-separated paths, which breaks every such comparison.
12
+ *
13
+ * Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the
14
+ * code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is
15
+ * exercisable from POSIX CI.
16
+ *
17
+ * @example
18
+ * toPosixPath('C:\\repo\\src\\pet.ts') // 'C:/repo/src/pet.ts'
19
+ */
20
+ function toPosixPath(filePath) {
21
+ return filePath.replaceAll("\\", "/");
22
+ }
23
+ //#endregion
24
+ //#region ../../internals/utils/src/buildTree.ts
25
+ /**
26
+ * Builds a directory tree rooted at `rootPath` from a list of absolute file paths.
27
+ * Paths outside `rootPath` are silently ignored. Children are sorted alphabetically
28
+ * by path so consumers (barrel exports, propagated indexes) emit a deterministic order.
29
+ *
30
+ * Both POSIX (`/`) and Windows (`\`) separators are accepted in input paths; emitted node
31
+ * paths are always POSIX-normalized so downstream prefix/lookup operations behave the same
32
+ * across platforms.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * buildTree('/src/gen/types', [
37
+ * '/src/gen/types/pet.ts',
38
+ * '/src/gen/types/pets/listPets.ts',
39
+ * ])
40
+ * ```
41
+ */
42
+ function buildTree(rootPath, filePaths) {
43
+ const normalizedRoot = toPosixPath(rootPath);
44
+ const root = {
45
+ path: normalizedRoot,
46
+ children: [],
47
+ isFile: false
48
+ };
49
+ const childIndex = /* @__PURE__ */ new WeakMap();
50
+ childIndex.set(root, /* @__PURE__ */ new Map());
51
+ const rootPrefix = `${normalizedRoot}/`;
52
+ for (const filePath of filePaths) {
53
+ const normalized = toPosixPath(filePath);
54
+ if (!normalized.startsWith(rootPrefix)) continue;
55
+ const parts = normalized.slice(rootPrefix.length).split("/");
56
+ if (parts.length === 0) continue;
57
+ let current = root;
58
+ const lastIndex = parts.length - 1;
59
+ for (const [i, part] of parts.entries()) {
60
+ if (!part) continue;
61
+ const isLast = i === lastIndex;
62
+ const siblings = childIndex.get(current);
63
+ let child = siblings.get(part);
64
+ if (!child) {
65
+ child = {
66
+ path: `${current.path}/${part}`,
67
+ children: [],
68
+ isFile: isLast
69
+ };
70
+ current.children.push(child);
71
+ siblings.set(part, child);
72
+ if (!isLast) childIndex.set(child, /* @__PURE__ */ new Map());
73
+ }
74
+ current = child;
75
+ }
76
+ }
77
+ sortTree(root);
78
+ return root;
79
+ }
80
+ function sortTree(node) {
81
+ if (node.children.length === 0) return;
82
+ node.children.sort(compareByPath);
83
+ for (const child of node.children) if (!child.isFile) sortTree(child);
84
+ }
85
+ function compareByPath(a, b) {
86
+ return a.path < b.path ? -1 : a.path > b.path ? 1 : 0;
87
+ }
88
+ //#endregion
89
+ //#region src/utils.ts
90
+ const SOURCE_EXTENSIONS = new Set([
91
+ ".ts",
92
+ ".tsx",
93
+ ".js",
94
+ ".jsx"
95
+ ]);
96
+ const BARREL_SUFFIX = `/index.ts`;
97
+ function toRelativeModulePath(fromDir, filePath) {
98
+ return `./${filePath.slice(fromDir.length + 1)}`;
99
+ }
100
+ function isBarrelPath(path) {
101
+ return path.endsWith(BARREL_SUFFIX);
102
+ }
103
+ function makeBarrel(dirPath, exports) {
104
+ return createFile({
105
+ baseName: "index.ts",
106
+ path: `${dirPath}${BARREL_SUFFIX}`,
107
+ exports,
108
+ sources: [],
109
+ imports: [],
110
+ banner: void 0,
111
+ footer: void 0
112
+ });
113
+ }
114
+ function hasOnlyNonIndexableSources(sources) {
115
+ if (sources.length === 0) return false;
116
+ for (const source of sources) if (source.isIndexable) return false;
117
+ return true;
118
+ }
119
+ function partitionIndexableNames(sources) {
120
+ const byTypeOnly = new Map([[false, /* @__PURE__ */ new Set()], [true, /* @__PURE__ */ new Set()]]);
121
+ for (const source of sources) {
122
+ if (!source.isIndexable || !source.name) continue;
123
+ byTypeOnly.get(Boolean(source.isTypeOnly)).add(source.name);
124
+ }
125
+ return byTypeOnly;
126
+ }
127
+ const allStrategy = ({ dirPath, leafPath, sourceFile }) => {
128
+ if (sourceFile && hasOnlyNonIndexableSources(sourceFile.sources)) return [];
129
+ return [createExport({ path: toRelativeModulePath(dirPath, leafPath) })];
130
+ };
131
+ const namedStrategy = ({ dirPath, leafPath, sourceFile }) => {
132
+ const modulePath = toRelativeModulePath(dirPath, leafPath);
133
+ if (!sourceFile) return [createExport({ path: modulePath })];
134
+ const namesByTypeOnly = partitionIndexableNames(sourceFile.sources);
135
+ const valueNames = namesByTypeOnly.get(false);
136
+ const typeNames = namesByTypeOnly.get(true);
137
+ if (valueNames.size === 0 && typeNames.size === 0) {
138
+ if (sourceFile.sources.length > 0) return [];
139
+ return [createExport({ path: modulePath })];
140
+ }
141
+ const exports = [];
142
+ if (valueNames.size > 0) exports.push(createExport({
143
+ name: [...valueNames].sort(),
144
+ path: modulePath
145
+ }));
146
+ if (typeNames.size > 0) exports.push(createExport({
147
+ name: [...typeNames].sort(),
148
+ path: modulePath,
149
+ isTypeOnly: true
150
+ }));
151
+ return exports;
152
+ };
153
+ const LEAF_STRATEGIES = new Map([["all", allStrategy], ["named", namedStrategy]]);
154
+ /**
155
+ * Post-order walk that yields a barrel per visited directory.
156
+ * Returns the list of leaf file paths collected in this subtree (used by the parent call).
157
+ */
158
+ function* walkAllOrNamed(node, params, isRoot) {
159
+ const subtreeLeaves = [];
160
+ for (const child of node.children) {
161
+ if (child.isFile) {
162
+ if (!isBarrelPath(child.path)) subtreeLeaves.push(child.path);
163
+ continue;
164
+ }
165
+ const childLeaves = yield* walkAllOrNamed(child, params, false);
166
+ for (const leaf of childLeaves) subtreeLeaves.push(leaf);
167
+ }
168
+ if (!isRoot && !params.recursive) return subtreeLeaves;
169
+ const exports = subtreeLeaves.flatMap((leafPath) => params.strategy({
170
+ dirPath: node.path,
171
+ leafPath,
172
+ sourceFile: params.sourceFiles.get(leafPath) ?? null
173
+ }));
174
+ if (exports.length > 0) yield makeBarrel(node.path, exports);
175
+ return subtreeLeaves;
176
+ }
177
+ /**
178
+ * Recursive walk that yields one barrel per directory, re-exporting files and sub-barrels.
179
+ * Used when nested: true.
180
+ */
181
+ function* walkNested(node) {
182
+ const exports = [];
183
+ for (const child of node.children) {
184
+ if (child.isFile) {
185
+ if (isBarrelPath(child.path)) continue;
186
+ exports.push(createExport({ path: toRelativeModulePath(node.path, child.path) }));
187
+ continue;
188
+ }
189
+ yield* walkNested(child);
190
+ exports.push(createExport({ path: toRelativeModulePath(node.path, `${child.path}${BARREL_SUFFIX}`) }));
191
+ }
192
+ if (exports.length > 0) yield makeBarrel(node.path, exports);
193
+ }
194
+ function indexRelevantFiles(files, outputPath) {
195
+ const outputPrefix = `${toPosixPath(outputPath)}/`;
196
+ const sourceFiles = /* @__PURE__ */ new Map();
197
+ const paths = [];
198
+ for (const file of files) {
199
+ const normalized = toPosixPath(file.path);
200
+ if (!normalized.startsWith(outputPrefix)) continue;
201
+ if (isBarrelPath(normalized)) continue;
202
+ if (!SOURCE_EXTENSIONS.has(extname(normalized))) continue;
203
+ sourceFiles.set(normalized, file);
204
+ paths.push(normalized);
205
+ }
206
+ return {
207
+ sourceFiles,
208
+ paths
209
+ };
210
+ }
211
+ /**
212
+ * Yields barrel `FileNode`s for the directory rooted at `outputPath`.
213
+ *
214
+ * @example
215
+ * ```ts
216
+ * for (const file of getBarrelFiles({ outputPath, files, barrelType })) {
217
+ * upsertFile(file)
218
+ * }
219
+ * // or collect into an array
220
+ * const barrels = [...getBarrelFiles({ outputPath, files, barrelType })]
221
+ * ```
222
+ */
223
+ function* getBarrelFiles({ outputPath, files, barrelType, nested = false, recursive = false }) {
224
+ const { sourceFiles, paths } = indexRelevantFiles(files, outputPath);
225
+ if (paths.length === 0) return;
226
+ const tree = buildTree(outputPath, paths);
227
+ if (nested) {
228
+ yield* walkNested(tree);
229
+ return;
230
+ }
231
+ const strategy = LEAF_STRATEGIES.get(barrelType);
232
+ if (!strategy) return;
233
+ yield* walkAllOrNamed(tree, {
234
+ sourceFiles,
235
+ strategy,
236
+ recursive
237
+ }, true);
238
+ }
239
+ /**
240
+ * Builds a POSIX-normalized prefix for a plugin's output. A directory output gets a trailing `/`,
241
+ * while a `mode: 'file'` output (the path is the file itself) gets the exact path with no trailing `/`.
242
+ *
243
+ * Used to detect (and later exclude) files generated by plugins that opted out of the root barrel.
244
+ */
245
+ function getPluginOutputPrefix(plugin, config) {
246
+ const resolved = toPosixPath(resolve(config.root, config.output.path, plugin.options.output.path));
247
+ return plugin.options.output.mode === "file" ? resolved : `${resolved}/`;
248
+ }
249
+ /**
250
+ * Returns `true` when `filePath` lives under any of the given excluded prefixes. A prefix with a
251
+ * trailing `/` matches a directory subtree, and a prefix without one matches that exact file
252
+ * (used for `mode: 'file'` outputs).
253
+ *
254
+ * Both sides are POSIX-normalized so Windows backslash paths match correctly.
255
+ */
256
+ function isExcludedPath(filePath, prefixes) {
257
+ const normalized = toPosixPath(filePath);
258
+ return prefixes.values().some((prefix) => prefix.endsWith("/") ? normalized.startsWith(prefix) : normalized === prefix);
259
+ }
260
+ //#endregion
261
+ //#region src/plugin.ts
262
+ /**
263
+ * Applies a plugin's configured `output.banner`/`footer` to a barrel file, flagged as `isBarrel`.
264
+ *
265
+ * Resolves through the plugin's own resolver, and only when the plugin explicitly sets a
266
+ * banner/footer, so barrels stay banner-free by default and never inherit the implicit
267
+ * "Generated by Kubb" notice.
268
+ */
269
+ function withBarrelBannerFooter({ file, plugin, config }) {
270
+ const output = plugin.options?.output;
271
+ const resolver = plugin.resolver;
272
+ if (!resolver) return file;
273
+ const hasBanner = output?.banner !== void 0;
274
+ const hasFooter = output?.footer !== void 0;
275
+ if (!hasBanner && !hasFooter) return file;
276
+ const context = {
277
+ output,
278
+ config,
279
+ file: {
280
+ path: file.path,
281
+ baseName: file.baseName,
282
+ isBarrel: true
283
+ }
284
+ };
285
+ return {
286
+ ...file,
287
+ banner: hasBanner ? resolver.resolveBanner(void 0, context) : file.banner,
288
+ footer: hasFooter ? resolver.resolveFooter(void 0, context) : file.footer
289
+ };
290
+ }
291
+ /**
292
+ * Canonical plugin name for `@kubb/plugin-barrel`. Used for driver lookups
293
+ * and to guard the `kubb:plugin:end` handler against reacting to its own lifecycle event.
294
+ */
295
+ const pluginBarrelName = "plugin-barrel";
296
+ /**
297
+ * Generates an `index.ts` for every plugin output directory and one root
298
+ * barrel at `config.output.path/index.ts` after the build completes. Ships
299
+ * with Kubb and is registered by default in `defineConfig`.
300
+ *
301
+ * Each plugin inherits `output.barrel` from `config.output.barrel` (which
302
+ * defaults to `{ type: 'named' }`). Set `barrel: false` on a plugin to skip
303
+ * its barrel and also exclude its files from the root barrel.
304
+ *
305
+ * A plugin with `output.mode: 'file'` gets no per-plugin barrel, since its output
306
+ * is a single file. The root barrel re-exports that file directly.
307
+ *
308
+ * @example
309
+ * ```ts
310
+ * import { defineConfig } from '@kubb/core'
311
+ * import { pluginBarrel } from '@kubb/plugin-barrel'
312
+ * import { pluginTs } from '@kubb/plugin-ts'
313
+ * import { pluginZod } from '@kubb/plugin-zod'
314
+ *
315
+ * export default defineConfig({
316
+ * input: { path: './petStore.yaml' },
317
+ * output: { path: 'src/gen', barrel: { type: 'named' } },
318
+ * plugins: [
319
+ * pluginTs({ output: { path: 'types', barrel: { type: 'all' } } }),
320
+ * pluginZod({ output: { path: 'schemas' } }),
321
+ * pluginBarrel(),
322
+ * ],
323
+ * })
324
+ * ```
325
+ */
326
+ const pluginBarrel = definePlugin(() => {
327
+ const excludedPrefixes = /* @__PURE__ */ new Set();
328
+ return {
329
+ name: pluginBarrelName,
330
+ enforce: "post",
331
+ hooks: {
332
+ "kubb:plugin:end"({ plugin, config, files, upsertFile }) {
333
+ if (plugin.name === "plugin-barrel") return;
334
+ const pluginBarrelOpt = plugin.options.output?.barrel;
335
+ const configBarrel = config.output.barrel;
336
+ const defaultBarrel = { type: "named" };
337
+ const barrelConfig = (() => {
338
+ if (pluginBarrelOpt !== void 0) return pluginBarrelOpt;
339
+ if (configBarrel !== void 0) return configBarrel === false ? false : {
340
+ ...configBarrel,
341
+ nested: false
342
+ };
343
+ return defaultBarrel;
344
+ })();
345
+ if (barrelConfig === false) {
346
+ excludedPrefixes.add(getPluginOutputPrefix(plugin, config));
347
+ return;
348
+ }
349
+ if (plugin.options.output.mode === "file") return;
350
+ const barrelType = barrelConfig.type;
351
+ const nested = barrelConfig.nested ?? false;
352
+ const base = resolve(config.root, config.output.path);
353
+ const target = resolve(base, plugin.options.output.path);
354
+ const relative = path.relative(base, target);
355
+ if (relative.startsWith("..") || path.isAbsolute(relative)) throw new Error("Invalid output path");
356
+ for (const file of getBarrelFiles({
357
+ outputPath: target,
358
+ files,
359
+ barrelType,
360
+ nested,
361
+ recursive: true
362
+ })) upsertFile(withBarrelBannerFooter({
363
+ file,
364
+ plugin,
365
+ config
366
+ }));
367
+ },
368
+ "kubb:plugins:end"({ files, config, upsertFile }) {
369
+ const barrelConfig = config.output.barrel ?? { type: "named" };
370
+ const filteredFiles = excludedPrefixes.size === 0 ? files : files.filter((f) => !isExcludedPath(f.path, excludedPrefixes));
371
+ excludedPrefixes.clear();
372
+ if (barrelConfig === false) return;
373
+ const barrelType = barrelConfig.type;
374
+ for (const file of getBarrelFiles({
375
+ outputPath: resolve(config.root, config.output.path),
376
+ files: filteredFiles,
377
+ barrelType
378
+ })) upsertFile(file);
379
+ }
380
+ }
381
+ };
382
+ });
383
+ //#endregion
384
+ export { pluginBarrel, pluginBarrelName };
385
+
386
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../internals/utils/src/path.ts","../../../internals/utils/src/buildTree.ts","../src/utils.ts","../src/plugin.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 // WeakMap keyed by object identity so directory nodes are GC-eligible once the tree is discarded.\n const childIndex = new WeakMap<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 { 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 type { BarrelType } from './types.ts'\n\nconst SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx'])\nconst BARREL_SUFFIX = `/index.ts`\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: 'index.ts',\n path: `${dirPath}${BARREL_SUFFIX}`,\n exports,\n sources: [],\n imports: [],\n // Default to no banner/footer. The barrel plugin resolves a configured plugin\n // banner/footer (with isBarrel: true) afterwards, so a `banner` function can\n // decide per file whether a barrel should carry a directive like \"use server\".\n banner: undefined,\n footer: undefined,\n })\n}\n\ntype LeafContext = {\n dirPath: string\n leafPath: string\n sourceFile: FileNode | null\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 yields a barrel per visited directory.\n * Returns the list of leaf file paths collected in this subtree (used by the parent call).\n */\nfunction* walkAllOrNamed(node: BuildTree, params: LeafWalkParams, isRoot: boolean): Generator<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 = yield* walkAllOrNamed(child, params, false)\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) ?? null }))\n\n if (exports.length > 0) {\n yield makeBarrel(node.path, exports)\n }\n\n return subtreeLeaves\n}\n\n/**\n * Recursive walk that yields one barrel per directory, re-exporting files and sub-barrels.\n * Used when nested: true.\n */\nfunction* walkNested(node: BuildTree): Generator<FileNode> {\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 yield* walkNested(child)\n exports.push(createExport({ path: toRelativeModulePath(node.path, `${child.path}${BARREL_SUFFIX}`) }))\n }\n\n if (exports.length > 0) {\n yield 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 * Yields barrel `FileNode`s for the directory rooted at `outputPath`.\n *\n * @example\n * ```ts\n * for (const file of getBarrelFiles({ outputPath, files, barrelType })) {\n * upsertFile(file)\n * }\n * // or collect into an array\n * const barrels = [...getBarrelFiles({ outputPath, files, barrelType })]\n * ```\n */\nexport function* getBarrelFiles({ outputPath, files, barrelType, nested = false, recursive = false }: GetBarrelFilesParams): Generator<FileNode> {\n const { sourceFiles, paths } = indexRelevantFiles(files, outputPath)\n if (paths.length === 0) return\n\n const tree = buildTree(outputPath, paths)\n\n if (nested) {\n yield* walkNested(tree)\n return\n }\n\n const strategy = LEAF_STRATEGIES.get(barrelType)\n if (!strategy) return\n\n yield* walkAllOrNamed(tree, { sourceFiles, strategy, recursive }, true)\n}\n\n/**\n * Builds a POSIX-normalized prefix for a plugin's output. A directory output gets a trailing `/`,\n * while a `mode: 'file'` output (the path is the file itself) gets the exact path with no 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 const resolved = toPosixPath(resolve(config.root, config.output.path, plugin.options.output.path))\n return plugin.options.output.mode === 'file' ? resolved : `${resolved}/`\n}\n\n/**\n * Returns `true` when `filePath` lives under any of the given excluded prefixes. A prefix with a\n * trailing `/` matches a directory subtree, and a prefix without one matches that exact file\n * (used for `mode: 'file'` outputs).\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) => (prefix.endsWith('/') ? normalized.startsWith(prefix) : normalized === prefix))\n}\n","import path from 'node:path'\nimport { resolve } from 'node:path'\nimport type { FileNode } from '@kubb/ast'\nimport { definePlugin } from '@kubb/core'\nimport type { Config, NormalizedPlugin, Plugin } from '@kubb/core'\nimport type { BarrelConfig, PluginBarrelConfig } from './types.ts'\nimport { getBarrelFiles, getPluginOutputPrefix, isExcludedPath } from './utils.ts'\n\n/**\n * Applies a plugin's configured `output.banner`/`footer` to a barrel file, flagged as `isBarrel`.\n *\n * Resolves through the plugin's own resolver, and only when the plugin explicitly sets a\n * banner/footer, so barrels stay banner-free by default and never inherit the implicit\n * \"Generated by Kubb\" notice.\n */\nfunction withBarrelBannerFooter({ file, plugin, config }: { file: FileNode; plugin: NormalizedPlugin; config: Config }): FileNode {\n const output = plugin.options?.output\n const resolver = plugin.resolver\n if (!resolver) return file\n\n const hasBanner = output?.banner !== undefined\n const hasFooter = output?.footer !== undefined\n if (!hasBanner && !hasFooter) return file\n\n const context = { output, config, file: { path: file.path, baseName: file.baseName, isBarrel: true } }\n return {\n ...file,\n banner: hasBanner ? resolver.resolveBanner(undefined, context) : file.banner,\n footer: hasFooter ? resolver.resolveFooter(undefined, context) : file.footer,\n }\n}\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 * Canonical plugin name for `@kubb/plugin-barrel`. Used for driver lookups\n * and to guard the `kubb:plugin:end` handler against reacting to its own lifecycle event.\n */\nexport const pluginBarrelName = 'plugin-barrel' satisfies Plugin['name']\n\n/**\n * Generates an `index.ts` for every plugin output directory and one root\n * barrel at `config.output.path/index.ts` after the build completes. Ships\n * with Kubb and is registered by default in `defineConfig`.\n *\n * Each plugin inherits `output.barrel` from `config.output.barrel` (which\n * defaults to `{ type: 'named' }`). Set `barrel: false` on a plugin to skip\n * its barrel and also exclude its files from the root barrel.\n *\n * A plugin with `output.mode: 'file'` gets no per-plugin barrel, since its output\n * is a single file. The root barrel re-exports that file directly.\n *\n * @example\n * ```ts\n * import { defineConfig } from '@kubb/core'\n * import { pluginBarrel } from '@kubb/plugin-barrel'\n * import { pluginTs } from '@kubb/plugin-ts'\n * import { pluginZod } from '@kubb/plugin-zod'\n *\n * export default defineConfig({\n * input: { path: './petStore.yaml' },\n * output: { path: 'src/gen', barrel: { type: 'named' } },\n * plugins: [\n * pluginTs({ output: { path: 'types', barrel: { type: 'all' } } }),\n * pluginZod({ output: { path: 'schemas' } }),\n * pluginBarrel(),\n * ],\n * })\n * ```\n */\nexport const pluginBarrel = definePlugin(() => {\n const excludedPrefixes = new Set<string>()\n\n return {\n name: pluginBarrelName,\n enforce: 'post' as const,\n hooks: {\n 'kubb:plugin:end'({ plugin, config, files, upsertFile }) {\n // Skip reactions to the barrel plugin's own lifecycle event\n if (plugin.name === pluginBarrelName) return\n\n const pluginBarrelOpt = plugin.options.output?.barrel\n const configBarrel = config.output.barrel\n const defaultBarrel = { type: 'named' } as const\n\n // Root config barrel doesn't have nested, so we add it\n const barrelConfig: PluginBarrelConfig | false = (() => {\n if (pluginBarrelOpt !== undefined) return pluginBarrelOpt\n if (configBarrel !== undefined) return configBarrel === false ? false : { ...configBarrel, nested: false }\n return defaultBarrel\n })()\n\n if (barrelConfig === false) {\n excludedPrefixes.add(getPluginOutputPrefix(plugin, config))\n return\n }\n\n // `mode: 'file'` writes a single file, so there is no directory to barrel. The root barrel\n // re-exports that file as a direct leaf of `config.output.path`.\n if (plugin.options.output.mode === 'file') {\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 for (const file of getBarrelFiles({ outputPath: target, files, barrelType, nested, recursive: true })) {\n upsertFile(withBarrelBannerFooter({ file, plugin, config }))\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 for (const file of getBarrelFiles({ outputPath: resolve(config.root, config.output.path), files: filteredFiles, barrelType })) {\n upsertFile(file)\n }\n },\n },\n }\n})\n"],"mappings":"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"}